Bug 1043808: Clean up rounding of sizes in MediaPipeline to handle odd sizes correctly r=jhlin a=sylvestre
authorRandell Jesup <rjesup@jesup.org>
Fri, 25 Jul 2014 03:11:13 -0400
changeset 217430 2cefba6dc41215b0d6c34f08692b8dc2d85e4e27
parent 217429 dbfe26a84fcf5222ed5b4e583ef1709669a2db6d
child 217431 6ca5b28fb162bc0837db6fcb6c3224ffbc3bee04
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhlin, sylvestre
bugs1043808
milestone33.0a2
Bug 1043808: Clean up rounding of sizes in MediaPipeline to handle odd sizes correctly r=jhlin a=sylvestre
media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
--- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
+++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp
@@ -937,16 +937,21 @@ NotifyQueuedTrackChanges(MediaStreamGrap
   MOZ_MTLOG(ML_DEBUG, "MediaPipeline::NotifyQueuedTrackChanges()");
 
   // ignore non-direct data if we're also getting direct data
   if (!direct_connect_) {
     NewData(graph, tid, rate, offset, events, queued_media);
   }
 }
 
+// I420 buffer size macros
+#define YSIZE(x,y) ((x)*(y))
+#define CRSIZE(x,y) ((((x)+1) >> 1) * (((y)+1) >> 1))
+#define I420SIZE(x,y) (YSIZE((x),(y)) + 2 * CRSIZE((x),(y)))
+
 void MediaPipelineTransmit::PipelineListener::
 NewData(MediaStreamGraph* graph, TrackID tid,
         TrackRate rate,
         TrackTicks offset,
         uint32_t events,
         const MediaSegment& media) {
   if (!active_) {
     MOZ_MTLOG(ML_DEBUG, "Discarding packets because transport not ready");
@@ -1098,32 +1103,28 @@ void MediaPipelineTransmit::PipelineList
   layers::Image *img = chunk.mFrame.GetImage();
 
   // We now need to send the video frame to the other side
   if (!img) {
     // segment.AppendFrame() allows null images, which show up here as null
     return;
   }
 
-  gfx::IntSize size = img->GetSize();
-  if ((size.width & 1) != 0 || (size.height & 1) != 0) {
-    MOZ_ASSERT(false, "Can't handle odd-sized images");
-    return;
-  }
-
   if (!enabled_ || chunk.mFrame.GetForceBlack()) {
-    uint32_t yPlaneLen = size.width*size.height;
-    uint32_t cbcrPlaneLen = yPlaneLen/2;
+    gfx::IntSize size = img->GetSize();
+    uint32_t yPlaneLen = YSIZE(size.width, size.height);
+    uint32_t cbcrPlaneLen = 2 * CRSIZE(size.width, size.height);
     uint32_t length = yPlaneLen + cbcrPlaneLen;
 
     // Send a black image.
     nsAutoArrayPtr<uint8_t> pixelData;
     static const fallible_t fallible = fallible_t();
     pixelData = new (fallible) uint8_t[length];
     if (pixelData) {
+      // YCrCb black = 0x10 0x80 0x80
       memset(pixelData, 0x10, yPlaneLen);
       // Fill Cb/Cr planes
       memset(pixelData + yPlaneLen, 0x80, cbcrPlaneLen);
 
       MOZ_MTLOG(ML_DEBUG, "Sending a black video frame");
       conduit->SendVideoFrame(pixelData, length, size.width, size.height,
                               mozilla::kVideoI420, 0);
     }
@@ -1139,20 +1140,22 @@ void MediaPipelineTransmit::PipelineList
 
   ImageFormat format = img->GetFormat();
 #ifdef WEBRTC_GONK
   if (format == ImageFormat::GRALLOC_PLANAR_YCBCR) {
     layers::GrallocImage *nativeImage = static_cast<layers::GrallocImage*>(img);
     android::sp<android::GraphicBuffer> graphicBuffer = nativeImage->GetGraphicBuffer();
     void *basePtr;
     graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_MASK, &basePtr);
+    uint32_t width = graphicBuffer->getWidth();
+    uint32_t height = graphicBuffer->getHeight();
     conduit->SendVideoFrame(static_cast<unsigned char*>(basePtr),
-                            (graphicBuffer->getWidth() * graphicBuffer->getHeight() * 3) / 2,
-                            graphicBuffer->getWidth(),
-                            graphicBuffer->getHeight(),
+                            I420SIZE(width, height),
+                            width,
+                            height,
                             mozilla::kVideoNV21, 0);
     graphicBuffer->unlock();
   } else
 #endif
   if (format == ImageFormat::PLANAR_YCBCR) {
     // Cast away constness b/c some of the accessors are non-const
     layers::PlanarYCbCrImage* yuv =
     const_cast<layers::PlanarYCbCrImage *>(
@@ -1167,18 +1170,19 @@ void MediaPipelineTransmit::PipelineList
     uint8_t *cr = data->mCrChannel;
 #endif
     uint32_t width = yuv->GetSize().width;
     uint32_t height = yuv->GetSize().height;
     uint32_t length = yuv->GetDataSize();
 
     // SendVideoFrame only supports contiguous YCrCb 4:2:0 buffers
     // Verify it's contiguous and in the right order
-    MOZ_ASSERT(cb == (y + width*height) &&
-               cr == (cb + width*height/4));
+    MOZ_ASSERT(cb == (y + YSIZE(width, height)) &&
+               cr == (cb + CRSIZE(width, height)) &&
+               length == I420SIZE(width, height));
     // XXX Consider making this a non-debug-only check if we ever implement
     // any subclasses of PlanarYCbCrImage that allow disjoint buffers such
     // that y+3(width*height)/2 might go outside the allocation.
     // GrallocImage can have wider strides, and so in some cases
     // would encode as garbage.  If we need to encode it we'll either want to
     // modify SendVideoFrame or copy/move the data in the buffer.
 
     // OK, pass it on to the conduit
@@ -1189,22 +1193,22 @@ void MediaPipelineTransmit::PipelineList
     layers::CairoImage* rgb =
     const_cast<layers::CairoImage *>(
           static_cast<const layers::CairoImage *>(img));
 
     gfx::IntSize size = rgb->GetSize();
     int half_width = (size.width + 1) >> 1;
     int half_height = (size.height + 1) >> 1;
     int c_size = half_width * half_height;
-    int buffer_size = size.width * size.height + 2 * c_size;
-    uint8* yuv = (uint8*) malloc(buffer_size);
+    int buffer_size = YSIZE(size.width, size.height) + 2 * c_size;
+    uint8* yuv = (uint8*) malloc(buffer_size); // fallible
     if (!yuv)
       return;
 
-    int cb_offset = size.width * size.height;
+    int cb_offset = YSIZE(size.width, size.height);
     int cr_offset = cb_offset + c_size;
     RefPtr<gfx::SourceSurface> tempSurf = rgb->GetAsSourceSurface();
     RefPtr<gfx::DataSourceSurface> surf = tempSurf->GetDataSurface();
 
     switch (surf->GetFormat()) {
       case gfx::SurfaceFormat::B8G8R8A8:
       case gfx::SurfaceFormat::B8G8R8X8:
         libyuv::ARGBToI420(static_cast<uint8*>(surf->GetData()), surf->Stride(),