content/media/omx/OmxDecoder.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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();
  1002       break;
  1005     case kNotifyStatusChanged:
  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;
  1013     default:
  1014       TRESPASS();
  1015       break;
  1019 void OmxDecoder::PostReleaseVideoBuffer(MediaBuffer *aBuffer, const FenceHandle& aReleaseFenceHandle)
  1022     Mutex::Autolock autoLock(mPendingVideoBuffersLock);
  1023     if (aBuffer) {
  1024       mPendingVideoBuffers.push(BufferItem(aBuffer, aReleaseFenceHandle));
  1028   sp<AMessage> notify =
  1029             new AMessage(kNotifyPostReleaseVideoBuffer, mReflector->id());
  1030   // post AMessage to OmxDecoder via ALooper.
  1031   notify->post();
  1034 void OmxDecoder::ReleaseAllPendingVideoBuffersLocked()
  1036   Vector<BufferItem> releasingVideoBuffers;
  1038     Mutex::Autolock autoLock(mPendingVideoBuffersLock);
  1040     int size = mPendingVideoBuffers.size();
  1041     for (int i = 0; i < size; i++) {
  1042       releasingVideoBuffers.push(mPendingVideoBuffers[i]);
  1044     mPendingVideoBuffers.clear();
  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();
  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();
  1074   releasingVideoBuffers.clear();
  1077 /* static */ void
  1078 OmxDecoder::RecycleCallback(TextureClient* aClient, void* aClosure)
  1080   OmxDecoder* decoder = static_cast<OmxDecoder*>(aClosure);
  1081   GrallocTextureClientOGL* client = static_cast<GrallocTextureClientOGL*>(aClient);
  1083   aClient->ClearRecycleCallback();
  1084   decoder->PostReleaseVideoBuffer(client->GetMediaBuffer(), client->GetReleaseFenceHandle());
  1087 int64_t OmxDecoder::ProcessCachedData(int64_t aOffset, bool aWaitForCompletion)
  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
  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();
  1127   return resourceLength - aOffset - bufferLength;

mercurial