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

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: Comments. 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
« no previous file with comments | « media/filters/ffmpeg_demuxer.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 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
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
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_demuxer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698