Commit 20645b6c authored by chcunningham's avatar chcunningham Committed by Commit bot

Wire up MediaCapabilities is_supported to media/

navigator.mediaCapabilities.decodingInfo(...) will now query
the media layer to parse the mime type and check platform support.

Some work remains to reject ambiguous mime strings. In some cases
we are also not deeply checking for platform support. Will get to
this soon.

BUG=695264
TEST=new browser tests

Review-Url: https://codereview.chromium.org/2805553004
Cr-Commit-Position: refs/heads/master@{#467184}
parent 7924a430
// Copyright 2014 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 <string>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "media/base/media_switches.h"
#include "media/base/test_data_util.h"
const char kDecodeTestFile[] = "decode_capabilities_test.html";
const char kSupported[] = "SUPPORTED";
const char kUnsupported[] = "UNSUPPORTED";
const char kError[] = "ERROR";
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
const char* kPropSupported = kSupported;
#else
const char* kPropSupported = kUnsupported;
#endif // USE_PROPRIETARY_CODECS
enum ConfigType { AUDIO, VIDEO };
namespace content {
class MediaCapabilitiesTest : public ContentBrowserTest {
public:
MediaCapabilitiesTest() = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
"MediaCapabilities");
command_line->AppendSwitch(switches::kEnableNewVp9CodecString);
command_line->AppendSwitch(switches::kEnableVp9InMp4);
}
std::string CanDecodeAudio(const std::string& content_type) {
return CanDecode(content_type, ConfigType::AUDIO);
}
std::string CanDecodeVideo(const std::string& content_type) {
return CanDecode(content_type, ConfigType::VIDEO);
}
std::string CanDecode(const std::string& content_type,
ConfigType configType) {
std::string command;
if (configType == ConfigType::AUDIO) {
command.append("testAudioDecodeContentType(");
} else {
command.append("testVideoDecodeContentType(");
}
command.append(content_type);
command.append(");");
EXPECT_TRUE(ExecuteScript(shell(), command));
TitleWatcher title_watcher(shell()->web_contents(),
base::ASCIIToUTF16(kSupported));
title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16(kUnsupported));
title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16(kError));
return base::UTF16ToASCII(title_watcher.WaitAndGetTitle());
}
private:
DISALLOW_COPY_AND_ASSIGN(MediaCapabilitiesTest);
};
// Cover basic codec support. See media_canplaytype_browsertest.cc for more
// exhaustive codec string testing.
IN_PROC_BROWSER_TEST_F(MediaCapabilitiesTest, VideoDecodeTypes) {
base::FilePath file_path = media::GetTestDataFilePath(kDecodeTestFile);
EXPECT_TRUE(
NavigateToURL(shell(), content::GetFileUrlWithQuery(file_path, "")));
EXPECT_EQ(kSupported, CanDecodeVideo("'video/webm; codecs=\"vp8\"'"));
// TODO(chcunningham): Drop support for the old VP9 string. Only support
// the new vp09 format which provides critical profile information.
EXPECT_EQ(kSupported, CanDecodeVideo("'video/webm; codecs=\"vp9\"'"));
// Requires command line flag switches::kEnableNewVp9CodecString
EXPECT_EQ(kSupported,
CanDecodeVideo("'video/webm; codecs=\"vp09.00.10.08\"'"));
// Supported when built with USE_PROPRIETARY_CODECS
EXPECT_EQ(kPropSupported,
CanDecodeVideo("'video/mp4; codecs=\"avc1.42E01E\"'"));
EXPECT_EQ(kPropSupported,
CanDecodeVideo("'video/mp4; codecs=\"avc1.42101E\"'"));
EXPECT_EQ(kPropSupported,
CanDecodeVideo("'video/mp4; codecs=\"avc1.42701E\"'"));
EXPECT_EQ(kPropSupported,
CanDecodeVideo("'video/mp4; codecs=\"avc1.42F01E\"'"));
// Requires command line flag switches::kEnableVp9InMp4
EXPECT_EQ(kPropSupported,
CanDecodeVideo("'video/mp4; codecs=\"vp09.00.10.08\"'"));
// Test a handful of invalid strings.
EXPECT_EQ(kUnsupported, CanDecodeVideo("'video/webm; codecs=\"theora\"'"));
EXPECT_EQ(kUnsupported,
CanDecodeVideo("'video/webm; codecs=\"avc1.42E01E\"'"));
// Only new vp09 format is supported with MP4.
EXPECT_EQ(kUnsupported, CanDecodeVideo("'video/mp4; codecs=\"vp9\"'"));
}
// Cover basic codec support. See media_canplaytype_browsertest.cc for more
// exhaustive codec string testing.
IN_PROC_BROWSER_TEST_F(MediaCapabilitiesTest, AudioDecodeTypes) {
base::FilePath file_path = media::GetTestDataFilePath(kDecodeTestFile);
EXPECT_TRUE(
NavigateToURL(shell(), content::GetFileUrlWithQuery(file_path, "")));
EXPECT_EQ(kSupported, CanDecodeAudio("'audio/ogg; codecs=\"flac\"'"));
EXPECT_EQ(kSupported, CanDecodeAudio("'audio/ogg; codecs=\"vorbis\"'"));
EXPECT_EQ(kSupported, CanDecodeAudio("'audio/ogg; codecs=\"opus\"'"));
EXPECT_EQ(kSupported, CanDecodeAudio("'audio/webm; codecs=\"opus\"'"));
EXPECT_EQ(kSupported, CanDecodeAudio("'audio/webm; codecs=\"vorbis\"'"));
EXPECT_EQ(kSupported, CanDecodeAudio("'audio/flac'"));
// Supported when built with USE_PROPRIETARY_CODECS
EXPECT_EQ(kPropSupported, CanDecodeAudio("'audio/mpeg; codecs=\"mp4a.69\"'"));
EXPECT_EQ(kPropSupported,
CanDecodeAudio("'audio/mp4; codecs=\"mp4a.40.02\"'"));
EXPECT_EQ(kPropSupported, CanDecodeAudio("'audio/aac'"));
// Test a handful of invalid strings.
EXPECT_EQ(kUnsupported, CanDecodeAudio("'audio/wav; codecs=\"mp3\"'"));
EXPECT_EQ(kUnsupported, CanDecodeAudio("'audio/webm; codecs=\"vp8\"'"));
}
} // namespace content
......@@ -292,33 +292,19 @@ void MediaRecorderHandler::EncodingInfo(
// TODO(mcasas): Support the case when both video and audio configurations are
// specified: https://crbug.com/709181.
std::string content_type;
if (configuration.video_configuration)
content_type = configuration.video_configuration->content_type.Ascii();
else
content_type = configuration.audio_configuration->content_type.Ascii();
// |content_type| should be of the form "bla;codecs=foo", where "bla" is the
// type and "codecs=foo" is the parameter ("foo" is the parameter value), see
// RFC 2231 [1]. CanSupportMimeType() operates on type and parameter value.
// [1] https://tools.ietf.org/html/rfc2231
base::StringTokenizer mime_tokenizer(content_type, ";");
blink::WebString web_type;
blink::WebString web_codecs;
if (mime_tokenizer.GetNext())
web_type = blink::WebString::FromASCII(mime_tokenizer.token());
if (mime_tokenizer.GetNext()) {
const std::string parameters = mime_tokenizer.token();
base::StringTokenizer parameter_tokenizer(parameters, "=");
if (parameter_tokenizer.GetNext() &&
base::ToLowerASCII(parameter_tokenizer.token()) == "codecs" &&
parameter_tokenizer.GetNext()) {
web_codecs = blink::WebString::FromASCII(parameter_tokenizer.token());
}
blink::WebString mime_type;
blink::WebString codec;
if (configuration.video_configuration) {
mime_type = configuration.video_configuration->mime_type;
codec = configuration.video_configuration->codec;
} else {
mime_type = configuration.audio_configuration->mime_type;
codec = configuration.audio_configuration->codec;
}
info->supported = CanSupportMimeType(web_type, web_codecs);
DVLOG(1) << "type: " << web_type.Ascii() << ", params:" << web_codecs.Ascii()
// See RFC 2231. https://tools.ietf.org/html/rfc2231
info->supported = CanSupportMimeType(mime_type, codec);
DVLOG(1) << "type: " << mime_type.Ascii() << ", codec:" << codec.Ascii()
<< " is" << (info->supported ? " supported" : " NOT supported");
scoped_callbacks.PassCallbacks()->OnSuccess(std::move(info));
......
......@@ -636,6 +636,7 @@ test("content_browsertests") {
"../browser/media/media_browsertest.cc",
"../browser/media/media_browsertest.h",
"../browser/media/media_canplaytype_browsertest.cc",
"../browser/media/media_capabilities_browsertest.cc",
"../browser/media/media_color_browsertest.cc",
"../browser/media/media_redirect_browsertest.cc",
"../browser/media/media_source_browsertest.cc",
......
......@@ -415,8 +415,10 @@ SupportsType MimeUtil::IsSupportedMediaFormat(
const std::string mime_type_lower_case = base::ToLowerASCII(mime_type);
MediaFormatMappings::const_iterator it_media_format_map =
media_format_map_.find(mime_type_lower_case);
if (it_media_format_map == media_format_map_.end())
if (it_media_format_map == media_format_map_.end()) {
DVLOG(3) << __func__ << " Unrecognized mime type: " << mime_type;
return IsNotSupported;
}
if (it_media_format_map->second.empty()) {
// We get here if the mimetype does not expect a codecs parameter.
......
......@@ -4,7 +4,11 @@
#include "media/blink/webmediacapabilitiesclient_impl.h"
#include "media/base/mime_util.h"
#include "third_party/WebKit/public/platform/modules/media_capabilities/WebAudioConfiguration.h"
#include "third_party/WebKit/public/platform/modules/media_capabilities/WebMediaCapabilitiesInfo.h"
#include "third_party/WebKit/public/platform/modules/media_capabilities/WebMediaConfiguration.h"
#include "third_party/WebKit/public/platform/modules/media_capabilities/WebVideoConfiguration.h"
namespace media {
......@@ -15,13 +19,53 @@ WebMediaCapabilitiesClientImpl::~WebMediaCapabilitiesClientImpl() = default;
void WebMediaCapabilitiesClientImpl::DecodingInfo(
const blink::WebMediaConfiguration& configuration,
std::unique_ptr<blink::WebMediaCapabilitiesQueryCallbacks> callbacks) {
// TODO(chcunningham, mlamouri): this is a dummy implementation that returns
// true for all the fields.
std::unique_ptr<blink::WebMediaCapabilitiesInfo> info(
new blink::WebMediaCapabilitiesInfo());
info->supported = true;
info->smooth = true;
info->power_efficient = true;
SupportsType audio_support = IsSupported;
SupportsType video_support = IsSupported;
if (configuration.audio_configuration) {
const blink::WebAudioConfiguration& audio_config =
configuration.audio_configuration.value();
std::vector<std::string> codec_vector;
SplitCodecsToVector(audio_config.codec.Ascii(), &codec_vector, false);
// TODO(chcunningham): Update to throw exception pending outcome of
// https://github.com/WICG/media-capabilities/issues/32
DCHECK_LE(codec_vector.size(), 1U);
audio_support =
IsSupportedMediaFormat(audio_config.mime_type.Ascii(), codec_vector);
}
if (configuration.video_configuration) {
const blink::WebVideoConfiguration& video_config =
configuration.video_configuration.value();
std::vector<std::string> codec_vector;
SplitCodecsToVector(video_config.codec.Ascii(), &codec_vector, false);
// TODO(chcunningham): Update to throw exception pending outcome of
// https://github.com/WICG/media-capabilities/issues/32
DCHECK_LE(codec_vector.size(), 1U);
video_support =
IsSupportedMediaFormat(video_config.mime_type.Ascii(), codec_vector);
}
// TODO(chcunningham): API should never have to mask uncertainty. Log a metric
// for any content type that is "maybe" supported.
if (video_support == MayBeSupported)
video_support = IsSupported;
if (audio_support == MayBeSupported)
audio_support = IsSupported;
info->supported =
audio_support == IsSupported && video_support == IsSupported;
// TODO(chcunningham, mlamouri): real implementation for these.
info->smooth = info->power_efficient = info->supported;
callbacks->OnSuccess(std::move(info));
}
......
<!DOCTYPE html>
<title>Decode Capabilities Test</title>
<div id="console"></div>
<script type='text/javascript'>
function log(message) {
let consoleElement = document.getElementById('console');
let entry = document.createElement('div');
entry.appendChild(document.createTextNode(message));
consoleElement.appendChild(entry);
console.log(message);
}
function runTest(configuration) {
try {
navigator.mediaCapabilities.decodingInfo(configuration)
.then((result) => {
log('Decoding is '
+ (result.supported ? '' : 'un') + 'supported');
document.title = result.supported ? 'SUPPORTED' : 'UNSUPPORTED';
})
.catch((e) => {
log('Promise rejected: ' + e);
document.title = "ERROR";
});
} catch (e) {
log('Exception:' + e);
document.title = "ERROR";
}
}
function testVideoDecodeContentType(contentType) {
// Clear previous test result from title.
document.title = '';
log("Testing video content type: " + contentType);
const configuration = {
// TODO(chcunningham): Add tests for type: "media-source".
type : 'file',
video : {
contentType : contentType,
// Any reasonable value will do.
width : 640,
height : 480,
bitrate : 10000,
framerate : 30
}
};
runTest(configuration);
}
function testAudioDecodeContentType(contentType) {
// Clear previous test result from title.
document.title = '';
log("Testing audio content type: " + contentType);
const configuration = {
// TODO(chcunningham): Add tests for type: "media-source".
type : 'file',
audio : {
contentType : contentType
}
};
runTest(configuration);
}
</script>
......@@ -13,6 +13,7 @@
#include "modules/media_capabilities/MediaConfiguration.h"
#include "modules/media_capabilities/MediaDecodingConfiguration.h"
#include "modules/media_capabilities/MediaEncodingConfiguration.h"
#include "platform/network/ParsedContentType.h"
#include "public/platform/Platform.h"
#include "public/platform/WebMediaRecorderHandler.h"
#include "public/platform/modules/media_capabilities/WebMediaCapabilitiesClient.h"
......@@ -29,7 +30,15 @@ WebAudioConfiguration ToWebAudioConfiguration(
// |contentType| is mandatory.
DCHECK(configuration.hasContentType());
web_configuration.content_type = configuration.contentType();
ParsedContentType parsed_content_type(configuration.contentType(),
ParsedContentType::Mode::kStrict);
// TODO(chcunningham): Throw TypeError for invalid input.
// DCHECK(parsed_content_type.IsValid());
DEFINE_STATIC_LOCAL(const String, codecs, ("codecs"));
web_configuration.mime_type = parsed_content_type.MimeType().LowerASCII();
web_configuration.codec = parsed_content_type.ParameterValueForName(codecs);
// |channels| is optional and will be set to a null WebString if not present.
web_configuration.channels = configuration.hasChannels()
......@@ -51,7 +60,15 @@ WebVideoConfiguration ToWebVideoConfiguration(
// All the properties are mandatory.
DCHECK(configuration.hasContentType());
web_configuration.content_type = configuration.contentType();
ParsedContentType parsed_content_type(configuration.contentType(),
ParsedContentType::Mode::kStrict);
// TODO(chcunningham): Throw TypeError for invalid input.
// DCHECK(parsed_content_type.IsValid());
DEFINE_STATIC_LOCAL(const String, codecs, ("codecs"));
web_configuration.mime_type = parsed_content_type.MimeType().LowerASCII();
web_configuration.codec = parsed_content_type.ParameterValueForName(codecs);
DCHECK(configuration.hasWidth());
web_configuration.width = configuration.width();
......
......@@ -14,7 +14,8 @@ namespace blink {
// It is created by Blink and passed to consumers that can assume that all
// required fields are properly set.
struct WebAudioConfiguration {
WebString content_type;
WebString mime_type;
WebString codec;
// `channels` is Optional too but it will be reflected with `isNull()`.
WebString channels;
......
......@@ -13,7 +13,8 @@ namespace blink {
// It is created by Blink and passed to consumers that can assume that all
// required fields are properly set.
struct WebVideoConfiguration {
WebString content_type;
WebString mime_type;
WebString codec;
unsigned width;
unsigned height;
unsigned bitrate;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment