OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <deque> | 5 #include <deque> |
6 | 6 |
7 #include "base/file_path.h" | |
8 #include "base/path_service.h" | |
9 #include "base/threading/thread.h" | 7 #include "base/threading/thread.h" |
10 #include "media/base/filters.h" | 8 #include "media/base/filters.h" |
11 #include "media/base/mock_callback.h" | 9 #include "media/base/mock_callback.h" |
| 10 #include "media/base/mock_ffmpeg.h" |
12 #include "media/base/mock_filter_host.h" | 11 #include "media/base/mock_filter_host.h" |
13 #include "media/base/mock_filters.h" | 12 #include "media/base/mock_filters.h" |
14 #include "media/base/mock_reader.h" | 13 #include "media/base/mock_reader.h" |
15 #include "media/ffmpeg/ffmpeg_common.h" | 14 #include "media/ffmpeg/ffmpeg_common.h" |
16 #include "media/filters/ffmpeg_demuxer.h" | 15 #include "media/filters/ffmpeg_demuxer.h" |
17 #include "media/filters/file_data_source.h" | |
18 #include "testing/gtest/include/gtest/gtest.h" | 16 #include "testing/gtest/include/gtest/gtest.h" |
19 | 17 |
20 using ::testing::AnyNumber; | 18 using ::testing::AnyNumber; |
21 using ::testing::DoAll; | 19 using ::testing::DoAll; |
22 using ::testing::InSequence; | 20 using ::testing::InSequence; |
23 using ::testing::Invoke; | 21 using ::testing::Invoke; |
24 using ::testing::NotNull; | 22 using ::testing::NotNull; |
25 using ::testing::Return; | 23 using ::testing::Return; |
26 using ::testing::SaveArg; | 24 using ::testing::SetArgumentPointee; |
27 using ::testing::SetArgPointee; | |
28 using ::testing::StrictMock; | 25 using ::testing::StrictMock; |
29 using ::testing::WithArgs; | 26 using ::testing::WithArgs; |
30 using ::testing::_; | 27 using ::testing::_; |
31 | 28 |
32 namespace media { | 29 namespace media { |
33 | 30 |
34 // Fixture class to facilitate writing tests. Takes care of setting up the | 31 // Fixture class to facilitate writing tests. Takes care of setting up the |
35 // FFmpeg, pipeline and filter host mocks. | 32 // FFmpeg, pipeline and filter host mocks. |
36 class FFmpegDemuxerTest : public testing::Test { | 33 class FFmpegDemuxerTest : public testing::Test { |
37 protected: | 34 protected: |
| 35 // These constants refer to the stream ordering inside AVFormatContext. We |
| 36 // simulate media with a data stream, audio stream and video stream. Having |
| 37 // the data stream first forces the audio and video streams to get remapped |
| 38 // from indices {1,2} to {0,1} respectively, which covers an important test |
| 39 // case. |
| 40 enum AVStreamIndex { |
| 41 AV_STREAM_DATA, |
| 42 AV_STREAM_VIDEO, |
| 43 AV_STREAM_AUDIO, |
| 44 AV_STREAM_MAX, |
| 45 }; |
| 46 |
| 47 // These constants refer to the stream ordering inside an initialized |
| 48 // FFmpegDemuxer based on the ordering of the AVStreamIndex constants. |
| 49 enum DemuxerStreamIndex { |
| 50 DS_STREAM_VIDEO, |
| 51 DS_STREAM_AUDIO, |
| 52 DS_STREAM_MAX, |
| 53 }; |
| 54 |
| 55 static const int kDurations[]; |
| 56 static const int kChannels; |
| 57 static const int kSampleRate; |
| 58 static const int kWidth; |
| 59 static const int kHeight; |
| 60 |
| 61 static const size_t kDataSize; |
| 62 static const uint8 kAudioData[]; |
| 63 static const uint8 kVideoData[]; |
| 64 static const uint8* kNullData; |
38 | 65 |
39 FFmpegDemuxerTest() { | 66 FFmpegDemuxerTest() { |
40 // Create an FFmpegDemuxer. | 67 // Create an FFmpegDemuxer. |
41 demuxer_ = new FFmpegDemuxer(&message_loop_); | 68 demuxer_ = new FFmpegDemuxer(&message_loop_); |
42 demuxer_->disable_first_seek_hack_for_testing(); | 69 demuxer_->disable_first_seek_hack_for_testing(); |
43 | 70 |
44 // Inject a filter host and message loop and prepare a data source. | 71 // Inject a filter host and message loop and prepare a data source. |
45 demuxer_->set_host(&host_); | 72 demuxer_->set_host(&host_); |
| 73 data_source_ = new StrictMock<MockDataSource>(); |
46 | 74 |
47 EXPECT_CALL(host_, SetTotalBytes(_)).Times(AnyNumber()); | 75 EXPECT_CALL(*data_source_, Stop(NotNull())) |
48 EXPECT_CALL(host_, SetBufferedBytes(_)).Times(AnyNumber()); | 76 .WillRepeatedly(Invoke(&RunStopFilterCallback)); |
49 EXPECT_CALL(host_, SetCurrentReadPosition(_)) | 77 |
50 .WillRepeatedly(SaveArg<0>(¤t_read_position_)); | 78 // Initialize FFmpeg fixtures. |
| 79 memset(&format_context_, 0, sizeof(format_context_)); |
| 80 memset(&input_format_, 0, sizeof(input_format_)); |
| 81 memset(&streams_, 0, sizeof(streams_)); |
| 82 memset(&codecs_, 0, sizeof(codecs_)); |
| 83 |
| 84 // Initialize AVCodecContext structures. |
| 85 codecs_[AV_STREAM_DATA].codec_type = AVMEDIA_TYPE_DATA; |
| 86 codecs_[AV_STREAM_DATA].codec_id = CODEC_ID_NONE; |
| 87 |
| 88 codecs_[AV_STREAM_VIDEO].codec_type = AVMEDIA_TYPE_VIDEO; |
| 89 codecs_[AV_STREAM_VIDEO].codec_id = CODEC_ID_THEORA; |
| 90 codecs_[AV_STREAM_VIDEO].width = kWidth; |
| 91 codecs_[AV_STREAM_VIDEO].height = kHeight; |
| 92 |
| 93 codecs_[AV_STREAM_AUDIO].codec_type = AVMEDIA_TYPE_AUDIO; |
| 94 codecs_[AV_STREAM_AUDIO].codec_id = CODEC_ID_VORBIS; |
| 95 codecs_[AV_STREAM_AUDIO].channels = kChannels; |
| 96 codecs_[AV_STREAM_AUDIO].sample_rate = kSampleRate; |
| 97 |
| 98 input_format_.name = "foo"; |
| 99 format_context_.iformat = &input_format_; |
| 100 |
| 101 // Initialize AVStream and AVFormatContext structures. We set the time base |
| 102 // of the streams such that duration is reported in microseconds. |
| 103 format_context_.nb_streams = AV_STREAM_MAX; |
| 104 format_context_.streams = new AVStream*[AV_STREAM_MAX]; |
| 105 for (size_t i = 0; i < AV_STREAM_MAX; ++i) { |
| 106 format_context_.streams[i] = &streams_[i]; |
| 107 streams_[i].codec = &codecs_[i]; |
| 108 streams_[i].duration = kDurations[i]; |
| 109 streams_[i].time_base.den = 1 * base::Time::kMicrosecondsPerSecond; |
| 110 streams_[i].time_base.num = 1; |
| 111 } |
51 } | 112 } |
52 | 113 |
53 virtual ~FFmpegDemuxerTest() { | 114 virtual ~FFmpegDemuxerTest() { |
54 // Call Stop() to shut down internal threads. | 115 // Call Stop() to shut down internal threads. |
55 demuxer_->Stop(NewExpectedCallback()); | 116 demuxer_->Stop(NewExpectedCallback()); |
56 | 117 |
57 // Finish up any remaining tasks. | 118 // Finish up any remaining tasks. |
58 message_loop_.RunAllPending(); | 119 message_loop_.RunAllPending(); |
59 // Release the reference to the demuxer. | 120 // Release the reference to the demuxer. |
60 demuxer_ = NULL; | 121 demuxer_ = NULL; |
61 } | 122 |
62 | 123 if (format_context_.streams) { |
63 scoped_refptr<DataSource> CreateDataSource(const std::string& name) { | 124 delete[] format_context_.streams; |
64 FilePath file_path; | 125 format_context_.streams = NULL; |
65 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); | 126 format_context_.nb_streams = 0; |
66 | 127 } |
67 file_path = file_path.Append(FILE_PATH_LITERAL("media")) | 128 } |
68 .Append(FILE_PATH_LITERAL("test")) | 129 |
69 .Append(FILE_PATH_LITERAL("data")) | 130 // Sets up MockFFmpeg to allow FFmpegDemuxer to successfully initialize. |
70 .AppendASCII(name); | 131 void InitializeDemuxerMocks() { |
71 | 132 EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL)) |
72 scoped_refptr<FileDataSource> data_source = new FileDataSource(); | 133 .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), Return(0))); |
73 | 134 EXPECT_CALL(mock_ffmpeg_, AVFindStreamInfo(&format_context_)) |
74 EXPECT_EQ(PIPELINE_OK, data_source->Initialize(file_path.MaybeAsASCII())); | 135 .WillOnce(Return(0)); |
75 | 136 EXPECT_CALL(mock_ffmpeg_, AVCloseInputFile(&format_context_)); |
76 return data_source.get(); | 137 } |
77 } | 138 |
78 | 139 // Initializes both MockFFmpeg and FFmpegDemuxer. |
79 MOCK_METHOD1(CheckPoint, void(int v)); | 140 void InitializeDemuxer() { |
80 | 141 InitializeDemuxerMocks(); |
81 // Initializes FFmpegDemuxer. | 142 |
82 void InitializeDemuxer(const scoped_refptr<DataSource>& data_source) { | 143 // Since we ignore data streams, the duration should be equal to the longest |
83 EXPECT_CALL(host_, SetDuration(_)); | 144 // supported stream's duration (audio, in this case). |
84 demuxer_->Initialize(data_source, NewExpectedStatusCB(PIPELINE_OK)); | 145 base::TimeDelta expected_duration = |
| 146 base::TimeDelta::FromMicroseconds(kDurations[AV_STREAM_AUDIO]); |
| 147 EXPECT_CALL(host_, SetDuration(expected_duration)); |
| 148 |
| 149 demuxer_->Initialize(data_source_.get(), |
| 150 NewExpectedStatusCB(PIPELINE_OK)); |
85 message_loop_.RunAllPending(); | 151 message_loop_.RunAllPending(); |
86 } | 152 } |
87 | 153 |
88 // Verifies that |buffer| has a specific |size| and |timestamp|. | |
89 // |location| simply indicates where the call to this function was made. | |
90 // This makes it easier to track down where test failures occur. | |
91 void ValidateBuffer(const tracked_objects::Location& location, | |
92 const scoped_refptr<Buffer>& buffer, | |
93 size_t size, int64 timestampInMicroseconds) { | |
94 std::string location_str; | |
95 location.Write(true, false, &location_str); | |
96 location_str += "\n"; | |
97 SCOPED_TRACE(location_str); | |
98 EXPECT_TRUE(buffer.get() != NULL); | |
99 EXPECT_EQ(size, buffer->GetDataSize()); | |
100 EXPECT_EQ(base::TimeDelta::FromMicroseconds(timestampInMicroseconds), | |
101 buffer->GetTimestamp()); | |
102 } | |
103 | |
104 // Fixture members. | 154 // Fixture members. |
105 scoped_refptr<FFmpegDemuxer> demuxer_; | 155 scoped_refptr<FFmpegDemuxer> demuxer_; |
| 156 scoped_refptr<StrictMock<MockDataSource> > data_source_; |
106 StrictMock<MockFilterHost> host_; | 157 StrictMock<MockFilterHost> host_; |
107 MessageLoop message_loop_; | 158 MessageLoop message_loop_; |
108 | 159 |
109 int64 current_read_position_; | 160 // FFmpeg fixtures. |
| 161 AVFormatContext format_context_; |
| 162 AVInputFormat input_format_; |
| 163 AVCodecContext codecs_[AV_STREAM_MAX]; |
| 164 AVStream streams_[AV_STREAM_MAX]; |
| 165 MockFFmpeg mock_ffmpeg_; |
110 | 166 |
111 private: | 167 private: |
112 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); | 168 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); |
113 }; | 169 }; |
114 | 170 |
| 171 // These durations are picked so that the demuxer chooses the longest supported |
| 172 // stream, which would be 30 in this case for the audio stream. |
| 173 const int FFmpegDemuxerTest::kDurations[AV_STREAM_MAX] = {100, 20, 30}; |
| 174 const int FFmpegDemuxerTest::kChannels = 2; |
| 175 const int FFmpegDemuxerTest::kSampleRate = 44100; |
| 176 const int FFmpegDemuxerTest::kWidth = 1280; |
| 177 const int FFmpegDemuxerTest::kHeight = 720; |
| 178 |
| 179 const size_t FFmpegDemuxerTest::kDataSize = 4; |
| 180 const uint8 FFmpegDemuxerTest::kAudioData[kDataSize] = {0, 1, 2, 3}; |
| 181 const uint8 FFmpegDemuxerTest::kVideoData[kDataSize] = {4, 5, 6, 7}; |
| 182 const uint8* FFmpegDemuxerTest::kNullData = NULL; |
| 183 |
115 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { | 184 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { |
116 // Simulate av_open_input_file() failing. | 185 // Simulate av_open_input_file() failing. |
117 EXPECT_CALL(host_, SetCurrentReadPosition(_)); | 186 EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL)) |
118 demuxer_->Initialize(CreateDataSource("ten_byte_file"), | 187 .WillOnce(Return(-1)); |
| 188 |
| 189 demuxer_->Initialize(data_source_.get(), |
119 NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); | 190 NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); |
120 | 191 message_loop_.RunAllPending(); |
121 message_loop_.RunAllPending(); | 192 } |
122 } | 193 |
123 | 194 TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { |
124 // TODO(acolwell): Uncomment this test when we discover a file that passes | 195 // Simulate av_find_stream_info() failing. |
125 // av_open_input_file(), but has av_find_stream_info() fail. | 196 EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL)) |
126 // | 197 .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), Return(0))); |
127 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { | 198 EXPECT_CALL(mock_ffmpeg_, AVFindStreamInfo(&format_context_)) |
128 // demuxer_->Initialize( | 199 .WillOnce(Return(AVERROR(EIO))); |
129 // CreateDataSource("find_stream_info_fail.webm"), | 200 EXPECT_CALL(mock_ffmpeg_, AVCloseInputFile(&format_context_)); |
130 // NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); | 201 |
131 // message_loop_.RunAllPending(); | 202 demuxer_->Initialize( |
132 //} | 203 data_source_.get(), |
| 204 NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); |
| 205 message_loop_.RunAllPending(); |
| 206 } |
133 | 207 |
134 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { | 208 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { |
135 // Open a file with no parseable streams. | 209 // Simulate media with no parseable streams. |
136 EXPECT_CALL(host_, SetCurrentReadPosition(_)); | 210 { |
| 211 SCOPED_TRACE(""); |
| 212 InitializeDemuxerMocks(); |
| 213 } |
| 214 format_context_.nb_streams = 0; |
| 215 |
137 demuxer_->Initialize( | 216 demuxer_->Initialize( |
138 CreateDataSource("no_streams.webm"), | 217 data_source_.get(), |
139 NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | 218 NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); |
140 message_loop_.RunAllPending(); | 219 message_loop_.RunAllPending(); |
141 } | 220 } |
142 | 221 |
143 // TODO(acolwell): Find a subtitle only file so we can uncomment this test. | 222 TEST_F(FFmpegDemuxerTest, Initialize_DataStreamOnly) { |
144 // | 223 // Simulate media with a data stream but no audio or video streams. |
145 //TEST_F(FFmpegDemuxerTest, Initialize_DataStreamOnly) { | 224 { |
146 // demuxer_->Initialize( | 225 SCOPED_TRACE(""); |
147 // CreateDataSource("subtitles_only.mp4"),, | 226 InitializeDemuxerMocks(); |
148 // NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | 227 } |
149 // message_loop_.RunAllPending(); | 228 EXPECT_EQ(format_context_.streams[0], &streams_[AV_STREAM_DATA]); |
150 //} | 229 format_context_.nb_streams = 1; |
| 230 |
| 231 demuxer_->Initialize( |
| 232 data_source_.get(), |
| 233 NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); |
| 234 message_loop_.RunAllPending(); |
| 235 } |
151 | 236 |
152 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { | 237 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { |
153 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); | 238 { |
| 239 SCOPED_TRACE(""); |
| 240 InitializeDemuxer(); |
| 241 } |
154 | 242 |
155 // First stream should be video and support the FFmpegDemuxerStream interface. | 243 // First stream should be video and support the FFmpegDemuxerStream interface. |
156 scoped_refptr<DemuxerStream> stream = | 244 scoped_refptr<DemuxerStream> stream = |
157 demuxer_->GetStream(DemuxerStream::VIDEO); | 245 demuxer_->GetStream(DemuxerStream::VIDEO); |
158 ASSERT_TRUE(stream); | 246 ASSERT_TRUE(stream); |
159 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); | 247 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); |
160 ASSERT_TRUE(stream->GetAVStream()); | 248 EXPECT_EQ(&streams_[AV_STREAM_VIDEO], stream->GetAVStream()); |
161 | 249 |
162 // Other stream should be audio and support the FFmpegDemuxerStream interface. | 250 // Other stream should be audio and support the FFmpegDemuxerStream interface. |
163 stream = demuxer_->GetStream(DemuxerStream::AUDIO); | 251 stream = demuxer_->GetStream(DemuxerStream::AUDIO); |
164 ASSERT_TRUE(stream); | 252 ASSERT_TRUE(stream); |
165 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); | 253 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); |
166 ASSERT_TRUE(stream->GetAVStream()); | 254 EXPECT_EQ(&streams_[AV_STREAM_AUDIO], stream->GetAVStream()); |
167 } | 255 } |
168 | 256 |
169 TEST_F(FFmpegDemuxerTest, Read_Audio) { | 257 TEST_F(FFmpegDemuxerTest, Read_DiscardUninteresting) { |
170 // We test that on a successful audio packet read. | 258 // We test that on a successful audio packet read, that the packet is |
171 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); | 259 // duplicated (FFmpeg memory management safety), and a copy of it ends up in |
| 260 // the DemuxerStream. |
| 261 { |
| 262 SCOPED_TRACE(""); |
| 263 InitializeDemuxer(); |
| 264 } |
| 265 |
| 266 // Ignore all AVFreePacket() calls. We check this elsewhere. |
| 267 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); |
| 268 |
| 269 // The demuxer will read a data packet which will get immediately freed, |
| 270 // followed by a read error to end the reading. |
| 271 InSequence s; |
| 272 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 273 .WillOnce(CreatePacketNoCount(AV_STREAM_DATA, kNullData, 0)); |
| 274 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 275 .WillOnce(Return(AVERROR(EIO))); |
172 | 276 |
173 // Attempt a read from the audio stream and run the message loop until done. | 277 // Attempt a read from the audio stream and run the message loop until done. |
174 scoped_refptr<DemuxerStream> audio = | 278 scoped_refptr<DemuxerStream> audio = |
175 demuxer_->GetStream(DemuxerStream::AUDIO); | 279 demuxer_->GetStream(DemuxerStream::AUDIO); |
176 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 280 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
177 reader->Read(audio); | 281 reader->Read(audio); |
178 message_loop_.RunAllPending(); | 282 message_loop_.RunAllPending(); |
179 EXPECT_TRUE(reader->called()); | 283 |
180 ValidateBuffer(FROM_HERE, reader->buffer(), 29, 0); | 284 EXPECT_TRUE(reader->called()); |
181 | 285 ASSERT_TRUE(reader->buffer()); |
182 reader->Reset(); | 286 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); |
| 287 } |
| 288 |
| 289 TEST_F(FFmpegDemuxerTest, Read_Audio) { |
| 290 // We test that on a successful audio packet read, that the packet is |
| 291 // duplicated (FFmpeg memory management safety), and a copy of it ends up in |
| 292 // the DemuxerStream. |
| 293 { |
| 294 SCOPED_TRACE(""); |
| 295 InitializeDemuxer(); |
| 296 } |
| 297 |
| 298 // Ignore all AVFreePacket() calls. We check this via valgrind. |
| 299 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); |
| 300 |
| 301 // The demuxer will read a data packet which will get immediately freed, |
| 302 // followed by reading an audio packet... |
| 303 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 304 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 305 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 306 .WillOnce(Return(0)); |
| 307 |
| 308 // Attempt a read from the audio stream and run the message loop until done. |
| 309 scoped_refptr<DemuxerStream> audio = |
| 310 demuxer_->GetStream(DemuxerStream::AUDIO); |
| 311 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
183 reader->Read(audio); | 312 reader->Read(audio); |
184 message_loop_.RunAllPending(); | 313 message_loop_.RunAllPending(); |
185 EXPECT_TRUE(reader->called()); | 314 |
186 ValidateBuffer(FROM_HERE, reader->buffer(), 27, 3000); | 315 EXPECT_TRUE(reader->called()); |
| 316 ASSERT_TRUE(reader->buffer()); |
| 317 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 318 EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(), |
| 319 reader->buffer()->GetDataSize())); |
187 } | 320 } |
188 | 321 |
189 TEST_F(FFmpegDemuxerTest, Read_Video) { | 322 TEST_F(FFmpegDemuxerTest, Read_Video) { |
190 // We test that on a successful video packet read. | 323 // We test that on a successful video packet read, that the packet is |
191 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); | 324 // duplicated (FFmpeg memory management safety), and a copy of it ends up in |
| 325 // the DemuxerStream. |
| 326 { |
| 327 SCOPED_TRACE(""); |
| 328 InitializeDemuxer(); |
| 329 } |
| 330 |
| 331 // Ignore all AVFreePacket() calls. We check this via valgrind. |
| 332 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); |
| 333 |
| 334 // Simulate a successful frame read. |
| 335 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 336 .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize)); |
| 337 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 338 .WillOnce(Return(0)); |
192 | 339 |
193 // Attempt a read from the video stream and run the message loop until done. | 340 // Attempt a read from the video stream and run the message loop until done. |
194 scoped_refptr<DemuxerStream> video = | 341 scoped_refptr<DemuxerStream> video = |
195 demuxer_->GetStream(DemuxerStream::VIDEO); | 342 demuxer_->GetStream(DemuxerStream::VIDEO); |
196 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 343 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
197 | |
198 reader->Read(video); | 344 reader->Read(video); |
199 message_loop_.RunAllPending(); | 345 message_loop_.RunAllPending(); |
200 EXPECT_TRUE(reader->called()); | 346 |
201 ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0); | 347 EXPECT_TRUE(reader->called()); |
202 | 348 ASSERT_TRUE(reader->buffer()); |
203 reader->Reset(); | 349 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
204 reader->Read(video); | 350 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), |
205 message_loop_.RunAllPending(); | 351 reader->buffer()->GetDataSize())); |
206 EXPECT_TRUE(reader->called()); | |
207 ValidateBuffer(FROM_HERE, reader->buffer(), 1057, 33000); | |
208 } | 352 } |
209 | 353 |
210 TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) { | 354 TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) { |
211 // Test the start time is the first timestamp of the video and audio stream. | 355 // Test the start time is the first timestamp of the video and audio stream. |
212 InitializeDemuxer(CreateDataSource("nonzero-start-time.webm")); | 356 const int64 kStartTime = 60000; |
| 357 // Set the audio and video stream's first timestamp. |
| 358 streams_[AV_STREAM_AUDIO].first_dts = kStartTime; |
| 359 streams_[AV_STREAM_VIDEO].first_dts = kStartTime; |
| 360 { |
| 361 SCOPED_TRACE(""); |
| 362 InitializeDemuxer(); |
| 363 } |
| 364 |
| 365 // Ignore all AVFreePacket() calls. We check this via valgrind. |
| 366 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); |
213 | 367 |
214 const base::TimeDelta kExpectedTimestamp = | 368 const base::TimeDelta kExpectedTimestamp = |
215 base::TimeDelta::FromMicroseconds(396000); | 369 base::TimeDelta::FromMicroseconds(kStartTime); |
| 370 |
| 371 // Simulate a successful frame read. |
| 372 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 373 .WillOnce(CreatePacketTimeNoCount(AV_STREAM_VIDEO, |
| 374 kVideoData, |
| 375 kDataSize, |
| 376 kStartTime)); |
| 377 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 378 .WillOnce(Return(0)); |
| 379 |
| 380 // Attempt a read from the video stream and run the message loop until done. |
| 381 scoped_refptr<DemuxerStream> video = |
| 382 demuxer_->GetStream(DemuxerStream::VIDEO); |
| 383 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
| 384 reader->Read(video); |
| 385 message_loop_.RunAllPending(); |
| 386 |
| 387 EXPECT_TRUE(reader->called()); |
| 388 ASSERT_TRUE(reader->buffer()); |
| 389 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 390 EXPECT_EQ(kExpectedTimestamp, reader->buffer()->GetTimestamp()); |
| 391 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), |
| 392 reader->buffer()->GetDataSize())); |
| 393 |
| 394 EXPECT_EQ(kExpectedTimestamp, demuxer_->GetStartTime()); |
| 395 } |
| 396 |
| 397 TEST_F(FFmpegDemuxerTest, CheckMinStartTime) { |
| 398 // Test the start time is minimum timestamp of all streams. |
| 399 const int64 kAudioStartTime = 5000000; |
| 400 const int64 kVideoStartTime = 5033000; |
| 401 // Set the audio and video stream's first timestamp. |
| 402 streams_[AV_STREAM_AUDIO].first_dts = kAudioStartTime; |
| 403 streams_[AV_STREAM_VIDEO].first_dts = kVideoStartTime; |
| 404 { |
| 405 SCOPED_TRACE(""); |
| 406 InitializeDemuxer(); |
| 407 } |
| 408 |
| 409 // Ignore all AVFreePacket() calls. We check this via valgrind. |
| 410 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); |
| 411 |
| 412 // Expect all calls in sequence. |
| 413 InSequence s; |
| 414 |
| 415 const base::TimeDelta kExpectedAudioTimestamp = |
| 416 base::TimeDelta::FromMicroseconds(kAudioStartTime); |
| 417 const base::TimeDelta kExpectedVideoTimestamp = |
| 418 base::TimeDelta::FromMicroseconds(kVideoStartTime); |
| 419 |
| 420 // First read a video packet, then an audio packet. |
| 421 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 422 .WillOnce(CreatePacketTimeNoCount(AV_STREAM_AUDIO, |
| 423 kAudioData, |
| 424 kDataSize, |
| 425 kAudioStartTime)); |
| 426 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 427 .WillOnce(Return(0)); |
| 428 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 429 .WillOnce(CreatePacketTimeNoCount(AV_STREAM_VIDEO, |
| 430 kVideoData, |
| 431 kDataSize, |
| 432 kVideoStartTime)); |
| 433 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 434 .WillOnce(Return(0)); |
216 | 435 |
217 // Attempt a read from the video stream and run the message loop until done. | 436 // Attempt a read from the video stream and run the message loop until done. |
218 scoped_refptr<DemuxerStream> video = | 437 scoped_refptr<DemuxerStream> video = |
219 demuxer_->GetStream(DemuxerStream::VIDEO); | 438 demuxer_->GetStream(DemuxerStream::VIDEO); |
220 scoped_refptr<DemuxerStream> audio = | 439 scoped_refptr<DemuxerStream> audio = |
221 demuxer_->GetStream(DemuxerStream::AUDIO); | 440 demuxer_->GetStream(DemuxerStream::AUDIO); |
222 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 441 ASSERT_TRUE(video); |
223 | 442 ASSERT_TRUE(audio); |
224 // Check first buffer in video stream. | 443 |
| 444 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
225 reader->Read(video); | 445 reader->Read(video); |
226 message_loop_.RunAllPending(); | 446 message_loop_.RunAllPending(); |
227 EXPECT_TRUE(reader->called()); | 447 |
228 ValidateBuffer(FROM_HERE, reader->buffer(), 5636, 400000); | 448 EXPECT_TRUE(reader->called()); |
229 const base::TimeDelta video_timestamp = reader->buffer()->GetTimestamp(); | 449 ASSERT_TRUE(reader->buffer()); |
230 | 450 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
231 // Check first buffer in audio stream. | 451 EXPECT_EQ(kExpectedVideoTimestamp, reader->buffer()->GetTimestamp()); |
| 452 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), |
| 453 reader->buffer()->GetDataSize())); |
| 454 |
| 455 EXPECT_EQ(kExpectedAudioTimestamp, demuxer_->GetStartTime()); |
| 456 |
232 reader->Reset(); | 457 reader->Reset(); |
233 reader->Read(audio); | 458 reader->Read(audio); |
234 message_loop_.RunAllPending(); | 459 message_loop_.RunAllPending(); |
235 EXPECT_TRUE(reader->called()); | 460 EXPECT_TRUE(reader->called()); |
236 ValidateBuffer(FROM_HERE, reader->buffer(), 165, 396000); | 461 ASSERT_TRUE(reader->buffer()); |
237 const base::TimeDelta audio_timestamp = reader->buffer()->GetTimestamp(); | 462 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
238 | 463 EXPECT_EQ(kExpectedAudioTimestamp, reader->buffer()->GetTimestamp()); |
239 // Verify that the start time is equal to the lowest timestamp. | 464 EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(), |
240 EXPECT_EQ(std::min(audio_timestamp, video_timestamp), | 465 reader->buffer()->GetDataSize())); |
241 demuxer_->GetStartTime()); | 466 |
| 467 EXPECT_EQ(kExpectedAudioTimestamp, demuxer_->GetStartTime()); |
242 } | 468 } |
243 | 469 |
244 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { | 470 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { |
245 // Verify that end of stream buffers are created. | 471 // On end of stream, a new, empty, AVPackets are created without any data for |
246 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); | 472 // each stream and enqueued into the Buffer stream. Verify that these are |
| 473 // indeed inserted. |
| 474 { |
| 475 SCOPED_TRACE(""); |
| 476 InitializeDemuxer(); |
| 477 } |
| 478 |
| 479 // Ignore all AVFreePacket() calls. We check this via valgrind. |
| 480 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); |
| 481 |
| 482 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 483 .WillOnce(Return(AVERROR(EIO))); |
247 | 484 |
248 // We should now expect an end of stream buffer. | 485 // We should now expect an end of stream buffer. |
249 scoped_refptr<DemuxerStream> audio = | 486 scoped_refptr<DemuxerStream> audio = |
250 demuxer_->GetStream(DemuxerStream::AUDIO); | 487 demuxer_->GetStream(DemuxerStream::AUDIO); |
251 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 488 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
252 | 489 reader->Read(audio); |
253 bool got_eos_buffer = false; | 490 message_loop_.RunAllPending(); |
254 const int kMaxBuffers = 170; | 491 EXPECT_TRUE(reader->called()); |
255 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) { | 492 ASSERT_TRUE(reader->buffer()); |
256 reader->Read(audio); | 493 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); |
257 message_loop_.RunAllPending(); | 494 EXPECT_TRUE(reader->buffer()->GetData() == NULL); |
258 EXPECT_TRUE(reader->called()); | 495 EXPECT_EQ(0u, reader->buffer()->GetDataSize()); |
259 ASSERT_TRUE(reader->buffer()); | |
260 | |
261 if (reader->buffer()->IsEndOfStream()) { | |
262 got_eos_buffer = true; | |
263 EXPECT_TRUE(reader->buffer()->GetData() == NULL); | |
264 EXPECT_EQ(0u, reader->buffer()->GetDataSize()); | |
265 break; | |
266 } | |
267 | |
268 EXPECT_TRUE(reader->buffer()->GetData() != NULL); | |
269 EXPECT_GT(reader->buffer()->GetDataSize(), 0u); | |
270 reader->Reset(); | |
271 } | |
272 | |
273 EXPECT_TRUE(got_eos_buffer); | |
274 } | 496 } |
275 | 497 |
276 TEST_F(FFmpegDemuxerTest, Seek) { | 498 TEST_F(FFmpegDemuxerTest, Seek) { |
277 // We're testing that the demuxer frees all queued packets when it receives | 499 // We're testing that the demuxer frees all queued packets when it receives |
278 // a Seek(). | 500 // a Seek(). |
279 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); | 501 // |
| 502 // Since we can't test which packets are being freed, we use check points to |
| 503 // infer that the correct packets have been freed. |
| 504 { |
| 505 SCOPED_TRACE(""); |
| 506 InitializeDemuxer(); |
| 507 } |
280 | 508 |
281 // Get our streams. | 509 // Get our streams. |
282 scoped_refptr<DemuxerStream> video = | 510 scoped_refptr<DemuxerStream> video = |
283 demuxer_->GetStream(DemuxerStream::VIDEO); | 511 demuxer_->GetStream(DemuxerStream::VIDEO); |
284 scoped_refptr<DemuxerStream> audio = | 512 scoped_refptr<DemuxerStream> audio = |
285 demuxer_->GetStream(DemuxerStream::AUDIO); | 513 demuxer_->GetStream(DemuxerStream::AUDIO); |
286 ASSERT_TRUE(video); | 514 ASSERT_TRUE(video); |
287 ASSERT_TRUE(audio); | 515 ASSERT_TRUE(audio); |
288 | 516 |
| 517 // Expected values. |
| 518 const int64 kExpectedTimestamp = 1234; |
| 519 const int64 kExpectedFlags = AVSEEK_FLAG_BACKWARD; |
| 520 |
| 521 // Ignore all AVFreePacket() calls. We check this via valgrind. |
| 522 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); |
| 523 |
| 524 // Expect all calls in sequence. |
| 525 InSequence s; |
| 526 |
| 527 // First we'll read a video packet that causes two audio packets to be queued |
| 528 // inside FFmpegDemuxer... |
| 529 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 530 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 531 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 532 .WillOnce(Return(0)); |
| 533 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 534 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 535 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 536 .WillOnce(Return(0)); |
| 537 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 538 .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize)); |
| 539 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 540 .WillOnce(Return(0)); |
| 541 |
| 542 EXPECT_CALL(mock_ffmpeg_, CheckPoint(1)); |
| 543 |
| 544 // ...then we'll expect a seek call... |
| 545 EXPECT_CALL(mock_ffmpeg_, |
| 546 AVSeekFrame(&format_context_, -1, kExpectedTimestamp, kExpectedFlags)) |
| 547 .WillOnce(Return(0)); |
| 548 |
| 549 // ...then our callback will be executed... |
| 550 FilterStatusCB seek_cb = NewExpectedStatusCB(PIPELINE_OK); |
| 551 EXPECT_CALL(mock_ffmpeg_, CheckPoint(2)); |
| 552 |
| 553 // ...followed by two audio packet reads we'll trigger... |
| 554 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 555 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 556 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 557 .WillOnce(Return(0)); |
| 558 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 559 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); |
| 560 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 561 .WillOnce(Return(0)); |
| 562 |
| 563 // ...followed by two video packet reads... |
| 564 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 565 .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize)); |
| 566 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 567 .WillOnce(Return(0)); |
| 568 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 569 .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize)); |
| 570 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) |
| 571 .WillOnce(Return(0)); |
| 572 |
| 573 // ...and finally a sanity checkpoint to make sure everything was released. |
| 574 EXPECT_CALL(mock_ffmpeg_, CheckPoint(3)); |
| 575 |
289 // Read a video packet and release it. | 576 // Read a video packet and release it. |
290 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 577 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
291 reader->Read(video); | 578 reader->Read(video); |
292 message_loop_.RunAllPending(); | 579 message_loop_.RunAllPending(); |
293 EXPECT_TRUE(reader->called()); | 580 EXPECT_TRUE(reader->called()); |
294 ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0); | 581 ASSERT_TRUE(reader->buffer()); |
| 582 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 583 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), |
| 584 reader->buffer()->GetDataSize())); |
295 | 585 |
296 // Release the video packet and verify the other packets are still queued. | 586 // Release the video packet and verify the other packets are still queued. |
297 reader->Reset(); | 587 reader->Reset(); |
298 message_loop_.RunAllPending(); | 588 message_loop_.RunAllPending(); |
| 589 mock_ffmpeg_.CheckPoint(1); |
299 | 590 |
300 // Issue a simple forward seek, which should discard queued packets. | 591 // Issue a simple forward seek, which should discard queued packets. |
301 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000), | 592 demuxer_->Seek(base::TimeDelta::FromMicroseconds(kExpectedTimestamp), |
302 NewExpectedStatusCB(PIPELINE_OK)); | 593 seek_cb); |
303 message_loop_.RunAllPending(); | 594 message_loop_.RunAllPending(); |
| 595 mock_ffmpeg_.CheckPoint(2); |
304 | 596 |
305 // Audio read #1. | 597 // Audio read #1. |
306 reader->Read(audio); | 598 reader->Read(audio); |
307 message_loop_.RunAllPending(); | 599 message_loop_.RunAllPending(); |
308 EXPECT_TRUE(reader->called()); | 600 EXPECT_TRUE(reader->called()); |
309 ValidateBuffer(FROM_HERE, reader->buffer(), 145, 803000); | 601 ASSERT_TRUE(reader->buffer()); |
| 602 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 603 EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(), |
| 604 reader->buffer()->GetDataSize())); |
310 | 605 |
311 // Audio read #2. | 606 // Audio read #2. |
312 reader->Reset(); | 607 reader->Reset(); |
313 reader->Read(audio); | 608 reader->Read(audio); |
314 message_loop_.RunAllPending(); | 609 message_loop_.RunAllPending(); |
315 EXPECT_TRUE(reader->called()); | 610 EXPECT_TRUE(reader->called()); |
316 ValidateBuffer(FROM_HERE, reader->buffer(), 148, 826000); | 611 ASSERT_TRUE(reader->buffer()); |
| 612 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 613 EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(), |
| 614 reader->buffer()->GetDataSize())); |
317 | 615 |
318 // Video read #1. | 616 // Video read #1. |
319 reader->Reset(); | 617 reader->Reset(); |
320 reader->Read(video); | 618 reader->Read(video); |
321 message_loop_.RunAllPending(); | 619 message_loop_.RunAllPending(); |
322 EXPECT_TRUE(reader->called()); | 620 EXPECT_TRUE(reader->called()); |
323 ValidateBuffer(FROM_HERE, reader->buffer(), 5425, 801000); | 621 ASSERT_TRUE(reader->buffer()); |
| 622 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 623 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), |
| 624 reader->buffer()->GetDataSize())); |
324 | 625 |
325 // Video read #2. | 626 // Video read #2. |
326 reader->Reset(); | 627 reader->Reset(); |
327 reader->Read(video); | 628 reader->Read(video); |
328 message_loop_.RunAllPending(); | 629 message_loop_.RunAllPending(); |
329 EXPECT_TRUE(reader->called()); | 630 EXPECT_TRUE(reader->called()); |
330 ValidateBuffer(FROM_HERE, reader->buffer(), 1906, 834000); | 631 ASSERT_TRUE(reader->buffer()); |
| 632 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); |
| 633 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), |
| 634 reader->buffer()->GetDataSize())); |
331 | 635 |
332 // Manually release the last reference to the buffer and verify it was freed. | 636 // Manually release the last reference to the buffer and verify it was freed. |
333 reader->Reset(); | 637 reader->Reset(); |
334 message_loop_.RunAllPending(); | 638 message_loop_.RunAllPending(); |
| 639 mock_ffmpeg_.CheckPoint(3); |
335 } | 640 } |
336 | 641 |
337 // A mocked callback specialization for calling Read(). Since RunWithParams() | 642 // A mocked callback specialization for calling Read(). Since RunWithParams() |
338 // is mocked we don't need to pass in object or method pointers. | 643 // is mocked we don't need to pass in object or method pointers. |
339 class MockReadCallback : public base::RefCountedThreadSafe<MockReadCallback> { | 644 class MockReadCallback : public base::RefCountedThreadSafe<MockReadCallback> { |
340 public: | 645 public: |
341 MockReadCallback() {} | 646 MockReadCallback() {} |
342 | 647 |
343 virtual ~MockReadCallback() { | 648 virtual ~MockReadCallback() { |
344 OnDelete(); | 649 OnDelete(); |
345 } | 650 } |
346 | 651 |
347 MOCK_METHOD0(OnDelete, void()); | 652 MOCK_METHOD0(OnDelete, void()); |
348 MOCK_METHOD1(Run, void(Buffer* buffer)); | 653 MOCK_METHOD1(Run, void(Buffer* buffer)); |
349 | 654 |
350 private: | 655 private: |
351 DISALLOW_COPY_AND_ASSIGN(MockReadCallback); | 656 DISALLOW_COPY_AND_ASSIGN(MockReadCallback); |
352 }; | 657 }; |
353 | 658 |
354 TEST_F(FFmpegDemuxerTest, Stop) { | 659 TEST_F(FFmpegDemuxerTest, Stop) { |
355 // Tests that calling Read() on a stopped demuxer immediately deletes the | 660 // Tests that calling Read() on a stopped demuxer immediately deletes the |
356 // callback. | 661 // callback. |
357 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); | 662 { |
| 663 SCOPED_TRACE(""); |
| 664 InitializeDemuxer(); |
| 665 } |
358 | 666 |
359 // Get our stream. | 667 // Get our stream. |
360 scoped_refptr<DemuxerStream> audio = | 668 scoped_refptr<DemuxerStream> audio = |
361 demuxer_->GetStream(DemuxerStream::AUDIO); | 669 demuxer_->GetStream(DemuxerStream::AUDIO); |
362 ASSERT_TRUE(audio); | 670 ASSERT_TRUE(audio); |
363 | 671 |
| 672 // Stop the demuxer, overriding the default expectation to assert that |
| 673 // data_source_ really is Stop()'d. |
| 674 EXPECT_CALL(*data_source_, Stop(_)) |
| 675 .WillOnce(Invoke(&RunStopFilterCallback)) |
| 676 .RetiresOnSaturation(); |
364 demuxer_->Stop(NewExpectedCallback()); | 677 demuxer_->Stop(NewExpectedCallback()); |
365 | 678 |
366 // Expect all calls in sequence. | 679 // Expect all calls in sequence. |
367 InSequence s; | 680 InSequence s; |
368 | 681 |
369 // Create our mocked callback. The Callback created by base::Bind() will take | 682 // Create our mocked callback. The Callback created by base::Bind() will take |
370 // ownership of this pointer. | 683 // ownership of this pointer. |
371 StrictMock<MockReadCallback>* callback = new StrictMock<MockReadCallback>(); | 684 StrictMock<MockReadCallback>* callback = new StrictMock<MockReadCallback>(); |
372 | 685 |
373 // The callback should be immediately deleted. We'll use a checkpoint to | 686 // The callback should be immediately deleted. We'll use a checkpoint to |
374 // verify that it has indeed been deleted. | 687 // verify that it has indeed been deleted. |
375 EXPECT_CALL(*callback, OnDelete()); | 688 EXPECT_CALL(*callback, OnDelete()); |
376 EXPECT_CALL(*this, CheckPoint(1)); | 689 EXPECT_CALL(mock_ffmpeg_, CheckPoint(1)); |
377 | 690 |
378 // Attempt the read... | 691 // Attempt the read... |
379 audio->Read(base::Bind(&MockReadCallback::Run, callback)); | 692 audio->Read(base::Bind(&MockReadCallback::Run, callback)); |
380 | 693 |
381 message_loop_.RunAllPending(); | 694 message_loop_.RunAllPending(); |
382 | 695 |
383 // ...and verify that |callback| was deleted. | 696 // ...and verify that |callback| was deleted. |
384 CheckPoint(1); | 697 mock_ffmpeg_.CheckPoint(1); |
385 } | 698 } |
386 | 699 |
387 TEST_F(FFmpegDemuxerTest, DisableAudioStream) { | 700 TEST_F(FFmpegDemuxerTest, DisableAudioStream) { |
388 // We are doing the following things here: | 701 // We are doing the following things here: |
389 // 1. Initialize the demuxer with audio and video stream. | 702 // 1. Initialize the demuxer with audio and video stream. |
390 // 2. Send a "disable audio stream" message to the demuxer. | 703 // 2. Send a "disable audio stream" message to the demuxer. |
391 // 3. Demuxer will free audio packets even if audio stream was initialized. | 704 // 3. Demuxer will free audio packets even if audio stream was initialized. |
392 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); | 705 { |
| 706 SCOPED_TRACE(""); |
| 707 InitializeDemuxer(); |
| 708 } |
393 | 709 |
394 // Submit a "disable audio stream" message to the demuxer. | 710 // Submit a "disable audio stream" message to the demuxer. |
395 demuxer_->OnAudioRendererDisabled(); | 711 demuxer_->OnAudioRendererDisabled(); |
396 message_loop_.RunAllPending(); | 712 message_loop_.RunAllPending(); |
397 | 713 |
| 714 // Ignore all AVFreePacket() calls. We check this via valgrind. |
| 715 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); |
| 716 |
| 717 // Expect all calls in sequence. |
| 718 InSequence s; |
| 719 |
| 720 // The demuxer will read an audio packet which will get immediately freed. |
| 721 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 722 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kNullData, 0)); |
| 723 |
| 724 // Then an end-of-stream packet is read. |
| 725 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) |
| 726 .WillOnce(Return(AVERROR(EIO))); |
| 727 |
398 // Get our streams. | 728 // Get our streams. |
399 scoped_refptr<DemuxerStream> video = | 729 scoped_refptr<DemuxerStream> video = |
400 demuxer_->GetStream(DemuxerStream::VIDEO); | 730 demuxer_->GetStream(DemuxerStream::VIDEO); |
401 scoped_refptr<DemuxerStream> audio = | |
402 demuxer_->GetStream(DemuxerStream::AUDIO); | |
403 ASSERT_TRUE(video); | 731 ASSERT_TRUE(video); |
404 ASSERT_TRUE(audio); | |
405 | 732 |
406 // Attempt a read from the video stream and run the message loop until done. | 733 // Attempt a read from the video stream and run the message loop until done. |
407 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 734 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
408 reader->Read(video); | 735 reader->Read(video); |
409 message_loop_.RunAllPending(); | 736 message_loop_.RunAllPending(); |
410 EXPECT_TRUE(reader->called()); | |
411 ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0); | |
412 | |
413 reader->Reset(); | |
414 reader->Read(audio); | |
415 message_loop_.RunAllPending(); | |
416 EXPECT_TRUE(reader->called()); | |
417 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); | |
418 } | 737 } |
419 | 738 |
420 class MockFFmpegDemuxer : public FFmpegDemuxer { | 739 class MockFFmpegDemuxer : public FFmpegDemuxer { |
421 public: | 740 public: |
422 explicit MockFFmpegDemuxer(MessageLoop* message_loop) | 741 explicit MockFFmpegDemuxer(MessageLoop* message_loop) |
423 : FFmpegDemuxer(message_loop) { | 742 : FFmpegDemuxer(message_loop) { |
424 } | 743 } |
425 virtual ~MockFFmpegDemuxer() {} | 744 virtual ~MockFFmpegDemuxer() {} |
426 | 745 |
427 MOCK_METHOD0(WaitForRead, size_t()); | 746 MOCK_METHOD0(WaitForRead, size_t()); |
428 MOCK_METHOD1(SignalReadCompleted, void(size_t size)); | 747 MOCK_METHOD1(SignalReadCompleted, void(size_t size)); |
429 | 748 |
430 private: | 749 private: |
431 DISALLOW_COPY_AND_ASSIGN(MockFFmpegDemuxer); | 750 DISALLOW_COPY_AND_ASSIGN(MockFFmpegDemuxer); |
432 }; | 751 }; |
433 | 752 |
434 // A gmock helper method to execute the callback and deletes it. | 753 // A gmock helper method to execute the callback and deletes it. |
435 void RunCallback(size_t size, DataSource::ReadCallback* callback) { | 754 void RunCallback(size_t size, DataSource::ReadCallback* callback) { |
436 DCHECK(callback); | 755 DCHECK(callback); |
437 callback->RunWithParams(Tuple1<size_t>(size)); | 756 callback->RunWithParams(Tuple1<size_t>(size)); |
438 delete callback; | 757 delete callback; |
439 } | 758 } |
440 | 759 |
441 TEST_F(FFmpegDemuxerTest, ProtocolRead) { | 760 TEST_F(FFmpegDemuxerTest, ProtocolRead) { |
442 scoped_refptr<StrictMock<MockDataSource> > data_source = | |
443 new StrictMock<MockDataSource>(); | |
444 | |
445 EXPECT_CALL(*data_source, Stop(NotNull())) | |
446 .WillRepeatedly(Invoke(&RunStopFilterCallback)); | |
447 | |
448 // Creates a demuxer. | 761 // Creates a demuxer. |
449 scoped_refptr<MockFFmpegDemuxer> demuxer( | 762 scoped_refptr<MockFFmpegDemuxer> demuxer( |
450 new MockFFmpegDemuxer(&message_loop_)); | 763 new MockFFmpegDemuxer(&message_loop_)); |
451 ASSERT_TRUE(demuxer); | 764 ASSERT_TRUE(demuxer); |
452 demuxer->set_host(&host_); | 765 demuxer->set_host(&host_); |
453 demuxer->data_source_ = data_source; | 766 demuxer->data_source_ = data_source_; |
454 | 767 |
455 uint8 kBuffer[1]; | 768 uint8 kBuffer[1]; |
456 InSequence s; | 769 InSequence s; |
457 // Actions taken in the first read. | 770 // Actions taken in the first read. |
458 EXPECT_CALL(*data_source, GetSize(_)) | 771 EXPECT_CALL(*data_source_, GetSize(_)) |
459 .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true))); | 772 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); |
460 EXPECT_CALL(*data_source, Read(0, 512, kBuffer, NotNull())) | 773 EXPECT_CALL(*data_source_, Read(0, 512, kBuffer, NotNull())) |
461 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); | 774 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); |
462 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); | 775 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); |
463 EXPECT_CALL(*demuxer, WaitForRead()) | 776 EXPECT_CALL(*demuxer, WaitForRead()) |
464 .WillOnce(Return(512)); | 777 .WillOnce(Return(512)); |
465 EXPECT_CALL(host_, SetCurrentReadPosition(512)); | 778 EXPECT_CALL(host_, SetCurrentReadPosition(512)); |
466 | 779 |
467 // Second read. | 780 // Second read. |
468 EXPECT_CALL(*data_source, GetSize(_)) | 781 EXPECT_CALL(*data_source_, GetSize(_)) |
469 .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true))); | 782 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); |
470 EXPECT_CALL(*data_source, Read(512, 512, kBuffer, NotNull())) | 783 EXPECT_CALL(*data_source_, Read(512, 512, kBuffer, NotNull())) |
471 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); | 784 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); |
472 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); | 785 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); |
473 EXPECT_CALL(*demuxer, WaitForRead()) | 786 EXPECT_CALL(*demuxer, WaitForRead()) |
474 .WillOnce(Return(512)); | 787 .WillOnce(Return(512)); |
475 EXPECT_CALL(host_, SetCurrentReadPosition(1024)); | 788 EXPECT_CALL(host_, SetCurrentReadPosition(1024)); |
476 | 789 |
477 // Third read will fail because it exceeds the file size. | 790 // Third read will fail because it exceeds the file size. |
478 EXPECT_CALL(*data_source, GetSize(_)) | 791 EXPECT_CALL(*data_source_, GetSize(_)) |
479 .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true))); | 792 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); |
480 | 793 |
481 // First read. | 794 // First read. |
482 EXPECT_EQ(512, demuxer->Read(512, kBuffer)); | 795 EXPECT_EQ(512, demuxer->Read(512, kBuffer)); |
483 int64 position; | 796 int64 position; |
484 EXPECT_TRUE(demuxer->GetPosition(&position)); | 797 EXPECT_TRUE(demuxer->GetPosition(&position)); |
485 EXPECT_EQ(512, position); | 798 EXPECT_EQ(512, position); |
486 | 799 |
487 // Second read. | 800 // Second read. |
488 EXPECT_EQ(512, demuxer->Read(512, kBuffer)); | 801 EXPECT_EQ(512, demuxer->Read(512, kBuffer)); |
489 EXPECT_TRUE(demuxer->GetPosition(&position)); | 802 EXPECT_TRUE(demuxer->GetPosition(&position)); |
490 EXPECT_EQ(1024, position); | 803 EXPECT_EQ(1024, position); |
491 | 804 |
492 // Third read will get an end-of-file error, which is represented as zero. | 805 // Third read will get an end-of-file error, which is represented as zero. |
493 EXPECT_EQ(0, demuxer->Read(512, kBuffer)); | 806 EXPECT_EQ(0, demuxer->Read(512, kBuffer)); |
494 | 807 |
495 // This read complete signal is generated when demuxer is stopped. | 808 // This read complete signal is generated when demuxer is stopped. |
496 EXPECT_CALL(*demuxer, SignalReadCompleted(DataSource::kReadError)); | 809 EXPECT_CALL(*demuxer, SignalReadCompleted(DataSource::kReadError)); |
497 demuxer->Stop(NewExpectedCallback()); | 810 demuxer->Stop(NewExpectedCallback()); |
498 message_loop_.RunAllPending(); | 811 message_loop_.RunAllPending(); |
499 } | 812 } |
500 | 813 |
501 TEST_F(FFmpegDemuxerTest, ProtocolGetSetPosition) { | 814 TEST_F(FFmpegDemuxerTest, ProtocolGetSetPosition) { |
502 scoped_refptr<DataSource> data_source = CreateDataSource("bear-320x240.webm"); | 815 { |
503 InitializeDemuxer(data_source); | 816 SCOPED_TRACE(""); |
| 817 InitializeDemuxer(); |
| 818 } |
504 | 819 |
505 InSequence s; | 820 InSequence s; |
506 | 821 |
507 int64 size; | 822 EXPECT_CALL(*data_source_, GetSize(_)) |
| 823 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); |
| 824 EXPECT_CALL(*data_source_, GetSize(_)) |
| 825 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); |
| 826 EXPECT_CALL(*data_source_, GetSize(_)) |
| 827 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); |
| 828 |
508 int64 position; | 829 int64 position; |
509 EXPECT_TRUE(demuxer_->GetSize(&size)); | |
510 EXPECT_TRUE(demuxer_->GetPosition(&position)); | 830 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
511 EXPECT_EQ(current_read_position_, position); | 831 EXPECT_EQ(0, position); |
512 | 832 |
513 EXPECT_TRUE(demuxer_->SetPosition(512)); | 833 EXPECT_TRUE(demuxer_->SetPosition(512)); |
514 EXPECT_FALSE(demuxer_->SetPosition(size)); | 834 EXPECT_FALSE(demuxer_->SetPosition(2048)); |
515 EXPECT_FALSE(demuxer_->SetPosition(size + 1)); | |
516 EXPECT_FALSE(demuxer_->SetPosition(-1)); | 835 EXPECT_FALSE(demuxer_->SetPosition(-1)); |
517 EXPECT_TRUE(demuxer_->GetPosition(&position)); | 836 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
518 EXPECT_EQ(512, position); | 837 EXPECT_EQ(512, position); |
519 } | 838 } |
520 | 839 |
521 TEST_F(FFmpegDemuxerTest, ProtocolGetSize) { | 840 TEST_F(FFmpegDemuxerTest, ProtocolGetSize) { |
522 scoped_refptr<DataSource> data_source = CreateDataSource("bear-320x240.webm"); | 841 { |
523 InitializeDemuxer(data_source); | 842 SCOPED_TRACE(""); |
| 843 InitializeDemuxer(); |
| 844 } |
524 | 845 |
525 int64 data_source_size = 0; | 846 EXPECT_CALL(*data_source_, GetSize(_)) |
526 int64 demuxer_size = 0; | 847 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); |
527 EXPECT_TRUE(data_source->GetSize(&data_source_size)); | 848 |
528 EXPECT_TRUE(demuxer_->GetSize(&demuxer_size)); | 849 int64 size; |
529 EXPECT_NE(0, data_source_size); | 850 EXPECT_TRUE(demuxer_->GetSize(&size)); |
530 EXPECT_EQ(data_source_size, demuxer_size); | 851 EXPECT_EQ(1024, size); |
531 } | 852 } |
532 | 853 |
533 TEST_F(FFmpegDemuxerTest, ProtocolIsStreaming) { | 854 TEST_F(FFmpegDemuxerTest, ProtocolIsStreaming) { |
534 scoped_refptr<DataSource> data_source = CreateDataSource("bear-320x240.webm"); | 855 { |
535 InitializeDemuxer(data_source); | 856 SCOPED_TRACE(""); |
536 | 857 InitializeDemuxer(); |
537 EXPECT_FALSE(data_source->IsStreaming()); | 858 } |
| 859 EXPECT_CALL(*data_source_, IsStreaming()) |
| 860 .WillOnce(Return(false)); |
538 EXPECT_FALSE(demuxer_->IsStreaming()); | 861 EXPECT_FALSE(demuxer_->IsStreaming()); |
539 } | 862 } |
540 | 863 |
541 } // namespace media | 864 } // namespace media |
OLD | NEW |