OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/filters/ffmpeg_demuxer.h" | 5 #include "media/filters/ffmpeg_demuxer.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <memory> | 8 #include <memory> |
9 #include <set> | 9 #include <set> |
10 #include <utility> | 10 #include <utility> |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
44 #include "media/media_features.h" | 44 #include "media/media_features.h" |
45 | 45 |
46 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) | 46 #if BUILDFLAG(ENABLE_HEVC_DEMUXING) |
47 #include "media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.h" | 47 #include "media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.h" |
48 #endif | 48 #endif |
49 | 49 |
50 namespace media { | 50 namespace media { |
51 | 51 |
52 namespace { | 52 namespace { |
53 | 53 |
54 // Try to have two second's worth of encoded data per stream. | |
55 const base::TimeDelta kDefaultStreamCapacity = base::TimeDelta::FromSeconds(2); | |
DaleCurtis
2017/05/24 22:24:17
constexpr or this is a static initializer.
servolk
2017/05/24 22:58:19
Done.
| |
56 | |
54 void SetAVStreamDiscard(AVStream* stream, AVDiscard discard) { | 57 void SetAVStreamDiscard(AVStream* stream, AVDiscard discard) { |
55 DCHECK(stream); | 58 DCHECK(stream); |
56 stream->discard = discard; | 59 stream->discard = discard; |
57 } | 60 } |
58 | 61 |
59 } // namespace | 62 } // namespace |
60 | 63 |
61 static base::Time ExtractTimelineOffset( | 64 static base::Time ExtractTimelineOffset( |
62 container_names::MediaContainerName container, | 65 container_names::MediaContainerName container, |
63 const AVFormatContext* format_context) { | 66 const AVFormatContext* format_context) { |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
295 media_log_(media_log), | 298 media_log_(media_log), |
296 type_(UNKNOWN), | 299 type_(UNKNOWN), |
297 liveness_(LIVENESS_UNKNOWN), | 300 liveness_(LIVENESS_UNKNOWN), |
298 end_of_stream_(false), | 301 end_of_stream_(false), |
299 last_packet_timestamp_(kNoTimestamp), | 302 last_packet_timestamp_(kNoTimestamp), |
300 last_packet_duration_(kNoTimestamp), | 303 last_packet_duration_(kNoTimestamp), |
301 video_rotation_(VIDEO_ROTATION_0), | 304 video_rotation_(VIDEO_ROTATION_0), |
302 is_enabled_(true), | 305 is_enabled_(true), |
303 waiting_for_keyframe_(false), | 306 waiting_for_keyframe_(false), |
304 aborted_(false), | 307 aborted_(false), |
305 fixup_negative_timestamps_(false) { | 308 fixup_negative_timestamps_(false), |
309 stream_capacity_(kDefaultStreamCapacity) { | |
306 DCHECK(demuxer_); | 310 DCHECK(demuxer_); |
307 | 311 |
308 bool is_encrypted = false; | 312 bool is_encrypted = false; |
309 int rotation = 0; | 313 int rotation = 0; |
310 AVDictionaryEntry* rotation_entry = NULL; | 314 AVDictionaryEntry* rotation_entry = NULL; |
311 | 315 |
312 // Determine our media format. | 316 // Determine our media format. |
313 switch (stream->codecpar->codec_type) { | 317 switch (stream->codecpar->codec_type) { |
314 case AVMEDIA_TYPE_AUDIO: | 318 case AVMEDIA_TYPE_AUDIO: |
315 DCHECK(audio_config_.get() && !video_config_.get()); | 319 DCHECK(audio_config_.get() && !video_config_.get()); |
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
804 } | 808 } |
805 } | 809 } |
806 | 810 |
807 // Have capacity? Ask for more! | 811 // Have capacity? Ask for more! |
808 if (HasAvailableCapacity() && !end_of_stream_) { | 812 if (HasAvailableCapacity() && !end_of_stream_) { |
809 demuxer_->NotifyCapacityAvailable(); | 813 demuxer_->NotifyCapacityAvailable(); |
810 } | 814 } |
811 } | 815 } |
812 | 816 |
813 bool FFmpegDemuxerStream::HasAvailableCapacity() { | 817 bool FFmpegDemuxerStream::HasAvailableCapacity() { |
814 // Try to have two second's worth of encoded data per stream. | 818 return buffer_queue_.IsEmpty() || buffer_queue_.Duration() < stream_capacity_; |
815 const base::TimeDelta kCapacity = base::TimeDelta::FromSeconds(2); | |
816 return buffer_queue_.IsEmpty() || buffer_queue_.Duration() < kCapacity; | |
817 } | 819 } |
818 | 820 |
819 size_t FFmpegDemuxerStream::MemoryUsage() const { | 821 size_t FFmpegDemuxerStream::MemoryUsage() const { |
820 return buffer_queue_.data_size(); | 822 return buffer_queue_.data_size(); |
821 } | 823 } |
822 | 824 |
823 TextKind FFmpegDemuxerStream::GetTextKind() const { | 825 TextKind FFmpegDemuxerStream::GetTextKind() const { |
824 DCHECK_EQ(type_, DemuxerStream::TEXT); | 826 DCHECK_EQ(type_, DemuxerStream::TEXT); |
825 | 827 |
826 if (stream_->disposition & AV_DISPOSITION_CAPTIONS) | 828 if (stream_->disposition & AV_DISPOSITION_CAPTIONS) |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
863 : host_(NULL), | 865 : host_(NULL), |
864 task_runner_(task_runner), | 866 task_runner_(task_runner), |
865 // FFmpeg has no asynchronous API, so we use base::WaitableEvents inside | 867 // FFmpeg has no asynchronous API, so we use base::WaitableEvents inside |
866 // the BlockingUrlProtocol to handle hops to the render thread for network | 868 // the BlockingUrlProtocol to handle hops to the render thread for network |
867 // reads and seeks. | 869 // reads and seeks. |
868 blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits( | 870 blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits( |
869 {base::MayBlock(), base::WithBaseSyncPrimitives(), | 871 {base::MayBlock(), base::WithBaseSyncPrimitives(), |
870 base::TaskPriority::USER_BLOCKING})), | 872 base::TaskPriority::USER_BLOCKING})), |
871 stopped_(false), | 873 stopped_(false), |
872 pending_read_(false), | 874 pending_read_(false), |
875 pending_seek_position_(kNoTimestamp), | |
873 data_source_(data_source), | 876 data_source_(data_source), |
874 media_log_(media_log), | 877 media_log_(media_log), |
875 bitrate_(0), | 878 bitrate_(0), |
876 start_time_(kNoTimestamp), | 879 start_time_(kNoTimestamp), |
877 text_enabled_(false), | 880 text_enabled_(false), |
878 duration_known_(false), | 881 duration_known_(false), |
879 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), | 882 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), |
880 media_tracks_updated_cb_(media_tracks_updated_cb), | 883 media_tracks_updated_cb_(media_tracks_updated_cb), |
884 last_audio_packet_pos_(-1), | |
885 restarting_stream_(nullptr), | |
881 cancel_pending_seek_factory_(this), | 886 cancel_pending_seek_factory_(this), |
882 weak_factory_(this) { | 887 weak_factory_(this) { |
883 DCHECK(task_runner_.get()); | 888 DCHECK(task_runner_.get()); |
884 DCHECK(data_source_); | 889 DCHECK(data_source_); |
885 DCHECK(!media_tracks_updated_cb_.is_null()); | 890 DCHECK(!media_tracks_updated_cb_.is_null()); |
886 } | 891 } |
887 | 892 |
888 FFmpegDemuxer::~FFmpegDemuxer() { | 893 FFmpegDemuxer::~FFmpegDemuxer() { |
889 // NOTE: This class is not destroyed on |task_runner|, so we must ensure that | 894 // NOTE: This class is not destroyed on |task_runner|, so we must ensure that |
890 // there are no outstanding WeakPtrs by the time we reach here. | 895 // there are no outstanding WeakPtrs by the time we reach here. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
961 blocking_task_runner_->PostTask( | 966 blocking_task_runner_->PostTask( |
962 FROM_HERE, | 967 FROM_HERE, |
963 base::Bind(&UnmarkEndOfStreamAndClearError, glue_->format_context())); | 968 base::Bind(&UnmarkEndOfStreamAndClearError, glue_->format_context())); |
964 pending_read_ = false; | 969 pending_read_ = false; |
965 | 970 |
966 // TODO(dalecurtis): We probably should report PIPELINE_ERROR_ABORT here | 971 // TODO(dalecurtis): We probably should report PIPELINE_ERROR_ABORT here |
967 // instead to avoid any preroll work that may be started upon return, but | 972 // instead to avoid any preroll work that may be started upon return, but |
968 // currently the PipelineImpl does not know how to handle this. | 973 // currently the PipelineImpl does not know how to handle this. |
969 if (!pending_seek_cb_.is_null()) | 974 if (!pending_seek_cb_.is_null()) |
970 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); | 975 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); |
976 pending_seek_position_ = kNoTimestamp; | |
971 } | 977 } |
972 | 978 |
973 void FFmpegDemuxer::Stop() { | 979 void FFmpegDemuxer::Stop() { |
974 DCHECK(task_runner_->BelongsToCurrentThread()); | 980 DCHECK(task_runner_->BelongsToCurrentThread()); |
975 | 981 |
976 // The order of Stop() and Abort() is important here. If Abort() is called | 982 // The order of Stop() and Abort() is important here. If Abort() is called |
977 // first, control may pass into FFmpeg where it can destruct buffers that are | 983 // first, control may pass into FFmpeg where it can destruct buffers that are |
978 // in the process of being fulfilled by the DataSource. | 984 // in the process of being fulfilled by the DataSource. |
979 data_source_->Stop(); | 985 data_source_->Stop(); |
980 url_protocol_->Abort(); | 986 url_protocol_->Abort(); |
(...skipping 21 matching lines...) Expand all Loading... | |
1002 } else { | 1008 } else { |
1003 // Don't use GetWeakPtr() here since we are on the wrong thread. | 1009 // Don't use GetWeakPtr() here since we are on the wrong thread. |
1004 task_runner_->PostTask( | 1010 task_runner_->PostTask( |
1005 FROM_HERE, base::Bind(&FFmpegDemuxer::AbortPendingReads, weak_this_)); | 1011 FROM_HERE, base::Bind(&FFmpegDemuxer::AbortPendingReads, weak_this_)); |
1006 } | 1012 } |
1007 } | 1013 } |
1008 | 1014 |
1009 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { | 1015 void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { |
1010 DCHECK(task_runner_->BelongsToCurrentThread()); | 1016 DCHECK(task_runner_->BelongsToCurrentThread()); |
1011 CHECK(pending_seek_cb_.is_null()); | 1017 CHECK(pending_seek_cb_.is_null()); |
1018 DCHECK_EQ(pending_seek_position_, kNoTimestamp); | |
1019 pending_seek_cb_ = cb; | |
1020 pending_seek_position_ = time; | |
1012 | 1021 |
1013 // FFmpeg requires seeks to be adjusted according to the lowest starting time. | 1022 SeekInternal( |
1014 // Since EnqueuePacket() rebased negative timestamps by the start time, we | 1023 time, nullptr, |
1015 // must correct the shift here. | |
1016 // | |
1017 // Additionally, to workaround limitations in how we expose seekable ranges to | |
1018 // Blink (http://crbug.com/137275), we also want to clamp seeks before the | |
1019 // start time to the start time. | |
1020 base::TimeDelta seek_time = start_time_ < base::TimeDelta() | |
1021 ? time + start_time_ | |
1022 : time < start_time_ ? start_time_ : time; | |
1023 | |
1024 // When seeking in an opus stream we need to ensure we deliver enough data to | |
1025 // satisfy the seek preroll; otherwise the audio at the actual seek time will | |
1026 // not be entirely accurate. | |
1027 FFmpegDemuxerStream* audio_stream = | |
1028 GetFirstEnabledFFmpegStream(DemuxerStream::AUDIO); | |
1029 if (audio_stream) { | |
1030 const AudioDecoderConfig& config = audio_stream->audio_decoder_config(); | |
1031 if (config.codec() == kCodecOpus) | |
1032 seek_time = std::max(start_time_, seek_time - config.seek_preroll()); | |
1033 } | |
1034 | |
1035 // Choose the seeking stream based on whether it contains the seek time, if no | |
1036 // match can be found prefer the preferred stream. | |
1037 // | |
1038 // TODO(dalecurtis): Currently FFmpeg does not ensure that all streams in a | |
1039 // given container will demux all packets after the seek point. Instead it | |
1040 // only guarantees that all packets after the file position of the seek will | |
1041 // be demuxed. It's an open question whether FFmpeg should fix this: | |
1042 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html | |
1043 // Tracked by http://crbug.com/387996. | |
1044 FFmpegDemuxerStream* demux_stream = FindPreferredStreamForSeeking(seek_time); | |
1045 DCHECK(demux_stream); | |
1046 const AVStream* seeking_stream = demux_stream->av_stream(); | |
1047 DCHECK(seeking_stream); | |
1048 | |
1049 pending_seek_cb_ = cb; | |
1050 base::PostTaskAndReplyWithResult( | |
1051 blocking_task_runner_.get(), FROM_HERE, | |
1052 base::Bind(&av_seek_frame, glue_->format_context(), seeking_stream->index, | |
1053 ConvertToTimeBase(seeking_stream->time_base, seek_time), | |
1054 // Always seek to a timestamp <= to the desired timestamp. | |
1055 AVSEEK_FLAG_BACKWARD), | |
1056 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr())); | 1024 base::Bind(&FFmpegDemuxer::OnSeekFrameDone, weak_factory_.GetWeakPtr())); |
1057 } | 1025 } |
1058 | 1026 |
1059 base::Time FFmpegDemuxer::GetTimelineOffset() const { | 1027 base::Time FFmpegDemuxer::GetTimelineOffset() const { |
1060 return timeline_offset_; | 1028 return timeline_offset_; |
1061 } | 1029 } |
1062 | 1030 |
1063 std::vector<DemuxerStream*> FFmpegDemuxer::GetAllStreams() { | 1031 std::vector<DemuxerStream*> FFmpegDemuxer::GetAllStreams() { |
1064 DCHECK(task_runner_->BelongsToCurrentThread()); | 1032 DCHECK(task_runner_->BelongsToCurrentThread()); |
1065 std::vector<DemuxerStream*> result; | 1033 std::vector<DemuxerStream*> result; |
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1652 return nullptr; | 1620 return nullptr; |
1653 } | 1621 } |
1654 | 1622 |
1655 void FFmpegDemuxer::OnSeekFrameDone(int result) { | 1623 void FFmpegDemuxer::OnSeekFrameDone(int result) { |
1656 DCHECK(task_runner_->BelongsToCurrentThread()); | 1624 DCHECK(task_runner_->BelongsToCurrentThread()); |
1657 CHECK(!pending_seek_cb_.is_null()); | 1625 CHECK(!pending_seek_cb_.is_null()); |
1658 | 1626 |
1659 if (stopped_) { | 1627 if (stopped_) { |
1660 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; | 1628 MEDIA_LOG(ERROR, media_log_) << GetDisplayName() << ": bad state"; |
1661 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); | 1629 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_ERROR_ABORT); |
1630 pending_seek_position_ = kNoTimestamp; | |
1662 return; | 1631 return; |
1663 } | 1632 } |
1664 | 1633 |
1665 if (result < 0) { | 1634 if (result < 0) { |
1666 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being | 1635 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being |
1667 // captured from stdout and contaminates testing. | 1636 // captured from stdout and contaminates testing. |
1668 // TODO(scherkus): Implement this properly and signal error (BUG=23447). | 1637 // TODO(scherkus): Implement this properly and signal error (BUG=23447). |
1669 VLOG(1) << "Not implemented"; | 1638 VLOG(1) << "Not implemented"; |
1670 } | 1639 } |
1671 | 1640 |
1641 // If we had been restarting the video stream, we can cancel that now, because | |
DaleCurtis
2017/05/25 00:08:06
I think this isn't true since you don't know how f
| |
1642 // we'll just restart reading it automatically from the new position after | |
1643 // this new seek request is completed. | |
1644 if (restarting_stream_) { | |
1645 DVLOG(2) << "Cancelled stream restart due to intervening seek"; | |
1646 restarting_stream_ = nullptr; | |
1647 } | |
1648 last_audio_packet_pos_ = -1; | |
1649 | |
1672 // Tell streams to flush buffers due to seeking. | 1650 // Tell streams to flush buffers due to seeking. |
1673 for (const auto& stream : streams_) { | 1651 for (const auto& stream : streams_) { |
1674 if (stream) | 1652 if (stream) |
1675 stream->FlushBuffers(); | 1653 stream->FlushBuffers(); |
1676 } | 1654 } |
1677 | 1655 |
1678 // Resume reading until capacity. | 1656 // Resume reading until capacity. |
1679 ReadFrameIfNeeded(); | 1657 ReadFrameIfNeeded(); |
1680 | 1658 |
1681 // Notify we're finished seeking. | 1659 // Notify we're finished seeking. |
1682 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); | 1660 base::ResetAndReturn(&pending_seek_cb_).Run(PIPELINE_OK); |
1661 pending_seek_position_ = kNoTimestamp; | |
1683 } | 1662 } |
1684 | 1663 |
1685 void FFmpegDemuxer::OnEnabledAudioTracksChanged( | 1664 void FFmpegDemuxer::OnEnabledAudioTracksChanged( |
1686 const std::vector<MediaTrack::Id>& track_ids, | 1665 const std::vector<MediaTrack::Id>& track_ids, |
1687 base::TimeDelta curr_time) { | 1666 base::TimeDelta curr_time) { |
1688 DCHECK(task_runner_->BelongsToCurrentThread()); | 1667 DCHECK(task_runner_->BelongsToCurrentThread()); |
1689 | 1668 |
1690 std::set<FFmpegDemuxerStream*> enabled_streams; | 1669 std::set<FFmpegDemuxerStream*> enabled_streams; |
1691 for (const auto& id : track_ids) { | 1670 for (const auto& id : track_ids) { |
1692 FFmpegDemuxerStream* stream = track_id_to_demux_stream_map_[id]; | 1671 FFmpegDemuxerStream* stream = track_id_to_demux_stream_map_[id]; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1735 for (const auto& stream : streams_) { | 1714 for (const auto& stream : streams_) { |
1736 if (stream && stream->type() == DemuxerStream::VIDEO && | 1715 if (stream && stream->type() == DemuxerStream::VIDEO && |
1737 stream.get() != selected_stream) { | 1716 stream.get() != selected_stream) { |
1738 DVLOG(1) << __func__ << ": disabling stream " << stream.get(); | 1717 DVLOG(1) << __func__ << ": disabling stream " << stream.get(); |
1739 stream->SetEnabled(false, curr_time); | 1718 stream->SetEnabled(false, curr_time); |
1740 } | 1719 } |
1741 } | 1720 } |
1742 if (selected_stream) { | 1721 if (selected_stream) { |
1743 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; | 1722 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; |
1744 selected_stream->SetEnabled(true, curr_time); | 1723 selected_stream->SetEnabled(true, curr_time); |
1724 // Now that the video stream is re-enabled we'll want video renderer to | |
1725 // restart playback from the |curr_time| position. For that we'll need to | |
1726 // seek back to the last key frame preceeding |curr_time| in the | |
1727 // |selected_stream|. | |
1728 if (!pending_seek_cb_) { | |
1729 selected_stream->FlushBuffers(); | |
1730 SeekInternal(curr_time, selected_stream, | |
1731 base::Bind(&FFmpegDemuxer::OnSeekDoneForRestartingStream, | |
1732 weak_factory_.GetWeakPtr(), selected_stream)); | |
1733 } else { | |
DaleCurtis
2017/05/24 22:24:18
Lets avoid this whole issue by just not allowing t
servolk
2017/05/24 22:58:19
Sure, if we didn't allow track changes during pend
DaleCurtis
2017/05/24 23:15:46
We're not talking about prohibiting them, we're ta
| |
1734 // If there's already pending seek, we'll need to restart it after its | |
1735 // completion and after SetAVStreamDiscard initiated by SetEnabled takes | |
1736 // effect, in order to ensure we get a key frame for |selected_stream|. | |
1737 auto old_pending_seek_cb = pending_seek_cb_; | |
1738 DCHECK_NE(pending_seek_position_, kNoTimestamp); | |
1739 DVLOG(2) << __func__ << ": Pending seek to " << pending_seek_position_ | |
1740 << " detected, postponing stream restart until seek completes."; | |
1741 pending_seek_cb_ = base::Bind( | |
1742 &FFmpegDemuxer::RestartPendingSeek, weak_factory_.GetWeakPtr(), | |
1743 pending_seek_position_, old_pending_seek_cb); | |
1744 } | |
1745 } | 1745 } |
1746 } | 1746 } |
1747 | 1747 |
1748 void FFmpegDemuxer::OnSeekDoneForRestartingStream(FFmpegDemuxerStream* stream, | |
1749 int result) { | |
1750 DCHECK(task_runner_->BelongsToCurrentThread()); | |
1751 if (result < 0) { | |
1752 MEDIA_LOG(ERROR, media_log_) | |
1753 << __func__ << ": seek failed: " << AVErrorToString(result); | |
1754 return; | |
1755 } | |
1756 DVLOG(2) << __func__ << ": will drop packets until last_audio_packet_pos_=" | |
1757 << last_audio_packet_pos_; | |
1758 if (restarting_stream_) | |
DaleCurtis
2017/05/25 00:08:06
This will need an early exit if a seek() comes in
| |
1759 restarting_stream_->FlushBuffers(); | |
1760 restarting_stream_ = stream; | |
1761 } | |
1762 | |
1748 void FFmpegDemuxer::ReadFrameIfNeeded() { | 1763 void FFmpegDemuxer::ReadFrameIfNeeded() { |
1749 DCHECK(task_runner_->BelongsToCurrentThread()); | 1764 DCHECK(task_runner_->BelongsToCurrentThread()); |
1750 | 1765 |
1751 // Make sure we have work to do before reading. | 1766 // Make sure we have work to do before reading. |
1752 if (stopped_ || !StreamsHaveAvailableCapacity() || pending_read_ || | 1767 if (stopped_ || !StreamsHaveAvailableCapacity() || pending_read_ || |
1753 !pending_seek_cb_.is_null()) { | 1768 !pending_seek_cb_.is_null()) { |
1754 return; | 1769 return; |
1755 } | 1770 } |
1756 | 1771 |
1757 // Allocate and read an AVPacket from the media. Save |packet_ptr| since | 1772 // Allocate and read an AVPacket from the media. Save |packet_ptr| since |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1822 // | 1837 // |
1823 // https://code.google.com/p/chromium/issues/detail?id=169133#c10 | 1838 // https://code.google.com/p/chromium/issues/detail?id=169133#c10 |
1824 if (!packet->data) { | 1839 if (!packet->data) { |
1825 ScopedAVPacket new_packet(new AVPacket()); | 1840 ScopedAVPacket new_packet(new AVPacket()); |
1826 av_new_packet(new_packet.get(), 0); | 1841 av_new_packet(new_packet.get(), 0); |
1827 av_packet_copy_props(new_packet.get(), packet.get()); | 1842 av_packet_copy_props(new_packet.get(), packet.get()); |
1828 packet.swap(new_packet); | 1843 packet.swap(new_packet); |
1829 } | 1844 } |
1830 | 1845 |
1831 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index].get(); | 1846 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index].get(); |
1832 if (demuxer_stream->IsEnabled()) | 1847 |
1848 DVLOG(5) << "Got AVPacket: stream_index=" << packet->stream_index | |
1849 << " type=" << demuxer_stream->type() << " pos=" << packet->pos | |
1850 << " pts=" << packet->pts; | |
1851 | |
1852 // If |restarting_stream_| is not null, we are in stream restart mode, which | |
1853 // means we seeked back the ffmpeg reading position and now we need to drop | |
1854 // packets from other streams until we reach the previously seen read | |
1855 // position |last_audio_packet_pos_|. | |
1856 bool drop_seen_packet = | |
1857 restarting_stream_ && demuxer_stream != restarting_stream_ && | |
1858 last_audio_packet_pos_ >= 0 && packet->pos <= last_audio_packet_pos_; | |
1859 if (drop_seen_packet) { | |
1860 DVLOG(4) << "Dropping already seen packet packet: pos=" << packet->pos; | |
1861 } else if (restarting_stream_ && demuxer_stream != restarting_stream_) { | |
1862 DVLOG(2) << "Restarting reading packets: pos=" << packet->pos; | |
1863 restarting_stream_ = nullptr; | |
1864 } | |
1865 | |
1866 if (!restarting_stream_ && demuxer_stream->type() == DemuxerStream::AUDIO) | |
DaleCurtis
2017/05/24 22:24:18
Isn't this going to be incorrect for streams with
| |
1867 last_audio_packet_pos_ = packet->pos; | |
1868 | |
1869 if (demuxer_stream->IsEnabled() && !drop_seen_packet) | |
1833 demuxer_stream->EnqueuePacket(std::move(packet)); | 1870 demuxer_stream->EnqueuePacket(std::move(packet)); |
1834 | 1871 |
1835 // If duration estimate was incorrect, update it and tell higher layers. | 1872 // If duration estimate was incorrect, update it and tell higher layers. |
1836 if (duration_known_) { | 1873 if (duration_known_) { |
1837 const base::TimeDelta duration = demuxer_stream->duration(); | 1874 const base::TimeDelta duration = demuxer_stream->duration(); |
1838 if (duration != kNoTimestamp && duration > duration_) { | 1875 if (duration != kNoTimestamp && duration > duration_) { |
1839 duration_ = duration; | 1876 duration_ = duration; |
1840 host_->SetDuration(duration_); | 1877 host_->SetDuration(duration_); |
1841 } | 1878 } |
1842 } | 1879 } |
1843 } | 1880 } |
1844 | 1881 |
1845 // Keep reading until we've reached capacity. | 1882 // Keep reading until we've reached capacity. |
1846 ReadFrameIfNeeded(); | 1883 ReadFrameIfNeeded(); |
1847 } | 1884 } |
1848 | 1885 |
1849 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() { | 1886 bool FFmpegDemuxer::StreamsHaveAvailableCapacity() { |
1850 DCHECK(task_runner_->BelongsToCurrentThread()); | 1887 DCHECK(task_runner_->BelongsToCurrentThread()); |
1851 for (const auto& stream : streams_) { | 1888 for (const auto& stream : streams_) { |
1852 if (stream && stream->HasAvailableCapacity()) | 1889 if (stream && stream->IsEnabled() && stream->HasAvailableCapacity()) |
1853 return true; | 1890 return true; |
1854 } | 1891 } |
1855 return false; | 1892 return false; |
1856 } | 1893 } |
1857 | 1894 |
1858 bool FFmpegDemuxer::IsMaxMemoryUsageReached() const { | 1895 bool FFmpegDemuxer::IsMaxMemoryUsageReached() const { |
1859 DCHECK(task_runner_->BelongsToCurrentThread()); | 1896 DCHECK(task_runner_->BelongsToCurrentThread()); |
1860 | 1897 |
1861 // Max allowed memory usage, all streams combined. | 1898 // Max allowed memory usage, all streams combined. |
1862 const size_t kDemuxerMemoryLimit = 150 * 1024 * 1024; | 1899 const size_t kDemuxerMemoryLimit = 150 * 1024 * 1024; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1894 } | 1931 } |
1895 | 1932 |
1896 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1933 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
1897 DCHECK(task_runner_->BelongsToCurrentThread()); | 1934 DCHECK(task_runner_->BelongsToCurrentThread()); |
1898 for (const auto& stream : streams_) { | 1935 for (const auto& stream : streams_) { |
1899 if (stream) | 1936 if (stream) |
1900 stream->SetLiveness(liveness); | 1937 stream->SetLiveness(liveness); |
1901 } | 1938 } |
1902 } | 1939 } |
1903 | 1940 |
1941 void FFmpegDemuxer::SeekInternal(base::TimeDelta time, | |
1942 FFmpegDemuxerStream* preferred_stream, | |
1943 const FFmpegSeekDoneCB& ffmpeg_seek_done_cb) { | |
1944 DCHECK(task_runner_->BelongsToCurrentThread()); | |
1945 DVLOG(2) << __func__ << " time=" << time << " stream=" << preferred_stream; | |
1946 | |
1947 // FFmpeg requires seeks to be adjusted according to the lowest starting time. | |
1948 // Since EnqueuePacket() rebased negative timestamps by the start time, we | |
1949 // must correct the shift here. | |
1950 // | |
1951 // Additionally, to workaround limitations in how we expose seekable ranges to | |
1952 // Blink (http://crbug.com/137275), we also want to clamp seeks before the | |
1953 // start time to the start time. | |
1954 base::TimeDelta seek_time = start_time_ < base::TimeDelta() | |
1955 ? time + start_time_ | |
1956 : time < start_time_ ? start_time_ : time; | |
1957 | |
1958 // When seeking in an opus stream we need to ensure we deliver enough data to | |
1959 // satisfy the seek preroll; otherwise the audio at the actual seek time will | |
1960 // not be entirely accurate. | |
1961 FFmpegDemuxerStream* audio_stream = | |
1962 GetFirstEnabledFFmpegStream(DemuxerStream::AUDIO); | |
1963 if (audio_stream) { | |
1964 const AudioDecoderConfig& config = audio_stream->audio_decoder_config(); | |
1965 if (config.codec() == kCodecOpus) | |
1966 seek_time = std::max(start_time_, seek_time - config.seek_preroll()); | |
1967 } | |
1968 | |
1969 if (!preferred_stream) { | |
1970 // Choose the seeking stream based on whether it contains the seek time, if | |
1971 // no match can be found prefer the preferred stream. | |
1972 // | |
1973 // TODO(dalecurtis): Currently FFmpeg does not ensure that all streams in a | |
DaleCurtis
2017/05/24 22:24:18
Note we may run into this issue now more frequentl
servolk
2017/05/24 22:58:19
We might, especially considering that this is goin
DaleCurtis
2017/05/25 00:08:06
I don't think that API fixes the issue. I experime
| |
1974 // given container will demux all packets after the seek point. Instead it | |
1975 // only guarantees that all packets after the file position of the seek will | |
1976 // be demuxed. It's an open question whether FFmpeg should fix this: | |
1977 // http://lists.ffmpeg.org/pipermail/ffmpeg-devel/2014-June/159212.html | |
1978 // Tracked by http://crbug.com/387996. | |
1979 preferred_stream = FindPreferredStreamForSeeking(seek_time); | |
1980 DCHECK(preferred_stream); | |
1981 } | |
1982 const AVStream* ffmpeg_stream = preferred_stream->av_stream(); | |
1983 DCHECK(ffmpeg_stream); | |
1984 | |
1985 base::PostTaskAndReplyWithResult( | |
1986 blocking_task_runner_.get(), FROM_HERE, | |
1987 base::Bind(&av_seek_frame, glue_->format_context(), ffmpeg_stream->index, | |
1988 ConvertToTimeBase(ffmpeg_stream->time_base, seek_time), | |
1989 // Always seek to a timestamp <= to the desired timestamp. | |
1990 AVSEEK_FLAG_BACKWARD), | |
1991 ffmpeg_seek_done_cb); | |
1992 } | |
1993 | |
1994 void FFmpegDemuxer::RestartPendingSeek(base::TimeDelta time, | |
1995 const PipelineStatusCB& cb, | |
1996 PipelineStatus prev_seek_status) { | |
1997 DCHECK(task_runner_->BelongsToCurrentThread()); | |
1998 DCHECK_NE(pending_seek_position_, kNoTimestamp); | |
1999 DCHECK(cb); | |
2000 // We are going to ignore prev_seek_status here, because we are about to | |
2001 // repeat the seek anyway. The previous seek outcome doesn't matter now. | |
2002 DVLOG(2) << __func__ << ": Previous seek completed, re-seeking to " | |
2003 << pending_seek_position_ << " to complete video stream restart."; | |
2004 base::ResetAndReturn(&pending_seek_cb_); | |
2005 pending_seek_position_ = kNoTimestamp; | |
2006 Seek(time, cb); | |
2007 } | |
2008 | |
1904 } // namespace media | 2009 } // namespace media |
OLD | NEW |