// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/macros.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "media/base/mime_util.h" #include "media/base/mime_util_internal.h" #include "media/media_features.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" #endif namespace media { namespace internal { // MIME type for use with IsCodecSupportedOnPlatform() test; type is ignored in // all cases except for when paired with the Opus codec. const char kTestMimeType[] = "foo/foo"; // Helper method for creating a multi-value vector of |kTestStates| if // |test_all_values| is true or if false, a single value vector containing // |single_value|. static std::vector CreateTestVector(bool test_all_values, bool single_value) { const bool kTestStates[] = {true, false}; if (test_all_values) return std::vector(kTestStates, kTestStates + arraysize(kTestStates)); return std::vector(1, single_value); } // Helper method for running IsCodecSupportedOnPlatform() tests that will // iterate over all possible field values for a MimeUtil::PlatformInfo struct. // // To request a field be varied, set its value to true in the |states_to_vary| // struct. If false, the only value tested will be the field value from // |test_states|. // // |test_func| should have the signature . template static void RunCodecSupportTest(const MimeUtil::PlatformInfo& states_to_vary, const MimeUtil::PlatformInfo& test_states, TestCallback test_func) { #define MAKE_TEST_VECTOR(name) \ std::vector name##_states = \ CreateTestVector(states_to_vary.name, test_states.name) // Stuff states to test into vectors for easy for_each() iteration. MAKE_TEST_VECTOR(has_platform_decoders); MAKE_TEST_VECTOR(has_platform_vp8_decoder); MAKE_TEST_VECTOR(supports_opus); MAKE_TEST_VECTOR(supports_vp9); MAKE_TEST_VECTOR(is_unified_media_pipeline_enabled); #undef MAKE_TEST_VECTOR MimeUtil::PlatformInfo info; #define RUN_TEST_VECTOR(name) \ size_t name##_index = 0; \ for (info.name = name##_states[name##_index]; \ name##_index < name##_states.size(); ++name##_index) RUN_TEST_VECTOR(has_platform_decoders) { RUN_TEST_VECTOR(has_platform_vp8_decoder) { RUN_TEST_VECTOR(supports_opus) { RUN_TEST_VECTOR(supports_vp9) { RUN_TEST_VECTOR(is_unified_media_pipeline_enabled) { for (int codec = MimeUtil::INVALID_CODEC; codec <= MimeUtil::LAST_CODEC; ++codec) { SCOPED_TRACE(base::StringPrintf( "has_platform_decoders=%d, has_platform_vp8_decoder=%d, " "supports_opus=%d, " "supports_vp9=%d, is_unified_media_pipeline_enabled=%d, " "codec=%d", info.has_platform_decoders, info.has_platform_vp8_decoder, info.supports_opus, info.supports_vp9, info.is_unified_media_pipeline_enabled, codec)); test_func(info, static_cast(codec)); } } } } } } #undef RUN_TEST_VECTOR } // Helper method for generating the |states_to_vary| value used by // RunPlatformCodecTest(). Marks all fields to be varied. static MimeUtil::PlatformInfo VaryAllFields() { MimeUtil::PlatformInfo states_to_vary; states_to_vary.has_platform_vp8_decoder = true; states_to_vary.supports_opus = true; states_to_vary.supports_vp9 = true; states_to_vary.is_unified_media_pipeline_enabled = true; states_to_vary.has_platform_decoders = true; return states_to_vary; } static bool HasHevcSupport() { #if BUILDFLAG(ENABLE_HEVC_DEMUXING) #if defined(OS_ANDROID) return base::android::BuildInfo::GetInstance()->sdk_int() >= 21; #else return true; #endif // defined(OS_ANDROID) #else return false; #endif // BUILDFLAG(ENABLE_HEVC_DEMUXING) } TEST(MimeUtilTest, CommonMediaMimeType) { EXPECT_TRUE(IsSupportedMediaMimeType("audio/webm")); EXPECT_TRUE(IsSupportedMediaMimeType("video/webm")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/wav")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-wav")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/ogg")); EXPECT_TRUE(IsSupportedMediaMimeType("application/ogg")); #if defined(OS_ANDROID) EXPECT_FALSE(IsSupportedMediaMimeType("video/ogg")); #else EXPECT_TRUE(IsSupportedMediaMimeType("video/ogg")); #endif // OS_ANDROID #if defined(OS_ANDROID) // HLS is supported on Android API level 14 and higher and Chrome supports // API levels 15 and higher, so these are expected to be supported. bool kHlsSupported = true; #else bool kHlsSupported = false; #endif EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType("application/x-mpegurl")); EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType("Application/X-MPEGURL")); EXPECT_EQ(kHlsSupported, IsSupportedMediaMimeType( "application/vnd.apple.mpegurl")); #if defined(USE_PROPRIETARY_CODECS) EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp4")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-m4a")); EXPECT_TRUE(IsSupportedMediaMimeType("video/mp4")); EXPECT_TRUE(IsSupportedMediaMimeType("video/x-m4v")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/mp3")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/x-mp3")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/mpeg")); EXPECT_TRUE(IsSupportedMediaMimeType("audio/aac")); #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER) EXPECT_TRUE(IsSupportedMediaMimeType("video/mp2t")); #else EXPECT_FALSE(IsSupportedMediaMimeType("video/mp2t")); #endif #else EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp4")); EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-m4a")); EXPECT_FALSE(IsSupportedMediaMimeType("video/mp4")); EXPECT_FALSE(IsSupportedMediaMimeType("video/x-m4v")); EXPECT_FALSE(IsSupportedMediaMimeType("audio/mp3")); EXPECT_FALSE(IsSupportedMediaMimeType("audio/x-mp3")); EXPECT_FALSE(IsSupportedMediaMimeType("audio/mpeg")); EXPECT_FALSE(IsSupportedMediaMimeType("audio/aac")); #endif // USE_PROPRIETARY_CODECS EXPECT_FALSE(IsSupportedMediaMimeType("video/mp3")); EXPECT_FALSE(IsSupportedMediaMimeType("video/unknown")); EXPECT_FALSE(IsSupportedMediaMimeType("audio/unknown")); EXPECT_FALSE(IsSupportedMediaMimeType("unknown/unknown")); } // Note: codecs should only be a list of 2 or fewer; hence the restriction of // results' length to 2. TEST(MimeUtilTest, ParseCodecString) { const struct { const char* const original; size_t expected_size; const char* const results[2]; } tests[] = { { "\"bogus\"", 1, { "bogus" } }, { "0", 1, { "0" } }, { "avc1.42E01E, mp4a.40.2", 2, { "avc1", "mp4a" } }, { "\"mp4v.20.240, mp4a.40.2\"", 2, { "mp4v", "mp4a" } }, { "mp4v.20.8, samr", 2, { "mp4v", "samr" } }, { "\"theora, vorbis\"", 2, { "theora", "vorbis" } }, { "", 0, { } }, { "\"\"", 0, { } }, { "\" \"", 0, { } }, { ",", 2, { "", "" } }, }; for (size_t i = 0; i < arraysize(tests); ++i) { std::vector codecs_out; ParseCodecString(tests[i].original, &codecs_out, true); ASSERT_EQ(tests[i].expected_size, codecs_out.size()); for (size_t j = 0; j < tests[i].expected_size; ++j) EXPECT_EQ(tests[i].results[j], codecs_out[j]); } // Test without stripping the codec type. std::vector codecs_out; ParseCodecString("avc1.42E01E, mp4a.40.2", &codecs_out, false); ASSERT_EQ(2u, codecs_out.size()); EXPECT_EQ("avc1.42E01E", codecs_out[0]); EXPECT_EQ("mp4a.40.2", codecs_out[1]); } TEST(IsCodecSupportedOnPlatformTest, EncryptedCodecsFailWithoutPlatformSupport) { // Vary all parameters except |has_platform_decoders|. MimeUtil::PlatformInfo states_to_vary = VaryAllFields(); states_to_vary.has_platform_decoders = false; // Disable platform decoders. MimeUtil::PlatformInfo test_states; test_states.has_platform_decoders = false; // Every codec should fail since platform support is missing and we've // requested encrypted codecs. RunCodecSupportTest( states_to_vary, test_states, [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) { EXPECT_FALSE(MimeUtil::IsCodecSupportedOnPlatform(codec, kTestMimeType, true, info)); }); } TEST(IsCodecSupportedOnPlatformTest, EncryptedCodecBehavior) { // Vary all parameters except |has_platform_decoders|. MimeUtil::PlatformInfo states_to_vary = VaryAllFields(); states_to_vary.has_platform_decoders = false; // Enable platform decoders. MimeUtil::PlatformInfo test_states; test_states.has_platform_decoders = true; RunCodecSupportTest( states_to_vary, test_states, [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) { const bool result = MimeUtil::IsCodecSupportedOnPlatform( codec, kTestMimeType, true, info); switch (codec) { // These codecs are never supported by the Android platform. case MimeUtil::INVALID_CODEC: case MimeUtil::AC3: case MimeUtil::EAC3: case MimeUtil::MPEG2_AAC: case MimeUtil::THEORA: EXPECT_FALSE(result); break; // These codecs are always available with platform decoder support. case MimeUtil::PCM: case MimeUtil::MP3: case MimeUtil::MPEG4_AAC: case MimeUtil::VORBIS: case MimeUtil::H264: EXPECT_TRUE(result); break; // The remaining codecs are not available on all platforms even when // a platform decoder is available. case MimeUtil::OPUS: EXPECT_EQ(info.supports_opus, result); break; case MimeUtil::VP8: EXPECT_EQ(info.has_platform_vp8_decoder, result); break; case MimeUtil::VP9: EXPECT_EQ(info.supports_vp9, result); break; case MimeUtil::HEVC_MAIN: EXPECT_EQ(HasHevcSupport(), result); break; } }); } TEST(IsCodecSupportedOnPlatformTest, ClearCodecBehaviorWithAndroidPipeline) { // Vary all parameters except |is_unified_media_pipeline_enabled|. MimeUtil::PlatformInfo states_to_vary = VaryAllFields(); states_to_vary.is_unified_media_pipeline_enabled = false; // Disable the unified pipeline. MimeUtil::PlatformInfo test_states; test_states.is_unified_media_pipeline_enabled = false; RunCodecSupportTest( states_to_vary, test_states, [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) { const bool result = MimeUtil::IsCodecSupportedOnPlatform( codec, kTestMimeType, false, info); switch (codec) { // These codecs are never supported by the Android platform. case MimeUtil::INVALID_CODEC: case MimeUtil::AC3: case MimeUtil::EAC3: case MimeUtil::MPEG2_AAC: case MimeUtil::THEORA: EXPECT_FALSE(result); break; // These codecs are always available via MediaPlayer. case MimeUtil::PCM: case MimeUtil::MP3: case MimeUtil::MPEG4_AAC: case MimeUtil::VORBIS: case MimeUtil::H264: case MimeUtil::VP8: EXPECT_TRUE(result); break; // The remaining codecs depend on the platform version. case MimeUtil::OPUS: EXPECT_EQ(info.supports_opus, result); break; case MimeUtil::VP9: EXPECT_EQ(info.supports_vp9, result); break; case MimeUtil::HEVC_MAIN: EXPECT_EQ(HasHevcSupport(), result); break; } }); } TEST(IsCodecSupportedOnPlatformTest, ClearCodecBehaviorWithUnifiedPipeline) { // Vary all parameters except |is_unified_media_pipeline_enabled|. MimeUtil::PlatformInfo states_to_vary = VaryAllFields(); states_to_vary.is_unified_media_pipeline_enabled = false; // Enable the unified pipeline. MimeUtil::PlatformInfo test_states; test_states.is_unified_media_pipeline_enabled = true; RunCodecSupportTest( states_to_vary, test_states, [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) { const bool result = MimeUtil::IsCodecSupportedOnPlatform( codec, kTestMimeType, false, info); switch (codec) { // These codecs are never supported by the Android platform. case MimeUtil::INVALID_CODEC: case MimeUtil::AC3: case MimeUtil::EAC3: case MimeUtil::THEORA: EXPECT_FALSE(result); break; // These codecs are always supported with the unified pipeline. case MimeUtil::PCM: case MimeUtil::MPEG2_AAC: case MimeUtil::MP3: case MimeUtil::MPEG4_AAC: case MimeUtil::OPUS: case MimeUtil::VORBIS: case MimeUtil::VP8: case MimeUtil::VP9: EXPECT_TRUE(result); break; // These codecs are only supported if platform decoders are supported. case MimeUtil::H264: EXPECT_EQ(info.has_platform_decoders, result); break; case MimeUtil::HEVC_MAIN: EXPECT_EQ(HasHevcSupport() && info.has_platform_decoders, result); break; } }); } TEST(IsCodecSupportedOnPlatformTest, OpusOggSupport) { // Vary all parameters; thus use default initial state. MimeUtil::PlatformInfo states_to_vary = VaryAllFields(); MimeUtil::PlatformInfo test_states; RunCodecSupportTest( states_to_vary, test_states, [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) { EXPECT_EQ(info.is_unified_media_pipeline_enabled, MimeUtil::IsCodecSupportedOnPlatform( MimeUtil::OPUS, "audio/ogg", false, info)); }); } } // namespace internal } // namespace media