Chromium Code Reviews| Index: media/filters/ffmpeg_demuxer.cc |
| diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc |
| index 081bcbf1a452be23ee45adb6a080e11bd5b55c77..238c31eeb6a53c3b3cf0b3977ec91a01ec1b482a 100644 |
| --- a/media/filters/ffmpeg_demuxer.cc |
| +++ b/media/filters/ffmpeg_demuxer.cc |
| @@ -867,6 +867,8 @@ FFmpegDemuxer::FFmpegDemuxer( |
| duration_known_(false), |
| encrypted_media_init_data_cb_(encrypted_media_init_data_cb), |
| media_tracks_updated_cb_(media_tracks_updated_cb), |
| + last_packet_pos_(-1), |
| + restarting_stream_(nullptr), |
| cancel_pending_seek_factory_(this), |
| weak_factory_(this) { |
| DCHECK(task_runner_.get()); |
| @@ -1655,6 +1657,8 @@ void FFmpegDemuxer::OnSeekFrameDone(int result) { |
| VLOG(1) << "Not implemented"; |
| } |
| + last_packet_pos_ = -1; |
| + |
| // Tell streams to flush buffers due to seeking. |
| for (const auto& stream : streams_) { |
| if (stream) |
| @@ -1728,9 +1732,38 @@ void FFmpegDemuxer::OnSelectedVideoTrackChanged( |
| if (selected_stream) { |
| DVLOG(1) << __func__ << ": enabling stream " << selected_stream; |
| selected_stream->SetEnabled(true, curr_time); |
| + selected_stream->FlushBuffers(); |
| + |
| + base::TimeDelta seek_time = |
|
DaleCurtis
2017/05/04 18:53:03
Extract common code from Seek() and put in an inte
servolk
2017/05/04 19:15:16
Will do.
servolk
2017/05/04 22:13:16
Done (I've extracted most of the common seeking lo
|
| + start_time_ < base::TimeDelta() |
| + ? curr_time + start_time_ |
| + : curr_time < start_time_ ? start_time_ : curr_time; |
| + |
| + base::PostTaskAndReplyWithResult( |
| + blocking_task_runner_.get(), FROM_HERE, |
| + base::Bind(&av_seek_frame, glue_->format_context(), |
| + selected_stream->av_stream()->index, |
| + ConvertToTimeBase(selected_stream->av_stream()->time_base, |
| + seek_time), |
| + // Always seek to a timestamp <= to the desired timestamp. |
| + AVSEEK_FLAG_BACKWARD), |
| + base::Bind(&FFmpegDemuxer::OnSeekDoneForRestartingStream, |
| + weak_factory_.GetWeakPtr(), selected_stream)); |
| } |
| } |
| +void FFmpegDemuxer::OnSeekDoneForRestartingStream(FFmpegDemuxerStream* stream, |
| + int result) { |
| + DCHECK(task_runner_->BelongsToCurrentThread()); |
| + if (result < 0) { |
| + DVLOG(1) << __func__ << ": seek failed: " << AVErrorToString(result); |
| + return; |
| + } |
| + DVLOG(2) << __func__ |
| + << ": will drop packets until last_packet_pos_=" << last_packet_pos_; |
| + restarting_stream_ = stream; |
|
DaleCurtis
2017/05/04 18:53:03
What happens if another track is enabled and tramp
servolk
2017/05/04 19:15:16
Great question. I think it could happen, but we sh
DaleCurtis
2017/05/04 21:21:06
Isn't that wrong though? I.e. the stream we restar
servolk
2017/05/04 21:38:30
I think that's ok, because we only use this logic
DaleCurtis
2017/05/04 21:41:12
Even if we just consider audio, depending on how t
DaleCurtis
2017/05/04 21:46:12
Oh right I see what you mean, we only run the seek
|
| +} |
| + |
| void FFmpegDemuxer::ReadFrameIfNeeded() { |
| DCHECK(task_runner_->BelongsToCurrentThread()); |
| @@ -1815,7 +1848,25 @@ void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { |
| } |
| FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index].get(); |
| - if (demuxer_stream->IsEnabled()) |
| + |
| + // If |restarting_stream_| is not null, we are in stream restart mode, which |
| + // means we seeked back the ffmpeg reading position and now we need to drop |
| + // packets from other streams until we reach the previously seen read |
| + // position |last_packet_pos_|. |
| + bool drop_seen_packet = |
|
DaleCurtis
2017/05/04 18:53:03
Drop unnecessary parens.
servolk
2017/05/04 19:15:16
Done.
|
| + (restarting_stream_ && demuxer_stream != restarting_stream_ && |
| + last_packet_pos_ >= 0 && packet.get()->pos <= last_packet_pos_); |
|
DaleCurtis
2017/05/04 18:53:03
Is pos monotonically increasing? I.e. this won't b
servolk
2017/05/04 19:15:15
I don't know for sure, but I think it should be mo
|
| + if (drop_seen_packet) { |
| + DVLOG(4) << "Dropping packet: pos=" << packet.get()->pos; |
|
DaleCurtis
2017/05/04 18:53:03
"already seen packet"
servolk
2017/05/04 19:15:16
Done.
|
| + } else if (restarting_stream_ && demuxer_stream != restarting_stream_) { |
| + DVLOG(2) << "Restarting reading packets: pos=" << packet.get()->pos; |
| + restarting_stream_ = nullptr; |
| + } |
| + |
| + if (!restarting_stream_) |
| + last_packet_pos_ = packet.get()->pos; |
| + |
| + if (demuxer_stream->IsEnabled() && !drop_seen_packet) |
| demuxer_stream->EnqueuePacket(std::move(packet)); |
| // If duration estimate was incorrect, update it and tell higher layers. |