Index: media/filters/ffmpeg_demuxer.cc |
=================================================================== |
--- media/filters/ffmpeg_demuxer.cc (revision 19853) |
+++ media/filters/ffmpeg_demuxer.cc (working copy) |
@@ -215,16 +215,40 @@ |
// FFmpegDemuxer |
// |
FFmpegDemuxer::FFmpegDemuxer() |
- : thread_id_(NULL) { |
+ : format_context_(NULL), |
+ thread_id_(NULL) { |
} |
FFmpegDemuxer::~FFmpegDemuxer() { |
- DCHECK(!format_context_.get()); |
- // TODO(scherkus): I believe we need to use av_close_input_file() here |
- // instead of scoped_ptr_malloc calling av_free(). |
- // |
- // Note that av_close_input_file() doesn't close the codecs so we need to |
- // figure out who's responsible for closing the them. |
+ // In this destructor, we clean up resources held by FFmpeg. It is ugly to |
+ // close the codec contexts here because the corresponding codecs are opened |
+ // in the decoder filters. By reaching this point, all filters should have |
+ // stopped, so this is the only safe place to do the global clean up. |
+ // TODO(hclam): close the codecs in the corresponding decoders. |
+ AutoLock auto_lock(FFmpegLock::get()->lock()); |
+ if (!format_context_) |
+ return; |
+ |
+ // Iterate each stream and destroy each one of them. |
+ int streams = format_context_->nb_streams; |
+ for (int i = 0; i < streams; ++i) { |
+ AVStream* stream = format_context_->streams[i]; |
+ |
+ // The conditions for calling avcodec_close(): |
+ // 1. AVStream is alive. |
+ // 2. AVCodecContext in AVStream is alive. |
+ // 3. AVCodec in AVCodecContext is alive. |
+ // Notice that closing a codec context without prior avcodec_open() will |
+ // result in a crash in FFmpeg. |
+ if (stream && stream->codec && stream->codec->codec) { |
+ stream->discard = AVDISCARD_ALL; |
+ avcodec_close(stream->codec); |
+ } |
+ } |
+ |
+ // Then finally cleanup the format context. |
+ av_close_input_file(format_context_); |
+ format_context_ = NULL; |
} |
void FFmpegDemuxer::PostDemuxTask() { |
@@ -281,7 +305,7 @@ |
std::string key = FFmpegGlue::get()->AddDataSource(data_source); |
// Open FFmpeg AVFormatContext. |
- DCHECK(!format_context_.get()); |
+ DCHECK(!format_context_); |
AVFormatContext* context = NULL; |
int result = av_open_input_file(&context, key.c_str(), NULL, 0, NULL); |
@@ -293,16 +317,15 @@ |
return; |
} |
- // Assign to our scoped_ptr_malloc. |
DCHECK(context); |
- format_context_.reset(context); |
+ format_context_ = context; |
// Serialize calls to av_find_stream_info(). |
{ |
AutoLock auto_lock(FFmpegLock::get()->lock()); |
// Fully initialize AVFormatContext by parsing the stream a little. |
- result = av_find_stream_info(format_context_.get()); |
+ result = av_find_stream_info(format_context_); |
if (result < 0) { |
host_->Error(DEMUXER_ERROR_COULD_NOT_PARSE); |
return; |
@@ -350,7 +373,7 @@ |
flags |= AVSEEK_FLAG_BACKWARD; |
} |
- if (av_seek_frame(format_context_.get(), -1, time.InMicroseconds(), |
+ if (av_seek_frame(format_context_, -1, time.InMicroseconds(), |
flags) < 0) { |
// TODO(scherkus): signal error. |
NOTIMPLEMENTED(); |
@@ -367,7 +390,7 @@ |
// Allocate and read an AVPacket from the media. |
scoped_ptr<AVPacket> packet(new AVPacket()); |
- int result = av_read_frame(format_context_.get(), packet.get()); |
+ int result = av_read_frame(format_context_, packet.get()); |
if (result < 0) { |
// If we have reached the end of stream, tell the downstream filters about |
// the event. |
@@ -420,9 +443,6 @@ |
for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
(*iter)->Stop(); |
} |
- |
- // Free our AVFormatContext. |
- format_context_.reset(); |
} |
bool FFmpegDemuxer::StreamsHavePendingReads() { |