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 #include "StageFrightVideoPrivate.h"
25 #include <EGL/eglext.h>
26 #include <GLES2/gl2.h>
27 #include <GLES2/gl2ext.h>
28 #include "windowing/egl/EGLWrapper.h"
29 #include "windowing/WindowingFactory.h"
30 #include "utils/log.h"
32 #include "android/jni/Surface.h"
33 #include "android/jni/SurfaceTexture.h"
36 #define CheckEglError(x) while((glerror = eglGetError()) != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",x, glerror);
37 #define CheckGlError(x) while((glerror = glGetError()) != GL_NO_ERROR) CLog::Log(LOGERROR, "GL error in %s: %x",x, glerror);
39 // EGL extension functions
40 static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
41 static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
42 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
44 int NP2( unsigned x ) {
54 CStageFrightVideoPrivate::CStageFrightVideoPrivate()
55 : decode_thread(NULL), source(NULL)
56 , eglDisplay(EGL_NO_DISPLAY), eglSurface(EGL_NO_SURFACE), eglContext(EGL_NO_CONTEXT)
57 , eglInitialized(false)
59 , quirks(QuirkNone), cur_frame(NULL), prev_frame(NULL)
60 , width(-1), height(-1)
61 , texwidth(-1), texheight(-1)
62 , client(NULL), decoder(NULL), decoder_component(NULL)
63 , drop_state(false), resetting(false)
64 , mVideoNativeWindow(NULL)
66 if (!eglCreateImageKHR)
67 eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglCreateImageKHR");
68 if (!eglDestroyImageKHR)
69 eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglDestroyImageKHR");
70 if (!glEGLImageTargetTexture2DOES)
71 glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) CEGLWrapper::GetProcAddress("glEGLImageTargetTexture2DOES");
74 void CStageFrightVideoPrivate::signalBufferReturned(MediaBuffer *buffer)
78 MediaBuffer* CStageFrightVideoPrivate::getBuffer(size_t size)
81 for (; i<INBUFCOUNT; ++i)
82 if (inbuf[i]->refcount() == 0 && inbuf[i]->size() >= size)
87 for (; i<INBUFCOUNT; ++i)
88 if (inbuf[i]->refcount() == 0)
92 inbuf[i]->setObserver(NULL);
94 inbuf[i] = new MediaBuffer(size);
95 inbuf[i]->setObserver(this);
99 inbuf[i]->set_range(0, size);
103 bool CStageFrightVideoPrivate::inputBufferAvailable()
105 for (int i=0; i<INBUFCOUNT; ++i)
106 if (inbuf[i]->refcount() == 0)
112 void CStageFrightVideoPrivate::loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader)
114 #if defined(DEBUG_VERBOSE)
115 CLog::Log(LOGDEBUG, ">>loadOESShader\n");
118 GLuint shader = glCreateShader(shaderType);
119 CheckGlError("loadOESShader");
121 glShaderSource(shader, 1, &pSource, NULL);
122 glCompileShader(shader);
124 glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
127 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
129 char* buf = (char*) malloc(infoLen);
131 glGetShaderInfoLog(shader, infoLen, NULL, buf);
132 printf("Shader compile log:\n%s\n", buf);
136 char* buf = (char*) malloc(0x1000);
138 glGetShaderInfoLog(shader, 0x1000, NULL, buf);
139 printf("Shader compile log:\n%s\n", buf);
143 glDeleteShader(shader);
150 void CStageFrightVideoPrivate::createOESProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm)
152 #if defined(DEBUG_VERBOSE)
153 CLog::Log(LOGDEBUG, ">>createOESProgram\n");
155 GLuint vertexShader, fragmentShader;
157 loadOESShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
160 loadOESShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
163 GLuint program = glCreateProgram();
165 glAttachShader(program, vertexShader);
166 glAttachShader(program, fragmentShader);
167 glLinkProgram(program);
168 GLint linkStatus = GL_FALSE;
169 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
170 if (linkStatus != GL_TRUE) {
172 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
174 char* buf = (char*) malloc(bufLength);
176 glGetProgramInfoLog(program, bufLength, NULL, buf);
177 printf("Program link log:\n%s\n", buf);
181 glDeleteProgram(program);
185 glDeleteShader(vertexShader);
186 glDeleteShader(fragmentShader);
190 void CStageFrightVideoPrivate::OES_shader_setUp()
194 "attribute vec4 vPosition;\n"
195 "varying vec2 texCoords;\n"
196 "uniform mat4 texMatrix;\n"
198 " vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
199 " texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
200 " gl_Position = vPosition;\n"
204 "#extension GL_OES_EGL_image_external : require\n"
205 "precision mediump float;\n"
206 "uniform samplerExternalOES texSampler;\n"
207 "varying vec2 texCoords;\n"
209 " gl_FragColor = texture2D(texSampler, texCoords);\n"
213 #if defined(DEBUG_VERBOSE)
214 CLog::Log(LOGDEBUG, ">>OES_shader_setUp\n");
216 CheckGlError("OES_shader_setUp");
217 createOESProgram(vsrc, fsrc, &mPgm);
220 mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
221 mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
222 mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
225 void CStageFrightVideoPrivate::InitializeEGL(int w, int h)
229 if (!g_Windowing.IsExtSupported("GL_TEXTURE_NPOT"))
231 texwidth = NP2(texwidth);
232 texheight = NP2(texheight);
235 eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
236 eglBindAPI(EGL_OPENGL_ES_API);
237 EGLint contextAttributes[] = {
238 EGL_CONTEXT_CLIENT_VERSION, 2,
241 eglContext = eglCreateContext(eglDisplay, g_Windowing.GetEGLConfig(), EGL_NO_CONTEXT, contextAttributes);
242 EGLint pbufferAttribs[] = {
244 EGL_HEIGHT, texheight,
247 eglSurface = eglCreatePbufferSurface(eglDisplay, g_Windowing.GetEGLConfig(), pbufferAttribs);
248 eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
249 CheckGlError("stf init");
251 static const EGLint imageAttributes[] = {
252 EGL_IMAGE_PRESERVED_KHR, EGL_FALSE,
253 EGL_GL_TEXTURE_LEVEL_KHR, 0,
257 for (int i=0; i<NUMFBOTEX; ++i)
259 glGenTextures(1, &(slots[i].texid));
260 glBindTexture(GL_TEXTURE_2D, slots[i].texid);
262 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texheight, 0,
263 GL_RGBA, GL_UNSIGNED_BYTE, 0);
265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
266 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
267 // This is necessary for non-power-of-two textures
268 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
269 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
271 slots[i].eglimg = eglCreateImageKHR(eglDisplay, eglContext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(slots[i].texid),imageAttributes);
272 free_queue.push_back(std::pair<EGLImageKHR, int>(slots[i].eglimg, i));
275 glBindTexture(GL_TEXTURE_2D, 0);
280 eglInitialized = true;
281 #if defined(DEBUG_VERBOSE)
282 CLog::Log(LOGDEBUG, "%s: >>> Initialized EGL: w:%d; h:%d\n", CLASSNAME, texwidth, texheight);
286 void CStageFrightVideoPrivate::UninitializeEGL()
289 for (int i=0; i<NUMFBOTEX; ++i)
291 glDeleteTextures(1, &(slots[i].texid));
292 eglDestroyImageKHR(eglDisplay, slots[i].eglimg);
295 if (eglContext != EGL_NO_CONTEXT)
296 eglDestroyContext(eglDisplay, eglContext);
297 eglContext = EGL_NO_CONTEXT;
299 if (eglSurface != EGL_NO_SURFACE)
300 eglDestroySurface(eglDisplay, eglSurface);
301 eglSurface = EGL_NO_SURFACE;
303 eglInitialized = false;
306 bool CStageFrightVideoPrivate::InitStagefrightSurface()
308 if (mVideoNativeWindow != NULL)
311 JNIEnv* env = xbmc_jnienv();
313 mVideoTextureId = -1;
315 glGenTextures(1, &mVideoTextureId);
316 glBindTexture(GL_TEXTURE_EXTERNAL_OES, mVideoTextureId);
317 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
318 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
319 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
320 glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
321 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
323 mSurfTexture = new CJNISurfaceTexture(mVideoTextureId);
324 mSurface = new CJNISurface(*mSurfTexture);
326 mVideoNativeWindow = ANativeWindow_fromSurface(env, mSurface->get_raw());
327 native_window_api_connect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
332 void CStageFrightVideoPrivate::UninitStagefrightSurface()
334 if (mVideoNativeWindow == NULL)
337 native_window_api_disconnect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
338 ANativeWindow_release(mVideoNativeWindow.get());
339 mVideoNativeWindow = NULL;
344 glDeleteTextures(1, &mVideoTextureId);
347 void CStageFrightVideoPrivate::UpdateStagefrightTexture()
349 mSurfTexture->updateTexImage();
352 void CStageFrightVideoPrivate::GetStagefrightTransformMatrix(float* transformMatrix)
354 mSurfTexture->getTransformMatrix(transformMatrix);