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