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 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
190 video_track_entry->GetDataSize() + | 196 video_track_entry->GetDataSize() + |
191 video_content_encodings->GetDataSize() - | 197 video_content_encodings->GetDataSize() - |
192 kVideoTrackEntryHeaderSize); | 198 kVideoTrackEntryHeaderSize); |
193 buf += video_content_encodings->GetDataSize(); | 199 buf += video_content_encodings->GetDataSize(); |
194 } | 200 } |
195 buf += video_track_entry->GetDataSize(); | 201 buf += video_track_entry->GetDataSize(); |
196 } | 202 } |
197 } | 203 } |
198 | 204 |
199 ChunkDemuxer::Status AddId() { | 205 ChunkDemuxer::Status AddId() { |
200 std::vector<std::string> codecs(2); | 206 return AddId(kSourceId, true, true); |
201 codecs[0] = "vp8"; | 207 } |
202 codecs[1] = "vorbis"; | 208 |
203 return demuxer_->AddId(kSourceId, "video/webm", codecs); | 209 ChunkDemuxer::Status AddId(const std::string& source_id, |
| 210 bool has_audio, bool has_video) { |
| 211 std::vector<std::string> codecs; |
| 212 std::string type; |
| 213 |
| 214 if (has_audio) { |
| 215 codecs.push_back("vorbis"); |
| 216 type = "audio/webm"; |
| 217 } |
| 218 |
| 219 if (has_video) { |
| 220 codecs.push_back("vp8"); |
| 221 type = "video/webm"; |
| 222 } |
| 223 |
| 224 if (!has_audio && !has_video) { |
| 225 return AddId(kSourceId, true, true); |
| 226 } |
| 227 |
| 228 return demuxer_->AddId(source_id, type, codecs); |
204 } | 229 } |
205 | 230 |
206 bool AppendData(const uint8* data, size_t length) { | 231 bool AppendData(const uint8* data, size_t length) { |
| 232 return AppendData(kSourceId, data, length); |
| 233 } |
| 234 |
| 235 bool AppendData(const std::string& source_id, |
| 236 const uint8* data, size_t length) { |
207 CHECK(length); | 237 CHECK(length); |
208 EXPECT_CALL(host_, AddBufferedByteRange(_, _)).Times(AnyNumber()) | 238 EXPECT_CALL(host_, AddBufferedByteRange(_, _)).Times(AnyNumber()) |
209 .WillRepeatedly(SaveArg<1>(&buffered_bytes_)); | 239 .WillRepeatedly(SaveArg<1>(&buffered_bytes_)); |
210 return demuxer_->AppendData(kSourceId, data, length); | 240 return demuxer_->AppendData(source_id, data, length); |
211 } | 241 } |
212 | 242 |
213 bool AppendDataInPieces(const uint8* data, size_t length) { | 243 bool AppendDataInPieces(const uint8* data, size_t length) { |
214 return AppendDataInPieces(data, length, 7); | 244 return AppendDataInPieces(data, length, 7); |
215 } | 245 } |
216 | 246 |
217 bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) { | 247 bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) { |
218 const uint8* start = data; | 248 const uint8* start = data; |
219 const uint8* end = data + length; | 249 const uint8* end = data + length; |
220 while (start < end) { | 250 while (start < end) { |
221 int64 old_buffered_bytes = buffered_bytes_; | 251 int64 old_buffered_bytes = buffered_bytes_; |
222 size_t append_size = std::min(piece_size, | 252 size_t append_size = std::min(piece_size, |
223 static_cast<size_t>(end - start)); | 253 static_cast<size_t>(end - start)); |
224 if (!AppendData(start, append_size)) | 254 if (!AppendData(start, append_size)) |
225 return false; | 255 return false; |
226 start += append_size; | 256 start += append_size; |
227 | 257 |
228 EXPECT_GT(buffered_bytes_, old_buffered_bytes); | 258 EXPECT_GT(buffered_bytes_, old_buffered_bytes); |
229 } | 259 } |
230 return true; | 260 return true; |
231 } | 261 } |
232 | 262 |
233 bool AppendInitSegment(bool has_audio, bool has_video, | 263 bool AppendInitSegment(bool has_audio, bool has_video, |
234 bool video_content_encoded) { | 264 bool video_content_encoded) { |
| 265 return AppendInitSegment(kSourceId, has_audio, has_video, |
| 266 video_content_encoded); |
| 267 } |
| 268 |
| 269 bool AppendInitSegment(const std::string& source_id, |
| 270 bool has_audio, bool has_video, |
| 271 bool video_content_encoded) { |
235 scoped_array<uint8> info_tracks; | 272 scoped_array<uint8> info_tracks; |
236 int info_tracks_size = 0; | 273 int info_tracks_size = 0; |
237 CreateInitSegment(has_audio, has_video, video_content_encoded, | 274 CreateInitSegment(has_audio, has_video, video_content_encoded, |
238 &info_tracks, &info_tracks_size); | 275 &info_tracks, &info_tracks_size); |
239 return AppendData(info_tracks.get(), info_tracks_size); | 276 return AppendData(source_id, info_tracks.get(), info_tracks_size); |
240 } | 277 } |
241 | 278 |
242 void InitDoneCalled(PipelineStatus expected_status, | 279 void InitDoneCalled(PipelineStatus expected_status, |
243 PipelineStatus status) { | 280 PipelineStatus status) { |
244 EXPECT_EQ(status, expected_status); | 281 EXPECT_EQ(status, expected_status); |
245 } | 282 } |
246 | 283 |
247 PipelineStatusCB CreateInitDoneCB(const base::TimeDelta& expected_duration, | 284 PipelineStatusCB CreateInitDoneCB(const base::TimeDelta& expected_duration, |
248 PipelineStatus expected_status) { | 285 PipelineStatus expected_status) { |
249 if (expected_status == PIPELINE_OK) | 286 if (expected_status == PIPELINE_OK) |
250 EXPECT_CALL(host_, SetDuration(expected_duration)); | 287 EXPECT_CALL(host_, SetDuration(expected_duration)); |
251 | 288 |
252 return base::Bind(&ChunkDemuxerTest::InitDoneCalled, | 289 return base::Bind(&ChunkDemuxerTest::InitDoneCalled, |
253 base::Unretained(this), | 290 base::Unretained(this), |
254 expected_status); | 291 expected_status); |
255 } | 292 } |
256 | 293 |
257 bool InitDemuxer(bool has_audio, bool has_video, | 294 bool InitDemuxer(bool has_audio, bool has_video, |
258 bool video_content_encoded) { | 295 bool video_content_encoded) { |
259 PipelineStatus expected_status = | 296 PipelineStatus expected_status = |
260 (has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN; | 297 (has_audio || has_video) ? PIPELINE_OK : DEMUXER_ERROR_COULD_NOT_OPEN; |
261 | 298 |
262 EXPECT_CALL(*client_, DemuxerOpened(_)); | 299 EXPECT_CALL(*client_, DemuxerOpened(_)); |
263 demuxer_->Initialize( | 300 demuxer_->Initialize( |
264 &host_, CreateInitDoneCB(kDefaultDuration(), expected_status)); | 301 &host_, CreateInitDoneCB(kDefaultDuration(), expected_status)); |
265 | 302 |
266 if (AddId() != ChunkDemuxer::kOk) | 303 if (AddId(kSourceId, has_audio, has_video) != ChunkDemuxer::kOk) |
267 return false; | 304 return false; |
268 | 305 |
269 return AppendInitSegment(has_audio, has_video, video_content_encoded); | 306 return AppendInitSegment(has_audio, has_video, video_content_encoded); |
270 } | 307 } |
271 | 308 |
| 309 bool InitDemuxerAudioAndVideoSources(const std::string& audio_id, |
| 310 const std::string& video_id) { |
| 311 EXPECT_CALL(*client_, DemuxerOpened(_)); |
| 312 demuxer_->Initialize( |
| 313 &host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK)); |
| 314 |
| 315 if (AddId(audio_id, true, false) != ChunkDemuxer::kOk) |
| 316 return false; |
| 317 if (AddId(video_id, false, true) != ChunkDemuxer::kOk) |
| 318 return false; |
| 319 |
| 320 bool success = AppendInitSegment(audio_id, true, false, false); |
| 321 success &= AppendInitSegment(video_id, false, true, false); |
| 322 return success; |
| 323 } |
| 324 |
272 void ShutdownDemuxer() { | 325 void ShutdownDemuxer() { |
273 if (demuxer_) { | 326 if (demuxer_) { |
274 EXPECT_CALL(*client_, DemuxerClosed()); | 327 EXPECT_CALL(*client_, DemuxerClosed()); |
275 demuxer_->Shutdown(); | 328 demuxer_->Shutdown(); |
276 } | 329 } |
277 } | 330 } |
278 | 331 |
279 void AddSimpleBlock(ClusterBuilder* cb, int track_num, int64 timecode) { | 332 void AddSimpleBlock(ClusterBuilder* cb, int track_num, int64 timecode) { |
280 uint8 data[] = { 0x00 }; | 333 uint8 data[] = { 0x00 }; |
281 cb->AddSimpleBlock(track_num, timecode, 0, data, sizeof(data)); | 334 cb->AddSimpleBlock(track_num, timecode, 0, data, sizeof(data)); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 } else { | 381 } else { |
329 cb.AddBlockGroup(kVideoTrackNum, video_timecode, kVideoBlockDuration, | 382 cb.AddBlockGroup(kVideoTrackNum, video_timecode, kVideoBlockDuration, |
330 video_flag, data.get(), size); | 383 video_flag, data.get(), size); |
331 cb.AddBlockGroup(kAudioTrackNum, audio_timecode, kAudioBlockDuration, | 384 cb.AddBlockGroup(kAudioTrackNum, audio_timecode, kAudioBlockDuration, |
332 kWebMFlagKeyframe, data.get(), size); | 385 kWebMFlagKeyframe, data.get(), size); |
333 } | 386 } |
334 | 387 |
335 return cb.Finish(); | 388 return cb.Finish(); |
336 } | 389 } |
337 | 390 |
| 391 scoped_ptr<Cluster> GenerateSingleStreamCluster(int timecode, |
| 392 int block_count, |
| 393 int track_number, |
| 394 int block_duration) { |
| 395 CHECK_GT(block_count, 0); |
| 396 |
| 397 int size = 10; |
| 398 scoped_array<uint8> data(new uint8[size]); |
| 399 |
| 400 ClusterBuilder cb; |
| 401 cb.SetClusterTimecode(timecode); |
| 402 |
| 403 // Create simple blocks for everything except the last block. |
| 404 for (int i = 0; i < block_count - 1; i++) { |
| 405 cb.AddSimpleBlock(track_number, timecode, kWebMFlagKeyframe, |
| 406 data.get(), size); |
| 407 timecode += block_duration; |
| 408 } |
| 409 |
| 410 // Make the last block a BlockGroup so that it doesn't get delayed by the |
| 411 // block duration calculation logic. |
| 412 cb.AddBlockGroup(track_number, timecode, block_duration, |
| 413 kWebMFlagKeyframe, data.get(), size); |
| 414 return cb.Finish(); |
| 415 } |
| 416 |
338 void GenerateExpectedReads(int timecode, int block_count, | 417 void GenerateExpectedReads(int timecode, int block_count, |
339 DemuxerStream* audio, | 418 DemuxerStream* audio, |
340 DemuxerStream* video) { | 419 DemuxerStream* video) { |
341 CHECK_GT(block_count, 0); | 420 CHECK_GT(block_count, 0); |
342 int audio_timecode = timecode; | 421 int audio_timecode = timecode; |
343 int video_timecode = timecode; | 422 int video_timecode = timecode; |
344 | 423 |
345 if (block_count == 1) { | 424 if (block_count == 1) { |
346 ExpectRead(audio, audio_timecode); | 425 ExpectRead(audio, audio_timecode); |
347 return; | 426 return; |
348 } | 427 } |
349 | 428 |
350 for (int i = 0; i < block_count; i++) { | 429 for (int i = 0; i < block_count; i++) { |
351 if (audio_timecode <= video_timecode) { | 430 if (audio_timecode <= video_timecode) { |
352 ExpectRead(audio, audio_timecode); | 431 ExpectRead(audio, audio_timecode); |
353 audio_timecode += kAudioBlockDuration; | 432 audio_timecode += kAudioBlockDuration; |
354 continue; | 433 continue; |
355 } | 434 } |
356 | 435 |
357 ExpectRead(video, video_timecode); | 436 ExpectRead(video, video_timecode); |
358 video_timecode += kVideoBlockDuration; | 437 video_timecode += kVideoBlockDuration; |
359 } | 438 } |
360 } | 439 } |
361 | 440 |
| 441 void GenerateExpectedReads(int timecode, int block_count, |
| 442 DemuxerStream* stream, int block_duration) { |
| 443 CHECK_GT(block_count, 0); |
| 444 int stream_timecode = timecode; |
| 445 |
| 446 for (int i = 0; i < block_count; i++) { |
| 447 ExpectRead(stream, stream_timecode); |
| 448 stream_timecode += block_duration; |
| 449 } |
| 450 } |
| 451 |
362 MOCK_METHOD1(ReadDone, void(const scoped_refptr<DecoderBuffer>&)); | 452 MOCK_METHOD1(ReadDone, void(const scoped_refptr<DecoderBuffer>&)); |
363 | 453 |
364 void ExpectRead(DemuxerStream* stream, int64 timestamp_in_ms) { | 454 void ExpectRead(DemuxerStream* stream, int64 timestamp_in_ms) { |
365 EXPECT_CALL(*this, ReadDone(HasTimestamp(timestamp_in_ms))); | 455 EXPECT_CALL(*this, ReadDone(HasTimestamp(timestamp_in_ms))); |
366 stream->Read(base::Bind(&ChunkDemuxerTest::ReadDone, | 456 stream->Read(base::Bind(&ChunkDemuxerTest::ReadDone, |
367 base::Unretained(this))); | 457 base::Unretained(this))); |
368 } | 458 } |
369 | 459 |
370 MOCK_METHOD1(Checkpoint, void(int id)); | 460 MOCK_METHOD1(Checkpoint, void(int id)); |
371 | 461 |
372 struct BufferTimestamps { | 462 struct BufferTimestamps { |
373 int video_time_ms; | 463 int video_time_ms; |
374 int audio_time_ms; | 464 int audio_time_ms; |
375 }; | 465 }; |
376 static const int kSkip = -1; | 466 static const int kSkip = -1; |
377 | 467 |
378 // Test parsing a WebM file. | 468 // Test parsing a WebM file. |
379 // |filename| - The name of the file in media/test/data to parse. | 469 // |filename| - The name of the file in media/test/data to parse. |
380 // |timestamps| - The expected timestamps on the parsed buffers. | 470 // |timestamps| - The expected timestamps on the parsed buffers. |
381 // a timestamp of kSkip indicates that a Read() call for that stream | 471 // a timestamp of kSkip indicates that a Read() call for that stream |
382 // shouldn't be made on that iteration of the loop. If both streams have | 472 // shouldn't be made on that iteration of the loop. If both streams have |
383 // a kSkip then the loop will terminate. | 473 // a kSkip then the loop will terminate. |
384 bool ParseWebMFile(const std::string& filename, | 474 bool ParseWebMFile(const std::string& filename, |
385 const BufferTimestamps* timestamps, | 475 const BufferTimestamps* timestamps, |
386 const base::TimeDelta& duration) { | 476 const base::TimeDelta& duration) { |
| 477 return ParseWebMFile(filename, timestamps, duration, true, true); |
| 478 } |
| 479 |
| 480 bool ParseWebMFile(const std::string& filename, |
| 481 const BufferTimestamps* timestamps, |
| 482 const base::TimeDelta& duration, |
| 483 bool has_audio, bool has_video) { |
387 EXPECT_CALL(*client_, DemuxerOpened(_)); | 484 EXPECT_CALL(*client_, DemuxerOpened(_)); |
388 demuxer_->Initialize( | 485 demuxer_->Initialize( |
389 &host_, CreateInitDoneCB(duration, PIPELINE_OK)); | 486 &host_, CreateInitDoneCB(duration, PIPELINE_OK)); |
390 | 487 |
391 if (AddId() != ChunkDemuxer::kOk) | 488 if (AddId(kSourceId, has_audio, has_video) != ChunkDemuxer::kOk) |
392 return false; | 489 return false; |
393 | 490 |
394 // Read a WebM file into memory and send the data to the demuxer. | 491 // Read a WebM file into memory and send the data to the demuxer. |
395 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename); | 492 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename); |
396 if (!AppendDataInPieces(buffer->GetData(), buffer->GetDataSize(), 512)) | 493 if (!AppendDataInPieces(buffer->GetData(), buffer->GetDataSize(), 512)) |
397 return false; | 494 return false; |
398 | 495 |
399 scoped_refptr<DemuxerStream> audio = | 496 scoped_refptr<DemuxerStream> audio = |
400 demuxer_->GetStream(DemuxerStream::AUDIO); | 497 demuxer_->GetStream(DemuxerStream::AUDIO); |
401 scoped_refptr<DemuxerStream> video = | 498 scoped_refptr<DemuxerStream> video = |
(...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
969 struct BufferTimestamps buffer_timestamps[] = { | 1066 struct BufferTimestamps buffer_timestamps[] = { |
970 {kSkip, 0}, | 1067 {kSkip, 0}, |
971 {kSkip, 3}, | 1068 {kSkip, 3}, |
972 {kSkip, 6}, | 1069 {kSkip, 6}, |
973 {kSkip, 9}, | 1070 {kSkip, 9}, |
974 {kSkip, 12}, | 1071 {kSkip, 12}, |
975 {kSkip, kSkip}, | 1072 {kSkip, kSkip}, |
976 }; | 1073 }; |
977 | 1074 |
978 ASSERT_TRUE(ParseWebMFile("bear-320x240-audio-only.webm", buffer_timestamps, | 1075 ASSERT_TRUE(ParseWebMFile("bear-320x240-audio-only.webm", buffer_timestamps, |
979 base::TimeDelta::FromMilliseconds(2744))); | 1076 base::TimeDelta::FromMilliseconds(2744), |
| 1077 true, false)); |
980 } | 1078 } |
981 | 1079 |
982 TEST_F(ChunkDemuxerTest, TestWebMFile_VideoOnly) { | 1080 TEST_F(ChunkDemuxerTest, TestWebMFile_VideoOnly) { |
983 struct BufferTimestamps buffer_timestamps[] = { | 1081 struct BufferTimestamps buffer_timestamps[] = { |
984 {0, kSkip}, | 1082 {0, kSkip}, |
985 {33, kSkip}, | 1083 {33, kSkip}, |
986 {67, kSkip}, | 1084 {67, kSkip}, |
987 {100, kSkip}, | 1085 {100, kSkip}, |
988 {133, kSkip}, | 1086 {133, kSkip}, |
989 {kSkip, kSkip}, | 1087 {kSkip, kSkip}, |
990 }; | 1088 }; |
991 | 1089 |
992 ASSERT_TRUE(ParseWebMFile("bear-320x240-video-only.webm", buffer_timestamps, | 1090 ASSERT_TRUE(ParseWebMFile("bear-320x240-video-only.webm", buffer_timestamps, |
993 base::TimeDelta::FromMilliseconds(2703))); | 1091 base::TimeDelta::FromMilliseconds(2703), |
| 1092 false, true)); |
994 } | 1093 } |
995 | 1094 |
996 TEST_F(ChunkDemuxerTest, TestWebMFile_AltRefFrames) { | 1095 TEST_F(ChunkDemuxerTest, TestWebMFile_AltRefFrames) { |
997 struct BufferTimestamps buffer_timestamps[] = { | 1096 struct BufferTimestamps buffer_timestamps[] = { |
998 {0, 0}, | 1097 {0, 0}, |
999 {33, 3}, | 1098 {33, 3}, |
1000 {33, 6}, | 1099 {33, 6}, |
1001 {67, 9}, | 1100 {67, 9}, |
1002 {100, 12}, | 1101 {100, 12}, |
1003 {kSkip, kSkip}, | 1102 {kSkip, kSkip}, |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1129 | 1228 |
1130 // Append another identical initialization segment. | 1229 // Append another identical initialization segment. |
1131 ASSERT_TRUE(AppendInitSegment(true, true, false)); | 1230 ASSERT_TRUE(AppendInitSegment(true, true, false)); |
1132 | 1231 |
1133 scoped_ptr<Cluster> cluster_b(kDefaultSecondCluster()); | 1232 scoped_ptr<Cluster> cluster_b(kDefaultSecondCluster()); |
1134 ASSERT_TRUE(AppendData(cluster_b->data(), cluster_b->size())); | 1233 ASSERT_TRUE(AppendData(cluster_b->data(), cluster_b->size())); |
1135 | 1234 |
1136 GenerateExpectedReads(0, 9, audio, video); | 1235 GenerateExpectedReads(0, 9, audio, video); |
1137 } | 1236 } |
1138 | 1237 |
| 1238 TEST_F(ChunkDemuxerTest, TestAddSeparateSourcesForAudioAndVideo) { |
| 1239 std::string audio_id = "audio1"; |
| 1240 std::string video_id = "video1"; |
| 1241 ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id)); |
| 1242 |
| 1243 scoped_refptr<DemuxerStream> audio = |
| 1244 demuxer_->GetStream(DemuxerStream::AUDIO); |
| 1245 scoped_refptr<DemuxerStream> video = |
| 1246 demuxer_->GetStream(DemuxerStream::VIDEO); |
| 1247 |
| 1248 scoped_ptr<Cluster> cluster_a( |
| 1249 GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration)); |
| 1250 |
| 1251 scoped_ptr<Cluster> cluster_v( |
| 1252 GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration)); |
| 1253 |
| 1254 // Append audio and video data into separate source ids. |
| 1255 ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size())); |
| 1256 GenerateExpectedReads(0, 4, audio, kAudioBlockDuration); |
| 1257 ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size())); |
| 1258 GenerateExpectedReads(0, 4, video, kVideoBlockDuration); |
| 1259 } |
| 1260 |
| 1261 TEST_F(ChunkDemuxerTest, TestAddIdFailures) { |
| 1262 EXPECT_CALL(*client_, DemuxerOpened(_)); |
| 1263 demuxer_->Initialize( |
| 1264 &host_, CreateInitDoneCB(kDefaultDuration(), PIPELINE_OK)); |
| 1265 |
| 1266 std::string audio_id = "audio1"; |
| 1267 std::string video_id = "video1"; |
| 1268 |
| 1269 ASSERT_EQ(AddId(audio_id, true, false), ChunkDemuxer::kOk); |
| 1270 |
| 1271 // Adding an id with audio/video should fail because we already added audio. |
| 1272 ASSERT_EQ(AddId(), ChunkDemuxer::kReachedIdLimit); |
| 1273 |
| 1274 ASSERT_TRUE(AppendInitSegment(audio_id, true, false, false)); |
| 1275 |
| 1276 // Adding an id after append should fail. |
| 1277 ASSERT_EQ(AddId(video_id, false, true), ChunkDemuxer::kReachedIdLimit); |
| 1278 } |
| 1279 |
| 1280 // Test that Read() calls after a RemoveId() return "end of stream" buffers. |
| 1281 TEST_F(ChunkDemuxerTest, TestRemoveId) { |
| 1282 std::string audio_id = "audio1"; |
| 1283 std::string video_id = "video1"; |
| 1284 ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id)); |
| 1285 |
| 1286 scoped_ptr<Cluster> cluster_a( |
| 1287 GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration)); |
| 1288 |
| 1289 scoped_ptr<Cluster> cluster_v( |
| 1290 GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration)); |
| 1291 |
| 1292 // Append audio and video data into separate source ids. |
| 1293 ASSERT_TRUE(AppendData(audio_id, cluster_a->data(), cluster_a->size())); |
| 1294 ASSERT_TRUE(AppendData(video_id, cluster_v->data(), cluster_v->size())); |
| 1295 |
| 1296 // Read() from audio should return normal buffers. |
| 1297 scoped_refptr<DemuxerStream> audio = |
| 1298 demuxer_->GetStream(DemuxerStream::AUDIO); |
| 1299 GenerateExpectedReads(0, 4, audio, kAudioBlockDuration); |
| 1300 |
| 1301 // Remove the audio id. |
| 1302 demuxer_->RemoveId(audio_id); |
| 1303 |
| 1304 // Read() from audio should return "end of stream" buffers. |
| 1305 bool audio_read_done = false; |
| 1306 audio->Read(base::Bind(&OnReadDone_EOSExpected, |
| 1307 &audio_read_done)); |
| 1308 EXPECT_TRUE(audio_read_done); |
| 1309 |
| 1310 // Read() from video should still return normal buffers. |
| 1311 scoped_refptr<DemuxerStream> video = |
| 1312 demuxer_->GetStream(DemuxerStream::VIDEO); |
| 1313 GenerateExpectedReads(0, 4, video, kVideoBlockDuration); |
| 1314 } |
| 1315 |
| 1316 // Test that Seek() successfully seeks to all source IDs. |
| 1317 TEST_F(ChunkDemuxerTest, TestSeekAudioAndVideoSources) { |
| 1318 std::string audio_id = "audio1"; |
| 1319 std::string video_id = "video1"; |
| 1320 ASSERT_TRUE(InitDemuxerAudioAndVideoSources(audio_id, video_id)); |
| 1321 |
| 1322 scoped_ptr<Cluster> cluster_a1( |
| 1323 GenerateSingleStreamCluster(0, 4, kAudioTrackNum, kAudioBlockDuration)); |
| 1324 |
| 1325 scoped_ptr<Cluster> cluster_v1( |
| 1326 GenerateSingleStreamCluster(0, 4, kVideoTrackNum, kVideoBlockDuration)); |
| 1327 |
| 1328 ASSERT_TRUE(AppendData(audio_id, cluster_a1->data(), cluster_a1->size())); |
| 1329 ASSERT_TRUE(AppendData(video_id, cluster_v1->data(), cluster_v1->size())); |
| 1330 |
| 1331 // Read() should return buffers at 0. |
| 1332 bool audio_read_done = false; |
| 1333 bool video_read_done = false; |
| 1334 scoped_refptr<DemuxerStream> audio = |
| 1335 demuxer_->GetStream(DemuxerStream::AUDIO); |
| 1336 scoped_refptr<DemuxerStream> video = |
| 1337 demuxer_->GetStream(DemuxerStream::VIDEO); |
| 1338 |
| 1339 audio->Read(base::Bind(&OnReadDone, |
| 1340 base::TimeDelta::FromMilliseconds(0), |
| 1341 &audio_read_done)); |
| 1342 video->Read(base::Bind(&OnReadDone, |
| 1343 base::TimeDelta::FromMilliseconds(0), |
| 1344 &video_read_done)); |
| 1345 EXPECT_TRUE(audio_read_done); |
| 1346 EXPECT_TRUE(video_read_done); |
| 1347 |
| 1348 // Seek to 3 (an unbuffered region). |
| 1349 demuxer_->StartWaitingForSeek(); |
| 1350 demuxer_->Seek(base::TimeDelta::FromSeconds(3), |
| 1351 NewExpectedStatusCB(PIPELINE_OK)); |
| 1352 |
| 1353 audio_read_done = false; |
| 1354 video_read_done = false; |
| 1355 audio->Read(base::Bind(&OnReadDone, |
| 1356 base::TimeDelta::FromSeconds(3), |
| 1357 &audio_read_done)); |
| 1358 video->Read(base::Bind(&OnReadDone, |
| 1359 base::TimeDelta::FromSeconds(3), |
| 1360 &video_read_done)); |
| 1361 |
| 1362 // Read()s should not return until after data is appended at the Seek point. |
| 1363 EXPECT_FALSE(audio_read_done); |
| 1364 EXPECT_FALSE(video_read_done); |
| 1365 |
| 1366 scoped_ptr<Cluster> cluster_a2( |
| 1367 GenerateSingleStreamCluster(3000, 4, kAudioTrackNum, |
| 1368 kAudioBlockDuration)); |
| 1369 |
| 1370 scoped_ptr<Cluster> cluster_v2( |
| 1371 GenerateSingleStreamCluster(3000, 4, kVideoTrackNum, |
| 1372 kVideoBlockDuration)); |
| 1373 |
| 1374 ASSERT_TRUE(AppendData(audio_id, cluster_a2->data(), cluster_a2->size())); |
| 1375 ASSERT_TRUE(AppendData(video_id, cluster_v2->data(), cluster_v2->size())); |
| 1376 |
| 1377 // Read() should return buffers at 3. |
| 1378 EXPECT_TRUE(audio_read_done); |
| 1379 EXPECT_TRUE(video_read_done); |
| 1380 } |
| 1381 |
1139 } // namespace media | 1382 } // namespace media |
OLD | NEW |