FIX: [stagefright] dyload the whole codec to prevent potential future api breakage
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / libstagefrightICS / StageFrightVideoPrivate.cpp
1 /*
2  *      Copyright (C) 2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20 /***************************************************************************/
21
22 //#define DEBUG_VERBOSE 1
23
24 #include "StageFrightVideoPrivate.h"
25
26 #include <EGL/egl.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"
34
35 #include "android/jni/Surface.h"
36 #include "android/jni/SurfaceTexture.h"
37
38 #define CLASSNAME "CStageFrightVideoPrivate"
39
40 GLint glerror;
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);
43
44 // EGL extension functions
45 static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
46 static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
47 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
48
49 int NP2( unsigned x ) {
50   --x;
51   x |= x >> 1;
52   x |= x >> 2;
53   x |= x >> 4;
54   x |= x >> 8;
55   x |= x >> 16;
56   return ++x;
57 }
58
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)
63     , framecount(0)
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)
69 {
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");
76
77   for (int i=0; i<INBUFCOUNT; ++i)
78     inbuf[i] = NULL;
79 }
80
81 void CStageFrightVideoPrivate::signalBufferReturned(MediaBuffer *buffer)
82 {
83 }
84
85 MediaBuffer* CStageFrightVideoPrivate::getBuffer(size_t size)
86 {
87   int i=0;
88   for (; i<INBUFCOUNT; ++i)
89     if (inbuf[i]->refcount() == 0 && inbuf[i]->size() >= size)
90       break;
91   if (i == INBUFCOUNT)
92   {
93     i = 0;
94     for (; i<INBUFCOUNT; ++i)
95       if (inbuf[i]->refcount() == 0)
96         break;
97     if (i == INBUFCOUNT)
98       return NULL;
99     inbuf[i]->setObserver(NULL);
100     inbuf[i]->release();
101     inbuf[i] = new MediaBuffer(size);
102     inbuf[i]->setObserver(this);
103   }
104
105   inbuf[i]->add_ref();
106   inbuf[i]->set_range(0, size);
107   return inbuf[i];
108 }
109
110 bool CStageFrightVideoPrivate::inputBufferAvailable()
111 {
112   for (int i=0; i<INBUFCOUNT; ++i)
113     if (inbuf[i]->refcount() == 0)
114       return true;
115
116   return false;
117 }
118
119 void CStageFrightVideoPrivate::loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader)
120 {
121 #if defined(DEBUG_VERBOSE)
122   CLog::Log(LOGDEBUG, ">>loadOESShader\n");
123 #endif
124
125   GLuint shader = glCreateShader(shaderType);
126   CheckGlError("loadOESShader");
127   if (shader) {
128     glShaderSource(shader, 1, &pSource, NULL);
129     glCompileShader(shader);
130     GLint compiled = 0;
131     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
132     if (!compiled) {
133       GLint infoLen = 0;
134       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
135       if (infoLen) {
136         char* buf = (char*) malloc(infoLen);
137         if (buf) {
138           glGetShaderInfoLog(shader, infoLen, NULL, buf);
139           printf("Shader compile log:\n%s\n", buf);
140           free(buf);
141         }
142       } else {
143         char* buf = (char*) malloc(0x1000);
144         if (buf) {
145           glGetShaderInfoLog(shader, 0x1000, NULL, buf);
146           printf("Shader compile log:\n%s\n", buf);
147           free(buf);
148         }
149       }
150       glDeleteShader(shader);
151       shader = 0;
152     }
153   }
154   *outShader = shader;
155 }
156
157 void CStageFrightVideoPrivate::createOESProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm)
158 {
159 #if defined(DEBUG_VERBOSE)
160   CLog::Log(LOGDEBUG, ">>createOESProgram\n");
161 #endif
162   GLuint vertexShader, fragmentShader;
163   {
164     loadOESShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
165   }
166   {
167     loadOESShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
168   }
169
170   GLuint program = glCreateProgram();
171   if (program) {
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) {
178       GLint bufLength = 0;
179       glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
180       if (bufLength) {
181         char* buf = (char*) malloc(bufLength);
182         if (buf) {
183           glGetProgramInfoLog(program, bufLength, NULL, buf);
184           printf("Program link log:\n%s\n", buf);
185           free(buf);
186         }
187       }
188       glDeleteProgram(program);
189       program = 0;
190     }
191   }
192   glDeleteShader(vertexShader);
193   glDeleteShader(fragmentShader);
194   *outPgm = program;
195 }
196
197 void CStageFrightVideoPrivate::OES_shader_setUp()
198 {
199
200   const char vsrc[] =
201   "attribute vec4 vPosition;\n"
202   "varying vec2 texCoords;\n"
203   "uniform mat4 texMatrix;\n"
204   "void main() {\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"
208   "}\n";
209
210   const char fsrc[] =
211   "#extension GL_OES_EGL_image_external : require\n"
212   "precision mediump float;\n"
213   "uniform samplerExternalOES texSampler;\n"
214   "varying vec2 texCoords;\n"
215   "void main() {\n"
216   "  gl_FragColor = texture2D(texSampler, texCoords);\n"
217   "}\n";
218
219   {
220   #if defined(DEBUG_VERBOSE)
221     CLog::Log(LOGDEBUG, ">>OES_shader_setUp\n");
222   #endif
223     CheckGlError("OES_shader_setUp");
224     createOESProgram(vsrc, fsrc, &mPgm);
225   }
226
227   mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
228   mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
229   mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
230 }
231
232 void CStageFrightVideoPrivate::InitializeEGL(int w, int h)
233 {
234 #if defined(DEBUG_VERBOSE)
235   CLog::Log(LOGDEBUG, "%s: >>> InitializeEGL: w:%d; h:%d\n", CLASSNAME, w, h);
236 #endif
237   texwidth = w;
238   texheight = h;
239   if (!m_g_Windowing->IsExtSupported("GL_TEXTURE_NPOT"))
240   {
241     texwidth  = NP2(texwidth);
242     texheight = NP2(texheight);
243   }
244
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,
251     EGL_NONE
252   };
253   eglContext = eglCreateContext(eglDisplay, m_g_Windowing->GetEGLConfig(), EGL_NO_CONTEXT, contextAttributes);
254   EGLint pbufferAttribs[] = {
255     EGL_WIDTH, texwidth,
256     EGL_HEIGHT, texheight,
257     EGL_NONE
258   };
259   eglSurface = eglCreatePbufferSurface(eglDisplay, m_g_Windowing->GetEGLConfig(), pbufferAttribs);
260   eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
261   CheckGlError("stf init");
262
263   static const EGLint imageAttributes[] = {
264     EGL_IMAGE_PRESERVED_KHR, EGL_FALSE,
265     EGL_GL_TEXTURE_LEVEL_KHR, 0,
266     EGL_NONE
267   };
268
269   for (int i=0; i<NUMFBOTEX; ++i)
270   {
271     glGenTextures(1, &(slots[i].texid));
272     glBindTexture(GL_TEXTURE_2D,  slots[i].texid);
273
274     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texheight, 0,
275            GL_RGBA, GL_UNSIGNED_BYTE, 0);
276
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);
282
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));
285
286   }
287   glBindTexture(GL_TEXTURE_2D,  0);
288
289   fbo.Initialize();
290   OES_shader_setUp();
291
292   eglInitialized = true;
293 #if defined(DEBUG_VERBOSE)
294   CLog::Log(LOGDEBUG, "%s: <<< InitializeEGL: w:%d; h:%d\n", CLASSNAME, texwidth, texheight);
295 #endif
296 }
297
298 void CStageFrightVideoPrivate::UninitializeEGL()
299 {
300 #if defined(DEBUG_VERBOSE)
301   CLog::Log(LOGDEBUG, "%s: >>> UninitializeEGL\n", CLASSNAME);
302 #endif
303   fbo.Cleanup();
304   for (int i=0; i<NUMFBOTEX; ++i)
305   {
306     glDeleteTextures(1, &(slots[i].texid));
307     eglDestroyImageKHR(eglDisplay, slots[i].eglimg);
308   }
309
310   if (eglContext != EGL_NO_CONTEXT)
311     eglDestroyContext(eglDisplay, eglContext);
312   eglContext = EGL_NO_CONTEXT;
313
314   if (eglSurface != EGL_NO_SURFACE)
315     eglDestroySurface(eglDisplay, eglSurface);
316   eglSurface = EGL_NO_SURFACE;
317
318   eglInitialized = false;
319 }
320
321 bool CStageFrightVideoPrivate::InitStagefrightSurface()
322 {
323 #if defined(DEBUG_VERBOSE)
324   CLog::Log(LOGDEBUG, "%s: >>> InitStagefrightSurface\n", CLASSNAME);
325 #endif
326    if (mVideoNativeWindow != NULL)
327     return true;
328
329   mVideoTextureId = -1;
330
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);
338
339   mSurfTexture = new CJNISurfaceTexture(mVideoTextureId);
340   mSurface = new CJNISurface(*mSurfTexture);
341
342   JNIEnv* env = xbmc_jnienv();
343   mVideoNativeWindow = ANativeWindow_fromSurface(env, mSurface->get_raw());
344   native_window_api_connect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
345
346 #if defined(DEBUG_VERBOSE)
347   CLog::Log(LOGDEBUG, "%s: <<< InitStagefrightSurface\n", CLASSNAME);
348 #endif
349   return true;
350 }
351
352 void CStageFrightVideoPrivate::UninitStagefrightSurface()
353 {
354 #if defined(DEBUG_VERBOSE)
355   CLog::Log(LOGDEBUG, "%s: >>> UninitStagefrightSurface\n", CLASSNAME);
356 #endif
357   if (mVideoNativeWindow == NULL)
358     return;
359
360   native_window_api_disconnect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
361   ANativeWindow_release(mVideoNativeWindow.get());
362   mVideoNativeWindow = NULL;
363
364   mSurface->release();
365   mSurfTexture->release();
366
367   delete mSurface;
368   delete mSurfTexture;
369
370   glDeleteTextures(1, &mVideoTextureId);
371 #if defined(DEBUG_VERBOSE)
372   CLog::Log(LOGDEBUG, "%s: <<< UninitStagefrightSurface\n", CLASSNAME);
373 #endif
374 }
375
376 void CStageFrightVideoPrivate::UpdateStagefrightTexture()
377 {
378   mSurfTexture->updateTexImage();
379 }
380
381 void CStageFrightVideoPrivate::GetStagefrightTransformMatrix(float* transformMatrix)
382 {
383   mSurfTexture->getTransformMatrix(transformMatrix);
384 }
385