1 /*
2  *  Copyright (C) 2016 Christian Browet
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 // http://developer.android.com/reference/android/media/MediaCodec.html
10 //
11 // Android MediaCodec class can be used to access low-level media codec,
12 // i.e. encoder/decoder components. (android.media.MediaCodec). Requires
13 // SDK16+ which is 4.1 Jellybean and above.
14 //
15 
16 #include "DVDAudioCodecAndroidMediaCodec.h"
17 
18 #include "DVDAudioCodecFFmpeg.h"
19 #include "DVDAudioCodecPassthrough.h"
20 #include "DVDCodecs/DVDCodecs.h"
21 #include "DVDCodecs/DVDFactoryCodec.h"
22 #include "ServiceBroker.h"
23 #include "cores/AudioEngine/Interfaces/AE.h"
24 #include "cores/AudioEngine/Utils/AEUtil.h"
25 #include "cores/VideoPlayer/Interface/DemuxCrypto.h"
26 #include "utils/StringUtils.h"
27 #include "utils/log.h"
28 
29 #include "platform/android/activity/AndroidFeatures.h"
30 
31 #include <cassert>
32 
33 #include <androidjni/ByteBuffer.h>
34 #include <androidjni/MediaCodec.h>
35 #include <androidjni/MediaCodecCryptoInfo.h>
36 #include <androidjni/MediaCodecInfo.h>
37 #include <androidjni/MediaCodecList.h>
38 #include <androidjni/MediaCrypto.h>
39 #include <androidjni/MediaFormat.h>
40 #include <androidjni/Surface.h>
41 #include <androidjni/UUID.h>
42 
43 static const AEChannel KnownChannels[] = { AE_CH_FL, AE_CH_FR, AE_CH_FC, AE_CH_LFE, AE_CH_SL, AE_CH_SR, AE_CH_BL, AE_CH_BR, AE_CH_BC, AE_CH_BLOC, AE_CH_BROC, AE_CH_NULL };
44 
IsDownmixDecoder(const std::string & name)45 static bool IsDownmixDecoder(const std::string &name)
46 {
47   static const char *downmixDecoders[] = {
48     "OMX.dolby",
49     // End of list
50     NULL
51   };
52   for (const char **ptr = downmixDecoders; *ptr; ptr++)
53   {
54     if (!StringUtils::CompareNoCase(*ptr, name, strlen(*ptr)))
55       return true;
56   }
57   return false;
58 }
59 
IsDecoderWhitelisted(const std::string & name)60 static bool IsDecoderWhitelisted(const std::string &name)
61 {
62   static const char *whitelistDecoders[] = {
63     // End of list
64     NULL
65   };
66   for (const char **ptr = whitelistDecoders; *ptr; ptr++)
67   {
68     if (!StringUtils::CompareNoCase(*ptr, name, strlen(*ptr)))
69       return true;
70   }
71   return false;
72 }
73 
74 /****************************/
75 
CDVDAudioCodecAndroidMediaCodec(CProcessInfo & processInfo)76 CDVDAudioCodecAndroidMediaCodec::CDVDAudioCodecAndroidMediaCodec(CProcessInfo &processInfo) :
77   CDVDAudioCodec(processInfo),
78   m_formatname("mediacodec"),
79   m_opened(false),
80   m_codecIsFed(false),
81   m_samplerate(0),
82   m_channels(0),
83   m_buffer(NULL),
84   m_bufferSize(0),
85   m_bufferUsed(0),
86   m_currentPts(DVD_NOPTS_VALUE),
87   m_crypto(nullptr)
88 {
89 }
90 
~CDVDAudioCodecAndroidMediaCodec()91 CDVDAudioCodecAndroidMediaCodec::~CDVDAudioCodecAndroidMediaCodec()
92 {
93   Dispose();
94 }
95 
Create(CProcessInfo & processInfo)96 CDVDAudioCodec* CDVDAudioCodecAndroidMediaCodec::Create(CProcessInfo &processInfo)
97 {
98   return new CDVDAudioCodecAndroidMediaCodec(processInfo);
99 }
100 
Register()101 bool CDVDAudioCodecAndroidMediaCodec::Register()
102 {
103   CDVDFactoryCodec::RegisterHWAudioCodec("mediacodec_dec", &CDVDAudioCodecAndroidMediaCodec::Create);
104   return true;
105 }
106 
Open(CDVDStreamInfo & hints,CDVDCodecOptions & options)107 bool CDVDAudioCodecAndroidMediaCodec::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
108 {
109   m_hints = hints;
110 
111   CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec::Open codec(%d), profile(%d), tag(%d), extrasize(%d)", hints.codec, hints.profile, hints.codec_tag, hints.extrasize);
112 
113   // First check if passthrough decoder is supported
114   CAEStreamInfo::DataType ptStreamType = CAEStreamInfo::STREAM_TYPE_NULL;
115   for (const auto &key : options.m_keys)
116     if (key.m_name == "ptstreamtype")
117     {
118       ptStreamType = static_cast<CAEStreamInfo::DataType>(atoi(key.m_value.c_str()));
119       break;
120     }
121 
122   if (ptStreamType != CAEStreamInfo::STREAM_TYPE_NULL)
123   {
124     //Look if the PT decoder can be opened
125     m_decryptCodec = std::shared_ptr<CDVDAudioCodec>(new CDVDAudioCodecPassthrough(m_processInfo, ptStreamType));
126     if (m_decryptCodec->Open(hints, options))
127       goto PROCESSDECODER;
128   }
129 
130   switch(m_hints.codec)
131   {
132     case AV_CODEC_ID_AAC:
133     case AV_CODEC_ID_AAC_LATM:
134       if (!m_hints.extrasize)
135       {
136         CLog::Log(LOGINFO, "CDVDAudioCodecAndroidMediaCodec: extradata required for aac decoder!");
137         return false;
138       }
139 
140       m_mime = "audio/mp4a-latm";
141       m_formatname = "amc-aac";
142       break;
143 
144     case AV_CODEC_ID_MP2:
145       m_mime = "audio/mpeg-L2";
146       m_formatname = "amc-mp2";
147       break;
148 
149     case AV_CODEC_ID_MP3:
150       m_mime = "audio/mpeg";
151       m_formatname = "amc-mp3";
152       break;
153 
154     case AV_CODEC_ID_VORBIS:
155       m_mime = "audio/vorbis";
156       m_formatname = "amc-ogg";
157 
158       //TODO
159       return false;
160 
161       break;
162 
163     case AV_CODEC_ID_WMAPRO:
164       m_mime = "audio/wmapro";
165       m_formatname = "amc-wma";
166 
167       //TODO
168       return false;
169 
170       break;
171 
172     case AV_CODEC_ID_WMAV1:
173     case AV_CODEC_ID_WMAV2:
174       m_mime = "audio/x-ms-wma";
175       m_formatname = "amc-wma";
176       //TODO
177       return false;
178 
179       break;
180 
181     case AV_CODEC_ID_AC3:
182       m_mime = "audio/ac3";
183       m_formatname = "amc-ac3";
184       break;
185 
186     case AV_CODEC_ID_EAC3:
187       m_mime = "audio/eac3";
188       m_formatname = "amc-eac3";
189       break;
190 
191     default:
192       CLog::Log(LOGINFO, "CDVDAudioCodecAndroidMediaCodec: Unknown hints.codec(%d)", hints.codec);
193       return false;
194       break;
195   }
196 
197   {
198     //StereoDownmixAllowed is true if the user has selected 2.0 Audio channels in settings
199     bool stereoDownmixAllowed = CServiceBroker::GetActiveAE()->HasStereoAudioChannelCount();
200     unsigned int num_codecs = CJNIMediaCodecList::getCodecCount();
201     std::vector<std::string> mimeTypes;
202 
203     for (int i = 0; i < num_codecs; i++)
204     {
205       CJNIMediaCodecInfo codec_info = CJNIMediaCodecList::getCodecInfoAt(i);
206       if (codec_info.isEncoder())
207         continue;
208 
209       std::string codecName = codec_info.getName();
210 
211       if (!IsDecoderWhitelisted(codecName))
212         continue;
213 
214       if (m_hints.channels > 2 && !stereoDownmixAllowed && IsDownmixDecoder(codecName))
215         continue;
216 
217       mimeTypes = codec_info.getSupportedTypes();
218       if (std::find(mimeTypes.begin(), mimeTypes.end(), m_mime) != mimeTypes.end())
219       {
220         m_codec = std::shared_ptr<CJNIMediaCodec>(new CJNIMediaCodec(CJNIMediaCodec::createByCodecName(codecName)));
221         if (xbmc_jnienv()->ExceptionCheck())
222         {
223           xbmc_jnienv()->ExceptionClear();
224           m_codec = NULL;
225           continue;
226         }
227         CLog::Log(LOGINFO, "CDVDAudioCodecAndroidMediaCodec: Selected audio decoder: %s", codecName.c_str());
228         break;
229       }
230     }
231   }
232 
233 PROCESSDECODER:
234 
235   if (m_crypto)
236     delete m_crypto;
237 
238   if (m_hints.cryptoSession)
239   {
240     CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec::Open Initializing MediaCrypto");
241 
242     CJNIUUID uuid(jni::jhobject(NULL));
243     if (m_hints.cryptoSession->keySystem == CRYPTO_SESSION_SYSTEM_WIDEVINE)
244       uuid = CJNIUUID(0xEDEF8BA979D64ACEULL, 0xA3C827DCD51D21EDULL);
245     else if (m_hints.cryptoSession->keySystem == CRYPTO_SESSION_SYSTEM_PLAYREADY)
246       uuid = CJNIUUID(0x9A04F07998404286ULL, 0xAB92E65BE0885F95ULL);
247     else
248     {
249       CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::Open Unsupported crypto-keysystem:%u", m_hints.cryptoSession->keySystem);
250       return false;
251     }
252 
253     m_crypto =
254         new CJNIMediaCrypto(uuid, std::vector<char>(m_hints.cryptoSession->sessionId.begin(),
255                                                     m_hints.cryptoSession->sessionId.end()));
256 
257     if (xbmc_jnienv()->ExceptionCheck())
258     {
259       CLog::Log(LOGERROR, "MediaCrypto::ExceptionCheck: <init>");
260       xbmc_jnienv()->ExceptionDescribe();
261       xbmc_jnienv()->ExceptionClear();
262       return false;
263     }
264   }
265   else
266     m_crypto = new CJNIMediaCrypto(jni::jhobject(NULL));
267 
268   if (!m_codec)
269   {
270     if (m_hints.cryptoSession)
271     {
272       m_mime = "audio/raw";
273       m_codec = std::shared_ptr<CJNIMediaCodec>(new CJNIMediaCodec(CJNIMediaCodec::createDecoderByType(m_mime)));
274       if (xbmc_jnienv()->ExceptionCheck())
275       {
276         xbmc_jnienv()->ExceptionClear();
277         CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::Open Failed creating raw decoder");
278         return false;
279       }
280       if (!m_decryptCodec)
281       {
282         CDVDStreamInfo ffhints = hints;
283         ffhints.cryptoSession = nullptr;
284 
285         m_decryptCodec = std::shared_ptr<CDVDAudioCodec>(new CDVDAudioCodecFFmpeg(m_processInfo));
286         if (!m_decryptCodec->Open(ffhints, options))
287         {
288           CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::Open() Failed opening FFmpeg decoder");
289           return false;
290         }
291       }
292       CLog::Log(LOGINFO, "CDVDAudioCodecAndroidMediaCodec Use raw decoder and decode using %s", m_decryptCodec->GetName());
293     }
294     else
295     {
296       CLog::Log(LOGINFO, "CDVDAudioCodecAndroidMediaCodec::Open() Use default handling for non encrypted stream");
297       return false;
298     }
299   }
300 
301   if (!ConfigureMediaCodec())
302   {
303     m_codec.reset();
304     return false;
305   }
306 
307   CLog::Log(LOGINFO, "CDVDAudioCodecAndroidMediaCodec Open Android MediaCodec %s", m_formatname.c_str());
308 
309   m_opened = true;
310   m_codecIsFed = false;
311   m_currentPts = DVD_NOPTS_VALUE;
312   return m_opened;
313 }
314 
GetName()315 std::string CDVDAudioCodecAndroidMediaCodec::GetName()
316 {
317   if (m_decryptCodec)
318     return "amc-raw/" + m_decryptCodec->GetName();
319   return m_formatname;
320 };
321 
Dispose()322 void CDVDAudioCodecAndroidMediaCodec::Dispose()
323 {
324   if (!m_opened)
325     return;
326 
327   m_opened = false;
328 
329   if (m_codec)
330   {
331     m_codec->stop();
332     m_codec->release();
333     m_codec.reset();
334     if (xbmc_jnienv()->ExceptionCheck())
335       xbmc_jnienv()->ExceptionClear();
336   }
337 
338   if (m_crypto)
339   {
340     delete m_crypto;
341     m_crypto = nullptr;
342   }
343   m_decryptCodec = nullptr;
344 }
345 
AddData(const DemuxPacket & packet)346 bool CDVDAudioCodecAndroidMediaCodec::AddData(const DemuxPacket &packet)
347 {
348   CLog::Log(LOGDEBUG, LOGAUDIO, "CDVDAudioCodecAndroidMediaCodec::AddData dts:%0.4lf pts:%0.4lf size(%d)", packet.dts, packet.pts, packet.iSize);
349 
350   if (packet.pData)
351   {
352     // try to fetch an input buffer
353     int64_t timeout_us = 5000;
354     int index = m_codec->dequeueInputBuffer(timeout_us);
355     if (xbmc_jnienv()->ExceptionCheck())
356     {
357       std::string err = CJNIBase::ExceptionToString();
358       CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::AddData ExceptionCheck \n %s", err.c_str());
359     }
360     else if (index >= 0)
361     {
362       CJNIByteBuffer buffer = m_codec->getInputBuffer(index);
363       int size = buffer.capacity();
364 
365       if (xbmc_jnienv()->ExceptionCheck())
366       {
367         CLog::Log(LOGERROR, "CDVDMediaCodecInfo::AddData getInputBuffers ExceptionCheck");
368         xbmc_jnienv()->ExceptionDescribe();
369         xbmc_jnienv()->ExceptionClear();
370       }
371 
372       if (packet.iSize > size)
373       {
374         CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::AddData, iSize(%d) > size(%d)", packet.iSize, size);
375         return packet.iSize;
376       }
377       // fetch a pointer to the ByteBuffer backing store
378       uint8_t *dst_ptr = (uint8_t*)xbmc_jnienv()->GetDirectBufferAddress(buffer.get_raw());
379 
380       if (dst_ptr)
381       {
382         // Codec specifics
383         switch(m_hints.codec)
384         {
385           default:
386             memcpy(dst_ptr, packet.pData, packet.iSize);
387             break;
388         }
389       }
390       else
391         return false;
392 
393       CJNIMediaCodecCryptoInfo *cryptoInfo(0);
394       if (!!m_crypto->get_raw() && packet.cryptoInfo)
395       {
396         cryptoInfo = new CJNIMediaCodecCryptoInfo();
397         cryptoInfo->set(
398           packet.cryptoInfo->numSubSamples,
399           std::vector<int>(packet.cryptoInfo->clearBytes, packet.cryptoInfo->clearBytes + packet.cryptoInfo->numSubSamples),
400           std::vector<int>(packet.cryptoInfo->cipherBytes, packet.cryptoInfo->cipherBytes + packet.cryptoInfo->numSubSamples),
401           std::vector<char>(packet.cryptoInfo->kid, packet.cryptoInfo->kid + 16),
402           std::vector<char>(packet.cryptoInfo->iv, packet.cryptoInfo->iv + 16),
403           CJNIMediaCodec::CRYPTO_MODE_AES_CTR);
404       }
405 
406       int flags = 0;
407       int offset = 0;
408       int64_t presentationTimeUs = static_cast<int64_t>(packet.pts);
409 
410       if (!cryptoInfo)
411         m_codec->queueInputBuffer(index, offset, packet.iSize, presentationTimeUs, flags);
412       else
413       {
414         m_codec->queueSecureInputBuffer(index, offset, *cryptoInfo, presentationTimeUs, flags);
415         delete cryptoInfo;
416       }
417 
418       // clear any jni exceptions, jni gets upset if we do not.
419       if (xbmc_jnienv()->ExceptionCheck())
420       {
421         CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::Decode ExceptionCheck");
422         xbmc_jnienv()->ExceptionDescribe();
423         xbmc_jnienv()->ExceptionClear();
424       }
425       m_codecIsFed = true;
426     }
427   }
428 
429   if (m_decryptCodec)
430   {
431     DemuxPacket newPkt;
432     newPkt.iSize = GetData(&newPkt.pData);
433     newPkt.pts = m_currentPts;
434     newPkt.iStreamId = packet.iStreamId;
435     newPkt.demuxerId = packet.demuxerId;
436     newPkt.iGroupId = packet.iGroupId;
437     newPkt.pSideData = packet.pSideData;
438     newPkt.duration = packet.duration;
439     newPkt.dispTime = packet.dispTime;
440     newPkt.recoveryPoint = packet.recoveryPoint;
441     if (!packet.pData || newPkt.iSize)
442       m_decryptCodec->AddData(newPkt);
443   }
444   else
445   {
446     m_format.m_dataFormat = GetDataFormat();
447     m_format.m_channelLayout = GetChannelMap();
448     m_format.m_sampleRate = GetSampleRate();
449     m_format.m_frameSize = m_format.m_channelLayout.Count() * CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3;
450   }
451   return true;
452 }
453 
Reset()454 void CDVDAudioCodecAndroidMediaCodec::Reset()
455 {
456   if (!m_opened)
457     return;
458 
459   if (m_codec && m_codecIsFed)
460   {
461     // now we can flush the actual MediaCodec object
462     m_codec->flush();
463     if (xbmc_jnienv()->ExceptionCheck())
464     {
465       CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::Reset ExceptionCheck");
466       xbmc_jnienv()->ExceptionClear();
467     }
468   }
469   m_codecIsFed = false;
470 
471   if (m_decryptCodec)
472     m_decryptCodec->Reset();
473 
474   m_currentPts = DVD_NOPTS_VALUE;
475 }
476 
GetFormat()477 AEAudioFormat CDVDAudioCodecAndroidMediaCodec::GetFormat()
478 {
479   if (m_decryptCodec)
480     return m_decryptCodec->GetFormat();
481 
482   return m_format;
483 }
484 
GetChannelMap()485 CAEChannelInfo CDVDAudioCodecAndroidMediaCodec::GetChannelMap()
486 {
487   CAEChannelInfo chaninfo;
488 
489   for (int i=0; i<m_channels; ++i)
490     chaninfo += KnownChannels[i];
491 
492   return chaninfo;
493 }
494 
ConfigureMediaCodec(void)495 bool CDVDAudioCodecAndroidMediaCodec::ConfigureMediaCodec(void)
496 {
497   // setup a MediaFormat to match the audio content,
498   // used by codec during configure
499   CJNIMediaFormat mediaformat(CJNIMediaFormat::createAudioFormat(
500     m_mime.c_str(), m_hints.samplerate, m_hints.channels));
501 
502   if (!m_decryptCodec)
503   {
504     // handle codec extradata
505     if (m_hints.extrasize)
506     {
507       size_t size = m_hints.extrasize;
508       void  *src_ptr = m_hints.extradata;
509       // Allocate a byte buffer via allocateDirect in java instead of NewDirectByteBuffer,
510       // since the latter doesn't allocate storage of its own, and we don't know how long
511       // the codec uses the buffer.
512       CJNIByteBuffer bytebuffer = CJNIByteBuffer::allocateDirect(size);
513       void *dts_ptr = xbmc_jnienv()->GetDirectBufferAddress(bytebuffer.get_raw());
514       memcpy(dts_ptr, src_ptr, size);
515       // codec will automatically handle buffers as extradata
516       // using entries with keys "csd-0", "csd-1", etc.
517       mediaformat.setByteBuffer("csd-0", bytebuffer);
518     }
519     else if (m_hints.codec == AV_CODEC_ID_AAC || m_hints.codec == AV_CODEC_ID_AAC_LATM)
520     {
521       mediaformat.setInteger(CJNIMediaFormat::KEY_IS_ADTS, 1);
522     }
523   }
524 
525   // configure and start the codec.
526   // use the MediaFormat that we have setup.
527   // use a null MediaCrypto, our content is not encrypted.
528   // use a null Surface
529   int flags = 0;
530   CJNISurface surface(jni::jhobject(NULL));
531   m_codec->configure(mediaformat, surface, *m_crypto, flags);
532 
533   // always, check/clear jni exceptions.
534   if (xbmc_jnienv()->ExceptionCheck())
535   {
536     CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::ExceptionCheck: configure");
537     xbmc_jnienv()->ExceptionDescribe();
538     xbmc_jnienv()->ExceptionClear();
539     return false;
540   }
541 
542   m_codec->start();
543   // always, check/clear jni exceptions.
544   if (xbmc_jnienv()->ExceptionCheck())
545   {
546     CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::ExceptionCheck: start");
547     xbmc_jnienv()->ExceptionDescribe();
548     xbmc_jnienv()->ExceptionClear();
549     return false;
550   }
551 
552   // There is no guarantee we'll get an INFO_OUTPUT_FORMAT_CHANGED (up to Android 4.3)
553   // Configure the output with defaults
554   if (!m_decryptCodec)
555     ConfigureOutputFormat(&mediaformat);
556 
557   return true;
558 }
559 
GetData(DVDAudioFrame & frame)560 void CDVDAudioCodecAndroidMediaCodec::GetData(DVDAudioFrame &frame)
561 {
562   if (m_decryptCodec)
563   {
564     m_decryptCodec->GetData(frame);
565     return;
566   }
567 
568   frame.passthrough = false;
569   frame.nb_frames = 0;
570   frame.framesOut = 0;
571   frame.format.m_dataFormat = m_format.m_dataFormat;
572   frame.format.m_channelLayout = m_format.m_channelLayout;
573   frame.framesize = (CAEUtil::DataFormatToBits(frame.format.m_dataFormat) >> 3) * frame.format.m_channelLayout.Count();
574 
575   if (frame.framesize == 0)
576     return;
577 
578   if (!m_codecIsFed)
579     return;
580 
581   frame.nb_frames = GetData(frame.data)/frame.framesize;
582   frame.planes = AE_IS_PLANAR(frame.format.m_dataFormat) ? frame.format.m_channelLayout.Count() : 1;
583   frame.bits_per_sample = CAEUtil::DataFormatToBits(frame.format.m_dataFormat);
584   frame.format.m_sampleRate = m_format.m_sampleRate;
585   frame.pts = m_currentPts;
586   m_currentPts = DVD_NOPTS_VALUE;
587   frame.matrix_encoding = GetMatrixEncoding();
588   frame.audio_service_type = GetAudioServiceType();
589   frame.profile = GetProfile();
590   // compute duration.
591   if (frame.format.m_sampleRate)
592     frame.duration = ((double)frame.nb_frames * DVD_TIME_BASE) / frame.format.m_sampleRate;
593   else
594     frame.duration = 0.0;
595   if (frame.nb_frames > 0 && CServiceBroker::GetLogging().CanLogComponent(LOGAUDIO))
596     CLog::Log(LOGDEBUG, "MediaCodecAudio::GetData: frames:%d pts: %0.4f", frame.nb_frames, frame.pts);
597 }
598 
GetData(uint8_t ** dst)599 int CDVDAudioCodecAndroidMediaCodec::GetData(uint8_t** dst)
600 {
601   m_bufferUsed = 0;
602 
603   int64_t timeout_us = 10000;
604   CJNIMediaCodecBufferInfo bufferInfo;
605   int index = m_codec->dequeueOutputBuffer(bufferInfo, timeout_us);
606   if (xbmc_jnienv()->ExceptionCheck())
607   {
608     std::string err = CJNIBase::ExceptionToString();
609     CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData ExceptionCheck; dequeueOutputBuffer \n %s", err.c_str());
610     xbmc_jnienv()->ExceptionDescribe();
611     xbmc_jnienv()->ExceptionClear();
612     return 0;
613   }
614   if (index >= 0)
615   {
616     CJNIByteBuffer buffer = m_codec->getOutputBuffer(index);
617     if (xbmc_jnienv()->ExceptionCheck())
618     {
619       CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData ExceptionCheck: getOutputBuffer(%d)", index);
620       xbmc_jnienv()->ExceptionDescribe();
621       xbmc_jnienv()->ExceptionClear();
622       return 0;
623     }
624 
625     int flags = bufferInfo.flags();
626     if (flags & CJNIMediaCodec::BUFFER_FLAG_SYNC_FRAME)
627       CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec:: BUFFER_FLAG_SYNC_FRAME");
628 
629     if (flags & CJNIMediaCodec::BUFFER_FLAG_CODEC_CONFIG)
630       CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec:: BUFFER_FLAG_CODEC_CONFIG");
631 
632     if (flags & CJNIMediaCodec::BUFFER_FLAG_END_OF_STREAM)
633     {
634       CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec:: BUFFER_FLAG_END_OF_STREAM");
635       m_codec->releaseOutputBuffer(index, false);
636       if (xbmc_jnienv()->ExceptionCheck())
637       {
638         CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData ExceptionCheck: releaseOutputBuffer");
639         xbmc_jnienv()->ExceptionDescribe();
640         xbmc_jnienv()->ExceptionClear();
641         return 0;
642       }
643       return 0;
644     }
645 
646     int size = bufferInfo.size();
647     int offset = bufferInfo.offset();
648 
649     if (!buffer.isDirect())
650       CLog::Log(LOGWARNING, "CDVDAudioCodecAndroidMediaCodec:: buffer.isDirect == false");
651 
652     if (size && buffer.capacity())
653     {
654       uint8_t *src_ptr = (uint8_t*)xbmc_jnienv()->GetDirectBufferAddress(buffer.get_raw());
655       src_ptr += offset;
656 
657       if (size > m_bufferSize)
658       {
659         m_bufferSize = size;
660         m_buffer = (uint8_t*)realloc(m_buffer, m_bufferSize);
661       }
662 
663       memcpy(m_buffer, src_ptr, size);
664       m_bufferUsed = size;
665     }
666     else
667       return 0;
668 
669     m_codec->releaseOutputBuffer(index, false);
670     if (xbmc_jnienv()->ExceptionCheck())
671     {
672       CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData ExceptionCheck: releaseOutputBuffer");
673       xbmc_jnienv()->ExceptionDescribe();
674       xbmc_jnienv()->ExceptionClear();
675     }
676 
677     CLog::Log(LOGDEBUG, LOGAUDIO, "CDVDAudioCodecAndroidMediaCodec::GetData index(%d), size(%d)", index, m_bufferUsed);
678 
679     m_currentPts = bufferInfo.presentationTimeUs() == (int64_t)DVD_NOPTS_VALUE ? DVD_NOPTS_VALUE :  bufferInfo.presentationTimeUs();
680 
681     // always, check/clear jni exceptions.
682     if (xbmc_jnienv()->ExceptionCheck())
683       xbmc_jnienv()->ExceptionClear();
684   }
685   else if (index == CJNIMediaCodec::INFO_OUTPUT_BUFFERS_CHANGED)
686   {
687     CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec:: GetData OUTPUT_BUFFERS_CHANGED");
688   }
689   else if (index == CJNIMediaCodec::INFO_OUTPUT_FORMAT_CHANGED)
690   {
691     CJNIMediaFormat mediaformat = m_codec->getOutputFormat();
692     if (xbmc_jnienv()->ExceptionCheck())
693     {
694       CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData(INFO_OUTPUT_FORMAT_CHANGED) ExceptionCheck: getOutputBuffers");
695       xbmc_jnienv()->ExceptionDescribe();
696       xbmc_jnienv()->ExceptionClear();
697     }
698     ConfigureOutputFormat(&mediaformat);
699   }
700   else if (index == CJNIMediaCodec::INFO_TRY_AGAIN_LATER)
701   {
702     // normal dequeueOutputBuffer timeout, ignore it.
703     m_bufferUsed = 0;
704   }
705   else
706   {
707     // we should never get here
708     CLog::Log(LOGERROR, "CDVDAudioCodecAndroidMediaCodec::GetData unknown index(%d)", index);
709   }
710 
711   *dst     = m_buffer;
712   return m_bufferUsed;
713 }
714 
ConfigureOutputFormat(CJNIMediaFormat * mediaformat)715 void CDVDAudioCodecAndroidMediaCodec::ConfigureOutputFormat(CJNIMediaFormat* mediaformat)
716 {
717   m_samplerate       = 0;
718   m_channels         = 0;
719 
720   if (mediaformat->containsKey("sample-rate"))
721     m_samplerate       = mediaformat->getInteger("sample-rate");
722   if (mediaformat->containsKey("channel-count"))
723     m_channels     = mediaformat->getInteger("channel-count");
724 
725 #if 1 //defined(DEBUG_VERBOSE)
726   CLog::Log(LOGDEBUG, "CDVDAudioCodecAndroidMediaCodec:: "
727     "sample_rate(%d), channel_count(%d)",
728     m_samplerate, m_channels);
729 #endif
730 
731   // clear any jni exceptions
732   if (xbmc_jnienv()->ExceptionCheck())
733     xbmc_jnienv()->ExceptionClear();
734 }
735