1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "MediaCodecDataDecoder.h"
6
7 #include "AndroidBridge.h"
8 #include "AndroidSurfaceTexture.h"
9 #include "GeneratedJNINatives.h"
10 #include "GLImages.h"
11
12 #include "MediaData.h"
13 #include "MediaInfo.h"
14 #include "VPXDecoder.h"
15
16 #include "nsThreadUtils.h"
17 #include "nsPromiseFlatString.h"
18 #include "nsIGfxInfo.h"
19
20 #include "prlog.h"
21
22 #include <jni.h>
23
24 #undef LOG
25 #define LOG(arg, ...) MOZ_LOG(sAndroidDecoderModuleLog, \
26 mozilla::LogLevel::Debug, ("MediaCodecDataDecoder(%p)::%s: " arg, \
27 this, __func__, ##__VA_ARGS__))
28
29 using namespace mozilla;
30 using namespace mozilla::gl;
31 using namespace mozilla::java;
32 using namespace mozilla::java::sdk;
33 using media::TimeUnit;
34
35 namespace mozilla {
36
37 #define INVOKE_CALLBACK(Func, ...) \
38 if (mCallback) { \
39 mCallback->Func(__VA_ARGS__); \
40 } else { \
41 NS_WARNING("Callback not set"); \
42 }
43
44 static MediaCodec::LocalRef
CreateDecoder(const nsACString & aMimeType)45 CreateDecoder(const nsACString& aMimeType)
46 {
47 MediaCodec::LocalRef codec;
48 NS_ENSURE_SUCCESS(MediaCodec::CreateDecoderByType(TranslateMimeType(aMimeType),
49 &codec), nullptr);
50 return codec;
51 }
52
53 class VideoDataDecoder : public MediaCodecDataDecoder
54 {
55 public:
VideoDataDecoder(const VideoInfo & aConfig,MediaFormat::Param aFormat,MediaDataDecoderCallback * aCallback,layers::ImageContainer * aImageContainer)56 VideoDataDecoder(const VideoInfo& aConfig,
57 MediaFormat::Param aFormat,
58 MediaDataDecoderCallback* aCallback,
59 layers::ImageContainer* aImageContainer)
60 : MediaCodecDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mMimeType,
61 aFormat, aCallback)
62 , mImageContainer(aImageContainer)
63 , mConfig(aConfig)
64 {
65
66 }
67
GetDescriptionName() const68 const char* GetDescriptionName() const override
69 {
70 return "Android MediaCodec video decoder";
71 }
72
Init()73 RefPtr<InitPromise> Init() override
74 {
75 mSurfaceTexture = AndroidSurfaceTexture::Create();
76 if (!mSurfaceTexture) {
77 NS_WARNING("Failed to create SurfaceTexture for video decode\n");
78 return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
79 }
80
81 if (NS_FAILED(InitDecoder(mSurfaceTexture->JavaSurface()))) {
82 return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
83 }
84
85 return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
86 }
87
Cleanup()88 void Cleanup() override
89 {
90 }
91
PostOutput(BufferInfo::Param aInfo,MediaFormat::Param aFormat,const TimeUnit & aDuration)92 nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat,
93 const TimeUnit& aDuration) override
94 {
95 RefPtr<layers::Image> img =
96 new SurfaceTextureImage(mSurfaceTexture.get(), mConfig.mDisplay,
97 gl::OriginPos::BottomLeft);
98
99 nsresult rv;
100 int32_t flags;
101 NS_ENSURE_SUCCESS(rv = aInfo->Flags(&flags), rv);
102
103 bool isSync = !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME);
104
105 int32_t offset;
106 NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
107
108 int64_t presentationTimeUs;
109 NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
110
111 RefPtr<VideoData> v =
112 VideoData::CreateFromImage(mConfig,
113 offset,
114 presentationTimeUs,
115 aDuration.ToMicroseconds(),
116 img,
117 isSync,
118 presentationTimeUs,
119 gfx::IntRect(0, 0,
120 mConfig.mDisplay.width,
121 mConfig.mDisplay.height));
122 INVOKE_CALLBACK(Output, v);
123 return NS_OK;
124 }
125
126 protected:
127 layers::ImageContainer* mImageContainer;
128 const VideoInfo& mConfig;
129 RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
130 };
131
132 class AudioDataDecoder : public MediaCodecDataDecoder
133 {
134 public:
AudioDataDecoder(const AudioInfo & aConfig,MediaFormat::Param aFormat,MediaDataDecoderCallback * aCallback)135 AudioDataDecoder(const AudioInfo& aConfig, MediaFormat::Param aFormat,
136 MediaDataDecoderCallback* aCallback)
137 : MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mMimeType,
138 aFormat, aCallback)
139 {
140 JNIEnv* const env = jni::GetEnvForThread();
141
142 jni::ByteBuffer::LocalRef buffer(env);
143 NS_ENSURE_SUCCESS_VOID(aFormat->GetByteBuffer(NS_LITERAL_STRING("csd-0"),
144 &buffer));
145
146 if (!buffer && aConfig.mCodecSpecificConfig->Length() >= 2) {
147 buffer = jni::ByteBuffer::New(
148 aConfig.mCodecSpecificConfig->Elements(),
149 aConfig.mCodecSpecificConfig->Length());
150 NS_ENSURE_SUCCESS_VOID(aFormat->SetByteBuffer(NS_LITERAL_STRING("csd-0"),
151 buffer));
152 }
153 }
154
GetDescriptionName() const155 const char* GetDescriptionName() const override
156 {
157 return "android audio decoder";
158 }
159
Output(BufferInfo::Param aInfo,void * aBuffer,MediaFormat::Param aFormat,const TimeUnit & aDuration)160 nsresult Output(BufferInfo::Param aInfo, void* aBuffer,
161 MediaFormat::Param aFormat, const TimeUnit& aDuration)
162 {
163 // The output on Android is always 16-bit signed
164 nsresult rv;
165 int32_t numChannels;
166 NS_ENSURE_SUCCESS(rv =
167 aFormat->GetInteger(NS_LITERAL_STRING("channel-count"), &numChannels), rv);
168 AudioConfig::ChannelLayout layout(numChannels);
169 if (!layout.IsValid()) {
170 return NS_ERROR_FAILURE;
171 }
172
173 int32_t sampleRate;
174 NS_ENSURE_SUCCESS(rv =
175 aFormat->GetInteger(NS_LITERAL_STRING("sample-rate"), &sampleRate), rv);
176
177 int32_t size;
178 NS_ENSURE_SUCCESS(rv = aInfo->Size(&size), rv);
179
180 int32_t offset;
181 NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
182
183 #ifdef MOZ_SAMPLE_TYPE_S16
184 const int32_t numSamples = size / 2;
185 #else
186 #error We only support 16-bit integer PCM
187 #endif
188
189 const int32_t numFrames = numSamples / numChannels;
190 AlignedAudioBuffer audio(numSamples);
191 if (!audio) {
192 return NS_ERROR_OUT_OF_MEMORY;
193 }
194
195 const uint8_t* bufferStart = static_cast<uint8_t*>(aBuffer) + offset;
196 PodCopy(audio.get(), reinterpret_cast<const AudioDataValue*>(bufferStart),
197 numSamples);
198
199 int64_t presentationTimeUs;
200 NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
201
202 RefPtr<AudioData> data = new AudioData(0, presentationTimeUs,
203 aDuration.ToMicroseconds(),
204 numFrames,
205 Move(audio),
206 numChannels,
207 sampleRate);
208 INVOKE_CALLBACK(Output, data);
209 return NS_OK;
210 }
211 };
212
213 MediaDataDecoder*
CreateAudioDecoder(const AudioInfo & aConfig,MediaFormat::Param aFormat,MediaDataDecoderCallback * aCallback)214 MediaCodecDataDecoder::CreateAudioDecoder(const AudioInfo& aConfig,
215 MediaFormat::Param aFormat,
216 MediaDataDecoderCallback* aCallback)
217 {
218 return new AudioDataDecoder(aConfig, aFormat, aCallback);
219 }
220
221 MediaDataDecoder*
CreateVideoDecoder(const VideoInfo & aConfig,MediaFormat::Param aFormat,MediaDataDecoderCallback * aCallback,layers::ImageContainer * aImageContainer)222 MediaCodecDataDecoder::CreateVideoDecoder(const VideoInfo& aConfig,
223 MediaFormat::Param aFormat,
224 MediaDataDecoderCallback* aCallback,
225 layers::ImageContainer* aImageContainer)
226 {
227 return new VideoDataDecoder(aConfig, aFormat, aCallback, aImageContainer);
228 }
229
MediaCodecDataDecoder(MediaData::Type aType,const nsACString & aMimeType,MediaFormat::Param aFormat,MediaDataDecoderCallback * aCallback)230 MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
231 const nsACString& aMimeType,
232 MediaFormat::Param aFormat,
233 MediaDataDecoderCallback* aCallback)
234 : mType(aType)
235 , mMimeType(aMimeType)
236 , mFormat(aFormat)
237 , mCallback(aCallback)
238 , mInputBuffers(nullptr)
239 , mOutputBuffers(nullptr)
240 , mMonitor("MediaCodecDataDecoder::mMonitor")
241 , mState(ModuleState::kDecoding)
242 {
243
244 }
245
~MediaCodecDataDecoder()246 MediaCodecDataDecoder::~MediaCodecDataDecoder()
247 {
248 Shutdown();
249 }
250
251 RefPtr<MediaDataDecoder::InitPromise>
Init()252 MediaCodecDataDecoder::Init()
253 {
254 nsresult rv = InitDecoder(nullptr);
255
256 TrackInfo::TrackType type =
257 (mType == MediaData::AUDIO_DATA ? TrackInfo::TrackType::kAudioTrack
258 : TrackInfo::TrackType::kVideoTrack);
259
260 return NS_SUCCEEDED(rv) ?
261 InitPromise::CreateAndResolve(type, __func__) :
262 InitPromise::CreateAndReject(
263 NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
264 }
265
266 nsresult
InitDecoder(Surface::Param aSurface)267 MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface)
268 {
269 mDecoder = CreateDecoder(mMimeType);
270 if (!mDecoder) {
271 INVOKE_CALLBACK(Error,
272 MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__));
273 return NS_ERROR_FAILURE;
274 }
275
276 nsresult rv;
277 NS_ENSURE_SUCCESS(rv = mDecoder->Configure(mFormat, aSurface, nullptr, 0), rv);
278 NS_ENSURE_SUCCESS(rv = mDecoder->Start(), rv);
279
280 NS_ENSURE_SUCCESS(rv = ResetInputBuffers(), rv);
281 NS_ENSURE_SUCCESS(rv = ResetOutputBuffers(), rv);
282
283 nsCOMPtr<nsIRunnable> r = NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop);
284 rv = NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread), r);
285
286 return rv;
287 }
288
289 // This is in usec, so that's 10ms.
290 static const int64_t kDecoderTimeout = 10000;
291
292 #define BREAK_ON_DECODER_ERROR() \
293 if (NS_FAILED(res)) { \
294 NS_WARNING("Exiting decoder loop due to exception"); \
295 if (mState == ModuleState::kDrainDecoder) { \
296 INVOKE_CALLBACK(DrainComplete); \
297 SetState(ModuleState::kDecoding); \
298 } \
299 INVOKE_CALLBACK(Error, MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__)); \
300 break; \
301 }
302
303 nsresult
GetInputBuffer(JNIEnv * aEnv,int aIndex,jni::Object::LocalRef * aBuffer)304 MediaCodecDataDecoder::GetInputBuffer(
305 JNIEnv* aEnv, int aIndex, jni::Object::LocalRef* aBuffer)
306 {
307 MOZ_ASSERT(aEnv);
308 MOZ_ASSERT(!*aBuffer);
309
310 int numTries = 2;
311
312 while (numTries--) {
313 *aBuffer = jni::Object::LocalRef::Adopt(
314 aEnv->GetObjectArrayElement(mInputBuffers.Get(), aIndex));
315 if (*aBuffer) {
316 return NS_OK;
317 }
318 nsresult res = ResetInputBuffers();
319 if (NS_FAILED(res)) {
320 return res;
321 }
322 }
323 return NS_ERROR_FAILURE;
324 }
325
326 bool
WaitForInput()327 MediaCodecDataDecoder::WaitForInput()
328 {
329 MonitorAutoLock lock(mMonitor);
330
331 while (mState == ModuleState::kDecoding && mQueue.empty()) {
332 // Signal that we require more input.
333 INVOKE_CALLBACK(InputExhausted);
334 lock.Wait();
335 }
336
337 return mState != ModuleState::kStopping;
338 }
339
340
341 already_AddRefed<MediaRawData>
PeekNextSample()342 MediaCodecDataDecoder::PeekNextSample()
343 {
344 MonitorAutoLock lock(mMonitor);
345
346 if (mState == ModuleState::kFlushing) {
347 mDecoder->Flush();
348 ClearQueue();
349 SetState(ModuleState::kDecoding);
350 lock.Notify();
351 return nullptr;
352 }
353
354 if (mQueue.empty()) {
355 if (mState == ModuleState::kDrainQueue) {
356 SetState(ModuleState::kDrainDecoder);
357 }
358 return nullptr;
359 }
360
361 // We're not stopping or flushing, so try to get a sample.
362 return RefPtr<MediaRawData>(mQueue.front()).forget();
363 }
364
365 nsresult
QueueSample(const MediaRawData * aSample)366 MediaCodecDataDecoder::QueueSample(const MediaRawData* aSample)
367 {
368 MOZ_ASSERT(aSample);
369 AutoLocalJNIFrame frame(jni::GetEnvForThread(), 1);
370
371 // We have a sample, try to feed it to the decoder.
372 int32_t inputIndex = -1;
373 nsresult res = mDecoder->DequeueInputBuffer(kDecoderTimeout, &inputIndex);
374 if (NS_FAILED(res)) {
375 return res;
376 }
377
378 if (inputIndex < 0) {
379 // There is no valid input buffer available.
380 return NS_ERROR_FAILURE;
381 }
382
383 jni::Object::LocalRef buffer(frame.GetEnv());
384 res = GetInputBuffer(frame.GetEnv(), inputIndex, &buffer);
385 if (NS_FAILED(res)) {
386 return res;
387 }
388
389 void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
390
391 MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >=
392 aSample->Size(),
393 "Decoder buffer is not large enough for sample");
394
395 PodCopy(static_cast<uint8_t*>(directBuffer), aSample->Data(), aSample->Size());
396
397 CryptoInfo::LocalRef cryptoInfo = GetCryptoInfoFromSample(aSample);
398 if (cryptoInfo) {
399 res = mDecoder->QueueSecureInputBuffer(inputIndex, 0, cryptoInfo,
400 aSample->mTime, 0);
401 } else {
402 res = mDecoder->QueueInputBuffer(inputIndex, 0, aSample->Size(),
403 aSample->mTime, 0);
404 }
405
406 if (NS_FAILED(res)) {
407 return res;
408 }
409
410 mDurations.push_back(TimeUnit::FromMicroseconds(aSample->mDuration));
411 return NS_OK;
412 }
413
414 nsresult
QueueEOS()415 MediaCodecDataDecoder::QueueEOS()
416 {
417 mMonitor.AssertCurrentThreadOwns();
418
419 nsresult res = NS_OK;
420 int32_t inputIndex = -1;
421 res = mDecoder->DequeueInputBuffer(kDecoderTimeout, &inputIndex);
422 if (NS_FAILED(res) || inputIndex < 0) {
423 return res;
424 }
425
426 res = mDecoder->QueueInputBuffer(inputIndex, 0, 0, 0,
427 MediaCodec::BUFFER_FLAG_END_OF_STREAM);
428 if (NS_SUCCEEDED(res)) {
429 SetState(ModuleState::kDrainWaitEOS);
430 mMonitor.Notify();
431 }
432 return res;
433 }
434
435 void
HandleEOS(int32_t aOutputStatus)436 MediaCodecDataDecoder::HandleEOS(int32_t aOutputStatus)
437 {
438 MonitorAutoLock lock(mMonitor);
439
440 if (mState == ModuleState::kDrainWaitEOS) {
441 SetState(ModuleState::kDecoding);
442 mMonitor.Notify();
443
444 INVOKE_CALLBACK(DrainComplete);
445 }
446
447 mDecoder->ReleaseOutputBuffer(aOutputStatus, false);
448 }
449
450 Maybe<TimeUnit>
GetOutputDuration()451 MediaCodecDataDecoder::GetOutputDuration()
452 {
453 if (mDurations.empty()) {
454 return Nothing();
455 }
456 const Maybe<TimeUnit> duration = Some(mDurations.front());
457 mDurations.pop_front();
458 return duration;
459 }
460
461 nsresult
ProcessOutput(BufferInfo::Param aInfo,MediaFormat::Param aFormat,int32_t aStatus)462 MediaCodecDataDecoder::ProcessOutput(
463 BufferInfo::Param aInfo, MediaFormat::Param aFormat, int32_t aStatus)
464 {
465 AutoLocalJNIFrame frame(jni::GetEnvForThread(), 1);
466
467 const Maybe<TimeUnit> duration = GetOutputDuration();
468 if (!duration) {
469 // Some devices report failure in QueueSample while actually succeeding at
470 // it, in which case we get an output buffer without having a cached duration
471 // (bug 1273523).
472 return NS_OK;
473 }
474
475 const auto buffer = jni::Object::LocalRef::Adopt(
476 frame.GetEnv()->GetObjectArrayElement(mOutputBuffers.Get(), aStatus));
477
478 if (buffer) {
479 // The buffer will be null on Android L if we are decoding to a Surface.
480 void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
481 Output(aInfo, directBuffer, aFormat, duration.value());
482 }
483
484 // The Surface will be updated at this point (for video).
485 mDecoder->ReleaseOutputBuffer(aStatus, true);
486 PostOutput(aInfo, aFormat, duration.value());
487
488 return NS_OK;
489 }
490
491 void
DecoderLoop()492 MediaCodecDataDecoder::DecoderLoop()
493 {
494 bool isOutputDone = false;
495 AutoLocalJNIFrame frame(jni::GetEnvForThread(), 1);
496 MediaFormat::LocalRef outputFormat(frame.GetEnv());
497 nsresult res = NS_OK;
498
499 while (WaitForInput()) {
500 RefPtr<MediaRawData> sample = PeekNextSample();
501
502 {
503 MonitorAutoLock lock(mMonitor);
504 if (mState == ModuleState::kDrainDecoder) {
505 MOZ_ASSERT(!sample, "Shouldn't have a sample when pushing EOF frame");
506 res = QueueEOS();
507 BREAK_ON_DECODER_ERROR();
508 }
509 }
510
511 if (sample) {
512 res = QueueSample(sample);
513 if (NS_SUCCEEDED(res)) {
514 // We've fed this into the decoder, so remove it from the queue.
515 MonitorAutoLock lock(mMonitor);
516 MOZ_RELEASE_ASSERT(mQueue.size(), "Queue may not be empty");
517 mQueue.pop_front();
518 isOutputDone = false;
519 }
520 }
521
522 if (isOutputDone) {
523 continue;
524 }
525
526 BufferInfo::LocalRef bufferInfo;
527 nsresult res = BufferInfo::New(&bufferInfo);
528 BREAK_ON_DECODER_ERROR();
529
530 int32_t outputStatus = -1;
531 res = mDecoder->DequeueOutputBuffer(bufferInfo, kDecoderTimeout,
532 &outputStatus);
533 BREAK_ON_DECODER_ERROR();
534
535 if (outputStatus == MediaCodec::INFO_TRY_AGAIN_LATER) {
536 // We might want to call mCallback->InputExhausted() here, but there seems
537 // to be some possible bad interactions here with the threading.
538 } else if (outputStatus == MediaCodec::INFO_OUTPUT_BUFFERS_CHANGED) {
539 res = ResetOutputBuffers();
540 BREAK_ON_DECODER_ERROR();
541 } else if (outputStatus == MediaCodec::INFO_OUTPUT_FORMAT_CHANGED) {
542 res = mDecoder->GetOutputFormat(ReturnTo(&outputFormat));
543 BREAK_ON_DECODER_ERROR();
544 } else if (outputStatus < 0) {
545 NS_WARNING("Unknown error from decoder!");
546 INVOKE_CALLBACK(Error,
547 MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
548 __func__));
549 // Don't break here just in case it's recoverable. If it's not, other
550 // stuff will fail later and we'll bail out.
551 } else {
552 // We have a valid buffer index >= 0 here.
553 int32_t flags;
554 nsresult res = bufferInfo->Flags(&flags);
555 BREAK_ON_DECODER_ERROR();
556
557 if (flags & MediaCodec::BUFFER_FLAG_END_OF_STREAM) {
558 HandleEOS(outputStatus);
559 isOutputDone = true;
560 // We only queue empty EOF frames, so we're done for now.
561 continue;
562 }
563
564 res = ProcessOutput(bufferInfo, outputFormat, outputStatus);
565 BREAK_ON_DECODER_ERROR();
566 }
567 }
568
569 Cleanup();
570
571 // We're done.
572 MonitorAutoLock lock(mMonitor);
573 SetState(ModuleState::kShutdown);
574 mMonitor.Notify();
575 }
576
577 const char*
ModuleStateStr(ModuleState aState)578 MediaCodecDataDecoder::ModuleStateStr(ModuleState aState) {
579 switch (aState) {
580 case ModuleState::kDecoding: return "Decoding";
581 case ModuleState::kFlushing: return "Flushing";
582 case ModuleState::kDrainQueue: return "DrainQueue";
583 case ModuleState::kDrainDecoder: return "DrainDecoder";
584 case ModuleState::kDrainWaitEOS: return "DrainWaitEOS";
585 case ModuleState::kStopping: return "Stopping";
586 case ModuleState::kShutdown: return "Shutdown";
587 default: MOZ_ASSERT_UNREACHABLE("Invalid state.");
588 }
589 return "Unknown";
590 }
591
592 bool
SetState(ModuleState aState)593 MediaCodecDataDecoder::SetState(ModuleState aState)
594 {
595 bool ok = true;
596
597 if (mState == ModuleState::kShutdown) {
598 ok = false;
599 } else if (mState == ModuleState::kStopping) {
600 ok = aState == ModuleState::kShutdown;
601 } else if (aState == ModuleState::kDrainDecoder) {
602 ok = mState == ModuleState::kDrainQueue;
603 } else if (aState == ModuleState::kDrainWaitEOS) {
604 ok = mState == ModuleState::kDrainDecoder;
605 }
606
607 if (ok) {
608 LOG("%s -> %s", ModuleStateStr(mState), ModuleStateStr(aState));
609 mState = aState;
610 } else {
611 LOG("Fail to transit from %s to %s state", ModuleStateStr(mState), ModuleStateStr(aState));
612 }
613
614 return ok;
615 }
616
617 void
ClearQueue()618 MediaCodecDataDecoder::ClearQueue()
619 {
620 mMonitor.AssertCurrentThreadOwns();
621
622 mQueue.clear();
623 mDurations.clear();
624 }
625
626 void
Input(MediaRawData * aSample)627 MediaCodecDataDecoder::Input(MediaRawData* aSample)
628 {
629 MonitorAutoLock lock(mMonitor);
630 mQueue.push_back(aSample);
631 lock.NotifyAll();
632 }
633
634 nsresult
ResetInputBuffers()635 MediaCodecDataDecoder::ResetInputBuffers()
636 {
637 return mDecoder->GetInputBuffers(ReturnTo(&mInputBuffers));
638 }
639
640 nsresult
ResetOutputBuffers()641 MediaCodecDataDecoder::ResetOutputBuffers()
642 {
643 return mDecoder->GetOutputBuffers(ReturnTo(&mOutputBuffers));
644 }
645
646 void
Flush()647 MediaCodecDataDecoder::Flush()
648 {
649 MonitorAutoLock lock(mMonitor);
650 if (!SetState(ModuleState::kFlushing)) {
651 return;
652 }
653 lock.Notify();
654
655 while (mState == ModuleState::kFlushing) {
656 lock.Wait();
657 }
658 }
659
660 void
Drain()661 MediaCodecDataDecoder::Drain()
662 {
663 MonitorAutoLock lock(mMonitor);
664 if (mState == ModuleState::kDrainDecoder ||
665 mState == ModuleState::kDrainQueue) {
666 return;
667 }
668
669 SetState(ModuleState::kDrainQueue);
670 lock.Notify();
671 }
672
673
674 void
Shutdown()675 MediaCodecDataDecoder::Shutdown()
676 {
677 MonitorAutoLock lock(mMonitor);
678
679 SetState(ModuleState::kStopping);
680 lock.Notify();
681
682 while (mThread && mState != ModuleState::kShutdown) {
683 lock.Wait();
684 }
685
686 if (mThread) {
687 mThread->Shutdown();
688 mThread = nullptr;
689 }
690
691 if (mDecoder) {
692 mDecoder->Stop();
693 mDecoder->Release();
694 mDecoder = nullptr;
695 }
696 }
697
698 } // mozilla
699