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