[Confluence] align subtitle popup to the bottom
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / 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 #include "StageFrightVideoPrivate.h"
23
24 #include <EGL/egl.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"
31
32 #include "android/jni/Surface.h"
33 #include "android/jni/SurfaceTexture.h"
34
35 GLint glerror;
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);
38
39 // EGL extension functions
40 static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
41 static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
42 static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
43
44 int NP2( unsigned x ) {
45   --x;
46   x |= x >> 1;
47   x |= x >> 2;
48   x |= x >> 4;
49   x |= x >> 8;
50   x |= x >> 16;
51   return ++x;
52 }
53
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)
58     , framecount(0)
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)
65 {
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");
72 }
73
74 void CStageFrightVideoPrivate::signalBufferReturned(MediaBuffer *buffer)
75 {
76 }
77
78 MediaBuffer* CStageFrightVideoPrivate::getBuffer(size_t size)
79 {
80   int i=0;
81   for (; i<INBUFCOUNT; ++i)
82     if (inbuf[i]->refcount() == 0 && inbuf[i]->size() >= size)
83       break;
84   if (i == INBUFCOUNT)
85   {
86     i = 0;
87     for (; i<INBUFCOUNT; ++i)
88       if (inbuf[i]->refcount() == 0)
89         break;
90     if (i == INBUFCOUNT)
91       return NULL;
92     inbuf[i]->setObserver(NULL);
93     inbuf[i]->release();
94     inbuf[i] = new MediaBuffer(size);
95     inbuf[i]->setObserver(this);
96   }
97
98   inbuf[i]->add_ref();
99   inbuf[i]->set_range(0, size);
100   return inbuf[i];
101 }
102
103 bool CStageFrightVideoPrivate::inputBufferAvailable()
104 {
105   for (int i=0; i<INBUFCOUNT; ++i)
106     if (inbuf[i]->refcount() == 0)
107       return true;
108
109   return false;
110 }
111
112 void CStageFrightVideoPrivate::loadOESShader(GLenum shaderType, const char* pSource, GLuint* outShader)
113 {
114 #if defined(DEBUG_VERBOSE)
115   CLog::Log(LOGDEBUG, ">>loadOESShader\n");
116 #endif
117
118   GLuint shader = glCreateShader(shaderType);
119   CheckGlError("loadOESShader");
120   if (shader) {
121     glShaderSource(shader, 1, &pSource, NULL);
122     glCompileShader(shader);
123     GLint compiled = 0;
124     glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
125     if (!compiled) {
126       GLint infoLen = 0;
127       glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
128       if (infoLen) {
129         char* buf = (char*) malloc(infoLen);
130         if (buf) {
131           glGetShaderInfoLog(shader, infoLen, NULL, buf);
132           printf("Shader compile log:\n%s\n", buf);
133           free(buf);
134         }
135       } else {
136         char* buf = (char*) malloc(0x1000);
137         if (buf) {
138           glGetShaderInfoLog(shader, 0x1000, NULL, buf);
139           printf("Shader compile log:\n%s\n", buf);
140           free(buf);
141         }
142       }
143       glDeleteShader(shader);
144       shader = 0;
145     }
146   }
147   *outShader = shader;
148 }
149
150 void CStageFrightVideoPrivate::createOESProgram(const char* pVertexSource, const char* pFragmentSource, GLuint* outPgm)
151 {
152 #if defined(DEBUG_VERBOSE)
153   CLog::Log(LOGDEBUG, ">>createOESProgram\n");
154 #endif
155   GLuint vertexShader, fragmentShader;
156   {
157     loadOESShader(GL_VERTEX_SHADER, pVertexSource, &vertexShader);
158   }
159   {
160     loadOESShader(GL_FRAGMENT_SHADER, pFragmentSource, &fragmentShader);
161   }
162
163   GLuint program = glCreateProgram();
164   if (program) {
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) {
171       GLint bufLength = 0;
172       glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
173       if (bufLength) {
174         char* buf = (char*) malloc(bufLength);
175         if (buf) {
176           glGetProgramInfoLog(program, bufLength, NULL, buf);
177           printf("Program link log:\n%s\n", buf);
178           free(buf);
179         }
180       }
181       glDeleteProgram(program);
182       program = 0;
183     }
184   }
185   glDeleteShader(vertexShader);
186   glDeleteShader(fragmentShader);
187   *outPgm = program;
188 }
189
190 void CStageFrightVideoPrivate::OES_shader_setUp()
191 {
192
193   const char vsrc[] =
194   "attribute vec4 vPosition;\n"
195   "varying vec2 texCoords;\n"
196   "uniform mat4 texMatrix;\n"
197   "void main() {\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"
201   "}\n";
202
203   const char fsrc[] =
204   "#extension GL_OES_EGL_image_external : require\n"
205   "precision mediump float;\n"
206   "uniform samplerExternalOES texSampler;\n"
207   "varying vec2 texCoords;\n"
208   "void main() {\n"
209   "  gl_FragColor = texture2D(texSampler, texCoords);\n"
210   "}\n";
211
212   {
213   #if defined(DEBUG_VERBOSE)
214     CLog::Log(LOGDEBUG, ">>OES_shader_setUp\n");
215   #endif
216     CheckGlError("OES_shader_setUp");
217     createOESProgram(vsrc, fsrc, &mPgm);
218   }
219
220   mPositionHandle = glGetAttribLocation(mPgm, "vPosition");
221   mTexSamplerHandle = glGetUniformLocation(mPgm, "texSampler");
222   mTexMatrixHandle = glGetUniformLocation(mPgm, "texMatrix");
223 }
224
225 void CStageFrightVideoPrivate::InitializeEGL(int w, int h)
226 {
227   texwidth = w;
228   texheight = h;
229   if (!g_Windowing.IsExtSupported("GL_TEXTURE_NPOT"))
230   {
231     texwidth  = NP2(texwidth);
232     texheight = NP2(texheight);
233   }
234
235   eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
236   eglBindAPI(EGL_OPENGL_ES_API);
237   EGLint contextAttributes[] = {
238     EGL_CONTEXT_CLIENT_VERSION, 2,
239     EGL_NONE
240   };
241   eglContext = eglCreateContext(eglDisplay, g_Windowing.GetEGLConfig(), EGL_NO_CONTEXT, contextAttributes);
242   EGLint pbufferAttribs[] = {
243     EGL_WIDTH, texwidth,
244     EGL_HEIGHT, texheight,
245     EGL_NONE
246   };
247   eglSurface = eglCreatePbufferSurface(eglDisplay, g_Windowing.GetEGLConfig(), pbufferAttribs);
248   eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
249   CheckGlError("stf init");
250
251   static const EGLint imageAttributes[] = {
252     EGL_IMAGE_PRESERVED_KHR, EGL_FALSE,
253     EGL_GL_TEXTURE_LEVEL_KHR, 0,
254     EGL_NONE
255   };
256
257   for (int i=0; i<NUMFBOTEX; ++i)
258   {
259     glGenTextures(1, &(slots[i].texid));
260     glBindTexture(GL_TEXTURE_2D,  slots[i].texid);
261
262     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texheight, 0,
263            GL_RGBA, GL_UNSIGNED_BYTE, 0);
264
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);
270
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));
273
274   }
275   glBindTexture(GL_TEXTURE_2D,  0);
276
277   fbo.Initialize();
278   OES_shader_setUp();
279
280   eglInitialized = true;
281 #if defined(DEBUG_VERBOSE)
282   CLog::Log(LOGDEBUG, "%s: >>> Initialized EGL: w:%d; h:%d\n", CLASSNAME, texwidth, texheight);
283 #endif
284 }
285
286 void CStageFrightVideoPrivate::UninitializeEGL()
287 {
288   fbo.Cleanup();
289   for (int i=0; i<NUMFBOTEX; ++i)
290   {
291     glDeleteTextures(1, &(slots[i].texid));
292     eglDestroyImageKHR(eglDisplay, slots[i].eglimg);
293   }
294
295   if (eglContext != EGL_NO_CONTEXT)
296     eglDestroyContext(eglDisplay, eglContext);
297   eglContext = EGL_NO_CONTEXT;
298
299   if (eglSurface != EGL_NO_SURFACE)
300     eglDestroySurface(eglDisplay, eglSurface);
301   eglSurface = EGL_NO_SURFACE;
302
303   eglInitialized = false;
304 }
305
306 bool CStageFrightVideoPrivate::InitStagefrightSurface()
307 {
308    if (mVideoNativeWindow != NULL)
309     return true;
310
311   JNIEnv* env = xbmc_jnienv();
312
313   mVideoTextureId = -1;
314
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);
322
323   mSurfTexture = new CJNISurfaceTexture(mVideoTextureId);
324   mSurface = new CJNISurface(*mSurfTexture);
325
326   mVideoNativeWindow = ANativeWindow_fromSurface(env, mSurface->get_raw());
327   native_window_api_connect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
328
329   return true;
330 }
331
332 void CStageFrightVideoPrivate::UninitStagefrightSurface()
333 {
334   if (mVideoNativeWindow == NULL)
335     return;
336
337   native_window_api_disconnect(mVideoNativeWindow.get(), NATIVE_WINDOW_API_MEDIA);
338   ANativeWindow_release(mVideoNativeWindow.get());
339   mVideoNativeWindow = NULL;
340
341   delete mSurface;
342   delete mSurfTexture;
343
344   glDeleteTextures(1, &mVideoTextureId);
345 }
346
347 void CStageFrightVideoPrivate::UpdateStagefrightTexture()
348 {
349   mSurfTexture->updateTexImage();
350 }
351
352 void CStageFrightVideoPrivate::GetStagefrightTransformMatrix(float* transformMatrix)
353 {
354     mSurfTexture->getTransformMatrix(transformMatrix);
355 }
356