Bug 1154162: P1. Properly handle aspect ratio in gonk video decoder. r?alfredo draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 15 Apr 2016 17:08:17 +1000
changeset 351922 48922737a5b0204e7070330beeb49b7ad538a23d
parent 351920 276b8f4301b6bba7ae2bd2394155bd477863431b
child 518524 06d235bc3d5353a52931b416fb1cc02f3809fdca
push id15552
push userbmo:jyavenard@mozilla.com
push dateFri, 15 Apr 2016 07:13:01 +0000
reviewersalfredo
bugs1154162, 1243538
milestone48.0a1
Bug 1154162: P1. Properly handle aspect ratio in gonk video decoder. r?alfredo The display size were used for the picture size which would be wrong if any aspect ratio was set. Additionally handle bug 1243538 specifically for gonk video decoder. MozReview-Commit-ID: 76r2CWQji42
dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
dom/media/platforms/gonk/GonkVideoDecoderManager.h
--- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp
@@ -91,34 +91,23 @@ public:
 
 private:
   uint32_t mGrallocFormat;
 };
 
 GonkVideoDecoderManager::GonkVideoDecoderManager(
   mozilla::layers::ImageContainer* aImageContainer,
   const VideoInfo& aConfig)
-  : mImageContainer(aImageContainer)
+  : mConfig(aConfig)
+  , mImageContainer(aImageContainer)
   , mColorConverterBufferSize(0)
   , mPendingReleaseItemsLock("GonkVideoDecoderManager::mPendingReleaseItemsLock")
   , mNeedsCopyBuffer(false)
 {
   MOZ_COUNT_CTOR(GonkVideoDecoderManager);
-  mMimeType = aConfig.mMimeType;
-  mVideoWidth  = aConfig.mDisplay.width;
-  mVideoHeight = aConfig.mDisplay.height;
-  mDisplayWidth = aConfig.mDisplay.width;
-  mDisplayHeight = aConfig.mDisplay.height;
-  mInfo.mVideo = aConfig;
-
-  mCodecSpecificData = aConfig.mCodecSpecificConfig;
-  nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight);
-  nsIntSize frameSize(mVideoWidth, mVideoHeight);
-  mPicture = pictureRect;
-  mInitialFrame = frameSize;
 }
 
 GonkVideoDecoderManager::~GonkVideoDecoderManager()
 {
   MOZ_COUNT_DTOR(GonkVideoDecoderManager);
 }
 
 nsresult
@@ -128,35 +117,31 @@ GonkVideoDecoderManager::Shutdown()
   return GonkDecoderManager::Shutdown();
 }
 
 RefPtr<MediaDataDecoder::InitPromise>
 GonkVideoDecoderManager::Init()
 {
   mNeedsCopyBuffer = false;
 
-  nsIntSize displaySize(mDisplayWidth, mDisplayHeight);
-  nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight);
-
   uint32_t maxWidth, maxHeight;
   char propValue[PROPERTY_VALUE_MAX];
   property_get("ro.moz.omx.hw.max_width", propValue, "-1");
   maxWidth = -1 == atoi(propValue) ? MAX_VIDEO_WIDTH : atoi(propValue);
   property_get("ro.moz.omx.hw.max_height", propValue, "-1");
   maxHeight = -1 == atoi(propValue) ? MAX_VIDEO_HEIGHT : atoi(propValue) ;
 
-  if (mVideoWidth * mVideoHeight > maxWidth * maxHeight) {
+  if (mConfig.mImage.width * mConfig.mImage.height > maxWidth * maxHeight) {
     GVDM_LOG("Video resolution exceeds hw codec capability");
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
 
   // Validate the container-reported frame and pictureRect sizes. This ensures
   // that our video frame creation code doesn't overflow.
-  nsIntSize frameSize(mVideoWidth, mVideoHeight);
-  if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) {
+  if (!IsValidVideoRegion(mConfig.mImage, mConfig.ImageRect(), mConfig.mDisplay)) {
     GVDM_LOG("It is not a valid region");
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
 
   mReaderTaskQueue = AbstractThread::GetCurrent()->AsTaskQueue();
   MOZ_ASSERT(mReaderTaskQueue);
 
   if (mDecodeLooper.get() != nullptr) {
@@ -164,17 +149,19 @@ GonkVideoDecoderManager::Init()
   }
 
   if (!InitLoopers(MediaData::VIDEO_DATA)) {
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
 
   RefPtr<InitPromise> p = mInitPromise.Ensure(__func__);
   android::sp<GonkVideoDecoderManager> self = this;
-  mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false);
+  mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper,
+                                           mConfig.mMimeType.get(),
+                                           false);
 
   uint32_t capability = MediaCodecProxy::kEmptyCapability;
   if (mDecoder->getCapability(&capability) == OK && (capability &
       MediaCodecProxy::kCanExposeGraphicBuffer)) {
 #if ANDROID_VERSION >= 21
     sp<IGonkGraphicBufferConsumer> consumer;
     GonkBufferQueue::createBufferQueue(&mGraphicBufferProducer, &consumer);
     mNativeWindow = new GonkNativeWindow(consumer);
@@ -229,38 +216,28 @@ GonkVideoDecoderManager::CreateVideoData
     // quoted from Android's AwesomePlayer.cpp
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   if (!aBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &keyFrame)) {
     keyFrame = 0;
   }
 
-  gfx::IntRect picture = mPicture;
-  if (mFrameInfo.mWidth != mInitialFrame.width ||
-      mFrameInfo.mHeight != mInitialFrame.height) {
-
-    // Frame size is different from what the container reports. This is legal,
-    // and we will preserve the ratio of the crop rectangle as it
-    // was reported relative to the picture size reported by the container.
-    picture.x = (mPicture.x * mFrameInfo.mWidth) / mInitialFrame.width;
-    picture.y = (mPicture.y * mFrameInfo.mHeight) / mInitialFrame.height;
-    picture.width = (mFrameInfo.mWidth * mPicture.width) / mInitialFrame.width;
-    picture.height = (mFrameInfo.mHeight * mPicture.height) / mInitialFrame.height;
-  }
-
   if (aBuffer->graphicBuffer().get()) {
     data = CreateVideoDataFromGraphicBuffer(aBuffer, picture);
     if (data && !mNeedsCopyBuffer) {
       // RecycleCallback() will be responsible for release the buffer.
       autoRelease.forget();
     }
     mNeedsCopyBuffer = false;
   } else {
-    data = CreateVideoDataFromDataBuffer(aBuffer, picture);
+    data =
+      CreateVideoDataFromDataBuffer(aBuffer,
+                                    mConfig.ScaledImageRect(mFrameInfo.mWidth,
+                                                            mFrameInfo.mHeight));
   }
 
   if (!data) {
     return NS_ERROR_UNEXPECTED;
   }
   // Fill necessary info.
   data->mOffset = aStreamOffset;
   data->mTime = timeUs;
@@ -560,17 +537,19 @@ GonkVideoDecoderManager::SetVideoFormat(
     }
     mFrameInfo.mWidth = width;
     mFrameInfo.mHeight = height;
     mFrameInfo.mStride = stride;
     mFrameInfo.mSliceHeight = slice_height;
     mFrameInfo.mColorFormat = color_format;
 
     nsIntSize displaySize(width, height);
-    if (!IsValidVideoRegion(mInitialFrame, mPicture, displaySize)) {
+    if (!IsValidVideoRegion(mConfig.mDisplay,
+                            mConfig.ScaledImageRect(width, height),
+                            displaySize)) {
       GVDM_LOG("It is not a valid region");
       return false;
     }
     return true;
   }
   GVDM_LOG("Fail to get output format");
   return false;
 }
@@ -663,36 +642,36 @@ GonkVideoDecoderManager::codecReserved()
   if (mInitPromise.IsEmpty()) {
     return;
   }
   GVDM_LOG("codecReserved");
   sp<AMessage> format = new AMessage;
   sp<Surface> surface;
   status_t rv = OK;
   // Fixed values
-  GVDM_LOG("Configure video mime type: %s, width:%d, height:%d", mMimeType.get(), mVideoWidth, mVideoHeight);
-  format->setString("mime", mMimeType.get());
-  format->setInt32("width", mVideoWidth);
-  format->setInt32("height", mVideoHeight);
+  GVDM_LOG("Configure video mime type: %s, width:%d, height:%d", mConfig.mMimeType.get(), mConfig.mImage.width, mConfig.mImage.height);
+  format->setString("mime", mConfig.mMimeType.get());
+  format->setInt32("width", mConfig.mImage.width);
+  format->setInt32("height", mConfig.mImage.height);
   // Set the "moz-use-undequeued-bufs" to use the undeque buffers to accelerate
   // the video decoding.
   format->setInt32("moz-use-undequeued-bufs", 1);
   if (mNativeWindow != nullptr) {
 #if ANDROID_VERSION >= 21
     surface = new Surface(mGraphicBufferProducer);
 #else
     surface = new Surface(mNativeWindow->getBufferQueue());
 #endif
   }
   mDecoder->configure(format, surface, nullptr, 0);
   mDecoder->Prepare();
 
-  if (mMimeType.EqualsLiteral("video/mp4v-es")) {
-    rv = mDecoder->Input(mCodecSpecificData->Elements(),
-                         mCodecSpecificData->Length(), 0,
+  if (mConfig.mMimeType.EqualsLiteral("video/mp4v-es")) {
+    rv = mDecoder->Input(mConfig.mCodecSpecificData->Elements(),
+                         mConfig.mCodecSpecificData->Length(), 0,
                          android::MediaCodec::BUFFER_FLAG_CODECCONFIG,
                          CODECCONFIG_TIMEOUT_US);
   }
 
   if (rv != OK) {
     GVDM_LOG("Failed to configure codec!!!!");
     mInitPromise.Reject(DecoderFailureReason::INIT_ERROR, __func__);
     return;
--- a/dom/media/platforms/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/platforms/gonk/GonkVideoDecoderManager.h
@@ -96,27 +96,21 @@ private:
   // For codec resource management
   void codecReserved();
   void codecCanceled();
 
   void ReleaseAllPendingVideoBuffers();
   void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer,
                               layers::FenceHandle mReleaseFence);
 
-  uint32_t mVideoWidth;
-  uint32_t mVideoHeight;
-  uint32_t mDisplayWidth;
-  uint32_t mDisplayHeight;
-  nsIntRect mPicture;
-  nsIntSize mInitialFrame;
+  VideoInfo mConfig;
 
   RefPtr<layers::ImageContainer> mImageContainer;
   RefPtr<layers::TextureClientRecycleAllocator> mCopyAllocator;
 
-  MediaInfo mInfo;
   MozPromiseRequestHolder<android::MediaCodecProxy::CodecPromise> mVideoCodecRequest;
   FrameInfo mFrameInfo;
 
   // color converter
   android::I420ColorConverterHelper mColorConverter;
   UniquePtr<uint8_t[]> mColorConverterBuffer;
   size_t mColorConverterBufferSize;