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