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 <stddef.h> | 5 #include <stddef.h> |
6 #include <stdint.h> | 6 #include <stdint.h> |
7 | 7 |
8 #include <algorithm> | 8 #include <algorithm> |
9 #include <deque> | 9 #include <deque> |
10 #include <string> | 10 #include <string> |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 media_tracks_ = std::move(tracks); | 271 media_tracks_ = std::move(tracks); |
272 } | 272 } |
273 | 273 |
274 // Accessor to demuxer internals. | 274 // Accessor to demuxer internals. |
275 void SetDurationKnown(bool duration_known) { | 275 void SetDurationKnown(bool duration_known) { |
276 demuxer_->duration_known_ = duration_known; | 276 demuxer_->duration_known_ = duration_known; |
277 if (!duration_known) | 277 if (!duration_known) |
278 demuxer_->duration_ = kInfiniteDuration; | 278 demuxer_->duration_ = kInfiniteDuration; |
279 } | 279 } |
280 | 280 |
| 281 void SetStreamCapacity(FFmpegDemuxerStream* s, base::TimeDelta capacity) { |
| 282 s->stream_capacity_ = capacity; |
| 283 } |
| 284 |
281 // Fixture members. | 285 // Fixture members. |
282 | 286 |
283 base::test::ScopedTaskScheduler task_scheduler_; | 287 base::test::ScopedTaskScheduler task_scheduler_; |
284 MediaLog media_log_; | 288 MediaLog media_log_; |
285 std::unique_ptr<FileDataSource> data_source_; | 289 std::unique_ptr<FileDataSource> data_source_; |
286 std::unique_ptr<FFmpegDemuxer> demuxer_; | 290 std::unique_ptr<FFmpegDemuxer> demuxer_; |
287 StrictMock<MockDemuxerHost> host_; | 291 StrictMock<MockDemuxerHost> host_; |
288 std::unique_ptr<MediaTracks> media_tracks_; | 292 std::unique_ptr<MediaTracks> media_tracks_; |
289 | 293 |
290 AVFormatContext* format_context() { | 294 AVFormatContext* format_context() { |
(...skipping 1362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1653 // there is no buffers ready to be returned by the Read right away, thus | 1657 // there is no buffers ready to be returned by the Read right away, thus |
1654 // ensuring that status changes occur while an async read is pending. | 1658 // ensuring that status changes occur while an async read is pending. |
1655 audio_stream->FlushBuffers(); | 1659 audio_stream->FlushBuffers(); |
1656 audio_stream->Read(base::Bind(&media::OnReadDone_ExpectEos)); | 1660 audio_stream->Read(base::Bind(&media::OnReadDone_ExpectEos)); |
1657 CheckStreamStatusNotifications(demuxer_.get(), audio_stream); | 1661 CheckStreamStatusNotifications(demuxer_.get(), audio_stream); |
1658 video_stream->FlushBuffers(); | 1662 video_stream->FlushBuffers(); |
1659 video_stream->Read(base::Bind(&media::OnReadDone_ExpectEos)); | 1663 video_stream->Read(base::Bind(&media::OnReadDone_ExpectEos)); |
1660 CheckStreamStatusNotifications(demuxer_.get(), video_stream); | 1664 CheckStreamStatusNotifications(demuxer_.get(), video_stream); |
1661 } | 1665 } |
1662 | 1666 |
| 1667 // This test verifies that when a video stream is restarted, we do an internal |
| 1668 // seek in the ffmpeg demuxer (because we need to read video frames starting |
| 1669 // with the previous video key frame before the current playback position, so |
| 1670 // that the video renderer is able to resume playback from the current media |
| 1671 // time), but then we'd drop all audio packets up to the last_audio_packet_pos_, |
| 1672 // because those have already been processed and are sitting in the audio stream |
| 1673 // buffer queue, we don't want to duplicate those. |
| 1674 TEST_F(FFmpegDemuxerTest, SeekAndDropSeenAudioPacketsAfterVideoRestart) { |
| 1675 CreateDemuxer("bear-320x240.webm"); |
| 1676 InitializeDemuxer(); |
| 1677 FFmpegDemuxerStream* audio = |
| 1678 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::AUDIO)); |
| 1679 FFmpegDemuxerStream* video = |
| 1680 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::VIDEO)); |
| 1681 EXPECT_NE(nullptr, audio); |
| 1682 EXPECT_NE(nullptr, video); |
| 1683 |
| 1684 // The audio stream in the test file has audio frames with timestamps about 3 |
| 1685 // milliseconds apart (0, 3, 6, 9, 12, 15, 17, 20, 23etc). So setting stream |
| 1686 // capacity to 5 millisec allows the demuxer to buffer 3 frames. We'll read |
| 1687 // two of them immediately, so the demuxer will have read 5 frames from FFmpeg |
| 1688 // by the time the video track is re-enabled. |
| 1689 SetStreamCapacity(audio, base::TimeDelta::FromMilliseconds(5)); |
| 1690 |
| 1691 // Disable the video stream and read a few frames from the audio stream. |
| 1692 demuxer_->OnSelectedVideoTrackChanged(base::nullopt, base::TimeDelta()); |
| 1693 |
| 1694 audio->Read(NewReadCB(FROM_HERE, 29, 0, true, DemuxerStream::kOk)); |
| 1695 base::RunLoop().Run(); |
| 1696 audio->Read(NewReadCB(FROM_HERE, 27, 3000, true, DemuxerStream::kOk)); |
| 1697 base::RunLoop().Run(); |
| 1698 |
| 1699 // At this point the demuxer have read frames with timestamps 0-15 millisec. |
| 1700 // Now re-enable the video stream, which will cause an FFmpeg read position to |
| 1701 // be seeked back to 0 (since the previous video key frame is at 0). |
| 1702 demuxer_->OnSelectedVideoTrackChanged(MediaTrack::Id("1"), base::TimeDelta()); |
| 1703 |
| 1704 // Now verify that frames read from the audio stream are continuous, as |
| 1705 // expected. There should be no duplicates or missing frames. |
| 1706 |
| 1707 // The first three frames were read and buffered before the video track was |
| 1708 // re-enabled. |
| 1709 audio->Read(NewReadCB(FROM_HERE, 31, 6000, true, DemuxerStream::kOk)); |
| 1710 base::RunLoop().Run(); |
| 1711 audio->Read(NewReadCB(FROM_HERE, 30, 9000, true, DemuxerStream::kOk)); |
| 1712 base::RunLoop().Run(); |
| 1713 audio->Read(NewReadCB(FROM_HERE, 32, 12000, true, DemuxerStream::kOk)); |
| 1714 base::RunLoop().Run(); |
| 1715 |
| 1716 // And the following three frames were read when we freed up capacity by |
| 1717 // reading the previous 3 frames above (i.e. after the video track was |
| 1718 // restarted). These should continue the audio stream reading sequence. |
| 1719 audio->Read(NewReadCB(FROM_HERE, 29, 15000, true, DemuxerStream::kOk)); |
| 1720 base::RunLoop().Run(); |
| 1721 audio->Read(NewReadCB(FROM_HERE, 31, 17000, true, DemuxerStream::kOk)); |
| 1722 base::RunLoop().Run(); |
| 1723 audio->Read(NewReadCB(FROM_HERE, 36, 20000, true, DemuxerStream::kOk)); |
| 1724 base::RunLoop().Run(); |
| 1725 } |
| 1726 |
| 1727 TEST_F(FFmpegDemuxerTest, SeekDuringVideoStreamRestart) { |
| 1728 CreateDemuxer("bear-320x240.webm"); |
| 1729 InitializeDemuxer(); |
| 1730 FFmpegDemuxerStream* video = |
| 1731 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::VIDEO)); |
| 1732 EXPECT_NE(nullptr, video); |
| 1733 |
| 1734 // Disable and then re-enable the video stream, this will initiate an |
| 1735 // internal seek for the video stream. |
| 1736 demuxer_->OnSelectedVideoTrackChanged(base::nullopt, base::TimeDelta()); |
| 1737 demuxer_->OnSelectedVideoTrackChanged(MediaTrack::Id("1"), base::TimeDelta()); |
| 1738 |
| 1739 // Now immediately request a seek to a different position. This should cancel |
| 1740 // the previous seek and kick off a new seek. |
| 1741 Seek(base::TimeDelta::FromMilliseconds(500)); |
| 1742 |
| 1743 // Verify that the next read returns the video buffer from the expected |
| 1744 // position, matching the latest seek. |
| 1745 video->Read(NewReadCB(FROM_HERE, 5636, 400000, true, DemuxerStream::kOk)); |
| 1746 base::RunLoop().Run(); |
| 1747 } |
| 1748 |
| 1749 TEST_F(FFmpegDemuxerTest, VideoStreamRestartDuringSeek) { |
| 1750 CreateDemuxer("bear-320x240.webm"); |
| 1751 InitializeDemuxer(); |
| 1752 FFmpegDemuxerStream* video = |
| 1753 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::VIDEO)); |
| 1754 EXPECT_NE(nullptr, video); |
| 1755 |
| 1756 demuxer_->OnSelectedVideoTrackChanged(base::nullopt, base::TimeDelta()); |
| 1757 |
| 1758 // Initiate a seek and re-enable the video track without waiting for the seek |
| 1759 // to be completed. |
| 1760 base::TimeDelta seek_target = base::TimeDelta::FromMilliseconds(500); |
| 1761 WaitableMessageLoopEvent seek_event; |
| 1762 demuxer_->Seek(seek_target, seek_event.GetPipelineStatusCB()); |
| 1763 |
| 1764 demuxer_->OnSelectedVideoTrackChanged(MediaTrack::Id("1"), base::TimeDelta()); |
| 1765 |
| 1766 // Wait for the seek to finish. |
| 1767 seek_event.RunAndWaitForStatus(PIPELINE_OK); |
| 1768 |
| 1769 // Verify that the next read returns the video buffer from the expected |
| 1770 // position, matching the latest seek. |
| 1771 video->Read(NewReadCB(FROM_HERE, 5636, 400000, true, DemuxerStream::kOk)); |
| 1772 base::RunLoop().Run(); |
| 1773 } |
| 1774 |
1663 } // namespace media | 1775 } // namespace media |
OLD | NEW |