Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: media/filters/ffmpeg_demuxer_unittest.cc

Issue 335273002: Fix seeking when the start time is non-zero. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Remove vector. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
436 // it starts 400ms after the first audio buffer.
437 video->Read(
438 NewReadCB(FROM_HERE,
439 5636,
440 (video_start_time - audio_start_time).InMicroseconds()));
441 message_loop_.Run();
405 442
406 // Verify that the start time is equal to the lowest timestamp (ie the audio). 443 // Since the audio buffer has a lower first timestamp, it should become
407 EXPECT_EQ(demuxer_->GetStartTime().InMicroseconds(), 396000); 444 // zero.
445 audio->Read(NewReadCB(FROM_HERE, 165, 0));
446 message_loop_.Run();
447
448 // Verify that the start time is equal to the lowest timestamp (ie the
449 // audio).
450 EXPECT_EQ(audio_start_time, demuxer_->start_time());
451
452 // Verify that the timeline offset has been adjusted by the start time.
453 EXPECT_EQ(kTimelineOffsetMs + audio_start_time.InMilliseconds(),
454 demuxer_->GetTimelineOffset().ToJavaTime());
455
456 // Seek back to the beginning and repeat the test.
457 WaitableMessageLoopEvent event;
458 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
459 event.RunAndWaitForStatus(PIPELINE_OK);
460 }
461 }
462
463 TEST_F(FFmpegDemuxerTest, Read_AudioNoStartTime) {
464 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the
465 // demuxer sets a start time of zero in this case.
466 CreateDemuxer("sfx_s24le.wav");
467 InitializeDemuxer();
468
469 // Run the test twice with a seek in between.
470 for (int i = 0; i < 2; ++i) {
471 demuxer_->GetStream(DemuxerStream::AUDIO)
472 ->Read(NewReadCB(FROM_HERE, 4095, 0));
473 message_loop_.Run();
474 EXPECT_EQ(base::TimeDelta(), demuxer_->start_time());
475
476 // Seek back to the beginning and repeat the test.
477 WaitableMessageLoopEvent event;
478 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
479 event.RunAndWaitForStatus(PIPELINE_OK);
480 }
481 }
482
483 TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOggDiscard) {
484 // Many ogg files have negative starting timestamps, so ensure demuxing and
485 // seeking work correctly with a negative start time.
486 CreateDemuxer("bear.ogv");
487 InitializeDemuxer();
488
489 // Run the test twice with a seek in between.
490 for (int i = 0; i < 2; ++i) {
491 demuxer_->GetStream(DemuxerStream::AUDIO)->Read(
492 NewReadCBWithCheckedDiscard(FROM_HERE, 40, 0, kInfiniteDuration()));
493 message_loop_.Run();
494 demuxer_->GetStream(DemuxerStream::AUDIO)->Read(
495 NewReadCBWithCheckedDiscard(FROM_HERE, 41, 2903, kInfiniteDuration()));
496 message_loop_.Run();
497 demuxer_->GetStream(DemuxerStream::AUDIO)->Read(NewReadCBWithCheckedDiscard(
498 FROM_HERE, 173, 5805, base::TimeDelta::FromMicroseconds(10159)));
499 message_loop_.Run();
500
501 demuxer_->GetStream(DemuxerStream::AUDIO)
502 ->Read(NewReadCB(FROM_HERE, 148, 18866));
503 message_loop_.Run();
504 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964),
505 demuxer_->start_time());
506
507 // Seek back to the beginning and repeat the test.
508 WaitableMessageLoopEvent event;
509 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
510 event.RunAndWaitForStatus(PIPELINE_OK);
511 }
408 } 512 }
409 513
410 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { 514 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) {
411 // Verify that end of stream buffers are created. 515 // Verify that end of stream buffers are created.
412 CreateDemuxer("bear-320x240.webm"); 516 CreateDemuxer("bear-320x240.webm");
413 InitializeDemuxer(); 517 InitializeDemuxer();
414 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 518 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
415 } 519 }
416 520
417 TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) { 521 TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) {
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 demuxer_->Stop(event.GetClosure()); 847 demuxer_->Stop(event.GetClosure());
744 event.RunAndWait(); 848 event.RunAndWait();
745 demuxer_.reset(); 849 demuxer_.reset();
746 data_source_.reset(); 850 data_source_.reset();
747 } 851 }
748 } 852 }
749 853
750 #endif 854 #endif
751 855
752 } // namespace media 856 } // namespace media
OLDNEW
« media/filters/ffmpeg_demuxer.cc ('K') | « media/filters/ffmpeg_demuxer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698