Index: media/filters/ffmpeg_demuxer.cc |
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc |
index dcc178469e3bec2be3ca2838269e174465507964..05fa340ad55147d5b6d0934f35ea1b73c71d665d 100644 |
--- a/media/filters/ffmpeg_demuxer.cc |
+++ b/media/filters/ffmpeg_demuxer.cc |
@@ -84,10 +84,8 @@ static base::TimeDelta ExtractStartTime(AVStream* stream, |
// |
// FFmpegDemuxerStream |
// |
-FFmpegDemuxerStream::FFmpegDemuxerStream( |
- FFmpegDemuxer* demuxer, |
- AVStream* stream, |
- bool discard_negative_timestamps) |
+FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer, |
+ AVStream* stream) |
: demuxer_(demuxer), |
task_runner_(base::MessageLoopProxy::current()), |
stream_(stream), |
@@ -95,7 +93,7 @@ FFmpegDemuxerStream::FFmpegDemuxerStream( |
end_of_stream_(false), |
last_packet_timestamp_(kNoTimestamp()), |
bitstream_converter_enabled_(false), |
- discard_negative_timestamps_(discard_negative_timestamps) { |
+ fixup_negative_ogg_timestamps_(false) { |
DCHECK(demuxer_); |
bool is_encrypted = false; |
@@ -262,11 +260,21 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { |
ConvertStreamTimestamp(stream_->time_base, packet->pts); |
if (stream_timestamp != kNoTimestamp()) { |
- buffer->set_timestamp(stream_timestamp - demuxer_->start_time()); |
+ // If this is an OGG file with negative timestamps don't rebase any other |
+ // stream types against the negative starting time. |
+ base::TimeDelta start_time = demuxer_->start_time(); |
+ if (fixup_negative_ogg_timestamps_ && type() != AUDIO && |
+ start_time < base::TimeDelta()) { |
+ DCHECK(stream_timestamp >= base::TimeDelta()); |
+ start_time = base::TimeDelta(); |
+ } |
+ |
+ buffer->set_timestamp(stream_timestamp - start_time); |
// If enabled, mark packets with negative timestamps for post-decode |
// discard. |
- if (discard_negative_timestamps_ && stream_timestamp < base::TimeDelta()) { |
+ if (fixup_negative_ogg_timestamps_ && |
+ stream_timestamp < base::TimeDelta()) { |
if (stream_timestamp + buffer->duration() < base::TimeDelta()) { |
// Discard the entire packet if it's entirely before zero. |
buffer->set_discard_padding( |
@@ -502,12 +510,21 @@ void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { |
// FFmpeg requires seeks to be adjusted according to the lowest starting time. |
const base::TimeDelta seek_time = time + start_time_; |
- // Choose the preferred stream if |seek_time| occurs after its starting time, |
- // otherwise use the fallback stream. |
+ // Choose the seeking stream based on whether it contains the seek time, if no |
+ // match can be found prefer the preferred stream. |
+ // |
+ // TODO(dalecurtis): Currently FFmpeg does not ensure that all streams in a |
+ // given container will demux all packets after the seek point. Instead it |
+ // only guarantees that all packets after the file position of the seek will |
+ // be demuxed. It's an open question whether FFmpeg should fix this: |
+ // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html |
+ // Tracked by http://crbug.com/387996. |
DCHECK(preferred_stream_for_seeking_.second != kNoTimestamp()); |
- const int stream_index = seek_time >= preferred_stream_for_seeking_.second |
- ? preferred_stream_for_seeking_.first |
- : fallback_stream_for_seeking_.first; |
+ const int stream_index = |
+ seek_time < preferred_stream_for_seeking_.second && |
+ seek_time >= fallback_stream_for_seeking_.second |
+ ? fallback_stream_for_seeking_.first |
+ : preferred_stream_for_seeking_.first; |
DCHECK_NE(stream_index, -1); |
const AVStream* seeking_stream = |
@@ -722,7 +739,6 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
AVStream* stream = format_context->streams[i]; |
const AVCodecContext* codec_context = stream->codec; |
const AVMediaType codec_type = codec_context->codec_type; |
- bool discard_negative_timestamps = false; |
if (codec_type == AVMEDIA_TYPE_AUDIO) { |
if (audio_stream) |
@@ -737,13 +753,6 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
if (!audio_config.IsValidConfig()) |
continue; |
audio_stream = stream; |
- |
- // Enable post-decode frame dropping for packets with negative timestamps |
- // as outlined in section A.2 in the Ogg Vorbis spec: |
- // http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
- discard_negative_timestamps = |
- audio_config.codec() == kCodecVorbis && |
- strcmp(glue_->format_context()->iformat->name, "ogg") == 0; |
} else if (codec_type == AVMEDIA_TYPE_VIDEO) { |
if (video_stream) |
continue; |
@@ -766,8 +775,7 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
continue; |
} |
- streams_[i] = |
- new FFmpegDemuxerStream(this, stream, discard_negative_timestamps); |
+ streams_[i] = new FFmpegDemuxerStream(this, stream); |
max_duration = std::max(max_duration, streams_[i]->duration()); |
const base::TimeDelta start_time = |
@@ -813,6 +821,27 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
max_duration = kInfiniteDuration(); |
} |
+ // Ogg has some peculiarities around negative timestamps, so use this flag to |
+ // setup the FFmpegDemuxerStreams appropriately. |
+ // |
+ // Post-decode frame dropping for packets with negative timestamps is outlined |
+ // in section A.2 in the Ogg Vorbis spec: |
+ // http://xiph.org/vorbis/doc/Vorbis_I_spec.html |
+ if (strcmp(format_context->iformat->name, "ogg") == 0 && audio_stream && |
+ audio_stream->codec->codec_id == AV_CODEC_ID_VORBIS) { |
+ for (size_t i = 0; i < streams_.size(); ++i) { |
+ if (streams_[i]) |
+ streams_[i]->enable_negative_timestamp_fixups_for_ogg(); |
+ } |
+ |
+ // Fixup the seeking information to avoid selecting the audio stream simply |
+ // because it has a lower starting time. |
+ if (fallback_stream_for_seeking_.first == audio_stream->index && |
+ fallback_stream_for_seeking_.second < base::TimeDelta()) { |
+ fallback_stream_for_seeking_.second = base::TimeDelta(); |
+ } |
+ } |
+ |
// If no start time could be determined, default to zero and prefer the video |
// stream over the audio stream for seeking. E.g., The WAV demuxer does not |
// put timestamps on its frames. |