Merge pull request #3332 from ace20022/cximage_fixes
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / StageFrightVideo.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 "system.h"
25 #include "system_gl.h"
26
27 #include "StageFrightVideo.h"
28 #include "StageFrightVideoPrivate.h"
29
30 #include "guilib/GraphicContext.h"
31 #include "DVDClock.h"
32 #include "utils/log.h"
33 #include "utils/fastmemcpy.h"
34 #include "threads/Thread.h"
35 #include "threads/Event.h"
36 #include "settings/AdvancedSettings.h"
37
38 #include "xbmc/guilib/FrameBufferObject.h"
39
40 #include <EGL/egl.h>
41 #include <EGL/eglext.h>
42 #include "windowing/egl/EGLWrapper.h"
43
44 #include <new>
45
46 #define OMX_QCOM_COLOR_FormatYVU420SemiPlanar 0x7FA30C00
47 #define OMX_TI_COLOR_FormatYUV420PackedSemiPlanar 0x7F000100
48
49 #define CLASSNAME "CStageFrightVideo"
50
51 #define EGL_NATIVE_BUFFER_ANDROID 0x3140
52 #define EGL_IMAGE_PRESERVED_KHR   0x30D2
53
54 const char *MEDIA_MIMETYPE_VIDEO_WMV  = "video/x-ms-wmv";
55
56 using namespace android;
57
58 static int64_t pts_dtoi(double pts)
59 {
60   return (int64_t)(pts);
61 }
62
63 static double pts_itod(int64_t pts)
64 {
65   return (double)pts;
66 }
67
68 /***********************************************************/
69
70 class CStageFrightMediaSource : public MediaSource
71 {
72 public:
73   CStageFrightMediaSource(CStageFrightVideoPrivate *priv, sp<MetaData> meta)
74   {
75     p = priv;
76     source_meta = meta;
77   }
78
79   virtual sp<MetaData> getFormat()
80   {
81     return source_meta;
82   }
83
84   virtual status_t start(MetaData *params)
85   {
86     return OK;
87   }
88
89   virtual status_t stop()
90   {
91     return OK;
92   }
93
94   virtual status_t read(MediaBuffer **buffer,
95                         const MediaSource::ReadOptions *options)
96   {
97     Frame *frame;
98     status_t ret;
99     *buffer = NULL;
100     int64_t time_us = -1;
101     MediaSource::ReadOptions::SeekMode mode;
102
103     if (options && options->getSeekTo(&time_us, &mode))
104     {
105 #if defined(DEBUG_VERBOSE)
106       CLog::Log(LOGDEBUG, "%s: reading source(%d): seek:%llu\n", CLASSNAME,p->in_queue.size(), time_us);
107 #endif
108     }
109     else
110     {
111 #if defined(DEBUG_VERBOSE)
112       CLog::Log(LOGDEBUG, "%s: reading source(%d)\n", CLASSNAME,p->in_queue.size());
113 #endif
114     }
115
116     p->in_mutex.lock();
117     while (p->in_queue.empty() && p->decode_thread)
118       p->in_condition.wait(p->in_mutex);
119
120     if (p->in_queue.empty())
121     {
122       p->in_mutex.unlock();
123       return VC_ERROR;
124     }
125
126     std::map<int64_t,Frame*>::iterator it = p->in_queue.begin();
127     frame = it->second;
128     ret = frame->status;
129     *buffer = frame->medbuf;
130
131     p->in_queue.erase(it);
132     p->in_mutex.unlock();
133
134 #if defined(DEBUG_VERBOSE)
135     CLog::Log(LOGDEBUG, ">>> exiting reading source(%d); pts:%llu\n", p->in_queue.size(),frame->pts);
136 #endif
137
138     free(frame);
139
140     return ret;
141   }
142
143 private:
144   sp<MetaData> source_meta;
145   CStageFrightVideoPrivate *p;
146 };
147
148 /********************************************/
149
150 class CStageFrightDecodeThread : public CThread
151 {
152 protected:
153   CStageFrightVideoPrivate *p;
154
155 public:
156   CStageFrightDecodeThread(CStageFrightVideoPrivate *priv)
157   : CThread("CStageFrightDecodeThread")
158   , p(priv)
159   {}
160
161   void OnStartup()
162   {
163   #if defined(DEBUG_VERBOSE)
164     CLog::Log(LOGDEBUG, "%s: entering decode thread\n", CLASSNAME);
165   #endif
166   }
167
168   void OnExit()
169   {
170   #if defined(DEBUG_VERBOSE)
171     CLog::Log(LOGDEBUG, "%s: exited decode thread\n", CLASSNAME);
172   #endif
173   }
174
175   void Process()
176   {
177     Frame* frame;
178     int32_t w, h, dw, dh;
179     int decode_done = 0;
180     int32_t keyframe = 0;
181     int32_t unreadable = 0;
182     MediaSource::ReadOptions readopt;
183     // GLuint texid;
184
185     //SetPriority(THREAD_PRIORITY_ABOVE_NORMAL);
186     do
187     {
188       #if defined(DEBUG_VERBOSE)
189       unsigned int time = XbmcThreads::SystemClockMillis();
190       CLog::Log(LOGDEBUG, "%s: >>> Handling frame\n", CLASSNAME);
191       #endif
192       p->cur_frame = NULL;
193       frame = (Frame*)malloc(sizeof(Frame));
194       if (!frame)
195       {
196         decode_done   = 1;
197         continue;
198       }
199
200       frame->eglimg = EGL_NO_IMAGE_KHR;
201       frame->medbuf = NULL;
202       if (p->resetting)
203       {
204         readopt.setSeekTo(0);
205         p->resetting = false;
206       }
207       frame->status = p->decoder->read(&frame->medbuf, &readopt);
208       readopt.clearSeekTo();
209
210       if (frame->status == OK)
211       {
212         if (!frame->medbuf->graphicBuffer().get())  // hw buffers
213         {
214           if (frame->medbuf->range_length() == 0)
215           {
216             CLog::Log(LOGERROR, "%s - Invalid buffer\n", CLASSNAME);
217             frame->status = VC_ERROR;
218             decode_done   = 1;
219             frame->medbuf->release();
220             frame->medbuf = NULL;
221           }
222           else
223             frame->format = RENDER_FMT_YUV420P;
224         }
225         else
226           frame->format = RENDER_FMT_EGLIMG;
227       }
228
229       if (frame->status == OK)
230       {
231         sp<MetaData> outFormat = p->decoder->getFormat();
232         outFormat->findInt32(kKeyWidth , &w);
233         outFormat->findInt32(kKeyHeight, &h);
234
235         if (!outFormat->findInt32(kKeyDisplayWidth , &dw))
236           dw = w;
237         if (!outFormat->findInt32(kKeyDisplayHeight, &dh))
238           dh = h;
239
240         if (!outFormat->findInt32(kKeyIsSyncFrame, &keyframe))
241           keyframe = 0;
242         if (!outFormat->findInt32(kKeyIsUnreadable, &unreadable))
243           unreadable = 0;
244
245         frame->pts = 0;
246
247         // The OMX.SEC decoder doesn't signal the modified width/height
248         if (p->decoder_component && !strncmp(p->decoder_component, "OMX.SEC", 7) &&
249           (w & 15 || h & 15))
250         {
251           if (((w + 15)&~15) * ((h + 15)&~15) * 3/2 == frame->medbuf->range_length())
252           {
253             w = (w + 15)&~15;
254             h = (h + 15)&~15;
255           }
256         }
257         frame->width = w;
258         frame->height = h;
259         frame->medbuf->meta_data()->findInt64(kKeyTime, &(frame->pts));
260       }
261       else if (frame->status == INFO_FORMAT_CHANGED)
262       {
263         int32_t cropLeft, cropTop, cropRight, cropBottom;
264         sp<MetaData> outFormat = p->decoder->getFormat();
265
266         outFormat->findInt32(kKeyWidth , &p->width);
267         outFormat->findInt32(kKeyHeight, &p->height);
268
269         cropLeft = cropTop = cropRight = cropBottom = 0;
270        if (!outFormat->findRect(kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom))
271         {
272           p->x = 0;
273           p->y = 0;
274         }
275         else
276         {
277           p->x = cropLeft;
278           p->y = cropTop;
279           p->width = cropRight - cropLeft + 1;
280           p->height = cropBottom - cropTop + 1;
281         }
282         outFormat->findInt32(kKeyColorFormat, &p->videoColorFormat);
283         if (!outFormat->findInt32(kKeyStride, &p->videoStride))
284           p->videoStride = p->width;
285         if (!outFormat->findInt32(kKeySliceHeight, &p->videoSliceHeight))
286           p->videoSliceHeight = p->height;
287
288 #if defined(DEBUG_VERBOSE)
289         CLog::Log(LOGDEBUG, ">>> new format col:%d, w:%d, h:%d, sw:%d, sh:%d, ctl:%d,%d; cbr:%d,%d\n", p->videoColorFormat, p->width, p->height, p->videoStride, p->videoSliceHeight, cropTop, cropLeft, cropBottom, cropRight);
290 #endif
291
292         if (frame->medbuf)
293           frame->medbuf->release();
294         frame->medbuf = NULL;
295         free(frame);
296         continue;
297       }
298       else
299       {
300         CLog::Log(LOGERROR, "%s - decoding error (%d)\n", CLASSNAME,frame->status);
301         if (frame->medbuf)
302           frame->medbuf->release();
303         frame->medbuf = NULL;
304         free(frame);
305         continue;
306       }
307
308       if (frame->format == RENDER_FMT_EGLIMG)
309       {
310         if (!p->eglInitialized)
311         {
312           p->InitializeEGL(frame->width, frame->height);
313         }
314         else if (p->texwidth != frame->width || p->texheight != frame->height)
315         {
316           p->UninitializeEGL();
317           p->InitializeEGL(frame->width, frame->height);
318         }
319
320         if (p->free_queue.empty())
321         {
322           CLog::Log(LOGERROR, "%s::%s - Error: No free output buffers\n", CLASSNAME, __func__);
323           if (frame->medbuf)
324             frame->medbuf->release();
325           free(frame);
326           continue;
327         }
328
329         ANativeWindowBuffer* graphicBuffer = frame->medbuf->graphicBuffer()->getNativeBuffer();
330         native_window_set_buffers_timestamp(p->mVideoNativeWindow.get(), frame->pts * 1000);
331         int err = p->mVideoNativeWindow.get()->queueBuffer(p->mVideoNativeWindow.get(), graphicBuffer);
332         if (err == 0)
333           frame->medbuf->meta_data()->setInt32(kKeyRendered, 1);
334         frame->medbuf->release();
335         frame->medbuf = NULL;
336         p->UpdateStagefrightTexture();
337
338         if (!p->drop_state)
339         {
340           p->free_mutex.lock();
341           while (!p->free_queue.size())
342             usleep(10000);
343           std::list<std::pair<EGLImageKHR, int> >::iterator itfree = p->free_queue.begin();
344           int cur_slot = itfree->second;
345           p->fbo.BindToTexture(GL_TEXTURE_2D, p->slots[cur_slot].texid);
346           p->fbo.BeginRender();
347
348           glDisable(GL_DEPTH_TEST);
349           //glClear(GL_COLOR_BUFFER_BIT);
350
351           const GLfloat triangleVertices[] = {
352           -1.0f, 1.0f,
353           -1.0f, -1.0f,
354           1.0f, -1.0f,
355           1.0f, 1.0f,
356           };
357
358           glVertexAttribPointer(p->mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices);
359           glEnableVertexAttribArray(p->mPositionHandle);
360
361           glUseProgram(p->mPgm);
362           glUniform1i(p->mTexSamplerHandle, 0);
363
364           glBindTexture(GL_TEXTURE_EXTERNAL_OES, p->mVideoTextureId);
365
366           GLfloat texMatrix[16];
367           // const GLfloat texMatrix[] = {
368             // 1, 0, 0, 0,
369             // 0, -1, 0, 0,
370             // 0, 0, 1, 0,
371             // 0, 1, 0, 1
372           // };
373           p->GetStagefrightTransformMatrix(texMatrix);
374           glUniformMatrix4fv(p->mTexMatrixHandle, 1, GL_FALSE, texMatrix);
375
376           glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
377
378           glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
379           // glDeleteTextures(1, &texid);
380           // eglDestroyImageKHR(p->eglDisplay, img);
381           p->fbo.EndRender();
382
383           glBindTexture(GL_TEXTURE_2D, 0);
384
385           frame->eglimg = p->slots[cur_slot].eglimg;
386           p->busy_queue.push_back(std::pair<EGLImageKHR, int>(*itfree));
387           p->free_queue.erase(itfree);
388           p->free_mutex.unlock();
389         }
390       }
391
392     #if defined(DEBUG_VERBOSE)
393       CLog::Log(LOGDEBUG, "%s: >>> pushed OUT frame; w:%d, h:%d, dw:%d, dh:%d, kf:%d, ur:%d, img:%p, tm:%d\n", CLASSNAME, frame->width, frame->height, dw, dh, keyframe, unreadable, frame->eglimg, XbmcThreads::SystemClockMillis() - time);
394     #endif
395
396       p->out_mutex.lock();
397       p->cur_frame = frame;
398       while (p->cur_frame)
399         p->out_condition.wait(p->out_mutex);
400       p->out_mutex.unlock();
401     }
402     while (!decode_done && !m_bStop);
403
404     if (p->eglInitialized)
405       p->UninitializeEGL();
406
407   }
408 };
409
410 /***********************************************************/
411
412 bool CStageFrightVideo::Open(CDVDStreamInfo &hints)
413 {
414 #if defined(DEBUG_VERBOSE)
415   CLog::Log(LOGDEBUG, "%s::Open\n", CLASSNAME);
416 #endif
417
418   CSingleLock lock(g_graphicsContext);
419
420   // stagefright crashes with null size. Trap this...
421   if (!hints.width || !hints.height)
422   {
423     CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"null size, cannot handle");
424     return false;
425   }
426
427   p = new CStageFrightVideoPrivate;
428   p->width     = hints.width;
429   p->height    = hints.height;
430
431   if (g_advancedSettings.m_stagefrightConfig.useSwRenderer)
432     p->quirks |= QuirkSWRender;
433
434   sp<MetaData> outFormat;
435   int32_t cropLeft, cropTop, cropRight, cropBottom;
436   //Vector<String8> matchingCodecs;
437
438   p->meta = new MetaData;
439   if (p->meta == NULL)
440   {
441     goto fail;
442   }
443
444   const char* mimetype;
445   switch (hints.codec)
446   {
447   case CODEC_ID_H264:
448     if (g_advancedSettings.m_stagefrightConfig.useAVCcodec == 0)
449       return false;
450     mimetype = MEDIA_MIMETYPE_VIDEO_AVC;
451     if ( *(char*)hints.extradata == 1 )
452       p->meta->setData(kKeyAVCC, kTypeAVCC, hints.extradata, hints.extrasize);
453     break;
454   case CODEC_ID_MPEG4:
455     if (g_advancedSettings.m_stagefrightConfig.useMP4codec == 0)
456       return false;
457     mimetype = MEDIA_MIMETYPE_VIDEO_MPEG4;
458     break;
459   case CODEC_ID_MPEG2VIDEO:
460     if (g_advancedSettings.m_stagefrightConfig.useMPEG2codec == 0)
461       return false;
462     mimetype = MEDIA_MIMETYPE_VIDEO_MPEG2;
463     break;
464   case CODEC_ID_VP3:
465   case CODEC_ID_VP6:
466   case CODEC_ID_VP6F:
467   case CODEC_ID_VP8:
468     if (g_advancedSettings.m_stagefrightConfig.useVPXcodec == 0)
469       return false;
470     mimetype = MEDIA_MIMETYPE_VIDEO_VPX;
471     break;
472   case CODEC_ID_VC1:
473   case CODEC_ID_WMV3:
474     if (g_advancedSettings.m_stagefrightConfig.useVC1codec == 0)
475       return false;
476     mimetype = MEDIA_MIMETYPE_VIDEO_WMV;
477     break;
478   default:
479     return false;
480     break;
481   }
482
483   p->meta->setCString(kKeyMIMEType, mimetype);
484   p->meta->setInt32(kKeyWidth, p->width);
485   p->meta->setInt32(kKeyHeight, p->height);
486
487   android::ProcessState::self()->startThreadPool();
488
489   p->source    = new CStageFrightMediaSource(p, p->meta);
490   p->client    = new OMXClient;
491
492   if (p->source == NULL || p->client == NULL)
493   {
494     goto fail;
495   }
496
497   if (p->client->connect() !=  OK)
498   {
499     delete p->client;
500     p->client = NULL;
501     CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Cannot connect OMX client");
502     goto fail;
503   }
504
505   if ((p->quirks & QuirkSWRender) == 0)
506     p->InitStagefrightSurface();
507
508   p->decoder  = OMXCodec::Create(p->client->interface(), p->meta,
509                                          false, p->source, NULL,
510                                          OMXCodec::kHardwareCodecsOnly | (p->quirks & QuirkSWRender ? OMXCodec::kClientNeedsFramebuffer : 0),
511                                          p->mVideoNativeWindow
512                                          );
513
514   if (!(p->decoder != NULL && p->decoder->start() ==  OK))
515   {
516     p->decoder = NULL;
517     goto fail;
518   }
519
520   outFormat = p->decoder->getFormat();
521
522   if (!outFormat->findInt32(kKeyWidth, &p->width) || !outFormat->findInt32(kKeyHeight, &p->height)
523         || !outFormat->findInt32(kKeyColorFormat, &p->videoColorFormat))
524     goto fail;
525
526   const char *component;
527   if (outFormat->findCString(kKeyDecoderComponent, &component))
528   {
529     CLog::Log(LOGDEBUG, "%s::%s - component: %s\n", CLASSNAME, __func__, component);
530
531     //Blacklist
532     if (!strncmp(component, "OMX.google", 10))
533     {
534       // On some platforms, software decoders are returned anyway
535       CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Blacklisted component (software)");
536       goto fail;
537     }
538     else if (!strncmp(component, "OMX.Nvidia.mp4.decode", 21) && g_advancedSettings.m_stagefrightConfig.useMP4codec != 1)
539     {
540       // Has issues with some XVID encoded MP4. Only fails after actual decoding starts...
541       CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Blacklisted component (MP4)");
542       goto fail;
543     }
544     else if (!strncmp(component, "OMX.rk.", 7))
545     {
546       if (g_advancedSettings.m_stagefrightConfig.useAVCcodec != 1 && g_advancedSettings.m_stagefrightConfig.useMP4codec != 1) 
547       {
548         if (p->width % 32 != 0 || p->height % 16 != 0)
549         {
550           // Buggy. Hard crash on non MOD16 height videos and stride errors for non MOD32 width
551           CLog::Log(LOGERROR, "%s::%s - %s\n", CLASSNAME, __func__,"Blacklisted component (MOD16)");
552           goto fail;
553
554         }
555       }
556     }
557   }
558
559   cropLeft = cropTop = cropRight = cropBottom = 0;
560   if (!outFormat->findRect(kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom))
561   {
562     p->x = 0;
563     p->y = 0;
564   }
565   else
566   {
567     p->x = cropLeft;
568     p->y = cropTop;
569     p->width = cropRight - cropLeft + 1;
570     p->height = cropBottom - cropTop + 1;
571   }
572
573   if (!outFormat->findInt32(kKeyStride, &p->videoStride))
574     p->videoStride = p->width;
575   if (!outFormat->findInt32(kKeySliceHeight, &p->videoSliceHeight))
576     p->videoSliceHeight = p->height;
577
578   for (int i=0; i<INBUFCOUNT; ++i)
579   {
580     p->inbuf[i] = new MediaBuffer(300000);
581     p->inbuf[i]->setObserver(p);
582   }
583
584   p->decode_thread = new CStageFrightDecodeThread(p);
585   p->decode_thread->Create(true /*autodelete*/);
586
587 #if defined(DEBUG_VERBOSE)
588   CLog::Log(LOGDEBUG, ">>> format col:%d, w:%d, h:%d, sw:%d, sh:%d, ctl:%d,%d; cbr:%d,%d\n", p->videoColorFormat, p->width, p->height, p->videoStride, p->videoSliceHeight, cropTop, cropLeft, cropBottom, cropRight);
589 #endif
590
591   return true;
592
593 fail:
594   if (p->decoder != 0)
595     p->decoder->stop();
596   if (p->client)
597   {
598     p->client->disconnect();
599     delete p->client;
600   }
601   if (p->decoder_component)
602     free(&p->decoder_component);
603   if ((p->quirks & QuirkSWRender) == 0)
604     p->UninitStagefrightSurface();
605   return false;
606 }
607
608 /*** Decode ***/
609 int  CStageFrightVideo::Decode(uint8_t *pData, int iSize, double dts, double pts)
610 {
611 #if defined(DEBUG_VERBOSE)
612   unsigned int time = XbmcThreads::SystemClockMillis();
613   CLog::Log(LOGDEBUG, "%s::Decode - d:%p; s:%d; dts:%f; pts:%f\n", CLASSNAME, pData, iSize, dts, pts);
614 #endif
615
616   Frame *frame;
617   int demuxer_bytes = iSize;
618   uint8_t *demuxer_content = pData;
619   int ret = 0;
620
621   if (demuxer_content)
622   {
623     frame = (Frame*)malloc(sizeof(Frame));
624     if (!frame)
625       return VC_ERROR;
626
627     frame->status  = OK;
628     if (g_advancedSettings.m_stagefrightConfig.useInputDTS)
629       frame->pts = (dts != DVD_NOPTS_VALUE) ? pts_dtoi(dts) : ((pts != DVD_NOPTS_VALUE) ? pts_dtoi(pts) : 0);
630     else
631       frame->pts = (pts != DVD_NOPTS_VALUE) ? pts_dtoi(pts) : ((dts != DVD_NOPTS_VALUE) ? pts_dtoi(dts) : 0);
632
633     // No valid pts? libstagefright asserts on this.
634     if (frame->pts < 0)
635     {
636       free(frame);
637       return ret;
638     }
639
640     frame->medbuf = p->getBuffer(demuxer_bytes);
641     if (!frame->medbuf)
642     {
643       free(frame);
644       return VC_ERROR;
645     }
646
647     fast_memcpy(frame->medbuf->data(), demuxer_content, demuxer_bytes);
648     frame->medbuf->meta_data()->clear();
649     frame->medbuf->meta_data()->setInt64(kKeyTime, frame->pts);
650
651     p->in_mutex.lock();
652     p->framecount++;
653     p->in_queue.insert(std::pair<int64_t, Frame*>(p->framecount, frame));
654     p->in_condition.notify();
655     p->in_mutex.unlock();
656   }
657
658   if (p->inputBufferAvailable() && p->in_queue.size() < INBUFCOUNT)
659     ret |= VC_BUFFER;
660   else
661     usleep(1000);
662   if (p->cur_frame != NULL)
663     ret |= VC_PICTURE;
664 #if defined(DEBUG_VERBOSE)
665   CLog::Log(LOGDEBUG, "%s::Decode: pushed IN frame (%d); tm:%d\n", CLASSNAME,p->in_queue.size(), XbmcThreads::SystemClockMillis() - time);
666 #endif
667
668   return ret;
669 }
670
671 bool CStageFrightVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
672 {
673  #if defined(DEBUG_VERBOSE)
674   unsigned int time = XbmcThreads::SystemClockMillis();
675 #endif
676   if (pDvdVideoPicture->format == RENDER_FMT_EGLIMG && pDvdVideoPicture->eglimg != EGL_NO_IMAGE_KHR)
677     ReleaseBuffer(pDvdVideoPicture->eglimg);
678
679   if (p->prev_frame) {
680     if (p->prev_frame->medbuf)
681       p->prev_frame->medbuf->release();
682     free(p->prev_frame);
683     p->prev_frame = NULL;
684   }
685 #if defined(DEBUG_VERBOSE)
686   CLog::Log(LOGDEBUG, "%s::ClearPicture (%d)\n", CLASSNAME, XbmcThreads::SystemClockMillis() - time);
687 #endif
688
689   return true;
690 }
691
692 bool CStageFrightVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
693 {
694 #if defined(DEBUG_VERBOSE)
695   unsigned int time = XbmcThreads::SystemClockMillis();
696   CLog::Log(LOGDEBUG, "%s::GetPicture\n", CLASSNAME);
697   if (p->cycle_time != 0)
698     CLog::Log(LOGDEBUG, ">>> cycle dur:%d\n", XbmcThreads::SystemClockMillis() - p->cycle_time);
699   p->cycle_time = time;
700 #endif
701
702   status_t status;
703
704   p->out_mutex.lock();
705   if (!p->cur_frame)
706   {
707     CLog::Log(LOGERROR, "%s::%s - Error getting frame\n", CLASSNAME, __func__);
708     p->out_condition.notify();
709     p->out_mutex.unlock();
710     return false;
711   }
712
713   Frame *frame = p->cur_frame;
714   status  = frame->status;
715
716   pDvdVideoPicture->format = frame->format;
717   pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
718   pDvdVideoPicture->pts = frame->pts;
719   pDvdVideoPicture->iWidth  = frame->width;
720   pDvdVideoPicture->iHeight = frame->height;
721   pDvdVideoPicture->iDisplayWidth = frame->width;
722   pDvdVideoPicture->iDisplayHeight = frame->height;
723   pDvdVideoPicture->iFlags  = DVP_FLAG_ALLOCATED;
724   pDvdVideoPicture->stf = this;
725   pDvdVideoPicture->eglimg = EGL_NO_IMAGE_KHR;
726
727   if (status != OK)
728   {
729     CLog::Log(LOGERROR, "%s::%s - Error getting picture from frame(%d)\n", CLASSNAME, __func__,status);
730     if (frame->medbuf) {
731       frame->medbuf->release();
732     }
733     free(frame);
734     p->cur_frame = NULL;
735     p->out_condition.notify();
736     p->out_mutex.unlock();
737     return false;
738   }
739
740   if (pDvdVideoPicture->format == RENDER_FMT_EGLIMG)
741   {
742     pDvdVideoPicture->eglimg = frame->eglimg;
743   #if defined(DEBUG_VERBOSE)
744     CLog::Log(LOGDEBUG, ">>> pic dts:%f, pts:%llu, img:%p, tm:%d\n", pDvdVideoPicture->dts, frame->pts, pDvdVideoPicture->eglimg, XbmcThreads::SystemClockMillis() - time);
745   #endif
746   }
747   else if (pDvdVideoPicture->format == RENDER_FMT_YUV420P)
748   {
749     pDvdVideoPicture->color_range  = 0;
750     pDvdVideoPicture->color_matrix = 4;
751
752     unsigned int luma_pixels = frame->width  * frame->height;
753     unsigned int chroma_pixels = luma_pixels/4;
754     uint8_t* data = NULL;
755     if (frame->medbuf && !p->drop_state)
756     {
757       data = (uint8_t*)((long)frame->medbuf->data() + frame->medbuf->range_offset());
758     }
759     switch (p->videoColorFormat)
760     {
761       case OMX_COLOR_FormatYUV420Planar:
762         pDvdVideoPicture->iLineSize[0] = frame->width;
763         pDvdVideoPicture->iLineSize[1] = frame->width / 2;
764         pDvdVideoPicture->iLineSize[2] = frame->width / 2;
765         pDvdVideoPicture->iLineSize[3] = 0;
766         pDvdVideoPicture->data[0] = data;
767         pDvdVideoPicture->data[1] = pDvdVideoPicture->data[0] + luma_pixels;
768         pDvdVideoPicture->data[2] = pDvdVideoPicture->data[1] + chroma_pixels;
769         pDvdVideoPicture->data[3] = 0;
770         break;
771       case OMX_COLOR_FormatYUV420SemiPlanar:
772       case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
773       case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
774         pDvdVideoPicture->iLineSize[0] = frame->width;
775         pDvdVideoPicture->iLineSize[1] = frame->width;
776         pDvdVideoPicture->iLineSize[2] = 0;
777         pDvdVideoPicture->iLineSize[3] = 0;
778         pDvdVideoPicture->data[0] = data;
779         pDvdVideoPicture->data[1] = pDvdVideoPicture->data[0] + luma_pixels;
780         pDvdVideoPicture->data[2] = pDvdVideoPicture->data[1] + chroma_pixels;
781         pDvdVideoPicture->data[3] = 0;
782         break;
783       default:
784         CLog::Log(LOGERROR, "%s::%s - Unsupported color format(%d)\n", CLASSNAME, __func__,p->videoColorFormat);
785     }
786   #if defined(DEBUG_VERBOSE)
787     CLog::Log(LOGDEBUG, ">>> pic pts:%f, data:%p, col:%d, w:%d, h:%d, tm:%d\n", pDvdVideoPicture->pts, data, p->videoColorFormat, frame->width, frame->height, XbmcThreads::SystemClockMillis() - time);
788   #endif
789   }
790
791   if (p->drop_state)
792     pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
793
794   p->prev_frame = p->cur_frame;
795   p->cur_frame = NULL;
796   p->out_condition.notify();
797   p->out_mutex.unlock();
798
799   return true;
800 }
801
802 void CStageFrightVideo::Close()
803 {
804 #if defined(DEBUG_VERBOSE)
805   CLog::Log(LOGDEBUG, "%s::Close\n", CLASSNAME);
806 #endif
807
808   Frame *frame;
809
810   if (p->decode_thread && p->decode_thread->IsRunning())
811     p->decode_thread->StopThread(false);
812   p->decode_thread = NULL;
813   p->in_condition.notify();
814
815   // Give decoder_thread time to process EOS, if stuck on reading
816   usleep(50000);
817
818 #if defined(DEBUG_VERBOSE)
819   CLog::Log(LOGDEBUG, "Cleaning OUT\n");
820 #endif
821   p->out_mutex.lock();
822   if (p->cur_frame)
823   {
824     if (p->cur_frame->medbuf)
825       p->cur_frame->medbuf->release();
826     free(p->cur_frame);
827     p->cur_frame = NULL;
828   }
829   p->out_condition.notify();
830   p->out_mutex.unlock();
831
832   if (p->prev_frame)
833   {
834     if (p->prev_frame->medbuf)
835       p->prev_frame->medbuf->release();
836     free(p->prev_frame);
837     p->prev_frame = NULL;
838   }
839
840 #if defined(DEBUG_VERBOSE)
841   CLog::Log(LOGDEBUG, "Stopping omxcodec\n");
842 #endif
843   p->decoder->stop();
844   p->client->disconnect();
845
846 #if defined(DEBUG_VERBOSE)
847   CLog::Log(LOGDEBUG, "Cleaning IN(%d)\n", p->in_queue.size());
848 #endif
849   std::map<int64_t,Frame*>::iterator it;
850   while (!p->in_queue.empty())
851   {
852     it = p->in_queue.begin();
853     frame = it->second;
854     p->in_queue.erase(it);
855     if (frame->medbuf)
856       frame->medbuf->release();
857     free(frame);
858   }
859
860   if (p->decoder_component)
861     free(&p->decoder_component);
862
863   delete p->client;
864
865   if ((p->quirks & QuirkSWRender) == 0)
866     p->UninitStagefrightSurface();
867
868   for (int i=0; i<INBUFCOUNT; ++i)
869   {
870     p->inbuf[i]->setObserver(NULL);
871     p->inbuf[i]->release();
872   }
873
874   delete p;
875 }
876
877 void CStageFrightVideo::Reset(void)
878 {
879 #if defined(DEBUG_VERBOSE)
880   CLog::Log(LOGDEBUG, "%s::Reset\n", CLASSNAME);
881 #endif
882   Frame* frame;
883   p->in_mutex.lock();
884   std::map<int64_t,Frame*>::iterator it;
885   while (!p->in_queue.empty())
886   {
887     it = p->in_queue.begin();
888     frame = it->second;
889     p->in_queue.erase(it);
890     if (frame->medbuf)
891       frame->medbuf->release();
892     free(frame);
893   }
894   p->resetting = true;
895   p->framecount = 0;
896
897   p->in_mutex.unlock();
898 }
899
900 void CStageFrightVideo::SetDropState(bool bDrop)
901 {
902   if (bDrop == p->drop_state)
903     return;
904
905 #if defined(DEBUG_VERBOSE)
906   CLog::Log(LOGDEBUG, "%s::SetDropState (%d->%d)\n", CLASSNAME,p->drop_state,bDrop);
907 #endif
908
909   p->drop_state = bDrop;
910 }
911
912 void CStageFrightVideo::SetSpeed(int iSpeed)
913 {
914 }
915
916 /***************/
917
918 void CStageFrightVideo::LockBuffer(EGLImageKHR eglimg)
919 {
920  #if defined(DEBUG_VERBOSE)
921   unsigned int time = XbmcThreads::SystemClockMillis();
922 #endif
923   p->free_mutex.lock();
924   std::list<std::pair<EGLImageKHR, int> >::iterator it = p->free_queue.begin();
925   for(;it != p->free_queue.end(); ++it)
926   {
927     if ((*it).first == eglimg)
928       break;
929   }
930   if (it == p->free_queue.end())
931   {
932     p->busy_queue.push_back(std::pair<EGLImageKHR, int>(*it));
933     p->free_mutex.unlock();
934     return;
935   }
936 #if defined(DEBUG_VERBOSE)
937   CLog::Log(LOGDEBUG, "Locking %p: tm:%d\n", eglimg, XbmcThreads::SystemClockMillis() - time);
938 #endif
939
940   p->busy_queue.push_back(std::pair<EGLImageKHR, int>(*it));
941   p->free_queue.erase(it);
942   p->free_mutex.unlock();
943 }
944
945 void CStageFrightVideo::ReleaseBuffer(EGLImageKHR eglimg)
946 {
947  #if defined(DEBUG_VERBOSE)
948   unsigned int time = XbmcThreads::SystemClockMillis();
949 #endif
950   p->free_mutex.lock();
951   int cnt = 0;
952   std::list<std::pair<EGLImageKHR, int> >::iterator it = p->busy_queue.begin();
953   std::list<std::pair<EGLImageKHR, int> >::iterator itfree;
954   for(;it != p->busy_queue.end(); ++it)
955   {
956     if ((*it).first == eglimg)
957     {
958       cnt++;
959       if (cnt==1)
960         itfree = it;
961       else
962         break;
963     }
964   }
965   if (it == p->busy_queue.end() && !cnt)
966   {
967     p->free_mutex.unlock();
968     return;
969   }
970 #if defined(DEBUG_VERBOSE)
971   CLog::Log(LOGDEBUG, "Unlocking %p: tm:%d\n", eglimg, XbmcThreads::SystemClockMillis() - time);
972 #endif
973
974   if (cnt==1)
975   {
976     p->free_queue.push_back(std::pair<EGLImageKHR, int>(*itfree));
977     p->busy_queue.erase(itfree);
978   }
979   p->free_mutex.unlock();
980 }