Chromium Code Reviews| 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 |