Merge pull request #4408 from koying/fixamcexynos
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Video / DVDVideoCodecAndroidMediaCodec.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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 // http://developer.android.com/reference/android/media/MediaCodec.html
23 //
24 // Android MediaCodec class can be used to access low-level media codec,
25 // i.e. encoder/decoder components. (android.media.MediaCodec). Requires
26 // SDK16+ which is 4.1 Jellybean and above.
27 //
28
29 #include "DVDVideoCodecAndroidMediaCodec.h"
30
31 #include "Application.h"
32 #include "ApplicationMessenger.h"
33 #include "DVDClock.h"
34 #include "threads/Atomics.h"
35 #include "utils/BitstreamConverter.h"
36 #include "utils/CPUInfo.h"
37 #include "utils/log.h"
38
39 #include "android/jni/ByteBuffer.h"
40 #include "android/jni/MediaCodec.h"
41 #include "android/jni/MediaCrypto.h"
42 #include "android/jni/MediaFormat.h"
43 #include "android/jni/MediaCodecList.h"
44 #include "android/jni/MediaCodecInfo.h"
45 #include "android/jni/Surface.h"
46 #include "android/jni/SurfaceTexture.h"
47 #include "android/activity/AndroidFeatures.h"
48
49 #include <GLES2/gl2.h>
50 #include <GLES2/gl2ext.h>
51
52 static bool CanSurfaceRenderWhiteList(const std::string &name)
53 {
54   // All devices 'should' be capiable of surface rendering
55   // but that seems to be hit or miss as most odd name devices
56   // cannot surface render.
57   static const char *cansurfacerender_decoders[] = {
58     "OMX.Nvidia",
59     "OMX.rk",
60     "OMX.qcom",
61     "OMX.Intel",
62     "OMX.Exynos",
63     NULL
64   };
65   for (const char **ptr = cansurfacerender_decoders; *ptr; ptr++)
66   {
67     if (!strnicmp(*ptr, name.c_str(), strlen(*ptr)))
68       return true;
69   }
70   return false;
71 }
72
73 static bool IsBlacklisted(const std::string &name)
74 {
75   static const char *blacklisted_decoders[] = {
76     // No software decoders
77     "OMX.google",
78     // For Rockchip non-standard components
79     "AVCDecoder",
80     "AVCDecoder_FLASH",
81     "FLVDecoder",
82     "M2VDecoder",
83     "M4vH263Decoder",
84     "RVDecoder",
85     "VC1Decoder",
86     "VPXDecoder",
87     // End of Rockchip
88     NULL
89   };
90   for (const char **ptr = blacklisted_decoders; *ptr; ptr++)
91   {
92     if (!strnicmp(*ptr, name.c_str(), strlen(*ptr)))
93       return true;
94   }
95   return false;
96 }
97
98 static bool IsSupportedColorFormat(int color_format)
99 {
100   static const int supported_colorformats[] = {
101     CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420Planar,
102     CJNIMediaCodecInfoCodecCapabilities::COLOR_TI_FormatYUV420PackedSemiPlanar,
103     CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420SemiPlanar,
104     CJNIMediaCodecInfoCodecCapabilities::COLOR_QCOM_FormatYUV420SemiPlanar,
105     CJNIMediaCodecInfoCodecCapabilities::OMX_QCOM_COLOR_FormatYVU420SemiPlanarInterlace,
106     -1
107   };
108   for (const int *ptr = supported_colorformats; *ptr != -1; ptr++)
109   {
110     if (color_format == *ptr)
111       return true;
112   }
113   return false;
114 }
115
116 /*****************************************************************************/
117 /*****************************************************************************/
118 class CNULL_Listener : public CJNISurfaceTextureOnFrameAvailableListener
119 {
120 public:
121   CNULL_Listener() : CJNISurfaceTextureOnFrameAvailableListener(jni::jhobject(NULL)) {};
122
123 protected:
124   virtual void OnFrameAvailable(CJNISurfaceTexture &surface) {};
125 };
126
127 class CDVDMediaCodecOnFrameAvailable : public CEvent, CJNISurfaceTextureOnFrameAvailableListener
128 {
129 public:
130   CDVDMediaCodecOnFrameAvailable(boost::shared_ptr<CJNISurfaceTexture> &surfaceTexture)
131   : m_surfaceTexture(surfaceTexture)
132   {
133     m_surfaceTexture->setOnFrameAvailableListener(*this);
134   }
135
136   virtual ~CDVDMediaCodecOnFrameAvailable()
137   {
138     // unhook the callback
139     CNULL_Listener null_listener;
140     m_surfaceTexture->setOnFrameAvailableListener(null_listener);
141   }
142
143 protected:
144   virtual void OnFrameAvailable(CJNISurfaceTexture &surface)
145   {
146     Set();
147   }
148
149 private:
150   boost::shared_ptr<CJNISurfaceTexture> m_surfaceTexture;
151
152 };
153
154 /*****************************************************************************/
155 /*****************************************************************************/
156 CDVDMediaCodecInfo::CDVDMediaCodecInfo(
157     int index
158   , unsigned int texture
159   , boost::shared_ptr<CJNIMediaCodec> &codec
160   , boost::shared_ptr<CJNISurfaceTexture> &surfacetexture
161   , boost::shared_ptr<CDVDMediaCodecOnFrameAvailable> &frameready
162 )
163 : m_refs(1)
164 , m_valid(true)
165 , m_index(index)
166 , m_texture(texture)
167 , m_timestamp(0)
168 , m_codec(codec)
169 , m_surfacetexture(surfacetexture)
170 , m_frameready(frameready)
171 {
172   // paranoid checks
173   assert(m_index >= 0);
174   assert(m_texture > 0);
175   assert(m_codec != NULL);
176   assert(m_surfacetexture != NULL);
177   assert(m_frameready != NULL);
178 }
179
180 CDVDMediaCodecInfo::~CDVDMediaCodecInfo()
181 {
182   assert(m_refs == 0);
183 }
184
185 CDVDMediaCodecInfo* CDVDMediaCodecInfo::Retain()
186 {
187   AtomicIncrement(&m_refs);
188
189   return this;
190 }
191
192 long CDVDMediaCodecInfo::Release()
193 {
194   long count = AtomicDecrement(&m_refs);
195   if (count == 0)
196   {
197     ReleaseOutputBuffer(false);
198     delete this;
199   }
200
201   return count;
202 }
203
204 void CDVDMediaCodecInfo::Validate(bool state)
205 {
206   CSingleLock lock(m_section);
207
208   m_valid = state;
209 }
210
211 void CDVDMediaCodecInfo::ReleaseOutputBuffer(bool render)
212 {
213   CSingleLock lock(m_section);
214
215   if (!m_valid)
216     return;
217
218   // release OutputBuffer and render if indicated
219   // then wait for rendered frame to become avaliable.
220
221   if (render)
222     m_frameready->Reset();
223
224   m_codec->releaseOutputBuffer(m_index, render);
225
226   if (xbmc_jnienv()->ExceptionOccurred())
227   {
228     CLog::Log(LOGERROR, "CDVDMediaCodecInfo::ReleaseOutputBuffer "
229       "ExceptionOccurred render(%d)", render);
230     xbmc_jnienv()->ExceptionDescribe();
231     xbmc_jnienv()->ExceptionClear();
232   }
233 }
234
235 int CDVDMediaCodecInfo::GetIndex() const
236 {
237   CSingleLock lock(m_section);
238
239   return m_index;
240 }
241
242 int CDVDMediaCodecInfo::GetTextureID() const
243 {
244   // since m_texture never changes,
245   // we do not need a m_section lock here.
246   return m_texture;
247 }
248
249 void CDVDMediaCodecInfo::GetTransformMatrix(float *textureMatrix)
250 {
251   CSingleLock lock(m_section);
252
253   if (!m_valid)
254     return;
255
256   m_surfacetexture->getTransformMatrix(textureMatrix);
257 }
258
259 void CDVDMediaCodecInfo::UpdateTexImage()
260 {
261   CSingleLock lock(m_section);
262
263   if (!m_valid)
264     return;
265
266   // updateTexImage will check and spew any prior gl errors,
267   // clear them before we call updateTexImage.
268   glGetError();
269
270   // this is key, after calling releaseOutputBuffer, we must
271   // wait a little for MediaCodec to render to the surface.
272   // Then we can updateTexImage without delay. If we do not
273   // wait, then video playback gets jerky. To optomize this,
274   // we hook the SurfaceTexture OnFrameAvailable callback
275   // using CJNISurfaceTextureOnFrameAvailableListener and wait
276   // on a CEvent to fire. 20ms seems to be a good max fallback.
277   m_frameready->WaitMSec(20);
278
279   m_surfacetexture->updateTexImage();
280   if (xbmc_jnienv()->ExceptionOccurred())
281   {
282     CLog::Log(LOGERROR, "CDVDMediaCodecInfo::UpdateTexImage updateTexImage:ExceptionOccurred");
283     xbmc_jnienv()->ExceptionDescribe();
284     xbmc_jnienv()->ExceptionClear();
285   }
286
287   m_timestamp = m_surfacetexture->getTimestamp();
288   if (xbmc_jnienv()->ExceptionOccurred())
289   {
290     CLog::Log(LOGERROR, "CDVDMediaCodecInfo::UpdateTexImage getTimestamp:ExceptionOccurred");
291     xbmc_jnienv()->ExceptionDescribe();
292     xbmc_jnienv()->ExceptionClear();
293   }
294 }
295
296 /*****************************************************************************/
297 /*****************************************************************************/
298 CDVDVideoCodecAndroidMediaCodec::CDVDVideoCodecAndroidMediaCodec()
299 : m_formatname("mediacodec")
300 , m_opened(false)
301 , m_surface(NULL)
302 , m_textureId(0)
303 , m_bitstream(NULL)
304 , m_render_sw(false)
305 {
306   memset(&m_videobuffer, 0x00, sizeof(DVDVideoPicture));
307 }
308
309 CDVDVideoCodecAndroidMediaCodec::~CDVDVideoCodecAndroidMediaCodec()
310 {
311   Dispose();
312 }
313
314 bool CDVDVideoCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
315 {
316   // check for 4.1 Jellybean and above.
317   if (CAndroidFeatures::GetVersion() < 16)
318     return false;
319
320   m_drop = false;
321   m_hints = hints;
322
323   switch(m_hints.codec)
324   {
325     case AV_CODEC_ID_MPEG2VIDEO:
326       m_mime = "video/mpeg2";
327       m_formatname = "amc-mpeg2";
328       break;
329     case AV_CODEC_ID_MPEG4:
330       m_mime = "video/mp4v-es";
331       m_formatname = "amc-mpeg4";
332       break;
333     case AV_CODEC_ID_H263:
334       m_mime = "video/3gpp";
335       m_formatname = "amc-h263";
336       break;
337     case AV_CODEC_ID_VP3:
338     case AV_CODEC_ID_VP6:
339     case AV_CODEC_ID_VP6F:
340     case AV_CODEC_ID_VP8:
341       //m_mime = "video/x-vp6";
342       //m_mime = "video/x-vp7";
343       m_mime = "video/x-vnd.on2.vp8";
344       m_formatname = "amc-vpX";
345       break;
346     case AV_CODEC_ID_AVS:
347     case AV_CODEC_ID_CAVS:
348     case AV_CODEC_ID_H264:
349       m_mime = "video/avc";
350       m_formatname = "amc-h264";
351       // check for h264-avcC and convert to h264-annex-b
352       if (m_hints.extradata && *(uint8_t*)m_hints.extradata == 1)
353       {
354         m_bitstream = new CBitstreamConverter;
355         if (!m_bitstream->Open(m_hints.codec, (uint8_t*)m_hints.extradata, m_hints.extrasize, true))
356         {
357           SAFE_DELETE(m_bitstream);
358           return false;
359         }
360       }
361       break;
362     case AV_CODEC_ID_VC1:
363     case AV_CODEC_ID_WMV3:
364       m_mime = "video/wvc1";
365       //m_mime = "video/wmv9";
366       m_formatname = "amc-vc1";
367       break;
368     default:
369       CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: Unknown hints.codec(%d)", hints.codec);
370       return false;
371       break;
372   }
373
374   // CJNIMediaCodec::createDecoderByXXX doesn't handle errors nicely,
375   // it crashes if the codec isn't found. This is fixed in latest AOSP,
376   // but not in current 4.1 devices. So 1st search for a matching codec, then create it.
377   bool hasSupportedColorFormat = false;
378   int num_codecs = CJNIMediaCodecList::getCodecCount();
379   for (int i = 0; i < num_codecs; i++)
380   {
381     CJNIMediaCodecInfo codec_info = CJNIMediaCodecList::getCodecInfoAt(i);
382     if (codec_info.isEncoder())
383       continue;
384     m_codecname = codec_info.getName();
385     if (IsBlacklisted(m_codecname))
386       continue;
387
388     std::vector<std::string> types = codec_info.getSupportedTypes();
389     // return the 1st one we find, that one is typically 'the best'
390     for (size_t j = 0; j < types.size(); ++j)
391     {
392       if (types[j] == m_mime)
393       {
394         m_codec = boost::shared_ptr<CJNIMediaCodec>(new CJNIMediaCodec(CJNIMediaCodec::createByCodecName(m_codecname)));
395
396         CJNIMediaCodecInfoCodecCapabilities codec_caps = codec_info.getCapabilitiesForType(m_mime);
397         std::vector<int> color_formats = codec_caps.colorFormats();
398
399         // clear any jni exceptions, jni gets upset if we do not.
400         if (xbmc_jnienv()->ExceptionOccurred())
401         {
402           CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Open ExceptionOccurred");
403           xbmc_jnienv()->ExceptionClear();
404           m_codec.reset();
405           continue;
406         }
407         hasSupportedColorFormat = false;
408         for (size_t k = 0; k < color_formats.size(); ++k)
409         {
410           CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::Open "
411             "m_codecname(%s), colorFormat(%d)", m_codecname.c_str(), color_formats[k]);
412           if (IsSupportedColorFormat(color_formats[k]))
413             hasSupportedColorFormat = true;
414         }
415         break;
416       }
417     }
418     if (m_codec)
419       break;
420   }
421   if (!m_codec)
422   {
423     CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec:: Failed to create Android MediaCodec");
424     SAFE_DELETE(m_bitstream);
425     return false;
426   }
427
428   // whitelist of devices that can surface render.
429   m_render_sw = !CanSurfaceRenderWhiteList(m_codecname);
430   if (m_render_sw)
431   {
432     if (!hasSupportedColorFormat)
433     {
434       CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec:: No supported color format");
435       m_codec.reset();
436       SAFE_DELETE(m_bitstream);
437       return false;
438     }
439   }
440
441   if (!ConfigureMediaCodec())
442   {
443     m_codec.reset();
444     SAFE_DELETE(m_bitstream);
445     return false;
446   }
447
448   // setup a YUV420P DVDVideoPicture buffer.
449   // first make sure all properties are reset.
450   memset(&m_videobuffer, 0x00, sizeof(DVDVideoPicture));
451
452   m_videobuffer.dts = DVD_NOPTS_VALUE;
453   m_videobuffer.pts = DVD_NOPTS_VALUE;
454   m_videobuffer.color_range  = 0;
455   m_videobuffer.color_matrix = 4;
456   m_videobuffer.iFlags  = DVP_FLAG_ALLOCATED;
457   m_videobuffer.iWidth  = m_hints.width;
458   m_videobuffer.iHeight = m_hints.height;
459   // these will get reset to crop values later
460   m_videobuffer.iDisplayWidth  = m_hints.width;
461   m_videobuffer.iDisplayHeight = m_hints.height;
462
463   CLog::Log(LOGINFO, "CDVDVideoCodecAndroidMediaCodec:: "
464     "Open Android MediaCodec %s", m_codecname.c_str());
465
466   m_opened = true;
467
468   return m_opened;
469 }
470
471 void CDVDVideoCodecAndroidMediaCodec::Dispose()
472 {
473   m_opened = false;
474
475   // release any retained demux packets
476   while (!m_demux.empty())
477   {
478     amc_demux &demux_pkt = m_demux.front();
479     free(demux_pkt.pData);
480     m_demux.pop();
481   }
482
483   // invalidate any inflight outputbuffers, make sure
484   // m_output is empty so we do not create new ones
485   m_input.clear();
486   m_output.clear();
487   FlushInternal();
488
489   // clear m_videobuffer bits
490   if (m_render_sw)
491   {
492     free(m_videobuffer.data[0]), m_videobuffer.data[0] = NULL;
493     free(m_videobuffer.data[1]), m_videobuffer.data[1] = NULL;
494     free(m_videobuffer.data[2]), m_videobuffer.data[2] = NULL;
495   }
496   m_videobuffer.iFlags = 0;
497   // m_videobuffer.mediacodec is unioned with m_videobuffer.data[0]
498   // so be very careful when and how you touch it.
499   m_videobuffer.mediacodec = NULL;
500
501   if (m_codec)
502   {
503     m_codec->stop();
504     m_codec->release();
505     m_codec.reset();
506   }
507   ReleaseSurfaceTexture();
508
509   SAFE_DELETE(m_bitstream);
510 }
511
512 int CDVDVideoCodecAndroidMediaCodec::Decode(uint8_t *pData, int iSize, double dts, double pts)
513 {
514   // Handle input, add demuxer packet to input queue, we must accept it or
515   // it will be discarded as DVDPlayerVideo has no concept of "try again".
516   // we must return VC_BUFFER or VC_PICTURE, default to VC_BUFFER.
517   int rtn = VC_BUFFER;
518
519   if (!m_opened)
520     return rtn;
521
522   if (m_hints.ptsinvalid)
523     pts = DVD_NOPTS_VALUE;
524
525   // must check for an output picture 1st,
526   // otherwise, mediacodec can stall on some devices.
527   if (GetOutputPicture() > 0)
528     rtn |= VC_PICTURE;
529
530   if (pData)
531   {
532     if (m_bitstream)
533     {
534       m_bitstream->Convert(pData, iSize);
535       iSize = m_bitstream->GetConvertSize();
536       pData = m_bitstream->GetConvertBuffer();
537     }
538
539     // queue demux pkt in case we cannot get an input buffer
540     amc_demux demux_pkt;
541     demux_pkt.dts = dts;
542     demux_pkt.pts = pts;
543     demux_pkt.iSize = iSize;
544     demux_pkt.pData = (uint8_t*)malloc(iSize);
545     memcpy(demux_pkt.pData, pData, iSize);
546     m_demux.push(demux_pkt);
547
548     // try to fetch an input buffer
549     int64_t timeout_us = 5000;
550     int index = m_codec->dequeueInputBuffer(timeout_us);
551     if (index >= 0)
552     {
553       // docs lie, getInputBuffers should be good after
554       // m_codec->start() but the internal refs are not
555       // setup until much later on some devices.
556       if (m_input.empty())
557         m_input = m_codec->getInputBuffers();
558
559       // we have an input buffer, fill it.
560       int size = m_input[index].capacity();
561       // fetch the front demux packet
562       amc_demux &demux_pkt = m_demux.front();
563       if (demux_pkt.iSize > size)
564       {
565         CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Decode, iSize(%d) > size(%d)", iSize, size);
566         demux_pkt.iSize = size;
567       }
568       // fetch a pointer to the ByteBuffer backing store
569       void *dst_ptr = xbmc_jnienv()->GetDirectBufferAddress(m_input[index].get_raw());
570       if (dst_ptr)
571         memcpy(dst_ptr, demux_pkt.pData, demux_pkt.iSize);
572
573       free(demux_pkt.pData);
574       m_demux.pop();
575
576       // Translate from dvdplayer dts/pts to MediaCodec pts,
577       // pts WILL get re-ordered by MediaCodec if needed.
578       // Do not try to pass pts as a unioned double/int64_t,
579       // some android devices will diddle with presentationTimeUs
580       // and you will get NaN back and DVDPlayerVideo will barf.
581       int64_t presentationTimeUs = AV_NOPTS_VALUE;
582       if (demux_pkt.pts != DVD_NOPTS_VALUE)
583         presentationTimeUs = demux_pkt.pts;
584       else if (demux_pkt.dts != DVD_NOPTS_VALUE)
585         presentationTimeUs = demux_pkt.dts;
586 /*
587       CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: "
588         "pts(%f), ipts(%lld), iSize(%d), GetDataSize(%d), loop_cnt(%d)",
589         presentationTimeUs, pts_dtoi(presentationTimeUs), iSize, GetDataSize(), loop_cnt);
590 */
591       int flags = 0;
592       int offset = 0;
593       m_codec->queueInputBuffer(index, offset, demux_pkt.iSize, presentationTimeUs, flags);
594       // clear any jni exceptions, jni gets upset if we do not.
595       if (xbmc_jnienv()->ExceptionOccurred())
596       {
597         CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Decode ExceptionOccurred");
598         xbmc_jnienv()->ExceptionClear();
599       }
600     }
601   }
602
603   return rtn;
604 }
605
606 void CDVDVideoCodecAndroidMediaCodec::Reset()
607 {
608   if (!m_opened)
609     return;
610
611   // dump any pending demux packets
612   while (!m_demux.empty())
613   {
614     amc_demux &demux_pkt = m_demux.front();
615     free(demux_pkt.pData);
616     m_demux.pop();
617   }
618
619   if (m_codec)
620   {
621     // flush all outputbuffers inflight, they will
622     // become invalid on m_codec->flush and generate
623     // a spew of java exceptions if used
624     FlushInternal();
625
626     // now we can flush the actual MediaCodec object
627     m_codec->flush();
628     if (xbmc_jnienv()->ExceptionOccurred())
629     {
630       CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Reset ExceptionOccurred");
631       xbmc_jnienv()->ExceptionClear();
632     }
633
634     // Invalidate our local DVDVideoPicture bits
635     m_videobuffer.pts = DVD_NOPTS_VALUE;
636     if (!m_render_sw)
637       m_videobuffer.mediacodec = NULL;
638   }
639 }
640
641 bool CDVDVideoCodecAndroidMediaCodec::GetPicture(DVDVideoPicture* pDvdVideoPicture)
642 {
643   if (!m_opened)
644     return false;
645
646   *pDvdVideoPicture = m_videobuffer;
647
648   // Invalidate our local DVDVideoPicture bits
649   m_videobuffer.pts = DVD_NOPTS_VALUE;
650   if (!m_render_sw)
651     m_videobuffer.mediacodec = NULL;
652
653   return true;
654 }
655
656 bool CDVDVideoCodecAndroidMediaCodec::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
657 {
658   if (pDvdVideoPicture->format == RENDER_FMT_MEDIACODEC)
659     SAFE_RELEASE(pDvdVideoPicture->mediacodec);
660   memset(pDvdVideoPicture, 0x00, sizeof(DVDVideoPicture));
661
662   return true;
663 }
664
665 void CDVDVideoCodecAndroidMediaCodec::SetDropState(bool bDrop)
666 {
667   m_drop = bDrop;
668   if (m_drop)
669     m_videobuffer.iFlags |=  DVP_FLAG_DROPPED;
670   else
671     m_videobuffer.iFlags &= ~DVP_FLAG_DROPPED;
672 }
673
674 int CDVDVideoCodecAndroidMediaCodec::GetDataSize(void)
675 {
676   // just ignore internal buffering contribution.
677   return 0;
678 }
679
680 double CDVDVideoCodecAndroidMediaCodec::GetTimeSize(void)
681 {
682   // just ignore internal buffering contribution.
683   return 0.0;
684 }
685
686 unsigned CDVDVideoCodecAndroidMediaCodec::GetAllowedReferences()
687 {
688   return 3;
689 }
690
691 void CDVDVideoCodecAndroidMediaCodec::FlushInternal()
692 {
693   // invalidate any existing inflight buffers and create
694   // new ones to match the number of output buffers
695
696   if (m_render_sw)
697     return;
698
699   for (size_t i = 0; i < m_inflight.size(); i++)
700     m_inflight[i]->Validate(false);
701   m_inflight.clear();
702
703   for (size_t i = 0; i < m_output.size(); i++)
704   {
705     m_inflight.push_back(
706       new CDVDMediaCodecInfo(i, m_textureId, m_codec, m_surfaceTexture, m_frameAvailable)
707     );
708   }
709 }
710
711 bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void)
712 {
713   // setup a MediaFormat to match the video content,
714   // used by codec during configure
715   CJNIMediaFormat mediaformat = CJNIMediaFormat::createVideoFormat(
716     m_mime.c_str(), m_hints.width, m_hints.height);
717   // some android devices forget to default the demux input max size
718   mediaformat.setInteger(CJNIMediaFormat::KEY_MAX_INPUT_SIZE, 0);
719
720   // handle codec extradata
721   if (m_hints.extrasize)
722   {
723     size_t size = m_hints.extrasize;
724     void  *src_ptr = m_hints.extradata;
725     if (m_bitstream)
726     {
727       size = m_bitstream->GetExtraSize();
728       src_ptr = m_bitstream->GetExtraData();
729     }
730     // Allocate a byte buffer via allocateDirect in java instead of NewDirectByteBuffer,
731     // since the latter doesn't allocate storage of its own, and we don't know how long
732     // the codec uses the buffer.
733     CJNIByteBuffer bytebuffer = CJNIByteBuffer::allocateDirect(size);
734     void *dts_ptr = xbmc_jnienv()->GetDirectBufferAddress(bytebuffer.get_raw());
735     memcpy(dts_ptr, src_ptr, size);
736     // codec will automatically handle buffers as extradata
737     // using entries with keys "csd-0", "csd-1", etc.
738     mediaformat.setByteBuffer("csd-0", bytebuffer);
739   }
740
741   InitSurfaceTexture();
742
743   // configure and start the codec.
744   // use the MediaFormat that we have setup.
745   // use a null MediaCrypto, our content is not encrypted.
746   // use a null Surface, we will extract the video picture data manually.
747   int flags = 0;
748   CJNIMediaCrypto crypto(jni::jhobject(NULL));
749   // our jni gets upset if we do this a different
750   // way, do not mess with it.
751   if (m_render_sw)
752   {
753     CJNISurface surface(jni::jhobject(NULL));
754     m_codec->configure(mediaformat, surface, crypto, flags);
755   }
756   else
757   {
758     m_codec->configure(mediaformat, *m_surface, crypto, flags);
759   }
760   // always, check/clear jni exceptions.
761   if (xbmc_jnienv()->ExceptionOccurred())
762   {
763     xbmc_jnienv()->ExceptionClear();
764     return false;
765   }
766
767
768   m_codec->start();
769   // always, check/clear jni exceptions.
770   if (xbmc_jnienv()->ExceptionOccurred())
771   {
772     xbmc_jnienv()->ExceptionClear();
773     return false;
774   }
775
776   return true;
777 }
778
779 int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void)
780 {
781   int rtn = 0;
782
783   int64_t timeout_us = 5000;
784   CJNIMediaCodecBufferInfo bufferInfo;
785   int index = m_codec->dequeueOutputBuffer(bufferInfo, timeout_us);
786   if (index >= 0)
787   {
788     if (m_drop)
789     {
790       m_codec->releaseOutputBuffer(index, false);
791       if (xbmc_jnienv()->ExceptionOccurred())
792         xbmc_jnienv()->ExceptionClear();
793       return 0;
794     }
795
796     // some devices will return a valid index
797     // before signaling INFO_OUTPUT_BUFFERS_CHANGED which
798     // is used to setup m_output, D'uh. setup m_output here.
799     if (m_output.empty())
800     {
801       m_output = m_codec->getOutputBuffers();
802       FlushInternal();
803     }
804
805     int flags = bufferInfo.flags();
806     if (flags & CJNIMediaCodec::BUFFER_FLAG_SYNC_FRAME)
807       CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_SYNC_FRAME");
808
809     if (flags & CJNIMediaCodec::BUFFER_FLAG_CODEC_CONFIG)
810       CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_CODEC_CONFIG");
811
812     if (flags & CJNIMediaCodec::BUFFER_FLAG_END_OF_STREAM)
813     {
814       CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_END_OF_STREAM");
815       m_codec->releaseOutputBuffer(index, false);
816       if (xbmc_jnienv()->ExceptionOccurred())
817         xbmc_jnienv()->ExceptionClear();
818       return 0;
819     }
820
821     if (!m_render_sw)
822     {
823       m_videobuffer.mediacodec = m_inflight[index]->Retain();
824       m_videobuffer.mediacodec->Validate(true);
825     }
826     else
827     {
828       int size = bufferInfo.size();
829       int offset = bufferInfo.offset();
830
831       if (!m_output[index].isDirect())
832         CLog::Log(LOGWARNING, "CDVDVideoCodecAndroidMediaCodec:: m_output[index].isDirect == false");
833
834       if (size && m_output[index].capacity())
835       {
836         uint8_t *src_ptr = (uint8_t*)xbmc_jnienv()->GetDirectBufferAddress(m_output[index].get_raw());
837         src_ptr += offset;
838
839         int loop_end = 0;
840         if (m_videobuffer.format == RENDER_FMT_NV12)
841           loop_end = 2;
842         else if (m_videobuffer.format == RENDER_FMT_YUV420P)
843           loop_end = 3;
844
845         for (int i = 0; i < loop_end; i++)
846         {
847           uint8_t *src   = src_ptr + m_src_offset[i];
848           int src_stride = m_src_stride[i];
849           uint8_t *dst   = m_videobuffer.data[i];
850           int dst_stride = m_videobuffer.iLineSize[i];
851
852           int height = m_videobuffer.iHeight;
853           if (i > 0)
854             height = (m_videobuffer.iHeight + 1) / 2;
855
856           if (src_stride == dst_stride)
857             memcpy(dst, src, dst_stride * height);
858           else
859             for (int j = 0; j < height; j++, src += src_stride, dst += dst_stride)
860               memcpy(dst, src, dst_stride);
861         }
862       }
863       m_codec->releaseOutputBuffer(index, false);
864     }
865
866     int64_t pts= bufferInfo.presentationTimeUs();
867     m_videobuffer.dts = DVD_NOPTS_VALUE;
868     m_videobuffer.pts = DVD_NOPTS_VALUE;
869     if (pts != AV_NOPTS_VALUE)
870       m_videobuffer.pts = pts;
871
872 /*
873     CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture "
874       "index(%d), pts(%f)", index, m_videobuffer.pts);
875 */
876     // always, check/clear jni exceptions.
877     if (xbmc_jnienv()->ExceptionOccurred())
878       xbmc_jnienv()->ExceptionClear();
879
880     rtn = 1;
881   }
882   else if (index == CJNIMediaCodec::INFO_OUTPUT_BUFFERS_CHANGED)
883   {
884     m_output = m_codec->getOutputBuffers();
885     FlushInternal();
886   }
887   else if (index == CJNIMediaCodec::INFO_OUTPUT_FORMAT_CHANGED)
888   {
889     OutputFormatChanged();
890   }
891   else if (index == CJNIMediaCodec::INFO_TRY_AGAIN_LATER)
892   {
893     // normal dequeueOutputBuffer timeout, ignore it.
894     rtn = -1;
895   }
896   else
897   {
898     // we should never get here
899     CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture unknown index(%d)", index);
900   }
901
902   return rtn;
903 }
904
905 void CDVDVideoCodecAndroidMediaCodec::OutputFormatChanged(void)
906 {
907   CJNIMediaFormat mediaformat = m_codec->getOutputFormat();
908
909   int width       = mediaformat.getInteger("width");
910   int height      = mediaformat.getInteger("height");
911   int stride      = mediaformat.getInteger("stride");
912   int slice_height= mediaformat.getInteger("slice-height");
913   int color_format= mediaformat.getInteger("color-format");
914   int crop_left   = mediaformat.getInteger("crop-left");
915   int crop_top    = mediaformat.getInteger("crop-top");
916   int crop_right  = mediaformat.getInteger("crop-right");
917   int crop_bottom = mediaformat.getInteger("crop-bottom");
918
919   CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: "
920     "width(%d), height(%d), stride(%d), slice-height(%d), color-format(%d)",
921     width, height, stride, slice_height, color_format);
922   CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: "
923     "crop-left(%d), crop-top(%d), crop-right(%d), crop-bottom(%d)",
924     crop_left, crop_top, crop_right, crop_bottom);
925
926   if (!m_render_sw)
927   {
928     CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: Direct Surface Rendering");
929     m_videobuffer.format = RENDER_FMT_MEDIACODEC;
930   }
931   else
932   {
933     // Android device quirks and fixes
934
935     // Samsung Quirk: ignore width/height/stride/slice: http://code.google.com/p/android/issues/detail?id=37768#c3
936     if (strstr(m_codecname.c_str(), "OMX.SEC.avc.dec") != NULL || strstr(m_codecname.c_str(), "OMX.SEC.avcdec") != NULL)
937     {
938       width = stride = m_hints.width;
939       height = slice_height = m_hints.height;
940     }
941     if (stride <= width)
942         stride = width;
943     if (slice_height <= height)
944     {
945       slice_height = height;
946       if (color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420Planar)
947       {
948         // NVidia Tegra 3 on Nexus 7 does not set slice_heights
949         if (strstr(m_codecname.c_str(), "OMX.Nvidia.") != NULL)
950         {
951           slice_height = (((height) + 15) & ~15);
952           CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: NVidia Tegra 3 quirk, slice_height(%d)", slice_height);
953         }
954       }
955     }
956     if (color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_TI_FormatYUV420PackedSemiPlanar)
957     {
958       slice_height -= crop_top / 2;
959       // set crop top/left here, since the offset parameter already includes this.
960       // if we would ignore the offset parameter in the BufferInfo, we could just keep
961       // the original slice height and apply the top/left cropping instead.
962       crop_top = 0;
963       crop_left = 0;
964     }
965
966     // default picture format to none
967     for (int i = 0; i < 4; i++)
968       m_src_offset[i] = m_src_stride[i] = 0;
969     // delete any existing buffers
970     for (int i = 0; i < 4; i++)
971       free(m_videobuffer.data[i]);
972
973     // setup picture format and data offset vectors
974     if (color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420Planar)
975     {
976       CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: COLOR_FormatYUV420Planar");
977
978       // Y plane
979       m_src_stride[0] = stride;
980       m_src_offset[0] = crop_top * stride;
981       m_src_offset[0]+= crop_left;
982
983       // U plane
984       m_src_stride[1] = (stride + 1) / 2;
985       //  skip over the Y plane
986       m_src_offset[1] = slice_height * stride;
987       //  crop_top/crop_left divided by two
988       //  because one byte of the U/V planes
989       //  corresponds to two pixels horizontally/vertically
990       m_src_offset[1]+= crop_top  / 2 * m_src_stride[1];
991       m_src_offset[1]+= crop_left / 2;
992
993       // V plane
994       m_src_stride[2] = (stride + 1) / 2;
995       //  skip over the Y plane
996       m_src_offset[2] = slice_height * stride;
997       //  skip over the U plane
998       m_src_offset[2]+= ((slice_height + 1) / 2) * ((stride + 1) / 2);
999       //  crop_top/crop_left divided by two
1000       //  because one byte of the U/V planes
1001       //  corresponds to two pixels horizontally/vertically
1002       m_src_offset[2]+= crop_top  / 2 * m_src_stride[2];
1003       m_src_offset[2]+= crop_left / 2;
1004
1005       m_videobuffer.iLineSize[0] =  width;         // Y
1006       m_videobuffer.iLineSize[1] = (width + 1) /2; // U
1007       m_videobuffer.iLineSize[2] = (width + 1) /2; // V
1008       m_videobuffer.iLineSize[3] = 0;
1009
1010       unsigned int iPixels = width * height;
1011       unsigned int iChromaPixels = iPixels/4;
1012       m_videobuffer.data[0] = (uint8_t*)malloc(16 + iPixels);
1013       m_videobuffer.data[1] = (uint8_t*)malloc(16 + iChromaPixels);
1014       m_videobuffer.data[2] = (uint8_t*)malloc(16 + iChromaPixels);
1015       m_videobuffer.data[3] = NULL;
1016       m_videobuffer.format  = RENDER_FMT_YUV420P;
1017     }
1018     else if (color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_FormatYUV420SemiPlanar
1019           || color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_QCOM_FormatYUV420SemiPlanar
1020           || color_format == CJNIMediaCodecInfoCodecCapabilities::COLOR_TI_FormatYUV420PackedSemiPlanar
1021           || color_format == CJNIMediaCodecInfoCodecCapabilities::OMX_QCOM_COLOR_FormatYVU420SemiPlanarInterlace)
1022
1023     {
1024       CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: COLOR_FormatYUV420SemiPlanar");
1025
1026       // Y plane
1027       m_src_stride[0] = stride;
1028       m_src_offset[0] = crop_top * stride;
1029       m_src_offset[0]+= crop_left;
1030
1031       // UV plane
1032       m_src_stride[1] = stride;
1033       //  skip over the Y plane
1034       m_src_offset[1] = slice_height * stride;
1035       m_src_offset[1]+= crop_top * stride;
1036       m_src_offset[1]+= crop_left;
1037
1038       m_videobuffer.iLineSize[0] = width;  // Y
1039       m_videobuffer.iLineSize[1] = width;  // UV
1040       m_videobuffer.iLineSize[2] = 0;
1041       m_videobuffer.iLineSize[3] = 0;
1042
1043       unsigned int iPixels = width * height;
1044       unsigned int iChromaPixels = iPixels;
1045       m_videobuffer.data[0] = (uint8_t*)malloc(16 + iPixels);
1046       m_videobuffer.data[1] = (uint8_t*)malloc(16 + iChromaPixels);
1047       m_videobuffer.data[2] = NULL;
1048       m_videobuffer.data[3] = NULL;
1049       m_videobuffer.format  = RENDER_FMT_NV12;
1050     }
1051     else
1052     {
1053       CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec:: Fixme unknown color_format(%d)", color_format);
1054       return;
1055     }
1056   }
1057
1058   // picture display width/height include the cropping.
1059   m_videobuffer.iDisplayWidth  = crop_right  + 1 - crop_left;
1060   m_videobuffer.iDisplayHeight = crop_bottom + 1 - crop_top;
1061
1062   // clear any jni exceptions
1063   if (xbmc_jnienv()->ExceptionOccurred())
1064     xbmc_jnienv()->ExceptionClear();
1065 }
1066
1067 void CDVDVideoCodecAndroidMediaCodec::CallbackInitSurfaceTexture(void *userdata)
1068 {
1069   CDVDVideoCodecAndroidMediaCodec *ctx = static_cast<CDVDVideoCodecAndroidMediaCodec*>(userdata);
1070   ctx->InitSurfaceTexture();
1071 }
1072
1073 void CDVDVideoCodecAndroidMediaCodec::InitSurfaceTexture(void)
1074 {
1075   if (m_render_sw)
1076     return;
1077
1078   // We MUST create the GLES texture on the main thread
1079   // to match where the valid GLES context is located.
1080   // It would be nice to move this out of here, we would need
1081   // to create/fetch/create from g_RenderMananger. But g_RenderMananger
1082   // does not know we are using MediaCodec until Configure and we
1083   // we need m_surfaceTexture valid before then. Chicken, meet Egg.
1084   if (g_application.IsCurrentThread())
1085   {
1086     // localize GLuint so we do not spew gles includes in our header
1087     GLuint texture_id;
1088
1089     glGenTextures(1, &texture_id);
1090     glBindTexture(  GL_TEXTURE_EXTERNAL_OES, texture_id);
1091     glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1092     glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1093     glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1094     glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1095     glBindTexture(  GL_TEXTURE_EXTERNAL_OES, 0);
1096     m_textureId = texture_id;
1097
1098     m_surfaceTexture = boost::shared_ptr<CJNISurfaceTexture>(new CJNISurfaceTexture(m_textureId));
1099     // hook the surfaceTexture OnFrameAvailable callback
1100     m_frameAvailable = boost::shared_ptr<CDVDMediaCodecOnFrameAvailable>(new CDVDMediaCodecOnFrameAvailable(m_surfaceTexture));
1101     m_surface = new CJNISurface(*m_surfaceTexture);
1102   }
1103   else
1104   {
1105     ThreadMessageCallback callbackData;
1106     callbackData.callback = &CallbackInitSurfaceTexture;
1107     callbackData.userptr  = (void*)this;
1108
1109     ThreadMessage msg;
1110     msg.dwMessage = TMSG_CALLBACK;
1111     msg.lpVoid = (void*)&callbackData;
1112
1113     // wait for it.
1114     CApplicationMessenger::Get().SendMessage(msg, true);
1115   }
1116
1117   return;
1118 }
1119
1120 void CDVDVideoCodecAndroidMediaCodec::ReleaseSurfaceTexture(void)
1121 {
1122   if (m_render_sw)
1123     return;
1124
1125   // it is safe to delete here even though these items
1126   // were created in the main thread instance
1127   SAFE_DELETE(m_surface);
1128   m_frameAvailable.reset();
1129   m_surfaceTexture.reset();
1130
1131   if (m_textureId > 0)
1132   {
1133     GLuint texture_id = m_textureId;
1134     glDeleteTextures(1, &texture_id);
1135     m_textureId = 0;
1136   }
1137 }