Bug 1321076 - New overloaded CreateAndCopy method that takes alpha plane and returns VideoData with SharedRGBImage, in the case of alpha. r=jya draft
authorkaro <kkoorts@mozilla.com>
Wed, 21 Dec 2016 15:19:46 +1300
changeset 452676 fcde786d529f69ba6fe2a533e351a8b33afa1de7
parent 452675 572dbf59e8a3b41e6c7366d1579a28e365062260
child 452677 15da81910ab6909ba9659e1f5c7ea86e4d0ebaa4
push id39448
push userbmo:kkoorts@mozilla.com
push dateThu, 22 Dec 2016 00:02:10 +0000
reviewersjya
bugs1321076
milestone53.0a1
Bug 1321076 - New overloaded CreateAndCopy method that takes alpha plane and returns VideoData with SharedRGBImage, in the case of alpha. r=jya MozReview-Commit-ID: AIJxPRjGvrg
dom/media/MediaData.cpp
dom/media/MediaData.h
--- a/dom/media/MediaData.cpp
+++ b/dom/media/MediaData.cpp
@@ -90,16 +90,55 @@ static bool
 ValidatePlane(const VideoData::YCbCrBuffer::Plane& aPlane)
 {
   return aPlane.mWidth <= PlanarYCbCrImage::MAX_DIMENSION &&
          aPlane.mHeight <= PlanarYCbCrImage::MAX_DIMENSION &&
          aPlane.mWidth * aPlane.mHeight < MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
          aPlane.mStride > 0;
 }
 
+static bool ValidateBufferAndPicture(const VideoData::YCbCrBuffer& aBuffer,
+                                     const IntRect& aPicture)
+{
+  // The following situation should never happen unless there is a bug
+  // in the decoder
+  if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
+      aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
+    NS_ERROR("C planes with different sizes");
+    return false;
+  }
+
+  // The following situations could be triggered by invalid input
+  if (aPicture.width <= 0 || aPicture.height <= 0) {
+    // In debug mode, makes the error more noticeable
+    MOZ_ASSERT(false, "Empty picture rect");
+    return false;
+  }
+  if (!ValidatePlane(aBuffer.mPlanes[0]) ||
+      !ValidatePlane(aBuffer.mPlanes[1]) ||
+      !ValidatePlane(aBuffer.mPlanes[2])) {
+    NS_WARNING("Invalid plane size");
+    return false;
+  }
+
+  // Ensure the picture size specified in the headers can be extracted out of
+  // the frame we've been supplied without indexing out of bounds.
+  CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
+  CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
+  if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
+      !yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
+  {
+    // The specified picture dimensions can't be contained inside the video
+    // frame, we'll stomp memory if we try to copy it. Fail.
+    NS_WARNING("Overflowing picture rect");
+    return false;
+  }
+  return true;
+}
+
 #ifdef MOZ_WIDGET_GONK
 static bool
 IsYV12Format(const VideoData::YCbCrBuffer::Plane& aYPlane,
              const VideoData::YCbCrBuffer::Plane& aCbPlane,
              const VideoData::YCbCrBuffer::Plane& aCrPlane)
 {
   return
     aYPlane.mWidth % 2 == 0 &&
@@ -258,46 +297,17 @@ VideoData::CreateAndCopyData(const Video
                                       aDuration,
                                       aKeyframe,
                                       aTimecode,
                                       aInfo.mDisplay,
                                       0));
     return v.forget();
   }
 
-  // The following situation should never happen unless there is a bug
-  // in the decoder
-  if (aBuffer.mPlanes[1].mWidth != aBuffer.mPlanes[2].mWidth ||
-      aBuffer.mPlanes[1].mHeight != aBuffer.mPlanes[2].mHeight) {
-    NS_ERROR("C planes with different sizes");
-    return nullptr;
-  }
-
-  // The following situations could be triggered by invalid input
-  if (aPicture.width <= 0 || aPicture.height <= 0) {
-    // In debug mode, makes the error more noticeable
-    MOZ_ASSERT(false, "Empty picture rect");
-    return nullptr;
-  }
-  if (!ValidatePlane(aBuffer.mPlanes[0]) || !ValidatePlane(aBuffer.mPlanes[1]) ||
-      !ValidatePlane(aBuffer.mPlanes[2])) {
-    NS_WARNING("Invalid plane size");
-    return nullptr;
-  }
-
-  // Ensure the picture size specified in the headers can be extracted out of
-  // the frame we've been supplied without indexing out of bounds.
-  CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
-  CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
-  if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
-      !yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
-  {
-    // The specified picture dimensions can't be contained inside the video
-    // frame, we'll stomp memory if we try to copy it. Fail.
-    NS_WARNING("Overflowing picture rect");
+  if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
     return nullptr;
   }
 
   RefPtr<VideoData> v(new VideoData(aOffset,
                                     aTime,
                                     aDuration,
                                     aKeyframe,
                                     aTimecode,
@@ -345,16 +355,84 @@ VideoData::CreateAndCopyData(const Video
                                         true /* aCopyData */)) {
       return nullptr;
     }
   }
 #endif
   return v.forget();
 }
 
+
+/* static */
+already_AddRefed<VideoData>
+VideoData::CreateAndCopyData(const VideoInfo& aInfo,
+                             ImageContainer* aContainer,
+                             int64_t aOffset,
+                             int64_t aTime,
+                             int64_t aDuration,
+                             const YCbCrBuffer& aBuffer,
+                             const YCbCrBuffer::Plane &aAlphaPlane,
+                             bool aKeyframe,
+                             int64_t aTimecode,
+                             const IntRect& aPicture)
+{
+  if (!aContainer) {
+    // Create a dummy VideoData with no image. This gives us something to
+    // send to media streams if necessary.
+    RefPtr<VideoData> v(new VideoData(aOffset,
+                                      aTime,
+                                      aDuration,
+                                      aKeyframe,
+                                      aTimecode,
+                                      aInfo.mDisplay,
+                                      0));
+    return v.forget();
+  }
+
+  if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
+    return nullptr;
+  }
+
+  RefPtr<VideoData> v(new VideoData(aOffset,
+                                    aTime,
+                                    aDuration,
+                                    aKeyframe,
+                                    aTimecode,
+                                    aInfo.mDisplay,
+                                    0));
+
+  // Convert from YUVA to BGRA format on the software side.
+  RefPtr<layers::SharedRGBImage> videoImage =
+    aContainer->CreateSharedRGBImage();
+  v->mImage = videoImage;
+
+  if (!v->mImage) {
+    return nullptr;
+  }
+  if (!videoImage->Allocate(IntSize(aBuffer.mPlanes[0].mWidth,
+                                    aBuffer.mPlanes[0].mHeight),
+                            SurfaceFormat::B8G8R8A8)) {
+    return nullptr;
+  }
+  uint8_t* argb_buffer = videoImage->GetBuffer();
+  IntSize size = videoImage->GetSize();
+
+  // The naming convention for libyuv and associated utils is word-order.
+  // The naming convention in the gfx stack is byte-order.
+  ConvertYCbCrAToARGB(aBuffer.mPlanes[0].mData,
+                      aBuffer.mPlanes[1].mData,
+                      aBuffer.mPlanes[2].mData,
+                      aAlphaPlane.mData,
+                      aBuffer.mPlanes[0].mStride, aBuffer.mPlanes[1].mStride,
+                      argb_buffer, size.width * 4,
+                      size.width, size.height);
+
+  return v.forget();
+}
+
 /* static */
 already_AddRefed<VideoData>
 VideoData::CreateFromImage(const VideoInfo& aInfo,
                            int64_t aOffset,
                            int64_t aTime,
                            int64_t aDuration,
                            const RefPtr<Image>& aImage,
                            bool aKeyframe,
--- a/dom/media/MediaData.h
+++ b/dom/media/MediaData.h
@@ -474,16 +474,27 @@ public:
                                                        int64_t aOffset,
                                                        int64_t aTime,
                                                        int64_t aDuration,
                                                        const YCbCrBuffer &aBuffer,
                                                        bool aKeyframe,
                                                        int64_t aTimecode,
                                                        const IntRect& aPicture);
 
+  static already_AddRefed<VideoData> CreateAndCopyData(const VideoInfo& aInfo,
+                                                       ImageContainer* aContainer,
+                                                       int64_t aOffset,
+                                                       int64_t aTime,
+                                                       int64_t aDuration,
+                                                       const YCbCrBuffer &aBuffer,
+                                                       const YCbCrBuffer::Plane &aAlphaPlane,
+                                                       bool aKeyframe,
+                                                       int64_t aTimecode,
+                                                       const IntRect& aPicture);
+
   static already_AddRefed<VideoData> CreateAndCopyIntoTextureClient(const VideoInfo& aInfo,
                                                                     int64_t aOffset,
                                                                     int64_t aTime,
                                                                     int64_t aDuration,
                                                                     layers::TextureClient* aBuffer,
                                                                     bool aKeyframe,
                                                                     int64_t aTimecode,
                                                                     const IntRect& aPicture);