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 <algorithm> | 5 #include <algorithm> |
6 #include <deque> | 6 #include <deque> |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 EXPECT_CALL(host_, SetDuration(_)); | 96 EXPECT_CALL(host_, SetDuration(_)); |
97 WaitableMessageLoopEvent event; | 97 WaitableMessageLoopEvent event; |
98 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), enable_text); | 98 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), enable_text); |
99 event.RunAndWaitForStatus(PIPELINE_OK); | 99 event.RunAndWaitForStatus(PIPELINE_OK); |
100 } | 100 } |
101 | 101 |
102 void InitializeDemuxer() { | 102 void InitializeDemuxer() { |
103 InitializeDemuxerText(false); | 103 InitializeDemuxerText(false); |
104 } | 104 } |
105 | 105 |
106 void InitializeDemuxerWithTimelineOffset(const char* utc_date) { | |
107 EXPECT_CALL(host_, SetDuration(_)); | |
108 WaitableMessageLoopEvent event; | |
109 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), false); | |
110 // Inject the timeline offset into the FFmpeg metadata dictionary. | |
111 av_dict_set(&demuxer_->glue_->format_context()->metadata, | |
112 "creation_time", | |
113 utc_date, | |
114 0); | |
115 event.RunAndWaitForStatus(PIPELINE_OK); | |
116 } | |
117 | |
118 MOCK_METHOD2(OnReadDoneCalled, void(int, int64)); | 106 MOCK_METHOD2(OnReadDoneCalled, void(int, int64)); |
119 | 107 |
120 // Verifies that |buffer| has a specific |size| and |timestamp|. | 108 // Verifies that |buffer| has a specific |size| and |timestamp|. |
121 // |location| simply indicates where the call to this function was made. | 109 // |location| simply indicates where the call to this function was made. |
122 // This makes it easier to track down where test failures occur. | 110 // This makes it easier to track down where test failures occur. |
123 void OnReadDone(const tracked_objects::Location& location, | 111 void OnReadDone(const tracked_objects::Location& location, |
124 int size, | 112 int size, int64 timestampInMicroseconds, |
125 int64 timestamp_us, | |
126 base::TimeDelta discard_front_padding, | |
127 DemuxerStream::Status status, | 113 DemuxerStream::Status status, |
128 const scoped_refptr<DecoderBuffer>& buffer) { | 114 const scoped_refptr<DecoderBuffer>& buffer) { |
129 std::string location_str; | 115 std::string location_str; |
130 location.Write(true, false, &location_str); | 116 location.Write(true, false, &location_str); |
131 location_str += "\n"; | 117 location_str += "\n"; |
132 SCOPED_TRACE(location_str); | 118 SCOPED_TRACE(location_str); |
133 EXPECT_EQ(status, DemuxerStream::kOk); | 119 EXPECT_EQ(status, DemuxerStream::kOk); |
134 OnReadDoneCalled(size, timestamp_us); | 120 OnReadDoneCalled(size, timestampInMicroseconds); |
135 EXPECT_TRUE(buffer.get() != NULL); | 121 EXPECT_TRUE(buffer.get() != NULL); |
136 EXPECT_EQ(size, buffer->data_size()); | 122 EXPECT_EQ(size, buffer->data_size()); |
137 EXPECT_EQ(timestamp_us, buffer->timestamp().InMicroseconds()); | 123 EXPECT_EQ(base::TimeDelta::FromMicroseconds(timestampInMicroseconds), |
138 EXPECT_EQ(discard_front_padding, buffer->discard_padding().first); | 124 buffer->timestamp()); |
| 125 |
139 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); | 126 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); |
140 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | 127 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
141 } | 128 } |
142 | 129 |
143 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location, | 130 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location, |
144 int size, | 131 int size, int64 timestampInMicroseconds) { |
145 int64 timestamp_us) { | 132 EXPECT_CALL(*this, OnReadDoneCalled(size, timestampInMicroseconds)); |
146 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us)); | 133 return base::Bind(&FFmpegDemuxerTest::OnReadDone, base::Unretained(this), |
147 return base::Bind(&FFmpegDemuxerTest::OnReadDone, | 134 location, size, timestampInMicroseconds); |
148 base::Unretained(this), | |
149 location, | |
150 size, | |
151 timestamp_us, | |
152 base::TimeDelta()); | |
153 } | |
154 | |
155 DemuxerStream::ReadCB NewReadCBWithCheckedDiscard( | |
156 const tracked_objects::Location& location, | |
157 int size, | |
158 int64 timestamp_us, | |
159 base::TimeDelta discard_front_padding) { | |
160 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us)); | |
161 return base::Bind(&FFmpegDemuxerTest::OnReadDone, | |
162 base::Unretained(this), | |
163 location, | |
164 size, | |
165 timestamp_us, | |
166 discard_front_padding); | |
167 } | 135 } |
168 | 136 |
169 // TODO(xhwang): This is a workaround of the issue that move-only parameters | 137 // TODO(xhwang): This is a workaround of the issue that move-only parameters |
170 // are not supported in mocked methods. Remove this when the issue is fixed | 138 // are not supported in mocked methods. Remove this when the issue is fixed |
171 // (http://code.google.com/p/googletest/issues/detail?id=395) or when we use | 139 // (http://code.google.com/p/googletest/issues/detail?id=395) or when we use |
172 // std::string instead of scoped_ptr<uint8[]> (http://crbug.com/130689). | 140 // std::string instead of scoped_ptr<uint8[]> (http://crbug.com/130689). |
173 MOCK_METHOD3(NeedKeyCBMock, void(const std::string& type, | 141 MOCK_METHOD3(NeedKeyCBMock, void(const std::string& type, |
174 const uint8* init_data, int init_data_size)); | 142 const uint8* init_data, int init_data_size)); |
175 void NeedKeyCB(const std::string& type, | 143 void NeedKeyCB(const std::string& type, |
176 const std::vector<uint8>& init_data) { | 144 const std::vector<uint8>& init_data) { |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
411 ASSERT_TRUE(text_stream); | 379 ASSERT_TRUE(text_stream); |
412 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); | 380 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); |
413 | 381 |
414 text_stream->Read(NewReadCB(FROM_HERE, 31, 0)); | 382 text_stream->Read(NewReadCB(FROM_HERE, 31, 0)); |
415 message_loop_.Run(); | 383 message_loop_.Run(); |
416 | 384 |
417 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000)); | 385 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000)); |
418 message_loop_.Run(); | 386 message_loop_.Run(); |
419 } | 387 } |
420 | 388 |
421 TEST_F(FFmpegDemuxerTest, Read_VideoPositiveStartTime) { | 389 TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) { |
422 const char kTimelineOffset[] = "2012-11-10 12:34:56"; | |
423 const int64 kTimelineOffsetMs = 1352550896000LL; | |
424 | |
425 // Test the start time is the first timestamp of the video and audio stream. | 390 // Test the start time is the first timestamp of the video and audio stream. |
426 CreateDemuxer("nonzero-start-time.webm"); | 391 CreateDemuxer("nonzero-start-time.webm"); |
427 InitializeDemuxerWithTimelineOffset(kTimelineOffset); | 392 InitializeDemuxer(); |
428 | 393 |
429 // Attempt a read from the video stream and run the message loop until done. | 394 // Attempt a read from the video stream and run the message loop until done. |
430 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); | 395 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); |
431 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); | 396 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); |
432 | 397 |
433 const base::TimeDelta video_start_time = | 398 // Check first buffer in video stream. |
434 base::TimeDelta::FromMicroseconds(400000); | 399 video->Read(NewReadCB(FROM_HERE, 5636, 400000)); |
435 const base::TimeDelta audio_start_time = | 400 message_loop_.Run(); |
436 base::TimeDelta::FromMicroseconds(396000); | |
437 | 401 |
438 // Run the test twice with a seek in between. | 402 // Check first buffer in audio stream. |
439 for (int i = 0; i < 2; ++i) { | 403 audio->Read(NewReadCB(FROM_HERE, 165, 396000)); |
440 // Check first buffer in video stream. It should have been adjusted such | 404 message_loop_.Run(); |
441 // that | |
442 // it starts 400ms after the first audio buffer. | |
443 video->Read( | |
444 NewReadCB(FROM_HERE, | |
445 5636, | |
446 (video_start_time - audio_start_time).InMicroseconds())); | |
447 message_loop_.Run(); | |
448 | 405 |
449 // Since the audio buffer has a lower first timestamp, it should become | 406 // Verify that the start time is equal to the lowest timestamp (ie the audio). |
450 // zero. | 407 EXPECT_EQ(demuxer_->GetStartTime().InMicroseconds(), 396000); |
451 audio->Read(NewReadCB(FROM_HERE, 165, 0)); | |
452 message_loop_.Run(); | |
453 | |
454 // Verify that the start time is equal to the lowest timestamp (ie the | |
455 // audio). | |
456 EXPECT_EQ(audio_start_time, demuxer_->start_time()); | |
457 | |
458 // Verify that the timeline offset has been adjusted by the start time. | |
459 EXPECT_EQ(kTimelineOffsetMs + audio_start_time.InMilliseconds(), | |
460 demuxer_->GetTimelineOffset().ToJavaTime()); | |
461 | |
462 // Seek back to the beginning and repeat the test. | |
463 WaitableMessageLoopEvent event; | |
464 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB()); | |
465 event.RunAndWaitForStatus(PIPELINE_OK); | |
466 } | |
467 } | |
468 | |
469 TEST_F(FFmpegDemuxerTest, Read_AudioNoStartTime) { | |
470 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the | |
471 // demuxer sets a start time of zero in this case. | |
472 CreateDemuxer("sfx_s24le.wav"); | |
473 InitializeDemuxer(); | |
474 | |
475 // Run the test twice with a seek in between. | |
476 for (int i = 0; i < 2; ++i) { | |
477 demuxer_->GetStream(DemuxerStream::AUDIO) | |
478 ->Read(NewReadCB(FROM_HERE, 4095, 0)); | |
479 message_loop_.Run(); | |
480 EXPECT_EQ(base::TimeDelta(), demuxer_->start_time()); | |
481 | |
482 // Seek back to the beginning and repeat the test. | |
483 WaitableMessageLoopEvent event; | |
484 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB()); | |
485 event.RunAndWaitForStatus(PIPELINE_OK); | |
486 } | |
487 } | |
488 | |
489 TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOggDiscard) { | |
490 // Many ogg files have negative starting timestamps, so ensure demuxing and | |
491 // seeking work correctly with a negative start time. | |
492 CreateDemuxer("bear.ogv"); | |
493 InitializeDemuxer(); | |
494 | |
495 // Run the test twice with a seek in between. | |
496 for (int i = 0; i < 2; ++i) { | |
497 demuxer_->GetStream(DemuxerStream::AUDIO)->Read( | |
498 NewReadCBWithCheckedDiscard(FROM_HERE, 40, 0, kInfiniteDuration())); | |
499 message_loop_.Run(); | |
500 demuxer_->GetStream(DemuxerStream::AUDIO)->Read( | |
501 NewReadCBWithCheckedDiscard(FROM_HERE, 41, 2903, kInfiniteDuration())); | |
502 message_loop_.Run(); | |
503 demuxer_->GetStream(DemuxerStream::AUDIO)->Read(NewReadCBWithCheckedDiscard( | |
504 FROM_HERE, 173, 5805, base::TimeDelta::FromMicroseconds(10159))); | |
505 message_loop_.Run(); | |
506 | |
507 demuxer_->GetStream(DemuxerStream::AUDIO) | |
508 ->Read(NewReadCB(FROM_HERE, 148, 18866)); | |
509 message_loop_.Run(); | |
510 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964), | |
511 demuxer_->start_time()); | |
512 | |
513 // Seek back to the beginning and repeat the test. | |
514 WaitableMessageLoopEvent event; | |
515 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB()); | |
516 event.RunAndWaitForStatus(PIPELINE_OK); | |
517 } | |
518 } | 408 } |
519 | 409 |
520 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { | 410 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { |
521 // Verify that end of stream buffers are created. | 411 // Verify that end of stream buffers are created. |
522 CreateDemuxer("bear-320x240.webm"); | 412 CreateDemuxer("bear-320x240.webm"); |
523 InitializeDemuxer(); | 413 InitializeDemuxer(); |
524 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); | 414 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); |
525 } | 415 } |
526 | 416 |
527 TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) { | 417 TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) { |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
853 demuxer_->Stop(event.GetClosure()); | 743 demuxer_->Stop(event.GetClosure()); |
854 event.RunAndWait(); | 744 event.RunAndWait(); |
855 demuxer_.reset(); | 745 demuxer_.reset(); |
856 data_source_.reset(); | 746 data_source_.reset(); |
857 } | 747 } |
858 } | 748 } |
859 | 749 |
860 #endif | 750 #endif |
861 | 751 |
862 } // namespace media | 752 } // namespace media |
OLD | NEW |