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

Side by Side Diff: media/filters/ffmpeg_video_decoder.cc

Issue 10704175: Add config change support to FFmpegVideoDecoder (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/ffmpeg_video_decoder.h" 5 #include "media/filters/ffmpeg_video_decoder.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/callback_helpers.h" 8 #include "base/callback_helpers.h"
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 DCHECK(format == VideoFrame::YV12 || format == VideoFrame::YV16); 76 DCHECK(format == VideoFrame::YV12 || format == VideoFrame::YV16);
77 77
78 int width = codec_context->width; 78 int width = codec_context->width;
79 int height = codec_context->height; 79 int height = codec_context->height;
80 int ret; 80 int ret;
81 if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) 81 if ((ret = av_image_check_size(width, height, 0, NULL)) < 0)
82 return ret; 82 return ret;
83 83
84 scoped_refptr<VideoFrame> video_frame = 84 scoped_refptr<VideoFrame> video_frame =
85 VideoFrame::CreateFrame(format, width, height, 85 VideoFrame::CreateFrame(format, width, height,
86 natural_size_.width(),
87 natural_size_.height(),
86 kNoTimestamp(), kNoTimestamp()); 88 kNoTimestamp(), kNoTimestamp());
87 89
88 for (int i = 0; i < 3; i++) { 90 for (int i = 0; i < 3; i++) {
89 frame->base[i] = video_frame->data(i); 91 frame->base[i] = video_frame->data(i);
90 frame->data[i] = video_frame->data(i); 92 frame->data[i] = video_frame->data(i);
91 frame->linesize[i] = video_frame->stride(i); 93 frame->linesize[i] = video_frame->stride(i);
92 } 94 }
93 95
94 frame->opaque = video_frame.release(); 96 frame->opaque = video_frame.release();
95 frame->type = FF_BUFFER_TYPE_USER; 97 frame->type = FF_BUFFER_TYPE_USER;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 const VideoDecoderConfig& config = stream->video_decoder_config(); 153 const VideoDecoderConfig& config = stream->video_decoder_config();
152 154
153 // TODO(scherkus): this check should go in Pipeline prior to creating 155 // TODO(scherkus): this check should go in Pipeline prior to creating
154 // decoder objects. 156 // decoder objects.
155 if (!config.IsValidConfig()) { 157 if (!config.IsValidConfig()) {
156 DLOG(ERROR) << "Invalid video stream - " << config.AsHumanReadableString(); 158 DLOG(ERROR) << "Invalid video stream - " << config.AsHumanReadableString();
157 status_cb.Run(PIPELINE_ERROR_DECODE); 159 status_cb.Run(PIPELINE_ERROR_DECODE);
158 return; 160 return;
159 } 161 }
160 162
161 // Initialize AVCodecContext structure. 163 if (!AllocateFFmpegResources(config)) {
Ami GONE FROM CHROMIUM 2012/07/13 00:59:05 I wonder if it doesn't make sense to inline AFFMR(
162 codec_context_ = avcodec_alloc_context3(NULL);
163 VideoDecoderConfigToAVCodecContext(config, codec_context_);
164
165 // Enable motion vector search (potentially slow), strong deblocking filter
166 // for damaged macroblocks, and set our error detection sensitivity.
167 codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
168 codec_context_->err_recognition = AV_EF_CAREFUL;
169 codec_context_->thread_count = GetThreadCount(codec_context_->codec_id);
170 codec_context_->opaque = this;
171 codec_context_->flags |= CODEC_FLAG_EMU_EDGE;
172 codec_context_->get_buffer = GetVideoBufferImpl;
173 codec_context_->release_buffer = ReleaseVideoBufferImpl;
174
175 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
176 if (!codec) {
177 status_cb.Run(PIPELINE_ERROR_DECODE);
178 return;
179 }
180
181 if (avcodec_open2(codec_context_, codec, NULL) < 0) {
182 status_cb.Run(PIPELINE_ERROR_DECODE); 164 status_cb.Run(PIPELINE_ERROR_DECODE);
183 return; 165 return;
184 } 166 }
185 167
186 // Success! 168 // Success!
187 state_ = kNormal; 169 state_ = kNormal;
188 av_frame_ = avcodec_alloc_frame();
189 natural_size_ = config.natural_size(); 170 natural_size_ = config.natural_size();
190 frame_rate_numerator_ = config.frame_rate_numerator(); 171 frame_rate_numerator_ = config.frame_rate_numerator();
191 frame_rate_denominator_ = config.frame_rate_denominator(); 172 frame_rate_denominator_ = config.frame_rate_denominator();
Ami GONE FROM CHROMIUM 2012/07/13 00:59:05 ...in which case these can go away
192 status_cb.Run(PIPELINE_OK); 173 status_cb.Run(PIPELINE_OK);
193 } 174 }
194 175
195 void FFmpegVideoDecoder::Read(const ReadCB& read_cb) { 176 void FFmpegVideoDecoder::Read(const ReadCB& read_cb) {
196 // Complete operation asynchronously on different stack of execution as per 177 // Complete operation asynchronously on different stack of execution as per
197 // the API contract of VideoDecoder::Read() 178 // the API contract of VideoDecoder::Read()
198 message_loop_->PostTask(FROM_HERE, base::Bind( 179 message_loop_->PostTask(FROM_HERE, base::Bind(
199 &FFmpegVideoDecoder::DoRead, this, read_cb)); 180 &FFmpegVideoDecoder::DoRead, this, read_cb));
200 } 181 }
201 182
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 DCHECK_NE(state_, kUninitialized); 275 DCHECK_NE(state_, kUninitialized);
295 DCHECK_NE(state_, kDecodeFinished); 276 DCHECK_NE(state_, kDecodeFinished);
296 DCHECK(!read_cb_.is_null()); 277 DCHECK(!read_cb_.is_null());
297 278
298 if (!reset_cb_.is_null()) { 279 if (!reset_cb_.is_null()) {
299 DeliverFrame(NULL); 280 DeliverFrame(NULL);
300 DoReset(); 281 DoReset();
301 return; 282 return;
302 } 283 }
303 284
304 if (status != DemuxerStream::kOk) { 285 if (status == DemuxerStream::kAborted) {
305 DecoderStatus decoder_status = 286 base::ResetAndReturn(&read_cb_).Run(kOk, NULL);
306 (status == DemuxerStream::kAborted) ? kOk : kDecodeError;
307 base::ResetAndReturn(&read_cb_).Run(decoder_status, NULL);
308 return; 287 return;
309 } 288 }
310 289
290 if (status == DemuxerStream::kConfigChanged) {
291 if (!HandleConfigChange()) {
292 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL);
293 return;
294 }
295
296 ReadFromDemuxerStream();
297 return;
298 }
299
311 // During decode, because reads are issued asynchronously, it is possible to 300 // During decode, because reads are issued asynchronously, it is possible to
312 // receive multiple end of stream buffers since each read is acked. When the 301 // receive multiple end of stream buffers since each read is acked. When the
313 // first end of stream buffer is read, FFmpeg may still have frames queued 302 // first end of stream buffer is read, FFmpeg may still have frames queued
314 // up in the decoder so we need to go through the decode loop until it stops 303 // up in the decoder so we need to go through the decode loop until it stops
315 // giving sensible data. After that, the decoder should output empty 304 // giving sensible data. After that, the decoder should output empty
316 // frames. There are three states the decoder can be in: 305 // frames. There are three states the decoder can be in:
317 // 306 //
318 // kNormal: This is the starting state. Buffers are decoded. Decode errors 307 // kNormal: This is the starting state. Buffers are decoded. Decode errors
319 // are discarded. 308 // are discarded.
320 // kFlushCodec: There isn't any more input data. Call avcodec_decode_video2 309 // kFlushCodec: There isn't any more input data. Call avcodec_decode_video2
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
470 459
471 return true; 460 return true;
472 } 461 }
473 462
474 void FFmpegVideoDecoder::DeliverFrame( 463 void FFmpegVideoDecoder::DeliverFrame(
475 const scoped_refptr<VideoFrame>& video_frame) { 464 const scoped_refptr<VideoFrame>& video_frame) {
476 // Reset the callback before running to protect against reentrancy. 465 // Reset the callback before running to protect against reentrancy.
477 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); 466 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame);
478 } 467 }
479 468
469 bool FFmpegVideoDecoder::AllocateFFmpegResources(
470 const VideoDecoderConfig& config) {
471 DCHECK(!codec_context_);
472 DCHECK(!av_frame_);
473
474 // Initialize AVCodecContext structure.
475 codec_context_ = avcodec_alloc_context3(NULL);
476 VideoDecoderConfigToAVCodecContext(config, codec_context_);
477
478 // Enable motion vector search (potentially slow), strong deblocking filter
479 // for damaged macroblocks, and set our error detection sensitivity.
480 codec_context_->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK;
481 codec_context_->err_recognition = AV_EF_CAREFUL;
482 codec_context_->thread_count = GetThreadCount(codec_context_->codec_id);
483 codec_context_->opaque = this;
484 codec_context_->flags |= CODEC_FLAG_EMU_EDGE;
485 codec_context_->get_buffer = GetVideoBufferImpl;
486 codec_context_->release_buffer = ReleaseVideoBufferImpl;
487
488 AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
489 if (!codec)
490 return false;
491
492 if (avcodec_open2(codec_context_, codec, NULL) < 0)
493 return false;
494
495 av_frame_ = avcodec_alloc_frame();
496 return true;
497 }
498
480 void FFmpegVideoDecoder::ReleaseFFmpegResources() { 499 void FFmpegVideoDecoder::ReleaseFFmpegResources() {
481 if (codec_context_) { 500 if (codec_context_) {
482 av_free(codec_context_->extradata); 501 av_free(codec_context_->extradata);
483 avcodec_close(codec_context_); 502 avcodec_close(codec_context_);
484 av_free(codec_context_); 503 av_free(codec_context_);
485 codec_context_ = NULL; 504 codec_context_ = NULL;
486 } 505 }
487 if (av_frame_) { 506 if (av_frame_) {
488 av_free(av_frame_); 507 av_free(av_frame_);
489 av_frame_ = NULL; 508 av_frame_ = NULL;
490 } 509 }
491 } 510 }
492 511
512 bool FFmpegVideoDecoder::HandleConfigChange() {
513 const VideoDecoderConfig& config = demuxer_stream_->video_decoder_config();
514
515 if (!config.IsValidConfig())
516 return false;
517
518 ReleaseFFmpegResources();
519 if (!AllocateFFmpegResources(config))
520 return false;
521
522 natural_size_ = config.natural_size();
523 frame_rate_numerator_ = config.frame_rate_numerator();
524 frame_rate_denominator_ = config.frame_rate_denominator();
525 return true;
526 }
527
493 } // namespace media 528 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698