Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <unistd.h>
7 #include <fcntl.h>
9 #include "base/basictypes.h"
10 #include <cutils/properties.h>
11 #include <stagefright/foundation/ADebug.h>
12 #include <stagefright/foundation/AMessage.h>
13 #include <stagefright/MediaExtractor.h>
14 #include <stagefright/MetaData.h>
15 #include <stagefright/OMXClient.h>
16 #include <stagefright/OMXCodec.h>
17 #include <OMX.h>
18 #if MOZ_WIDGET_GONK && ANDROID_VERSION >= 17
19 #include <ui/Fence.h>
20 #endif
22 #include "mozilla/layers/GrallocTextureClient.h"
23 #include "mozilla/layers/TextureClient.h"
24 #include "mozilla/Preferences.h"
25 #include "mozilla/Types.h"
26 #include "mozilla/Monitor.h"
27 #include "nsMimeTypes.h"
28 #include "MPAPI.h"
29 #include "prlog.h"
31 #include "GonkNativeWindow.h"
32 #include "GonkNativeWindowClient.h"
33 #include "OMXCodecProxy.h"
34 #include "OmxDecoder.h"
35 #include "nsISeekableStream.h"
37 #ifdef PR_LOGGING
38 PRLogModuleInfo *gOmxDecoderLog;
39 #define LOG(type, msg...) PR_LOG(gOmxDecoderLog, type, (msg))
40 #else
41 #define LOG(x...)
42 #endif
44 using namespace MPAPI;
45 using namespace mozilla;
46 using namespace mozilla::gfx;
47 using namespace mozilla::layers;
49 namespace mozilla {
51 class ReleaseOmxDecoderRunnable : public nsRunnable
52 {
53 public:
54 ReleaseOmxDecoderRunnable(const android::sp<android::OmxDecoder>& aOmxDecoder)
55 : mOmxDecoder(aOmxDecoder)
56 {
57 }
59 NS_METHOD Run() MOZ_OVERRIDE
60 {
61 MOZ_ASSERT(NS_IsMainThread());
62 mOmxDecoder = nullptr; // release OmxDecoder
63 return NS_OK;
64 }
66 private:
67 android::sp<android::OmxDecoder> mOmxDecoder;
68 };
70 class OmxDecoderProcessCachedDataTask : public Task
71 {
72 public:
73 OmxDecoderProcessCachedDataTask(android::OmxDecoder* aOmxDecoder, int64_t aOffset)
74 : mOmxDecoder(aOmxDecoder),
75 mOffset(aOffset)
76 { }
78 void Run()
79 {
80 MOZ_ASSERT(!NS_IsMainThread());
81 MOZ_ASSERT(mOmxDecoder.get());
82 int64_t rem = mOmxDecoder->ProcessCachedData(mOffset, false);
84 if (rem <= 0) {
85 ReleaseOmxDecoderRunnable* r = new ReleaseOmxDecoderRunnable(mOmxDecoder);
86 mOmxDecoder.clear();
87 NS_DispatchToMainThread(r);
88 }
89 }
91 private:
92 android::sp<android::OmxDecoder> mOmxDecoder;
93 int64_t mOffset;
94 };
96 // When loading an MP3 stream from a file, we need to parse the file's
97 // content to find its duration. Reading files of 100 MiB or more can
98 // delay the player app noticably, so the file is read and decoded in
99 // smaller chunks.
100 //
101 // We first read on the decode thread, but parsing must be done on the
102 // main thread. After we read the file's initial MiBs in the decode
103 // thread, an instance of this class is scheduled to the main thread for
104 // parsing the MP3 stream. The decode thread waits until it has finished.
105 //
106 // If there is more data available from the file, the runnable dispatches
107 // a task to the IO thread for retrieving the next chunk of data, and
108 // the IO task dispatches a runnable to the main thread for parsing the
109 // data. This goes on until all of the MP3 file has been parsed.
111 class OmxDecoderNotifyDataArrivedRunnable : public nsRunnable
112 {
113 public:
114 OmxDecoderNotifyDataArrivedRunnable(android::OmxDecoder* aOmxDecoder,
115 const char* aBuffer, uint64_t aLength,
116 int64_t aOffset, uint64_t aFullLength)
117 : mOmxDecoder(aOmxDecoder),
118 mBuffer(aBuffer),
119 mLength(aLength),
120 mOffset(aOffset),
121 mFullLength(aFullLength),
122 mCompletedMonitor("OmxDecoderNotifyDataArrived.mCompleted"),
123 mCompleted(false)
124 {
125 MOZ_ASSERT(mOmxDecoder.get());
126 MOZ_ASSERT(mBuffer.get() || !mLength);
127 }
129 NS_IMETHOD Run()
130 {
131 NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
133 NotifyDataArrived();
134 Completed();
136 return NS_OK;
137 }
139 void WaitForCompletion()
140 {
141 MOZ_ASSERT(!NS_IsMainThread());
143 MonitorAutoLock mon(mCompletedMonitor);
144 if (!mCompleted) {
145 mCompletedMonitor.Wait();
146 }
147 }
149 private:
150 void NotifyDataArrived()
151 {
152 const char* buffer = mBuffer.get();
154 while (mLength) {
155 uint32_t length = std::min<uint64_t>(mLength, UINT32_MAX);
156 bool success = mOmxDecoder->NotifyDataArrived(buffer, mLength,
157 mOffset);
158 if (!success) {
159 return;
160 }
162 buffer += length;
163 mLength -= length;
164 mOffset += length;
165 }
167 if (mOffset < mFullLength) {
168 // We cannot read data in the main thread because it
169 // might block for too long. Instead we post an IO task
170 // to the IO thread if there is more data available.
171 XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
172 new OmxDecoderProcessCachedDataTask(mOmxDecoder.get(), mOffset));
173 }
174 }
176 // Call this function at the end of Run() to notify waiting
177 // threads.
178 void Completed()
179 {
180 MonitorAutoLock mon(mCompletedMonitor);
181 MOZ_ASSERT(!mCompleted);
182 mCompleted = true;
183 mCompletedMonitor.Notify();
184 }
186 android::sp<android::OmxDecoder> mOmxDecoder;
187 nsAutoArrayPtr<const char> mBuffer;
188 uint64_t mLength;
189 int64_t mOffset;
190 uint64_t mFullLength;
192 Monitor mCompletedMonitor;
193 bool mCompleted;
194 };
196 }
198 namespace android {
200 MediaStreamSource::MediaStreamSource(MediaResource *aResource,
201 AbstractMediaDecoder *aDecoder) :
202 mResource(aResource), mDecoder(aDecoder)
203 {
204 }
206 MediaStreamSource::~MediaStreamSource()
207 {
208 }
210 status_t MediaStreamSource::initCheck() const
211 {
212 return OK;
213 }
215 ssize_t MediaStreamSource::readAt(off64_t offset, void *data, size_t size)
216 {
217 char *ptr = static_cast<char *>(data);
218 size_t todo = size;
219 while (todo > 0) {
220 Mutex::Autolock autoLock(mLock);
221 uint32_t bytesRead;
222 if ((offset != mResource->Tell() &&
223 NS_FAILED(mResource->Seek(nsISeekableStream::NS_SEEK_SET, offset))) ||
224 NS_FAILED(mResource->Read(ptr, todo, &bytesRead))) {
225 return ERROR_IO;
226 }
228 if (bytesRead == 0) {
229 return size - todo;
230 }
232 offset += bytesRead;
233 todo -= bytesRead;
234 ptr += bytesRead;
235 }
236 return size;
237 }
239 status_t MediaStreamSource::getSize(off64_t *size)
240 {
241 uint64_t length = mResource->GetLength();
242 if (length == static_cast<uint64_t>(-1))
243 return ERROR_UNSUPPORTED;
245 *size = length;
247 return OK;
248 }
250 } // namespace android
252 using namespace android;
254 OmxDecoder::OmxDecoder(MediaResource *aResource,
255 AbstractMediaDecoder *aDecoder) :
256 mDecoder(aDecoder),
257 mResource(aResource),
258 mDisplayWidth(0),
259 mDisplayHeight(0),
260 mVideoWidth(0),
261 mVideoHeight(0),
262 mVideoColorFormat(0),
263 mVideoStride(0),
264 mVideoSliceHeight(0),
265 mVideoRotation(0),
266 mAudioChannels(-1),
267 mAudioSampleRate(-1),
268 mDurationUs(-1),
269 mMP3FrameParser(aResource->GetLength()),
270 mIsMp3(false),
271 mVideoBuffer(nullptr),
272 mAudioBuffer(nullptr),
273 mIsVideoSeeking(false),
274 mAudioMetadataRead(false),
275 mAudioPaused(false),
276 mVideoPaused(false)
277 {
278 mLooper = new ALooper;
279 mLooper->setName("OmxDecoder");
281 mReflector = new AHandlerReflector<OmxDecoder>(this);
282 // Register AMessage handler to ALooper.
283 mLooper->registerHandler(mReflector);
284 // Start ALooper thread.
285 mLooper->start();
286 }
288 OmxDecoder::~OmxDecoder()
289 {
290 MOZ_ASSERT(NS_IsMainThread());
292 ReleaseMediaResources();
294 // unregister AMessage handler from ALooper.
295 mLooper->unregisterHandler(mReflector->id());
296 // Stop ALooper thread.
297 mLooper->stop();
298 }
300 void OmxDecoder::statusChanged()
301 {
302 sp<AMessage> notify =
303 new AMessage(kNotifyStatusChanged, mReflector->id());
304 // post AMessage to OmxDecoder via ALooper.
305 notify->post();
306 }
308 static sp<IOMX> sOMX = nullptr;
309 static sp<IOMX> GetOMX()
310 {
311 if(sOMX.get() == nullptr) {
312 sOMX = new OMX;
313 }
314 return sOMX;
315 }
317 bool OmxDecoder::Init(sp<MediaExtractor>& extractor) {
318 #ifdef PR_LOGGING
319 if (!gOmxDecoderLog) {
320 gOmxDecoderLog = PR_NewLogModule("OmxDecoder");
321 }
322 #endif
324 const char* extractorMime;
325 sp<MetaData> meta = extractor->getMetaData();
326 if (meta->findCString(kKeyMIMEType, &extractorMime) && !strcasecmp(extractorMime, AUDIO_MP3)) {
327 mIsMp3 = true;
328 }
330 ssize_t audioTrackIndex = -1;
331 ssize_t videoTrackIndex = -1;
333 for (size_t i = 0; i < extractor->countTracks(); ++i) {
334 sp<MetaData> meta = extractor->getTrackMetaData(i);
336 int32_t bitRate;
337 if (!meta->findInt32(kKeyBitRate, &bitRate))
338 bitRate = 0;
340 const char *mime;
341 if (!meta->findCString(kKeyMIMEType, &mime)) {
342 continue;
343 }
345 if (videoTrackIndex == -1 && !strncasecmp(mime, "video/", 6)) {
346 videoTrackIndex = i;
347 } else if (audioTrackIndex == -1 && !strncasecmp(mime, "audio/", 6)) {
348 audioTrackIndex = i;
349 }
350 }
352 if (videoTrackIndex == -1 && audioTrackIndex == -1) {
353 NS_WARNING("OMX decoder could not find video or audio tracks");
354 return false;
355 }
357 mResource->SetReadMode(MediaCacheStream::MODE_PLAYBACK);
359 if (videoTrackIndex != -1) {
360 mVideoTrack = extractor->getTrack(videoTrackIndex);
361 }
363 if (audioTrackIndex != -1) {
364 mAudioTrack = extractor->getTrack(audioTrackIndex);
366 #ifdef MOZ_AUDIO_OFFLOAD
367 // mAudioTrack is be used by OMXCodec. For offloaded audio track, using same
368 // object gives undetermined behavior. So get a new track
369 mAudioOffloadTrack = extractor->getTrack(audioTrackIndex);
370 #endif
371 }
372 return true;
373 }
375 bool OmxDecoder::TryLoad() {
377 if (!AllocateMediaResources()) {
378 return false;
379 }
381 //check if video is waiting resources
382 if (mVideoSource.get()) {
383 if (mVideoSource->IsWaitingResources()) {
384 return true;
385 }
386 }
388 // calculate duration
389 int64_t totalDurationUs = 0;
390 int64_t durationUs = 0;
391 if (mVideoTrack.get() && mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
392 if (durationUs > totalDurationUs)
393 totalDurationUs = durationUs;
394 }
395 if (mAudioTrack.get()) {
396 durationUs = -1;
397 const char* audioMime;
398 sp<MetaData> meta = mAudioTrack->getFormat();
400 if (mIsMp3) {
401 // Feed MP3 parser with cached data. Local files will be fully
402 // cached already, network streams will update with sucessive
403 // calls to NotifyDataArrived.
404 if (ProcessCachedData(0, true) >= 0) {
405 durationUs = mMP3FrameParser.GetDuration();
406 if (durationUs > totalDurationUs) {
407 totalDurationUs = durationUs;
408 }
409 }
410 }
411 if ((durationUs == -1) && meta->findInt64(kKeyDuration, &durationUs)) {
412 if (durationUs > totalDurationUs) {
413 totalDurationUs = durationUs;
414 }
415 }
416 }
417 mDurationUs = totalDurationUs;
419 // read video metadata
420 if (mVideoSource.get() && !SetVideoFormat()) {
421 NS_WARNING("Couldn't set OMX video format");
422 return false;
423 }
425 // read audio metadata
426 if (mAudioSource.get()) {
427 // To reliably get the channel and sample rate data we need to read from the
428 // audio source until we get a INFO_FORMAT_CHANGE status
429 status_t err = mAudioSource->read(&mAudioBuffer);
430 if (err != INFO_FORMAT_CHANGED) {
431 if (err != OK) {
432 NS_WARNING("Couldn't read audio buffer from OMX decoder");
433 return false;
434 }
435 sp<MetaData> meta = mAudioSource->getFormat();
436 if (!meta->findInt32(kKeyChannelCount, &mAudioChannels) ||
437 !meta->findInt32(kKeySampleRate, &mAudioSampleRate)) {
438 NS_WARNING("Couldn't get audio metadata from OMX decoder");
439 return false;
440 }
441 mAudioMetadataRead = true;
442 }
443 else if (!SetAudioFormat()) {
444 NS_WARNING("Couldn't set audio format");
445 return false;
446 }
447 }
449 return true;
450 }
452 bool OmxDecoder::IsDormantNeeded()
453 {
454 if (mVideoTrack.get()) {
455 return true;
456 }
457 return false;
458 }
460 bool OmxDecoder::IsWaitingMediaResources()
461 {
462 if (mVideoSource.get()) {
463 return mVideoSource->IsWaitingResources();
464 }
465 return false;
466 }
468 static bool isInEmulator()
469 {
470 char propQemu[PROPERTY_VALUE_MAX];
471 property_get("ro.kernel.qemu", propQemu, "");
472 return !strncmp(propQemu, "1", 1);
473 }
475 bool OmxDecoder::AllocateMediaResources()
476 {
477 // OMXClient::connect() always returns OK and abort's fatally if
478 // it can't connect.
479 OMXClient client;
480 DebugOnly<status_t> err = client.connect();
481 NS_ASSERTION(err == OK, "Failed to connect to OMX in mediaserver.");
482 sp<IOMX> omx = client.interface();
484 if ((mVideoTrack != nullptr) && (mVideoSource == nullptr)) {
485 mNativeWindow = new GonkNativeWindow();
486 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
487 mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow->getBufferQueue());
488 #else
489 mNativeWindowClient = new GonkNativeWindowClient(mNativeWindow);
490 #endif
492 // Experience with OMX codecs is that only the HW decoders are
493 // worth bothering with, at least on the platforms where this code
494 // is currently used, and for formats this code is currently used
495 // for (h.264). So if we don't get a hardware decoder, just give
496 // up.
497 int flags = kHardwareCodecsOnly;
499 if (isInEmulator()) {
500 // If we are in emulator, allow to fall back to software.
501 flags = 0;
502 }
503 mVideoSource =
504 OMXCodecProxy::Create(omx,
505 mVideoTrack->getFormat(),
506 false, // decoder
507 mVideoTrack,
508 nullptr,
509 flags,
510 mNativeWindowClient);
511 if (mVideoSource == nullptr) {
512 NS_WARNING("Couldn't create OMX video source");
513 return false;
514 } else {
515 sp<OMXCodecProxy::EventListener> listener = this;
516 mVideoSource->setEventListener(listener);
517 mVideoSource->requestResource();
518 }
519 }
521 if ((mAudioTrack != nullptr) && (mAudioSource == nullptr)) {
522 const char *audioMime = nullptr;
523 sp<MetaData> meta = mAudioTrack->getFormat();
524 if (!meta->findCString(kKeyMIMEType, &audioMime)) {
525 return false;
526 }
527 if (!strcasecmp(audioMime, "audio/raw")) {
528 mAudioSource = mAudioTrack;
529 } else {
530 // try to load hardware codec in mediaserver process.
531 int flags = kHardwareCodecsOnly;
532 mAudioSource = OMXCodec::Create(omx,
533 mAudioTrack->getFormat(),
534 false, // decoder
535 mAudioTrack,
536 nullptr,
537 flags);
538 }
540 if (mAudioSource == nullptr) {
541 // try to load software codec in this process.
542 int flags = kSoftwareCodecsOnly;
543 mAudioSource = OMXCodec::Create(GetOMX(),
544 mAudioTrack->getFormat(),
545 false, // decoder
546 mAudioTrack,
547 nullptr,
548 flags);
549 if (mAudioSource == nullptr) {
550 NS_WARNING("Couldn't create OMX audio source");
551 return false;
552 }
553 }
554 if (mAudioSource->start() != OK) {
555 NS_WARNING("Couldn't start OMX audio source");
556 mAudioSource.clear();
557 return false;
558 }
559 }
560 return true;
561 }
564 void OmxDecoder::ReleaseMediaResources() {
565 {
566 // Free all pending video buffers.
567 Mutex::Autolock autoLock(mSeekLock);
568 ReleaseAllPendingVideoBuffersLocked();
569 }
571 ReleaseVideoBuffer();
572 ReleaseAudioBuffer();
574 if (mVideoSource.get()) {
575 mVideoSource->stop();
576 mVideoSource.clear();
577 }
579 if (mAudioSource.get()) {
580 mAudioSource->stop();
581 mAudioSource.clear();
582 }
584 mNativeWindowClient.clear();
585 mNativeWindow.clear();
586 }
588 bool OmxDecoder::SetVideoFormat() {
589 const char *componentName;
591 if (!mVideoSource->getFormat()->findInt32(kKeyWidth, &mVideoWidth) ||
592 !mVideoSource->getFormat()->findInt32(kKeyHeight, &mVideoHeight) ||
593 !mVideoSource->getFormat()->findCString(kKeyDecoderComponent, &componentName) ||
594 !mVideoSource->getFormat()->findInt32(kKeyColorFormat, &mVideoColorFormat) ) {
595 return false;
596 }
598 if (!mVideoTrack.get() || !mVideoTrack->getFormat()->findInt32(kKeyDisplayWidth, &mDisplayWidth)) {
599 mDisplayWidth = mVideoWidth;
600 NS_WARNING("display width not available, assuming width");
601 }
603 if (!mVideoTrack.get() || !mVideoTrack->getFormat()->findInt32(kKeyDisplayHeight, &mDisplayHeight)) {
604 mDisplayHeight = mVideoHeight;
605 NS_WARNING("display height not available, assuming height");
606 }
608 if (!mVideoSource->getFormat()->findInt32(kKeyStride, &mVideoStride)) {
609 mVideoStride = mVideoWidth;
610 NS_WARNING("stride not available, assuming width");
611 }
613 if (!mVideoSource->getFormat()->findInt32(kKeySliceHeight, &mVideoSliceHeight)) {
614 mVideoSliceHeight = mVideoHeight;
615 NS_WARNING("slice height not available, assuming height");
616 }
618 // Since ICS, valid video side is caluculated from kKeyCropRect.
619 // kKeyWidth means decoded video buffer width.
620 // kKeyHeight means decoded video buffer height.
621 // On some hardwares, decoded video buffer and valid video size are different.
622 int32_t crop_left, crop_top, crop_right, crop_bottom;
623 if (mVideoSource->getFormat()->findRect(kKeyCropRect,
624 &crop_left,
625 &crop_top,
626 &crop_right,
627 &crop_bottom)) {
628 mVideoWidth = crop_right - crop_left + 1;
629 mVideoHeight = crop_bottom - crop_top + 1;
630 }
632 if (!mVideoSource->getFormat()->findInt32(kKeyRotation, &mVideoRotation)) {
633 mVideoRotation = 0;
634 NS_WARNING("rotation not available, assuming 0");
635 }
637 LOG(PR_LOG_DEBUG, "display width: %d display height %d width: %d height: %d component: %s format: %d stride: %d sliceHeight: %d rotation: %d",
638 mDisplayWidth, mDisplayHeight, mVideoWidth, mVideoHeight, componentName,
639 mVideoColorFormat, mVideoStride, mVideoSliceHeight, mVideoRotation);
641 return true;
642 }
644 bool OmxDecoder::SetAudioFormat() {
645 // If the format changed, update our cached info.
646 if (!mAudioSource->getFormat()->findInt32(kKeyChannelCount, &mAudioChannels) ||
647 !mAudioSource->getFormat()->findInt32(kKeySampleRate, &mAudioSampleRate)) {
648 return false;
649 }
651 LOG(PR_LOG_DEBUG, "channelCount: %d sampleRate: %d",
652 mAudioChannels, mAudioSampleRate);
654 return true;
655 }
657 void OmxDecoder::ReleaseDecoder()
658 {
659 mDecoder = nullptr;
660 }
662 bool OmxDecoder::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
663 {
664 if (!mAudioTrack.get() || !mIsMp3 || !mMP3FrameParser.IsMP3() || !mDecoder) {
665 return false;
666 }
668 mMP3FrameParser.Parse(aBuffer, aLength, aOffset);
670 int64_t durationUs = mMP3FrameParser.GetDuration();
672 if (durationUs != mDurationUs) {
673 mDurationUs = durationUs;
675 MOZ_ASSERT(mDecoder);
676 ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
677 mDecoder->UpdateEstimatedMediaDuration(mDurationUs);
678 }
680 return true;
681 }
683 void OmxDecoder::ReleaseVideoBuffer() {
684 if (mVideoBuffer) {
685 mVideoBuffer->release();
686 mVideoBuffer = nullptr;
687 }
688 }
690 void OmxDecoder::ReleaseAudioBuffer() {
691 if (mAudioBuffer) {
692 mAudioBuffer->release();
693 mAudioBuffer = nullptr;
694 }
695 }
697 void OmxDecoder::PlanarYUV420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
698 void *y = aData;
699 void *u = static_cast<uint8_t *>(y) + mVideoStride * mVideoSliceHeight;
700 void *v = static_cast<uint8_t *>(u) + mVideoStride/2 * mVideoSliceHeight/2;
702 aFrame->Set(aTimeUs, aKeyFrame,
703 aData, aSize, mVideoStride, mVideoSliceHeight, mVideoRotation,
704 y, mVideoStride, mVideoWidth, mVideoHeight, 0, 0,
705 u, mVideoStride/2, mVideoWidth/2, mVideoHeight/2, 0, 0,
706 v, mVideoStride/2, mVideoWidth/2, mVideoHeight/2, 0, 0);
707 }
709 void OmxDecoder::CbYCrYFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
710 aFrame->Set(aTimeUs, aKeyFrame,
711 aData, aSize, mVideoStride, mVideoSliceHeight, mVideoRotation,
712 aData, mVideoStride, mVideoWidth, mVideoHeight, 1, 1,
713 aData, mVideoStride, mVideoWidth/2, mVideoHeight/2, 0, 3,
714 aData, mVideoStride, mVideoWidth/2, mVideoHeight/2, 2, 3);
715 }
717 void OmxDecoder::SemiPlanarYUV420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
718 void *y = aData;
719 void *uv = static_cast<uint8_t *>(y) + (mVideoStride * mVideoSliceHeight);
721 aFrame->Set(aTimeUs, aKeyFrame,
722 aData, aSize, mVideoStride, mVideoSliceHeight, mVideoRotation,
723 y, mVideoStride, mVideoWidth, mVideoHeight, 0, 0,
724 uv, mVideoStride, mVideoWidth/2, mVideoHeight/2, 0, 1,
725 uv, mVideoStride, mVideoWidth/2, mVideoHeight/2, 1, 1);
726 }
728 void OmxDecoder::SemiPlanarYVU420Frame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
729 SemiPlanarYUV420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
730 aFrame->Cb.mOffset = 1;
731 aFrame->Cr.mOffset = 0;
732 }
734 bool OmxDecoder::ToVideoFrame(VideoFrame *aFrame, int64_t aTimeUs, void *aData, size_t aSize, bool aKeyFrame) {
735 const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
737 aFrame->mGraphicBuffer = nullptr;
739 switch (mVideoColorFormat) {
740 case OMX_COLOR_FormatYUV420Planar:
741 PlanarYUV420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
742 break;
743 case OMX_COLOR_FormatCbYCrY:
744 CbYCrYFrame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
745 break;
746 case OMX_COLOR_FormatYUV420SemiPlanar:
747 SemiPlanarYUV420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
748 break;
749 case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
750 SemiPlanarYVU420Frame(aFrame, aTimeUs, aData, aSize, aKeyFrame);
751 break;
752 default:
753 LOG(PR_LOG_DEBUG, "Unknown video color format %08x", mVideoColorFormat);
754 return false;
755 }
756 return true;
757 }
759 bool OmxDecoder::ToAudioFrame(AudioFrame *aFrame, int64_t aTimeUs, void *aData, size_t aDataOffset, size_t aSize, int32_t aAudioChannels, int32_t aAudioSampleRate)
760 {
761 aFrame->Set(aTimeUs, static_cast<char *>(aData) + aDataOffset, aSize, aAudioChannels, aAudioSampleRate);
762 return true;
763 }
765 bool OmxDecoder::ReadVideo(VideoFrame *aFrame, int64_t aTimeUs,
766 bool aKeyframeSkip, bool aDoSeek)
767 {
768 if (!mVideoSource.get())
769 return false;
771 ReleaseVideoBuffer();
773 status_t err;
775 if (aDoSeek) {
776 {
777 Mutex::Autolock autoLock(mSeekLock);
778 mIsVideoSeeking = true;
779 }
780 MediaSource::ReadOptions options;
781 options.setSeekTo(aTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
782 err = mVideoSource->read(&mVideoBuffer, &options);
783 {
784 Mutex::Autolock autoLock(mSeekLock);
785 mIsVideoSeeking = false;
786 PostReleaseVideoBuffer(nullptr, FenceHandle());
787 }
789 aDoSeek = false;
790 } else {
791 err = mVideoSource->read(&mVideoBuffer);
792 }
794 aFrame->mSize = 0;
796 if (err == OK) {
797 int64_t timeUs;
798 int32_t unreadable;
799 int32_t keyFrame;
801 if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs) ) {
802 NS_WARNING("OMX decoder did not return frame time");
803 return false;
804 }
806 if (!mVideoBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &keyFrame)) {
807 keyFrame = 0;
808 }
810 if (!mVideoBuffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)) {
811 unreadable = 0;
812 }
814 RefPtr<mozilla::layers::TextureClient> textureClient;
815 if ((mVideoBuffer->graphicBuffer().get())) {
816 textureClient = mNativeWindow->getTextureClientFromBuffer(mVideoBuffer->graphicBuffer().get());
817 }
819 if (textureClient) {
820 // Manually increment reference count to keep MediaBuffer alive
821 // during TextureClient is in use.
822 mVideoBuffer->add_ref();
823 GrallocTextureClientOGL* grallocClient = static_cast<GrallocTextureClientOGL*>(textureClient.get());
824 grallocClient->SetMediaBuffer(mVideoBuffer);
825 // Set recycle callback for TextureClient
826 textureClient->SetRecycleCallback(OmxDecoder::RecycleCallback, this);
828 aFrame->mGraphicBuffer = textureClient;
829 aFrame->mRotation = mVideoRotation;
830 aFrame->mTimeUs = timeUs;
831 aFrame->mKeyFrame = keyFrame;
832 aFrame->Y.mWidth = mVideoWidth;
833 aFrame->Y.mHeight = mVideoHeight;
834 // Release to hold video buffer in OmxDecoder more.
835 // MediaBuffer's ref count is changed from 2 to 1.
836 ReleaseVideoBuffer();
837 } else if (mVideoBuffer->range_length() > 0) {
838 char *data = static_cast<char *>(mVideoBuffer->data()) + mVideoBuffer->range_offset();
839 size_t length = mVideoBuffer->range_length();
841 if (unreadable) {
842 LOG(PR_LOG_DEBUG, "video frame is unreadable");
843 }
845 if (!ToVideoFrame(aFrame, timeUs, data, length, keyFrame)) {
846 return false;
847 }
848 }
850 if (aKeyframeSkip && timeUs < aTimeUs) {
851 aFrame->mShouldSkip = true;
852 }
853 }
854 else if (err == INFO_FORMAT_CHANGED) {
855 // If the format changed, update our cached info.
856 if (!SetVideoFormat()) {
857 return false;
858 } else {
859 return ReadVideo(aFrame, aTimeUs, aKeyframeSkip, aDoSeek);
860 }
861 }
862 else if (err == ERROR_END_OF_STREAM) {
863 return false;
864 }
865 else if (err == -ETIMEDOUT) {
866 LOG(PR_LOG_DEBUG, "OmxDecoder::ReadVideo timed out, will retry");
867 return true;
868 }
869 else {
870 // UNKNOWN_ERROR is sometimes is used to mean "out of memory", but
871 // regardless, don't keep trying to decode if the decoder doesn't want to.
872 LOG(PR_LOG_DEBUG, "OmxDecoder::ReadVideo failed, err=%d", err);
873 return false;
874 }
876 return true;
877 }
879 bool OmxDecoder::ReadAudio(AudioFrame *aFrame, int64_t aSeekTimeUs)
880 {
881 status_t err;
883 if (mAudioMetadataRead && aSeekTimeUs == -1) {
884 // Use the data read into the buffer during metadata time
885 err = OK;
886 }
887 else {
888 ReleaseAudioBuffer();
889 if (aSeekTimeUs != -1) {
890 MediaSource::ReadOptions options;
891 options.setSeekTo(aSeekTimeUs);
892 err = mAudioSource->read(&mAudioBuffer, &options);
893 } else {
894 err = mAudioSource->read(&mAudioBuffer);
895 }
896 }
897 mAudioMetadataRead = false;
899 aSeekTimeUs = -1;
900 aFrame->mSize = 0;
902 if (err == OK && mAudioBuffer && mAudioBuffer->range_length() != 0) {
903 int64_t timeUs;
904 if (!mAudioBuffer->meta_data()->findInt64(kKeyTime, &timeUs))
905 return false;
907 return ToAudioFrame(aFrame, timeUs,
908 mAudioBuffer->data(),
909 mAudioBuffer->range_offset(),
910 mAudioBuffer->range_length(),
911 mAudioChannels, mAudioSampleRate);
912 }
913 else if (err == INFO_FORMAT_CHANGED) {
914 // If the format changed, update our cached info.
915 if (!SetAudioFormat()) {
916 return false;
917 } else {
918 return ReadAudio(aFrame, aSeekTimeUs);
919 }
920 }
921 else if (err == ERROR_END_OF_STREAM) {
922 if (aFrame->mSize == 0) {
923 return false;
924 }
925 }
926 else if (err == -ETIMEDOUT) {
927 LOG(PR_LOG_DEBUG, "OmxDecoder::ReadAudio timed out, will retry");
928 return true;
929 }
930 else if (err != OK) {
931 LOG(PR_LOG_DEBUG, "OmxDecoder::ReadAudio failed, err=%d", err);
932 return false;
933 }
935 return true;
936 }
938 nsresult OmxDecoder::Play()
939 {
940 if (!mVideoPaused && !mAudioPaused) {
941 return NS_OK;
942 }
944 if (mVideoPaused && mVideoSource.get() && mVideoSource->start() != OK) {
945 return NS_ERROR_UNEXPECTED;
946 }
947 mVideoPaused = false;
949 if (mAudioPaused && mAudioSource.get() && mAudioSource->start() != OK) {
950 return NS_ERROR_UNEXPECTED;
951 }
952 mAudioPaused = false;
954 return NS_OK;
955 }
957 // AOSP didn't give implementation on OMXCodec::Pause() and not define
958 // OMXCodec::Start() should be called for resuming the decoding. Currently
959 // it is customized by a specific open source repository only.
960 // ToDo The one not supported OMXCodec::Pause() should return error code here,
961 // so OMXCodec::Start() doesn't be called again for resuming. But if someone
962 // implement the OMXCodec::Pause() and need a following OMXCodec::Read() with
963 // seek option (define in MediaSource.h) then it is still not supported here.
964 // We need to fix it until it is really happened.
965 void OmxDecoder::Pause()
966 {
967 /* The implementation of OMXCodec::pause is flawed.
968 * OMXCodec::start will not restore from the paused state and result in
969 * buffer timeout which causes timeouts in mochitests.
970 * Since there is not power consumption problem in emulator, we will just
971 * return when running in emulator to fix timeouts in mochitests.
972 */
973 if (isInEmulator()) {
974 return;
975 }
977 if (mVideoPaused || mAudioPaused) {
978 return;
979 }
981 if (mVideoSource.get() && mVideoSource->pause() == OK) {
982 mVideoPaused = true;
983 }
985 if (mAudioSource.get() && mAudioSource->pause() == OK) {
986 mAudioPaused = true;
987 }
988 }
990 // Called on ALooper thread.
991 void OmxDecoder::onMessageReceived(const sp<AMessage> &msg)
992 {
993 switch (msg->what()) {
994 case kNotifyPostReleaseVideoBuffer:
995 {
996 Mutex::Autolock autoLock(mSeekLock);
997 // Free pending video buffers when OmxDecoder is not seeking video.
998 // If OmxDecoder is seeking video, the buffers are freed on seek exit.
999 if (!mIsVideoSeeking) {
1000 ReleaseAllPendingVideoBuffersLocked();
1001 }
1002 break;
1003 }
1005 case kNotifyStatusChanged:
1006 {
1007 // Our decode may have acquired the hardware resource that it needs
1008 // to start. Notify the state machine to resume loading metadata.
1009 mDecoder->NotifyWaitingForResourcesStatusChanged();
1010 break;
1011 }
1013 default:
1014 TRESPASS();
1015 break;
1016 }
1017 }
1019 void OmxDecoder::PostReleaseVideoBuffer(MediaBuffer *aBuffer, const FenceHandle& aReleaseFenceHandle)
1020 {
1021 {
1022 Mutex::Autolock autoLock(mPendingVideoBuffersLock);
1023 if (aBuffer) {
1024 mPendingVideoBuffers.push(BufferItem(aBuffer, aReleaseFenceHandle));
1025 }
1026 }
1028 sp<AMessage> notify =
1029 new AMessage(kNotifyPostReleaseVideoBuffer, mReflector->id());
1030 // post AMessage to OmxDecoder via ALooper.
1031 notify->post();
1032 }
1034 void OmxDecoder::ReleaseAllPendingVideoBuffersLocked()
1035 {
1036 Vector<BufferItem> releasingVideoBuffers;
1037 {
1038 Mutex::Autolock autoLock(mPendingVideoBuffersLock);
1040 int size = mPendingVideoBuffers.size();
1041 for (int i = 0; i < size; i++) {
1042 releasingVideoBuffers.push(mPendingVideoBuffers[i]);
1043 }
1044 mPendingVideoBuffers.clear();
1045 }
1046 // Free all pending video buffers without holding mPendingVideoBuffersLock.
1047 int size = releasingVideoBuffers.size();
1048 for (int i = 0; i < size; i++) {
1049 MediaBuffer *buffer;
1050 buffer = releasingVideoBuffers[i].mMediaBuffer;
1051 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
1052 android::sp<Fence> fence;
1053 int fenceFd = -1;
1054 fence = releasingVideoBuffers[i].mReleaseFenceHandle.mFence;
1055 if (fence.get() && fence->isValid()) {
1056 fenceFd = fence->dup();
1057 }
1058 MOZ_ASSERT(buffer->refcount() == 1);
1059 // This code expect MediaBuffer's ref count is 1.
1060 // Return gralloc buffer to ANativeWindow
1061 ANativeWindow* window = static_cast<ANativeWindow*>(mNativeWindowClient.get());
1062 window->cancelBuffer(window,
1063 buffer->graphicBuffer().get(),
1064 fenceFd);
1065 // Mark MediaBuffer as rendered.
1066 // When gralloc buffer is directly returned to ANativeWindow,
1067 // this mark is necesary.
1068 sp<MetaData> metaData = buffer->meta_data();
1069 metaData->setInt32(kKeyRendered, 1);
1070 #endif
1071 // Return MediaBuffer to OMXCodec.
1072 buffer->release();
1073 }
1074 releasingVideoBuffers.clear();
1075 }
1077 /* static */ void
1078 OmxDecoder::RecycleCallback(TextureClient* aClient, void* aClosure)
1079 {
1080 OmxDecoder* decoder = static_cast<OmxDecoder*>(aClosure);
1081 GrallocTextureClientOGL* client = static_cast<GrallocTextureClientOGL*>(aClient);
1083 aClient->ClearRecycleCallback();
1084 decoder->PostReleaseVideoBuffer(client->GetMediaBuffer(), client->GetReleaseFenceHandle());
1085 }
1087 int64_t OmxDecoder::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
1088 {
1089 // We read data in chunks of 32 KiB. We can reduce this
1090 // value if media, such as sdcards, is too slow.
1091 // Because of SD card's slowness, need to keep sReadSize to small size.
1092 // See Bug 914870.
1093 static const int64_t sReadSize = 32 * 1024;
1095 NS_ASSERTION(!NS_IsMainThread(), "Should not be on main thread.");
1097 MOZ_ASSERT(mResource);
1099 int64_t resourceLength = mResource->GetCachedDataEnd(0);
1100 NS_ENSURE_TRUE(resourceLength >= 0, -1);
1102 if (aOffset >= resourceLength) {
1103 return 0; // Cache is empty, nothing to do
1104 }
1106 int64_t bufferLength = std::min<int64_t>(resourceLength-aOffset, sReadSize);
1108 nsAutoArrayPtr<char> buffer(new char[bufferLength]);
1110 nsresult rv = mResource->ReadFromCache(buffer.get(), aOffset, bufferLength);
1111 NS_ENSURE_SUCCESS(rv, -1);
1113 nsRefPtr<OmxDecoderNotifyDataArrivedRunnable> runnable(
1114 new OmxDecoderNotifyDataArrivedRunnable(this,
1115 buffer.forget(),
1116 bufferLength,
1117 aOffset,
1118 resourceLength));
1120 rv = NS_DispatchToMainThread(runnable.get());
1121 NS_ENSURE_SUCCESS(rv, -1);
1123 if (aWaitForCompletion) {
1124 runnable->WaitForCompletion();
1125 }
1127 return resourceLength - aOffset - bufferLength;
1128 }