{
"args": [
"./disable",
"8802535516802193537",
".*PipelineIntegrationTest.TrackStatusChangesWhileSuspended.*",
"win"
],
"requests": "{\"QueryTestResults/{\\\"invocations\\\": [\\\"invocations/build-8802535516802193537\\\"], \\\"readMask\\\": {\\\"paths\\\": [\\\"test_id\\\", \\\"test_metadata\\\"]}, \\\"pageSize\\\": 1000, \\\"predicate\\\": {\\\"testIdRegexp\\\": \\\".*PipelineIntegrationTest.TrackStatusChangesWhileSuspended.*\\\"}}\": \"{\\\"testResults\\\":[{\\\"name\\\":\\\"invocations/task-chromium-swarm.appspot.com-5d71cde739018311/tests/ninja:%2F%2Fmedia:media_unittests%2FPipelineIntegrationTest.TrackStatusChangesWhileSuspended/results/cc650930-04490\\\",\\\"testId\\\":\\\"ninja://media:media_unittests/PipelineIntegrationTest.TrackStatusChangesWhileSuspended\\\",\\\"testMetadata\\\":{\\\"name\\\":\\\"PipelineIntegrationTest.TrackStatusChangesWhileSuspended\\\",\\\"location\\\":{\\\"repo\\\":\\\"https://chromium.googlesource.com/chromium/src\\\",\\\"fileName\\\":\\\"//media/test/pipeline_integration_test.cc\\\",\\\"line\\\":874}}}]}\\n\"}",
"read_data": {
"media/test/pipeline_integration_test.cc": "// Copyright 2012 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include <memory>\n#include <utility>\n\n#include \"base/bind.h\"\n#include \"base/callback_helpers.h\"\n#include \"base/command_line.h\"\n#include \"base/memory/ref_counted.h\"\n#include \"base/run_loop.h\"\n#include \"base/strings/string_split.h\"\n#include \"base/strings/string_util.h\"\n#include \"base/test/bind.h\"\n#include \"base/threading/thread_task_runner_handle.h\"\n#include \"base/time/time.h\"\n#include \"build/build_config.h\"\n#include \"media/base/cdm_callback_promise.h\"\n#include \"media/base/cdm_key_information.h\"\n#include \"media/base/decoder_buffer.h\"\n#include \"media/base/media.h\"\n#include \"media/base/media_switches.h\"\n#include \"media/base/media_tracks.h\"\n#include \"media/base/mock_media_log.h\"\n#include \"media/base/test_data_util.h\"\n#include \"media/base/timestamp_constants.h\"\n#include \"media/cdm/aes_decryptor.h\"\n#include \"media/cdm/json_web_key.h\"\n#include \"media/media_buildflags.h\"\n#include \"media/renderers/renderer_impl.h\"\n#include \"media/test/fake_encrypted_media.h\"\n#include \"media/test/pipeline_integration_test_base.h\"\n#include \"media/test/test_media_source.h\"\n#include \"testing/gmock/include/gmock/gmock.h\"\n#include \"url/gurl.h\"\n\n#if BUILDFLAG(IS_MAC)\n#include \"media/filters/mac/audio_toolbox_audio_decoder.h\"\n#endif\n\n#define EXPECT_HASH_EQ(a, b) EXPECT_EQ(a, b)\n#define EXPECT_VIDEO_FORMAT_EQ(a, b) EXPECT_EQ(a, b)\n#define EXPECT_COLOR_SPACE_EQ(a, b) EXPECT_EQ(a, b)\n\nusing ::testing::_;\nusing ::testing::AnyNumber;\nusing ::testing::AtLeast;\nusing ::testing::AtMost;\nusing ::testing::HasSubstr;\nusing ::testing::SaveArg;\n\nnamespace media {\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nconst int kAV110bitMp4FileDurationMs = 2735;\nconst int kAV1640WebMFileDurationMs = 2736;\n#endif // BUILDFLAG(ENABLE_AV1_DECODER)\n\n// Constants for the Media Source config change tests.\nconst int kAppendTimeSec = 1;\nconst int kAppendTimeMs = kAppendTimeSec * 1000;\nconst int k320WebMFileDurationMs = 2736;\nconst int k640WebMFileDurationMs = 2762;\nconst int kVP9WebMFileDurationMs = 2736;\nconst int kVP8AWebMFileDurationMs = 2734;\n\nstatic const char kSfxLosslessHash[] = \"3.03,2.86,2.99,3.31,3.57,4.06,\";\n\n#if defined(OPUS_FIXED_POINT)\n// NOTE: These hashes are specific to ARM devices, which use fixed-point Opus\n// implementation. x86 uses floating-point Opus, so x86 hashes won't match\n#if defined(ARCH_CPU_ARM64)\nstatic const char kOpusEndTrimmingHash_1[] =\n \"-4.58,-5.68,-6.53,-6.28,-4.35,-3.59,\";\nstatic const char kOpusEndTrimmingHash_2[] =\n \"-11.92,-11.11,-8.25,-7.10,-7.84,-10.00,\";\nstatic const char kOpusEndTrimmingHash_3[] =\n \"-13.33,-14.38,-13.68,-11.66,-10.18,-10.49,\";\nstatic const char kOpusSmallCodecDelayHash_1[] =\n \"-0.48,-0.09,1.27,1.06,1.54,-0.22,\";\nstatic const char kOpusSmallCodecDelayHash_2[] =\n \"0.29,0.15,-0.19,0.25,0.68,0.83,\";\nstatic const char kOpusMonoOutputHash[] = \"-2.39,-1.66,0.81,1.54,1.48,-0.91,\";\n#else\nstatic const char kOpusEndTrimmingHash_1[] =\n \"-4.57,-5.66,-6.52,-6.30,-4.37,-3.61,\";\nstatic const char kOpusEndTrimmingHash_2[] =\n \"-11.91,-11.11,-8.27,-7.13,-7.86,-10.00,\";\nstatic const char kOpusEndTrimmingHash_3[] =\n \"-13.31,-14.38,-13.70,-11.71,-10.21,-10.49,\";\nstatic const char kOpusSmallCodecDelayHash_1[] =\n \"-0.48,-0.09,1.27,1.06,1.54,-0.22,\";\nstatic const char kOpusSmallCodecDelayHash_2[] =\n \"0.29,0.14,-0.20,0.24,0.68,0.83,\";\nstatic const char kOpusMonoOutputHash[] = \"-2.41,-1.66,0.79,1.53,1.46,-0.91,\";\n#endif // defined(ARCH_CPU_ARM64)\n\n#else\n// Hash for a full playthrough of \"opus-trimming-test.(webm|ogg)\".\nstatic const char kOpusEndTrimmingHash_1[] =\n \"-4.57,-5.67,-6.52,-6.28,-4.34,-3.58,\";\n// The above hash, plus an additional playthrough starting from T=1s.\nstatic const char kOpusEndTrimmingHash_2[] =\n \"-11.91,-11.10,-8.24,-7.08,-7.82,-9.99,\";\n// The above hash, plus an additional playthrough starting from T=6.36s.\nstatic const char kOpusEndTrimmingHash_3[] =\n \"-13.31,-14.36,-13.66,-11.65,-10.16,-10.47,\";\n// Hash for a full playthrough of \"bear-opus.webm\".\nstatic const char kOpusSmallCodecDelayHash_1[] =\n \"-0.47,-0.09,1.28,1.07,1.55,-0.22,\";\n// The above hash, plus an additional playthrough starting from T=1.414s.\nstatic const char kOpusSmallCodecDelayHash_2[] =\n \"0.31,0.15,-0.18,0.25,0.70,0.84,\";\n// For BasicPlaybackOpusWebmHashed_MonoOutput test case.\nstatic const char kOpusMonoOutputHash[] = \"-2.36,-1.64,0.84,1.55,1.51,-0.90,\";\n#endif // defined(OPUS_FIXED_POINT)\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\nconst int k640IsoCencFileDurationMs = 2769;\nconst int k1280IsoFileDurationMs = 2736;\n\n// TODO(wolenetz): Update to 2769 once MSE endOfStream implementation no longer\n// truncates duration to the highest in intersection ranges, but compliantly to\n// the largest track buffer ranges end time across all tracks and SourceBuffers.\n// See https://crbug.com/639144.\nconst int k1280IsoFileDurationMsAV = 2763;\n\nconst int k1280IsoAVC3FileDurationMs = 2736;\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\n// Return a timeline offset for bear-320x240-live.webm.\nstatic base::Time kLiveTimelineOffset() {\n // The file contains the following UTC timeline offset:\n // 2012-11-10 12:34:56.789123456\n // Since base::Time only has a resolution of microseconds,\n // construct a base::Time for 2012-11-10 12:34:56.789123.\n base::Time::Exploded exploded_time;\n exploded_time.year = 2012;\n exploded_time.month = 11;\n exploded_time.day_of_month = 10;\n exploded_time.day_of_week = 6;\n exploded_time.hour = 12;\n exploded_time.minute = 34;\n exploded_time.second = 56;\n exploded_time.millisecond = 789;\n base::Time timeline_offset;\n EXPECT_TRUE(base::Time::FromUTCExploded(exploded_time, &timeline_offset));\n\n timeline_offset += base::Microseconds(123);\n\n return timeline_offset;\n}\n\n#if BUILDFLAG(IS_MAC)\nclass ScopedVerboseLogEnabler {\n public:\n ScopedVerboseLogEnabler() : old_level_(logging::GetMinLogLevel()) {\n logging::SetMinLogLevel(-1);\n }\n\n ScopedVerboseLogEnabler(const ScopedVerboseLogEnabler&) = delete;\n ScopedVerboseLogEnabler& operator=(const ScopedVerboseLogEnabler&) = delete;\n\n ~ScopedVerboseLogEnabler() { logging::SetMinLogLevel(old_level_); }\n\n private:\n const int old_level_;\n};\n#endif\n\nenum PromiseResult { RESOLVED, REJECTED };\n\n// Provides the test key in response to the encrypted event.\nclass KeyProvidingApp : public FakeEncryptedMedia::AppBase {\n public:\n KeyProvidingApp() = default;\n\n void OnResolveWithSession(PromiseResult expected,\n const std::string& session_id) {\n EXPECT_EQ(expected, RESOLVED);\n EXPECT_GT(session_id.length(), 0ul);\n current_session_id_ = session_id;\n }\n\n void OnResolve(PromiseResult expected) { EXPECT_EQ(expected, RESOLVED); }\n\n void OnReject(PromiseResult expected,\n media::CdmPromise::Exception exception_code,\n uint32_t system_code,\n const std::string& error_message) {\n EXPECT_EQ(expected, REJECTED) << error_message;\n }\n\n std::unique_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected) {\n auto promise = std::make_unique<media::CdmCallbackPromise<>>(\n base::BindOnce(&KeyProvidingApp::OnResolve, base::Unretained(this),\n expected),\n base::BindOnce(&KeyProvidingApp::OnReject, base::Unretained(this),\n expected));\n return promise;\n }\n\n std::unique_ptr<NewSessionCdmPromise> CreateSessionPromise(\n PromiseResult expected) {\n auto promise = std::make_unique<media::CdmCallbackPromise<std::string>>(\n base::BindOnce(&KeyProvidingApp::OnResolveWithSession,\n base::Unretained(this), expected),\n base::BindOnce(&KeyProvidingApp::OnReject, base::Unretained(this),\n expected));\n return promise;\n }\n\n void OnSessionMessage(const std::string& session_id,\n CdmMessageType message_type,\n const std::vector<uint8_t>& message,\n AesDecryptor* decryptor) override {\n EXPECT_FALSE(session_id.empty());\n EXPECT_FALSE(message.empty());\n EXPECT_EQ(current_session_id_, session_id);\n EXPECT_EQ(CdmMessageType::LICENSE_REQUEST, message_type);\n\n // Extract the key ID from |message|. For Clear Key this is a JSON object\n // containing a set of \"kids\". There should only be 1 key ID in |message|.\n std::string message_string(message.begin(), message.end());\n KeyIdList key_ids;\n std::string error_message;\n EXPECT_TRUE(ExtractKeyIdsFromKeyIdsInitData(message_string, &key_ids,\n &error_message))\n << error_message;\n EXPECT_EQ(1u, key_ids.size());\n\n // Determine the key that matches the key ID |key_ids[0]|.\n std::vector<uint8_t> key;\n EXPECT_TRUE(LookupKey(key_ids[0], &key));\n\n // Update the session with the key ID and key.\n std::string jwk = GenerateJWKSet(key.data(), key.size(), key_ids[0].data(),\n key_ids[0].size());\n decryptor->UpdateSession(session_id,\n std::vector<uint8_t>(jwk.begin(), jwk.end()),\n CreatePromise(RESOLVED));\n }\n\n void OnSessionClosed(const std::string& session_id,\n CdmSessionClosedReason /*reason*/) override {\n EXPECT_EQ(current_session_id_, session_id);\n }\n\n void OnSessionKeysChange(const std::string& session_id,\n bool has_additional_usable_key,\n CdmKeysInfo keys_info) override {\n EXPECT_EQ(current_session_id_, session_id);\n EXPECT_EQ(has_additional_usable_key, true);\n }\n\n void OnSessionExpirationUpdate(const std::string& session_id,\n base::Time new_expiry_time) override {\n EXPECT_EQ(current_session_id_, session_id);\n }\n\n void OnEncryptedMediaInitData(EmeInitDataType init_data_type,\n const std::vector<uint8_t>& init_data,\n AesDecryptor* decryptor) override {\n // Since only 1 session is created, skip the request if the |init_data|\n // has been seen before (no need to add the same key again).\n if (init_data == prev_init_data_)\n return;\n prev_init_data_ = init_data;\n\n if (current_session_id_.empty()) {\n decryptor->CreateSessionAndGenerateRequest(\n CdmSessionType::kTemporary, init_data_type, init_data,\n CreateSessionPromise(RESOLVED));\n EXPECT_FALSE(current_session_id_.empty());\n }\n }\n\n virtual bool LookupKey(const std::vector<uint8_t>& key_id,\n std::vector<uint8_t>* key) {\n // No key rotation.\n return LookupTestKeyVector(key_id, false, key);\n }\n\n std::string current_session_id_;\n std::vector<uint8_t> prev_init_data_;\n};\n\nclass RotatingKeyProvidingApp : public KeyProvidingApp {\n public:\n RotatingKeyProvidingApp() : num_distinct_need_key_calls_(0) {}\n ~RotatingKeyProvidingApp() override {\n // Expect that OnEncryptedMediaInitData is fired multiple times with\n // different |init_data|.\n EXPECT_GT(num_distinct_need_key_calls_, 1u);\n }\n\n void OnEncryptedMediaInitData(EmeInitDataType init_data_type,\n const std::vector<uint8_t>& init_data,\n AesDecryptor* decryptor) override {\n // Skip the request if the |init_data| has been seen.\n if (init_data == prev_init_data_)\n return;\n prev_init_data_ = init_data;\n ++num_distinct_need_key_calls_;\n\n decryptor->CreateSessionAndGenerateRequest(CdmSessionType::kTemporary,\n init_data_type, init_data,\n CreateSessionPromise(RESOLVED));\n }\n\n bool LookupKey(const std::vector<uint8_t>& key_id,\n std::vector<uint8_t>* key) override {\n // With key rotation.\n return LookupTestKeyVector(key_id, true, key);\n }\n\n uint32_t num_distinct_need_key_calls_;\n};\n\n// Ignores the encrypted event and does not perform a license request.\nclass NoResponseApp : public FakeEncryptedMedia::AppBase {\n public:\n void OnSessionMessage(const std::string& session_id,\n CdmMessageType message_type,\n const std::vector<uint8_t>& message,\n AesDecryptor* decryptor) override {\n EXPECT_FALSE(session_id.empty());\n EXPECT_FALSE(message.empty());\n FAIL() << \"Unexpected Message\";\n }\n\n void OnSessionClosed(const std::string& session_id,\n CdmSessionClosedReason /*reason*/) override {\n EXPECT_FALSE(session_id.empty());\n FAIL() << \"Unexpected Closed\";\n }\n\n void OnSessionKeysChange(const std::string& session_id,\n bool has_additional_usable_key,\n CdmKeysInfo keys_info) override {\n EXPECT_FALSE(session_id.empty());\n EXPECT_EQ(has_additional_usable_key, true);\n }\n\n void OnSessionExpirationUpdate(const std::string& session_id,\n base::Time new_expiry_time) override {}\n\n void OnEncryptedMediaInitData(EmeInitDataType init_data_type,\n const std::vector<uint8_t>& init_data,\n AesDecryptor* decryptor) override {}\n};\n\n// A rough simulation of GpuVideoDecoder that fails every Decode() request. This\n// is used to test post-Initialize() fallback paths.\nclass FailingVideoDecoder : public VideoDecoder {\n public:\n VideoDecoderType GetDecoderType() const override {\n return VideoDecoderType::kTesting;\n }\n void Initialize(const VideoDecoderConfig& config,\n bool low_delay,\n CdmContext* cdm_context,\n InitCB init_cb,\n const OutputCB& output_cb,\n const WaitingCB& waiting_cb) override {\n std::move(init_cb).Run(DecoderStatus::Codes::kOk);\n }\n void Decode(scoped_refptr<DecoderBuffer> buffer,\n DecodeCB decode_cb) override {\n base::ThreadTaskRunnerHandle::Get()->PostTask(\n FROM_HERE,\n base::BindOnce(std::move(decode_cb), DecoderStatus::Codes::kFailed));\n }\n void Reset(base::OnceClosure closure) override { std::move(closure).Run(); }\n bool NeedsBitstreamConversion() const override { return true; }\n};\n\nclass PipelineIntegrationTest : public testing::Test,\n public PipelineIntegrationTestBase {\n public:\n // Verifies that seeking works properly for ChunkDemuxer when the\n // seek happens while there is a pending read on the ChunkDemuxer\n // and no data is available.\n bool TestSeekDuringRead(const std::string& filename,\n int initial_append_size,\n base::TimeDelta start_seek_time,\n base::TimeDelta seek_time,\n int seek_file_position,\n int seek_append_size) {\n TestMediaSource source(filename, initial_append_size);\n\n if (StartPipelineWithMediaSource(&source, kNoClockless, nullptr) !=\n PIPELINE_OK) {\n return false;\n }\n\n Play();\n if (!WaitUntilCurrentTimeIsAfter(start_seek_time))\n return false;\n\n source.Seek(seek_time, seek_file_position, seek_append_size);\n if (!Seek(seek_time))\n return false;\n\n source.EndOfStream();\n\n source.Shutdown();\n Stop();\n return true;\n }\n\n void OnEnabledAudioTracksChanged(\n const std::vector<MediaTrack::Id>& enabled_track_ids) {\n base::RunLoop run_loop;\n pipeline_->OnEnabledAudioTracksChanged(enabled_track_ids,\n run_loop.QuitClosure());\n run_loop.Run();\n }\n\n void OnSelectedVideoTrackChanged(\n absl::optional<MediaTrack::Id> selected_track_id) {\n base::RunLoop run_loop;\n pipeline_->OnSelectedVideoTrackChanged(selected_track_id,\n run_loop.QuitClosure());\n run_loop.Run();\n }\n};\n\nstruct PlaybackTestData {\n const std::string filename;\n const uint32_t start_time_ms;\n const uint32_t duration_ms;\n};\n\nstruct MSEPlaybackTestData {\n const std::string filename;\n const size_t append_bytes;\n const uint32_t duration_ms;\n};\n\n// Tells gtest how to print our PlaybackTestData structure.\nstd::ostream& operator<<(std::ostream& os, const PlaybackTestData& data) {\n return os << data.filename;\n}\n\nstd::ostream& operator<<(std::ostream& os, const MSEPlaybackTestData& data) {\n return os << data.filename;\n}\n\nclass BasicPlaybackTest : public PipelineIntegrationTest,\n public testing::WithParamInterface<PlaybackTestData> {\n};\n\nTEST_P(BasicPlaybackTest, PlayToEnd) {\n PlaybackTestData data = GetParam();\n\n ASSERT_EQ(PIPELINE_OK, Start(data.filename, kUnreliableDuration));\n EXPECT_EQ(data.start_time_ms, demuxer_->GetStartTime().InMilliseconds());\n EXPECT_EQ(data.duration_ms, pipeline_->GetMediaDuration().InMilliseconds());\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nconst PlaybackTestData kOpenCodecsTests[] = {{\"bear-vp9-i422.webm\", 0, 2736}};\n\nINSTANTIATE_TEST_SUITE_P(OpenCodecs,\n BasicPlaybackTest,\n testing::ValuesIn(kOpenCodecsTests));\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n\nclass BasicMSEPlaybackTest\n : public ::testing::WithParamInterface<MSEPlaybackTestData>,\n public PipelineIntegrationTest {\n protected:\n void PlayToEnd() {\n MSEPlaybackTestData data = GetParam();\n\n TestMediaSource source(data.filename, data.append_bytes);\n ASSERT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kNormal, nullptr));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(data.duration_ms,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());\n source.Shutdown();\n Stop();\n }\n};\n\nTEST_P(BasicMSEPlaybackTest, PlayToEnd) {\n PlayToEnd();\n}\n\nconst PlaybackTestData kADTSTests[] = {\n {\"bear-audio-main-aac.aac\", 0, 2708},\n {\"bear-audio-lc-aac.aac\", 0, 2791},\n {\"bear-audio-implicit-he-aac-v1.aac\", 0, 2829},\n {\"bear-audio-implicit-he-aac-v2.aac\", 0, 2900},\n};\n\n// TODO(chcunningham): Migrate other basic playback tests to TEST_P.\nINSTANTIATE_TEST_SUITE_P(ProprietaryCodecs,\n BasicPlaybackTest,\n testing::ValuesIn(kADTSTests));\n\nconst MSEPlaybackTestData kMediaSourceADTSTests[] = {\n {\"bear-audio-main-aac.aac\", kAppendWholeFile, 2773},\n {\"bear-audio-lc-aac.aac\", kAppendWholeFile, 2794},\n {\"bear-audio-implicit-he-aac-v1.aac\", kAppendWholeFile, 2858},\n {\"bear-audio-implicit-he-aac-v2.aac\", kAppendWholeFile, 2901},\n};\n\n// TODO(chcunningham): Migrate other basic MSE playback tests to TEST_P.\nINSTANTIATE_TEST_SUITE_P(ProprietaryCodecs,\n BasicMSEPlaybackTest,\n testing::ValuesIn(kMediaSourceADTSTests));\n\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\nstruct MSEChangeTypeTestData {\n const MSEPlaybackTestData file_one;\n const MSEPlaybackTestData file_two;\n};\n\nclass MSEChangeTypeTest\n : public ::testing::WithParamInterface<\n std::tuple<MSEPlaybackTestData, MSEPlaybackTestData>>,\n public PipelineIntegrationTest {\n public:\n // Populate meaningful test suffixes instead of /0, /1, etc.\n struct PrintToStringParamName {\n template <class ParamType>\n std::string operator()(\n const testing::TestParamInfo<ParamType>& info) const {\n std::stringstream ss;\n ss << std::get<0>(info.param) << \"_AND_\" << std::get<1>(info.param);\n std::string s = ss.str();\n // Strip out invalid param name characters.\n std::stringstream ss2;\n for (size_t i = 0; i < s.size(); ++i) {\n if (isalnum(s[i]) || s[i] == '_')\n ss2 << s[i];\n }\n return ss2.str();\n }\n };\n\n protected:\n void PlayBackToBack() {\n // TODO(wolenetz): Consider a modified, composable, hash that lets us\n // combine known hashes for two files to generate an expected hash for when\n // both are played. For now, only the duration (and successful append and\n // play-to-end) are verified.\n MSEPlaybackTestData file_one = std::get<0>(GetParam());\n MSEPlaybackTestData file_two = std::get<1>(GetParam());\n\n // Start in 'sequence' appendMode, because some test media begin near enough\n // to time 0, resulting in gaps across the changeType boundary in buffered\n // media timeline.\n // TODO(wolenetz): Switch back to 'segments' mode once we have some\n // incubation of a way to flexibly allow playback through unbuffered\n // regions. Known test media requiring sequence mode: MP3-in-MP2T\n TestMediaSource source(file_one.filename, file_one.append_bytes, true);\n ASSERT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kNormal, nullptr));\n source.EndOfStream();\n\n // Transitions between VP8A and other test media can trigger this again.\n EXPECT_CALL(*this, OnVideoOpacityChange(_)).Times(AnyNumber());\n\n Ranges<base::TimeDelta> ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, ranges.size());\n EXPECT_EQ(0, ranges.start(0).InMilliseconds());\n base::TimeDelta file_one_end_time = ranges.end(0);\n EXPECT_EQ(file_one.duration_ms, file_one_end_time.InMilliseconds());\n\n // Change type and append |file_two| with start time abutting end of\n // the previous buffered range.\n source.UnmarkEndOfStream();\n source.ChangeType(GetMimeTypeForFile(file_two.filename));\n scoped_refptr<DecoderBuffer> file_two_contents =\n ReadTestDataFile(file_two.filename);\n source.AppendAtTime(file_one_end_time, file_two_contents->data(),\n file_two.append_bytes == kAppendWholeFile\n ? file_two_contents->data_size()\n : file_two.append_bytes);\n source.EndOfStream();\n ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, ranges.size());\n EXPECT_EQ(0, ranges.start(0).InMilliseconds());\n\n base::TimeDelta file_two_actual_duration =\n ranges.end(0) - file_one_end_time;\n EXPECT_EQ(file_two_actual_duration.InMilliseconds(), file_two.duration_ms);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());\n source.Shutdown();\n Stop();\n }\n};\n\nTEST_P(MSEChangeTypeTest, PlayBackToBack) {\n PlayBackToBack();\n}\n\nconst MSEPlaybackTestData kMediaSourceAudioFiles[] = {\n // MP3\n {\"sfx.mp3\", kAppendWholeFile, 313},\n\n // Opus in WebM\n {\"sfx-opus-441.webm\", kAppendWholeFile, 301},\n\n // Vorbis in WebM\n {\"bear-320x240-audio-only.webm\", kAppendWholeFile, 2768},\n\n // FLAC in MP4\n {\"sfx-flac_frag.mp4\", kAppendWholeFile, 288},\n\n // Opus in MP4\n {\"sfx-opus_frag.mp4\", kAppendWholeFile, 301},\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n // AAC in ADTS\n {\"bear-audio-main-aac.aac\", kAppendWholeFile, 2773},\n\n // AAC in MP4\n {\"bear-640x360-a_frag.mp4\", kAppendWholeFile, 2803},\n\n#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n // MP3 in MP2T\n {\"bear-audio-mp4a.6B.ts\", kAppendWholeFile, 1097},\n#endif // BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n};\n\nconst MSEPlaybackTestData kMediaSourceVideoFiles[] = {\n // VP9 in WebM\n {\"bear-vp9.webm\", kAppendWholeFile, kVP9WebMFileDurationMs},\n\n // VP9 in MP4\n {\"bear-320x240-v_frag-vp9.mp4\", kAppendWholeFile, 2736},\n\n // VP8 in WebM\n {\"bear-vp8a.webm\", kAppendWholeFile, kVP8AWebMFileDurationMs},\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\n // AV1 in MP4\n {\"bear-av1.mp4\", kAppendWholeFile, kVP9WebMFileDurationMs},\n\n // AV1 in WebM\n {\"bear-av1.webm\", kAppendWholeFile, kVP9WebMFileDurationMs},\n#endif // BUILDFLAG(ENABLE_AV1_DECODER)\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n // H264 AVC3 in MP4\n {\"bear-1280x720-v_frag-avc3.mp4\", kAppendWholeFile,\n k1280IsoAVC3FileDurationMs},\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n};\n\nINSTANTIATE_TEST_SUITE_P(\n AudioOnly,\n MSEChangeTypeTest,\n testing::Combine(testing::ValuesIn(kMediaSourceAudioFiles),\n testing::ValuesIn(kMediaSourceAudioFiles)),\n MSEChangeTypeTest::PrintToStringParamName());\n\nINSTANTIATE_TEST_SUITE_P(\n VideoOnly,\n MSEChangeTypeTest,\n testing::Combine(testing::ValuesIn(kMediaSourceVideoFiles),\n testing::ValuesIn(kMediaSourceVideoFiles)),\n MSEChangeTypeTest::PrintToStringParamName());\n\nTEST_F(PipelineIntegrationTest, BasicPlayback) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-opus.ogg\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg_4ch_ChannelMapping2) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-opus-4ch-channelmapping2.ogg\", kWebAudio));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg_11ch_ChannelMapping2) {\n ASSERT_EQ(PIPELINE_OK,\n Start(\"bear-opus-11ch-channelmapping2.ogg\", kWebAudio));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_HASH_EQ(\"f0be120a90a811506777c99a2cdf7cc1\", GetVideoHash());\n EXPECT_HASH_EQ(\"-3.59,-2.06,-0.43,2.15,0.77,-0.95,\", GetAudioHash());\n EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());\n}\n\nbase::TimeDelta TimestampMs(int milliseconds) {\n return base::Milliseconds(milliseconds);\n}\n\nTEST_F(PipelineIntegrationTest, WaveLayoutChange) {\n ASSERT_EQ(PIPELINE_OK, Start(\"layout_change.wav\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// TODO(https://crbug.com/1354581): At most one of Playback9Channels48000hz and\n// Playback9Channels44100hz will pass, because for 9+ channel files the hardware\n// sample rate has to match the file's sample rate. They are both disabled\n// because different CI configurations have different hardware sample rates. To\n// run the tests, enable them both and expect at most one of them to pass.\nTEST_F(PipelineIntegrationTest, DISABLED_Playback9Channels48000hz) {\n EXPECT_EQ(PIPELINE_OK, Start(\"9ch.wav\"));\n}\n\nTEST_F(PipelineIntegrationTest, DISABLED_Playback9Channels44100hz) {\n EXPECT_EQ(PIPELINE_OK, Start(\"9ch_44100.wav\"));\n}\n\nTEST_F(PipelineIntegrationTest, PlaybackStereo48000hz) {\n EXPECT_EQ(PIPELINE_OK, Start(\"stereo_48000.wav\"));\n}\n\nTEST_F(PipelineIntegrationTest, PlaybackWithAudioTrackDisabledThenEnabled) {\n#if BUILDFLAG(IS_MAC)\n // Enable scoped logs to help track down hangs. http://crbug.com/1014646\n ScopedVerboseLogEnabler scoped_log_enabler;\n#endif\n\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kHashed | kNoClockless));\n\n // Disable audio.\n std::vector<MediaTrack::Id> empty;\n OnEnabledAudioTracksChanged(empty);\n\n // Seek to flush the pipeline and ensure there's no prerolled audio data.\n ASSERT_TRUE(Seek(base::TimeDelta()));\n\n Play();\n const base::TimeDelta k500ms = TimestampMs(500);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(k500ms));\n Pause();\n\n // Verify that no audio has been played, since we disabled audio tracks.\n EXPECT_HASH_EQ(kNullAudioHash, GetAudioHash());\n\n // Re-enable audio.\n std::vector<MediaTrack::Id> audio_track_id;\n audio_track_id.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(audio_track_id);\n\n // Restart playback from 500ms position.\n ASSERT_TRUE(Seek(k500ms));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify that audio has been playing after being enabled.\n EXPECT_HASH_EQ(\"-1.53,0.21,1.23,1.56,-0.34,-0.94,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, PlaybackWithVideoTrackDisabledThenEnabled) {\n#if BUILDFLAG(IS_MAC)\n // Enable scoped logs to help track down hangs. http://crbug.com/1014646\n ScopedVerboseLogEnabler scoped_log_enabler;\n#endif\n\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kHashed | kNoClockless));\n\n // Disable video.\n OnSelectedVideoTrackChanged(absl::nullopt);\n\n // Seek to flush the pipeline and ensure there's no prerolled video data.\n ASSERT_TRUE(Seek(base::TimeDelta()));\n\n // Reset the video hash in case some of the prerolled video frames have been\n // hashed already.\n ResetVideoHash();\n\n Play();\n const base::TimeDelta k500ms = TimestampMs(500);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(k500ms));\n Pause();\n\n // Verify that no video has been rendered, since we disabled video tracks.\n EXPECT_HASH_EQ(kNullVideoHash, GetVideoHash());\n\n // Re-enable video.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n\n // Seek to flush video pipeline and reset the video hash again to clear state\n // if some prerolled frames got hashed after enabling video.\n ASSERT_TRUE(Seek(base::TimeDelta()));\n ResetVideoHash();\n\n // Restart playback from 500ms position.\n ASSERT_TRUE(Seek(k500ms));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify that video has been rendered after being enabled.\n EXPECT_HASH_EQ(\"fd59357dfd9c144ab4fb8181b2de32c3\", GetVideoHash());\n}\n\nTEST_F(PipelineIntegrationTest, TrackStatusChangesBeforePipelineStarted) {\n std::vector<MediaTrack::Id> empty_track_ids;\n OnEnabledAudioTracksChanged(empty_track_ids);\n OnSelectedVideoTrackChanged(absl::nullopt);\n}\n\nTEST_F(PipelineIntegrationTest, TrackStatusChangesAfterPipelineEnded) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n std::vector<MediaTrack::Id> track_ids;\n // Disable audio track.\n OnEnabledAudioTracksChanged(track_ids);\n // Re-enable audio track.\n track_ids.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(track_ids);\n // Disable video track.\n OnSelectedVideoTrackChanged(absl::nullopt);\n // Re-enable video track.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n}\n\n// TODO(crbug.com/40101269): Enable test when MacOS flake is fixed.\n#if BUILDFLAG(IS_MAC)\n#define MAYBE_TrackStatusChangesWhileSuspended \\\n DISABLED_TrackStatusChangesWhileSuspended\n#else\n#define MAYBE_TrackStatusChangesWhileSuspended TrackStatusChangesWhileSuspended\n#endif\n\nTEST_F(PipelineIntegrationTest, MAYBE_TrackStatusChangesWhileSuspended) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n Play();\n\n ASSERT_TRUE(Suspend());\n\n // These get triggered every time playback is resumed.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240)))\n .Times(AnyNumber());\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(AnyNumber());\n\n std::vector<MediaTrack::Id> track_ids;\n\n // Disable audio track.\n OnEnabledAudioTracksChanged(track_ids);\n ASSERT_TRUE(Resume(TimestampMs(100)));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n ASSERT_TRUE(Suspend());\n\n // Re-enable audio track.\n track_ids.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(track_ids);\n ASSERT_TRUE(Resume(TimestampMs(200)));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(300)));\n ASSERT_TRUE(Suspend());\n\n // Disable video track.\n OnSelectedVideoTrackChanged(absl::nullopt);\n ASSERT_TRUE(Resume(TimestampMs(300)));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(400)));\n ASSERT_TRUE(Suspend());\n\n // Re-enable video track.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n ASSERT_TRUE(Resume(TimestampMs(400)));\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, ReinitRenderersWhileAudioTrackIsDisabled) {\n // This test is flaky without kNoClockless, see crbug.com/788387.\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n Play();\n\n // These get triggered every time playback is resumed.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240)))\n .Times(AnyNumber());\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(AnyNumber());\n\n // Disable the audio track.\n std::vector<MediaTrack::Id> track_ids;\n OnEnabledAudioTracksChanged(track_ids);\n // pipeline.Suspend() releases renderers and pipeline.Resume() recreates and\n // reinitializes renderers while the audio track is disabled.\n ASSERT_TRUE(Suspend());\n ASSERT_TRUE(Resume(TimestampMs(100)));\n // Now re-enable the audio track, playback should continue successfully.\n EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)).Times(1);\n track_ids.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(track_ids);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, ReinitRenderersWhileVideoTrackIsDisabled) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n Play();\n\n // These get triggered every time playback is resumed.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240)))\n .Times(AnyNumber());\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(AnyNumber());\n\n // Disable the video track.\n OnSelectedVideoTrackChanged(absl::nullopt);\n // pipeline.Suspend() releases renderers and pipeline.Resume() recreates and\n // reinitializes renderers while the video track is disabled.\n ASSERT_TRUE(Suspend());\n ASSERT_TRUE(Resume(TimestampMs(100)));\n // Now re-enable the video track, playback should continue successfully.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, PipelineStoppedWhileAudioRestartPending) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n Play();\n\n // Disable audio track first, to re-enable it later and stop the pipeline\n // (which destroys the media renderer) while audio restart is pending.\n std::vector<MediaTrack::Id> track_ids;\n OnEnabledAudioTracksChanged(track_ids);\n\n // Playback is paused while all audio tracks are disabled.\n\n track_ids.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(track_ids);\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, PipelineStoppedWhileVideoRestartPending) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n Play();\n\n // Disable video track first, to re-enable it later and stop the pipeline\n // (which destroys the media renderer) while video restart is pending.\n OnSelectedVideoTrackChanged(absl::nullopt);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, SwitchAudioTrackDuringPlayback) {\n ASSERT_EQ(PIPELINE_OK, Start(\"multitrack-3video-2audio.webm\", kNoClockless));\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(100)));\n // The first audio track (TrackId=4) is enabled by default. This should\n // disable TrackId=4 and enable TrackId=5.\n std::vector<MediaTrack::Id> track_ids;\n track_ids.push_back(MediaTrack::Id(\"5\"));\n OnEnabledAudioTracksChanged(track_ids);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, SwitchVideoTrackDuringPlayback) {\n ASSERT_EQ(PIPELINE_OK, Start(\"multitrack-3video-2audio.webm\", kNoClockless));\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(100)));\n // The first video track (TrackId=1) is enabled by default. This should\n // disable TrackId=1 and enable TrackId=2.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"2\"));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusOggTrimmingHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"opus-trimming-test.ogg\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n ASSERT_TRUE(Seek(base::Seconds(1)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n ASSERT_TRUE(Seek(base::Milliseconds(6360)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusWebmTrimmingHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"opus-trimming-test.webm\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n ASSERT_TRUE(Seek(base::Seconds(1)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n ASSERT_TRUE(Seek(base::Milliseconds(6360)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusMp4TrimmingHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"opus-trimming-test.mp4\", kHashed));\n\n Play();\n\n // TODO(dalecurtis): The test clip currently does not have the edit list\n // entries required to achieve correctness here. Delete this comment and\n // uncomment the EXPECT_HASH_EQ lines when https://crbug.com/876544 is fixed.\n\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n ASSERT_TRUE(Seek(base::Seconds(1)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n ASSERT_TRUE(Seek(base::Milliseconds(6360)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlaybackOpusWebmTrimmingHashed) {\n TestMediaSource source(\"opus-trimming-test.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n base::TimeDelta seek_time = base::Seconds(1);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n seek_time = base::Milliseconds(6360);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlaybackOpusMp4TrimmingHashed) {\n TestMediaSource source(\"opus-trimming-test.mp4\", kAppendWholeFile);\n\n // TODO(dalecurtis): The test clip currently does not have the edit list\n // entries required to achieve correctness here, so we're manually specifying\n // the edits using append window trimming.\n //\n // It's unclear if MSE actually supports edit list features required to\n // achieve correctness either. Delete this comment and remove the manual\n // SetAppendWindow() if/when https://crbug.com/876544 is fixed.\n source.SetAppendWindow(base::TimeDelta(), base::TimeDelta(),\n base::Microseconds(12720021));\n\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n base::TimeDelta seek_time = base::Seconds(1);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n seek_time = base::Milliseconds(6360);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusWebmHashed_MonoOutput) {\n ASSERT_EQ(PIPELINE_OK,\n Start(\"bunny-opus-intensity-stereo.webm\", kHashed | kMonoOutput));\n\n // File should have stereo output, which we know to be encoded using \"phase\n // intensity\". Downmixing such files to MONO produces artifacts unless the\n // decoder performs the downmix, which disables \"phase inversion\". See\n // http://crbug.com/806219\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n ASSERT_EQ(config.channel_layout(), CHANNEL_LAYOUT_STEREO);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Hash has very slight differences when phase inversion is enabled.\n EXPECT_HASH_EQ(kOpusMonoOutputHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusPrerollExceedsCodecDelay) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-opus.webm\", kHashed));\n\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n\n // Verify that this file's preroll is not eclipsed by the codec delay so we\n // can detect when preroll is not properly performed.\n base::TimeDelta codec_delay = base::Seconds(\n static_cast<double>(config.codec_delay()) / config.samples_per_second());\n ASSERT_GT(config.seek_preroll(), codec_delay);\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());\n\n // Seek halfway through the file to invoke seek preroll.\n ASSERT_TRUE(Seek(base::Seconds(1.414)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusMp4PrerollExceedsCodecDelay) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-opus.mp4\", kHashed));\n\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n\n // Verify that this file's preroll is not eclipsed by the codec delay so we\n // can detect when preroll is not properly performed.\n base::TimeDelta codec_delay = base::Seconds(\n static_cast<double>(config.codec_delay()) / config.samples_per_second());\n ASSERT_GT(config.seek_preroll(), codec_delay);\n\n // TODO(dalecurtis): The test clip currently does not have the edit list\n // entries required to achieve correctness here. Delete this comment and\n // uncomment the EXPECT_HASH_EQ lines when https://crbug.com/876544 is fixed.\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());\n\n // Seek halfway through the file to invoke seek preroll.\n ASSERT_TRUE(Seek(base::Seconds(1.414)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlaybackOpusPrerollExceedsCodecDelay) {\n TestMediaSource source(\"bear-opus.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n\n // Verify that this file's preroll is not eclipsed by the codec delay so we\n // can detect when preroll is not properly performed.\n base::TimeDelta codec_delay = base::Seconds(\n static_cast<double>(config.codec_delay()) / config.samples_per_second());\n ASSERT_GT(config.seek_preroll(), codec_delay);\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());\n\n // Seek halfway through the file to invoke seek preroll.\n base::TimeDelta seek_time = base::Seconds(1.414);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_BasicPlaybackOpusMp4PrerollExceedsCodecDelay) {\n TestMediaSource source(\"bear-opus.mp4\", kAppendWholeFile);\n\n // TODO(dalecurtis): The test clip currently does not have the edit list\n // entries required to achieve correctness here, so we're manually specifying\n // the edits using append window trimming.\n //\n // It's unclear if MSE actually supports edit list features required to\n // achieve correctness either. Delete this comment and remove the manual\n // SetAppendWindow() if/when https://crbug.com/876544 is fixed.\n source.SetAppendWindow(base::TimeDelta(), base::TimeDelta(),\n base::Microseconds(2740834));\n\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n\n // Verify that this file's preroll is not eclipsed by the codec delay so we\n // can detect when preroll is not properly performed.\n base::TimeDelta codec_delay = base::Seconds(\n static_cast<double>(config.codec_delay()) / config.samples_per_second());\n ASSERT_GT(config.seek_preroll(), codec_delay);\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());\n\n // Seek halfway through the file to invoke seek preroll.\n base::TimeDelta seek_time = base::Seconds(1.414);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackLive) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240-live.webm\", kHashed));\n\n // Live stream does not have duration in the initialization segment.\n // It will be set after the entire file is available.\n EXPECT_CALL(*this, OnDurationChange()).Times(1);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_HASH_EQ(\"f0be120a90a811506777c99a2cdf7cc1\", GetVideoHash());\n EXPECT_HASH_EQ(\"-3.59,-2.06,-0.43,2.15,0.77,-0.95,\", GetAudioHash());\n EXPECT_EQ(kLiveTimelineOffset(), demuxer_->GetTimelineOffset());\n}\n\nTEST_F(PipelineIntegrationTest, S32PlaybackHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx_s32le.wav\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, F32PlaybackHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx_f32le.wav\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackEncrypted) {\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n set_encrypted_media_init_data_cb(\n base::BindRepeating(&FakeEncryptedMedia::OnEncryptedMediaInitData,\n base::Unretained(&encrypted_media)));\n\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240-av_enc-av.webm\",\n encrypted_media.GetCdmContext()));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, FlacPlaybackHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx.flac\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback) {\n TestMediaSource source(\"bear-320x240.webm\", 219229);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(k320WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EosBeforeDemuxerOpened) {\n // After appending only a partial initialization segment, marking end of\n // stream should let the test complete with error indicating failure to open\n // demuxer. Here we append only the first 10 bytes of a test WebM, definitely\n // less than the ~4400 bytes needed to parse its full initialization segment.\n TestMediaSource source(\"bear-320x240.webm\", 10);\n source.set_do_eos_after_next_append(true);\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n}\n\nTEST_F(PipelineIntegrationTest, MSE_CorruptedFirstMediaSegment) {\n // After successful initialization segment append completing demuxer opening,\n // immediately append a corrupted media segment to trigger parse error while\n // pipeline is still completing renderer setup.\n TestMediaSource source(\"bear-320x240_corrupted_after_init_segment.webm\",\n 4380);\n source.set_expected_append_result(\n TestMediaSource::ExpectedAppendResult::kFailure);\n EXPECT_EQ(CHUNK_DEMUXER_ERROR_APPEND_FAILED,\n StartPipelineWithMediaSource(&source));\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_Live) {\n TestMediaSource source(\"bear-320x240-live.webm\", 219221);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(k320WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(kLiveTimelineOffset(), demuxer_->GetTimelineOffset());\n source.Shutdown();\n Stop();\n}\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_WebM) {\n TestMediaSource source(\"bear-av1.webm\", 18898);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_10bit_WebM) {\n TestMediaSource source(\"bear-av1-320x180-10bit.webm\", 19076);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YUV420P10);\n Stop();\n}\n\n#endif\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VP9_WebM) {\n TestMediaSource source(\"bear-vp9.webm\", 67504);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VP9_BlockGroup_WebM) {\n TestMediaSource source(\"bear-vp9-blockgroup.webm\", 67871);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VP8A_WebM) {\n TestMediaSource source(\"bear-vp8a.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP8AWebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_AV1_WebM) {\n TestMediaSource source(\"bear-av1-480x360.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n const gfx::Size kNewSize(640, 480);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-av1-640x480.webm\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + kAV1640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n#endif // BUILDFLAG(ENABLE_AV1_DECODER)\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_WebM) {\n TestMediaSource source(\"bear-320x240-16x9-aspect.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n const gfx::Size kNewSize(640, 360);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-640x360.webm\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_AudioConfigChange_WebM) {\n TestMediaSource source(\"bear-320x240-audio-only.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n const int kNewSampleRate = 48000;\n EXPECT_CALL(*this,\n OnAudioConfigChange(::testing::Property(\n &AudioDecoderConfig::samples_per_second, kNewSampleRate)))\n .Times(1);\n\n // A higher sample rate will cause the audio buffer durations to change. This\n // should not manifest as a timestamp gap in AudioTimestampValidator.\n // Timestamp expectations should be reset across config changes.\n EXPECT_MEDIA_LOG(Not(HasSubstr(\"Large timestamp gap detected\")))\n .Times(AnyNumber());\n\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-320x240-audio-only-48khz.webm\");\n ASSERT_TRUE(source.AppendAtTime(base::Seconds(kAppendTimeSec),\n second_file->data(),\n second_file->data_size()));\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(3774, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_RemoveUpdatesBufferedRanges) {\n TestMediaSource source(\"bear-320x240.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n auto buffered_ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, buffered_ranges.size());\n EXPECT_EQ(0, buffered_ranges.start(0).InMilliseconds());\n EXPECT_EQ(k320WebMFileDurationMs, buffered_ranges.end(0).InMilliseconds());\n\n source.RemoveRange(base::Milliseconds(1000),\n base::Milliseconds(k320WebMFileDurationMs));\n task_environment_.RunUntilIdle();\n\n buffered_ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, buffered_ranges.size());\n EXPECT_EQ(0, buffered_ranges.start(0).InMilliseconds());\n EXPECT_EQ(1001, buffered_ranges.end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\n// This test case imitates media playback with advancing media_time and\n// continuously adding new data. At some point we should reach the buffering\n// limit, after that MediaSource should evict some buffered data and that\n// evicted data shold be reflected in the change of media::Pipeline buffered\n// ranges (returned by GetBufferedTimeRanges). At that point the buffered ranges\n// will no longer start at 0.\nTEST_F(PipelineIntegrationTest, MSE_FillUpBuffer) {\n const char* input_filename = \"bear-320x240.webm\";\n TestMediaSource source(input_filename, kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.SetMemoryLimits(1048576);\n\n scoped_refptr<DecoderBuffer> file = ReadTestDataFile(input_filename);\n\n auto buffered_ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, buffered_ranges.size());\n do {\n // Advance media_time to the end of the currently buffered data\n base::TimeDelta media_time = buffered_ranges.end(0);\n source.Seek(media_time);\n // Ask MediaSource to evict buffered data if buffering limit has been\n // reached (the data will be evicted from the front of the buffered range).\n source.EvictCodedFrames(media_time, file->data_size());\n source.AppendAtTime(media_time, file->data(), file->data_size());\n task_environment_.RunUntilIdle();\n\n buffered_ranges = pipeline_->GetBufferedTimeRanges();\n } while (buffered_ranges.size() == 1 &&\n buffered_ranges.start(0) == base::Seconds(0));\n\n EXPECT_EQ(1u, buffered_ranges.size());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_GCWithDisabledVideoStream) {\n const char* input_filename = \"bear-320x240.webm\";\n TestMediaSource source(input_filename, kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n scoped_refptr<DecoderBuffer> file = ReadTestDataFile(input_filename);\n // The input file contains audio + video data. Assuming video data size is\n // larger than audio, so setting memory limits to half of file data_size will\n // ensure that video SourceBuffer is above memory limit and the audio\n // SourceBuffer is below the memory limit.\n source.SetMemoryLimits(file->data_size() / 2);\n\n // Disable the video track and start playback. Renderer won't read from the\n // disabled video stream, so the video stream read position should be 0.\n OnSelectedVideoTrackChanged(absl::nullopt);\n Play();\n\n // Wait until audio playback advances past 2 seconds and call MSE GC algorithm\n // to prepare for more data to be appended.\n base::TimeDelta media_time = base::Seconds(2);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(media_time));\n // At this point the video SourceBuffer is over the memory limit (see the\n // SetMemoryLimits comment above), but MSE GC should be able to remove some\n // of video data and return true indicating success, even though no data has\n // been read from the disabled video stream and its read position is 0.\n ASSERT_TRUE(source.EvictCodedFrames(media_time, 10));\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_Encrypted_WebM) {\n TestMediaSource source(\"bear-320x240-16x9-aspect-av_enc-av.webm\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n const gfx::Size kNewSize(640, 360);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-640x360-av_enc-av.webm\");\n\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_ClearThenEncrypted_WebM) {\n TestMediaSource source(\"bear-320x240-16x9-aspect.webm\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n const gfx::Size kNewSize(640, 360);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-640x360-av_enc-av.webm\");\n\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\n// Config change from encrypted to clear is allowed by the demuxer, and is\n// supported by the Renderer.\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_EncryptedThenClear_WebM) {\n TestMediaSource source(\"bear-320x240-16x9-aspect-av_enc-av.webm\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n const gfx::Size kNewSize(640, 360);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-640x360.webm\");\n\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\n#if defined(ARCH_CPU_X86_FAMILY) && !BUILDFLAG(IS_ANDROID)\nTEST_F(PipelineIntegrationTest, BasicPlaybackHi10PVP9) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x180-hi10p-vp9.webm\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHi12PVP9) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x180-hi12p-vp9.webm\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_MP4) {\n TestMediaSource source(\"bear-av1.mp4\", 24355);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_Audio_OPUS_MP4) {\n TestMediaSource source(\"bear-av1-opus.mp4\", 50253);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_10bit_MP4) {\n TestMediaSource source(\"bear-av1-320x180-10bit.mp4\", 19658);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAV110bitMp4FileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YUV420P10);\n Stop();\n}\n#endif\n\nTEST_F(PipelineIntegrationTest, MSE_FlacInMp4_Hashed) {\n TestMediaSource source(\"sfx-flac_frag.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(288, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx.mp3\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify codec delay and preroll are stripped.\n EXPECT_HASH_EQ(\"1.30,2.72,4.56,5.08,3.74,2.03,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed_FlacInMp4) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx-flac.mp4\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_AV1_Mp4) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-av1.mp4\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_MonoAV1_Mp4) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-mono-av1.mp4\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlayback_Video_AV1_Audio_Opus_Mp4) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-av1-opus.mp4\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif\n\nclass Mp3FastSeekParams {\n public:\n Mp3FastSeekParams(const char* filename, const char* hash)\n : filename(filename), hash(hash) {}\n const char* filename;\n const char* hash;\n};\n\nclass Mp3FastSeekIntegrationTest\n : public PipelineIntegrationTest,\n public testing::WithParamInterface<Mp3FastSeekParams> {};\n\nTEST_P(Mp3FastSeekIntegrationTest, FastSeekAccuracy_MP3) {\n Mp3FastSeekParams config = GetParam();\n ASSERT_EQ(PIPELINE_OK, Start(config.filename, kHashed));\n\n // The XING TOC is inaccurate. We don't use it for CBR, we tolerate it for VBR\n // (best option for fast seeking; see Mp3SeekFFmpegDemuxerTest). The chosen\n // seek time exposes inaccuracy in TOC such that the hash will change if seek\n // logic is regressed. See https://crbug.com/545914.\n //\n // Quick TOC design (not pretty!):\n // - All MP3 TOCs are 100 bytes\n // - Each byte is read as a uint8_t; value between 0 - 255.\n // - The index into this array is the numerator in the ratio: index / 100.\n // This fraction represents a playback time as a percentage of duration.\n // - The value at the given index is the numerator in the ratio: value / 256.\n // This fraction represents a byte offset as a percentage of the file size.\n //\n // For CBR files, each frame is the same size, so the offset for time of\n // (0.98 * duration) should be around (0.98 * file size). This is 250.88 / 256\n // but the numerator will be truncated in the TOC as 250, losing precision.\n base::TimeDelta seek_time(0.98 * pipeline_->GetMediaDuration());\n\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_HASH_EQ(config.hash, GetAudioHash());\n}\n\n// CBR seeks should always be fast and accurate.\nINSTANTIATE_TEST_SUITE_P(\n CBRSeek_HasTOC,\n Mp3FastSeekIntegrationTest,\n ::testing::Values(Mp3FastSeekParams(\"bear-audio-10s-CBR-has-TOC.mp3\",\n \"-0.58,0.61,3.08,2.55,0.90,-1.20,\")));\n\nINSTANTIATE_TEST_SUITE_P(\n CBRSeeks_NoTOC,\n Mp3FastSeekIntegrationTest,\n ::testing::Values(Mp3FastSeekParams(\"bear-audio-10s-CBR-no-TOC.mp3\",\n \"1.16,0.68,1.25,0.60,1.66,0.93,\")));\n\n// VBR seeks can be fast *OR* accurate, but not both. We chose fast.\nINSTANTIATE_TEST_SUITE_P(\n VBRSeeks_HasTOC,\n Mp3FastSeekIntegrationTest,\n ::testing::Values(Mp3FastSeekParams(\"bear-audio-10s-VBR-has-TOC.mp3\",\n \"-0.08,-0.53,0.75,0.89,2.44,0.73,\")));\n\nINSTANTIATE_TEST_SUITE_P(\n VBRSeeks_NoTOC,\n Mp3FastSeekIntegrationTest,\n ::testing::Values(Mp3FastSeekParams(\"bear-audio-10s-VBR-no-TOC.mp3\",\n \"-0.22,0.80,1.19,0.73,-0.31,-1.12,\")));\n\nTEST_F(PipelineIntegrationTest, MSE_MP3) {\n TestMediaSource source(\"sfx.mp3\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(313, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n EXPECT_TRUE(WaitUntilOnEnded());\n\n // Verify that codec delay was stripped.\n EXPECT_HASH_EQ(\"1.01,2.71,4.18,4.32,3.04,1.12,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_MP3_TimestampOffset) {\n TestMediaSource source(\"sfx.mp3\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n EXPECT_EQ(313, source.last_timestamp_offset().InMilliseconds());\n\n // There are 576 silent frames at the start of this mp3. The second append\n // should trim them off.\n const base::TimeDelta mp3_preroll_duration = base::Seconds(576.0 / 44100);\n const base::TimeDelta append_time =\n source.last_timestamp_offset() - mp3_preroll_duration;\n\n scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile(\"sfx.mp3\");\n source.AppendAtTimeWithWindow(append_time, append_time + mp3_preroll_duration,\n kInfiniteDuration, second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(613, source.last_timestamp_offset().InMilliseconds());\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(613, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_MP3_Icecast) {\n TestMediaSource source(\"icy_sfx.mp3\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n Play();\n\n EXPECT_TRUE(WaitUntilOnEnded());\n}\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n\nTEST_F(PipelineIntegrationTest, MSE_ADTS) {\n TestMediaSource source(\"sfx.adts\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(325, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n EXPECT_TRUE(WaitUntilOnEnded());\n\n // Verify that nothing was stripped.\n EXPECT_HASH_EQ(\"0.46,1.72,4.26,4.57,3.39,1.53,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ADTS_TimestampOffset) {\n TestMediaSource source(\"sfx.adts\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n EXPECT_EQ(325, source.last_timestamp_offset().InMilliseconds());\n\n // Trim off multiple frames off the beginning of the segment which will cause\n // the first decoded frame to be incorrect if preroll isn't implemented.\n const base::TimeDelta adts_preroll_duration =\n base::Seconds(2.5 * 1024 / 44100);\n const base::TimeDelta append_time =\n source.last_timestamp_offset() - adts_preroll_duration;\n\n scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile(\"sfx.adts\");\n source.AppendAtTimeWithWindow(\n append_time, append_time + adts_preroll_duration, kInfiniteDuration,\n second_file->data(), second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(592, source.last_timestamp_offset().InMilliseconds());\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n // Verify preroll is stripped.\n EXPECT_HASH_EQ(\"-1.76,-1.35,-0.72,0.70,1.24,0.52,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed_ADTS) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx.adts\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify codec delay and preroll are stripped.\n EXPECT_HASH_EQ(\"1.80,1.66,2.31,3.26,4.46,3.36,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed_M4A) {\n ASSERT_EQ(PIPELINE_OK,\n Start(\"440hz-10ms.m4a\", kHashed | kUnreliableDuration));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify preroll is stripped. This file uses a preroll of 2112 frames, which\n // spans all three packets in the file. Postroll is not correctly stripped at\n // present; see the note below.\n EXPECT_HASH_EQ(\"3.84,4.25,4.33,3.58,3.27,3.16,\", GetAudioHash());\n\n // Note the above hash is incorrect since the <audio> path doesn't properly\n // trim trailing silence at end of stream for AAC decodes. This isn't a huge\n // deal since plain src= tags can't splice streams and MSE requires an\n // explicit append window for correctness.\n //\n // The WebAudio path via AudioFileReader computes this correctly, so the hash\n // below is taken from that test.\n //\n // EXPECT_HASH_EQ(\"3.77,4.53,4.75,3.48,3.67,3.76,\", GetAudioHash());\n}\n\n// TODO(crbug.com/1289825): Make this work on Android.\n#if BUILDFLAG(IS_MAC)\nconstexpr char kXHE_AACAudioHash[] = \"34.02,8.92,-11.02,12.15,16.11,10.75,\";\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackXHE_AAC) {\n if (__builtin_available(macOS 10.15, *)) {\n // Annoyingly !__builtin_available() doesn't work.\n } else {\n GTEST_SKIP() << \"Unsupported platform.\";\n }\n\n auto prepend_audio_decoders_cb = base::BindLambdaForTesting([]() {\n std::vector<std::unique_ptr<AudioDecoder>> audio_decoders;\n audio_decoders.push_back(std::make_unique<AudioToolboxAudioDecoder>());\n return audio_decoders;\n });\n\n ASSERT_EQ(PIPELINE_OK,\n Start(\"noise-xhe-aac.mp4\", kHashed, CreateVideoDecodersCB(),\n prepend_audio_decoders_cb));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Hash testing may be a poor choice here since we're using the OS decoders,\n // but lets wait to see what the test says on Android before removing.\n EXPECT_HASH_EQ(kXHE_AACAudioHash, GetAudioHash());\n\n // TODO(crbug.com/1289825): Seeking doesn't always work properly when using\n // ffmpeg since it doesn't handle non-keyframe xHE-AAC samples properly.\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlaybackXHE_AAC) {\n if (__builtin_available(macOS 10.15, *)) {\n // Annoyingly !__builtin_available() doesn't work.\n } else {\n GTEST_SKIP() << \"Unsupported platform.\";\n }\n\n auto prepend_audio_decoders_cb = base::BindLambdaForTesting([]() {\n std::vector<std::unique_ptr<AudioDecoder>> audio_decoders;\n audio_decoders.push_back(std::make_unique<AudioToolboxAudioDecoder>());\n return audio_decoders;\n });\n\n TestMediaSource source(\"noise-xhe-aac.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(\n &source, kHashed, prepend_audio_decoders_cb));\n source.EndOfStream();\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n Pause();\n\n // Hash testing may be a poor choice here since we're using the OS decoders,\n // but lets wait to see what the test says on Android before removing.\n EXPECT_HASH_EQ(kXHE_AACAudioHash, GetAudioHash());\n\n // Seek to ensure a flushing and playback resumption works properly.\n auto seek_time = pipeline_->GetMediaDuration() / 2;\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_EQ(seek_time, pipeline_->GetMediaTime());\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif // BUILDFLAG(IS_MAC)\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHi10P) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x180-hi10p.mp4\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nstd::vector<std::unique_ptr<VideoDecoder>> CreateFailingVideoDecoder() {\n std::vector<std::unique_ptr<VideoDecoder>> failing_video_decoder;\n failing_video_decoder.push_back(std::make_unique<FailingVideoDecoder>());\n return failing_video_decoder;\n}\n\nTEST_F(PipelineIntegrationTest, BasicFallback) {\n ASSERT_EQ(PIPELINE_OK,\n Start(\"bear.mp4\", kNormal,\n base::BindRepeating(&CreateFailingVideoDecoder)));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_MP4) {\n TestMediaSource source(\"bear-640x360-av_frag.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n const gfx::Size kNewSize(1280, 720);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-av_frag.mp4\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMsAV,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_Encrypted_MP4_CENC_VideoOnly) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-mdat.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n const gfx::Size kNewSize(1280, 720);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-v_frag-cenc.mp4\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(33, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_ConfigChange_Encrypted_MP4_CENC_KeyRotation_VideoOnly) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-key_rotation.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(1280, 720))).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-v_frag-cenc-key_rotation.mp4\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(33, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_ClearThenEncrypted_MP4_CENC) {\n TestMediaSource source(\"bear-640x360-v_frag.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(1280, 720))).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-v_frag-cenc.mp4\");\n source.set_expected_append_result(\n TestMediaSource::ExpectedAppendResult::kFailure);\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n\n source.EndOfStream();\n\n EXPECT_EQ(33, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n// Config changes from encrypted to clear are not currently supported.\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_EncryptedThenClear_MP4_CENC) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-mdat.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-av_frag.mp4\");\n\n source.set_expected_append_result(\n TestMediaSource::ExpectedAppendResult::kFailure);\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(33, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n\n // The second video was not added, so its time has not been added.\n EXPECT_EQ(k640IsoCencFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n EXPECT_EQ(CHUNK_DEMUXER_ERROR_APPEND_FAILED, WaitUntilEndedOrError());\n source.Shutdown();\n}\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\n// Verify files which change configuration midstream fail gracefully.\nTEST_F(PipelineIntegrationTest, MidStreamConfigChangesFail) {\n ASSERT_EQ(PIPELINE_OK, Start(\"midstream_config_change.mp3\"));\n Play();\n ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE);\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240-16x9-aspect.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_WebM) {\n TestMediaSource source(\"bear-320x240-av_enc-av.webm\", 219816);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_ClearStart_WebM) {\n TestMediaSource source(\"bear-320x240-av_enc-av_clear-1s.webm\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_NoEncryptedFrames_WebM) {\n TestMediaSource source(\"bear-320x240-av_enc-av_clear-all.webm\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new NoResponseApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_VP9_CENC_VideoOnly) {\n TestMediaSource source(\"bear-320x240-v_frag-vp9-cenc.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VideoOnly_MP4_VP9) {\n TestMediaSource source(\"bear-320x240-v_frag-vp9.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_CENC_VideoOnly) {\n TestMediaSource source(\"bear-1280x720-v_frag-cenc.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_CENC_AudioOnly) {\n TestMediaSource source(\"bear-1280x720-a_frag-cenc.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_NoEncryptedFrames_MP4_CENC_VideoOnly) {\n TestMediaSource source(\"bear-1280x720-v_frag-cenc_clear-all.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new NoResponseApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_Mp2ts_AAC_HE_SBR_Audio) {\n TestMediaSource source(\"bear-1280x720-aac_he.ts\", kAppendWholeFile);\n#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n // Check that SBR is taken into account correctly by mpeg2ts parser. When an\n // SBR stream is parsed as non-SBR stream, then audio frame durations are\n // calculated incorrectly and that leads to gaps in buffered ranges (so this\n // check will fail) and eventually leads to stalled playback.\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif\n}\n\nTEST_F(PipelineIntegrationTest, MSE_Mpeg2ts_MP3Audio_Mp4a_6B) {\n TestMediaSource source(\"bear-audio-mp4a.6B.ts\",\n \"video/mp2t; codecs=\\\"mp4a.6B\\\"\", kAppendWholeFile);\n#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif\n}\n\nTEST_F(PipelineIntegrationTest, MSE_Mpeg2ts_MP3Audio_Mp4a_69) {\n TestMediaSource source(\"bear-audio-mp4a.69.ts\",\n \"video/mp2t; codecs=\\\"mp4a.69\\\"\", kAppendWholeFile);\n#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_NoEncryptedFrames_MP4_CENC_AudioOnly) {\n TestMediaSource source(\"bear-1280x720-a_frag-cenc_clear-all.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new NoResponseApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n// Older packagers saved sample encryption auxiliary information in the\n// beginning of mdat box.\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_CENC_MDAT_Video) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-mdat.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_CENC_SENC_Video) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-senc.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n// 'SAIZ' and 'SAIO' boxes contain redundant information which is already\n// available in 'SENC' box. Although 'SAIZ' and 'SAIO' boxes are required per\n// CENC spec for backward compatibility reasons, but we do not use the two\n// boxes if 'SENC' box is present, so the code should work even if the two\n// boxes are not present.\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_MP4_CENC_SENC_NO_SAIZ_SAIO_Video) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-senc-no-saiz-saio.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_MP4_CENC_KeyRotation_Video) {\n TestMediaSource source(\"bear-1280x720-v_frag-cenc-key_rotation.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_MP4_CENC_KeyRotation_Audio) {\n TestMediaSource source(\"bear-1280x720-a_frag-cenc-key_rotation.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VideoOnly_MP4_AVC3) {\n TestMediaSource source(\"bear-1280x720-v_frag-avc3.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(k1280IsoAVC3FileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VideoOnly_MP4_HEVC) {\n // HEVC demuxing might be enabled even on platforms that don't support HEVC\n // decoding. For those cases we'll get DECODER_ERROR_NOT_SUPPORTED, which\n // indicates indicates that we did pass media mime type checks and attempted\n // to actually demux and decode the stream. On platforms that support both\n // demuxing and decoding we'll get PIPELINE_OK.\n const char kMp4HevcVideoOnly[] = \"video/mp4; codecs=\\\"hvc1.1.6.L93.B0\\\"\";\n TestMediaSource source(\"bear-320x240-v_frag-hevc.mp4\", kMp4HevcVideoOnly,\n kAppendWholeFile);\n#if BUILDFLAG(ENABLE_PLATFORM_HEVC)\n PipelineStatus status = StartPipelineWithMediaSource(&source);\n EXPECT_TRUE(status == PIPELINE_OK || status == DECODER_ERROR_NOT_SUPPORTED);\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC)\n}\n\n// Same test as above but using a different mime type.\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VideoOnly_MP4_HEV1) {\n const char kMp4Hev1VideoOnly[] = \"video/mp4; codecs=\\\"hev1.1.6.L93.B0\\\"\";\n TestMediaSource source(\"bear-320x240-v_frag-hevc.mp4\", kMp4Hev1VideoOnly,\n kAppendWholeFile);\n#if BUILDFLAG(ENABLE_PLATFORM_HEVC)\n PipelineStatus status = StartPipelineWithMediaSource(&source);\n EXPECT_TRUE(status == PIPELINE_OK || status == DECODER_ERROR_NOT_SUPPORTED);\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC)\n}\n\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\nTEST_F(PipelineIntegrationTest, SeekWhilePaused) {\n#if BUILDFLAG(IS_MAC)\n // Enable scoped logs to help track down hangs. http://crbug.com/1014646\n ScopedVerboseLogEnabler scoped_log_enabler;\n#endif\n\n // This test is flaky without kNoClockless, see crbug.com/796250.\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n\n base::TimeDelta duration(pipeline_->GetMediaDuration());\n base::TimeDelta start_seek_time(duration / 4);\n base::TimeDelta seek_time(duration * 3 / 4);\n\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));\n Pause();\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_EQ(seek_time, pipeline_->GetMediaTime());\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Make sure seeking after reaching the end works as expected.\n Pause();\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_EQ(seek_time, pipeline_->GetMediaTime());\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, SeekWhilePlaying) {\n#if BUILDFLAG(IS_MAC)\n // Enable scoped logs to help track down hangs. http://crbug.com/1014646\n ScopedVerboseLogEnabler scoped_log_enabler;\n#endif\n\n // This test is flaky without kNoClockless, see crbug.com/796250.\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n\n base::TimeDelta duration(pipeline_->GetMediaDuration());\n base::TimeDelta start_seek_time(duration / 4);\n base::TimeDelta seek_time(duration * 3 / 4);\n\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_GE(pipeline_->GetMediaTime(), seek_time);\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Make sure seeking after reaching the end works as expected.\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_GE(pipeline_->GetMediaTime(), seek_time);\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, SuspendWhilePaused) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n\n base::TimeDelta duration(pipeline_->GetMediaDuration());\n base::TimeDelta start_seek_time(duration / 4);\n base::TimeDelta seek_time(duration * 3 / 4);\n\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));\n Pause();\n\n // Suspend while paused.\n ASSERT_TRUE(Suspend());\n\n // Resuming the pipeline will create a new Renderer,\n // which in turn will trigger video size and opacity notifications.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240))).Times(1);\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(1);\n\n ASSERT_TRUE(Resume(seek_time));\n EXPECT_GE(pipeline_->GetMediaTime(), seek_time);\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, SuspendWhilePlaying) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n\n base::TimeDelta duration(pipeline_->GetMediaDuration());\n base::TimeDelta start_seek_time(duration / 4);\n base::TimeDelta seek_time(duration * 3 / 4);\n\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));\n ASSERT_TRUE(Suspend());\n\n // Resuming the pipeline will create a new Renderer,\n // which in turn will trigger video size and opacity notifications.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240))).Times(1);\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(1);\n\n ASSERT_TRUE(Resume(seek_time));\n EXPECT_GE(pipeline_->GetMediaTime(), seek_time);\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\nTEST_F(PipelineIntegrationTest, Rotated_Metadata_0) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_rotate_0.mp4\"));\n ASSERT_EQ(VIDEO_ROTATION_0,\n metadata_.video_decoder_config.video_transformation().rotation);\n}\n\nTEST_F(PipelineIntegrationTest, Rotated_Metadata_90) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_rotate_90.mp4\"));\n ASSERT_EQ(VIDEO_ROTATION_90,\n metadata_.video_decoder_config.video_transformation().rotation);\n}\n\nTEST_F(PipelineIntegrationTest, Rotated_Metadata_180) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_rotate_180.mp4\"));\n ASSERT_EQ(VIDEO_ROTATION_180,\n metadata_.video_decoder_config.video_transformation().rotation);\n}\n\nTEST_F(PipelineIntegrationTest, Rotated_Metadata_270) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_rotate_270.mp4\"));\n ASSERT_EQ(VIDEO_ROTATION_270,\n metadata_.video_decoder_config.video_transformation().rotation);\n}\n\nTEST_F(PipelineIntegrationTest, Spherical) {\n ASSERT_EQ(PIPELINE_OK, Start(\"spherical.mp4\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(\"1cb7f980020d99ea852e22dd6bd8d9de\", GetVideoHash());\n}\n\nTEST_F(PipelineIntegrationTest, StereoAACMarkedAsMono) {\n ASSERT_EQ(PIPELINE_OK, Start(\"mono_cpe.adts\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\n// Verify audio decoder & renderer can handle aborted demuxer reads.\nTEST_F(PipelineIntegrationTest, MSE_ChunkDemuxerAbortRead_AudioOnly) {\n ASSERT_TRUE(TestSeekDuringRead(\"bear-320x240-audio-only.webm\", 16384,\n base::Milliseconds(464),\n base::Milliseconds(617), 0x10CA, 19730));\n}\n\n// Verify video decoder & renderer can handle aborted demuxer reads.\nTEST_F(PipelineIntegrationTest, MSE_ChunkDemuxerAbortRead_VideoOnly) {\n ASSERT_TRUE(TestSeekDuringRead(\"bear-320x240-video-only.webm\", 32768,\n base::Milliseconds(167),\n base::Milliseconds(1668), 0x1C896, 65536));\n}\n\nTEST_F(PipelineIntegrationTest,\n BasicPlayback_AudioOnly_Opus_4ch_ChannelMapping2_WebM) {\n ASSERT_EQ(\n PIPELINE_OK,\n Start(\"bear-opus-end-trimming-4ch-channelmapping2.webm\", kWebAudio));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest,\n BasicPlayback_AudioOnly_Opus_11ch_ChannelMapping2_WebM) {\n ASSERT_EQ(\n PIPELINE_OK,\n Start(\"bear-opus-end-trimming-11ch-channelmapping2.webm\", kWebAudio));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that VP9 video in WebM containers can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_VP9_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_AV1_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-av1.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif\n\n// Verify that VP9 video and Opus audio in the same WebM container can be played\n// back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Opus_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9-opus.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that VP8 video with alpha channel can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp8a.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);\n}\n\n// Verify that VP8A video with odd width/height can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_Odd_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp8a-odd-dimensions.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);\n}\n\n// Verify that VP9 video with odd width/height can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Odd_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9-odd-dimensions.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that VP9 video with alpha channel can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP9A_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9a.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);\n}\n\n// Verify that VP9A video with odd width/height can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP9A_Odd_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9a-odd-dimensions.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);\n}\n\n// Verify that VP9 video with 4:4:4 subsampling can be played back.\nTEST_F(PipelineIntegrationTest, P444_VP9_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240-P444.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I444);\n}\n\n// Verify that frames of VP9 video in the BT.709 color space have the YV12HD\n// format.\nTEST_F(PipelineIntegrationTest, BT709_VP9_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9-bt709.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420);\n EXPECT_COLOR_SPACE_EQ(last_video_frame_color_space_,\n gfx::ColorSpace::CreateREC709());\n}\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n// Verify that full-range H264 video has the right color space.\nTEST_F(PipelineIntegrationTest, Fullrange_H264) {\n ASSERT_EQ(PIPELINE_OK, Start(\"blackwhite_yuvj420p.mp4\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_COLOR_SPACE_EQ(last_video_frame_color_space_,\n gfx::ColorSpace::CreateJpeg());\n}\n#endif\n\nTEST_F(PipelineIntegrationTest, HD_VP9_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-1280x720.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that videos with an odd frame size playback successfully.\nTEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) {\n ASSERT_EQ(PIPELINE_OK, Start(\"butterfly-853x480.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that OPUS audio in a webm which reports a 44.1kHz sample rate plays\n// correctly at 48kHz\nTEST_F(PipelineIntegrationTest, BasicPlayback_Opus441kHz) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx-opus-441.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(48000, demuxer_->GetFirstStream(DemuxerStream::AUDIO)\n ->audio_decoder_config()\n .samples_per_second());\n}\n\n// Same as above but using MediaSource.\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_Opus441kHz) {\n TestMediaSource source(\"sfx-opus-441.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n EXPECT_EQ(48000, demuxer_->GetFirstStream(DemuxerStream::AUDIO)\n ->audio_decoder_config()\n .samples_per_second());\n}\n\n// Ensures audio-only playback with missing or negative timestamps works. Tests\n// the common live-streaming case for chained ogg. See http://crbug.com/396864.\nTEST_F(PipelineIntegrationTest, BasicPlaybackChainedOgg) {\n ASSERT_EQ(PIPELINE_OK, Start(\"double-sfx.ogg\", kUnreliableDuration));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n ASSERT_EQ(base::TimeDelta(), demuxer_->GetStartTime());\n}\n\nTEST_F(PipelineIntegrationTest, TrailingGarbage) {\n ASSERT_EQ(PIPELINE_OK, Start(\"trailing-garbage.mp3\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Ensures audio-video playback with missing or negative timestamps fails\n// instead of crashing. See http://crbug.com/396864.\nTEST_F(PipelineIntegrationTest, BasicPlaybackChainedOggVideo) {\n ASSERT_EQ(DEMUXER_ERROR_COULD_NOT_PARSE,\n Start(\"double-bear.ogv\", kUnreliableDuration));\n}\n\n// Tests that we signal ended even when audio runs longer than video track.\nTEST_F(PipelineIntegrationTest, BasicPlaybackAudioLongerThanVideo) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_audio_longer_than_video.ogv\"));\n // Audio track is 2000ms. Video track is 1001ms. Duration should be higher\n // of the two.\n EXPECT_EQ(2000, pipeline_->GetMediaDuration().InMilliseconds());\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Tests that we signal ended even when audio runs shorter than video track.\nTEST_F(PipelineIntegrationTest, BasicPlaybackAudioShorterThanVideo) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_audio_shorter_than_video.ogv\"));\n // Audio track is 500ms. Video track is 1001ms. Duration should be higher of\n // the two.\n EXPECT_EQ(1001, pipeline_->GetMediaDuration().InMilliseconds());\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackPositiveStartTime) {\n ASSERT_EQ(PIPELINE_OK, Start(\"nonzero-start-time.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n ASSERT_EQ(base::Microseconds(396000), demuxer_->GetStartTime());\n}\n\n} // namespace media\n"
},
"written_data": {
"media/test/pipeline_integration_test.cc": "// Copyright 2012 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n#include <stddef.h>\n#include <stdint.h>\n\n#include <memory>\n#include <utility>\n\n#include \"base/bind.h\"\n#include \"base/callback_helpers.h\"\n#include \"base/command_line.h\"\n#include \"base/memory/ref_counted.h\"\n#include \"base/run_loop.h\"\n#include \"base/strings/string_split.h\"\n#include \"base/strings/string_util.h\"\n#include \"base/test/bind.h\"\n#include \"base/threading/thread_task_runner_handle.h\"\n#include \"base/time/time.h\"\n#include \"build/build_config.h\"\n#include \"media/base/cdm_callback_promise.h\"\n#include \"media/base/cdm_key_information.h\"\n#include \"media/base/decoder_buffer.h\"\n#include \"media/base/media.h\"\n#include \"media/base/media_switches.h\"\n#include \"media/base/media_tracks.h\"\n#include \"media/base/mock_media_log.h\"\n#include \"media/base/test_data_util.h\"\n#include \"media/base/timestamp_constants.h\"\n#include \"media/cdm/aes_decryptor.h\"\n#include \"media/cdm/json_web_key.h\"\n#include \"media/media_buildflags.h\"\n#include \"media/renderers/renderer_impl.h\"\n#include \"media/test/fake_encrypted_media.h\"\n#include \"media/test/pipeline_integration_test_base.h\"\n#include \"media/test/test_media_source.h\"\n#include \"testing/gmock/include/gmock/gmock.h\"\n#include \"url/gurl.h\"\n\n#if BUILDFLAG(IS_MAC)\n#include \"media/filters/mac/audio_toolbox_audio_decoder.h\"\n#endif\n\n#define EXPECT_HASH_EQ(a, b) EXPECT_EQ(a, b)\n#define EXPECT_VIDEO_FORMAT_EQ(a, b) EXPECT_EQ(a, b)\n#define EXPECT_COLOR_SPACE_EQ(a, b) EXPECT_EQ(a, b)\n\nusing ::testing::_;\nusing ::testing::AnyNumber;\nusing ::testing::AtLeast;\nusing ::testing::AtMost;\nusing ::testing::HasSubstr;\nusing ::testing::SaveArg;\n\nnamespace media {\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nconst int kAV110bitMp4FileDurationMs = 2735;\nconst int kAV1640WebMFileDurationMs = 2736;\n#endif // BUILDFLAG(ENABLE_AV1_DECODER)\n\n// Constants for the Media Source config change tests.\nconst int kAppendTimeSec = 1;\nconst int kAppendTimeMs = kAppendTimeSec * 1000;\nconst int k320WebMFileDurationMs = 2736;\nconst int k640WebMFileDurationMs = 2762;\nconst int kVP9WebMFileDurationMs = 2736;\nconst int kVP8AWebMFileDurationMs = 2734;\n\nstatic const char kSfxLosslessHash[] = \"3.03,2.86,2.99,3.31,3.57,4.06,\";\n\n#if defined(OPUS_FIXED_POINT)\n// NOTE: These hashes are specific to ARM devices, which use fixed-point Opus\n// implementation. x86 uses floating-point Opus, so x86 hashes won't match\n#if defined(ARCH_CPU_ARM64)\nstatic const char kOpusEndTrimmingHash_1[] =\n \"-4.58,-5.68,-6.53,-6.28,-4.35,-3.59,\";\nstatic const char kOpusEndTrimmingHash_2[] =\n \"-11.92,-11.11,-8.25,-7.10,-7.84,-10.00,\";\nstatic const char kOpusEndTrimmingHash_3[] =\n \"-13.33,-14.38,-13.68,-11.66,-10.18,-10.49,\";\nstatic const char kOpusSmallCodecDelayHash_1[] =\n \"-0.48,-0.09,1.27,1.06,1.54,-0.22,\";\nstatic const char kOpusSmallCodecDelayHash_2[] =\n \"0.29,0.15,-0.19,0.25,0.68,0.83,\";\nstatic const char kOpusMonoOutputHash[] = \"-2.39,-1.66,0.81,1.54,1.48,-0.91,\";\n#else\nstatic const char kOpusEndTrimmingHash_1[] =\n \"-4.57,-5.66,-6.52,-6.30,-4.37,-3.61,\";\nstatic const char kOpusEndTrimmingHash_2[] =\n \"-11.91,-11.11,-8.27,-7.13,-7.86,-10.00,\";\nstatic const char kOpusEndTrimmingHash_3[] =\n \"-13.31,-14.38,-13.70,-11.71,-10.21,-10.49,\";\nstatic const char kOpusSmallCodecDelayHash_1[] =\n \"-0.48,-0.09,1.27,1.06,1.54,-0.22,\";\nstatic const char kOpusSmallCodecDelayHash_2[] =\n \"0.29,0.14,-0.20,0.24,0.68,0.83,\";\nstatic const char kOpusMonoOutputHash[] = \"-2.41,-1.66,0.79,1.53,1.46,-0.91,\";\n#endif // defined(ARCH_CPU_ARM64)\n\n#else\n// Hash for a full playthrough of \"opus-trimming-test.(webm|ogg)\".\nstatic const char kOpusEndTrimmingHash_1[] =\n \"-4.57,-5.67,-6.52,-6.28,-4.34,-3.58,\";\n// The above hash, plus an additional playthrough starting from T=1s.\nstatic const char kOpusEndTrimmingHash_2[] =\n \"-11.91,-11.10,-8.24,-7.08,-7.82,-9.99,\";\n// The above hash, plus an additional playthrough starting from T=6.36s.\nstatic const char kOpusEndTrimmingHash_3[] =\n \"-13.31,-14.36,-13.66,-11.65,-10.16,-10.47,\";\n// Hash for a full playthrough of \"bear-opus.webm\".\nstatic const char kOpusSmallCodecDelayHash_1[] =\n \"-0.47,-0.09,1.28,1.07,1.55,-0.22,\";\n// The above hash, plus an additional playthrough starting from T=1.414s.\nstatic const char kOpusSmallCodecDelayHash_2[] =\n \"0.31,0.15,-0.18,0.25,0.70,0.84,\";\n// For BasicPlaybackOpusWebmHashed_MonoOutput test case.\nstatic const char kOpusMonoOutputHash[] = \"-2.36,-1.64,0.84,1.55,1.51,-0.90,\";\n#endif // defined(OPUS_FIXED_POINT)\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\nconst int k640IsoCencFileDurationMs = 2769;\nconst int k1280IsoFileDurationMs = 2736;\n\n// TODO(wolenetz): Update to 2769 once MSE endOfStream implementation no longer\n// truncates duration to the highest in intersection ranges, but compliantly to\n// the largest track buffer ranges end time across all tracks and SourceBuffers.\n// See https://crbug.com/639144.\nconst int k1280IsoFileDurationMsAV = 2763;\n\nconst int k1280IsoAVC3FileDurationMs = 2736;\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\n// Return a timeline offset for bear-320x240-live.webm.\nstatic base::Time kLiveTimelineOffset() {\n // The file contains the following UTC timeline offset:\n // 2012-11-10 12:34:56.789123456\n // Since base::Time only has a resolution of microseconds,\n // construct a base::Time for 2012-11-10 12:34:56.789123.\n base::Time::Exploded exploded_time;\n exploded_time.year = 2012;\n exploded_time.month = 11;\n exploded_time.day_of_month = 10;\n exploded_time.day_of_week = 6;\n exploded_time.hour = 12;\n exploded_time.minute = 34;\n exploded_time.second = 56;\n exploded_time.millisecond = 789;\n base::Time timeline_offset;\n EXPECT_TRUE(base::Time::FromUTCExploded(exploded_time, &timeline_offset));\n\n timeline_offset += base::Microseconds(123);\n\n return timeline_offset;\n}\n\n#if BUILDFLAG(IS_MAC)\nclass ScopedVerboseLogEnabler {\n public:\n ScopedVerboseLogEnabler() : old_level_(logging::GetMinLogLevel()) {\n logging::SetMinLogLevel(-1);\n }\n\n ScopedVerboseLogEnabler(const ScopedVerboseLogEnabler&) = delete;\n ScopedVerboseLogEnabler& operator=(const ScopedVerboseLogEnabler&) = delete;\n\n ~ScopedVerboseLogEnabler() { logging::SetMinLogLevel(old_level_); }\n\n private:\n const int old_level_;\n};\n#endif\n\nenum PromiseResult { RESOLVED, REJECTED };\n\n// Provides the test key in response to the encrypted event.\nclass KeyProvidingApp : public FakeEncryptedMedia::AppBase {\n public:\n KeyProvidingApp() = default;\n\n void OnResolveWithSession(PromiseResult expected,\n const std::string& session_id) {\n EXPECT_EQ(expected, RESOLVED);\n EXPECT_GT(session_id.length(), 0ul);\n current_session_id_ = session_id;\n }\n\n void OnResolve(PromiseResult expected) { EXPECT_EQ(expected, RESOLVED); }\n\n void OnReject(PromiseResult expected,\n media::CdmPromise::Exception exception_code,\n uint32_t system_code,\n const std::string& error_message) {\n EXPECT_EQ(expected, REJECTED) << error_message;\n }\n\n std::unique_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected) {\n auto promise = std::make_unique<media::CdmCallbackPromise<>>(\n base::BindOnce(&KeyProvidingApp::OnResolve, base::Unretained(this),\n expected),\n base::BindOnce(&KeyProvidingApp::OnReject, base::Unretained(this),\n expected));\n return promise;\n }\n\n std::unique_ptr<NewSessionCdmPromise> CreateSessionPromise(\n PromiseResult expected) {\n auto promise = std::make_unique<media::CdmCallbackPromise<std::string>>(\n base::BindOnce(&KeyProvidingApp::OnResolveWithSession,\n base::Unretained(this), expected),\n base::BindOnce(&KeyProvidingApp::OnReject, base::Unretained(this),\n expected));\n return promise;\n }\n\n void OnSessionMessage(const std::string& session_id,\n CdmMessageType message_type,\n const std::vector<uint8_t>& message,\n AesDecryptor* decryptor) override {\n EXPECT_FALSE(session_id.empty());\n EXPECT_FALSE(message.empty());\n EXPECT_EQ(current_session_id_, session_id);\n EXPECT_EQ(CdmMessageType::LICENSE_REQUEST, message_type);\n\n // Extract the key ID from |message|. For Clear Key this is a JSON object\n // containing a set of \"kids\". There should only be 1 key ID in |message|.\n std::string message_string(message.begin(), message.end());\n KeyIdList key_ids;\n std::string error_message;\n EXPECT_TRUE(ExtractKeyIdsFromKeyIdsInitData(message_string, &key_ids,\n &error_message))\n << error_message;\n EXPECT_EQ(1u, key_ids.size());\n\n // Determine the key that matches the key ID |key_ids[0]|.\n std::vector<uint8_t> key;\n EXPECT_TRUE(LookupKey(key_ids[0], &key));\n\n // Update the session with the key ID and key.\n std::string jwk = GenerateJWKSet(key.data(), key.size(), key_ids[0].data(),\n key_ids[0].size());\n decryptor->UpdateSession(session_id,\n std::vector<uint8_t>(jwk.begin(), jwk.end()),\n CreatePromise(RESOLVED));\n }\n\n void OnSessionClosed(const std::string& session_id,\n CdmSessionClosedReason /*reason*/) override {\n EXPECT_EQ(current_session_id_, session_id);\n }\n\n void OnSessionKeysChange(const std::string& session_id,\n bool has_additional_usable_key,\n CdmKeysInfo keys_info) override {\n EXPECT_EQ(current_session_id_, session_id);\n EXPECT_EQ(has_additional_usable_key, true);\n }\n\n void OnSessionExpirationUpdate(const std::string& session_id,\n base::Time new_expiry_time) override {\n EXPECT_EQ(current_session_id_, session_id);\n }\n\n void OnEncryptedMediaInitData(EmeInitDataType init_data_type,\n const std::vector<uint8_t>& init_data,\n AesDecryptor* decryptor) override {\n // Since only 1 session is created, skip the request if the |init_data|\n // has been seen before (no need to add the same key again).\n if (init_data == prev_init_data_)\n return;\n prev_init_data_ = init_data;\n\n if (current_session_id_.empty()) {\n decryptor->CreateSessionAndGenerateRequest(\n CdmSessionType::kTemporary, init_data_type, init_data,\n CreateSessionPromise(RESOLVED));\n EXPECT_FALSE(current_session_id_.empty());\n }\n }\n\n virtual bool LookupKey(const std::vector<uint8_t>& key_id,\n std::vector<uint8_t>* key) {\n // No key rotation.\n return LookupTestKeyVector(key_id, false, key);\n }\n\n std::string current_session_id_;\n std::vector<uint8_t> prev_init_data_;\n};\n\nclass RotatingKeyProvidingApp : public KeyProvidingApp {\n public:\n RotatingKeyProvidingApp() : num_distinct_need_key_calls_(0) {}\n ~RotatingKeyProvidingApp() override {\n // Expect that OnEncryptedMediaInitData is fired multiple times with\n // different |init_data|.\n EXPECT_GT(num_distinct_need_key_calls_, 1u);\n }\n\n void OnEncryptedMediaInitData(EmeInitDataType init_data_type,\n const std::vector<uint8_t>& init_data,\n AesDecryptor* decryptor) override {\n // Skip the request if the |init_data| has been seen.\n if (init_data == prev_init_data_)\n return;\n prev_init_data_ = init_data;\n ++num_distinct_need_key_calls_;\n\n decryptor->CreateSessionAndGenerateRequest(CdmSessionType::kTemporary,\n init_data_type, init_data,\n CreateSessionPromise(RESOLVED));\n }\n\n bool LookupKey(const std::vector<uint8_t>& key_id,\n std::vector<uint8_t>* key) override {\n // With key rotation.\n return LookupTestKeyVector(key_id, true, key);\n }\n\n uint32_t num_distinct_need_key_calls_;\n};\n\n// Ignores the encrypted event and does not perform a license request.\nclass NoResponseApp : public FakeEncryptedMedia::AppBase {\n public:\n void OnSessionMessage(const std::string& session_id,\n CdmMessageType message_type,\n const std::vector<uint8_t>& message,\n AesDecryptor* decryptor) override {\n EXPECT_FALSE(session_id.empty());\n EXPECT_FALSE(message.empty());\n FAIL() << \"Unexpected Message\";\n }\n\n void OnSessionClosed(const std::string& session_id,\n CdmSessionClosedReason /*reason*/) override {\n EXPECT_FALSE(session_id.empty());\n FAIL() << \"Unexpected Closed\";\n }\n\n void OnSessionKeysChange(const std::string& session_id,\n bool has_additional_usable_key,\n CdmKeysInfo keys_info) override {\n EXPECT_FALSE(session_id.empty());\n EXPECT_EQ(has_additional_usable_key, true);\n }\n\n void OnSessionExpirationUpdate(const std::string& session_id,\n base::Time new_expiry_time) override {}\n\n void OnEncryptedMediaInitData(EmeInitDataType init_data_type,\n const std::vector<uint8_t>& init_data,\n AesDecryptor* decryptor) override {}\n};\n\n// A rough simulation of GpuVideoDecoder that fails every Decode() request. This\n// is used to test post-Initialize() fallback paths.\nclass FailingVideoDecoder : public VideoDecoder {\n public:\n VideoDecoderType GetDecoderType() const override {\n return VideoDecoderType::kTesting;\n }\n void Initialize(const VideoDecoderConfig& config,\n bool low_delay,\n CdmContext* cdm_context,\n InitCB init_cb,\n const OutputCB& output_cb,\n const WaitingCB& waiting_cb) override {\n std::move(init_cb).Run(DecoderStatus::Codes::kOk);\n }\n void Decode(scoped_refptr<DecoderBuffer> buffer,\n DecodeCB decode_cb) override {\n base::ThreadTaskRunnerHandle::Get()->PostTask(\n FROM_HERE,\n base::BindOnce(std::move(decode_cb), DecoderStatus::Codes::kFailed));\n }\n void Reset(base::OnceClosure closure) override { std::move(closure).Run(); }\n bool NeedsBitstreamConversion() const override { return true; }\n};\n\nclass PipelineIntegrationTest : public testing::Test,\n public PipelineIntegrationTestBase {\n public:\n // Verifies that seeking works properly for ChunkDemuxer when the\n // seek happens while there is a pending read on the ChunkDemuxer\n // and no data is available.\n bool TestSeekDuringRead(const std::string& filename,\n int initial_append_size,\n base::TimeDelta start_seek_time,\n base::TimeDelta seek_time,\n int seek_file_position,\n int seek_append_size) {\n TestMediaSource source(filename, initial_append_size);\n\n if (StartPipelineWithMediaSource(&source, kNoClockless, nullptr) !=\n PIPELINE_OK) {\n return false;\n }\n\n Play();\n if (!WaitUntilCurrentTimeIsAfter(start_seek_time))\n return false;\n\n source.Seek(seek_time, seek_file_position, seek_append_size);\n if (!Seek(seek_time))\n return false;\n\n source.EndOfStream();\n\n source.Shutdown();\n Stop();\n return true;\n }\n\n void OnEnabledAudioTracksChanged(\n const std::vector<MediaTrack::Id>& enabled_track_ids) {\n base::RunLoop run_loop;\n pipeline_->OnEnabledAudioTracksChanged(enabled_track_ids,\n run_loop.QuitClosure());\n run_loop.Run();\n }\n\n void OnSelectedVideoTrackChanged(\n absl::optional<MediaTrack::Id> selected_track_id) {\n base::RunLoop run_loop;\n pipeline_->OnSelectedVideoTrackChanged(selected_track_id,\n run_loop.QuitClosure());\n run_loop.Run();\n }\n};\n\nstruct PlaybackTestData {\n const std::string filename;\n const uint32_t start_time_ms;\n const uint32_t duration_ms;\n};\n\nstruct MSEPlaybackTestData {\n const std::string filename;\n const size_t append_bytes;\n const uint32_t duration_ms;\n};\n\n// Tells gtest how to print our PlaybackTestData structure.\nstd::ostream& operator<<(std::ostream& os, const PlaybackTestData& data) {\n return os << data.filename;\n}\n\nstd::ostream& operator<<(std::ostream& os, const MSEPlaybackTestData& data) {\n return os << data.filename;\n}\n\nclass BasicPlaybackTest : public PipelineIntegrationTest,\n public testing::WithParamInterface<PlaybackTestData> {\n};\n\nTEST_P(BasicPlaybackTest, PlayToEnd) {\n PlaybackTestData data = GetParam();\n\n ASSERT_EQ(PIPELINE_OK, Start(data.filename, kUnreliableDuration));\n EXPECT_EQ(data.start_time_ms, demuxer_->GetStartTime().InMilliseconds());\n EXPECT_EQ(data.duration_ms, pipeline_->GetMediaDuration().InMilliseconds());\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nconst PlaybackTestData kOpenCodecsTests[] = {{\"bear-vp9-i422.webm\", 0, 2736}};\n\nINSTANTIATE_TEST_SUITE_P(OpenCodecs,\n BasicPlaybackTest,\n testing::ValuesIn(kOpenCodecsTests));\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n\nclass BasicMSEPlaybackTest\n : public ::testing::WithParamInterface<MSEPlaybackTestData>,\n public PipelineIntegrationTest {\n protected:\n void PlayToEnd() {\n MSEPlaybackTestData data = GetParam();\n\n TestMediaSource source(data.filename, data.append_bytes);\n ASSERT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kNormal, nullptr));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(data.duration_ms,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());\n source.Shutdown();\n Stop();\n }\n};\n\nTEST_P(BasicMSEPlaybackTest, PlayToEnd) {\n PlayToEnd();\n}\n\nconst PlaybackTestData kADTSTests[] = {\n {\"bear-audio-main-aac.aac\", 0, 2708},\n {\"bear-audio-lc-aac.aac\", 0, 2791},\n {\"bear-audio-implicit-he-aac-v1.aac\", 0, 2829},\n {\"bear-audio-implicit-he-aac-v2.aac\", 0, 2900},\n};\n\n// TODO(chcunningham): Migrate other basic playback tests to TEST_P.\nINSTANTIATE_TEST_SUITE_P(ProprietaryCodecs,\n BasicPlaybackTest,\n testing::ValuesIn(kADTSTests));\n\nconst MSEPlaybackTestData kMediaSourceADTSTests[] = {\n {\"bear-audio-main-aac.aac\", kAppendWholeFile, 2773},\n {\"bear-audio-lc-aac.aac\", kAppendWholeFile, 2794},\n {\"bear-audio-implicit-he-aac-v1.aac\", kAppendWholeFile, 2858},\n {\"bear-audio-implicit-he-aac-v2.aac\", kAppendWholeFile, 2901},\n};\n\n// TODO(chcunningham): Migrate other basic MSE playback tests to TEST_P.\nINSTANTIATE_TEST_SUITE_P(ProprietaryCodecs,\n BasicMSEPlaybackTest,\n testing::ValuesIn(kMediaSourceADTSTests));\n\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\nstruct MSEChangeTypeTestData {\n const MSEPlaybackTestData file_one;\n const MSEPlaybackTestData file_two;\n};\n\nclass MSEChangeTypeTest\n : public ::testing::WithParamInterface<\n std::tuple<MSEPlaybackTestData, MSEPlaybackTestData>>,\n public PipelineIntegrationTest {\n public:\n // Populate meaningful test suffixes instead of /0, /1, etc.\n struct PrintToStringParamName {\n template <class ParamType>\n std::string operator()(\n const testing::TestParamInfo<ParamType>& info) const {\n std::stringstream ss;\n ss << std::get<0>(info.param) << \"_AND_\" << std::get<1>(info.param);\n std::string s = ss.str();\n // Strip out invalid param name characters.\n std::stringstream ss2;\n for (size_t i = 0; i < s.size(); ++i) {\n if (isalnum(s[i]) || s[i] == '_')\n ss2 << s[i];\n }\n return ss2.str();\n }\n };\n\n protected:\n void PlayBackToBack() {\n // TODO(wolenetz): Consider a modified, composable, hash that lets us\n // combine known hashes for two files to generate an expected hash for when\n // both are played. For now, only the duration (and successful append and\n // play-to-end) are verified.\n MSEPlaybackTestData file_one = std::get<0>(GetParam());\n MSEPlaybackTestData file_two = std::get<1>(GetParam());\n\n // Start in 'sequence' appendMode, because some test media begin near enough\n // to time 0, resulting in gaps across the changeType boundary in buffered\n // media timeline.\n // TODO(wolenetz): Switch back to 'segments' mode once we have some\n // incubation of a way to flexibly allow playback through unbuffered\n // regions. Known test media requiring sequence mode: MP3-in-MP2T\n TestMediaSource source(file_one.filename, file_one.append_bytes, true);\n ASSERT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kNormal, nullptr));\n source.EndOfStream();\n\n // Transitions between VP8A and other test media can trigger this again.\n EXPECT_CALL(*this, OnVideoOpacityChange(_)).Times(AnyNumber());\n\n Ranges<base::TimeDelta> ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, ranges.size());\n EXPECT_EQ(0, ranges.start(0).InMilliseconds());\n base::TimeDelta file_one_end_time = ranges.end(0);\n EXPECT_EQ(file_one.duration_ms, file_one_end_time.InMilliseconds());\n\n // Change type and append |file_two| with start time abutting end of\n // the previous buffered range.\n source.UnmarkEndOfStream();\n source.ChangeType(GetMimeTypeForFile(file_two.filename));\n scoped_refptr<DecoderBuffer> file_two_contents =\n ReadTestDataFile(file_two.filename);\n source.AppendAtTime(file_one_end_time, file_two_contents->data(),\n file_two.append_bytes == kAppendWholeFile\n ? file_two_contents->data_size()\n : file_two.append_bytes);\n source.EndOfStream();\n ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, ranges.size());\n EXPECT_EQ(0, ranges.start(0).InMilliseconds());\n\n base::TimeDelta file_two_actual_duration =\n ranges.end(0) - file_one_end_time;\n EXPECT_EQ(file_two_actual_duration.InMilliseconds(), file_two.duration_ms);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());\n source.Shutdown();\n Stop();\n }\n};\n\nTEST_P(MSEChangeTypeTest, PlayBackToBack) {\n PlayBackToBack();\n}\n\nconst MSEPlaybackTestData kMediaSourceAudioFiles[] = {\n // MP3\n {\"sfx.mp3\", kAppendWholeFile, 313},\n\n // Opus in WebM\n {\"sfx-opus-441.webm\", kAppendWholeFile, 301},\n\n // Vorbis in WebM\n {\"bear-320x240-audio-only.webm\", kAppendWholeFile, 2768},\n\n // FLAC in MP4\n {\"sfx-flac_frag.mp4\", kAppendWholeFile, 288},\n\n // Opus in MP4\n {\"sfx-opus_frag.mp4\", kAppendWholeFile, 301},\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n // AAC in ADTS\n {\"bear-audio-main-aac.aac\", kAppendWholeFile, 2773},\n\n // AAC in MP4\n {\"bear-640x360-a_frag.mp4\", kAppendWholeFile, 2803},\n\n#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n // MP3 in MP2T\n {\"bear-audio-mp4a.6B.ts\", kAppendWholeFile, 1097},\n#endif // BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n};\n\nconst MSEPlaybackTestData kMediaSourceVideoFiles[] = {\n // VP9 in WebM\n {\"bear-vp9.webm\", kAppendWholeFile, kVP9WebMFileDurationMs},\n\n // VP9 in MP4\n {\"bear-320x240-v_frag-vp9.mp4\", kAppendWholeFile, 2736},\n\n // VP8 in WebM\n {\"bear-vp8a.webm\", kAppendWholeFile, kVP8AWebMFileDurationMs},\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\n // AV1 in MP4\n {\"bear-av1.mp4\", kAppendWholeFile, kVP9WebMFileDurationMs},\n\n // AV1 in WebM\n {\"bear-av1.webm\", kAppendWholeFile, kVP9WebMFileDurationMs},\n#endif // BUILDFLAG(ENABLE_AV1_DECODER)\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n // H264 AVC3 in MP4\n {\"bear-1280x720-v_frag-avc3.mp4\", kAppendWholeFile,\n k1280IsoAVC3FileDurationMs},\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n};\n\nINSTANTIATE_TEST_SUITE_P(\n AudioOnly,\n MSEChangeTypeTest,\n testing::Combine(testing::ValuesIn(kMediaSourceAudioFiles),\n testing::ValuesIn(kMediaSourceAudioFiles)),\n MSEChangeTypeTest::PrintToStringParamName());\n\nINSTANTIATE_TEST_SUITE_P(\n VideoOnly,\n MSEChangeTypeTest,\n testing::Combine(testing::ValuesIn(kMediaSourceVideoFiles),\n testing::ValuesIn(kMediaSourceVideoFiles)),\n MSEChangeTypeTest::PrintToStringParamName());\n\nTEST_F(PipelineIntegrationTest, BasicPlayback) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-opus.ogg\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg_4ch_ChannelMapping2) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-opus-4ch-channelmapping2.ogg\", kWebAudio));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusOgg_11ch_ChannelMapping2) {\n ASSERT_EQ(PIPELINE_OK,\n Start(\"bear-opus-11ch-channelmapping2.ogg\", kWebAudio));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_HASH_EQ(\"f0be120a90a811506777c99a2cdf7cc1\", GetVideoHash());\n EXPECT_HASH_EQ(\"-3.59,-2.06,-0.43,2.15,0.77,-0.95,\", GetAudioHash());\n EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());\n}\n\nbase::TimeDelta TimestampMs(int milliseconds) {\n return base::Milliseconds(milliseconds);\n}\n\nTEST_F(PipelineIntegrationTest, WaveLayoutChange) {\n ASSERT_EQ(PIPELINE_OK, Start(\"layout_change.wav\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// TODO(https://crbug.com/1354581): At most one of Playback9Channels48000hz and\n// Playback9Channels44100hz will pass, because for 9+ channel files the hardware\n// sample rate has to match the file's sample rate. They are both disabled\n// because different CI configurations have different hardware sample rates. To\n// run the tests, enable them both and expect at most one of them to pass.\nTEST_F(PipelineIntegrationTest, DISABLED_Playback9Channels48000hz) {\n EXPECT_EQ(PIPELINE_OK, Start(\"9ch.wav\"));\n}\n\nTEST_F(PipelineIntegrationTest, DISABLED_Playback9Channels44100hz) {\n EXPECT_EQ(PIPELINE_OK, Start(\"9ch_44100.wav\"));\n}\n\nTEST_F(PipelineIntegrationTest, PlaybackStereo48000hz) {\n EXPECT_EQ(PIPELINE_OK, Start(\"stereo_48000.wav\"));\n}\n\nTEST_F(PipelineIntegrationTest, PlaybackWithAudioTrackDisabledThenEnabled) {\n#if BUILDFLAG(IS_MAC)\n // Enable scoped logs to help track down hangs. http://crbug.com/1014646\n ScopedVerboseLogEnabler scoped_log_enabler;\n#endif\n\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kHashed | kNoClockless));\n\n // Disable audio.\n std::vector<MediaTrack::Id> empty;\n OnEnabledAudioTracksChanged(empty);\n\n // Seek to flush the pipeline and ensure there's no prerolled audio data.\n ASSERT_TRUE(Seek(base::TimeDelta()));\n\n Play();\n const base::TimeDelta k500ms = TimestampMs(500);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(k500ms));\n Pause();\n\n // Verify that no audio has been played, since we disabled audio tracks.\n EXPECT_HASH_EQ(kNullAudioHash, GetAudioHash());\n\n // Re-enable audio.\n std::vector<MediaTrack::Id> audio_track_id;\n audio_track_id.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(audio_track_id);\n\n // Restart playback from 500ms position.\n ASSERT_TRUE(Seek(k500ms));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify that audio has been playing after being enabled.\n EXPECT_HASH_EQ(\"-1.53,0.21,1.23,1.56,-0.34,-0.94,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, PlaybackWithVideoTrackDisabledThenEnabled) {\n#if BUILDFLAG(IS_MAC)\n // Enable scoped logs to help track down hangs. http://crbug.com/1014646\n ScopedVerboseLogEnabler scoped_log_enabler;\n#endif\n\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kHashed | kNoClockless));\n\n // Disable video.\n OnSelectedVideoTrackChanged(absl::nullopt);\n\n // Seek to flush the pipeline and ensure there's no prerolled video data.\n ASSERT_TRUE(Seek(base::TimeDelta()));\n\n // Reset the video hash in case some of the prerolled video frames have been\n // hashed already.\n ResetVideoHash();\n\n Play();\n const base::TimeDelta k500ms = TimestampMs(500);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(k500ms));\n Pause();\n\n // Verify that no video has been rendered, since we disabled video tracks.\n EXPECT_HASH_EQ(kNullVideoHash, GetVideoHash());\n\n // Re-enable video.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n\n // Seek to flush video pipeline and reset the video hash again to clear state\n // if some prerolled frames got hashed after enabling video.\n ASSERT_TRUE(Seek(base::TimeDelta()));\n ResetVideoHash();\n\n // Restart playback from 500ms position.\n ASSERT_TRUE(Seek(k500ms));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify that video has been rendered after being enabled.\n EXPECT_HASH_EQ(\"fd59357dfd9c144ab4fb8181b2de32c3\", GetVideoHash());\n}\n\nTEST_F(PipelineIntegrationTest, TrackStatusChangesBeforePipelineStarted) {\n std::vector<MediaTrack::Id> empty_track_ids;\n OnEnabledAudioTracksChanged(empty_track_ids);\n OnSelectedVideoTrackChanged(absl::nullopt);\n}\n\nTEST_F(PipelineIntegrationTest, TrackStatusChangesAfterPipelineEnded) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n std::vector<MediaTrack::Id> track_ids;\n // Disable audio track.\n OnEnabledAudioTracksChanged(track_ids);\n // Re-enable audio track.\n track_ids.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(track_ids);\n // Disable video track.\n OnSelectedVideoTrackChanged(absl::nullopt);\n // Re-enable video track.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n}\n\n// TODO(crbug.com/40101269): Enable test when MacOS flake is fixed.\n#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)\n#define MAYBE_TrackStatusChangesWhileSuspended \\\n DISABLED_TrackStatusChangesWhileSuspended\n#else\n#define MAYBE_TrackStatusChangesWhileSuspended TrackStatusChangesWhileSuspended\n#endif\n\nTEST_F(PipelineIntegrationTest, MAYBE_TrackStatusChangesWhileSuspended) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n Play();\n\n ASSERT_TRUE(Suspend());\n\n // These get triggered every time playback is resumed.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240)))\n .Times(AnyNumber());\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(AnyNumber());\n\n std::vector<MediaTrack::Id> track_ids;\n\n // Disable audio track.\n OnEnabledAudioTracksChanged(track_ids);\n ASSERT_TRUE(Resume(TimestampMs(100)));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n ASSERT_TRUE(Suspend());\n\n // Re-enable audio track.\n track_ids.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(track_ids);\n ASSERT_TRUE(Resume(TimestampMs(200)));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(300)));\n ASSERT_TRUE(Suspend());\n\n // Disable video track.\n OnSelectedVideoTrackChanged(absl::nullopt);\n ASSERT_TRUE(Resume(TimestampMs(300)));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(400)));\n ASSERT_TRUE(Suspend());\n\n // Re-enable video track.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n ASSERT_TRUE(Resume(TimestampMs(400)));\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, ReinitRenderersWhileAudioTrackIsDisabled) {\n // This test is flaky without kNoClockless, see crbug.com/788387.\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n Play();\n\n // These get triggered every time playback is resumed.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240)))\n .Times(AnyNumber());\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(AnyNumber());\n\n // Disable the audio track.\n std::vector<MediaTrack::Id> track_ids;\n OnEnabledAudioTracksChanged(track_ids);\n // pipeline.Suspend() releases renderers and pipeline.Resume() recreates and\n // reinitializes renderers while the audio track is disabled.\n ASSERT_TRUE(Suspend());\n ASSERT_TRUE(Resume(TimestampMs(100)));\n // Now re-enable the audio track, playback should continue successfully.\n EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH, _)).Times(1);\n track_ids.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(track_ids);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, ReinitRenderersWhileVideoTrackIsDisabled) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n Play();\n\n // These get triggered every time playback is resumed.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240)))\n .Times(AnyNumber());\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(AnyNumber());\n\n // Disable the video track.\n OnSelectedVideoTrackChanged(absl::nullopt);\n // pipeline.Suspend() releases renderers and pipeline.Resume() recreates and\n // reinitializes renderers while the video track is disabled.\n ASSERT_TRUE(Suspend());\n ASSERT_TRUE(Resume(TimestampMs(100)));\n // Now re-enable the video track, playback should continue successfully.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, PipelineStoppedWhileAudioRestartPending) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n Play();\n\n // Disable audio track first, to re-enable it later and stop the pipeline\n // (which destroys the media renderer) while audio restart is pending.\n std::vector<MediaTrack::Id> track_ids;\n OnEnabledAudioTracksChanged(track_ids);\n\n // Playback is paused while all audio tracks are disabled.\n\n track_ids.push_back(MediaTrack::Id(\"2\"));\n OnEnabledAudioTracksChanged(track_ids);\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, PipelineStoppedWhileVideoRestartPending) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n Play();\n\n // Disable video track first, to re-enable it later and stop the pipeline\n // (which destroys the media renderer) while video restart is pending.\n OnSelectedVideoTrackChanged(absl::nullopt);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"1\"));\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, SwitchAudioTrackDuringPlayback) {\n ASSERT_EQ(PIPELINE_OK, Start(\"multitrack-3video-2audio.webm\", kNoClockless));\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(100)));\n // The first audio track (TrackId=4) is enabled by default. This should\n // disable TrackId=4 and enable TrackId=5.\n std::vector<MediaTrack::Id> track_ids;\n track_ids.push_back(MediaTrack::Id(\"5\"));\n OnEnabledAudioTracksChanged(track_ids);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, SwitchVideoTrackDuringPlayback) {\n ASSERT_EQ(PIPELINE_OK, Start(\"multitrack-3video-2audio.webm\", kNoClockless));\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(100)));\n // The first video track (TrackId=1) is enabled by default. This should\n // disable TrackId=1 and enable TrackId=2.\n OnSelectedVideoTrackChanged(MediaTrack::Id(\"2\"));\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(TimestampMs(200)));\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusOggTrimmingHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"opus-trimming-test.ogg\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n ASSERT_TRUE(Seek(base::Seconds(1)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n ASSERT_TRUE(Seek(base::Milliseconds(6360)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusWebmTrimmingHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"opus-trimming-test.webm\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n ASSERT_TRUE(Seek(base::Seconds(1)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n ASSERT_TRUE(Seek(base::Milliseconds(6360)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusMp4TrimmingHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"opus-trimming-test.mp4\", kHashed));\n\n Play();\n\n // TODO(dalecurtis): The test clip currently does not have the edit list\n // entries required to achieve correctness here. Delete this comment and\n // uncomment the EXPECT_HASH_EQ lines when https://crbug.com/876544 is fixed.\n\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n ASSERT_TRUE(Seek(base::Seconds(1)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n ASSERT_TRUE(Seek(base::Milliseconds(6360)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlaybackOpusWebmTrimmingHashed) {\n TestMediaSource source(\"opus-trimming-test.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n base::TimeDelta seek_time = base::Seconds(1);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n seek_time = base::Milliseconds(6360);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlaybackOpusMp4TrimmingHashed) {\n TestMediaSource source(\"opus-trimming-test.mp4\", kAppendWholeFile);\n\n // TODO(dalecurtis): The test clip currently does not have the edit list\n // entries required to achieve correctness here, so we're manually specifying\n // the edits using append window trimming.\n //\n // It's unclear if MSE actually supports edit list features required to\n // achieve correctness either. Delete this comment and remove the manual\n // SetAppendWindow() if/when https://crbug.com/876544 is fixed.\n source.SetAppendWindow(base::TimeDelta(), base::TimeDelta(),\n base::Microseconds(12720021));\n\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_1, GetAudioHash());\n\n // Seek within the pre-skip section, this should not cause a beep.\n base::TimeDelta seek_time = base::Seconds(1);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_2, GetAudioHash());\n\n // Seek somewhere outside of the pre-skip / end-trim section, demuxer should\n // correctly preroll enough to accurately decode this segment.\n seek_time = base::Milliseconds(6360);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusEndTrimmingHash_3, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusWebmHashed_MonoOutput) {\n ASSERT_EQ(PIPELINE_OK,\n Start(\"bunny-opus-intensity-stereo.webm\", kHashed | kMonoOutput));\n\n // File should have stereo output, which we know to be encoded using \"phase\n // intensity\". Downmixing such files to MONO produces artifacts unless the\n // decoder performs the downmix, which disables \"phase inversion\". See\n // http://crbug.com/806219\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n ASSERT_EQ(config.channel_layout(), CHANNEL_LAYOUT_STEREO);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Hash has very slight differences when phase inversion is enabled.\n EXPECT_HASH_EQ(kOpusMonoOutputHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusPrerollExceedsCodecDelay) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-opus.webm\", kHashed));\n\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n\n // Verify that this file's preroll is not eclipsed by the codec delay so we\n // can detect when preroll is not properly performed.\n base::TimeDelta codec_delay = base::Seconds(\n static_cast<double>(config.codec_delay()) / config.samples_per_second());\n ASSERT_GT(config.seek_preroll(), codec_delay);\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());\n\n // Seek halfway through the file to invoke seek preroll.\n ASSERT_TRUE(Seek(base::Seconds(1.414)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackOpusMp4PrerollExceedsCodecDelay) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-opus.mp4\", kHashed));\n\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n\n // Verify that this file's preroll is not eclipsed by the codec delay so we\n // can detect when preroll is not properly performed.\n base::TimeDelta codec_delay = base::Seconds(\n static_cast<double>(config.codec_delay()) / config.samples_per_second());\n ASSERT_GT(config.seek_preroll(), codec_delay);\n\n // TODO(dalecurtis): The test clip currently does not have the edit list\n // entries required to achieve correctness here. Delete this comment and\n // uncomment the EXPECT_HASH_EQ lines when https://crbug.com/876544 is fixed.\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());\n\n // Seek halfway through the file to invoke seek preroll.\n ASSERT_TRUE(Seek(base::Seconds(1.414)));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n // EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlaybackOpusPrerollExceedsCodecDelay) {\n TestMediaSource source(\"bear-opus.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n\n // Verify that this file's preroll is not eclipsed by the codec delay so we\n // can detect when preroll is not properly performed.\n base::TimeDelta codec_delay = base::Seconds(\n static_cast<double>(config.codec_delay()) / config.samples_per_second());\n ASSERT_GT(config.seek_preroll(), codec_delay);\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());\n\n // Seek halfway through the file to invoke seek preroll.\n base::TimeDelta seek_time = base::Seconds(1.414);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_BasicPlaybackOpusMp4PrerollExceedsCodecDelay) {\n TestMediaSource source(\"bear-opus.mp4\", kAppendWholeFile);\n\n // TODO(dalecurtis): The test clip currently does not have the edit list\n // entries required to achieve correctness here, so we're manually specifying\n // the edits using append window trimming.\n //\n // It's unclear if MSE actually supports edit list features required to\n // achieve correctness either. Delete this comment and remove the manual\n // SetAppendWindow() if/when https://crbug.com/876544 is fixed.\n source.SetAppendWindow(base::TimeDelta(), base::TimeDelta(),\n base::Microseconds(2740834));\n\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n AudioDecoderConfig config =\n demuxer_->GetFirstStream(DemuxerStream::AUDIO)->audio_decoder_config();\n\n // Verify that this file's preroll is not eclipsed by the codec delay so we\n // can detect when preroll is not properly performed.\n base::TimeDelta codec_delay = base::Seconds(\n static_cast<double>(config.codec_delay()) / config.samples_per_second());\n ASSERT_GT(config.seek_preroll(), codec_delay);\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_1, GetAudioHash());\n\n // Seek halfway through the file to invoke seek preroll.\n base::TimeDelta seek_time = base::Seconds(1.414);\n source.Seek(seek_time);\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(kOpusSmallCodecDelayHash_2, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackLive) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240-live.webm\", kHashed));\n\n // Live stream does not have duration in the initialization segment.\n // It will be set after the entire file is available.\n EXPECT_CALL(*this, OnDurationChange()).Times(1);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_HASH_EQ(\"f0be120a90a811506777c99a2cdf7cc1\", GetVideoHash());\n EXPECT_HASH_EQ(\"-3.59,-2.06,-0.43,2.15,0.77,-0.95,\", GetAudioHash());\n EXPECT_EQ(kLiveTimelineOffset(), demuxer_->GetTimelineOffset());\n}\n\nTEST_F(PipelineIntegrationTest, S32PlaybackHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx_s32le.wav\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, F32PlaybackHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx_f32le.wav\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackEncrypted) {\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n set_encrypted_media_init_data_cb(\n base::BindRepeating(&FakeEncryptedMedia::OnEncryptedMediaInitData,\n base::Unretained(&encrypted_media)));\n\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240-av_enc-av.webm\",\n encrypted_media.GetCdmContext()));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, FlacPlaybackHashed) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx.flac\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback) {\n TestMediaSource source(\"bear-320x240.webm\", 219229);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(k320WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_TRUE(demuxer_->GetTimelineOffset().is_null());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EosBeforeDemuxerOpened) {\n // After appending only a partial initialization segment, marking end of\n // stream should let the test complete with error indicating failure to open\n // demuxer. Here we append only the first 10 bytes of a test WebM, definitely\n // less than the ~4400 bytes needed to parse its full initialization segment.\n TestMediaSource source(\"bear-320x240.webm\", 10);\n source.set_do_eos_after_next_append(true);\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n}\n\nTEST_F(PipelineIntegrationTest, MSE_CorruptedFirstMediaSegment) {\n // After successful initialization segment append completing demuxer opening,\n // immediately append a corrupted media segment to trigger parse error while\n // pipeline is still completing renderer setup.\n TestMediaSource source(\"bear-320x240_corrupted_after_init_segment.webm\",\n 4380);\n source.set_expected_append_result(\n TestMediaSource::ExpectedAppendResult::kFailure);\n EXPECT_EQ(CHUNK_DEMUXER_ERROR_APPEND_FAILED,\n StartPipelineWithMediaSource(&source));\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_Live) {\n TestMediaSource source(\"bear-320x240-live.webm\", 219221);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(k320WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(kLiveTimelineOffset(), demuxer_->GetTimelineOffset());\n source.Shutdown();\n Stop();\n}\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_WebM) {\n TestMediaSource source(\"bear-av1.webm\", 18898);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_10bit_WebM) {\n TestMediaSource source(\"bear-av1-320x180-10bit.webm\", 19076);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YUV420P10);\n Stop();\n}\n\n#endif\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VP9_WebM) {\n TestMediaSource source(\"bear-vp9.webm\", 67504);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VP9_BlockGroup_WebM) {\n TestMediaSource source(\"bear-vp9-blockgroup.webm\", 67871);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VP8A_WebM) {\n TestMediaSource source(\"bear-vp8a.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP8AWebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_AV1_WebM) {\n TestMediaSource source(\"bear-av1-480x360.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n const gfx::Size kNewSize(640, 480);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-av1-640x480.webm\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + kAV1640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n#endif // BUILDFLAG(ENABLE_AV1_DECODER)\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_WebM) {\n TestMediaSource source(\"bear-320x240-16x9-aspect.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n const gfx::Size kNewSize(640, 360);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-640x360.webm\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_AudioConfigChange_WebM) {\n TestMediaSource source(\"bear-320x240-audio-only.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n const int kNewSampleRate = 48000;\n EXPECT_CALL(*this,\n OnAudioConfigChange(::testing::Property(\n &AudioDecoderConfig::samples_per_second, kNewSampleRate)))\n .Times(1);\n\n // A higher sample rate will cause the audio buffer durations to change. This\n // should not manifest as a timestamp gap in AudioTimestampValidator.\n // Timestamp expectations should be reset across config changes.\n EXPECT_MEDIA_LOG(Not(HasSubstr(\"Large timestamp gap detected\")))\n .Times(AnyNumber());\n\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-320x240-audio-only-48khz.webm\");\n ASSERT_TRUE(source.AppendAtTime(base::Seconds(kAppendTimeSec),\n second_file->data(),\n second_file->data_size()));\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(3774, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_RemoveUpdatesBufferedRanges) {\n TestMediaSource source(\"bear-320x240.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n auto buffered_ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, buffered_ranges.size());\n EXPECT_EQ(0, buffered_ranges.start(0).InMilliseconds());\n EXPECT_EQ(k320WebMFileDurationMs, buffered_ranges.end(0).InMilliseconds());\n\n source.RemoveRange(base::Milliseconds(1000),\n base::Milliseconds(k320WebMFileDurationMs));\n task_environment_.RunUntilIdle();\n\n buffered_ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, buffered_ranges.size());\n EXPECT_EQ(0, buffered_ranges.start(0).InMilliseconds());\n EXPECT_EQ(1001, buffered_ranges.end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\n// This test case imitates media playback with advancing media_time and\n// continuously adding new data. At some point we should reach the buffering\n// limit, after that MediaSource should evict some buffered data and that\n// evicted data shold be reflected in the change of media::Pipeline buffered\n// ranges (returned by GetBufferedTimeRanges). At that point the buffered ranges\n// will no longer start at 0.\nTEST_F(PipelineIntegrationTest, MSE_FillUpBuffer) {\n const char* input_filename = \"bear-320x240.webm\";\n TestMediaSource source(input_filename, kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.SetMemoryLimits(1048576);\n\n scoped_refptr<DecoderBuffer> file = ReadTestDataFile(input_filename);\n\n auto buffered_ranges = pipeline_->GetBufferedTimeRanges();\n EXPECT_EQ(1u, buffered_ranges.size());\n do {\n // Advance media_time to the end of the currently buffered data\n base::TimeDelta media_time = buffered_ranges.end(0);\n source.Seek(media_time);\n // Ask MediaSource to evict buffered data if buffering limit has been\n // reached (the data will be evicted from the front of the buffered range).\n source.EvictCodedFrames(media_time, file->data_size());\n source.AppendAtTime(media_time, file->data(), file->data_size());\n task_environment_.RunUntilIdle();\n\n buffered_ranges = pipeline_->GetBufferedTimeRanges();\n } while (buffered_ranges.size() == 1 &&\n buffered_ranges.start(0) == base::Seconds(0));\n\n EXPECT_EQ(1u, buffered_ranges.size());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_GCWithDisabledVideoStream) {\n const char* input_filename = \"bear-320x240.webm\";\n TestMediaSource source(input_filename, kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n scoped_refptr<DecoderBuffer> file = ReadTestDataFile(input_filename);\n // The input file contains audio + video data. Assuming video data size is\n // larger than audio, so setting memory limits to half of file data_size will\n // ensure that video SourceBuffer is above memory limit and the audio\n // SourceBuffer is below the memory limit.\n source.SetMemoryLimits(file->data_size() / 2);\n\n // Disable the video track and start playback. Renderer won't read from the\n // disabled video stream, so the video stream read position should be 0.\n OnSelectedVideoTrackChanged(absl::nullopt);\n Play();\n\n // Wait until audio playback advances past 2 seconds and call MSE GC algorithm\n // to prepare for more data to be appended.\n base::TimeDelta media_time = base::Seconds(2);\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(media_time));\n // At this point the video SourceBuffer is over the memory limit (see the\n // SetMemoryLimits comment above), but MSE GC should be able to remove some\n // of video data and return true indicating success, even though no data has\n // been read from the disabled video stream and its read position is 0.\n ASSERT_TRUE(source.EvictCodedFrames(media_time, 10));\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_Encrypted_WebM) {\n TestMediaSource source(\"bear-320x240-16x9-aspect-av_enc-av.webm\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n const gfx::Size kNewSize(640, 360);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-640x360-av_enc-av.webm\");\n\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_ClearThenEncrypted_WebM) {\n TestMediaSource source(\"bear-320x240-16x9-aspect.webm\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n const gfx::Size kNewSize(640, 360);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-640x360-av_enc-av.webm\");\n\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\n// Config change from encrypted to clear is allowed by the demuxer, and is\n// supported by the Renderer.\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_EncryptedThenClear_WebM) {\n TestMediaSource source(\"bear-320x240-16x9-aspect-av_enc-av.webm\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n const gfx::Size kNewSize(640, 360);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-640x360.webm\");\n\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k640WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\n#if defined(ARCH_CPU_X86_FAMILY) && !BUILDFLAG(IS_ANDROID)\nTEST_F(PipelineIntegrationTest, BasicPlaybackHi10PVP9) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x180-hi10p-vp9.webm\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHi12PVP9) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x180-hi12p-vp9.webm\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_MP4) {\n TestMediaSource source(\"bear-av1.mp4\", 24355);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_Audio_OPUS_MP4) {\n TestMediaSource source(\"bear-av1-opus.mp4\", 50253);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kVP9WebMFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_AV1_10bit_MP4) {\n TestMediaSource source(\"bear-av1-320x180-10bit.mp4\", 19658);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAV110bitMp4FileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YUV420P10);\n Stop();\n}\n#endif\n\nTEST_F(PipelineIntegrationTest, MSE_FlacInMp4_Hashed) {\n TestMediaSource source(\"sfx-flac_frag.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(288, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed_MP3) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx.mp3\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify codec delay and preroll are stripped.\n EXPECT_HASH_EQ(\"1.30,2.72,4.56,5.08,3.74,2.03,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed_FlacInMp4) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx-flac.mp4\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(std::string(kNullVideoHash), GetVideoHash());\n EXPECT_HASH_EQ(kSfxLosslessHash, GetAudioHash());\n}\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_AV1_Mp4) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-av1.mp4\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_MonoAV1_Mp4) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-mono-av1.mp4\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlayback_Video_AV1_Audio_Opus_Mp4) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-av1-opus.mp4\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif\n\nclass Mp3FastSeekParams {\n public:\n Mp3FastSeekParams(const char* filename, const char* hash)\n : filename(filename), hash(hash) {}\n const char* filename;\n const char* hash;\n};\n\nclass Mp3FastSeekIntegrationTest\n : public PipelineIntegrationTest,\n public testing::WithParamInterface<Mp3FastSeekParams> {};\n\nTEST_P(Mp3FastSeekIntegrationTest, FastSeekAccuracy_MP3) {\n Mp3FastSeekParams config = GetParam();\n ASSERT_EQ(PIPELINE_OK, Start(config.filename, kHashed));\n\n // The XING TOC is inaccurate. We don't use it for CBR, we tolerate it for VBR\n // (best option for fast seeking; see Mp3SeekFFmpegDemuxerTest). The chosen\n // seek time exposes inaccuracy in TOC such that the hash will change if seek\n // logic is regressed. See https://crbug.com/545914.\n //\n // Quick TOC design (not pretty!):\n // - All MP3 TOCs are 100 bytes\n // - Each byte is read as a uint8_t; value between 0 - 255.\n // - The index into this array is the numerator in the ratio: index / 100.\n // This fraction represents a playback time as a percentage of duration.\n // - The value at the given index is the numerator in the ratio: value / 256.\n // This fraction represents a byte offset as a percentage of the file size.\n //\n // For CBR files, each frame is the same size, so the offset for time of\n // (0.98 * duration) should be around (0.98 * file size). This is 250.88 / 256\n // but the numerator will be truncated in the TOC as 250, losing precision.\n base::TimeDelta seek_time(0.98 * pipeline_->GetMediaDuration());\n\n ASSERT_TRUE(Seek(seek_time));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_HASH_EQ(config.hash, GetAudioHash());\n}\n\n// CBR seeks should always be fast and accurate.\nINSTANTIATE_TEST_SUITE_P(\n CBRSeek_HasTOC,\n Mp3FastSeekIntegrationTest,\n ::testing::Values(Mp3FastSeekParams(\"bear-audio-10s-CBR-has-TOC.mp3\",\n \"-0.58,0.61,3.08,2.55,0.90,-1.20,\")));\n\nINSTANTIATE_TEST_SUITE_P(\n CBRSeeks_NoTOC,\n Mp3FastSeekIntegrationTest,\n ::testing::Values(Mp3FastSeekParams(\"bear-audio-10s-CBR-no-TOC.mp3\",\n \"1.16,0.68,1.25,0.60,1.66,0.93,\")));\n\n// VBR seeks can be fast *OR* accurate, but not both. We chose fast.\nINSTANTIATE_TEST_SUITE_P(\n VBRSeeks_HasTOC,\n Mp3FastSeekIntegrationTest,\n ::testing::Values(Mp3FastSeekParams(\"bear-audio-10s-VBR-has-TOC.mp3\",\n \"-0.08,-0.53,0.75,0.89,2.44,0.73,\")));\n\nINSTANTIATE_TEST_SUITE_P(\n VBRSeeks_NoTOC,\n Mp3FastSeekIntegrationTest,\n ::testing::Values(Mp3FastSeekParams(\"bear-audio-10s-VBR-no-TOC.mp3\",\n \"-0.22,0.80,1.19,0.73,-0.31,-1.12,\")));\n\nTEST_F(PipelineIntegrationTest, MSE_MP3) {\n TestMediaSource source(\"sfx.mp3\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(313, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n EXPECT_TRUE(WaitUntilOnEnded());\n\n // Verify that codec delay was stripped.\n EXPECT_HASH_EQ(\"1.01,2.71,4.18,4.32,3.04,1.12,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_MP3_TimestampOffset) {\n TestMediaSource source(\"sfx.mp3\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n EXPECT_EQ(313, source.last_timestamp_offset().InMilliseconds());\n\n // There are 576 silent frames at the start of this mp3. The second append\n // should trim them off.\n const base::TimeDelta mp3_preroll_duration = base::Seconds(576.0 / 44100);\n const base::TimeDelta append_time =\n source.last_timestamp_offset() - mp3_preroll_duration;\n\n scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile(\"sfx.mp3\");\n source.AppendAtTimeWithWindow(append_time, append_time + mp3_preroll_duration,\n kInfiniteDuration, second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(613, source.last_timestamp_offset().InMilliseconds());\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(613, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_MP3_Icecast) {\n TestMediaSource source(\"icy_sfx.mp3\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n Play();\n\n EXPECT_TRUE(WaitUntilOnEnded());\n}\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n\nTEST_F(PipelineIntegrationTest, MSE_ADTS) {\n TestMediaSource source(\"sfx.adts\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(325, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n EXPECT_TRUE(WaitUntilOnEnded());\n\n // Verify that nothing was stripped.\n EXPECT_HASH_EQ(\"0.46,1.72,4.26,4.57,3.39,1.53,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ADTS_TimestampOffset) {\n TestMediaSource source(\"sfx.adts\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithMediaSource(&source, kHashed, nullptr));\n EXPECT_EQ(325, source.last_timestamp_offset().InMilliseconds());\n\n // Trim off multiple frames off the beginning of the segment which will cause\n // the first decoded frame to be incorrect if preroll isn't implemented.\n const base::TimeDelta adts_preroll_duration =\n base::Seconds(2.5 * 1024 / 44100);\n const base::TimeDelta append_time =\n source.last_timestamp_offset() - adts_preroll_duration;\n\n scoped_refptr<DecoderBuffer> second_file = ReadTestDataFile(\"sfx.adts\");\n source.AppendAtTimeWithWindow(\n append_time, append_time + adts_preroll_duration, kInfiniteDuration,\n second_file->data(), second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(592, source.last_timestamp_offset().InMilliseconds());\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(592, pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n // Verify preroll is stripped.\n EXPECT_HASH_EQ(\"-1.76,-1.35,-0.72,0.70,1.24,0.52,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed_ADTS) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx.adts\", kHashed));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify codec delay and preroll are stripped.\n EXPECT_HASH_EQ(\"1.80,1.66,2.31,3.26,4.46,3.36,\", GetAudioHash());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHashed_M4A) {\n ASSERT_EQ(PIPELINE_OK,\n Start(\"440hz-10ms.m4a\", kHashed | kUnreliableDuration));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Verify preroll is stripped. This file uses a preroll of 2112 frames, which\n // spans all three packets in the file. Postroll is not correctly stripped at\n // present; see the note below.\n EXPECT_HASH_EQ(\"3.84,4.25,4.33,3.58,3.27,3.16,\", GetAudioHash());\n\n // Note the above hash is incorrect since the <audio> path doesn't properly\n // trim trailing silence at end of stream for AAC decodes. This isn't a huge\n // deal since plain src= tags can't splice streams and MSE requires an\n // explicit append window for correctness.\n //\n // The WebAudio path via AudioFileReader computes this correctly, so the hash\n // below is taken from that test.\n //\n // EXPECT_HASH_EQ(\"3.77,4.53,4.75,3.48,3.67,3.76,\", GetAudioHash());\n}\n\n// TODO(crbug.com/1289825): Make this work on Android.\n#if BUILDFLAG(IS_MAC)\nconstexpr char kXHE_AACAudioHash[] = \"34.02,8.92,-11.02,12.15,16.11,10.75,\";\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackXHE_AAC) {\n if (__builtin_available(macOS 10.15, *)) {\n // Annoyingly !__builtin_available() doesn't work.\n } else {\n GTEST_SKIP() << \"Unsupported platform.\";\n }\n\n auto prepend_audio_decoders_cb = base::BindLambdaForTesting([]() {\n std::vector<std::unique_ptr<AudioDecoder>> audio_decoders;\n audio_decoders.push_back(std::make_unique<AudioToolboxAudioDecoder>());\n return audio_decoders;\n });\n\n ASSERT_EQ(PIPELINE_OK,\n Start(\"noise-xhe-aac.mp4\", kHashed, CreateVideoDecodersCB(),\n prepend_audio_decoders_cb));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Hash testing may be a poor choice here since we're using the OS decoders,\n // but lets wait to see what the test says on Android before removing.\n EXPECT_HASH_EQ(kXHE_AACAudioHash, GetAudioHash());\n\n // TODO(crbug.com/1289825): Seeking doesn't always work properly when using\n // ffmpeg since it doesn't handle non-keyframe xHE-AAC samples properly.\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlaybackXHE_AAC) {\n if (__builtin_available(macOS 10.15, *)) {\n // Annoyingly !__builtin_available() doesn't work.\n } else {\n GTEST_SKIP() << \"Unsupported platform.\";\n }\n\n auto prepend_audio_decoders_cb = base::BindLambdaForTesting([]() {\n std::vector<std::unique_ptr<AudioDecoder>> audio_decoders;\n audio_decoders.push_back(std::make_unique<AudioToolboxAudioDecoder>());\n return audio_decoders;\n });\n\n TestMediaSource source(\"noise-xhe-aac.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(\n &source, kHashed, prepend_audio_decoders_cb));\n source.EndOfStream();\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n Pause();\n\n // Hash testing may be a poor choice here since we're using the OS decoders,\n // but lets wait to see what the test says on Android before removing.\n EXPECT_HASH_EQ(kXHE_AACAudioHash, GetAudioHash());\n\n // Seek to ensure a flushing and playback resumption works properly.\n auto seek_time = pipeline_->GetMediaDuration() / 2;\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_EQ(seek_time, pipeline_->GetMediaTime());\n\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif // BUILDFLAG(IS_MAC)\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackHi10P) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x180-hi10p.mp4\"));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nstd::vector<std::unique_ptr<VideoDecoder>> CreateFailingVideoDecoder() {\n std::vector<std::unique_ptr<VideoDecoder>> failing_video_decoder;\n failing_video_decoder.push_back(std::make_unique<FailingVideoDecoder>());\n return failing_video_decoder;\n}\n\nTEST_F(PipelineIntegrationTest, BasicFallback) {\n ASSERT_EQ(PIPELINE_OK,\n Start(\"bear.mp4\", kNormal,\n base::BindRepeating(&CreateFailingVideoDecoder)));\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_MP4) {\n TestMediaSource source(\"bear-640x360-av_frag.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n\n const gfx::Size kNewSize(1280, 720);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-av_frag.mp4\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMsAV,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_Encrypted_MP4_CENC_VideoOnly) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-mdat.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n const gfx::Size kNewSize(1280, 720);\n EXPECT_CALL(*this, OnVideoConfigChange(::testing::Property(\n &VideoDecoderConfig::natural_size, kNewSize)))\n .Times(1);\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(kNewSize)).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-v_frag-cenc.mp4\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(33, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_ConfigChange_Encrypted_MP4_CENC_KeyRotation_VideoOnly) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-key_rotation.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(1280, 720))).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-v_frag-cenc-key_rotation.mp4\");\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n source.EndOfStream();\n\n Play();\n EXPECT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(33, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_ClearThenEncrypted_MP4_CENC) {\n TestMediaSource source(\"bear-640x360-v_frag.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(1280, 720))).Times(1);\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-v_frag-cenc.mp4\");\n source.set_expected_append_result(\n TestMediaSource::ExpectedAppendResult::kFailure);\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n\n source.EndOfStream();\n\n EXPECT_EQ(33, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(kAppendTimeMs + k1280IsoFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n// Config changes from encrypted to clear are not currently supported.\nTEST_F(PipelineIntegrationTest, MSE_ConfigChange_EncryptedThenClear_MP4_CENC) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-mdat.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n scoped_refptr<DecoderBuffer> second_file =\n ReadTestDataFile(\"bear-1280x720-av_frag.mp4\");\n\n source.set_expected_append_result(\n TestMediaSource::ExpectedAppendResult::kFailure);\n source.AppendAtTime(base::Seconds(kAppendTimeSec), second_file->data(),\n second_file->data_size());\n\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(33, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n\n // The second video was not added, so its time has not been added.\n EXPECT_EQ(k640IsoCencFileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n EXPECT_EQ(CHUNK_DEMUXER_ERROR_APPEND_FAILED, WaitUntilEndedOrError());\n source.Shutdown();\n}\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\n// Verify files which change configuration midstream fail gracefully.\nTEST_F(PipelineIntegrationTest, MidStreamConfigChangesFail) {\n ASSERT_EQ(PIPELINE_OK, Start(\"midstream_config_change.mp3\"));\n Play();\n ASSERT_EQ(WaitUntilEndedOrError(), PIPELINE_ERROR_DECODE);\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlayback_16x9AspectRatio) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240-16x9-aspect.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_WebM) {\n TestMediaSource source(\"bear-320x240-av_enc-av.webm\", 219816);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_ClearStart_WebM) {\n TestMediaSource source(\"bear-320x240-av_enc-av_clear-1s.webm\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_NoEncryptedFrames_WebM) {\n TestMediaSource source(\"bear-320x240-av_enc-av_clear-all.webm\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new NoResponseApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_VP9_CENC_VideoOnly) {\n TestMediaSource source(\"bear-320x240-v_frag-vp9-cenc.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VideoOnly_MP4_VP9) {\n TestMediaSource source(\"bear-320x240-v_frag-vp9.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_CENC_VideoOnly) {\n TestMediaSource source(\"bear-1280x720-v_frag-cenc.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_CENC_AudioOnly) {\n TestMediaSource source(\"bear-1280x720-a_frag-cenc.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_NoEncryptedFrames_MP4_CENC_VideoOnly) {\n TestMediaSource source(\"bear-1280x720-v_frag-cenc_clear-all.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new NoResponseApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_Mp2ts_AAC_HE_SBR_Audio) {\n TestMediaSource source(\"bear-1280x720-aac_he.ts\", kAppendWholeFile);\n#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n\n // Check that SBR is taken into account correctly by mpeg2ts parser. When an\n // SBR stream is parsed as non-SBR stream, then audio frame durations are\n // calculated incorrectly and that leads to gaps in buffered ranges (so this\n // check will fail) and eventually leads to stalled playback.\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif\n}\n\nTEST_F(PipelineIntegrationTest, MSE_Mpeg2ts_MP3Audio_Mp4a_6B) {\n TestMediaSource source(\"bear-audio-mp4a.6B.ts\",\n \"video/mp2t; codecs=\\\"mp4a.6B\\\"\", kAppendWholeFile);\n#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif\n}\n\nTEST_F(PipelineIntegrationTest, MSE_Mpeg2ts_MP3Audio_Mp4a_69) {\n TestMediaSource source(\"bear-audio-mp4a.69.ts\",\n \"video/mp2t; codecs=\\\"mp4a.69\\\"\", kAppendWholeFile);\n#if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n ASSERT_EQ(PIPELINE_OK, pipeline_status_);\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_NoEncryptedFrames_MP4_CENC_AudioOnly) {\n TestMediaSource source(\"bear-1280x720-a_frag-cenc_clear-all.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new NoResponseApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n// Older packagers saved sample encryption auxiliary information in the\n// beginning of mdat box.\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_CENC_MDAT_Video) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-mdat.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_EncryptedPlayback_MP4_CENC_SENC_Video) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-senc.mp4\", kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\n// 'SAIZ' and 'SAIO' boxes contain redundant information which is already\n// available in 'SENC' box. Although 'SAIZ' and 'SAIO' boxes are required per\n// CENC spec for backward compatibility reasons, but we do not use the two\n// boxes if 'SENC' box is present, so the code should work even if the two\n// boxes are not present.\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_MP4_CENC_SENC_NO_SAIZ_SAIO_Video) {\n TestMediaSource source(\"bear-640x360-v_frag-cenc-senc-no-saiz-saio.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new KeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_MP4_CENC_KeyRotation_Video) {\n TestMediaSource source(\"bear-1280x720-v_frag-cenc-key_rotation.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest,\n MSE_EncryptedPlayback_MP4_CENC_KeyRotation_Audio) {\n TestMediaSource source(\"bear-1280x720-a_frag-cenc-key_rotation.mp4\",\n kAppendWholeFile);\n FakeEncryptedMedia encrypted_media(new RotatingKeyProvidingApp());\n EXPECT_EQ(PIPELINE_OK,\n StartPipelineWithEncryptedMedia(&source, &encrypted_media));\n\n source.EndOfStream();\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VideoOnly_MP4_AVC3) {\n TestMediaSource source(\"bear-1280x720-v_frag-avc3.mp4\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n\n EXPECT_EQ(1u, pipeline_->GetBufferedTimeRanges().size());\n EXPECT_EQ(0, pipeline_->GetBufferedTimeRanges().start(0).InMilliseconds());\n EXPECT_EQ(k1280IsoAVC3FileDurationMs,\n pipeline_->GetBufferedTimeRanges().end(0).InMilliseconds());\n\n Play();\n\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n}\n\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VideoOnly_MP4_HEVC) {\n // HEVC demuxing might be enabled even on platforms that don't support HEVC\n // decoding. For those cases we'll get DECODER_ERROR_NOT_SUPPORTED, which\n // indicates indicates that we did pass media mime type checks and attempted\n // to actually demux and decode the stream. On platforms that support both\n // demuxing and decoding we'll get PIPELINE_OK.\n const char kMp4HevcVideoOnly[] = \"video/mp4; codecs=\\\"hvc1.1.6.L93.B0\\\"\";\n TestMediaSource source(\"bear-320x240-v_frag-hevc.mp4\", kMp4HevcVideoOnly,\n kAppendWholeFile);\n#if BUILDFLAG(ENABLE_PLATFORM_HEVC)\n PipelineStatus status = StartPipelineWithMediaSource(&source);\n EXPECT_TRUE(status == PIPELINE_OK || status == DECODER_ERROR_NOT_SUPPORTED);\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC)\n}\n\n// Same test as above but using a different mime type.\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_VideoOnly_MP4_HEV1) {\n const char kMp4Hev1VideoOnly[] = \"video/mp4; codecs=\\\"hev1.1.6.L93.B0\\\"\";\n TestMediaSource source(\"bear-320x240-v_frag-hevc.mp4\", kMp4Hev1VideoOnly,\n kAppendWholeFile);\n#if BUILDFLAG(ENABLE_PLATFORM_HEVC)\n PipelineStatus status = StartPipelineWithMediaSource(&source);\n EXPECT_TRUE(status == PIPELINE_OK || status == DECODER_ERROR_NOT_SUPPORTED);\n#else\n EXPECT_EQ(\n DEMUXER_ERROR_COULD_NOT_OPEN,\n StartPipelineWithMediaSource(&source, kExpectDemuxerFailure, nullptr));\n#endif // BUILDFLAG(ENABLE_PLATFORM_HEVC)\n}\n\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\nTEST_F(PipelineIntegrationTest, SeekWhilePaused) {\n#if BUILDFLAG(IS_MAC)\n // Enable scoped logs to help track down hangs. http://crbug.com/1014646\n ScopedVerboseLogEnabler scoped_log_enabler;\n#endif\n\n // This test is flaky without kNoClockless, see crbug.com/796250.\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n\n base::TimeDelta duration(pipeline_->GetMediaDuration());\n base::TimeDelta start_seek_time(duration / 4);\n base::TimeDelta seek_time(duration * 3 / 4);\n\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));\n Pause();\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_EQ(seek_time, pipeline_->GetMediaTime());\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Make sure seeking after reaching the end works as expected.\n Pause();\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_EQ(seek_time, pipeline_->GetMediaTime());\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, SeekWhilePlaying) {\n#if BUILDFLAG(IS_MAC)\n // Enable scoped logs to help track down hangs. http://crbug.com/1014646\n ScopedVerboseLogEnabler scoped_log_enabler;\n#endif\n\n // This test is flaky without kNoClockless, see crbug.com/796250.\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\", kNoClockless));\n\n base::TimeDelta duration(pipeline_->GetMediaDuration());\n base::TimeDelta start_seek_time(duration / 4);\n base::TimeDelta seek_time(duration * 3 / 4);\n\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_GE(pipeline_->GetMediaTime(), seek_time);\n ASSERT_TRUE(WaitUntilOnEnded());\n\n // Make sure seeking after reaching the end works as expected.\n ASSERT_TRUE(Seek(seek_time));\n EXPECT_GE(pipeline_->GetMediaTime(), seek_time);\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, SuspendWhilePaused) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n\n base::TimeDelta duration(pipeline_->GetMediaDuration());\n base::TimeDelta start_seek_time(duration / 4);\n base::TimeDelta seek_time(duration * 3 / 4);\n\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));\n Pause();\n\n // Suspend while paused.\n ASSERT_TRUE(Suspend());\n\n // Resuming the pipeline will create a new Renderer,\n // which in turn will trigger video size and opacity notifications.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240))).Times(1);\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(1);\n\n ASSERT_TRUE(Resume(seek_time));\n EXPECT_GE(pipeline_->GetMediaTime(), seek_time);\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, SuspendWhilePlaying) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240.webm\"));\n\n base::TimeDelta duration(pipeline_->GetMediaDuration());\n base::TimeDelta start_seek_time(duration / 4);\n base::TimeDelta seek_time(duration * 3 / 4);\n\n Play();\n ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time));\n ASSERT_TRUE(Suspend());\n\n // Resuming the pipeline will create a new Renderer,\n // which in turn will trigger video size and opacity notifications.\n EXPECT_CALL(*this, OnVideoNaturalSizeChange(gfx::Size(320, 240))).Times(1);\n EXPECT_CALL(*this, OnVideoOpacityChange(true)).Times(1);\n\n ASSERT_TRUE(Resume(seek_time));\n EXPECT_GE(pipeline_->GetMediaTime(), seek_time);\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\nTEST_F(PipelineIntegrationTest, Rotated_Metadata_0) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_rotate_0.mp4\"));\n ASSERT_EQ(VIDEO_ROTATION_0,\n metadata_.video_decoder_config.video_transformation().rotation);\n}\n\nTEST_F(PipelineIntegrationTest, Rotated_Metadata_90) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_rotate_90.mp4\"));\n ASSERT_EQ(VIDEO_ROTATION_90,\n metadata_.video_decoder_config.video_transformation().rotation);\n}\n\nTEST_F(PipelineIntegrationTest, Rotated_Metadata_180) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_rotate_180.mp4\"));\n ASSERT_EQ(VIDEO_ROTATION_180,\n metadata_.video_decoder_config.video_transformation().rotation);\n}\n\nTEST_F(PipelineIntegrationTest, Rotated_Metadata_270) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_rotate_270.mp4\"));\n ASSERT_EQ(VIDEO_ROTATION_270,\n metadata_.video_decoder_config.video_transformation().rotation);\n}\n\nTEST_F(PipelineIntegrationTest, Spherical) {\n ASSERT_EQ(PIPELINE_OK, Start(\"spherical.mp4\", kHashed));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_HASH_EQ(\"1cb7f980020d99ea852e22dd6bd8d9de\", GetVideoHash());\n}\n\nTEST_F(PipelineIntegrationTest, StereoAACMarkedAsMono) {\n ASSERT_EQ(PIPELINE_OK, Start(\"mono_cpe.adts\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)\n\n// Verify audio decoder & renderer can handle aborted demuxer reads.\nTEST_F(PipelineIntegrationTest, MSE_ChunkDemuxerAbortRead_AudioOnly) {\n ASSERT_TRUE(TestSeekDuringRead(\"bear-320x240-audio-only.webm\", 16384,\n base::Milliseconds(464),\n base::Milliseconds(617), 0x10CA, 19730));\n}\n\n// Verify video decoder & renderer can handle aborted demuxer reads.\nTEST_F(PipelineIntegrationTest, MSE_ChunkDemuxerAbortRead_VideoOnly) {\n ASSERT_TRUE(TestSeekDuringRead(\"bear-320x240-video-only.webm\", 32768,\n base::Milliseconds(167),\n base::Milliseconds(1668), 0x1C896, 65536));\n}\n\nTEST_F(PipelineIntegrationTest,\n BasicPlayback_AudioOnly_Opus_4ch_ChannelMapping2_WebM) {\n ASSERT_EQ(\n PIPELINE_OK,\n Start(\"bear-opus-end-trimming-4ch-channelmapping2.webm\", kWebAudio));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest,\n BasicPlayback_AudioOnly_Opus_11ch_ChannelMapping2_WebM) {\n ASSERT_EQ(\n PIPELINE_OK,\n Start(\"bear-opus-end-trimming-11ch-channelmapping2.webm\", kWebAudio));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that VP9 video in WebM containers can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_VP9_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n#if BUILDFLAG(ENABLE_AV1_DECODER)\nTEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_AV1_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-av1.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n#endif\n\n// Verify that VP9 video and Opus audio in the same WebM container can be played\n// back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Opus_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9-opus.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that VP8 video with alpha channel can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp8a.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);\n}\n\n// Verify that VP8A video with odd width/height can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_Odd_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp8a-odd-dimensions.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);\n}\n\n// Verify that VP9 video with odd width/height can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Odd_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9-odd-dimensions.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that VP9 video with alpha channel can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP9A_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9a.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);\n}\n\n// Verify that VP9A video with odd width/height can be played back.\nTEST_F(PipelineIntegrationTest, BasicPlayback_VP9A_Odd_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9a-odd-dimensions.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420A);\n}\n\n// Verify that VP9 video with 4:4:4 subsampling can be played back.\nTEST_F(PipelineIntegrationTest, P444_VP9_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-320x240-P444.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I444);\n}\n\n// Verify that frames of VP9 video in the BT.709 color space have the YV12HD\n// format.\nTEST_F(PipelineIntegrationTest, BT709_VP9_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-vp9-bt709.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420);\n EXPECT_COLOR_SPACE_EQ(last_video_frame_color_space_,\n gfx::ColorSpace::CreateREC709());\n}\n\n#if BUILDFLAG(USE_PROPRIETARY_CODECS)\n// Verify that full-range H264 video has the right color space.\nTEST_F(PipelineIntegrationTest, Fullrange_H264) {\n ASSERT_EQ(PIPELINE_OK, Start(\"blackwhite_yuvj420p.mp4\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n EXPECT_COLOR_SPACE_EQ(last_video_frame_color_space_,\n gfx::ColorSpace::CreateJpeg());\n}\n#endif\n\nTEST_F(PipelineIntegrationTest, HD_VP9_WebM) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear-1280x720.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that videos with an odd frame size playback successfully.\nTEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) {\n ASSERT_EQ(PIPELINE_OK, Start(\"butterfly-853x480.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Verify that OPUS audio in a webm which reports a 44.1kHz sample rate plays\n// correctly at 48kHz\nTEST_F(PipelineIntegrationTest, BasicPlayback_Opus441kHz) {\n ASSERT_EQ(PIPELINE_OK, Start(\"sfx-opus-441.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n\n EXPECT_EQ(48000, demuxer_->GetFirstStream(DemuxerStream::AUDIO)\n ->audio_decoder_config()\n .samples_per_second());\n}\n\n// Same as above but using MediaSource.\nTEST_F(PipelineIntegrationTest, MSE_BasicPlayback_Opus441kHz) {\n TestMediaSource source(\"sfx-opus-441.webm\", kAppendWholeFile);\n EXPECT_EQ(PIPELINE_OK, StartPipelineWithMediaSource(&source));\n source.EndOfStream();\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n source.Shutdown();\n Stop();\n EXPECT_EQ(48000, demuxer_->GetFirstStream(DemuxerStream::AUDIO)\n ->audio_decoder_config()\n .samples_per_second());\n}\n\n// Ensures audio-only playback with missing or negative timestamps works. Tests\n// the common live-streaming case for chained ogg. See http://crbug.com/396864.\nTEST_F(PipelineIntegrationTest, BasicPlaybackChainedOgg) {\n ASSERT_EQ(PIPELINE_OK, Start(\"double-sfx.ogg\", kUnreliableDuration));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n ASSERT_EQ(base::TimeDelta(), demuxer_->GetStartTime());\n}\n\nTEST_F(PipelineIntegrationTest, TrailingGarbage) {\n ASSERT_EQ(PIPELINE_OK, Start(\"trailing-garbage.mp3\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Ensures audio-video playback with missing or negative timestamps fails\n// instead of crashing. See http://crbug.com/396864.\nTEST_F(PipelineIntegrationTest, BasicPlaybackChainedOggVideo) {\n ASSERT_EQ(DEMUXER_ERROR_COULD_NOT_PARSE,\n Start(\"double-bear.ogv\", kUnreliableDuration));\n}\n\n// Tests that we signal ended even when audio runs longer than video track.\nTEST_F(PipelineIntegrationTest, BasicPlaybackAudioLongerThanVideo) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_audio_longer_than_video.ogv\"));\n // Audio track is 2000ms. Video track is 1001ms. Duration should be higher\n // of the two.\n EXPECT_EQ(2000, pipeline_->GetMediaDuration().InMilliseconds());\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\n// Tests that we signal ended even when audio runs shorter than video track.\nTEST_F(PipelineIntegrationTest, BasicPlaybackAudioShorterThanVideo) {\n ASSERT_EQ(PIPELINE_OK, Start(\"bear_audio_shorter_than_video.ogv\"));\n // Audio track is 500ms. Video track is 1001ms. Duration should be higher of\n // the two.\n EXPECT_EQ(1001, pipeline_->GetMediaDuration().InMilliseconds());\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n}\n\nTEST_F(PipelineIntegrationTest, BasicPlaybackPositiveStartTime) {\n ASSERT_EQ(PIPELINE_OK, Start(\"nonzero-start-time.webm\"));\n Play();\n ASSERT_TRUE(WaitUntilOnEnded());\n ASSERT_EQ(base::Microseconds(396000), demuxer_->GetStartTime());\n}\n\n} // namespace media\n"
}
}