Remove LiveTV menu.
[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 "Application.h"
32 #include "ApplicationMessenger.h"
33 #include "windowing/WindowingFactory.h"
34 #include "settings/AdvancedSettings.h"
35 #include "utils/log.h"
36 #include "threads/Thread.h"
37
38 #include "android/jni/Surface.h"
39 #include "android/jni/SurfaceTexture.h"
40
41 #define CLASSNAME "CStageFrightVideoPrivate"
42
43 GLint glerror;
44 #define CheckEglError(x) while((glerror = eglGetError()) != EGL_SUCCESS) CLog::Log(LOGERROR, "EGL error in %s: %x",x, glerror);
45 #define CheckGlError(x)  while((glerror = glGetError()) != GL_NO_ERROR) CLog::Log(LOGERROR, "GL error in %s: %x",x, glerror);
46
47 // EGL extension functions
48 static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
49 static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
50 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
51
52 int NP2( unsigned x ) {
53   --x;
54   x |= x >> 1;
55   x |= x >> 2;
56   x |= x >> 4;
57   x |= x >> 8;
58   x |= x >> 16;
59   return ++x;
60 }
61
62 CStageFrightVideoPrivate::CStageFrightVideoPrivate()
63     : decode_thread(NULL), source(NULL)
64     , eglDisplay(EGL_NO_DISPLAY), eglSurface(EGL_NO_SURFACE), eglContext(EGL_NO_CONTEXT)
65     , eglInitialized(false)
66     , framecount(0)
67     , quirks(QuirkNone), cur_frame(NULL), prev_frame(NULL)
68     , width(-1), height(-1)
69     , texwidth(-1), texheight(-1)
70     , client(NULL), decoder(NULL), decoder_component(NULL)
71     , drop_state(false), resetting(false)
72 {
73   if (!eglCreateImageKHR)
74     eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglCreateImageKHR");
75   if (!eglDestroyImageKHR)
76     eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) CEGLWrapper::GetProcAddress("eglDestroyImageKHR");
77   if (!glEGLImageTargetTexture2DOES)
78     glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) CEGLWrapper::GetProcAddress("glEGLImageTargetTexture2DOES");
79
80   for (int i=0; i<INBUFCOUNT; ++i)
81     inbuf[i] = NULL;
82 }
83
84 void CStageFrightVideoPrivate::signalBufferReturned(MediaBuffer *buffer)
85 {
86 }
87
88 MediaBuffer* CStageFrightVideoPrivate::getBuffer(size_t size)
89 {
90   int i=0;
91   for (; i<INBUFCOUNT; ++i)
92     if (inbuf[i]->refcount() == 0 && inbuf[i]->size() >= size)
93       break;
94   if (i == INBUFCOUNT)
95   {
96     i = 0;
97     for (; i<INBUFCOUNT; ++i)
98       if (inbuf[i]->refcount() == 0)
99         break;
100     if (i == INBUFCOUNT)
101       return NULL;
102     inbuf[i]->setObserver(NULL);
103     inbuf[i]->release();
104     inbuf[i] = new MediaBuffer(size);
105     inbuf[i]->setObserver(this);
106   }
107
108   inbuf[i]->reset();
109   inbuf[i]->add_ref();
110   return inbuf[i];
111 }
112
113 bool CStageFrightVideoPrivate::inputBufferAvailable()
114 {
115   for (int i=0; i<INBUFCOUNT; ++i)
116     if (inbuf[i]->refcount() == 0)
117       return true;
118
119   return false;
120 }
121
122 stSlot* CStageFrightVideoPrivate::getSlot(EGLImageKHR eglimg)
123 {
124   for (int i=0; i<NUMFBOTEX; ++i)
125     if (texslots[i].eglimg == eglimg)
126       return &(texslots[i]);
127
128   return NULL;
129 }
130
131 stSlot* CStageFrightVideoPrivate::getFreeSlot()
132 {
133   for (int i=0; i<NUMFBOTEX; ++i)
134     if (texslots[i].use_cnt == 0)
135       return &(texslots[i]);
136
137   return NULL;
138 }
139
140 void CStageFrightVideoPrivate::loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader)
141 {
142 #if defined(DEBUG_VERBOSE)
143   CLog::Log(LOGDEBUG, ">>loadOESShader\n");
144 #endif
145
146   GLuint shader = glCreateShader(shaderType);
147   CheckGlError("loadOESShader");
148   if (shader) {
149     glShaderSource(shader, 1, &pSource, NULL);
150     glCompileShader(shader);
151     GLint compiled = 0;
152     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
153     if (!compiled) {
154       GLint infoLen = 0;
155       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
156       if (infoLen) {
157         char* buf = (char*) malloc(infoLen);
158         if (buf) {
159           glGetShaderInfoLog(shader, infoLen, NULL, buf);
160           printf("Shader compile log:\n%s\n", buf);
161           free(buf);
162         }
163       } else {
164         char* buf = (char*) malloc(0x1000);
165         if (buf) {
166           glGetShaderInfoLog(shader, 0x1000, NULL, buf);
167           printf("Shader compile log:\n%s\n", buf);
168           free(buf);
169         }
170       }
171       glDeleteShader(shader);
172       shader = 0;
173     }
174   }
175   *outShader = shader;
176 }
177
178 void CStageFrightVideoPrivate::createOESProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm)
179 {
180 #if defined(DEBUG_VERBOSE)
181   CLog::Log(LOGDEBUG, ">>createOESProgram\n");
182 #endif
183   GLuint vertexShader, fragmentShader;
184   {
185     loadOESShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
186   }
187   {
188     loadOESShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
189   }
190
191   GLuint program = glCreateProgram();
192   if (program) {
193     glAttachShader(program, vertexShader);
194     glAttachShader(program, fragmentShader);
195     glLinkProgram(program);
196     GLint linkStatus = GL_FALSE;
197     glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
198     if (linkStatus != GL_TRUE) {
199       GLint bufLength = 0;
200       glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
201       if (bufLength) {
202         char* buf = (char*) malloc(bufLength);
203         if (buf) {
204           glGetProgramInfoLog(program, bufLength, NULL, buf);
205           printf("Program link log:\n%s\n", buf);
206           free(buf);
207         }
208       }
209       glDeleteProgram(program);
210       program = 0;
211     }
212   }
213   glDeleteShader(vertexShader);
214   glDeleteShader(fragmentShader);
215   *outPgm = program;
216 }
217
218 void CStageFrightVideoPrivate::OES_shader_setUp()
219 {
220
221   const char vsrc[] =
222   "attribute vec4 vPosition;\n"
223   "varying vec2 texCoords;\n"
224   "uniform mat4 texMatrix;\n"
225   "void main() {\n"
226   "  vec2 vTexCoords = 0.5 * (vPosition.xy + vec2(1.0, 1.0));\n"
227   "  texCoords = (texMatrix * vec4(vTexCoords, 0.0, 1.0)).xy;\n"
228   "  gl_Position = vPosition;\n"
229   "}\n";
230
231   const char fsrc[] =
232   "#extension GL_OES_EGL_image_external : require\n"
233   "precision mediump float;\n"
234   "uniform samplerExternalOES texSampler;\n"
235   "varying vec2 texCoords;\n"
236   "void main() {\n"
237   "  gl_FragColor = texture2D(texSampler, texCoords);\n"
238   "}\n";
239
240   {
241   #if defined(DEBUG_VERBOSE)
242     CLog::Log(LOGDEBUG, ">>OES_shader_setUp\n");
243   #endif
244     CheckGlError("OES_shader_setUp");
245     createOESProgram(vsrc, fsrc, &mPgm);
246   }
247
248   mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
249   mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
250   mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
251 }
252
253 void CStageFrightVideoPrivate::InitializeEGL(int w, int h)
254 {
255 #if defined(DEBUG_VERBOSE)
256   CLog::Log(LOGDEBUG, "%s: >>> InitializeEGL: w:%d; h:%d\n", CLASSNAME, w, h);
257 #endif
258   texwidth = w;
259   texheight = h;
260   if (!m_g_Windowing->IsExtSupported("GL_TEXTURE_NPOT"))
261   {
262     texwidth  = NP2(texwidth);
263     texheight = NP2(texheight);
264   }
265
266   eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
267   if (eglDisplay == EGL_NO_DISPLAY)
268     CLog::Log(LOGERROR, "%s: InitializeEGL: no display\n", CLASSNAME);
269   eglBindAPI(EGL_OPENGL_ES_API);
270   EGLint contextAttributes[] = {
271     EGL_CONTEXT_CLIENT_VERSION, 2,
272     EGL_NONE
273   };
274   eglContext = eglCreateContext(eglDisplay, m_g_Windowing->GetEGLConfig(), EGL_NO_CONTEXT, contextAttributes);
275   EGLint pbufferAttribs[] = {
276     EGL_WIDTH, texwidth,
277     EGL_HEIGHT, texheight,
278     EGL_NONE
279   };
280   eglSurface = eglCreatePbufferSurface(eglDisplay, m_g_Windowing->GetEGLConfig(), pbufferAttribs);
281   eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
282   CheckGlError("stf init");
283
284   static const EGLint imageAttributes[] = {
285     EGL_IMAGE_PRESERVED_KHR, EGL_FALSE,
286     EGL_GL_TEXTURE_LEVEL_KHR, 0,
287     EGL_NONE
288   };
289
290   for (int i=0; i<NUMFBOTEX; ++i)
291   {
292     glGenTextures(1, &(texslots[i].texid));
293     glBindTexture(GL_TEXTURE_2D,  texslots[i].texid);
294
295     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texheight, 0,
296            GL_RGBA, GL_UNSIGNED_BYTE, 0);
297
298     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
299     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
300     // This is necessary for non-power-of-two textures
301     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
302     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
303
304     texslots[i].eglimg = eglCreateImageKHR(eglDisplay, eglContext, EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(texslots[i].texid),imageAttributes);
305     texslots[i].use_cnt = 0;
306   }
307   glBindTexture(GL_TEXTURE_2D,  0);
308
309   fbo.Initialize();
310   OES_shader_setUp();
311
312   eglInitialized = true;
313 #if defined(DEBUG_VERBOSE)
314   CLog::Log(LOGDEBUG, "%s: <<< InitializeEGL: w:%d; h:%d\n", CLASSNAME, texwidth, texheight);
315 #endif
316 }
317
318 void CStageFrightVideoPrivate::ReleaseEGL()
319 {
320 #if defined(DEBUG_VERBOSE)
321   CLog::Log(LOGDEBUG, "%s: >>> UninitializeEGL\n", CLASSNAME);
322 #endif
323   fbo.Cleanup();
324   for (int i=0; i<NUMFBOTEX; ++i)
325   {
326     glDeleteTextures(1, &(texslots[i].texid));
327     eglDestroyImageKHR(eglDisplay, texslots[i].eglimg);
328   }
329
330   if (eglContext != EGL_NO_CONTEXT)
331     eglDestroyContext(eglDisplay, eglContext);
332   eglContext = EGL_NO_CONTEXT;
333
334   if (eglSurface != EGL_NO_SURFACE)
335     eglDestroySurface(eglDisplay, eglSurface);
336   eglSurface = EGL_NO_SURFACE;
337
338   eglInitialized = false;
339 }
340
341 void CStageFrightVideoPrivate::CallbackInitSurfaceTexture(void *userdata)
342 {
343   CStageFrightVideoPrivate *ctx = static_cast<CStageFrightVideoPrivate*>(userdata);
344   ctx->InitSurfaceTexture();
345 }
346
347 bool CStageFrightVideoPrivate::InitSurfaceTexture()
348 {
349 #if defined(DEBUG_VERBOSE)
350   CLog::Log(LOGDEBUG, "%s: >>> InitSurfaceTexture\n", CLASSNAME);
351 #endif
352    if (mVideoNativeWindow != NULL)
353     return false;
354
355    //FIXME: Playing back-to-back vids induces a bug when properly generating textures between runs.
356    //       Symptoms are upside down vid, "updateTexImage: error binding external texture" in log, and crash
357    //       after stopping.
358    //       Workaround is to always use the same, arbitrary chosen, texture ids.
359   mVideoTextureId = 0xbaad;
360
361   glBindTexture(  GL_TEXTURE_EXTERNAL_OES, mVideoTextureId);
362   glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
363   glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
364   glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
365   glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
366   glBindTexture(  GL_TEXTURE_EXTERNAL_OES, 0);
367
368   mSurfTexture = new CJNISurfaceTexture(mVideoTextureId);
369   mSurface = new CJNISurface(*mSurfTexture);
370
371   JNIEnv* env = xbmc_jnienv();
372   mVideoNativeWindow = ANativeWindow_fromSurface(env, mSurface->get_raw());
373   native_window_api_connect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
374
375 #if defined(DEBUG_VERBOSE)
376   CLog::Log(LOGDEBUG, "%s: <<< InitSurfaceTexture texid(%d) natwin(%p)\n", CLASSNAME, mVideoTextureId, mVideoNativeWindow.get());
377 #endif
378
379   return true;
380 }
381
382 void CStageFrightVideoPrivate::ReleaseSurfaceTexture()
383 {
384 #if defined(DEBUG_VERBOSE)
385   CLog::Log(LOGDEBUG, "%s: >>> ReleaseSurfaceTexture\n", CLASSNAME);
386 #endif
387   if (mVideoNativeWindow == NULL)
388     return;
389
390   native_window_api_disconnect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
391   ANativeWindow_release(mVideoNativeWindow.get());
392   mVideoNativeWindow.clear();
393
394   mSurface->release();
395   mSurfTexture->release();
396
397   delete mSurface;
398   delete mSurfTexture;
399
400 #if defined(DEBUG_VERBOSE)
401   CLog::Log(LOGDEBUG, "%s: <<< ReleaseSurfaceTexture\n", CLASSNAME);
402 #endif
403 }
404
405 void CStageFrightVideoPrivate::UpdateSurfaceTexture()
406 {
407   mSurfTexture->updateTexImage();
408 }
409
410 void CStageFrightVideoPrivate::GetSurfaceTextureTransformMatrix(float* transformMatrix)
411 {
412   mSurfTexture->getTransformMatrix(transformMatrix);
413 }
414