2 * Copyright (C) 2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
20 /***************************************************************************/
22 //#define DEBUG_VERBOSE 1
24 #include "StageFrightVideoPrivate.h"
27 #include <EGL/eglext.h>
28 #include <GLES2/gl2.h>
29 #include <GLES2/gl2ext.h>
30 #include "windowing/egl/EGLWrapper.h"
31 #include "windowing/WindowingFactory.h"
32 #include "settings/AdvancedSettings.h"
33 #include "utils/log.h"
35 #include "android/jni/Surface.h"
36 #include "android/jni/SurfaceTexture.h"
38 #define CLASSNAME "CStageFrightVideoPrivate"
41 #define CheckEglError(x) while((glerror = eglGetError()) != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",x, glerror);
42 #define CheckGlError(x) while((glerror = glGetError()) != GL_NO_ERROR) CLog::Log(LOGERROR, "GL error in %s: %x",x, glerror);
44 // EGL extension functions
45 static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
46 static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
47 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
49 int NP2( unsigned x ) {
59 CStageFrightVideoPrivate::CStageFrightVideoPrivate()
60 : decode_thread(NULL), source(NULL)
61 , eglDisplay(EGL_NO_DISPLAY), eglSurface(EGL_NO_SURFACE), eglContext(EGL_NO_CONTEXT)
62 , eglInitialized(false)
64 , quirks(QuirkNone), cur_frame(NULL), prev_frame(NULL)
65 , width(-1), height(-1)
66 , texwidth(-1), texheight(-1)
67 , client(NULL), decoder(NULL), decoder_component(NULL)
68 , drop_state(false), resetting(false)
70 if (!eglCreateImageKHR)
71 eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglCreateImageKHR");
72 if (!eglDestroyImageKHR)
73 eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglDestroyImageKHR");
74 if (!glEGLImageTargetTexture2DOES)
75 glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) CEGLWrapper::GetProcAddress("glEGLImageTargetTexture2DOES");
77 for (int i=0; i<INBUFCOUNT; ++i)
81 void CStageFrightVideoPrivate::signalBufferReturned(MediaBuffer *buffer)
85 MediaBuffer* CStageFrightVideoPrivate::getBuffer(size_t size)
88 for (; i<INBUFCOUNT; ++i)
89 if (inbuf[i]->refcount() == 0 && inbuf[i]->size() >= size)
94 for (; i<INBUFCOUNT; ++i)
95 if (inbuf[i]->refcount() == 0)
99 inbuf[i]->setObserver(NULL);
101 inbuf[i] = new MediaBuffer(size);
102 inbuf[i]->setObserver(this);
106 inbuf[i]->set_range(0, size);
110 bool CStageFrightVideoPrivate::inputBufferAvailable()
112 for (int i=0; i<INBUFCOUNT; ++i)
113 if (inbuf[i]->refcount() == 0)
119 void CStageFrightVideoPrivate::loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader)
121 #if defined(DEBUG_VERBOSE)
122 CLog::Log(LOGDEBUG, ">>loadOESShader\n");
125 GLuint shader = glCreateShader(shaderType);
126 CheckGlError("loadOESShader");
128 glShaderSource(shader, 1, &pSource, NULL);
129 glCompileShader(shader);
131 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
134 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
136 char* buf = (char*) malloc(infoLen);
138 glGetShaderInfoLog(shader, infoLen, NULL, buf);
139 printf("Shader compile log:\n%s\n", buf);
143 char* buf = (char*) malloc(0x1000);
145 glGetShaderInfoLog(shader, 0x1000, NULL, buf);
146 printf("Shader compile log:\n%s\n", buf);
150 glDeleteShader(shader);
157 void CStageFrightVideoPrivate::createOESProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm)
159 #if defined(DEBUG_VERBOSE)
160 CLog::Log(LOGDEBUG, ">>createOESProgram\n");
162 GLuint vertexShader, fragmentShader;
164 loadOESShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
167 loadOESShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
170 GLuint program = glCreateProgram();
172 glAttachShader(program, vertexShader);
173 glAttachShader(program, fragmentShader);
174 glLinkProgram(program);
175 GLint linkStatus = GL_FALSE;
176 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
177 if (linkStatus != GL_TRUE) {
179 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
181 char* buf = (char*) malloc(bufLength);
183 glGetProgramInfoLog(program, bufLength, NULL, buf);
184 printf("Program link log:\n%s\n", buf);
188 glDeleteProgram(program);
192 glDeleteShader(vertexShader);
193 glDeleteShader(fragmentShader);
197 void CStageFrightVideoPrivate::OES_shader_setUp()
201 "attribute vec4 vPosition;\n"
202 "varying vec2 texCoords;\n"
203 "uniform mat4 texMatrix;\n"
205 " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
206 " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
207 " gl_Position = vPosition;\n"
211 "#extension GL_OES_EGL_image_external : require\n"
212 "precision mediump float;\n"
213 "uniform samplerExternalOES texSampler;\n"
214 "varying vec2 texCoords;\n"
216 " gl_FragColor = texture2D(texSampler, texCoords);\n"
220 #if defined(DEBUG_VERBOSE)
221 CLog::Log(LOGDEBUG, ">>OES_shader_setUp\n");
223 CheckGlError("OES_shader_setUp");
224 createOESProgram(vsrc, fsrc, &mPgm);
227 mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
228 mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
229 mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
232 void CStageFrightVideoPrivate::InitializeEGL(int w, int h)
234 #if defined(DEBUG_VERBOSE)
235 CLog::Log(LOGDEBUG, "%s: >>> InitializeEGL: w:%d; h:%d\n", CLASSNAME, w, h);
239 if (!m_g_Windowing->IsExtSupported("GL_TEXTURE_NPOT"))
241 texwidth = NP2(texwidth);
242 texheight = NP2(texheight);
245 eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
246 if (eglDisplay == EGL_NO_DISPLAY)
247 CLog::Log(LOGERROR, "%s: InitializeEGL: no display\n", CLASSNAME);
248 eglBindAPI(EGL_OPENGL_ES_API);
249 EGLint contextAttributes[] = {
250 EGL_CONTEXT_CLIENT_VERSION, 2,
253 eglContext = eglCreateContext(eglDisplay, m_g_Windowing->GetEGLConfig(), EGL_NO_CONTEXT, contextAttributes);
254 EGLint pbufferAttribs[] = {
256 EGL_HEIGHT, texheight,
259 eglSurface = eglCreatePbufferSurface(eglDisplay, m_g_Windowing->GetEGLConfig(), pbufferAttribs);
260 eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
261 CheckGlError("stf init");
263 static const EGLint imageAttributes[] = {
264 EGL_IMAGE_PRESERVED_KHR, EGL_FALSE,
265 EGL_GL_TEXTURE_LEVEL_KHR, 0,
269 for (int i=0; i<NUMFBOTEX; ++i)
271 glGenTextures(1, &(slots[i].texid));
272 glBindTexture(GL_TEXTURE_2D, slots[i].texid);
274 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texheight, 0,
275 GL_RGBA, GL_UNSIGNED_BYTE, 0);
277 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
278 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
279 // This is necessary for non-power-of-two textures
280 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
281 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
283 slots[i].eglimg = eglCreateImageKHR(eglDisplay, eglContext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(slots[i].texid),imageAttributes);
284 free_queue.push_back(std::pair<EGLImageKHR, int>(slots[i].eglimg, i));
287 glBindTexture(GL_TEXTURE_2D, 0);
292 eglInitialized = true;
293 #if defined(DEBUG_VERBOSE)
294 CLog::Log(LOGDEBUG, "%s: <<< InitializeEGL: w:%d; h:%d\n", CLASSNAME, texwidth, texheight);
298 void CStageFrightVideoPrivate::UninitializeEGL()
300 #if defined(DEBUG_VERBOSE)
301 CLog::Log(LOGDEBUG, "%s: >>> UninitializeEGL\n", CLASSNAME);
304 for (int i=0; i<NUMFBOTEX; ++i)
306 glDeleteTextures(1, &(slots[i].texid));
307 eglDestroyImageKHR(eglDisplay, slots[i].eglimg);
310 if (eglContext != EGL_NO_CONTEXT)
311 eglDestroyContext(eglDisplay, eglContext);
312 eglContext = EGL_NO_CONTEXT;
314 if (eglSurface != EGL_NO_SURFACE)
315 eglDestroySurface(eglDisplay, eglSurface);
316 eglSurface = EGL_NO_SURFACE;
318 eglInitialized = false;
321 bool CStageFrightVideoPrivate::InitStagefrightSurface()
323 #if defined(DEBUG_VERBOSE)
324 CLog::Log(LOGDEBUG, "%s: >>> InitStagefrightSurface\n", CLASSNAME);
326 if (mVideoNativeWindow != NULL)
329 mVideoTextureId = -1;
331 glGenTextures(1, &mVideoTextureId);
332 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mVideoTextureId);
333 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
334 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
335 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
336 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
337 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
339 mSurfTexture = new CJNISurfaceTexture(mVideoTextureId);
340 mSurface = new CJNISurface(*mSurfTexture);
342 JNIEnv* env = xbmc_jnienv();
343 mVideoNativeWindow = ANativeWindow_fromSurface(env, mSurface->get_raw());
344 native_window_api_connect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
346 #if defined(DEBUG_VERBOSE)
347 CLog::Log(LOGDEBUG, "%s: <<< InitStagefrightSurface\n", CLASSNAME);
352 void CStageFrightVideoPrivate::UninitStagefrightSurface()
354 #if defined(DEBUG_VERBOSE)
355 CLog::Log(LOGDEBUG, "%s: >>> UninitStagefrightSurface\n", CLASSNAME);
357 if (mVideoNativeWindow == NULL)
360 native_window_api_disconnect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
361 ANativeWindow_release(mVideoNativeWindow.get());
362 mVideoNativeWindow = NULL;
365 mSurfTexture->release();
370 glDeleteTextures(1, &mVideoTextureId);
371 #if defined(DEBUG_VERBOSE)
372 CLog::Log(LOGDEBUG, "%s: <<< UninitStagefrightSurface\n", CLASSNAME);
376 void CStageFrightVideoPrivate::UpdateStagefrightTexture()
378 mSurfTexture->updateTexImage();
381 void CStageFrightVideoPrivate::GetStagefrightTransformMatrix(float* transformMatrix)
383 mSurfTexture->getTransformMatrix(transformMatrix);