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 849 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
860 stopped_(false), | 860 stopped_(false), |
861 pending_read_(false), | 861 pending_read_(false), |
862 data_source_(data_source), | 862 data_source_(data_source), |
863 media_log_(media_log), | 863 media_log_(media_log), |
864 bitrate_(0), | 864 bitrate_(0), |
865 start_time_(kNoTimestamp), | 865 start_time_(kNoTimestamp), |
866 text_enabled_(false), | 866 text_enabled_(false), |
867 duration_known_(false), | 867 duration_known_(false), |
868 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), | 868 encrypted_media_init_data_cb_(encrypted_media_init_data_cb), |
869 media_tracks_updated_cb_(media_tracks_updated_cb), | 869 media_tracks_updated_cb_(media_tracks_updated_cb), |
870 last_packet_pos_(-1), | |
871 restarting_stream_(nullptr), | |
870 cancel_pending_seek_factory_(this), | 872 cancel_pending_seek_factory_(this), |
871 weak_factory_(this) { | 873 weak_factory_(this) { |
872 DCHECK(task_runner_.get()); | 874 DCHECK(task_runner_.get()); |
873 DCHECK(data_source_); | 875 DCHECK(data_source_); |
874 DCHECK(!media_tracks_updated_cb_.is_null()); | 876 DCHECK(!media_tracks_updated_cb_.is_null()); |
875 } | 877 } |
876 | 878 |
877 FFmpegDemuxer::~FFmpegDemuxer() { | 879 FFmpegDemuxer::~FFmpegDemuxer() { |
878 // NOTE: This class is not destroyed on |task_runner|, so we must ensure that | 880 // NOTE: This class is not destroyed on |task_runner|, so we must ensure that |
879 // there are no outstanding WeakPtrs by the time we reach here. | 881 // there are no outstanding WeakPtrs by the time we reach here. |
(...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1648 return; | 1650 return; |
1649 } | 1651 } |
1650 | 1652 |
1651 if (result < 0) { | 1653 if (result < 0) { |
1652 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being | 1654 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being |
1653 // captured from stdout and contaminates testing. | 1655 // captured from stdout and contaminates testing. |
1654 // TODO(scherkus): Implement this properly and signal error (BUG=23447). | 1656 // TODO(scherkus): Implement this properly and signal error (BUG=23447). |
1655 VLOG(1) << "Not implemented"; | 1657 VLOG(1) << "Not implemented"; |
1656 } | 1658 } |
1657 | 1659 |
1660 last_packet_pos_ = -1; | |
1661 | |
1658 // Tell streams to flush buffers due to seeking. | 1662 // Tell streams to flush buffers due to seeking. |
1659 for (const auto& stream : streams_) { | 1663 for (const auto& stream : streams_) { |
1660 if (stream) | 1664 if (stream) |
1661 stream->FlushBuffers(); | 1665 stream->FlushBuffers(); |
1662 } | 1666 } |
1663 | 1667 |
1664 // Resume reading until capacity. | 1668 // Resume reading until capacity. |
1665 ReadFrameIfNeeded(); | 1669 ReadFrameIfNeeded(); |
1666 | 1670 |
1667 // Notify we're finished seeking. | 1671 // Notify we're finished seeking. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1721 for (const auto& stream : streams_) { | 1725 for (const auto& stream : streams_) { |
1722 if (stream && stream->type() == DemuxerStream::VIDEO && | 1726 if (stream && stream->type() == DemuxerStream::VIDEO && |
1723 stream.get() != selected_stream) { | 1727 stream.get() != selected_stream) { |
1724 DVLOG(1) << __func__ << ": disabling stream " << stream.get(); | 1728 DVLOG(1) << __func__ << ": disabling stream " << stream.get(); |
1725 stream->SetEnabled(false, curr_time); | 1729 stream->SetEnabled(false, curr_time); |
1726 } | 1730 } |
1727 } | 1731 } |
1728 if (selected_stream) { | 1732 if (selected_stream) { |
1729 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; | 1733 DVLOG(1) << __func__ << ": enabling stream " << selected_stream; |
1730 selected_stream->SetEnabled(true, curr_time); | 1734 selected_stream->SetEnabled(true, curr_time); |
1735 selected_stream->FlushBuffers(); | |
1736 | |
1737 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
| |
1738 start_time_ < base::TimeDelta() | |
1739 ? curr_time + start_time_ | |
1740 : curr_time < start_time_ ? start_time_ : curr_time; | |
1741 | |
1742 base::PostTaskAndReplyWithResult( | |
1743 blocking_task_runner_.get(), FROM_HERE, | |
1744 base::Bind(&av_seek_frame, glue_->format_context(), | |
1745 selected_stream->av_stream()->index, | |
1746 ConvertToTimeBase(selected_stream->av_stream()->time_base, | |
1747 seek_time), | |
1748 // Always seek to a timestamp <= to the desired timestamp. | |
1749 AVSEEK_FLAG_BACKWARD), | |
1750 base::Bind(&FFmpegDemuxer::OnSeekDoneForRestartingStream, | |
1751 weak_factory_.GetWeakPtr(), selected_stream)); | |
1731 } | 1752 } |
1732 } | 1753 } |
1733 | 1754 |
1755 void FFmpegDemuxer::OnSeekDoneForRestartingStream(FFmpegDemuxerStream* stream, | |
1756 int result) { | |
1757 DCHECK(task_runner_->BelongsToCurrentThread()); | |
1758 if (result < 0) { | |
1759 DVLOG(1) << __func__ << ": seek failed: " << AVErrorToString(result); | |
1760 return; | |
1761 } | |
1762 DVLOG(2) << __func__ | |
1763 << ": will drop packets until last_packet_pos_=" << last_packet_pos_; | |
1764 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
| |
1765 } | |
1766 | |
1734 void FFmpegDemuxer::ReadFrameIfNeeded() { | 1767 void FFmpegDemuxer::ReadFrameIfNeeded() { |
1735 DCHECK(task_runner_->BelongsToCurrentThread()); | 1768 DCHECK(task_runner_->BelongsToCurrentThread()); |
1736 | 1769 |
1737 // Make sure we have work to do before reading. | 1770 // Make sure we have work to do before reading. |
1738 if (stopped_ || !StreamsHaveAvailableCapacity() || pending_read_ || | 1771 if (stopped_ || !StreamsHaveAvailableCapacity() || pending_read_ || |
1739 !pending_seek_cb_.is_null()) { | 1772 !pending_seek_cb_.is_null()) { |
1740 return; | 1773 return; |
1741 } | 1774 } |
1742 | 1775 |
1743 // Allocate and read an AVPacket from the media. Save |packet_ptr| since | 1776 // 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... | |
1808 // | 1841 // |
1809 // https://code.google.com/p/chromium/issues/detail?id=169133#c10 | 1842 // https://code.google.com/p/chromium/issues/detail?id=169133#c10 |
1810 if (!packet->data) { | 1843 if (!packet->data) { |
1811 ScopedAVPacket new_packet(new AVPacket()); | 1844 ScopedAVPacket new_packet(new AVPacket()); |
1812 av_new_packet(new_packet.get(), 0); | 1845 av_new_packet(new_packet.get(), 0); |
1813 av_packet_copy_props(new_packet.get(), packet.get()); | 1846 av_packet_copy_props(new_packet.get(), packet.get()); |
1814 packet.swap(new_packet); | 1847 packet.swap(new_packet); |
1815 } | 1848 } |
1816 | 1849 |
1817 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index].get(); | 1850 FFmpegDemuxerStream* demuxer_stream = streams_[packet->stream_index].get(); |
1818 if (demuxer_stream->IsEnabled()) | 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_packet_pos_|. | |
1856 bool drop_seen_packet = | |
DaleCurtis
2017/05/04 18:53:03
Drop unnecessary parens.
servolk
2017/05/04 19:15:16
Done.
| |
1857 (restarting_stream_ && demuxer_stream != restarting_stream_ && | |
1858 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
| |
1859 if (drop_seen_packet) { | |
1860 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.
| |
1861 } else if (restarting_stream_ && demuxer_stream != restarting_stream_) { | |
1862 DVLOG(2) << "Restarting reading packets: pos=" << packet.get()->pos; | |
1863 restarting_stream_ = nullptr; | |
1864 } | |
1865 | |
1866 if (!restarting_stream_) | |
1867 last_packet_pos_ = packet.get()->pos; | |
1868 | |
1869 if (demuxer_stream->IsEnabled() && !drop_seen_packet) | |
1819 demuxer_stream->EnqueuePacket(std::move(packet)); | 1870 demuxer_stream->EnqueuePacket(std::move(packet)); |
1820 | 1871 |
1821 // If duration estimate was incorrect, update it and tell higher layers. | 1872 // If duration estimate was incorrect, update it and tell higher layers. |
1822 if (duration_known_) { | 1873 if (duration_known_) { |
1823 const base::TimeDelta duration = demuxer_stream->duration(); | 1874 const base::TimeDelta duration = demuxer_stream->duration(); |
1824 if (duration != kNoTimestamp && duration > duration_) { | 1875 if (duration != kNoTimestamp && duration > duration_) { |
1825 duration_ = duration; | 1876 duration_ = duration; |
1826 host_->SetDuration(duration_); | 1877 host_->SetDuration(duration_); |
1827 } | 1878 } |
1828 } | 1879 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1881 | 1932 |
1882 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1933 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
1883 DCHECK(task_runner_->BelongsToCurrentThread()); | 1934 DCHECK(task_runner_->BelongsToCurrentThread()); |
1884 for (const auto& stream : streams_) { | 1935 for (const auto& stream : streams_) { |
1885 if (stream) | 1936 if (stream) |
1886 stream->SetLiveness(liveness); | 1937 stream->SetLiveness(liveness); |
1887 } | 1938 } |
1888 } | 1939 } |
1889 | 1940 |
1890 } // namespace media | 1941 } // namespace media |
OLD | NEW |