Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(488)

Unified Diff: media/filters/ffmpeg_video_decode_engine.cc

Issue 1669002: remove AVFrame Dependency (Closed)
Patch Set: more patch Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/ffmpeg_video_decode_engine.h ('k') | media/filters/ffmpeg_video_decode_engine_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/ffmpeg_video_decode_engine.cc
diff --git a/media/filters/ffmpeg_video_decode_engine.cc b/media/filters/ffmpeg_video_decode_engine.cc
index 8685fbfa6a6908916fd21fcbaf39d8f190a42d5c..d13a247b19eb1e6338ece6901890dc93529ee14d 100644
--- a/media/filters/ffmpeg_video_decode_engine.cc
+++ b/media/filters/ffmpeg_video_decode_engine.cc
@@ -5,8 +5,9 @@
#include "media/filters/ffmpeg_video_decode_engine.h"
#include "base/task.h"
-#include "media/base/callback.h"
#include "media/base/buffers.h"
+#include "media/base/callback.h"
+#include "media/base/limits.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/ffmpeg/ffmpeg_util.h"
#include "media/filters/ffmpeg_demuxer.h"
@@ -50,21 +51,54 @@ void FFmpegVideoDecodeEngine::Initialize(AVStream* stream, Task* done_cb) {
int decode_threads = (codec_context_->codec_id == CODEC_ID_THEORA)
? 1 : kDecodeThreads;
+ // We don't allocate AVFrame on the stack since different versions of FFmpeg
+ // may change the size of AVFrame, causing stack corruption. The solution is
+ // to let FFmpeg allocate the structure via avcodec_alloc_frame().
+ av_frame_.reset(avcodec_alloc_frame());
+
if (codec &&
avcodec_thread_init(codec_context_, decode_threads) >= 0 &&
- avcodec_open(codec_context_, codec) >= 0) {
+ avcodec_open(codec_context_, codec) >= 0 &&
+ av_frame_.get()) {
state_ = kNormal;
} else {
state_ = kError;
}
}
+static void CopyPlane(size_t plane,
+ scoped_refptr<VideoFrame> video_frame,
+ const AVFrame* frame) {
+ DCHECK(video_frame->width() % 2 == 0);
+ const uint8* source = frame->data[plane];
+ const size_t source_stride = frame->linesize[plane];
+ uint8* dest = video_frame->data(plane);
+ const size_t dest_stride = video_frame->stride(plane);
+ size_t bytes_per_line = video_frame->width();
+ size_t copy_lines = video_frame->height();
+ if (plane != VideoFrame::kYPlane) {
+ bytes_per_line /= 2;
+ if (video_frame->format() == VideoFrame::YV12) {
+ copy_lines = (copy_lines + 1) / 2;
+ }
+ }
+ DCHECK(bytes_per_line <= source_stride && bytes_per_line <= dest_stride);
+ for (size_t i = 0; i < copy_lines; ++i) {
+ memcpy(dest, source, bytes_per_line);
+ source += source_stride;
+ dest += dest_stride;
+ }
+}
+
// Decodes one frame of video with the given buffer.
-void FFmpegVideoDecodeEngine::DecodeFrame(Buffer* buffer,
- AVFrame* yuv_frame,
- bool* got_frame,
- Task* done_cb) {
+void FFmpegVideoDecodeEngine::DecodeFrame(
+ Buffer* buffer,
+ scoped_refptr<VideoFrame>* video_frame,
+ bool* got_frame,
+ Task* done_cb) {
AutoTaskRunner done_runner(done_cb);
+ *got_frame = false;
+ *video_frame = NULL;
// Create a packet for input data.
// Due to FFmpeg API changes we no longer have const read-only pointers.
@@ -73,12 +107,11 @@ void FFmpegVideoDecodeEngine::DecodeFrame(Buffer* buffer,
packet.data = const_cast<uint8*>(buffer->GetData());
packet.size = buffer->GetDataSize();
- // We don't allocate AVFrame on the stack since different versions of FFmpeg
- // may change the size of AVFrame, causing stack corruption. The solution is
- // to let FFmpeg allocate the structure via avcodec_alloc_frame().
int frame_decoded = 0;
- int result =
- avcodec_decode_video2(codec_context_, yuv_frame, &frame_decoded, &packet);
+ int result = avcodec_decode_video2(codec_context_,
+ av_frame_.get(),
+ &frame_decoded,
+ &packet);
// Log the problem if we can't decode a video frame and exit early.
if (result < 0) {
@@ -92,6 +125,43 @@ void FFmpegVideoDecodeEngine::DecodeFrame(Buffer* buffer,
} else {
// If frame_decoded == 0, then no frame was produced.
*got_frame = frame_decoded != 0;
+
+ if (*got_frame) {
+ // TODO(fbarchard): Work around for FFmpeg http://crbug.com/27675
+ // The decoder is in a bad state and not decoding correctly.
+ // Checking for NULL avoids a crash in CopyPlane().
+ if (!av_frame_->data[VideoFrame::kYPlane] ||
+ !av_frame_->data[VideoFrame::kUPlane] ||
+ !av_frame_->data[VideoFrame::kVPlane]) {
+ // TODO(jiesun): this is also an error case handled as normal.
+ *got_frame = false;
+ return;
+ }
+
+ VideoFrame::CreateFrame(GetSurfaceFormat(),
+ codec_context_->width,
+ codec_context_->height,
+ StreamSample::kInvalidTimestamp,
+ StreamSample::kInvalidTimestamp,
+ video_frame);
+ if (!video_frame->get()) {
+ // TODO(jiesun): this is also an error case handled as normal.
+ *got_frame = false;
+ return;
+ }
+
+ // Copy the frame data since FFmpeg reuses internal buffers for AVFrame
+ // output, meaning the data is only valid until the next
+ // avcodec_decode_video() call.
+ // TODO(scherkus): figure out pre-allocation/buffer cycling scheme.
+ // TODO(scherkus): is there a cleaner way to figure out the # of planes?
+ CopyPlane(VideoFrame::kYPlane, video_frame->get(), av_frame_.get());
+ CopyPlane(VideoFrame::kUPlane, video_frame->get(), av_frame_.get());
+ CopyPlane(VideoFrame::kVPlane, video_frame->get(), av_frame_.get());
+
+ DCHECK_LE(av_frame_->repeat_pict, 2); // Sanity check.
+ (*video_frame)->SetRepeatCount(av_frame_->repeat_pict);
+ }
}
}
« no previous file with comments | « media/filters/ffmpeg_video_decode_engine.h ('k') | media/filters/ffmpeg_video_decode_engine_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698