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