Bug 1041950 - Create image copy instead of reference. r=edwin
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 28 Jul 2014 16:10:29 +1200
changeset 196598 3e4236a5d8eda333e58eb051d98ba44535e78038
parent 196597 b39daaf8394b5786634d9d6804d07df1b9c4e7d5
child 196599 d240749902d703837b57b7e11930bd3f6186931c
push id27220
push userkwierso@gmail.com
push dateWed, 30 Jul 2014 00:01:50 +0000
treeherdermozilla-central@f61a27b00e05 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedwin
bugs1041950
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1041950 - Create image copy instead of reference. r=edwin
content/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
content/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
--- a/content/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
+++ b/content/media/fmp4/ffmpeg/FFmpegDataDecoder.cpp
@@ -92,16 +92,20 @@ FFmpegDataDecoder<LIBAV_VER>::Init()
   mCodecContext->thread_safe_callbacks = false;
 
   mCodecContext->extradata_size = mExtraData.length();
   for (int i = 0; i < FF_INPUT_BUFFER_PADDING_SIZE; i++) {
     mExtraData.append(0);
   }
   mCodecContext->extradata = mExtraData.begin();
 
+  if (codec->capabilities & CODEC_CAP_DR1) {
+    mCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
+  }
+
   if (avcodec_open2(mCodecContext, codec, nullptr) < 0) {
     NS_WARNING("Couldn't initialise ffmpeg decoder");
     return NS_ERROR_FAILURE;
   }
 
   if (mCodecContext->codec_type == AVMEDIA_TYPE_AUDIO &&
       mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT &&
       mCodecContext->sample_fmt != AV_SAMPLE_FMT_FLTP) {
--- a/content/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
+++ b/content/media/fmp4/ffmpeg/FFmpegH264Decoder.cpp
@@ -73,58 +73,62 @@ FFmpegH264Decoder<LIBAV_VER>::DecodeFram
   if (bytesConsumed < 0) {
     NS_WARNING("FFmpeg video decoder error.");
     mCallback->Error();
     return;
   }
 
   // If we've decoded a frame then we need to output it
   if (decoded) {
-    nsAutoPtr<VideoData> data;
-
     VideoInfo info;
     info.mDisplay = nsIntSize(mCodecContext->width, mCodecContext->height);
     info.mStereoMode = StereoMode::MONO;
     info.mHasVideo = true;
 
-    data = VideoData::CreateFromImage(
-      info, mImageContainer, aSample->byte_offset, mFrame->pkt_pts,
-      aSample->duration, static_cast<Image*>(mFrame->opaque),
-      aSample->is_sync_point, -1,
-      gfx::IntRect(0, 0, mCodecContext->width, mCodecContext->height));
+    VideoData::YCbCrBuffer b;
+    b.mPlanes[0].mData = mFrame->data[0];
+    b.mPlanes[0].mStride = mFrame->linesize[0];
+    b.mPlanes[0].mHeight = mFrame->height;
+    b.mPlanes[0].mWidth = mFrame->width;
+    b.mPlanes[0].mOffset = b.mPlanes[0].mSkip = 0;
+
+    b.mPlanes[1].mData = mFrame->data[1];
+    b.mPlanes[1].mStride = mFrame->linesize[1];
+    b.mPlanes[1].mHeight = (mFrame->height + 1) >> 1;
+    b.mPlanes[1].mWidth = (mFrame->width + 1) >> 1;
+    b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0;
 
-    mCallback->Output(data.forget());
+    b.mPlanes[2].mData = mFrame->data[2];
+    b.mPlanes[2].mStride = mFrame->linesize[2];
+    b.mPlanes[2].mHeight = (mFrame->height + 1) >> 1;
+    b.mPlanes[2].mWidth = (mFrame->width + 1) >> 1;
+    b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;
+
+    VideoData *v = VideoData::Create(info,
+                                     mImageContainer,
+                                     aSample->byte_offset,
+                                     mFrame->pkt_pts,
+                                     aSample->duration,
+                                     b,
+                                     aSample->is_sync_point,
+                                     -1,
+                                     gfx::IntRect(0, 0, mCodecContext->width, mCodecContext->height));
+    if (!v) {
+      NS_WARNING("image allocation error.");
+      mCallback->Error();
+      return;
+    }
+    mCallback->Output(v);
   }
 
   if (mTaskQueue->IsEmpty()) {
     mCallback->InputExhausted();
   }
 }
 
-static void
-PlanarYCbCrDataFromAVFrame(mozilla::layers::PlanarYCbCrData& aData,
-                           AVFrame* aFrame)
-{
-  aData.mPicX = aData.mPicY = 0;
-  aData.mPicSize = mozilla::gfx::IntSize(aFrame->width, aFrame->height);
-  aData.mStereoMode = StereoMode::MONO;
-
-  aData.mYChannel = aFrame->data[0];
-  aData.mYStride = aFrame->linesize[0];
-  aData.mYSize = aData.mPicSize;
-  aData.mYSkip = 0;
-
-  aData.mCbChannel = aFrame->data[1];
-  aData.mCrChannel = aFrame->data[2];
-  aData.mCbCrStride = aFrame->linesize[1];
-  aData.mCbSkip = aData.mCrSkip = 0;
-  aData.mCbCrSize =
-    mozilla::gfx::IntSize((aFrame->width + 1) / 2, (aFrame->height + 1) / 2);
-}
-
 /* static */ int
 FFmpegH264Decoder<LIBAV_VER>::AllocateBufferCb(AVCodecContext* aCodecContext,
                                                AVFrame* aFrame)
 {
   MOZ_ASSERT(aCodecContext->codec_type == AVMEDIA_TYPE_VIDEO);
 
   FFmpegH264Decoder* self =
     static_cast<FFmpegH264Decoder*>(aCodecContext->opaque);
@@ -154,26 +158,27 @@ FFmpegH264Decoder<LIBAV_VER>::ReleaseBuf
       break;
   }
 }
 
 int
 FFmpegH264Decoder<LIBAV_VER>::AllocateYUV420PVideoBuffer(
   AVCodecContext* aCodecContext, AVFrame* aFrame)
 {
-  // Older versions of ffmpeg require that edges be allocated* around* the
-  // actual image.
-  int edgeWidth = avcodec_get_edge_width();
+  bool needAlign = aCodecContext->codec->capabilities & CODEC_CAP_DR1;
+  int edgeWidth =  needAlign ? avcodec_get_edge_width() : 0;
   int decodeWidth = aCodecContext->width + edgeWidth * 2;
   int decodeHeight = aCodecContext->height + edgeWidth * 2;
 
-  // Align width and height to possibly speed up decode.
-  int stride_align[AV_NUM_DATA_POINTERS];
-  avcodec_align_dimensions2(aCodecContext, &decodeWidth, &decodeHeight,
-                            stride_align);
+  if (needAlign) {
+    // Align width and height to account for CODEC_FLAG_EMU_EDGE.
+    int stride_align[AV_NUM_DATA_POINTERS];
+    avcodec_align_dimensions2(aCodecContext, &decodeWidth, &decodeHeight,
+                              stride_align);
+  }
 
   // Get strides for each plane.
   av_image_fill_linesizes(aFrame->linesize, aCodecContext->pix_fmt,
                           decodeWidth);
 
   // Let FFmpeg set up its YUV plane pointers and tell us how much memory we
   // need.
   // Note that we're passing |nullptr| here as the base address as we haven't
@@ -210,20 +215,16 @@ FFmpegH264Decoder<LIBAV_VER>::AllocateYU
 
   // Unused, but needs to be non-zero to keep ffmpeg happy.
   aFrame->type = GECKO_FRAME_TYPE;
 
   aFrame->extended_data = aFrame->data;
   aFrame->width = aCodecContext->width;
   aFrame->height = aCodecContext->height;
 
-  mozilla::layers::PlanarYCbCrData data;
-  PlanarYCbCrDataFromAVFrame(data, aFrame);
-  ycbcr->SetDataNoCopy(data);
-
   aFrame->opaque = static_cast<void*>(image.forget().take());
 
   return 0;
 }
 
 nsresult
 FFmpegH264Decoder<LIBAV_VER>::Input(mp4_demuxer::MP4Sample* aSample)
 {