Bug 1382718 - Update detection of image bitmap format in VP8 Encoder. r?jesup draft
authorBryce Van Dyk <bvandyk@mozilla.com>
Mon, 24 Jul 2017 09:13:01 +1200
changeset 615008 e926e663cab063a9aca6121678ffb683ed0a846f
parent 615007 d8090c63bedba7545c167c247022f6bff7491f4c
child 615009 65270d5c6daf79dc77e2c6b84feb8124d382e08e
push id70207
push userbvandyk@mozilla.com
push dateTue, 25 Jul 2017 09:03:30 +0000
reviewersjesup
bugs1382718
milestone56.0a1
Bug 1382718 - Update detection of image bitmap format in VP8 Encoder. r?jesup Utilize ImageUtils to detect the bitmap format of images passed to the VP8 encoder, rather than duplicating this functionality in the encoder. Resolve an issue with incorrect identification of unevenly sized I420 frames that was breaking screen capture based MediaRecorder. clang-format code which has been touched. MozReview-Commit-ID: 4IfKSYxGuAX
dom/media/encoder/VP8TrackEncoder.cpp
--- a/dom/media/encoder/VP8TrackEncoder.cpp
+++ b/dom/media/encoder/VP8TrackEncoder.cpp
@@ -10,29 +10,32 @@
 #include "mozilla/gfx/2D.h"
 #include "prsystem.h"
 #include "VideoSegment.h"
 #include "VideoUtils.h"
 #include "vpx/vp8cx.h"
 #include "vpx/vpx_encoder.h"
 #include "WebMWriter.h"
 #include "mozilla/media/MediaUtils.h"
+#include "mozilla/dom/ImageUtils.h"
+#include "mozilla/dom/ImageBitmapBinding.h"
 
 namespace mozilla {
 
 LazyLogModule gVP8TrackEncoderLog("VP8TrackEncoder");
 #define VP8LOG(level, msg, ...) MOZ_LOG(gVP8TrackEncoderLog, \
                                         level, \
                                         (msg, ##__VA_ARGS__))
 
 #define DEFAULT_BITRATE_BPS 2500000
 
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 using namespace mozilla::media;
+using namespace mozilla::dom;
 
 static already_AddRefed<SourceSurface>
 GetSourceSurface(already_AddRefed<Image> aImg)
 {
   RefPtr<Image> img = aImg;
   if (!img) {
     return nullptr;
   }
@@ -310,41 +313,16 @@ VP8TrackEncoder::GetEncodedPartitions(En
            videoData->GetTimeStamp(), videoData->GetDuration(),
            videoData->GetFrameType());
     aData.AppendEncodedFrame(videoData);
   }
 
   return pkt ? NS_OK : NS_ERROR_NOT_AVAILABLE;
 }
 
-static bool isYUV420(const PlanarYCbCrImage::Data *aData)
-{
-  if (aData->mYSize == aData->mCbCrSize * 2) {
-    return true;
-  }
-  return false;
-}
-
-static bool isYUV422(const PlanarYCbCrImage::Data *aData)
-{
-  if ((aData->mYSize.width == aData->mCbCrSize.width * 2) &&
-      (aData->mYSize.height == aData->mCbCrSize.height)) {
-    return true;
-  }
-  return false;
-}
-
-static bool isYUV444(const PlanarYCbCrImage::Data *aData)
-{
-  if (aData->mYSize == aData->mCbCrSize) {
-    return true;
-  }
-  return false;
-}
-
 nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk)
 {
   RefPtr<Image> img;
   if (aChunk.mFrame.GetForceBlack() || aChunk.IsNull()) {
     if (!mMuteFrame) {
       mMuteFrame = VideoFrame::CreateBlackImage(gfx::IntSize(mFrameWidth, mFrameHeight));
     }
     if (!mMuteFrame) {
@@ -389,20 +367,26 @@ nsresult VP8TrackEncoder::PrepareRawFram
   if (format == ImageFormat::PLANAR_YCBCR) {
     PlanarYCbCrImage* yuv = static_cast<PlanarYCbCrImage *>(img.get());
 
     MOZ_RELEASE_ASSERT(yuv);
     if (!yuv->IsValid()) {
       NS_WARNING("PlanarYCbCrImage is not valid");
       return NS_ERROR_FAILURE;
     }
-    const PlanarYCbCrImage::Data *data = yuv->GetData();
 
-    if (isYUV420(data) && !data->mCbSkip) {
+    // The ImageUtils API may change depending on our support for ImageBitmap
+    // extensions. Should this happen in a breaking way we should abstract out
+    // the format detection for use here.
+    const ImageUtils imageUtils(img);
+    const ImageBitmapFormat imageBitmapFormat = imageUtils.GetFormat();
+
+    if (imageBitmapFormat == ImageBitmapFormat::YUV420P) {
       // 420 planar, no need for conversions
+      const PlanarYCbCrImage::Data* data = yuv->GetData();
       mVPXImageWrapper->planes[VPX_PLANE_Y] = data->mYChannel;
       mVPXImageWrapper->planes[VPX_PLANE_U] = data->mCbChannel;
       mVPXImageWrapper->planes[VPX_PLANE_V] = data->mCrChannel;
       mVPXImageWrapper->stride[VPX_PLANE_Y] = data->mYStride;
       mVPXImageWrapper->stride[VPX_PLANE_U] = data->mCbCrStride;
       mVPXImageWrapper->stride[VPX_PLANE_V] = data->mCbCrStride;
 
       return NS_OK;
@@ -426,56 +410,82 @@ nsresult VP8TrackEncoder::PrepareRawFram
   if (format == ImageFormat::PLANAR_YCBCR) {
     PlanarYCbCrImage* yuv = static_cast<PlanarYCbCrImage *>(img.get());
 
     MOZ_RELEASE_ASSERT(yuv);
     if (!yuv->IsValid()) {
       NS_WARNING("PlanarYCbCrImage is not valid");
       return NS_ERROR_FAILURE;
     }
+
+    const ImageUtils imageUtils(img);
+    const ImageBitmapFormat imageBitmapFormat = imageUtils.GetFormat();
     const PlanarYCbCrImage::Data *data = yuv->GetData();
 
     int rv;
     std::string yuvFormat;
-    if (isYUV420(data) && data->mCbSkip) {
-      // If mCbSkip is set, we assume it's nv12 or nv21.
-      if (data->mCbChannel < data->mCrChannel) { // nv12
-        rv = libyuv::NV12ToI420(data->mYChannel, data->mYStride,
-                                data->mCbChannel, data->mCbCrStride,
-                                y, mFrameWidth,
-                                cb, halfWidth,
-                                cr, halfWidth,
-                                mFrameWidth, mFrameHeight);
-        yuvFormat = "NV12";
-      } else { // nv21
-        rv = libyuv::NV21ToI420(data->mYChannel, data->mYStride,
-                                data->mCrChannel, data->mCbCrStride,
-                                y, mFrameWidth,
-                                cb, halfWidth,
-                                cr, halfWidth,
-                                mFrameWidth, mFrameHeight);
-        yuvFormat = "NV21";
-      }
-    } else if (isYUV444(data) && !data->mCbSkip) {
-      rv = libyuv::I444ToI420(data->mYChannel, data->mYStride,
-                              data->mCbChannel, data->mCbCrStride,
-                              data->mCrChannel, data->mCbCrStride,
-                              y, mFrameWidth,
-                              cb, halfWidth,
-                              cr, halfWidth,
-                              mFrameWidth, mFrameHeight);
+    if (imageBitmapFormat == ImageBitmapFormat::YUV420SP_NV12) {
+      rv = libyuv::NV12ToI420(data->mYChannel,
+                              data->mYStride,
+                              data->mCbChannel,
+                              data->mCbCrStride,
+                              y,
+                              mFrameWidth,
+                              cb,
+                              halfWidth,
+                              cr,
+                              halfWidth,
+                              mFrameWidth,
+                              mFrameHeight);
+      yuvFormat = "NV12";
+    } else if (imageBitmapFormat == ImageBitmapFormat::YUV420SP_NV21) {
+      rv = libyuv::NV21ToI420(data->mYChannel,
+                              data->mYStride,
+                              data->mCrChannel,
+                              data->mCbCrStride,
+                              y,
+                              mFrameWidth,
+                              cb,
+                              halfWidth,
+                              cr,
+                              halfWidth,
+                              mFrameWidth,
+                              mFrameHeight);
+      yuvFormat = "NV21";
+    } else if (imageBitmapFormat == ImageBitmapFormat::YUV444P) {
+      rv = libyuv::I444ToI420(data->mYChannel,
+                              data->mYStride,
+                              data->mCbChannel,
+                              data->mCbCrStride,
+                              data->mCrChannel,
+                              data->mCbCrStride,
+                              y,
+                              mFrameWidth,
+                              cb,
+                              halfWidth,
+                              cr,
+                              halfWidth,
+                              mFrameWidth,
+                              mFrameHeight);
       yuvFormat = "I444";
-    } else if (isYUV422(data) && !data->mCbSkip) {
-      rv = libyuv::I422ToI420(data->mYChannel, data->mYStride,
-                              data->mCbChannel, data->mCbCrStride,
-                              data->mCrChannel, data->mCbCrStride,
-                              y, mFrameWidth,
-                              cb, halfWidth,
-                              cr, halfWidth,
-                              mFrameWidth, mFrameHeight);
+    } else if (imageBitmapFormat == ImageBitmapFormat::YUV422P) {
+      rv = libyuv::I422ToI420(data->mYChannel,
+                              data->mYStride,
+                              data->mCbChannel,
+                              data->mCbCrStride,
+                              data->mCrChannel,
+                              data->mCbCrStride,
+                              y,
+                              mFrameWidth,
+                              cb,
+                              halfWidth,
+                              cr,
+                              halfWidth,
+                              mFrameWidth,
+                              mFrameHeight);
       yuvFormat = "I422";
     } else {
       VP8LOG(LogLevel::Error, "Unsupported planar format");
       NS_ASSERTION(false, "Unsupported planar format");
       return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     if (rv != 0) {