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