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 "base/bind.h" | 5 #include "base/bind.h" |
6 #include "media/base/audio_decoder_config.h" | 6 #include "media/base/audio_decoder_config.h" |
7 #include "media/base/decoder_buffer.h" | 7 #include "media/base/decoder_buffer.h" |
8 #include "media/base/mock_callback.h" | 8 #include "media/base/mock_callback.h" |
9 #include "media/base/mock_demuxer_host.h" | 9 #include "media/base/mock_demuxer_host.h" |
10 #include "media/base/test_data_util.h" | 10 #include "media/base/test_data_util.h" |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 arg->GetTimestamp().InMilliseconds() == timestamp_in_ms; | 69 arg->GetTimestamp().InMilliseconds() == timestamp_in_ms; |
70 } | 70 } |
71 | 71 |
72 static void OnReadDone(const base::TimeDelta& expected_time, | 72 static void OnReadDone(const base::TimeDelta& expected_time, |
73 bool* called, | 73 bool* called, |
74 const scoped_refptr<DecoderBuffer>& buffer) { | 74 const scoped_refptr<DecoderBuffer>& buffer) { |
75 EXPECT_EQ(expected_time, buffer->GetTimestamp()); | 75 EXPECT_EQ(expected_time, buffer->GetTimestamp()); |
76 *called = true; | 76 *called = true; |
77 } | 77 } |
78 | 78 |
| 79 static void OnReadDone_EOSExpected(bool* called, |
| 80 const scoped_refptr<DecoderBuffer>& buffer) { |
| 81 EXPECT_TRUE(buffer->IsEndOfStream()); |
| 82 *called = true; |
| 83 } |
| 84 |
79 class MockChunkDemuxerClient : public ChunkDemuxerClient { | 85 class MockChunkDemuxerClient : public ChunkDemuxerClient { |
80 public: | 86 public: |
81 MockChunkDemuxerClient() {} | 87 MockChunkDemuxerClient() {} |
82 virtual ~MockChunkDemuxerClient() {} | 88 virtual ~MockChunkDemuxerClient() {} |
83 | 89 |
84 MOCK_METHOD1(DemuxerOpened, void(ChunkDemuxer* demuxer)); | 90 MOCK_METHOD1(DemuxerOpened, void(ChunkDemuxer* demuxer)); |
85 MOCK_METHOD0(DemuxerClosed, void()); | 91 MOCK_METHOD0(DemuxerClosed, void()); |
86 // TODO(xhwang): This is a workaround of the issue that move-only parameters | 92 // TODO(xhwang): This is a workaround of the issue that move-only parameters |
87 // are not supported in mocked methods. Remove this when the issue is fixed. | 93 // are not supported in mocked methods. Remove this when the issue is fixed. |
88 // See http://code.google.com/p/googletest/issues/detail?id=395 | 94 // See http://code.google.com/p/googletest/issues/detail?id=395 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 video_track_entry->GetDataSize() + | 174 video_track_entry->GetDataSize() + |
169 video_content_encodings->GetDataSize() - | 175 video_content_encodings->GetDataSize() - |
170 kVideoTrackEntryHeaderSize); | 176 kVideoTrackEntryHeaderSize); |
171 buf += video_content_encodings->GetDataSize(); | 177 buf += video_content_encodings->GetDataSize(); |
172 } | 178 } |
173 buf += video_track_entry->GetDataSize(); | 179 buf += video_track_entry->GetDataSize(); |
174 } | 180 } |
175 } | 181 } |
176 | 182 |
177 ChunkDemuxer::Status AddId() { | 183 ChunkDemuxer::Status AddId() { |
178 std::vector<std::string> codecs(2); | 184 return AddId(kSourceId, true, true); |
179 codecs[0] = "vp8"; | 185 } |
180 codecs[1] = "vorbis"; | 186 |
181 return demuxer_->AddId(kSourceId, "video/webm", codecs); | 187 ChunkDemuxer::Status AddId(const std::string& source_id, |
| 188 bool has_audio, bool has_video) { |
| 189 std::vector<std::string> codecs; |
| 190 std::string type; |
| 191 |
| 192 if (has_audio) { |
| 193 codecs.push_back("vorbis"); |
| 194 type = "audio/webm"; |
| 195 } |
| 196 |
| 197 if (has_video) { |
| 198 codecs.push_back("vp8"); |
| 199 type = "video/webm"; |
| 200 } |
| 201 |
| 202 if (!has_audio && !has_video) { |
| 203 return AddId(kSourceId, true, true); |
| 204 } |
| 205 |
| 206 return demuxer_->AddId(source_id, type, codecs); |
182 } | 207 } |
183 | 208 |
184 bool AppendData(const uint8* data, size_t length) { | 209 bool AppendData(const uint8* data, size_t length) { |
| 210 return AppendData(kSourceId, data, length); |
| 211 } |
| 212 |
| 213 bool AppendData(const std::string& source_id, |
| 214 const uint8* data, size_t length) { |
185 CHECK(length); | 215 CHECK(length); |
186 EXPECT_CALL(host_, AddBufferedByteRange(_, _)).Times(AnyNumber()) | 216 EXPECT_CALL(host_, AddBufferedByteRange(_, _)).Times(AnyNumber()) |
187 .WillRepeatedly(SaveArg<1>(&buffered_bytes_)); | 217 .WillRepeatedly(SaveArg<1>(&buffered_bytes_)); |
188 EXPECT_CALL(host_, SetNetworkActivity(true)) | 218 EXPECT_CALL(host_, SetNetworkActivity(true)) |
189 .Times(AnyNumber()); | 219 .Times(AnyNumber()); |
190 return demuxer_->AppendData(kSourceId, data, length); | 220 return demuxer_->AppendData(source_id, data, length); |
191 } | 221 } |
192 | 222 |
193 bool AppendDataInPieces(const uint8* data, size_t length) { | 223 bool AppendDataInPieces(const uint8* data, size_t length) { |
194 return AppendDataInPieces(data, length, 7); | 224 return AppendDataInPieces(data, length, 7); |
195 } | 225 } |
196 | 226 |
197 bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) { | 227 bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) { |
198 const uint8* start = data; | 228 const uint8* start = data; |
199 const uint8* end = data + length; | 229 const uint8* end = data + length; |
200 while (start < end) { | 230 while (start < end) { |
201 int64 old_buffered_bytes = buffered_bytes_; | 231 int64 old_buffered_bytes = buffered_bytes_; |
202 size_t append_size = std::min(piece_size, | 232 size_t append_size = std::min(piece_size, |
203 static_cast<size_t>(end - start)); | 233 static_cast<size_t>(end - start)); |
204 if (!AppendData(start, append_size)) | 234 if (!AppendData(start, append_size)) |
205 return false; | 235 return false; |
206 start += append_size; | 236 start += append_size; |
207 | 237 |
208 EXPECT_GT(buffered_bytes_, old_buffered_bytes); | 238 EXPECT_GT(buffered_bytes_, old_buffered_bytes); |
209 } | 239 } |
210 return true; | 240 return true; |
211 } | 241 } |
212 | 242 |
213 bool AppendInfoTracks(bool has_audio, bool has_video, | 243 bool AppendInfoTracks(bool has_audio, bool has_video, |
214 bool video_content_encoded) { | 244 bool video_content_encoded) { |
| 245 return AppendInfoTracks(kSourceId, has_audio, has_video, |
| 246 video_content_encoded); |
| 247 } |
| 248 |
| 249 bool AppendInfoTracks(const std::string& source_id, |
| 250 bool has_audio, bool has_video, |
| 251 bool video_content_encoded) { |
215 scoped_array<uint8> info_tracks; | 252 scoped_array<uint8> info_tracks; |
216 int info_tracks_size = 0; | 253 int info_tracks_size = 0; |
217 CreateInfoTracks(has_audio, has_video, video_content_encoded, | 254 CreateInfoTracks(has_audio, has_video, video_content_encoded, |
218 &info_tracks, &info_tracks_size); | 255 &info_tracks, &info_tracks_size); |
219 return AppendData(info_tracks.get(), info_tracks_size); | 256 return AppendData(source_id, info_tracks.get(), info_tracks_size); |
220 } | 257 } |
221 | 258 |
222 void InitDoneCalled(PipelineStatus expected_status, | 259 void InitDoneCalled(PipelineStatus expected_status, |
223 PipelineStatus status) { | 260 PipelineStatus status) { |
224 EXPECT_EQ(status, expected_status); | 261 EXPECT_EQ(status, expected_status); |
225 } | 262 } |
226 | 263 |
227 PipelineStatusCB CreateInitDoneCB(const base::TimeDelta& expected_duration, | 264 PipelineStatusCB CreateInitDoneCB(const base::TimeDelta& expected_duration, |
228 PipelineStatus expected_status) { | 265 PipelineStatus expected_status) { |
229 if (expected_status == PIPELINE_OK) | 266 if (expected_status == PIPELINE_OK) |
230 EXPECT_CALL(host_, SetDuration(expected_duration)); | 267 EXPECT_CALL(host_, SetDuration(expected_duration)); |
231 | 268 |
232 return base::Bind(&ChunkDemuxerTest::InitDoneCalled, | 269 return base::Bind(&ChunkDemuxerTest::InitDoneCalled, |
233 base::Unretained(this), | 270 base::Unretained(this), |
234 expected_status); | 271 expected_status); |
235 } | 272 } |
236 | 273 |
237 bool InitDemuxer(bool has_audio, bool has_video, | 274 bool InitDemuxer(bool has_audio, bool has_video, |
238 bool video_content_encoded) { | 275 bool video_content_encoded) { |
239 PipelineStatus expected_status = | 276 PipelineStatus expected_status = |
240 (has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN; | 277 (has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN; |
241 | 278 |
242 EXPECT_CALL(*client_, DemuxerOpened(_)); | 279 EXPECT_CALL(*client_, DemuxerOpened(_)); |
243 demuxer_->Initialize( | 280 demuxer_->Initialize( |
244 &host_, CreateInitDoneCB(kDefaultDuration(), expected_status)); | 281 &host_, CreateInitDoneCB(kDefaultDuration(), expected_status)); |
245 | 282 |
246 if (AddId() != ChunkDemuxer::kOk) | 283 if (AddId(kSourceId, has_audio, has_video) != ChunkDemuxer::kOk) |
247 return false; | 284 return false; |
248 | 285 |
249 return AppendInfoTracks(has_audio, has_video, video_content_encoded); | 286 return AppendInfoTracks(has_audio, has_video, video_content_encoded); |
250 } | 287 } |
251 | 288 |
| 289 bool InitDemuxerAudioAndVideoSources(const std::string& audio_id, |
| 290 const std::string& video_id) { |
| 291 EXPECT_CALL(*client_, DemuxerOpened(_)); |
| 292 demuxer_->Initialize( |
| 293 &host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK)); |
| 294 |
| 295 if (AddId(audio_id, true, false) != ChunkDemuxer::kOk) |
| 296 return false; |
| 297 if (AddId(video_id, false, true) != ChunkDemuxer::kOk) |
| 298 return false; |
| 299 |
| 300 bool success = AppendInfoTracks(audio_id, true, false, false); |
| 301 success &= AppendInfoTracks(video_id, false, true, false); |
| 302 return success; |
| 303 } |
| 304 |
252 void ShutdownDemuxer() { | 305 void ShutdownDemuxer() { |
253 if (demuxer_) { | 306 if (demuxer_) { |
254 EXPECT_CALL(*client_, DemuxerClosed()); | 307 EXPECT_CALL(*client_, DemuxerClosed()); |
255 demuxer_->Shutdown(); | 308 demuxer_->Shutdown(); |
256 } | 309 } |
257 } | 310 } |
258 | 311 |
259 void AddSimpleBlock(ClusterBuilder* cb, int track_num, int64 timecode) { | 312 void AddSimpleBlock(ClusterBuilder* cb, int track_num, int64 timecode) { |
260 uint8 data[] = { 0x00 }; | 313 uint8 data[] = { 0x00 }; |
261 cb->AddSimpleBlock(track_num, timecode, 0, data, sizeof(data)); | 314 cb->AddSimpleBlock(track_num, timecode, 0, data, sizeof(data)); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 } else { | 361 } else { |
309 cb.AddBlockGroup(kVideoTrackNum, video_timecode, kVideoBlockDuration, | 362 cb.AddBlockGroup(kVideoTrackNum, video_timecode, kVideoBlockDuration, |
310 video_flag, data.get(), size); | 363 video_flag, data.get(), size); |
311 cb.AddBlockGroup(kAudioTrackNum, audio_timecode, kAudioBlockDuration, | 364 cb.AddBlockGroup(kAudioTrackNum, audio_timecode, kAudioBlockDuration, |
312 kWebMFlagKeyframe, data.get(), size); | 365 kWebMFlagKeyframe, data.get(), size); |
313 } | 366 } |
314 | 367 |
315 return cb.Finish(); | 368 return cb.Finish(); |
316 } | 369 } |
317 | 370 |
| 371 scoped_ptr<Cluster> GenerateSingleStreamCluster(int timecode, |
| 372 int block_count, |
| 373 int track_number, |
| 374 int block_duration) { |
| 375 CHECK_GT(block_count, 0); |
| 376 |
| 377 int size = 10; |
| 378 scoped_array<uint8> data(new uint8[size]); |
| 379 |
| 380 ClusterBuilder cb; |
| 381 cb.SetClusterTimecode(timecode); |
| 382 |
| 383 // Create simple blocks for everything except the last block. |
| 384 for (int i = 0; i < block_count - 1; i++) { |
| 385 cb.AddSimpleBlock(track_number, timecode, kWebMFlagKeyframe, |
| 386 data.get(), size); |
| 387 timecode += block_duration; |
| 388 } |
| 389 |
| 390 // Make the last block a BlockGroup so that it doesn't get delayed by the |
| 391 // block duration calculation logic. |
| 392 cb.AddBlockGroup(track_number, timecode, block_duration, |
| 393 kWebMFlagKeyframe, data.get(), size); |
| 394 return cb.Finish(); |
| 395 } |
| 396 |
318 void GenerateExpectedReads(int timecode, int block_count, | 397 void GenerateExpectedReads(int timecode, int block_count, |
319 DemuxerStream* audio, | 398 DemuxerStream* audio, |
320 DemuxerStream* video) { | 399 DemuxerStream* video) { |
321 CHECK_GT(block_count, 0); | 400 CHECK_GT(block_count, 0); |
322 int audio_timecode = timecode; | 401 int audio_timecode = timecode; |
323 int video_timecode = timecode; | 402 int video_timecode = timecode; |
324 | 403 |
325 if (block_count == 1) { | 404 if (block_count == 1) { |
326 ExpectRead(audio, audio_timecode); | 405 ExpectRead(audio, audio_timecode); |
327 return; | 406 return; |
328 } | 407 } |
329 | 408 |
330 for (int i = 0; i < block_count; i++) { | 409 for (int i = 0; i < block_count; i++) { |
331 if (audio_timecode <= video_timecode) { | 410 if (audio_timecode <= video_timecode) { |
332 ExpectRead(audio, audio_timecode); | 411 ExpectRead(audio, audio_timecode); |
333 audio_timecode += kAudioBlockDuration; | 412 audio_timecode += kAudioBlockDuration; |
334 continue; | 413 continue; |
335 } | 414 } |
336 | 415 |
337 ExpectRead(video, video_timecode); | 416 ExpectRead(video, video_timecode); |
338 video_timecode += kVideoBlockDuration; | 417 video_timecode += kVideoBlockDuration; |
339 } | 418 } |
340 } | 419 } |
341 | 420 |
| 421 void GenerateExpectedReads(int timecode, int block_count, |
| 422 DemuxerStream* stream, int block_duration) { |
| 423 CHECK_GT(block_count, 0); |
| 424 int stream_timecode = timecode; |
| 425 |
| 426 for (int i = 0; i < block_count; i++) { |
| 427 ExpectRead(stream, stream_timecode); |
| 428 stream_timecode += block_duration; |
| 429 } |
| 430 } |
| 431 |
342 MOCK_METHOD1(ReadDone, void(const scoped_refptr<DecoderBuffer>&)); | 432 MOCK_METHOD1(ReadDone, void(const scoped_refptr<DecoderBuffer>&)); |
343 | 433 |
344 void ExpectRead(DemuxerStream* stream, int64 timestamp_in_ms) { | 434 void ExpectRead(DemuxerStream* stream, int64 timestamp_in_ms) { |
345 EXPECT_CALL(*this, ReadDone(HasTimestamp(timestamp_in_ms))); | 435 EXPECT_CALL(*this, ReadDone(HasTimestamp(timestamp_in_ms))); |
346 stream->Read(base::Bind(&ChunkDemuxerTest::ReadDone, | 436 stream->Read(base::Bind(&ChunkDemuxerTest::ReadDone, |
347 base::Unretained(this))); | 437 base::Unretained(this))); |
348 } | 438 } |
349 | 439 |
350 MOCK_METHOD1(Checkpoint, void(int id)); | 440 MOCK_METHOD1(Checkpoint, void(int id)); |
351 | 441 |
352 struct BufferTimestamps { | 442 struct BufferTimestamps { |
353 int video_time_ms; | 443 int video_time_ms; |
354 int audio_time_ms; | 444 int audio_time_ms; |
355 }; | 445 }; |
356 static const int kSkip = -1; | 446 static const int kSkip = -1; |
357 | 447 |
358 // Test parsing a WebM file. | 448 // Test parsing a WebM file. |
359 // |filename| - The name of the file in media/test/data to parse. | 449 // |filename| - The name of the file in media/test/data to parse. |
360 // |timestamps| - The expected timestamps on the parsed buffers. | 450 // |timestamps| - The expected timestamps on the parsed buffers. |
361 // a timestamp of kSkip indicates that a Read() call for that stream | 451 // a timestamp of kSkip indicates that a Read() call for that stream |
362 // shouldn't be made on that iteration of the loop. If both streams have | 452 // shouldn't be made on that iteration of the loop. If both streams have |
363 // a kSkip then the loop will terminate. | 453 // a kSkip then the loop will terminate. |
364 bool ParseWebMFile(const std::string& filename, | 454 bool ParseWebMFile(const std::string& filename, |
365 const BufferTimestamps* timestamps, | 455 const BufferTimestamps* timestamps, |
366 const base::TimeDelta& duration) { | 456 const base::TimeDelta& duration) { |
| 457 return ParseWebMFile(filename, timestamps, duration, true, true); |
| 458 } |
| 459 |
| 460 bool ParseWebMFile(const std::string& filename, |
| 461 const BufferTimestamps* timestamps, |
| 462 const base::TimeDelta& duration, |
| 463 bool has_audio, bool has_video) { |
367 EXPECT_CALL(*client_, DemuxerOpened(_)); | 464 EXPECT_CALL(*client_, DemuxerOpened(_)); |
368 demuxer_->Initialize( | 465 demuxer_->Initialize( |
369 &host_, CreateInitDoneCB(duration, PIPELINE_OK)); | 466 &host_, CreateInitDoneCB(duration, PIPELINE_OK)); |
370 | 467 |
371 if (AddId() != ChunkDemuxer::kOk) | 468 if (AddId(kSourceId, has_audio, has_video) != ChunkDemuxer::kOk) |
372 return false; | 469 return false; |
373 | 470 |
374 // Read a WebM file into memory and send the data to the demuxer. | 471 // Read a WebM file into memory and send the data to the demuxer. |
375 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename); | 472 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename); |
376 if (!AppendDataInPieces(buffer->GetData(), buffer->GetDataSize(), 512)) | 473 if (!AppendDataInPieces(buffer->GetData(), buffer->GetDataSize(), 512)) |
377 return false; | 474 return false; |
378 | 475 |
379 scoped_refptr<DemuxerStream> audio = | 476 scoped_refptr<DemuxerStream> audio = |
380 demuxer_->GetStream(DemuxerStream::AUDIO); | 477 demuxer_->GetStream(DemuxerStream::AUDIO); |
381 scoped_refptr<DemuxerStream> video = | 478 scoped_refptr<DemuxerStream> video = |
(...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
949 struct BufferTimestamps buffer_timestamps[] = { | 1046 struct BufferTimestamps buffer_timestamps[] = { |
950 {kSkip, 0}, | 1047 {kSkip, 0}, |
951 {kSkip, 3}, | 1048 {kSkip, 3}, |
952 {kSkip, 6}, | 1049 {kSkip, 6}, |
953 {kSkip, 9}, | 1050 {kSkip, 9}, |
954 {kSkip, 12}, | 1051 {kSkip, 12}, |
955 {kSkip, kSkip}, | 1052 {kSkip, kSkip}, |
956 }; | 1053 }; |
957 | 1054 |
958 ASSERT_TRUE(ParseWebMFile("bear-320x240-audio-only.webm", buffer_timestamps, | 1055 ASSERT_TRUE(ParseWebMFile("bear-320x240-audio-only.webm", buffer_timestamps, |
959 base::TimeDelta::FromMilliseconds(2744))); | 1056 base::TimeDelta::FromMilliseconds(2744), |
| 1057 true, false)); |
960 } | 1058 } |
961 | 1059 |
962 TEST_F(ChunkDemuxerTest, TestWebMFile_VideoOnly) { | 1060 TEST_F(ChunkDemuxerTest, TestWebMFile_VideoOnly) { |
963 struct BufferTimestamps buffer_timestamps[] = { | 1061 struct BufferTimestamps buffer_timestamps[] = { |
964 {0, kSkip}, | 1062 {0, kSkip}, |
965 {33, kSkip}, | 1063 {33, kSkip}, |
966 {67, kSkip}, | 1064 {67, kSkip}, |
967 {100, kSkip}, | 1065 {100, kSkip}, |
968 {133, kSkip}, | 1066 {133, kSkip}, |
969 {kSkip, kSkip}, | 1067 {kSkip, kSkip}, |
970 }; | 1068 }; |
971 | 1069 |
972 ASSERT_TRUE(ParseWebMFile("bear-320x240-video-only.webm", buffer_timestamps, | 1070 ASSERT_TRUE(ParseWebMFile("bear-320x240-video-only.webm", buffer_timestamps, |
973 base::TimeDelta::FromMilliseconds(2703))); | 1071 base::TimeDelta::FromMilliseconds(2703), |
| 1072 false, true)); |
974 } | 1073 } |
975 | 1074 |
976 TEST_F(ChunkDemuxerTest, TestWebMFile_AltRefFrames) { | 1075 TEST_F(ChunkDemuxerTest, TestWebMFile_AltRefFrames) { |
977 struct BufferTimestamps buffer_timestamps[] = { | 1076 struct BufferTimestamps buffer_timestamps[] = { |
978 {0, 0}, | 1077 {0, 0}, |
979 {33, 3}, | 1078 {33, 3}, |
980 {33, 6}, | 1079 {33, 6}, |
981 {67, 9}, | 1080 {67, 9}, |
982 {100, 12}, | 1081 {100, 12}, |
983 {kSkip, kSkip}, | 1082 {kSkip, kSkip}, |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1089 DEMUXER_ERROR_COULD_NOT_OPEN)); | 1188 DEMUXER_ERROR_COULD_NOT_OPEN)); |
1090 | 1189 |
1091 std::vector<std::string> codecs(1); | 1190 std::vector<std::string> codecs(1); |
1092 codecs[0] = "vp8"; | 1191 codecs[0] = "vp8"; |
1093 ASSERT_EQ(demuxer_->AddId(kSourceId, "video/webm", codecs), | 1192 ASSERT_EQ(demuxer_->AddId(kSourceId, "video/webm", codecs), |
1094 ChunkDemuxer::kOk); | 1193 ChunkDemuxer::kOk); |
1095 | 1194 |
1096 ASSERT_TRUE(AppendInfoTracks(true, true, false)); | 1195 ASSERT_TRUE(AppendInfoTracks(true, true, false)); |
1097 } | 1196 } |
1098 | 1197 |
| 1198 TEST_F(ChunkDemuxerTest, TestAddSeparateSourcesForAudioAndVideo) { |
| 1199 std::string audio_id = "audio1"; |
| 1200 std::string video_id = "video1"; |
| 1201 ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id)); |
| 1202 |
| 1203 scoped_refptr<DemuxerStream> audio = |
| 1204 demuxer_->GetStream(DemuxerStream::AUDIO); |
| 1205 scoped_refptr<DemuxerStream> video = |
| 1206 demuxer_->GetStream(DemuxerStream::VIDEO); |
| 1207 |
| 1208 scoped_ptr<Cluster> cluster_a( |
| 1209 GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration)); |
| 1210 |
| 1211 scoped_ptr<Cluster> cluster_v( |
| 1212 GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration)); |
| 1213 |
| 1214 // Append audio and video data into separate source ids. |
| 1215 ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size())); |
| 1216 GenerateExpectedReads(0, 4, audio, kAudioBlockDuration); |
| 1217 ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size())); |
| 1218 GenerateExpectedReads(0, 4, video, kVideoBlockDuration); |
| 1219 } |
| 1220 |
| 1221 TEST_F(ChunkDemuxerTest, TestAddIdFailures) { |
| 1222 EXPECT_CALL(*client_, DemuxerOpened(_)); |
| 1223 demuxer_->Initialize( |
| 1224 &host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK)); |
| 1225 |
| 1226 std::string audio_id = "audio1"; |
| 1227 std::string video_id = "video1"; |
| 1228 |
| 1229 ASSERT_EQ(AddId(audio_id, true, false), ChunkDemuxer::kOk); |
| 1230 |
| 1231 // Adding an id with audio/video should fail because we already added audio. |
| 1232 ASSERT_EQ(AddId(), ChunkDemuxer::kReachedIdLimit); |
| 1233 |
| 1234 ASSERT_TRUE(AppendInfoTracks(audio_id, true, false, false)); |
| 1235 |
| 1236 // Adding an id after append should fail. |
| 1237 ASSERT_EQ(AddId(video_id, false, true), ChunkDemuxer::kReachedIdLimit); |
| 1238 } |
| 1239 |
| 1240 // Test that Read() calls after a RemoveId() return "end of stream" buffers. |
| 1241 TEST_F(ChunkDemuxerTest, TestRemoveId) { |
| 1242 std::string audio_id = "audio1"; |
| 1243 std::string video_id = "video1"; |
| 1244 ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id)); |
| 1245 |
| 1246 scoped_ptr<Cluster> cluster_a( |
| 1247 GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration)); |
| 1248 |
| 1249 scoped_ptr<Cluster> cluster_v( |
| 1250 GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration)); |
| 1251 |
| 1252 // Append audio and video data into separate source ids. |
| 1253 ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size())); |
| 1254 ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size())); |
| 1255 |
| 1256 // Read() from audio should return normal buffers. |
| 1257 scoped_refptr<DemuxerStream> audio = |
| 1258 demuxer_->GetStream(DemuxerStream::AUDIO); |
| 1259 GenerateExpectedReads(0, 4, audio, kAudioBlockDuration); |
| 1260 |
| 1261 // Remove the audio id. |
| 1262 demuxer_->RemoveId(audio_id); |
| 1263 |
| 1264 // Read() from audio should return "end of stream" buffers. |
| 1265 bool audio_read_done = false; |
| 1266 audio->Read(base::Bind(&OnReadDone_EOSExpected, |
| 1267 &audio_read_done)); |
| 1268 EXPECT_TRUE(audio_read_done); |
| 1269 |
| 1270 // Read() from video should still return normal buffers. |
| 1271 scoped_refptr<DemuxerStream> video = |
| 1272 demuxer_->GetStream(DemuxerStream::VIDEO); |
| 1273 GenerateExpectedReads(0, 4, video, kVideoBlockDuration); |
| 1274 } |
| 1275 |
| 1276 // Test that Seek() successfully seeks to all source IDs. |
| 1277 TEST_F(ChunkDemuxerTest, TestSeekAudioAndVideoSources) { |
| 1278 std::string audio_id = "audio1"; |
| 1279 std::string video_id = "video1"; |
| 1280 ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id)); |
| 1281 |
| 1282 scoped_ptr<Cluster> cluster_a1( |
| 1283 GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration)); |
| 1284 |
| 1285 scoped_ptr<Cluster> cluster_v1( |
| 1286 GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration)); |
| 1287 |
| 1288 ASSERT_TRUE(AppendData(audio_id, cluster_a1->data(), cluster_a1->size())); |
| 1289 ASSERT_TRUE(AppendData(video_id, cluster_v1->data(), cluster_v1->size())); |
| 1290 |
| 1291 // Read() should return buffers at 0. |
| 1292 bool audio_read_done = false; |
| 1293 bool video_read_done = false; |
| 1294 scoped_refptr<DemuxerStream> audio = |
| 1295 demuxer_->GetStream(DemuxerStream::AUDIO); |
| 1296 scoped_refptr<DemuxerStream> video = |
| 1297 demuxer_->GetStream(DemuxerStream::VIDEO); |
| 1298 |
| 1299 audio->Read(base::Bind(&OnReadDone, |
| 1300 base::TimeDelta::FromMilliseconds(0), |
| 1301 &audio_read_done)); |
| 1302 video->Read(base::Bind(&OnReadDone, |
| 1303 base::TimeDelta::FromMilliseconds(0), |
| 1304 &video_read_done)); |
| 1305 EXPECT_TRUE(audio_read_done); |
| 1306 EXPECT_TRUE(video_read_done); |
| 1307 |
| 1308 // Seek to 3 (an unbuffered region). |
| 1309 demuxer_->StartWaitingForSeek(); |
| 1310 demuxer_->Seek(base::TimeDelta::FromSeconds(3), |
| 1311 NewExpectedStatusCB(PIPELINE_OK)); |
| 1312 |
| 1313 audio_read_done = false; |
| 1314 video_read_done = false; |
| 1315 audio->Read(base::Bind(&OnReadDone, |
| 1316 base::TimeDelta::FromSeconds(3), |
| 1317 &audio_read_done)); |
| 1318 video->Read(base::Bind(&OnReadDone, |
| 1319 base::TimeDelta::FromSeconds(3), |
| 1320 &video_read_done)); |
| 1321 |
| 1322 // Read()s should not return until after data is appended at the Seek point. |
| 1323 EXPECT_FALSE(audio_read_done); |
| 1324 EXPECT_FALSE(video_read_done); |
| 1325 |
| 1326 scoped_ptr<Cluster> cluster_a2( |
| 1327 GenerateSingleStreamCluster(3000, 4, kAudioTrackNum, |
| 1328 kAudioBlockDuration)); |
| 1329 |
| 1330 scoped_ptr<Cluster> cluster_v2( |
| 1331 GenerateSingleStreamCluster(3000, 4, kVideoTrackNum, |
| 1332 kVideoBlockDuration)); |
| 1333 |
| 1334 ASSERT_TRUE(AppendData(audio_id, cluster_a2->data(), cluster_a2->size())); |
| 1335 ASSERT_TRUE(AppendData(video_id, cluster_v2->data(), cluster_v2->size())); |
| 1336 |
| 1337 // Read() should return buffers at 3. |
| 1338 EXPECT_TRUE(audio_read_done); |
| 1339 EXPECT_TRUE(video_read_done); |
| 1340 } |
| 1341 |
1099 } // namespace media | 1342 } // namespace media |
OLD | NEW |