| Index: media/filters/video_decoder_impl.cc
|
| diff --git a/media/filters/video_decoder_impl.cc b/media/filters/video_decoder_impl.cc
|
| index 9592dbb2d367b2433780284a40b3decc7de6b157..a4a655efd13e493a7fda11f3dcdc7c1c7f23ee18 100644
|
| --- a/media/filters/video_decoder_impl.cc
|
| +++ b/media/filters/video_decoder_impl.cc
|
| @@ -139,31 +139,31 @@ void VideoDecoderImpl::DoDecode(Buffer* buffer, Task* done_cb) {
|
| }
|
|
|
| // Otherwise, attempt to decode a single frame.
|
| - AVFrame* yuv_frame = avcodec_alloc_frame();
|
| bool* got_frame = new bool;
|
| + scoped_refptr<VideoFrame>* video_frame = new scoped_refptr<VideoFrame>(NULL);
|
| decode_engine_->DecodeFrame(
|
| buffer,
|
| - yuv_frame,
|
| + video_frame,
|
| got_frame,
|
| NewRunnableMethod(this,
|
| &VideoDecoderImpl::OnDecodeComplete,
|
| - yuv_frame,
|
| + video_frame,
|
| got_frame,
|
| done_runner.release()));
|
| }
|
|
|
| -void VideoDecoderImpl::OnDecodeComplete(AVFrame* yuv_frame, bool* got_frame,
|
| - Task* done_cb) {
|
| +void VideoDecoderImpl::OnDecodeComplete(scoped_refptr<VideoFrame>* video_frame,
|
| + bool* got_frame, Task* done_cb) {
|
| // Note: The |done_runner| must be declared *last* to ensure proper
|
| // destruction order.
|
| - scoped_ptr_malloc<AVFrame, ScopedPtrAVFree> yuv_frame_deleter(yuv_frame);
|
| scoped_ptr<bool> got_frame_deleter(got_frame);
|
| + scoped_ptr<scoped_refptr<VideoFrame> > video_frame_deleter(video_frame);
|
| AutoTaskRunner done_runner(done_cb);
|
|
|
| // If we actually got data back, enqueue a frame.
|
| if (*got_frame) {
|
| last_pts_ = FindPtsAndDuration(*time_base_, pts_heap_, last_pts_,
|
| - yuv_frame);
|
| + video_frame->get());
|
|
|
| // Pop off a pts on a successful decode since we are "using up" one
|
| // timestamp.
|
| @@ -179,12 +179,9 @@ void VideoDecoderImpl::OnDecodeComplete(AVFrame* yuv_frame, bool* got_frame,
|
| NOTREACHED() << "Attempting to decode more frames than were input.";
|
| }
|
|
|
| - if (!EnqueueVideoFrame(
|
| - decode_engine_->GetSurfaceFormat(), last_pts_, yuv_frame)) {
|
| - // On an EnqueueEmptyFrame error, error out the whole pipeline and
|
| - // set the state to kDecodeFinished.
|
| - SignalPipelineError();
|
| - }
|
| + (*video_frame)->SetTimestamp(last_pts_.timestamp);
|
| + (*video_frame)->SetDuration(last_pts_.duration);
|
| + EnqueueVideoFrame(*video_frame);
|
| } else {
|
| // When in kFlushCodec, any errored decode, or a 0-lengthed frame,
|
| // is taken as a signal to stop decoding.
|
| @@ -195,59 +192,9 @@ void VideoDecoderImpl::OnDecodeComplete(AVFrame* yuv_frame, bool* got_frame,
|
| }
|
| }
|
|
|
| -bool VideoDecoderImpl::EnqueueVideoFrame(VideoFrame::Format surface_format,
|
| - const TimeTuple& time,
|
| - const AVFrame* 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 (!frame->data[VideoFrame::kYPlane] ||
|
| - !frame->data[VideoFrame::kUPlane] ||
|
| - !frame->data[VideoFrame::kVPlane]) {
|
| - return true;
|
| - }
|
| -
|
| - scoped_refptr<VideoFrame> video_frame;
|
| - VideoFrame::CreateFrame(surface_format, width_, height_,
|
| - time.timestamp, time.duration, &video_frame);
|
| - if (!video_frame) {
|
| - return false;
|
| - }
|
| -
|
| - // 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, frame);
|
| - CopyPlane(VideoFrame::kUPlane, *video_frame, frame);
|
| - CopyPlane(VideoFrame::kVPlane, *video_frame, frame);
|
| +void VideoDecoderImpl::EnqueueVideoFrame(
|
| + const scoped_refptr<VideoFrame>& video_frame) {
|
| EnqueueResult(video_frame);
|
| - return true;
|
| -}
|
| -
|
| -void VideoDecoderImpl::CopyPlane(size_t plane,
|
| - const 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;
|
| - }
|
| }
|
|
|
| void VideoDecoderImpl::EnqueueEmptyFrame() {
|
| @@ -260,29 +207,24 @@ VideoDecoderImpl::TimeTuple VideoDecoderImpl::FindPtsAndDuration(
|
| const AVRational& time_base,
|
| const PtsHeap& pts_heap,
|
| const TimeTuple& last_pts,
|
| - const AVFrame* frame) {
|
| + const VideoFrame* frame) {
|
| TimeTuple pts;
|
|
|
| - // Default |repeat_pict| to 0 because if there is no frame information,
|
| - // we just assume the frame only plays for one time_base.
|
| - int repeat_pict = 0;
|
| + // First search the VideoFrame for the pts. This is the most authoritative.
|
| + // Make a special exclusion for the value pts == 0. Though this is
|
| + // technically a valid value, it seems a number of ffmpeg codecs will
|
| + // mistakenly always set pts to 0.
|
| + DCHECK(frame);
|
| + base::TimeDelta timestamp = frame->GetTimestamp();
|
| + if (timestamp != StreamSample::kInvalidTimestamp &&
|
| + timestamp.ToInternalValue() != 0) {
|
| + pts.timestamp = ConvertTimestamp(time_base, timestamp.ToInternalValue());
|
| + pts.duration = ConvertTimestamp(time_base, 1 + frame->GetRepeatCount());
|
| + return pts;
|
| + }
|
|
|
| - // First search the AVFrame for the pts. This is the most authoritative.
|
| - // Make a special exclusion for the value frame->pts == 0. Though this
|
| - // is technically a valid value, it seems a number of ffmpeg codecs will
|
| - // mistakenly always set frame->pts to 0.
|
| - //
|
| - // Oh, and we have to cast AV_NOPTS_VALUE since it ends up becoming unsigned
|
| - // because the value they use doesn't fit in a signed 64-bit number which
|
| - // produces a signedness comparison warning on gcc.
|
| - if (frame &&
|
| - (frame->pts != static_cast<int64_t>(AV_NOPTS_VALUE)) &&
|
| - (frame->pts != 0)) {
|
| - pts.timestamp = ConvertTimestamp(time_base, frame->pts);
|
| - repeat_pict = frame->repeat_pict;
|
| - } else if (!pts_heap.IsEmpty()) {
|
| - // If the frame did not have pts, try to get the pts from the
|
| - // |pts_heap|.
|
| + if (!pts_heap.IsEmpty()) {
|
| + // If the frame did not have pts, try to get the pts from the |pts_heap|.
|
| pts.timestamp = pts_heap.Top();
|
| } else {
|
| DCHECK(last_pts.timestamp != StreamSample::kInvalidTimestamp);
|
| @@ -292,9 +234,7 @@ VideoDecoderImpl::TimeTuple VideoDecoderImpl::FindPtsAndDuration(
|
| }
|
|
|
| // Fill in the duration while accounting for repeated frames.
|
| - //
|
| - // TODO(ajwong): Make sure this formula is correct.
|
| - pts.duration = ConvertTimestamp(time_base, 1 + repeat_pict);
|
| + pts.duration = ConvertTimestamp(time_base, 1);
|
|
|
| return pts;
|
| }
|
|
|