| Index: media/filters/ffmpeg_demuxer.cc
|
| diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
|
| index c1a056cdbb8f2dc4cc86b43b183725e6ee859547..aa24e7a4d3150020ab2134de77859a723f1acb3f 100644
|
| --- a/media/filters/ffmpeg_demuxer.cc
|
| +++ b/media/filters/ffmpeg_demuxer.cc
|
| @@ -362,9 +362,13 @@ void FFmpegDemuxer::Initialize(DataSource* data_source,
|
|
|
| scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(
|
| DemuxerStream::Type type) {
|
| - DCHECK_GE(type, 0);
|
| - DCHECK_LT(type, DemuxerStream::NUM_TYPES);
|
| - return streams_[type];
|
| + StreamVector::iterator iter;
|
| + for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
|
| + if (*iter && (*iter)->type() == type) {
|
| + return *iter;
|
| + }
|
| + }
|
| + return NULL;
|
| }
|
|
|
| base::TimeDelta FFmpegDemuxer::GetStartTime() const {
|
| @@ -479,38 +483,48 @@ void FFmpegDemuxer::InitializeTask(DataSource* data_source,
|
| return;
|
| }
|
|
|
| - // Create demuxer streams for all supported streams.
|
| - streams_.resize(DemuxerStream::NUM_TYPES);
|
| + // Create demuxer stream entries for each possible AVStream.
|
| + streams_.resize(format_context_->nb_streams);
|
| + bool found_audio_stream = false;
|
| + bool found_video_stream = false;
|
| +
|
| base::TimeDelta max_duration;
|
| - bool no_supported_streams = true;
|
| for (size_t i = 0; i < format_context_->nb_streams; ++i) {
|
| AVCodecContext* codec_context = format_context_->streams[i]->codec;
|
| AVMediaType codec_type = codec_context->codec_type;
|
| - if (codec_type == AVMEDIA_TYPE_AUDIO || codec_type == AVMEDIA_TYPE_VIDEO) {
|
| - AVStream* stream = format_context_->streams[i];
|
| - scoped_refptr<FFmpegDemuxerStream> demuxer_stream(
|
| - new FFmpegDemuxerStream(this, stream));
|
| - if (!streams_[demuxer_stream->type()]) {
|
| - no_supported_streams = false;
|
| - streams_[demuxer_stream->type()] = demuxer_stream;
|
| - max_duration = std::max(max_duration, demuxer_stream->duration());
|
| -
|
| - if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) {
|
| - const base::TimeDelta first_dts = ConvertFromTimeBase(
|
| - stream->time_base, stream->first_dts);
|
| - if (start_time_ == kNoTimestamp || first_dts < start_time_)
|
| - start_time_ = first_dts;
|
| - }
|
| - }
|
| - packet_streams_.push_back(demuxer_stream);
|
| +
|
| + if (codec_type == AVMEDIA_TYPE_AUDIO) {
|
| + if (found_audio_stream)
|
| + continue;
|
| + found_audio_stream = true;
|
| + } else if (codec_type == AVMEDIA_TYPE_VIDEO) {
|
| + if (found_video_stream)
|
| + continue;
|
| + found_video_stream = true;
|
| } else {
|
| - packet_streams_.push_back(NULL);
|
| + continue;
|
| + }
|
| +
|
| + AVStream* stream = format_context_->streams[i];
|
| + scoped_refptr<FFmpegDemuxerStream> demuxer_stream(
|
| + new FFmpegDemuxerStream(this, stream));
|
| +
|
| + streams_[i] = demuxer_stream;
|
| + max_duration = std::max(max_duration, demuxer_stream->duration());
|
| +
|
| + if (stream->first_dts != static_cast<int64_t>(AV_NOPTS_VALUE)) {
|
| + const base::TimeDelta first_dts = ConvertFromTimeBase(
|
| + stream->time_base, stream->first_dts);
|
| + if (start_time_ == kNoTimestamp || first_dts < start_time_)
|
| + start_time_ = first_dts;
|
| }
|
| }
|
| - if (no_supported_streams) {
|
| +
|
| + if (!found_audio_stream && !found_video_stream) {
|
| callback.Run(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
|
| return;
|
| }
|
| +
|
| if (format_context_->duration != static_cast<int64_t>(AV_NOPTS_VALUE)) {
|
| // If there is a duration value in the container use that to find the
|
| // maximum between it and the duration from A/V streams.
|
| @@ -642,26 +656,24 @@ void FFmpegDemuxer::DemuxTask() {
|
| // worried about downstream filters (i.e., decoders) executing on this
|
| // thread.
|
| DCHECK_GE(packet->stream_index, 0);
|
| - DCHECK_LT(packet->stream_index, static_cast<int>(packet_streams_.size()));
|
| - FFmpegDemuxerStream* demuxer_stream = NULL;
|
| - size_t i = packet->stream_index;
|
| + DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size()));
|
| +
|
| // Defend against ffmpeg giving us a bad stream index.
|
| - if (i < packet_streams_.size()) {
|
| - demuxer_stream = packet_streams_[i];
|
| - }
|
| - if (demuxer_stream) {
|
| - // Queue the packet with the appropriate stream. The stream takes
|
| - // ownership of the AVPacket.
|
| - if (packet.get()) {
|
| - // If a packet is returned by FFmpeg's av_parser_parse2()
|
| - // the packet will reference an inner memory of FFmpeg.
|
| - // In this case, the packet's "destruct" member is NULL,
|
| - // and it MUST be duplicated. This fixes issue with MP3 and possibly
|
| - // other codecs. It is safe to call this function even if the packet does
|
| - // not refer to inner memory from FFmpeg.
|
| - av_dup_packet(packet.get());
|
| - demuxer_stream->EnqueuePacket(packet.release());
|
| - }
|
| + if (packet->stream_index >= 0 &&
|
| + packet->stream_index < static_cast<int>(streams_.size()) &&
|
| + streams_[packet->stream_index]) {
|
| + FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index];
|
| +
|
| + // If a packet is returned by FFmpeg's av_parser_parse2()
|
| + // the packet will reference an inner memory of FFmpeg.
|
| + // In this case, the packet's "destruct" member is NULL,
|
| + // and it MUST be duplicated. This fixes issue with MP3 and possibly
|
| + // other codecs. It is safe to call this function even if the packet does
|
| + // not refer to inner memory from FFmpeg.
|
| + av_dup_packet(packet.get());
|
| +
|
| + // The stream takes ownership of the AVPacket.
|
| + demuxer_stream->EnqueuePacket(packet.release());
|
| }
|
|
|
| // Create a loop by posting another task. This allows seek and message loop
|
| @@ -687,17 +699,10 @@ void FFmpegDemuxer::StopTask(const base::Closure& callback) {
|
|
|
| void FFmpegDemuxer::DisableAudioStreamTask() {
|
| DCHECK_EQ(MessageLoop::current(), message_loop_);
|
| -
|
| StreamVector::iterator iter;
|
| - for (size_t i = 0; i < packet_streams_.size(); ++i) {
|
| - if (!packet_streams_[i])
|
| - continue;
|
| -
|
| - // If the codec type is audio, remove the reference. DemuxTask() will
|
| - // look for such reference, and this will result in deleting the
|
| - // audio packets after they are demuxed.
|
| - if (packet_streams_[i]->type() == DemuxerStream::AUDIO) {
|
| - packet_streams_[i] = NULL;
|
| + for (iter = streams_.begin(); iter != streams_.end(); ++iter) {
|
| + if (*iter && (*iter)->type() == DemuxerStream::AUDIO) {
|
| + (*iter)->Stop();
|
| }
|
| }
|
| }
|
|
|