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
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6 #include <stdint.h>
7
8 #include <algorithm>
9 #include <string>
10 #include <utility>
11
12 #include "base/bind.h"
13 #include "base/callback_forward.h"
14 #include "base/files/file_path.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/path_service.h"
18 #include "base/run_loop.h"
19 #include "base/single_thread_task_runner.h"
20 #include "base/stl_util.h"
21 #include "base/test/mock_callback.h"
22 #include "base/test/task_environment.h"
23 #include "base/threading/thread.h"
24 #include "base/threading/thread_task_runner_handle.h"
25 #include "build/build_config.h"
26 #include "media/base/decrypt_config.h"
27 #include "media/base/demuxer_stream.h"
28 #include "media/base/media_client.h"
29 #include "media/base/media_tracks.h"
30 #include "media/base/media_util.h"
31 #include "media/base/mock_demuxer_host.h"
32 #include "media/base/mock_filters.h"
33 #include "media/base/mock_media_log.h"
34 #include "media/base/test_helpers.h"
35 #include "media/base/timestamp_constants.h"
36 #include "media/ffmpeg/ffmpeg_common.h"
37 #include "media/filters/ffmpeg_demuxer.h"
38 #include "media/filters/file_data_source.h"
39 #include "media/formats/mp4/avc.h"
40 #include "media/formats/mp4/bitstream_converter.h"
41 #include "media/media_buildflags.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43 #include "ui/gfx/color_space.h"
44
45 using ::testing::_;
46 using ::testing::AnyNumber;
47 using ::testing::DoAll;
48 using ::testing::Eq;
49 using ::testing::Exactly;
50 using ::testing::InSequence;
51 using ::testing::Invoke;
52 using ::testing::NotNull;
53 using ::testing::Return;
54 using ::testing::SaveArg;
55 using ::testing::SetArgPointee;
56 using ::testing::StrictMock;
57 using ::testing::WithArgs;
58
59 namespace media {
60
61 MATCHER(IsEndOfStreamBuffer,
62 std::string(negation ? "isn't" : "is") + " end of stream") {
63 return arg->end_of_stream();
64 }
65
66 // This does not verify any of the codec parameters that may be included in the
67 // log entry.
68 MATCHER_P(SimpleCreatedFFmpegDemuxerStream, stream_type, "") {
69 return CONTAINS_STRING(arg, "\"info\":\"FFmpegDemuxer: created " +
70 std::string(stream_type) +
71 " stream, config codec:");
72 }
73
74 MATCHER_P(FailedToCreateValidDecoderConfigFromStream, stream_type, "") {
75 return CONTAINS_STRING(
76 arg,
77 "\"debug\":\"Warning, FFmpegDemuxer failed to create a "
78 "valid/supported " +
79 std::string(stream_type) +
80 " decoder configuration from muxed stream");
81 }
82
83 MATCHER_P(SkippingUnsupportedStream, stream_type, "") {
84 return CONTAINS_STRING(
85 arg, "\"info\":\"FFmpegDemuxer: skipping invalid or unsupported " +
86 std::string(stream_type) + " track");
87 }
88
89 const uint8_t kEncryptedMediaInitData[] = {
90 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
91 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
92 };
93
EosOnReadDone(bool * got_eos_buffer,DemuxerStream::Status status,scoped_refptr<DecoderBuffer> buffer)94 static void EosOnReadDone(bool* got_eos_buffer,
95 DemuxerStream::Status status,
96 scoped_refptr<DecoderBuffer> buffer) {
97 base::ThreadTaskRunnerHandle::Get()->PostTask(
98 FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
99
100 EXPECT_EQ(status, DemuxerStream::kOk);
101 if (buffer->end_of_stream()) {
102 *got_eos_buffer = true;
103 return;
104 }
105
106 EXPECT_TRUE(buffer->data());
107 EXPECT_GT(buffer->data_size(), 0u);
108 *got_eos_buffer = false;
109 }
110
111 // Fixture class to facilitate writing tests. Takes care of setting up the
112 // FFmpeg, pipeline and filter host mocks.
113 class FFmpegDemuxerTest : public testing::Test {
114 protected:
115 FFmpegDemuxerTest() = default;
116
~FFmpegDemuxerTest()117 ~FFmpegDemuxerTest() override { Shutdown(); }
118
Shutdown()119 void Shutdown() {
120 if (demuxer_)
121 demuxer_->Stop();
122 demuxer_.reset();
123 task_environment_.RunUntilIdle();
124 data_source_.reset();
125 }
126
127 // TODO(wolenetz): Combine with CreateDemuxer() and expand coverage of all of
128 // these tests to use strict media log. See https://crbug.com/749178.
CreateDemuxerWithStrictMediaLog(const std::string & name)129 void CreateDemuxerWithStrictMediaLog(const std::string& name) {
130 CreateDemuxerInternal(name, &media_log_);
131 }
132
CreateDemuxer(const std::string & name)133 void CreateDemuxer(const std::string& name) {
134 CreateDemuxerInternal(name, &dummy_media_log_);
135 }
136
GetStream(DemuxerStream::Type type)137 DemuxerStream* GetStream(DemuxerStream::Type type) {
138 std::vector<DemuxerStream*> streams = demuxer_->GetAllStreams();
139 for (auto* stream : streams) {
140 if (stream->type() == type)
141 return stream;
142 }
143 return nullptr;
144 }
145
146 MOCK_METHOD1(CheckPoint, void(int v));
147
InitializeDemuxerInternal(media::PipelineStatus expected_pipeline_status,base::Time timeline_offset)148 void InitializeDemuxerInternal(media::PipelineStatus expected_pipeline_status,
149 base::Time timeline_offset) {
150 if (expected_pipeline_status == PIPELINE_OK)
151 EXPECT_CALL(host_, SetDuration(_)).Times(AnyNumber());
152 WaitableMessageLoopEvent event;
153 demuxer_->Initialize(&host_, event.GetPipelineStatusCB());
154 demuxer_->timeline_offset_ = timeline_offset;
155 event.RunAndWaitForStatus(expected_pipeline_status);
156 }
157
InitializeDemuxer()158 void InitializeDemuxer() {
159 InitializeDemuxerInternal(PIPELINE_OK, base::Time());
160 }
161
InitializeDemuxerWithTimelineOffset(base::Time timeline_offset)162 void InitializeDemuxerWithTimelineOffset(base::Time timeline_offset) {
163 InitializeDemuxerInternal(PIPELINE_OK, timeline_offset);
164 }
165
InitializeDemuxerAndExpectPipelineStatus(media::PipelineStatus expected_pipeline_status)166 void InitializeDemuxerAndExpectPipelineStatus(
167 media::PipelineStatus expected_pipeline_status) {
168 InitializeDemuxerInternal(expected_pipeline_status, base::Time());
169 }
170
SeekOnVideoTrackChangePassthrough(base::TimeDelta time,base::OnceCallback<void (DemuxerStream::Type,const std::vector<DemuxerStream * > &)> cb,DemuxerStream::Type type,const std::vector<DemuxerStream * > & streams)171 void SeekOnVideoTrackChangePassthrough(
172 base::TimeDelta time,
173 base::OnceCallback<void(DemuxerStream::Type,
174 const std::vector<DemuxerStream*>&)> cb,
175 DemuxerStream::Type type,
176 const std::vector<DemuxerStream*>& streams) {
177 // The tests can't access private methods directly because gtest uses
178 // some magic macros that break the 'friend' declaration.
179 demuxer_->SeekOnVideoTrackChange(time, std::move(cb), type, streams);
180 }
181
182 MOCK_METHOD2(OnReadDoneCalled, void(int, int64_t));
183
184 struct ReadExpectation {
ReadExpectationmedia::FFmpegDemuxerTest::ReadExpectation185 ReadExpectation(size_t size,
186 int64_t timestamp_us,
187 base::TimeDelta discard_front_padding,
188 bool is_key_frame,
189 DemuxerStream::Status status)
190 : size(size),
191 timestamp_us(timestamp_us),
192 discard_front_padding(discard_front_padding),
193 is_key_frame(is_key_frame),
194 status(status) {}
195
196 size_t size;
197 int64_t timestamp_us;
198 base::TimeDelta discard_front_padding;
199 bool is_key_frame;
200 DemuxerStream::Status status;
201 };
202
203 // Verifies that |buffer| has a specific |size| and |timestamp|.
204 // |location| simply indicates where the call to this function was made.
205 // This makes it easier to track down where test failures occur.
OnReadDone(const base::Location & location,const ReadExpectation & read_expectation,base::OnceClosure quit_closure,DemuxerStream::Status status,scoped_refptr<DecoderBuffer> buffer)206 void OnReadDone(const base::Location& location,
207 const ReadExpectation& read_expectation,
208 base::OnceClosure quit_closure,
209 DemuxerStream::Status status,
210 scoped_refptr<DecoderBuffer> buffer) {
211 std::string location_str = location.ToString();
212 location_str += "\n";
213 SCOPED_TRACE(location_str);
214 EXPECT_EQ(read_expectation.status, status);
215 if (status == DemuxerStream::kOk) {
216 EXPECT_TRUE(buffer);
217 EXPECT_EQ(read_expectation.size, buffer->data_size());
218 EXPECT_EQ(read_expectation.timestamp_us,
219 buffer->timestamp().InMicroseconds());
220 EXPECT_EQ(read_expectation.discard_front_padding,
221 buffer->discard_padding().first);
222 EXPECT_EQ(read_expectation.is_key_frame, buffer->is_key_frame());
223 }
224 OnReadDoneCalled(read_expectation.size, read_expectation.timestamp_us);
225 std::move(quit_closure).Run();
226 }
227
NewReadCBWithCheckedDiscard(const base::Location & location,int size,int64_t timestamp_us,base::TimeDelta discard_front_padding,bool is_key_frame,DemuxerStream::Status status,base::OnceClosure quit_closure)228 DemuxerStream::ReadCB NewReadCBWithCheckedDiscard(
229 const base::Location& location,
230 int size,
231 int64_t timestamp_us,
232 base::TimeDelta discard_front_padding,
233 bool is_key_frame,
234 DemuxerStream::Status status,
235 base::OnceClosure quit_closure) {
236 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us));
237
238 struct ReadExpectation read_expectation(
239 size, timestamp_us, discard_front_padding, is_key_frame, status);
240
241 return base::BindOnce(&FFmpegDemuxerTest::OnReadDone,
242 base::Unretained(this), location, read_expectation,
243 std::move(quit_closure));
244 }
245
Read(DemuxerStream * stream,const base::Location & location,int size,int64_t timestamp_us,bool is_key_frame,DemuxerStream::Status status=DemuxerStream::Status::kOk,base::TimeDelta discard_front_padding=base::TimeDelta ())246 void Read(DemuxerStream* stream,
247 const base::Location& location,
248 int size,
249 int64_t timestamp_us,
250 bool is_key_frame,
251 DemuxerStream::Status status = DemuxerStream::Status::kOk,
252 base::TimeDelta discard_front_padding = base::TimeDelta()) {
253 base::RunLoop run_loop;
254 stream->Read(NewReadCBWithCheckedDiscard(
255 location, size, timestamp_us, discard_front_padding, is_key_frame,
256 status, run_loop.QuitClosure()));
257 run_loop.Run();
258
259 // Ensure tasks posted after the ReadCB is satisfied run. These are always
260 // tasks posted to FFmpegDemuxer's internal |blocking_task_runner_|, which
261 // the RunLoop above won't pump.
262 task_environment_.RunUntilIdle();
263 }
264
265 MOCK_METHOD2(OnEncryptedMediaInitData,
266 void(EmeInitDataType init_data_type,
267 const std::vector<uint8_t>& init_data));
268
OnMediaTracksUpdated(std::unique_ptr<MediaTracks> tracks)269 void OnMediaTracksUpdated(std::unique_ptr<MediaTracks> tracks) {
270 CHECK(tracks.get());
271 media_tracks_ = std::move(tracks);
272 }
273
274 // Accessor to demuxer internals.
SetDurationKnown(bool duration_known)275 void SetDurationKnown(bool duration_known) {
276 demuxer_->duration_known_ = duration_known;
277 if (!duration_known)
278 demuxer_->duration_ = kInfiniteDuration;
279 }
280
281 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
HasBitstreamConverter(DemuxerStream * stream) const282 bool HasBitstreamConverter(DemuxerStream* stream) const {
283 return !!reinterpret_cast<FFmpegDemuxerStream*>(stream)
284 ->bitstream_converter_;
285 }
286 #endif
287
288 // Fixture members.
289
290 base::test::TaskEnvironment task_environment_;
291
292 // TODO(wolenetz): Consider expanding MediaLog verification coverage here
293 // using StrictMock<MockMediaLog> for all FFmpegDemuxerTests. See
294 // https://crbug.com/749178.
295 StrictMock<MockMediaLog> media_log_;
296 NullMediaLog dummy_media_log_;
297
298 std::unique_ptr<FileDataSource> data_source_;
299 std::unique_ptr<FFmpegDemuxer> demuxer_;
300 StrictMock<MockDemuxerHost> host_;
301 std::unique_ptr<MediaTracks> media_tracks_;
302
format_context()303 AVFormatContext* format_context() {
304 return demuxer_->glue_->format_context();
305 }
306
preferred_seeking_stream(base::TimeDelta seek_time) const307 DemuxerStream* preferred_seeking_stream(base::TimeDelta seek_time) const {
308 return demuxer_->FindPreferredStreamForSeeking(seek_time);
309 }
310
ReadUntilEndOfStream(DemuxerStream * stream)311 void ReadUntilEndOfStream(DemuxerStream* stream) {
312 bool got_eos_buffer = false;
313 const int kMaxBuffers = 170;
314 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) {
315 stream->Read(base::BindOnce(&EosOnReadDone, &got_eos_buffer));
316 base::RunLoop().Run();
317 }
318
319 EXPECT_TRUE(got_eos_buffer);
320 }
321
Seek(base::TimeDelta seek_target)322 void Seek(base::TimeDelta seek_target) {
323 WaitableMessageLoopEvent event;
324 demuxer_->Seek(seek_target, event.GetPipelineStatusCB());
325 event.RunAndWaitForStatus(PIPELINE_OK);
326 }
327
328 private:
CreateDemuxerInternal(const std::string & name,MediaLog * media_log)329 void CreateDemuxerInternal(const std::string& name, MediaLog* media_log) {
330 CHECK(!demuxer_);
331
332 EXPECT_CALL(host_, OnBufferedTimeRangesChanged(_)).Times(AnyNumber());
333
334 CreateDataSource(name);
335
336 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb =
337 base::BindRepeating(&FFmpegDemuxerTest::OnEncryptedMediaInitData,
338 base::Unretained(this));
339
340 Demuxer::MediaTracksUpdatedCB tracks_updated_cb = base::Bind(
341 &FFmpegDemuxerTest::OnMediaTracksUpdated, base::Unretained(this));
342
343 demuxer_.reset(new FFmpegDemuxer(
344 base::ThreadTaskRunnerHandle::Get(), data_source_.get(),
345 encrypted_media_init_data_cb, tracks_updated_cb, media_log, false));
346 }
347
CreateDataSource(const std::string & name)348 void CreateDataSource(const std::string& name) {
349 CHECK(!data_source_);
350
351 base::FilePath file_path;
352 EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
353
354 file_path = file_path.Append(FILE_PATH_LITERAL("media"))
355 .Append(FILE_PATH_LITERAL("test"))
356 .Append(FILE_PATH_LITERAL("data"))
357 .AppendASCII(name);
358
359 data_source_.reset(new FileDataSource());
360 EXPECT_TRUE(data_source_->Initialize(file_path));
361 }
362
363 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest);
364 };
365
TEST_F(FFmpegDemuxerTest,Initialize_OpenFails)366 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) {
367 // Simulate avformat_open_input() failing.
368 CreateDemuxer("ten_byte_file");
369 WaitableMessageLoopEvent event;
370 demuxer_->Initialize(&host_, event.GetPipelineStatusCB());
371 event.RunAndWaitForStatus(DEMUXER_ERROR_COULD_NOT_OPEN);
372 }
373
TEST_F(FFmpegDemuxerTest,Initialize_NoStreams)374 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) {
375 // Open a file with no streams whatsoever.
376 CreateDemuxer("no_streams.webm");
377 WaitableMessageLoopEvent event;
378 demuxer_->Initialize(&host_, event.GetPipelineStatusCB());
379 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
380 }
381
TEST_F(FFmpegDemuxerTest,Initialize_NoAudioVideo)382 TEST_F(FFmpegDemuxerTest, Initialize_NoAudioVideo) {
383 // Open a file containing streams but none of which are audio/video streams.
384 CreateDemuxer("no_audio_video.webm");
385 WaitableMessageLoopEvent event;
386 demuxer_->Initialize(&host_, event.GetPipelineStatusCB());
387 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
388 }
389
TEST_F(FFmpegDemuxerTest,Initialize_Successful)390 TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
391 CreateDemuxer("bear-320x240.webm");
392 InitializeDemuxer();
393
394 // Video stream should be present.
395 DemuxerStream* stream = GetStream(DemuxerStream::VIDEO);
396 ASSERT_TRUE(stream);
397 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
398
399 const VideoDecoderConfig& video_config = stream->video_decoder_config();
400 EXPECT_EQ(kCodecVP8, video_config.codec());
401 EXPECT_EQ(VideoDecoderConfig::AlphaMode::kIsOpaque,
402 video_config.alpha_mode());
403 EXPECT_EQ(320, video_config.coded_size().width());
404 EXPECT_EQ(240, video_config.coded_size().height());
405 EXPECT_EQ(0, video_config.visible_rect().x());
406 EXPECT_EQ(0, video_config.visible_rect().y());
407 EXPECT_EQ(320, video_config.visible_rect().width());
408 EXPECT_EQ(240, video_config.visible_rect().height());
409 EXPECT_EQ(320, video_config.natural_size().width());
410 EXPECT_EQ(240, video_config.natural_size().height());
411 EXPECT_TRUE(video_config.extra_data().empty());
412
413 // Audio stream should be present.
414 stream = GetStream(DemuxerStream::AUDIO);
415 ASSERT_TRUE(stream);
416 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
417
418 const AudioDecoderConfig& audio_config = stream->audio_decoder_config();
419 EXPECT_EQ(kCodecVorbis, audio_config.codec());
420 EXPECT_EQ(32, audio_config.bits_per_channel());
421 EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout());
422 EXPECT_EQ(44100, audio_config.samples_per_second());
423 EXPECT_EQ(kSampleFormatPlanarF32, audio_config.sample_format());
424 EXPECT_FALSE(audio_config.extra_data().empty());
425
426 // Unknown stream should never be present.
427 EXPECT_EQ(2u, demuxer_->GetAllStreams().size());
428 }
429
430 // Android has no Theora support, so this test doesn't work.
431 #if !defined(OS_ANDROID)
TEST_F(FFmpegDemuxerTest,Initialize_Multitrack)432 TEST_F(FFmpegDemuxerTest, Initialize_Multitrack) {
433 // Open a file containing the following streams:
434 // Stream #0: Video (VP8)
435 // Stream #1: Audio (Vorbis)
436 // Stream #2: Subtitles (SRT)
437 // Stream #3: Video (Theora)
438 // Stream #4: Audio (16-bit signed little endian PCM)
439 CreateDemuxer("bear-320x240-multitrack.webm");
440 InitializeDemuxer();
441
442 std::vector<DemuxerStream*> streams = demuxer_->GetAllStreams();
443 EXPECT_EQ(4u, streams.size());
444
445 // Stream #0 should be VP8 video.
446 DemuxerStream* stream = streams[0];
447 ASSERT_TRUE(stream);
448 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
449 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec());
450
451 // Stream #1 should be Vorbis audio.
452 stream = streams[1];
453 ASSERT_TRUE(stream);
454 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
455 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec());
456
457 // The subtitles stream is skipped.
458 // Stream #2 should be Theora video.
459 stream = streams[2];
460 ASSERT_TRUE(stream);
461 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
462 EXPECT_EQ(kCodecTheora, stream->video_decoder_config().codec());
463
464 // Stream #3 should be PCM audio.
465 stream = streams[3];
466 ASSERT_TRUE(stream);
467 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
468 EXPECT_EQ(kCodecPCM, stream->audio_decoder_config().codec());
469 }
470 #endif
471
TEST_F(FFmpegDemuxerTest,Initialize_Encrypted)472 TEST_F(FFmpegDemuxerTest, Initialize_Encrypted) {
473 EXPECT_CALL(
474 *this, OnEncryptedMediaInitData(
475 EmeInitDataType::WEBM,
476 std::vector<uint8_t>(kEncryptedMediaInitData,
477 kEncryptedMediaInitData +
478 base::size(kEncryptedMediaInitData))))
479 .Times(Exactly(2));
480
481 CreateDemuxer("bear-320x240-av_enc-av.webm");
482 InitializeDemuxer();
483 }
484
TEST_F(FFmpegDemuxerTest,Initialize_NoConfigChangeSupport)485 TEST_F(FFmpegDemuxerTest, Initialize_NoConfigChangeSupport) {
486 // Will create one audio, one video, and one text stream.
487 CreateDemuxer("bear-vp8-webvtt.webm");
488 InitializeDemuxer();
489
490 for (auto* stream : demuxer_->GetAllStreams())
491 EXPECT_FALSE(stream->SupportsConfigChanges());
492 }
493
TEST_F(FFmpegDemuxerTest,AbortPendingReads)494 TEST_F(FFmpegDemuxerTest, AbortPendingReads) {
495 // We test that on a successful audio packet read.
496 CreateDemuxer("bear-320x240.webm");
497 InitializeDemuxer();
498
499 // Attempt a read from the audio stream and run the message loop until done.
500 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
501
502 // Depending on where in the reading process ffmpeg is, an error may cause the
503 // stream to be marked as EOF. Simulate this here to ensure it is properly
504 // cleared by the AbortPendingReads() call.
505 format_context()->pb->eof_reached = 1;
506 {
507 base::RunLoop run_loop;
508 audio->Read(NewReadCBWithCheckedDiscard(FROM_HERE, 29, 0, base::TimeDelta(),
509 true, DemuxerStream::kAborted,
510 run_loop.QuitClosure()));
511 demuxer_->AbortPendingReads();
512 run_loop.Run();
513 task_environment_.RunUntilIdle();
514 }
515
516 // Additional reads should also be aborted (until a Seek()).
517 Read(audio, FROM_HERE, 29, 0, true, DemuxerStream::kAborted);
518
519 // Ensure blocking thread has completed outstanding work.
520 demuxer_->Stop();
521 EXPECT_EQ(format_context()->pb->eof_reached, 0);
522
523 // Calling abort after stop should not crash.
524 demuxer_->AbortPendingReads();
525 demuxer_.reset();
526 }
527
TEST_F(FFmpegDemuxerTest,Read_Audio)528 TEST_F(FFmpegDemuxerTest, Read_Audio) {
529 // We test that on a successful audio packet read.
530 CreateDemuxer("bear-320x240.webm");
531 InitializeDemuxer();
532
533 // Attempt a read from the audio stream and run the message loop until done.
534 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
535 Read(audio, FROM_HERE, 29, 0, true);
536 Read(audio, FROM_HERE, 27, 3000, true);
537 EXPECT_EQ(166866, demuxer_->GetMemoryUsage());
538 }
539
TEST_F(FFmpegDemuxerTest,Read_Video)540 TEST_F(FFmpegDemuxerTest, Read_Video) {
541 // We test that on a successful video packet read.
542 CreateDemuxer("bear-320x240.webm");
543 InitializeDemuxer();
544
545 // Attempt a read from the video stream and run the message loop until done.
546 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
547 Read(video, FROM_HERE, 22084, 0, true);
548 Read(video, FROM_HERE, 1057, 33000, false);
549 EXPECT_EQ(148778, demuxer_->GetMemoryUsage());
550 }
551
TEST_F(FFmpegDemuxerTest,SeekInitialized_NoVideoStartTime)552 TEST_F(FFmpegDemuxerTest, SeekInitialized_NoVideoStartTime) {
553 CreateDemuxer("audio-start-time-only.webm");
554 InitializeDemuxer();
555 // Video stream should be preferred for seeking even if video start time is
556 // unknown.
557 DemuxerStream* vstream = GetStream(DemuxerStream::VIDEO);
558 EXPECT_EQ(vstream, preferred_seeking_stream(base::TimeDelta()));
559 }
560
TEST_F(FFmpegDemuxerTest,Seeking_PreferredStreamSelection)561 TEST_F(FFmpegDemuxerTest, Seeking_PreferredStreamSelection) {
562 const int64_t kTimelineOffsetMs = 1352550896000LL;
563
564 // Test the start time is the first timestamp of the video and audio stream.
565 CreateDemuxer("nonzero-start-time.webm");
566 InitializeDemuxerWithTimelineOffset(
567 base::Time::FromJsTime(kTimelineOffsetMs));
568
569 FFmpegDemuxerStream* video =
570 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::VIDEO));
571 FFmpegDemuxerStream* audio =
572 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::AUDIO));
573
574 const base::TimeDelta video_start_time =
575 base::TimeDelta::FromMicroseconds(400000);
576 const base::TimeDelta audio_start_time =
577 base::TimeDelta::FromMicroseconds(396000);
578
579 // Seeking to a position lower than the start time of either stream should
580 // prefer video stream for seeking.
581 EXPECT_EQ(video, preferred_seeking_stream(base::TimeDelta()));
582 // Seeking to a position that has audio data, but not video, should prefer
583 // the audio stream for seeking.
584 EXPECT_EQ(audio, preferred_seeking_stream(audio_start_time));
585 // Seeking to a position where both audio and video streams have data should
586 // prefer the video stream for seeking.
587 EXPECT_EQ(video, preferred_seeking_stream(video_start_time));
588
589 // A disabled stream should be preferred only when there's no other viable
590 // option among enabled streams.
591 audio->SetEnabled(false, base::TimeDelta());
592 EXPECT_EQ(video, preferred_seeking_stream(video_start_time));
593 // Audio stream is preferred, even though it is disabled, since video stream
594 // start time is higher than the seek target == audio_start_time in this case.
595 EXPECT_EQ(audio, preferred_seeking_stream(audio_start_time));
596
597 audio->SetEnabled(true, base::TimeDelta());
598 video->SetEnabled(false, base::TimeDelta());
599 EXPECT_EQ(audio, preferred_seeking_stream(audio_start_time));
600 EXPECT_EQ(audio, preferred_seeking_stream(video_start_time));
601
602 // When both audio and video streams are disabled and there's no enabled
603 // streams, then audio is preferred since it has lower start time.
604 audio->SetEnabled(false, base::TimeDelta());
605 EXPECT_EQ(audio, preferred_seeking_stream(audio_start_time));
606 EXPECT_EQ(audio, preferred_seeking_stream(video_start_time));
607 }
608
TEST_F(FFmpegDemuxerTest,Read_VideoPositiveStartTime)609 TEST_F(FFmpegDemuxerTest, Read_VideoPositiveStartTime) {
610 const int64_t kTimelineOffsetMs = 1352550896000LL;
611
612 // Test the start time is the first timestamp of the video and audio stream.
613 CreateDemuxer("nonzero-start-time.webm");
614 InitializeDemuxerWithTimelineOffset(
615 base::Time::FromJsTime(kTimelineOffsetMs));
616
617 // Attempt a read from the video stream and run the message loop until done.
618 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
619 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
620
621 const base::TimeDelta video_start_time =
622 base::TimeDelta::FromMicroseconds(400000);
623 const base::TimeDelta audio_start_time =
624 base::TimeDelta::FromMicroseconds(396000);
625
626 // Run the test twice with a seek in between.
627 for (int i = 0; i < 2; ++i) {
628 Read(video, FROM_HERE, 5636, video_start_time.InMicroseconds(), true);
629 Read(audio, FROM_HERE, 165, audio_start_time.InMicroseconds(), true);
630
631 // Verify that the start time is equal to the lowest timestamp (ie the
632 // audio).
633 EXPECT_EQ(audio_start_time, demuxer_->start_time());
634
635 // Verify that the timeline offset has not been adjusted by the start time.
636 EXPECT_EQ(kTimelineOffsetMs, demuxer_->GetTimelineOffset().ToJavaTime());
637
638 // Seek back to the beginning and repeat the test.
639 WaitableMessageLoopEvent event;
640 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
641 event.RunAndWaitForStatus(PIPELINE_OK);
642 }
643 }
644
TEST_F(FFmpegDemuxerTest,Read_AudioNoStartTime)645 TEST_F(FFmpegDemuxerTest, Read_AudioNoStartTime) {
646 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the
647 // demuxer sets a start time of zero in this case.
648 CreateDemuxer("sfx_s24le.wav");
649 InitializeDemuxer();
650
651 // Run the test twice with a seek in between.
652 for (int i = 0; i < 2; ++i) {
653 Read(GetStream(DemuxerStream::AUDIO), FROM_HERE, 4095, 0, true);
654 EXPECT_EQ(base::TimeDelta(), demuxer_->start_time());
655
656 // Seek back to the beginning and repeat the test.
657 WaitableMessageLoopEvent event;
658 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
659 event.RunAndWaitForStatus(PIPELINE_OK);
660 }
661 }
662
TEST_F(FFmpegDemuxerTest,Read_InvalidNegativeTimestamp)663 TEST_F(FFmpegDemuxerTest, Read_InvalidNegativeTimestamp) {
664 CreateDemuxer("negative_ts.flac");
665 InitializeDemuxer();
666 EXPECT_CALL(host_, OnDemuxerError(DEMUXER_ERROR_COULD_NOT_PARSE));
667 ReadUntilEndOfStream(GetStream(DemuxerStream::AUDIO));
668 }
669
670 // Android has no Theora support, so these tests doesn't work.
671 #if !defined(OS_ANDROID)
TEST_F(FFmpegDemuxerTest,Read_AudioNegativeStartTimeAndOggDiscard_Bear)672 TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOggDiscard_Bear) {
673 // Many ogg files have negative starting timestamps, so ensure demuxing and
674 // seeking work correctly with a negative start time.
675 CreateDemuxer("bear.ogv");
676 InitializeDemuxer();
677
678 // Attempt a read from the video stream and run the message loop until done.
679 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
680 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
681
682 // Run the test once (should be twice..., see note) with a seek in between.
683 //
684 // TODO(dalecurtis): We only run the test once since FFmpeg does not currently
685 // guarantee the order of demuxed packets in OGG containers. See
686 // http://crbug.com/387996.
687 for (int i = 0; i < 1; ++i) {
688 Read(audio, FROM_HERE, 40, 0, true, DemuxerStream::Status::kOk,
689 kInfiniteDuration);
690 Read(audio, FROM_HERE, 41, 2903, true, DemuxerStream::Status::kOk,
691 kInfiniteDuration);
692 Read(audio, FROM_HERE, 173, 5805, true, DemuxerStream::Status::kOk,
693 base::TimeDelta::FromMicroseconds(10159));
694
695 Read(audio, FROM_HERE, 148, 18866, true);
696 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964),
697 demuxer_->start_time());
698
699 Read(video, FROM_HERE, 5751, 0, true);
700 Read(video, FROM_HERE, 846, 33367, false);
701 Read(video, FROM_HERE, 1255, 66733, false);
702
703 // Seek back to the beginning and repeat the test.
704 WaitableMessageLoopEvent event;
705 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
706 event.RunAndWaitForStatus(PIPELINE_OK);
707 }
708 }
709
710 // Same test above, but using sync2.ogv which has video stream muxed before the
711 // audio stream, so seeking based only on start time will fail since ffmpeg is
712 // essentially just seeking based on file position.
TEST_F(FFmpegDemuxerTest,Read_AudioNegativeStartTimeAndOggDiscard_Sync)713 TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOggDiscard_Sync) {
714 // Many ogg files have negative starting timestamps, so ensure demuxing and
715 // seeking work correctly with a negative start time.
716 CreateDemuxer("sync2.ogv");
717 InitializeDemuxer();
718
719 // Attempt a read from the video stream and run the message loop until done.
720 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
721 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
722
723 // Run the test twice with a seek in between.
724 for (int i = 0; i < 2; ++i) {
725 Read(audio, FROM_HERE, 1, 0, true, DemuxerStream::Status::kOk,
726 base::TimeDelta::FromMicroseconds(2902));
727 Read(audio, FROM_HERE, 1, 2902, true);
728 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-2902), demuxer_->start_time());
729
730 // Though the internal start time may be below zero, the exposed media time
731 // must always be >= zero.
732 EXPECT_EQ(base::TimeDelta(), demuxer_->GetStartTime());
733
734 Read(video, FROM_HERE, 9997, 0, true);
735 Read(video, FROM_HERE, 16, 33241, false);
736 Read(video, FROM_HERE, 631, 66482, false);
737
738 // Seek back to the beginning and repeat the test.
739 WaitableMessageLoopEvent event;
740 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
741 event.RunAndWaitForStatus(PIPELINE_OK);
742 }
743 }
744 #endif // !defined(OS_ANDROID)
745
746 // Similar to the test above, but using an opus clip with a large amount of
747 // pre-skip, which ffmpeg encodes as negative timestamps.
TEST_F(FFmpegDemuxerTest,Read_AudioNegativeStartTimeAndOpusDiscard_Sync)748 TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOpusDiscard_Sync) {
749 CreateDemuxer("opus-trimming-video-test.webm");
750 InitializeDemuxer();
751
752 // Attempt a read from the video stream and run the message loop until done.
753 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
754 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
755 EXPECT_EQ(audio->audio_decoder_config().codec_delay(), 65535);
756
757 // Packet size to timestamp (in microseconds) mapping for the first N packets
758 // which should be fully discarded.
759 static const int kTestExpectations[][2] = {
760 {635, 0}, {594, 120000}, {597, 240000}, {591, 360000},
761 {582, 480000}, {583, 600000}, {592, 720000}, {567, 840000},
762 {579, 960000}, {572, 1080000}, {583, 1200000}};
763
764 // Run the test twice with a seek in between.
765 for (int i = 0; i < 2; ++i) {
766 for (size_t j = 0; j < base::size(kTestExpectations); ++j) {
767 Read(audio, FROM_HERE, kTestExpectations[j][0], kTestExpectations[j][1],
768 true);
769 }
770
771 // Though the internal start time may be below zero, the exposed media time
772 // must always be >= zero.
773 EXPECT_EQ(base::TimeDelta(), demuxer_->GetStartTime());
774
775 Read(video, FROM_HERE, 16009, 0, true);
776 Read(video, FROM_HERE, 2715, 1000, false);
777 Read(video, FROM_HERE, 427, 33000, false);
778
779 // Seek back to the beginning and repeat the test.
780 WaitableMessageLoopEvent event;
781 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
782 event.RunAndWaitForStatus(PIPELINE_OK);
783 }
784 }
785
786 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
787
788 #if defined(OS_CHROMEOS)
TEST_F(FFmpegDemuxerTest,TestAudioNegativeTimestamps)789 TEST_F(FFmpegDemuxerTest, TestAudioNegativeTimestamps) {
790 // Note: This test will _crash_ the browser if negative timestamp
791 // values are skipped, since this file is heavily truncated to avoid
792 // copyright issue. If the negative timestamp packets are dropped, the
793 // demuxer will continue to read off the end of the stream.
794 CreateDemuxer("negative-audio-timestamps.avi");
795 InitializeDemuxer();
796
797 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
798 Read(audio, FROM_HERE, 104, 0, true);
799 Read(audio, FROM_HERE, 104, 25873, true);
800 Read(audio, FROM_HERE, 104, 51746, true);
801 Read(audio, FROM_HERE, 104, 77619, true);
802 Read(audio, FROM_HERE, 104, 103492, true);
803 }
804 #endif // defined(OS_CHROMEOS)
805
806 // Similar to the test above, but using an opus clip plus h264 b-frames to
807 // ensure we don't apply chained ogg workarounds to other content.
TEST_F(FFmpegDemuxerTest,Read_AudioNegativeStartTimeAndOpusDiscardH264Mp4_Sync)808 TEST_F(FFmpegDemuxerTest,
809 Read_AudioNegativeStartTimeAndOpusDiscardH264Mp4_Sync) {
810 CreateDemuxer("tos-h264-opus.mp4");
811 InitializeDemuxer();
812
813 // Attempt a read from the video stream and run the message loop until done.
814 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
815 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
816 EXPECT_EQ(audio->audio_decoder_config().codec_delay(), 312);
817
818 // Packet size to timestamp (in microseconds) mapping for the first N packets
819 // which should be fully discarded.
820 static const int kTestExpectations[][2] = {
821 {234, 20000}, {228, 40000}, {340, 60000}};
822
823 // Run the test twice with a seek in between.
824 for (int i = 0; i < 2; ++i) {
825 Read(audio, FROM_HERE, 408, 0, true, DemuxerStream::Status::kOk,
826 base::TimeDelta::FromMicroseconds(6500));
827
828 for (size_t j = 0; j < base::size(kTestExpectations); ++j) {
829 Read(audio, FROM_HERE, kTestExpectations[j][0], kTestExpectations[j][1],
830 true);
831 }
832
833 // Though the internal start time may be below zero, the exposed media time
834 // must always be >= zero.
835 EXPECT_EQ(base::TimeDelta(), demuxer_->GetStartTime());
836
837 Read(video, FROM_HERE, 185105, 0, true);
838 Read(video, FROM_HERE, 35941, 125000, false);
839
840 // If things aren't working correctly, this expectation will fail because
841 // the chained ogg workaround breaks out of order timestamps.
842 Read(video, FROM_HERE, 8129, 84000, false);
843
844 // Seek back to the beginning and repeat the test.
845 WaitableMessageLoopEvent event;
846 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
847 event.RunAndWaitForStatus(PIPELINE_OK);
848 }
849 }
850 #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
851
852 // Similar to the test above, but using sfx-opus.ogg, which has a much smaller
853 // amount of discard padding and no |start_time| set on the AVStream.
TEST_F(FFmpegDemuxerTest,Read_AudioNegativeStartTimeAndOpusSfxDiscard_Sync)854 TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOpusSfxDiscard_Sync) {
855 CreateDemuxer("sfx-opus.ogg");
856 InitializeDemuxer();
857
858 // Attempt a read from the video stream and run the message loop until done.
859 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
860 EXPECT_EQ(audio->audio_decoder_config().codec_delay(), 312);
861
862 // Run the test twice with a seek in between.
863 for (int i = 0; i < 2; ++i) {
864 Read(audio, FROM_HERE, 314, 0, true);
865 Read(audio, FROM_HERE, 244, 20000, true);
866
867 // Though the internal start time may be below zero, the exposed media time
868 // must always be >= zero.
869 EXPECT_EQ(base::TimeDelta(), demuxer_->GetStartTime());
870
871 // Seek back to the beginning and repeat the test.
872 WaitableMessageLoopEvent event;
873 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
874 event.RunAndWaitForStatus(PIPELINE_OK);
875 }
876 }
877
TEST_F(FFmpegDemuxerTest,Read_DiscardDisabledVideoStream)878 TEST_F(FFmpegDemuxerTest, Read_DiscardDisabledVideoStream) {
879 // Verify that disabling the video stream properly marks it as AVDISCARD_ALL
880 // in FFmpegDemuxer. The AVDISCARD_ALL flag allows FFmpeg to ignore key frame
881 // requirements for the disabled stream and thus allows to select the seek
882 // position closer to the |seek_target|, resulting in less data being read
883 // from the data source.
884 // The input file bear-vp8-webvtt.webm has key video frames at 1.602s and at
885 // 2.002s. If we want to seek to 2.0s position while the video stream is
886 // enabled, then FFmpeg is forced to start reading from 1.602s, which is the
887 // earliest position guaranteed to give us key frames for all enabled streams.
888 // But when the video stream is disabled, FFmpeg can start reading from 1.987s
889 // which is earliest audio key frame before the 2.0s |seek_target|.
890 const base::TimeDelta seek_target = base::TimeDelta::FromMilliseconds(2000);
891
892 CreateDemuxer("bear-vp8-webvtt.webm");
893 InitializeDemuxer();
894 Seek(seek_target);
895 Read(GetStream(DemuxerStream::AUDIO), FROM_HERE, 163, 1612000, true);
896 auto bytes_read_with_video_enabled = data_source_->bytes_read_for_testing();
897
898 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::VIDEO))
899 ->SetEnabled(false, base::TimeDelta());
900 data_source_->reset_bytes_read_for_testing();
901 Seek(seek_target);
902 Read(GetStream(DemuxerStream::AUDIO), FROM_HERE, 156, 1987000, true);
903 auto bytes_read_with_video_disabled = data_source_->bytes_read_for_testing();
904 EXPECT_LT(bytes_read_with_video_disabled, bytes_read_with_video_enabled);
905 }
906
TEST_F(FFmpegDemuxerTest,Read_EndOfStream)907 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) {
908 // Verify that end of stream buffers are created.
909 CreateDemuxer("bear-320x240.webm");
910 InitializeDemuxer();
911 ReadUntilEndOfStream(GetStream(DemuxerStream::AUDIO));
912 }
913
TEST_F(FFmpegDemuxerTest,Read_EndOfStream_NoDuration)914 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration) {
915 // Verify that end of stream buffers are created.
916 CreateDemuxer("bear-320x240.webm");
917 InitializeDemuxer();
918 SetDurationKnown(false);
919 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2744)));
920 ReadUntilEndOfStream(GetStream(DemuxerStream::AUDIO));
921 ReadUntilEndOfStream(GetStream(DemuxerStream::VIDEO));
922 }
923
TEST_F(FFmpegDemuxerTest,Read_EndOfStream_NoDuration_VideoOnly)924 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_VideoOnly) {
925 // Verify that end of stream buffers are created.
926 CreateDemuxer("bear-320x240-video-only.webm");
927 InitializeDemuxer();
928 SetDurationKnown(false);
929 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2703)));
930 ReadUntilEndOfStream(GetStream(DemuxerStream::VIDEO));
931 }
932
TEST_F(FFmpegDemuxerTest,Read_EndOfStream_NoDuration_AudioOnly)933 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_AudioOnly) {
934 // Verify that end of stream buffers are created.
935 CreateDemuxer("bear-320x240-audio-only.webm");
936 InitializeDemuxer();
937 SetDurationKnown(false);
938 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2744)));
939 ReadUntilEndOfStream(GetStream(DemuxerStream::AUDIO));
940 }
941
TEST_F(FFmpegDemuxerTest,Read_EndOfStream_NoDuration_UnsupportedStream)942 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_UnsupportedStream) {
943 // Verify that end of stream buffers are created and we don't crash
944 // if there are streams in the file that we don't support.
945 CreateDemuxer("vorbis_audio_wmv_video.mkv");
946 InitializeDemuxer();
947 SetDurationKnown(false);
948 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(991)));
949 ReadUntilEndOfStream(GetStream(DemuxerStream::AUDIO));
950 }
951
TEST_F(FFmpegDemuxerTest,Seek)952 TEST_F(FFmpegDemuxerTest, Seek) {
953 // We're testing that the demuxer frees all queued packets when it receives
954 // a Seek().
955 CreateDemuxer("bear-320x240.webm");
956 InitializeDemuxer();
957
958 // Get our streams.
959 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
960 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
961 ASSERT_TRUE(video);
962 ASSERT_TRUE(audio);
963
964 // Read a video packet and release it.
965 Read(video, FROM_HERE, 22084, 0, true);
966
967 // Issue a simple forward seek, which should discard queued packets.
968 WaitableMessageLoopEvent event;
969 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
970 event.GetPipelineStatusCB());
971 event.RunAndWaitForStatus(PIPELINE_OK);
972
973 // Audio read #1.
974 Read(audio, FROM_HERE, 145, 803000, true);
975
976 // Audio read #2.
977 Read(audio, FROM_HERE, 148, 826000, true);
978
979 // Video read #1.
980 Read(video, FROM_HERE, 5425, 801000, true);
981
982 // Video read #2.
983 Read(video, FROM_HERE, 1906, 834000, false);
984 }
985
TEST_F(FFmpegDemuxerTest,CancelledSeek)986 TEST_F(FFmpegDemuxerTest, CancelledSeek) {
987 CreateDemuxer("bear-320x240.webm");
988 InitializeDemuxer();
989
990 // Get our streams.
991 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
992 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
993 ASSERT_TRUE(video);
994 ASSERT_TRUE(audio);
995
996 // Read a video packet and release it.
997 Read(video, FROM_HERE, 22084, 0, true);
998
999 // Issue a simple forward seek, which should discard queued packets.
1000 WaitableMessageLoopEvent event;
1001 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
1002 event.GetPipelineStatusCB());
1003 // FFmpegDemuxer does not care what the previous seek time was when canceling.
1004 demuxer_->CancelPendingSeek(base::TimeDelta::FromSeconds(12345));
1005 event.RunAndWaitForStatus(PIPELINE_OK);
1006 }
1007
TEST_F(FFmpegDemuxerTest,Stop)1008 TEST_F(FFmpegDemuxerTest, Stop) {
1009 // Tests that calling Read() on a stopped demuxer stream immediately deletes
1010 // the callback.
1011 CreateDemuxer("bear-320x240.webm");
1012 InitializeDemuxer();
1013
1014 // Get our stream.
1015 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
1016 ASSERT_TRUE(audio);
1017
1018 demuxer_->Stop();
1019
1020 // Reads after being stopped are all EOS buffers.
1021 StrictMock<base::MockCallback<DemuxerStream::ReadCB>> callback;
1022 EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer()));
1023
1024 // Attempt the read...
1025 audio->Read(callback.Get());
1026 task_environment_.RunUntilIdle();
1027
1028 // Don't let the test call Stop() again.
1029 demuxer_.reset();
1030 }
1031
1032 // Verify that seek works properly when the WebM cues data is at the start of
1033 // the file instead of at the end.
TEST_F(FFmpegDemuxerTest,SeekWithCuesBeforeFirstCluster)1034 TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) {
1035 CreateDemuxer("bear-320x240-cues-in-front.webm");
1036 InitializeDemuxer();
1037
1038 // Get our streams.
1039 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
1040 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
1041 ASSERT_TRUE(video);
1042 ASSERT_TRUE(audio);
1043
1044 // Read a video packet and release it.
1045 Read(video, FROM_HERE, 22084, 0, true);
1046
1047 // Issue a simple forward seek, which should discard queued packets.
1048 WaitableMessageLoopEvent event;
1049 demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000),
1050 event.GetPipelineStatusCB());
1051 event.RunAndWaitForStatus(PIPELINE_OK);
1052
1053 // Audio read #1.
1054 Read(audio, FROM_HERE, 40, 2403000, true);
1055
1056 // Audio read #2.
1057 Read(audio, FROM_HERE, 42, 2406000, true);
1058
1059 // Video read #1.
1060 Read(video, FROM_HERE, 5276, 2402000, true);
1061
1062 // Video read #2.
1063 Read(video, FROM_HERE, 1740, 2436000, false);
1064 }
1065
1066 // Ensure ID3v1 tag reading is disabled. id3_test.mp3 has an ID3v1 tag with the
1067 // field "title" set to "sample for id3 test".
TEST_F(FFmpegDemuxerTest,NoID3TagData)1068 TEST_F(FFmpegDemuxerTest, NoID3TagData) {
1069 CreateDemuxer("id3_test.mp3");
1070 InitializeDemuxer();
1071 EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", nullptr, 0));
1072 }
1073
1074 // Ensure MP3 files with large image/video based ID3 tags demux okay. FFmpeg
1075 // will hand us a video stream to the data which will likely be in a format we
1076 // don't accept as video; e.g. PNG.
TEST_F(FFmpegDemuxerTest,Mp3WithVideoStreamID3TagData)1077 TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) {
1078 CreateDemuxerWithStrictMediaLog("id3_png_test.mp3");
1079
1080 EXPECT_MEDIA_LOG_PROPERTY(kBitrate, 1421305);
1081 EXPECT_MEDIA_LOG_PROPERTY(kStartTime, 0.0f);
1082 EXPECT_MEDIA_LOG_PROPERTY(kVideoTracks, std::vector<VideoDecoderConfig>{});
1083 EXPECT_MEDIA_LOG_PROPERTY_ANY_VALUE(kMaxDuration);
1084 EXPECT_MEDIA_LOG_PROPERTY_ANY_VALUE(kAudioTracks);
1085 EXPECT_MEDIA_LOG(SimpleCreatedFFmpegDemuxerStream("audio"));
1086 EXPECT_MEDIA_LOG(FailedToCreateValidDecoderConfigFromStream("video"));
1087
1088 // TODO(wolenetz): Use a matcher that verifies more of the event parameters
1089 // than FoundStream. See https://crbug.com/749178.
1090 EXPECT_MEDIA_LOG(SkippingUnsupportedStream("video"));
1091 InitializeDemuxer();
1092
1093 // Ensure the expected streams are present.
1094 EXPECT_FALSE(GetStream(DemuxerStream::VIDEO));
1095 EXPECT_TRUE(GetStream(DemuxerStream::AUDIO));
1096 }
1097
1098 // Ensure a video with an unsupported audio track still results in the video
1099 // stream being demuxed. Because we disable the speex parser for ogg, the audio
1100 // track won't even show up to the demuxer.
1101 //
1102 // Android has no Theora support, so this test doesn't work.
1103 #if !defined(OS_ANDROID)
TEST_F(FFmpegDemuxerTest,UnsupportedAudioSupportedVideoDemux)1104 TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) {
1105 CreateDemuxerWithStrictMediaLog("speex_audio_vorbis_video.ogv");
1106
1107 EXPECT_MEDIA_LOG_PROPERTY(kBitrate, 398289);
1108 EXPECT_MEDIA_LOG_PROPERTY(kStartTime, 0.0f);
1109 EXPECT_MEDIA_LOG_PROPERTY(kAudioTracks, std::vector<AudioDecoderConfig>{});
1110 EXPECT_MEDIA_LOG_PROPERTY_ANY_VALUE(kVideoTracks);
1111 EXPECT_MEDIA_LOG_PROPERTY_ANY_VALUE(kMaxDuration);
1112 EXPECT_MEDIA_LOG(SimpleCreatedFFmpegDemuxerStream("video"));
1113
1114 // TODO(wolenetz): Use a matcher that verifies more of the event parameters
1115 // than FoundStream. See https://crbug.com/749178.
1116 InitializeDemuxer();
1117
1118 // Ensure the expected streams are present.
1119 EXPECT_TRUE(GetStream(DemuxerStream::VIDEO));
1120 EXPECT_FALSE(GetStream(DemuxerStream::AUDIO));
1121 }
1122 #endif
1123
1124 // Ensure a video with an unsupported video track still results in the audio
1125 // stream being demuxed.
TEST_F(FFmpegDemuxerTest,UnsupportedVideoSupportedAudioDemux)1126 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) {
1127 CreateDemuxer("vorbis_audio_wmv_video.mkv");
1128 InitializeDemuxer();
1129
1130 // Ensure the expected streams are present.
1131 EXPECT_FALSE(GetStream(DemuxerStream::VIDEO));
1132 EXPECT_TRUE(GetStream(DemuxerStream::AUDIO));
1133 }
1134
1135 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
1136 // FFmpeg returns null data pointers when samples have zero size, leading to
1137 // mistakenly creating end of stream buffers http://crbug.com/169133
TEST_F(FFmpegDemuxerTest,MP4_ZeroStszEntry)1138 TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) {
1139 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
1140 InitializeDemuxer();
1141 ReadUntilEndOfStream(GetStream(DemuxerStream::AUDIO));
1142 }
1143 #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
1144
1145 class Mp3SeekFFmpegDemuxerTest
1146 : public FFmpegDemuxerTest,
1147 public testing::WithParamInterface<const char*> {};
TEST_P(Mp3SeekFFmpegDemuxerTest,TestFastSeek)1148 TEST_P(Mp3SeekFFmpegDemuxerTest, TestFastSeek) {
1149 // Init demxuer with given MP3 file parameter.
1150 CreateDemuxer(GetParam());
1151 InitializeDemuxer();
1152
1153 // We read a bunch of bytes when we first open the file. Reset the count
1154 // here to just track the bytes read for the upcoming seek. This allows us
1155 // to use a more narrow threshold for passing the test.
1156 data_source_->reset_bytes_read_for_testing();
1157
1158 FFmpegDemuxerStream* audio =
1159 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::AUDIO));
1160 ASSERT_TRUE(audio);
1161
1162 // Seek to near the end of the file
1163 WaitableMessageLoopEvent event;
1164 demuxer_->Seek(.9 * audio->duration(), event.GetPipelineStatusCB());
1165 event.RunAndWaitForStatus(PIPELINE_OK);
1166
1167 // Verify that seeking to the end read only a small portion of the file.
1168 // Slow seeks that read sequentially up to the seek point will read too many
1169 // bytes and fail this check.
1170 int64_t file_size = 0;
1171 ASSERT_TRUE(data_source_->GetSize(&file_size));
1172 EXPECT_LT(data_source_->bytes_read_for_testing(), (file_size * .25));
1173 }
1174
1175 // MP3s should seek quickly without sequentially reading up to the seek point.
1176 // VBR vs CBR and the presence/absence of TOC influence the seeking algorithm.
1177 // See http://crbug.com/530043 and FFmpeg flag AVFMT_FLAG_FAST_SEEK.
1178 INSTANTIATE_TEST_SUITE_P(All,
1179 Mp3SeekFFmpegDemuxerTest,
1180 ::testing::Values("bear-audio-10s-CBR-has-TOC.mp3",
1181 "bear-audio-10s-CBR-no-TOC.mp3",
1182 "bear-audio-10s-VBR-has-TOC.mp3",
1183 "bear-audio-10s-VBR-no-TOC.mp3"));
1184
1185 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
ValidateAnnexB(DemuxerStream * stream,DemuxerStream::Status status,scoped_refptr<DecoderBuffer> buffer)1186 static void ValidateAnnexB(DemuxerStream* stream,
1187 DemuxerStream::Status status,
1188 scoped_refptr<DecoderBuffer> buffer) {
1189 EXPECT_EQ(status, DemuxerStream::kOk);
1190
1191 if (buffer->end_of_stream()) {
1192 base::ThreadTaskRunnerHandle::Get()->PostTask(
1193 FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
1194 return;
1195 }
1196
1197 std::vector<SubsampleEntry> subsamples;
1198
1199 if (buffer->decrypt_config())
1200 subsamples = buffer->decrypt_config()->subsamples();
1201
1202 bool is_valid =
1203 mp4::AVC::AnalyzeAnnexB(buffer->data(), buffer->data_size(), subsamples)
1204 .is_conformant.value_or(false);
1205 EXPECT_TRUE(is_valid);
1206
1207 if (!is_valid) {
1208 LOG(ERROR) << "Buffer contains invalid Annex B data.";
1209 base::ThreadTaskRunnerHandle::Get()->PostTask(
1210 FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
1211 return;
1212 }
1213
1214 stream->Read(base::BindOnce(&ValidateAnnexB, stream));
1215 }
1216
TEST_F(FFmpegDemuxerTest,IsValidAnnexB)1217 TEST_F(FFmpegDemuxerTest, IsValidAnnexB) {
1218 const char* files[] = {"bear-1280x720-av_frag.mp4",
1219 "bear-1280x720-av_with-aud-nalus_frag.mp4"};
1220
1221 for (size_t i = 0; i < base::size(files); ++i) {
1222 DVLOG(1) << "Testing " << files[i];
1223 CreateDemuxer(files[i]);
1224 InitializeDemuxer();
1225
1226 // Ensure the expected streams are present.
1227 DemuxerStream* stream = GetStream(DemuxerStream::VIDEO);
1228 ASSERT_TRUE(stream);
1229 stream->EnableBitstreamConverter();
1230
1231 stream->Read(base::BindOnce(&ValidateAnnexB, stream));
1232 base::RunLoop().Run();
1233
1234 demuxer_->Stop();
1235 demuxer_.reset();
1236 data_source_.reset();
1237 }
1238 }
1239
TEST_F(FFmpegDemuxerTest,Rotate_Metadata_0)1240 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_0) {
1241 CreateDemuxer("bear_rotate_0.mp4");
1242 InitializeDemuxer();
1243
1244 DemuxerStream* stream = GetStream(DemuxerStream::VIDEO);
1245 ASSERT_TRUE(stream);
1246
1247 const VideoDecoderConfig& video_config = stream->video_decoder_config();
1248 ASSERT_EQ(VIDEO_ROTATION_0, video_config.video_transformation().rotation);
1249 }
1250
TEST_F(FFmpegDemuxerTest,Rotate_Metadata_90)1251 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_90) {
1252 CreateDemuxer("bear_rotate_90.mp4");
1253 InitializeDemuxer();
1254
1255 DemuxerStream* stream = GetStream(DemuxerStream::VIDEO);
1256 ASSERT_TRUE(stream);
1257
1258 const VideoDecoderConfig& video_config = stream->video_decoder_config();
1259 ASSERT_EQ(VIDEO_ROTATION_90, video_config.video_transformation().rotation);
1260 }
1261
TEST_F(FFmpegDemuxerTest,Rotate_Metadata_180)1262 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_180) {
1263 CreateDemuxer("bear_rotate_180.mp4");
1264 InitializeDemuxer();
1265
1266 DemuxerStream* stream = GetStream(DemuxerStream::VIDEO);
1267 ASSERT_TRUE(stream);
1268
1269 const VideoDecoderConfig& video_config = stream->video_decoder_config();
1270 ASSERT_EQ(VIDEO_ROTATION_180, video_config.video_transformation().rotation);
1271 }
1272
TEST_F(FFmpegDemuxerTest,Rotate_Metadata_270)1273 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_270) {
1274 CreateDemuxer("bear_rotate_270.mp4");
1275 InitializeDemuxer();
1276
1277 DemuxerStream* stream = GetStream(DemuxerStream::VIDEO);
1278 ASSERT_TRUE(stream);
1279
1280 const VideoDecoderConfig& video_config = stream->video_decoder_config();
1281 ASSERT_EQ(VIDEO_ROTATION_270, video_config.video_transformation().rotation);
1282 }
1283
TEST_F(FFmpegDemuxerTest,NaturalSizeWithoutPASP)1284 TEST_F(FFmpegDemuxerTest, NaturalSizeWithoutPASP) {
1285 CreateDemuxer("bear-640x360-non_square_pixel-without_pasp.mp4");
1286 InitializeDemuxer();
1287
1288 DemuxerStream* stream = GetStream(DemuxerStream::VIDEO);
1289 ASSERT_TRUE(stream);
1290
1291 const VideoDecoderConfig& video_config = stream->video_decoder_config();
1292 EXPECT_EQ(gfx::Size(639, 360), video_config.natural_size());
1293 }
1294
TEST_F(FFmpegDemuxerTest,NaturalSizeWithPASP)1295 TEST_F(FFmpegDemuxerTest, NaturalSizeWithPASP) {
1296 CreateDemuxer("bear-640x360-non_square_pixel-with_pasp.mp4");
1297 InitializeDemuxer();
1298
1299 DemuxerStream* stream = GetStream(DemuxerStream::VIDEO);
1300 ASSERT_TRUE(stream);
1301
1302 const VideoDecoderConfig& video_config = stream->video_decoder_config();
1303 EXPECT_EQ(gfx::Size(639, 360), video_config.natural_size());
1304 }
1305
TEST_F(FFmpegDemuxerTest,HEVC_in_MP4_container)1306 TEST_F(FFmpegDemuxerTest, HEVC_in_MP4_container) {
1307 CreateDemuxer("bear-hevc-frag.mp4");
1308 #if BUILDFLAG(ENABLE_PLATFORM_HEVC)
1309 // HEVC is not supported by default media platform. Embedders who add support
1310 // must declare it via MediaClient.
1311 MockMediaClient media_client;
1312 SetMediaClient(&media_client);
1313
1314 VideoColorSpace color_space(VideoColorSpace::PrimaryID::SMPTE170M,
1315 VideoColorSpace::TransferID::SMPTE170M,
1316 VideoColorSpace::MatrixID::SMPTE170M,
1317 gfx::ColorSpace::RangeID::LIMITED);
1318 VideoType hevc_type = {VideoCodec::kCodecHEVC,
1319 VideoCodecProfile::HEVCPROFILE_MAIN, 10, color_space};
1320 EXPECT_CALL(media_client, IsSupportedVideoType(Eq(hevc_type)))
1321 .WillRepeatedly(Return(true));
1322
1323 InitializeDemuxer();
1324
1325 DemuxerStream* video = GetStream(DemuxerStream::VIDEO);
1326 ASSERT_TRUE(video);
1327
1328 Read(video, FROM_HERE, 3569, 66733, true);
1329 Read(video, FROM_HERE, 1042, 200200, false);
1330
1331 SetMediaClient(nullptr);
1332 #else
1333 InitializeDemuxerAndExpectPipelineStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
1334 #endif
1335 }
1336
TEST_F(FFmpegDemuxerTest,Read_AC3_Audio)1337 TEST_F(FFmpegDemuxerTest, Read_AC3_Audio) {
1338 CreateDemuxer("bear-ac3-only-frag.mp4");
1339 #if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO)
1340 // AC3 is not supported by default media platform. Embedders who add support
1341 // must declare it via MediaClient.
1342 MockMediaClient media_client;
1343 SetMediaClient(&media_client);
1344
1345 AudioType ac3_type = {AudioCodec::kCodecAC3};
1346 EXPECT_CALL(media_client, IsSupportedAudioType(Eq(ac3_type)))
1347 .WillRepeatedly(Return(true));
1348
1349 InitializeDemuxer();
1350
1351 // Attempt a read from the audio stream and run the message loop until done.
1352 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
1353
1354 // Read the first two frames and check that we are getting expected data
1355 Read(audio, FROM_HERE, 834, 0, true);
1356 Read(audio, FROM_HERE, 836, 34830, true);
1357
1358 SetMediaClient(nullptr);
1359 #else
1360 InitializeDemuxerAndExpectPipelineStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
1361 #endif
1362 }
1363
TEST_F(FFmpegDemuxerTest,Read_EAC3_Audio)1364 TEST_F(FFmpegDemuxerTest, Read_EAC3_Audio) {
1365 CreateDemuxer("bear-eac3-only-frag.mp4");
1366 #if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO)
1367 // EAC3 is not supported by default media platform. Embedders who add support
1368 // must declare it via MediaClient.
1369 MockMediaClient media_client;
1370 SetMediaClient(&media_client);
1371
1372 AudioType eac3_type = {AudioCodec::kCodecEAC3};
1373 EXPECT_CALL(media_client, IsSupportedAudioType(Eq(eac3_type)))
1374 .WillRepeatedly(Return(true));
1375
1376 InitializeDemuxer();
1377
1378 // Attempt a read from the audio stream and run the message loop until done.
1379 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
1380
1381 // Read the first two frames and check that we are getting expected data
1382 Read(audio, FROM_HERE, 870, 0, true);
1383 Read(audio, FROM_HERE, 872, 34830, true);
1384
1385 SetMediaClient(nullptr);
1386 #else
1387 InitializeDemuxerAndExpectPipelineStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
1388 #endif
1389 }
1390
TEST_F(FFmpegDemuxerTest,Read_Mp4_Media_Track_Info)1391 TEST_F(FFmpegDemuxerTest, Read_Mp4_Media_Track_Info) {
1392 CreateDemuxer("bear.mp4");
1393 InitializeDemuxer();
1394
1395 EXPECT_EQ(media_tracks_->tracks().size(), 2u);
1396
1397 const MediaTrack& audio_track = *(media_tracks_->tracks()[1]);
1398 EXPECT_EQ(audio_track.type(), MediaTrack::Audio);
1399 EXPECT_EQ(audio_track.bytestream_track_id(), 2);
1400 EXPECT_EQ(audio_track.kind().value(), "main");
1401 EXPECT_EQ(audio_track.label().value(), "SoundHandler");
1402 EXPECT_EQ(audio_track.language().value(), "und");
1403
1404 const MediaTrack& video_track = *(media_tracks_->tracks()[0]);
1405 EXPECT_EQ(video_track.type(), MediaTrack::Video);
1406 EXPECT_EQ(video_track.bytestream_track_id(), 1);
1407 EXPECT_EQ(video_track.kind().value(), "main");
1408 EXPECT_EQ(video_track.label().value(), "VideoHandler");
1409 EXPECT_EQ(video_track.language().value(), "und");
1410 }
1411
TEST_F(FFmpegDemuxerTest,Read_Mp4_Multiple_Tracks)1412 TEST_F(FFmpegDemuxerTest, Read_Mp4_Multiple_Tracks) {
1413 CreateDemuxer("bbb-320x240-2video-2audio.mp4");
1414 InitializeDemuxer();
1415
1416 EXPECT_EQ(media_tracks_->tracks().size(), 4u);
1417
1418 const MediaTrack& video_track = *(media_tracks_->tracks()[0]);
1419 EXPECT_EQ(video_track.type(), MediaTrack::Video);
1420 EXPECT_EQ(video_track.bytestream_track_id(), 1);
1421 EXPECT_EQ(video_track.kind().value(), "main");
1422 EXPECT_EQ(video_track.label().value(), "VideoHandler");
1423 EXPECT_EQ(video_track.language().value(), "und");
1424
1425 const MediaTrack& audio_track = *(media_tracks_->tracks()[1]);
1426 EXPECT_EQ(audio_track.type(), MediaTrack::Audio);
1427 EXPECT_EQ(audio_track.bytestream_track_id(), 2);
1428 EXPECT_EQ(audio_track.kind().value(), "main");
1429 EXPECT_EQ(audio_track.label().value(), "SoundHandler");
1430 EXPECT_EQ(audio_track.language().value(), "und");
1431
1432 const MediaTrack& video_track2 = *(media_tracks_->tracks()[2]);
1433 EXPECT_EQ(video_track2.type(), MediaTrack::Video);
1434 EXPECT_EQ(video_track2.bytestream_track_id(), 3);
1435 EXPECT_EQ(video_track2.kind().value(), "main");
1436 EXPECT_EQ(video_track2.label().value(), "VideoHandler");
1437 EXPECT_EQ(video_track2.language().value(), "und");
1438
1439 const MediaTrack& audio_track2 = *(media_tracks_->tracks()[3]);
1440 EXPECT_EQ(audio_track2.type(), MediaTrack::Audio);
1441 EXPECT_EQ(audio_track2.bytestream_track_id(), 4);
1442 EXPECT_EQ(audio_track2.kind().value(), "main");
1443 EXPECT_EQ(audio_track2.label().value(), "SoundHandler");
1444 EXPECT_EQ(audio_track2.language().value(), "und");
1445 }
1446
TEST_F(FFmpegDemuxerTest,Read_Mp4_Crbug657437)1447 TEST_F(FFmpegDemuxerTest, Read_Mp4_Crbug657437) {
1448 CreateDemuxer("crbug657437.mp4");
1449 InitializeDemuxer();
1450 }
1451
TEST_F(FFmpegDemuxerTest,XHE_AAC)1452 TEST_F(FFmpegDemuxerTest, XHE_AAC) {
1453 CreateDemuxer("noise-xhe-aac.mp4");
1454 InitializeDemuxer();
1455
1456 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
1457 ASSERT_TRUE(audio);
1458
1459 EXPECT_EQ(audio->audio_decoder_config().profile(),
1460 AudioCodecProfile::kXHE_AAC);
1461
1462 // ADTS bitstream conversion shouldn't be enabled for xHE-AAC since it can't
1463 // be represented with only two bits for the profile.
1464 audio->EnableBitstreamConverter();
1465 EXPECT_FALSE(HasBitstreamConverter(audio));
1466
1467 // Even though FFmpeg can't decode xHE-AAC content, it should be demuxing it
1468 // just fine.
1469 Read(audio, FROM_HERE, 1796, 0, true);
1470 }
1471
1472 #endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
1473
TEST_F(FFmpegDemuxerTest,Read_Webm_Multiple_Tracks)1474 TEST_F(FFmpegDemuxerTest, Read_Webm_Multiple_Tracks) {
1475 CreateDemuxer("multitrack-3video-2audio.webm");
1476 InitializeDemuxer();
1477
1478 EXPECT_EQ(media_tracks_->tracks().size(), 5u);
1479
1480 const MediaTrack& video_track1 = *(media_tracks_->tracks()[0]);
1481 EXPECT_EQ(video_track1.type(), MediaTrack::Video);
1482 EXPECT_EQ(video_track1.bytestream_track_id(), 1);
1483
1484 const MediaTrack& video_track2 = *(media_tracks_->tracks()[1]);
1485 EXPECT_EQ(video_track2.type(), MediaTrack::Video);
1486 EXPECT_EQ(video_track2.bytestream_track_id(), 2);
1487
1488 const MediaTrack& video_track3 = *(media_tracks_->tracks()[2]);
1489 EXPECT_EQ(video_track3.type(), MediaTrack::Video);
1490 EXPECT_EQ(video_track3.bytestream_track_id(), 3);
1491
1492 const MediaTrack& audio_track1 = *(media_tracks_->tracks()[3]);
1493 EXPECT_EQ(audio_track1.type(), MediaTrack::Audio);
1494 EXPECT_EQ(audio_track1.bytestream_track_id(), 4);
1495
1496 const MediaTrack& audio_track2 = *(media_tracks_->tracks()[4]);
1497 EXPECT_EQ(audio_track2.type(), MediaTrack::Audio);
1498 EXPECT_EQ(audio_track2.bytestream_track_id(), 5);
1499 }
1500
TEST_F(FFmpegDemuxerTest,Read_Webm_Media_Track_Info)1501 TEST_F(FFmpegDemuxerTest, Read_Webm_Media_Track_Info) {
1502 CreateDemuxer("bear.webm");
1503 InitializeDemuxer();
1504
1505 EXPECT_EQ(media_tracks_->tracks().size(), 2u);
1506
1507 const MediaTrack& video_track = *(media_tracks_->tracks()[0]);
1508 EXPECT_EQ(video_track.type(), MediaTrack::Video);
1509 EXPECT_EQ(video_track.bytestream_track_id(), 1);
1510 EXPECT_EQ(video_track.kind().value(), "main");
1511 EXPECT_EQ(video_track.label().value(), "");
1512 EXPECT_EQ(video_track.language().value(), "");
1513
1514 const MediaTrack& audio_track = *(media_tracks_->tracks()[1]);
1515 EXPECT_EQ(audio_track.type(), MediaTrack::Audio);
1516 EXPECT_EQ(audio_track.bytestream_track_id(), 2);
1517 EXPECT_EQ(audio_track.kind().value(), "main");
1518 EXPECT_EQ(audio_track.label().value(), "");
1519 EXPECT_EQ(audio_track.language().value(), "");
1520 }
1521
1522 // UTCDateToTime_* tests here assume FFmpegDemuxer's ExtractTimelineOffset
1523 // helper uses base::Time::FromUTCString() for conversion.
TEST_F(FFmpegDemuxerTest,UTCDateToTime_Valid)1524 TEST_F(FFmpegDemuxerTest, UTCDateToTime_Valid) {
1525 base::Time result;
1526 EXPECT_TRUE(
1527 base::Time::FromUTCString("2012-11-10T12:34:56.987654Z", &result));
1528
1529 base::Time::Exploded exploded;
1530 result.UTCExplode(&exploded);
1531 EXPECT_TRUE(exploded.HasValidValues());
1532 EXPECT_EQ(2012, exploded.year);
1533 EXPECT_EQ(11, exploded.month);
1534 EXPECT_EQ(6, exploded.day_of_week);
1535 EXPECT_EQ(10, exploded.day_of_month);
1536 EXPECT_EQ(12, exploded.hour);
1537 EXPECT_EQ(34, exploded.minute);
1538 EXPECT_EQ(56, exploded.second);
1539 EXPECT_EQ(987, exploded.millisecond);
1540
1541 // base::Time exploding operations round fractional milliseconds down, so
1542 // verify fractional milliseconds using a base::TimeDelta.
1543 base::Time without_fractional_ms;
1544 EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &without_fractional_ms));
1545 base::TimeDelta delta = result - without_fractional_ms;
1546 EXPECT_EQ(654, delta.InMicroseconds());
1547 }
1548
TEST_F(FFmpegDemuxerTest,UTCDateToTime_Invalid)1549 TEST_F(FFmpegDemuxerTest, UTCDateToTime_Invalid) {
1550 const char* invalid_date_strings[] = {
1551 "",
1552 "12:34:56",
1553 "-- ::",
1554 "2012-11- 12:34:56",
1555 "2012--10 12:34:56",
1556 "-11-10 12:34:56",
1557 "2012-11 12:34:56",
1558 "ABCD-11-10 12:34:56",
1559 "2012-EF-10 12:34:56",
1560 "2012-11-GH 12:34:56",
1561 "2012-11-1012:34:56",
1562 };
1563
1564 for (size_t i = 0; i < base::size(invalid_date_strings); ++i) {
1565 const char* date_string = invalid_date_strings[i];
1566 base::Time result;
1567 EXPECT_FALSE(base::Time::FromUTCString(date_string, &result))
1568 << "date_string '" << date_string << "'";
1569 }
1570 }
1571
VerifyFlacStream(DemuxerStream * stream,int expected_bits_per_channel,ChannelLayout expected_channel_layout,int expected_samples_per_second,SampleFormat expected_sample_format)1572 static void VerifyFlacStream(DemuxerStream* stream,
1573 int expected_bits_per_channel,
1574 ChannelLayout expected_channel_layout,
1575 int expected_samples_per_second,
1576 SampleFormat expected_sample_format) {
1577 ASSERT_TRUE(stream);
1578 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
1579
1580 const AudioDecoderConfig& audio_config = stream->audio_decoder_config();
1581 EXPECT_EQ(kCodecFLAC, audio_config.codec());
1582 EXPECT_EQ(expected_bits_per_channel, audio_config.bits_per_channel());
1583 EXPECT_EQ(expected_channel_layout, audio_config.channel_layout());
1584 EXPECT_EQ(expected_samples_per_second, audio_config.samples_per_second());
1585 EXPECT_EQ(expected_sample_format, audio_config.sample_format());
1586 }
1587
TEST_F(FFmpegDemuxerTest,Read_Flac)1588 TEST_F(FFmpegDemuxerTest, Read_Flac) {
1589 CreateDemuxer("sfx.flac");
1590 InitializeDemuxer();
1591
1592 // Video stream should not be present.
1593 EXPECT_EQ(nullptr, GetStream(DemuxerStream::VIDEO));
1594
1595 VerifyFlacStream(GetStream(DemuxerStream::AUDIO), 32, CHANNEL_LAYOUT_MONO,
1596 44100, kSampleFormatS32);
1597 }
1598
TEST_F(FFmpegDemuxerTest,Read_Flac_Mp4)1599 TEST_F(FFmpegDemuxerTest, Read_Flac_Mp4) {
1600 CreateDemuxer("bear-flac.mp4");
1601 InitializeDemuxer();
1602
1603 // Video stream should not be present.
1604 EXPECT_EQ(nullptr, GetStream(DemuxerStream::VIDEO));
1605
1606 VerifyFlacStream(GetStream(DemuxerStream::AUDIO), 32, CHANNEL_LAYOUT_STEREO,
1607 44100, kSampleFormatS32);
1608 }
1609
TEST_F(FFmpegDemuxerTest,Read_Flac_192kHz_Mp4)1610 TEST_F(FFmpegDemuxerTest, Read_Flac_192kHz_Mp4) {
1611 CreateDemuxer("bear-flac-192kHz.mp4");
1612 InitializeDemuxer();
1613
1614 // Video stream should not be present.
1615 EXPECT_EQ(nullptr, GetStream(DemuxerStream::VIDEO));
1616
1617 VerifyFlacStream(GetStream(DemuxerStream::AUDIO), 32, CHANNEL_LAYOUT_STEREO,
1618 192000, kSampleFormatS32);
1619 }
1620
1621 // Verify that FFmpeg demuxer falls back to choosing disabled streams for
1622 // seeking if there's no suitable enabled stream found.
TEST_F(FFmpegDemuxerTest,Seek_FallbackToDisabledVideoStream)1623 TEST_F(FFmpegDemuxerTest, Seek_FallbackToDisabledVideoStream) {
1624 // Input has only video stream, no audio.
1625 CreateDemuxer("bear-320x240-video-only.webm");
1626 InitializeDemuxer();
1627 EXPECT_EQ(nullptr, GetStream(DemuxerStream::AUDIO));
1628 FFmpegDemuxerStream* vstream =
1629 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::VIDEO));
1630 EXPECT_NE(nullptr, vstream);
1631 EXPECT_EQ(vstream, preferred_seeking_stream(base::TimeDelta()));
1632
1633 // Now pretend that video stream got disabled, e.g. due to current tab going
1634 // into background.
1635 vstream->SetEnabled(false, base::TimeDelta());
1636 // Since there's no other enabled streams, the preferred seeking stream should
1637 // still be the video stream.
1638 EXPECT_EQ(vstream, preferred_seeking_stream(base::TimeDelta()));
1639 }
1640
TEST_F(FFmpegDemuxerTest,Seek_FallbackToDisabledAudioStream)1641 TEST_F(FFmpegDemuxerTest, Seek_FallbackToDisabledAudioStream) {
1642 CreateDemuxer("bear-320x240-audio-only.webm");
1643 InitializeDemuxer();
1644 FFmpegDemuxerStream* astream =
1645 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::AUDIO));
1646 EXPECT_NE(nullptr, astream);
1647 EXPECT_EQ(nullptr, GetStream(DemuxerStream::VIDEO));
1648 EXPECT_EQ(astream, preferred_seeking_stream(base::TimeDelta()));
1649
1650 // Now pretend that audio stream got disabled.
1651 astream->SetEnabled(false, base::TimeDelta());
1652 // Since there's no other enabled streams, the preferred seeking stream should
1653 // still be the audio stream.
1654 EXPECT_EQ(astream, preferred_seeking_stream(base::TimeDelta()));
1655 }
1656
1657 namespace {
QuitLoop(base::Closure quit_closure,DemuxerStream::Type type,const std::vector<DemuxerStream * > & streams)1658 void QuitLoop(base::Closure quit_closure,
1659 DemuxerStream::Type type,
1660 const std::vector<DemuxerStream*>& streams) {
1661 quit_closure.Run();
1662 }
1663
DisableAndEnableDemuxerTracks(FFmpegDemuxer * demuxer,base::test::TaskEnvironment * task_environment)1664 void DisableAndEnableDemuxerTracks(
1665 FFmpegDemuxer* demuxer,
1666 base::test::TaskEnvironment* task_environment) {
1667 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
1668 base::WaitableEvent::InitialState::NOT_SIGNALED);
1669 std::vector<MediaTrack::Id> audio_tracks;
1670 std::vector<MediaTrack::Id> video_tracks;
1671
1672 base::RunLoop disable_video;
1673 demuxer->OnSelectedVideoTrackChanged(
1674 video_tracks, base::TimeDelta(),
1675 base::BindOnce(QuitLoop, disable_video.QuitClosure()));
1676 disable_video.Run();
1677
1678 base::RunLoop disable_audio;
1679 demuxer->OnEnabledAudioTracksChanged(
1680 audio_tracks, base::TimeDelta(),
1681 base::BindOnce(QuitLoop, disable_audio.QuitClosure()));
1682 disable_audio.Run();
1683
1684 base::RunLoop enable_video;
1685 video_tracks.push_back(MediaTrack::Id("1"));
1686 demuxer->OnSelectedVideoTrackChanged(
1687 video_tracks, base::TimeDelta(),
1688 base::BindOnce(QuitLoop, enable_video.QuitClosure()));
1689 enable_video.Run();
1690
1691 base::RunLoop enable_audio;
1692 audio_tracks.push_back(MediaTrack::Id("2"));
1693 demuxer->OnEnabledAudioTracksChanged(
1694 audio_tracks, base::TimeDelta(),
1695 base::BindOnce(QuitLoop, enable_audio.QuitClosure()));
1696 enable_audio.Run();
1697
1698 task_environment->RunUntilIdle();
1699 }
1700
OnReadDoneExpectEos(DemuxerStream::Status status,const scoped_refptr<DecoderBuffer> buffer)1701 void OnReadDoneExpectEos(DemuxerStream::Status status,
1702 const scoped_refptr<DecoderBuffer> buffer) {
1703 EXPECT_EQ(status, DemuxerStream::kOk);
1704 EXPECT_TRUE(buffer->end_of_stream());
1705 }
1706 } // namespace
1707
TEST_F(FFmpegDemuxerTest,StreamStatusNotifications)1708 TEST_F(FFmpegDemuxerTest, StreamStatusNotifications) {
1709 CreateDemuxer("bear-320x240.webm");
1710 InitializeDemuxer();
1711 FFmpegDemuxerStream* audio_stream =
1712 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::AUDIO));
1713 EXPECT_NE(nullptr, audio_stream);
1714 FFmpegDemuxerStream* video_stream =
1715 static_cast<FFmpegDemuxerStream*>(GetStream(DemuxerStream::VIDEO));
1716 EXPECT_NE(nullptr, video_stream);
1717
1718 // Verify stream status notifications delivery without pending read first.
1719 DisableAndEnableDemuxerTracks(demuxer_.get(), &task_environment_);
1720
1721 // Verify that stream notifications are delivered properly when stream status
1722 // changes with a pending read. Call FlushBuffers before reading, to ensure
1723 // there is no buffers ready to be returned by the Read right away, thus
1724 // ensuring that status changes occur while an async read is pending.
1725
1726 audio_stream->FlushBuffers(true);
1727 video_stream->FlushBuffers(true);
1728 audio_stream->Read(base::BindOnce(&OnReadDoneExpectEos));
1729 video_stream->Read(base::BindOnce(&OnReadDoneExpectEos));
1730
1731 DisableAndEnableDemuxerTracks(demuxer_.get(), &task_environment_);
1732 }
1733
TEST_F(FFmpegDemuxerTest,MultitrackMemoryUsage)1734 TEST_F(FFmpegDemuxerTest, MultitrackMemoryUsage) {
1735 CreateDemuxer("multitrack-3video-2audio.webm");
1736 InitializeDemuxer();
1737
1738 DemuxerStream* audio = GetStream(DemuxerStream::AUDIO);
1739
1740 // Read from the audio stream to make sure FFmpegDemuxer buffers data for all
1741 // streams with available capacity, i.e all enabled streams. By default only
1742 // the first audio and the first video stream are enabled, so the memory usage
1743 // shouldn't be too high.
1744 Read(audio, FROM_HERE, 304, 0, true);
1745 EXPECT_EQ(22134, demuxer_->GetMemoryUsage());
1746
1747 // Now enable all demuxer streams in the file and perform another read, this
1748 // will buffer the data for additional streams and memory usage will increase.
1749 std::vector<DemuxerStream*> streams = demuxer_->GetAllStreams();
1750 for (auto* stream : streams) {
1751 static_cast<FFmpegDemuxerStream*>(stream)->SetEnabled(true,
1752 base::TimeDelta());
1753 }
1754 Read(audio, FROM_HERE, 166, 21000, true);
1755
1756 // With newly enabled demuxer streams the amount of memory used by the demuxer
1757 // is much higher.
1758 EXPECT_EQ(156011, demuxer_->GetMemoryUsage());
1759 }
1760
TEST_F(FFmpegDemuxerTest,SeekOnVideoTrackChangeWontSeekIfEmpty)1761 TEST_F(FFmpegDemuxerTest, SeekOnVideoTrackChangeWontSeekIfEmpty) {
1762 // We only care about video tracks.
1763 CreateDemuxer("bear-320x240-video-only.webm");
1764 InitializeDemuxer();
1765 std::vector<DemuxerStream*> streams;
1766 base::RunLoop loop;
1767
1768 SeekOnVideoTrackChangePassthrough(
1769 base::TimeDelta(), base::BindOnce(QuitLoop, loop.QuitClosure()),
1770 DemuxerStream::VIDEO, streams);
1771
1772 loop.Run();
1773 }
1774
1775 } // namespace media
1776