blob: ca4a8433f99d8795c80cc652c3500cf951ac1aa1 [file] [log] [blame]
// Copyright (c) 2013 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 <tuple>
#include "base/command_line.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/browser/media/media_browsertest.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "media/base/media.h"
#include "media/base/media_switches.h"
#include "media/base/test_data_util.h"
#include "media/media_buildflags.h"
#include "media/mojo/buildflags.h"
#if defined(OS_ANDROID)
#include "base/android/build_info.h"
#endif
#if defined(OS_WIN)
#include "base/win/windows_version.h"
#endif
#if BUILDFLAG(ENABLE_MOJO_CDM) && !BUILDFLAG(ENABLE_LIBRARY_CDMS)
// When mojo CDM is enabled, External Clear Key is supported in //content/shell/
// by using mojo CDM with AesDecryptor running in the remote (e.g. GPU or
// Browser) process. When pepper CDM is supported, External Clear Key is
// supported in chrome/, which is tested in browser_tests.
#define SUPPORTS_EXTERNAL_CLEAR_KEY_IN_CONTENT_SHELL
#endif
namespace content {
// Available key systems.
const char kClearKeyKeySystem[] = "org.w3.clearkey";
#if defined(SUPPORTS_EXTERNAL_CLEAR_KEY_IN_CONTENT_SHELL)
const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
#endif
// EME-specific test results and errors.
const char kEmeKeyError[] = "KEYERROR";
const char kEmeNotSupportedError[] = "NOTSUPPORTEDERROR";
const char kDefaultEmePlayer[] = "eme_player.html";
const char kDefaultMseOnlyEmePlayer[] = "mse_different_containers.html";
// The type of video src used to load media.
enum class SrcType { SRC, MSE };
// Must be in sync with CONFIG_CHANGE_TYPE in eme_player_js/global.js
enum class ConfigChangeType {
CLEAR_TO_CLEAR = 0,
CLEAR_TO_ENCRYPTED = 1,
ENCRYPTED_TO_CLEAR = 2,
ENCRYPTED_TO_ENCRYPTED = 3,
};
// Tests encrypted media playback with a combination of parameters:
// - char*: Key system name.
// - SrcType: The type of video src used to load media, MSE or SRC.
// It is okay to run this test as a non-parameterized test, in this case,
// GetParam() should not be called.
class EncryptedMediaTest
: public MediaBrowserTest,
public testing::WithParamInterface<std::tuple<const char*, SrcType>> {
public:
// Can only be used in parameterized (*_P) tests.
const std::string CurrentKeySystem() { return std::get<0>(GetParam()); }
// Can only be used in parameterized (*_P) tests.
SrcType CurrentSourceType() { return std::get<1>(GetParam()); }
void TestSimplePlayback(const std::string& encrypted_media) {
RunSimplePlaybackTest(encrypted_media, CurrentKeySystem(),
CurrentSourceType());
}
void TestFrameSizeChange() {
RunTest("encrypted_frame_size_change.html",
"frame_size_change-av_enc-v.webm", CurrentKeySystem(),
CurrentSourceType(), media::kEnded);
}
void TestConfigChange(ConfigChangeType config_change_type) {
// TODO(xhwang): Even when config change is not supported we still start
// content shell only to return directly here. We probably should not run
// these test cases at all.
if (CurrentSourceType() != SrcType::MSE) {
DVLOG(0) << "Config change only happens when using MSE.";
return;
}
base::StringPairs query_params;
query_params.emplace_back("keySystem", CurrentKeySystem());
query_params.emplace_back(
"configChangeType",
base::NumberToString(static_cast<int>(config_change_type)));
RunMediaTestPage("mse_config_change.html", query_params, media::kEnded,
true);
}
void RunTest(const std::string& html_page,
const std::string& media_file,
const std::string& key_system,
SrcType src_type,
const std::string& expectation) {
base::StringPairs query_params;
query_params.emplace_back("mediaFile", media_file);
query_params.emplace_back("mediaType",
media::GetMimeTypeForFile(media_file));
query_params.emplace_back("keySystem", key_system);
if (src_type == SrcType::MSE)
query_params.emplace_back("useMSE", "1");
RunMediaTestPage(html_page, query_params, expectation, true);
}
void RunSimplePlaybackTest(const std::string& media_file,
const std::string& key_system,
SrcType src_type) {
RunTest(kDefaultEmePlayer, media_file, key_system, src_type, media::kEnded);
}
void RunMultipleFileTest(const std::string& video_file,
const std::string& audio_file,
const std::string& expected_title) {
if (CurrentSourceType() != SrcType::MSE) {
DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
return;
}
base::StringPairs query_params;
query_params.emplace_back("keySystem", CurrentKeySystem());
query_params.emplace_back("runEncrypted", "1");
if (!video_file.empty()) {
query_params.emplace_back("videoFile", video_file);
query_params.emplace_back("videoFormat",
media::GetMimeTypeForFile(video_file));
}
if (!audio_file.empty()) {
query_params.emplace_back("audioFile", audio_file);
query_params.emplace_back("audioFormat",
media::GetMimeTypeForFile(audio_file));
}
RunMediaTestPage(kDefaultMseOnlyEmePlayer, query_params, expected_title,
true);
}
protected:
// We want to fail quickly when a test fails because an error is encountered.
void AddTitlesToAwait(content::TitleWatcher* title_watcher) override {
MediaBrowserTest::AddTitlesToAwait(title_watcher);
title_watcher->AlsoWaitForTitle(base::ASCIIToUTF16(kEmeNotSupportedError));
title_watcher->AlsoWaitForTitle(base::ASCIIToUTF16(kEmeKeyError));
}
void SetUpCommandLine(base::CommandLine* command_line) override {
MediaBrowserTest::SetUpCommandLine(command_line);
#if defined(SUPPORTS_EXTERNAL_CLEAR_KEY_IN_CONTENT_SHELL)
scoped_feature_list_.InitWithFeatures({media::kExternalClearKeyForTesting},
{});
#endif
}
base::test::ScopedFeatureList scoped_feature_list_;
};
using ::testing::Combine;
using ::testing::Values;
INSTANTIATE_TEST_SUITE_P(SRC_ClearKey,
EncryptedMediaTest,
Combine(Values(kClearKeyKeySystem),
Values(SrcType::SRC)));
INSTANTIATE_TEST_SUITE_P(MSE_ClearKey,
EncryptedMediaTest,
Combine(Values(kClearKeyKeySystem),
Values(SrcType::MSE)));
#if defined(SUPPORTS_EXTERNAL_CLEAR_KEY_IN_CONTENT_SHELL)
INSTANTIATE_TEST_SUITE_P(SRC_ExternalClearKey,
EncryptedMediaTest,
Combine(Values(kExternalClearKeyKeySystem),
Values(SrcType::SRC)));
INSTANTIATE_TEST_SUITE_P(MSE_ExternalClearKey,
EncryptedMediaTest,
Combine(Values(kExternalClearKeyKeySystem),
Values(SrcType::MSE)));
#endif
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM) {
TestSimplePlayback("bear-a_enc-a.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioClearVideo_WebM) {
TestSimplePlayback("bear-320x240-av_enc-a.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM) {
TestSimplePlayback("bear-320x240-av_enc-av.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM) {
TestSimplePlayback("bear-320x240-v_enc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_Fullsample) {
TestSimplePlayback("bear-320x240-v-vp9_fullsample_enc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_Subsample) {
TestSimplePlayback("bear-320x240-v-vp9_subsample_enc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
TestSimplePlayback("bear-320x240-av_enc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM_Opus) {
#if defined(OS_ANDROID)
if (!media::PlatformHasOpusSupport())
return;
#endif
TestSimplePlayback("bear-320x240-opus-a_enc-a.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM_Opus) {
#if defined(OS_ANDROID)
if (!media::PlatformHasOpusSupport())
return;
#endif
TestSimplePlayback("bear-320x240-opus-av_enc-av.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM_Opus) {
#if defined(OS_ANDROID)
if (!media::PlatformHasOpusSupport())
return;
#endif
TestSimplePlayback("bear-320x240-opus-av_enc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_MP4_FLAC) {
RunMultipleFileTest(std::string(), "bear-flac-cenc.mp4", media::kEnded);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4_VP9) {
// MP4 without MSE is not support yet, http://crbug.com/170793.
if (CurrentSourceType() != SrcType::MSE) {
DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
return;
}
TestSimplePlayback("bear-320x240-v_frag-vp9-cenc.mp4");
}
// TODO(crbug.com/707127): Decide when it's supported on Android.
#if !defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
Playback_VideoOnly_WebM_VP9Profile2) {
TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4_VP9Profile2) {
// MP4 without MSE is not support yet, http://crbug.com/170793.
if (CurrentSourceType() != SrcType::MSE) {
DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
return;
}
TestSimplePlayback("bear-320x240-v-vp9_profile2_subsample_cenc-v.mp4");
}
#endif // !defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_AV1_DECODER)
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_AV1) {
TestSimplePlayback("bear-av1-cenc.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM_AV1_10bit) {
TestSimplePlayback("bear-av1-320x180-10bit-cenc.webm");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4_AV1) {
// MP4 without MSE is not support yet, http://crbug.com/170793.
if (CurrentSourceType() != SrcType::MSE) {
DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
return;
}
TestSimplePlayback("bear-av1-cenc.mp4");
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4_AV1_10bit) {
// MP4 without MSE is not support yet, http://crbug.com/170793.
if (CurrentSourceType() != SrcType::MSE) {
DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
return;
}
TestSimplePlayback("bear-av1-320x180-10bit-cenc.mp4");
}
#endif // BUILDFLAG(ENABLE_AV1_DECODER)
// Strictly speaking this is not an "encrypted" media test. Keep it here for
// completeness.
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo_ClearToClear) {
TestConfigChange(ConfigChangeType::CLEAR_TO_CLEAR);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo_ClearToEncrypted) {
TestConfigChange(ConfigChangeType::CLEAR_TO_ENCRYPTED);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, ConfigChangeVideo_EncryptedToClear) {
TestConfigChange(ConfigChangeType::ENCRYPTED_TO_CLEAR);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
ConfigChangeVideo_EncryptedToEncrypted) {
TestConfigChange(ConfigChangeType::ENCRYPTED_TO_ENCRYPTED);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
#if defined(OS_ANDROID)
// https://crbug.com/778245
if (base::android::BuildInfo::GetInstance()->sdk_int() <
base::android::SDK_VERSION_MARSHMALLOW) {
DVLOG(0) << "Skipping test - FrameSizeChange is flaky on KitKat and "
"Lollipop devices.";
return;
}
#endif
TestFrameSizeChange();
}
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_Encryption_CENC) {
RunMultipleFileTest("bear-640x360-v_frag-cenc.mp4",
"bear-640x360-a_frag-cenc.mp4", media::kEnded);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_Encryption_CBC1) {
RunMultipleFileTest("bear-640x360-v_frag-cbc1.mp4", std::string(),
media::kError);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_Encryption_CENS) {
RunMultipleFileTest("bear-640x360-v_frag-cens.mp4", std::string(),
media::kError);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_Encryption_CBCS) {
std::string expected_result =
BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) ? media::kEnded : media::kError;
RunMultipleFileTest("bear-640x360-v_frag-cbcs.mp4",
"bear-640x360-a_frag-cbcs.mp4", expected_result);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
Playback_Encryption_CBCS_Video_CENC_Audio) {
std::string expected_result =
BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) ? media::kEnded : media::kError;
RunMultipleFileTest("bear-640x360-v_frag-cbcs.mp4",
"bear-640x360-a_frag-cenc.mp4", expected_result);
}
IN_PROC_BROWSER_TEST_P(EncryptedMediaTest,
Playback_Encryption_CENC_Video_CBCS_Audio) {
std::string expected_result =
BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) ? media::kEnded : media::kError;
RunMultipleFileTest("bear-640x360-v_frag-cenc.mp4",
"bear-640x360-a_frag-cbcs.mp4", expected_result);
}
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
IN_PROC_BROWSER_TEST_F(EncryptedMediaTest, UnknownKeySystemThrowsException) {
RunTest(kDefaultEmePlayer, "bear-a_enc-a.webm", "com.example.foo",
SrcType::MSE, kEmeNotSupportedError);
}
} // namespace content