Chromium Code Reviews| 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 | |
| 106 MOCK_METHOD2(OnReadDoneCalled, void(int, int64)); | 118 MOCK_METHOD2(OnReadDoneCalled, void(int, int64)); |
| 107 | 119 |
| 108 // Verifies that |buffer| has a specific |size| and |timestamp|. | 120 // Verifies that |buffer| has a specific |size| and |timestamp|. |
| 109 // |location| simply indicates where the call to this function was made. | 121 // |location| simply indicates where the call to this function was made. |
| 110 // This makes it easier to track down where test failures occur. | 122 // This makes it easier to track down where test failures occur. |
| 111 void OnReadDone(const tracked_objects::Location& location, | 123 void OnReadDone(const tracked_objects::Location& location, |
| 112 int size, int64 timestampInMicroseconds, | 124 int size, |
| 125 int64 timestamp_us, | |
| 126 bool should_be_marked_for_discard, | |
| 113 DemuxerStream::Status status, | 127 DemuxerStream::Status status, |
| 114 const scoped_refptr<DecoderBuffer>& buffer) { | 128 const scoped_refptr<DecoderBuffer>& buffer) { |
| 115 std::string location_str; | 129 std::string location_str; |
| 116 location.Write(true, false, &location_str); | 130 location.Write(true, false, &location_str); |
| 117 location_str += "\n"; | 131 location_str += "\n"; |
| 118 SCOPED_TRACE(location_str); | 132 SCOPED_TRACE(location_str); |
| 119 EXPECT_EQ(status, DemuxerStream::kOk); | 133 EXPECT_EQ(status, DemuxerStream::kOk); |
| 120 OnReadDoneCalled(size, timestampInMicroseconds); | 134 OnReadDoneCalled(size, timestamp_us); |
| 121 EXPECT_TRUE(buffer.get() != NULL); | 135 EXPECT_TRUE(buffer.get() != NULL); |
| 122 EXPECT_EQ(size, buffer->data_size()); | 136 EXPECT_EQ(size, buffer->data_size()); |
| 123 EXPECT_EQ(base::TimeDelta::FromMicroseconds(timestampInMicroseconds), | 137 EXPECT_EQ(timestamp_us, buffer->timestamp().InMicroseconds()); |
| 124 buffer->timestamp()); | |
| 125 | 138 |
| 139 const base::TimeDelta expected_front_discard = | |
| 140 should_be_marked_for_discard ? kInfiniteDuration() : base::TimeDelta(); | |
| 141 EXPECT_EQ(expected_front_discard, buffer->discard_padding().first); | |
| 126 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); | 142 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); |
| 127 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); | 143 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
| 128 } | 144 } |
| 129 | 145 |
| 130 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location, | 146 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location, |
| 131 int size, int64 timestampInMicroseconds) { | 147 int size, |
| 132 EXPECT_CALL(*this, OnReadDoneCalled(size, timestampInMicroseconds)); | 148 int64 timestamp_us) { |
| 133 return base::Bind(&FFmpegDemuxerTest::OnReadDone, base::Unretained(this), | 149 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us)); |
| 134 location, size, timestampInMicroseconds); | 150 return base::Bind(&FFmpegDemuxerTest::OnReadDone, |
| 151 base::Unretained(this), | |
| 152 location, | |
| 153 size, | |
| 154 timestamp_us, | |
| 155 false); | |
| 156 } | |
| 157 | |
| 158 DemuxerStream::ReadCB NewReadCBWithCheckedDiscard( | |
| 159 const tracked_objects::Location& location, | |
| 160 int size, | |
| 161 int64 timestamp_us) { | |
| 162 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us)); | |
| 163 return base::Bind(&FFmpegDemuxerTest::OnReadDone, | |
| 164 base::Unretained(this), | |
| 165 location, | |
| 166 size, | |
| 167 timestamp_us, | |
| 168 true); | |
| 135 } | 169 } |
| 136 | 170 |
| 137 // TODO(xhwang): This is a workaround of the issue that move-only parameters | 171 // 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 | 172 // 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 | 173 // (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). | 174 // std::string instead of scoped_ptr<uint8[]> (http://crbug.com/130689). |
| 141 MOCK_METHOD3(NeedKeyCBMock, void(const std::string& type, | 175 MOCK_METHOD3(NeedKeyCBMock, void(const std::string& type, |
| 142 const uint8* init_data, int init_data_size)); | 176 const uint8* init_data, int init_data_size)); |
| 143 void NeedKeyCB(const std::string& type, | 177 void NeedKeyCB(const std::string& type, |
| 144 const std::vector<uint8>& init_data) { | 178 const std::vector<uint8>& init_data) { |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 379 ASSERT_TRUE(text_stream); | 413 ASSERT_TRUE(text_stream); |
| 380 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); | 414 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); |
| 381 | 415 |
| 382 text_stream->Read(NewReadCB(FROM_HERE, 31, 0)); | 416 text_stream->Read(NewReadCB(FROM_HERE, 31, 0)); |
| 383 message_loop_.Run(); | 417 message_loop_.Run(); |
| 384 | 418 |
| 385 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000)); | 419 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000)); |
| 386 message_loop_.Run(); | 420 message_loop_.Run(); |
| 387 } | 421 } |
| 388 | 422 |
| 389 TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) { | 423 TEST_F(FFmpegDemuxerTest, Read_VideoPositiveStartTime) { |
| 424 const char kTimelineOffset[] = "2012-11-10 12:34:56"; | |
| 425 const int64 kTimelineOffsetMs = 1352550896000LL; | |
| 426 | |
| 390 // Test the start time is the first timestamp of the video and audio stream. | 427 // Test the start time is the first timestamp of the video and audio stream. |
| 391 CreateDemuxer("nonzero-start-time.webm"); | 428 CreateDemuxer("nonzero-start-time.webm"); |
| 392 InitializeDemuxer(); | 429 InitializeDemuxerWithTimelineOffset(kTimelineOffset); |
| 393 | 430 |
| 394 // Attempt a read from the video stream and run the message loop until done. | 431 // Attempt a read from the video stream and run the message loop until done. |
| 395 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); | 432 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); |
| 396 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); | 433 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); |
| 397 | 434 |
| 398 // Check first buffer in video stream. | 435 const base::TimeDelta video_start_time = |
| 399 video->Read(NewReadCB(FROM_HERE, 5636, 400000)); | 436 base::TimeDelta::FromMicroseconds(400000); |
| 437 const base::TimeDelta audio_start_time = | |
| 438 base::TimeDelta::FromMicroseconds(396000); | |
| 439 | |
| 440 // Run the test twice with a seek in between. | |
| 441 for (int i = 0; i < 2; ++i) { | |
| 442 // Check first buffer in video stream. It should have been adjusted such | |
| 443 // that | |
| 444 // it starts 400ms after the first audio buffer. | |
| 445 video->Read( | |
| 446 NewReadCB(FROM_HERE, | |
| 447 5636, | |
| 448 (video_start_time - audio_start_time).InMicroseconds())); | |
| 449 message_loop_.Run(); | |
| 450 | |
| 451 // Since the audio buffer has a lower first timestamp, it should become | |
| 452 // zero. | |
| 453 audio->Read(NewReadCB(FROM_HERE, 165, 0)); | |
| 454 message_loop_.Run(); | |
| 455 | |
| 456 // Verify that the start time is equal to the lowest timestamp (ie the | |
| 457 // audio). | |
| 458 EXPECT_EQ(audio_start_time, demuxer_->start_time()); | |
| 459 | |
| 460 // Verify that the timeline offset has been adjusted by the start time. | |
| 461 EXPECT_EQ(kTimelineOffsetMs + audio_start_time.InMilliseconds(), | |
| 462 demuxer_->GetTimelineOffset().ToJavaTime()); | |
| 463 | |
| 464 // Seek back to the beginning and repeat the test. | |
| 465 WaitableMessageLoopEvent event; | |
| 466 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB()); | |
| 467 event.RunAndWaitForStatus(PIPELINE_OK); | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 TEST_F(FFmpegDemuxerTest, Read_AudioNoStartTime) { | |
| 472 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the | |
| 473 // demuxer sets a start time of zero in this case. | |
| 474 CreateDemuxer("sfx_s24le.wav"); | |
| 475 InitializeDemuxer(); | |
| 476 | |
| 477 // Run the test twice with a seek in between. | |
| 478 for (int i = 0; i < 2; ++i) { | |
| 479 demuxer_->GetStream(DemuxerStream::AUDIO) | |
| 480 ->Read(NewReadCB(FROM_HERE, 4095, 0)); | |
| 481 message_loop_.Run(); | |
| 482 EXPECT_EQ(base::TimeDelta(), demuxer_->start_time()); | |
| 483 | |
| 484 // Seek back to the beginning and repeat the test. | |
| 485 WaitableMessageLoopEvent event; | |
| 486 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB()); | |
| 487 event.RunAndWaitForStatus(PIPELINE_OK); | |
| 488 } | |
| 489 } | |
| 490 | |
| 491 TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOggDiscard) { | |
| 492 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the | |
|
acolwell GONE FROM CHROMIUM
2014/06/10 23:20:38
nit: Fix the comment since it talks about wave, bu
DaleCurtis
2014/06/12 00:21:56
Done.
| |
| 493 // demuxer sets a start time of zero in this case. | |
| 494 CreateDemuxer("bear.ogv"); | |
| 495 InitializeDemuxer(); | |
| 496 demuxer_->GetStream(DemuxerStream::AUDIO) | |
| 497 ->Read(NewReadCBWithCheckedDiscard(FROM_HERE, 40, 0)); | |
| 498 message_loop_.Run(); | |
| 499 demuxer_->GetStream(DemuxerStream::AUDIO) | |
| 500 ->Read(NewReadCBWithCheckedDiscard(FROM_HERE, 41, 0)); | |
| 400 message_loop_.Run(); | 501 message_loop_.Run(); |
| 401 | 502 |
| 402 // Check first buffer in audio stream. | 503 // TODO(dalecurtis): This negative timestamp is incorrect and due to an |
| 403 audio->Read(NewReadCB(FROM_HERE, 165, 396000)); | 504 // upstream bug: https://trac.ffmpeg.org/ticket/3710. Once fixed this |
| 505 // test should have only positive timestamps and should pass a seek test | |
| 506 // similar to the positive and zero start time tests. | |
|
acolwell GONE FROM CHROMIUM
2014/06/10 23:20:38
Shouldn't we resolve this before landing this chan
DaleCurtis
2014/06/11 16:59:07
http://git.videolan.org/?p=ffmpeg.git;a=blobdiff;f
| |
| 507 demuxer_->GetStream(DemuxerStream::AUDIO) | |
| 508 ->Read(NewReadCBWithCheckedDiscard(FROM_HERE, 173, -7257)); | |
| 404 message_loop_.Run(); | 509 message_loop_.Run(); |
| 405 | 510 |
| 406 // Verify that the start time is equal to the lowest timestamp (ie the audio). | 511 demuxer_->GetStream(DemuxerStream::AUDIO) |
| 407 EXPECT_EQ(demuxer_->GetStartTime().InMicroseconds(), 396000); | 512 ->Read(NewReadCB(FROM_HERE, 148, 5804)); |
| 513 message_loop_.Run(); | |
| 514 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-2902), demuxer_->start_time()); | |
| 408 } | 515 } |
| 409 | 516 |
| 410 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { | 517 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { |
| 411 // Verify that end of stream buffers are created. | 518 // Verify that end of stream buffers are created. |
| 412 CreateDemuxer("bear-320x240.webm"); | 519 CreateDemuxer("bear-320x240.webm"); |
| 413 InitializeDemuxer(); | 520 InitializeDemuxer(); |
| 414 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); | 521 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); |
| 415 } | 522 } |
| 416 | 523 |
| 417 TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) { | 524 TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) { |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 demuxer_->Stop(event.GetClosure()); | 850 demuxer_->Stop(event.GetClosure()); |
| 744 event.RunAndWait(); | 851 event.RunAndWait(); |
| 745 demuxer_.reset(); | 852 demuxer_.reset(); |
| 746 data_source_.reset(); | 853 data_source_.reset(); |
| 747 } | 854 } |
| 748 } | 855 } |
| 749 | 856 |
| 750 #endif | 857 #endif |
| 751 | 858 |
| 752 } // namespace media | 859 } // namespace media |
| OLD | NEW |