| Index: media/filters/ffmpeg_demuxer.cc
|
| diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
|
| index 49d18d3823f115a335a1e0b88df7c572b2c46960..df4c37f076a78d0334ca0bcd03fba5a4d5b36d59 100644
|
| --- a/media/filters/ffmpeg_demuxer.cc
|
| +++ b/media/filters/ffmpeg_demuxer.cc
|
| @@ -253,6 +253,10 @@ std::unique_ptr<FFmpegDemuxerStream> FFmpegDemuxerStream::Create(
|
| demuxer, stream, std::move(audio_config), std::move(video_config)));
|
| }
|
|
|
| +static void UnmarkEndOfStream(AVFormatContext* format_context) {
|
| + format_context->pb->eof_reached = 0;
|
| +}
|
| +
|
| //
|
| // FFmpegDemuxerStream
|
| //
|
| @@ -593,6 +597,11 @@ void FFmpegDemuxerStream::FlushBuffers() {
|
| last_packet_duration_ = kNoTimestamp;
|
| }
|
|
|
| +void FFmpegDemuxerStream::Abort() {
|
| + if (!read_cb_.is_null())
|
| + base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kAborted, nullptr);
|
| +}
|
| +
|
| void FFmpegDemuxerStream::Stop() {
|
| DCHECK(task_runner_->BelongsToCurrentThread());
|
| buffer_queue_.Clear();
|
| @@ -821,7 +830,6 @@ FFmpegDemuxer::FFmpegDemuxer(
|
| task_runner_(task_runner),
|
| blocking_thread_("FFmpegDemuxer"),
|
| pending_read_(false),
|
| - pending_seek_(false),
|
| data_source_(data_source),
|
| media_log_(media_log),
|
| bitrate_(0),
|
| @@ -880,6 +888,36 @@ void FFmpegDemuxer::Initialize(DemuxerHost* host,
|
| status_cb));
|
| }
|
|
|
| +void FFmpegDemuxer::AbortPendingReads() {
|
| + DCHECK(task_runner_->BelongsToCurrentThread());
|
| +
|
| + // This should only be called after the demuxer has been initialized.
|
| + DCHECK(blocking_thread_.IsRunning());
|
| + DCHECK_GT(streams_.size(), 0u);
|
| +
|
| + // Abort all outstanding reads.
|
| + for (auto* stream : streams_) {
|
| + if (stream)
|
| + stream->Abort();
|
| + }
|
| +
|
| + // It's important to invalidate read/seek completion callbacks to avoid any
|
| + // errors that occur because of the data source abort.
|
| + weak_factory_.InvalidateWeakPtrs();
|
| + data_source_->Abort();
|
| +
|
| + // Aborting the read may cause EOF to be marked, undo this.
|
| + blocking_thread_.task_runner()->PostTask(
|
| + FROM_HERE, base::Bind(&UnmarkEndOfStream, glue_->format_context()));
|
| + pending_read_ = false;
|
| +
|
| + // TODO(dalecurtis): We probably should report PIPELINE_ERROR_ABORT here
|
| + // instead to avoid any preroll work that may be started upon return, but
|
| + // currently the PipelineImpl does not know how to handle this.
|
| + if (!pending_seek_cb_.is_null())
|
| + base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK);
|
| +}
|
| +
|
| void FFmpegDemuxer::Stop() {
|
| DCHECK(task_runner_->BelongsToCurrentThread());
|
|
|
| @@ -910,15 +948,19 @@ void FFmpegDemuxer::Stop() {
|
|
|
| void FFmpegDemuxer::StartWaitingForSeek(base::TimeDelta seek_time) {}
|
|
|
| -void FFmpegDemuxer::CancelPendingSeek(base::TimeDelta seek_time) {}
|
| +void FFmpegDemuxer::CancelPendingSeek(base::TimeDelta seek_time) {
|
| + if (task_runner_->BelongsToCurrentThread()) {
|
| + AbortPendingReads();
|
| + } else {
|
| + task_runner_->PostTask(FROM_HERE,
|
| + base::Bind(&FFmpegDemuxer::AbortPendingReads,
|
| + weak_factory_.GetWeakPtr()));
|
| + }
|
| +}
|
|
|
| void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
|
| DCHECK(task_runner_->BelongsToCurrentThread());
|
| - CHECK(!pending_seek_);
|
| -
|
| - // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|,
|
| - // otherwise we can end up waiting for a pre-seek read to complete even though
|
| - // we know we're going to drop it on the floor.
|
| + CHECK(pending_seek_cb_.is_null());
|
|
|
| // FFmpeg requires seeks to be adjusted according to the lowest starting time.
|
| // Since EnqueuePacket() rebased negative timestamps by the start time, we
|
| @@ -955,18 +997,14 @@ void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) {
|
| const AVStream* seeking_stream = demux_stream->av_stream();
|
| DCHECK(seeking_stream);
|
|
|
| - pending_seek_ = true;
|
| + pending_seek_cb_ = cb;
|
| base::PostTaskAndReplyWithResult(
|
| - blocking_thread_.task_runner().get(),
|
| - FROM_HERE,
|
| - base::Bind(&av_seek_frame,
|
| - glue_->format_context(),
|
| - seeking_stream->index,
|
| + blocking_thread_.task_runner().get(), FROM_HERE,
|
| + base::Bind(&av_seek_frame, glue_->format_context(), seeking_stream->index,
|
| ConvertToTimeBase(seeking_stream->time_base, seek_time),
|
| // Always seek to a timestamp <= to the desired timestamp.
|
| AVSEEK_FLAG_BACKWARD),
|
| - base::Bind(
|
| - &FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr(), cb));
|
| + base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr()));
|
| }
|
|
|
| base::Time FFmpegDemuxer::GetTimelineOffset() const {
|
| @@ -1506,14 +1544,13 @@ FFmpegDemuxerStream* FFmpegDemuxer::FindPreferredStreamForSeeking(
|
| GetStream(DemuxerStream::AUDIO));
|
| }
|
|
|
| -void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) {
|
| +void FFmpegDemuxer::OnSeekFrameDone(int result) {
|
| DCHECK(task_runner_->BelongsToCurrentThread());
|
| - CHECK(pending_seek_);
|
| - pending_seek_ = false;
|
| + CHECK(!pending_seek_cb_.is_null());
|
|
|
| if (!blocking_thread_.IsRunning()) {
|
| MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state";
|
| - cb.Run(PIPELINE_ERROR_ABORT);
|
| + base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT);
|
| return;
|
| }
|
|
|
| @@ -1535,7 +1572,7 @@ void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) {
|
| ReadFrameIfNeeded();
|
|
|
| // Notify we're finished seeking.
|
| - cb.Run(PIPELINE_OK);
|
| + base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK);
|
| }
|
|
|
| void FFmpegDemuxer::OnEnabledAudioTracksChanged(
|
| @@ -1575,7 +1612,7 @@ void FFmpegDemuxer::ReadFrameIfNeeded() {
|
|
|
| // Make sure we have work to do before reading.
|
| if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() ||
|
| - pending_read_ || pending_seek_) {
|
| + pending_read_ || !pending_seek_cb_.is_null()) {
|
| return;
|
| }
|
|
|
| @@ -1600,16 +1637,15 @@ void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) {
|
| DCHECK(pending_read_);
|
| pending_read_ = false;
|
|
|
| - if (!blocking_thread_.IsRunning() || pending_seek_) {
|
| + if (!blocking_thread_.IsRunning() || !pending_seek_cb_.is_null())
|
| return;
|
| - }
|
|
|
| // Consider the stream as ended if:
|
| // - either underlying ffmpeg returned an error
|
| // - or FFMpegDemuxer reached the maximum allowed memory usage.
|
| if (result < 0 || IsMaxMemoryUsageReached()) {
|
| - LOG(ERROR) << __func__ << " result=" << result
|
| - << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached();
|
| + DVLOG(1) << __func__ << " result=" << result
|
| + << " IsMaxMemoryUsageReached=" << IsMaxMemoryUsageReached();
|
| // Update the duration based on the highest elapsed time across all streams
|
| // if it was previously unknown.
|
| if (!duration_known_) {
|
|
|