Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "modules/media_capabilities/MediaCapabilities.h" | 5 #include "modules/media_capabilities/MediaCapabilities.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/CallbackPromiseAdapter.h" | 7 #include "bindings/core/v8/CallbackPromiseAdapter.h" |
| 8 #include "bindings/core/v8/ScriptPromise.h" | 8 #include "bindings/core/v8/ScriptPromise.h" |
| 9 #include "bindings/core/v8/ScriptPromiseResolver.h" | 9 #include "bindings/core/v8/ScriptPromiseResolver.h" |
| 10 #include "core/dom/DOMException.h" | 10 #include "core/dom/DOMException.h" |
| 11 #include "modules/media_capabilities/MediaCapabilitiesInfo.h" | 11 #include "modules/media_capabilities/MediaCapabilitiesInfo.h" |
| 12 #include "modules/media_capabilities/MediaConfiguration.h" | 12 #include "modules/media_capabilities/MediaConfiguration.h" |
| 13 #include "modules/media_capabilities/MediaDecodingConfiguration.h" | 13 #include "modules/media_capabilities/MediaDecodingConfiguration.h" |
| 14 #include "modules/media_capabilities/MediaEncodingConfiguration.h" | 14 #include "modules/media_capabilities/MediaEncodingConfiguration.h" |
| 15 #include "platform/bindings/ScriptState.h" | 15 #include "platform/bindings/ScriptState.h" |
| 16 #include "platform/network/ParsedContentType.h" | 16 #include "platform/network/ParsedContentType.h" |
| 17 #include "public/platform/Platform.h" | 17 #include "public/platform/Platform.h" |
| 18 #include "public/platform/WebMediaRecorderHandler.h" | 18 #include "public/platform/WebMediaRecorderHandler.h" |
| 19 #include "public/platform/modules/media_capabilities/WebMediaCapabilitiesClient. h" | 19 #include "public/platform/modules/media_capabilities/WebMediaCapabilitiesClient. h" |
| 20 #include "public/platform/modules/media_capabilities/WebMediaCapabilitiesInfo.h" | 20 #include "public/platform/modules/media_capabilities/WebMediaCapabilitiesInfo.h" |
| 21 #include "public/platform/modules/media_capabilities/WebMediaConfiguration.h" | 21 #include "public/platform/modules/media_capabilities/WebMediaConfiguration.h" |
| 22 | 22 |
| 23 namespace blink { | 23 namespace blink { |
| 24 | 24 |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 constexpr const char* kAudioMimeTypePrefix = "audio/"; | |
| 28 constexpr const char* kVideoMimeTypePrefix = "video/"; | |
|
chcunningham
2017/05/10 21:10:13
we may need to add in the HLS prefix "application/
mlamouri (slow - plz ping)
2017/05/11 10:41:23
That means we should update the specification, rig
| |
| 29 constexpr const char* kCodecsMimeTypeParam = "codecs"; | |
| 30 | |
| 31 bool IsValidMimeType(const String& content_type, const String& prefix) { | |
| 32 ParsedContentType parsed_content_type(content_type, | |
| 33 ParsedContentType::Mode::kStrict); | |
| 34 if (!parsed_content_type.IsValid()) | |
| 35 return false; | |
| 36 | |
| 37 if (!parsed_content_type.MimeType().StartsWith(prefix)) | |
| 38 return false; | |
| 39 | |
| 40 if (parsed_content_type.ParameterCount() > 1) | |
| 41 return false; | |
| 42 | |
| 43 if (parsed_content_type.ParameterCount() == 1 && | |
| 44 parsed_content_type.ParameterValueForName(kCodecsMimeTypeParam) | |
| 45 .IsNull()) { | |
| 46 return false; | |
| 47 } | |
| 48 | |
| 49 return true; | |
| 50 } | |
| 51 | |
| 52 bool IsValidMediaConfiguration(const MediaConfiguration& configuration) { | |
| 53 return configuration.hasAudio() || configuration.hasVideo(); | |
| 54 } | |
| 55 | |
| 56 bool IsValidVideoConfiguration(const VideoConfiguration& configuration) { | |
| 57 DCHECK(configuration.hasContentType()); | |
| 58 | |
| 59 if (!IsValidMimeType(configuration.contentType(), kVideoMimeTypePrefix)) | |
| 60 return false; | |
| 61 | |
| 62 DCHECK(configuration.hasFramerate()); | |
| 63 if (!std::isfinite(configuration.framerate()) || | |
| 64 configuration.framerate() <= 0) { | |
| 65 return false; | |
| 66 } | |
| 67 | |
| 68 return true; | |
| 69 } | |
| 70 | |
| 71 bool IsValidAudioConfiguration(const AudioConfiguration& configuration) { | |
| 72 DCHECK(configuration.hasContentType()); | |
| 73 | |
| 74 if (!IsValidMimeType(configuration.contentType(), kAudioMimeTypePrefix)) | |
| 75 return false; | |
| 76 | |
| 77 return true; | |
| 78 } | |
| 79 | |
| 27 WebAudioConfiguration ToWebAudioConfiguration( | 80 WebAudioConfiguration ToWebAudioConfiguration( |
| 28 const AudioConfiguration& configuration) { | 81 const AudioConfiguration& configuration) { |
| 29 WebAudioConfiguration web_configuration; | 82 WebAudioConfiguration web_configuration; |
| 30 | 83 |
| 31 // |contentType| is mandatory. | 84 // |contentType| is mandatory. |
| 32 DCHECK(configuration.hasContentType()); | 85 DCHECK(configuration.hasContentType()); |
| 33 ParsedContentType parsed_content_type(configuration.contentType(), | 86 ParsedContentType parsed_content_type(configuration.contentType(), |
| 34 ParsedContentType::Mode::kStrict); | 87 ParsedContentType::Mode::kStrict); |
| 35 | 88 DCHECK(parsed_content_type.IsValid()); |
| 36 // TODO(chcunningham): Throw TypeError for invalid input. | |
| 37 // DCHECK(parsed_content_type.IsValid()); | |
| 38 | 89 |
| 39 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); | 90 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); |
| 40 web_configuration.mime_type = parsed_content_type.MimeType().LowerASCII(); | 91 web_configuration.mime_type = parsed_content_type.MimeType().LowerASCII(); |
| 41 web_configuration.codec = parsed_content_type.ParameterValueForName(codecs); | 92 web_configuration.codec = parsed_content_type.ParameterValueForName(codecs); |
| 42 | 93 |
| 43 // |channels| is optional and will be set to a null WebString if not present. | 94 // |channels| is optional and will be set to a null WebString if not present. |
| 44 web_configuration.channels = configuration.hasChannels() | 95 web_configuration.channels = configuration.hasChannels() |
| 45 ? WebString(configuration.channels()) | 96 ? WebString(configuration.channels()) |
| 46 : WebString(); | 97 : WebString(); |
| 47 | 98 |
| 48 if (configuration.hasBitrate()) | 99 if (configuration.hasBitrate()) |
| 49 web_configuration.bitrate = configuration.bitrate(); | 100 web_configuration.bitrate = configuration.bitrate(); |
| 50 | 101 |
| 51 if (configuration.hasSamplerate()) | 102 if (configuration.hasSamplerate()) |
| 52 web_configuration.samplerate = configuration.samplerate(); | 103 web_configuration.samplerate = configuration.samplerate(); |
| 53 | 104 |
| 54 return web_configuration; | 105 return web_configuration; |
| 55 } | 106 } |
| 56 | 107 |
| 57 WebVideoConfiguration ToWebVideoConfiguration( | 108 WebVideoConfiguration ToWebVideoConfiguration( |
| 58 const VideoConfiguration& configuration) { | 109 const VideoConfiguration& configuration) { |
| 59 WebVideoConfiguration web_configuration; | 110 WebVideoConfiguration web_configuration; |
| 60 | 111 |
| 61 // All the properties are mandatory. | 112 // All the properties are mandatory. |
| 62 DCHECK(configuration.hasContentType()); | 113 DCHECK(configuration.hasContentType()); |
| 63 ParsedContentType parsed_content_type(configuration.contentType(), | 114 ParsedContentType parsed_content_type(configuration.contentType(), |
| 64 ParsedContentType::Mode::kStrict); | 115 ParsedContentType::Mode::kStrict); |
| 65 | 116 DCHECK(parsed_content_type.IsValid()); |
| 66 // TODO(chcunningham): Throw TypeError for invalid input. | |
| 67 // DCHECK(parsed_content_type.IsValid()); | |
| 68 | 117 |
| 69 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); | 118 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); |
| 70 web_configuration.mime_type = parsed_content_type.MimeType().LowerASCII(); | 119 web_configuration.mime_type = parsed_content_type.MimeType().LowerASCII(); |
| 71 web_configuration.codec = parsed_content_type.ParameterValueForName(codecs); | 120 web_configuration.codec = parsed_content_type.ParameterValueForName(codecs); |
| 72 | 121 |
| 73 DCHECK(configuration.hasWidth()); | 122 DCHECK(configuration.hasWidth()); |
| 74 web_configuration.width = configuration.width(); | 123 web_configuration.width = configuration.width(); |
| 75 | 124 |
| 76 DCHECK(configuration.hasHeight()); | 125 DCHECK(configuration.hasHeight()); |
| 77 web_configuration.height = configuration.height(); | 126 web_configuration.height = configuration.height(); |
| 78 | 127 |
| 79 DCHECK(configuration.hasBitrate()); | 128 DCHECK(configuration.hasBitrate()); |
| 80 web_configuration.bitrate = configuration.bitrate(); | 129 web_configuration.bitrate = configuration.bitrate(); |
| 81 | 130 |
| 82 DCHECK(configuration.hasFramerate()); | 131 DCHECK(configuration.hasFramerate()); |
| 83 web_configuration.framerate = configuration.framerate(); | 132 web_configuration.framerate = configuration.framerate(); |
| 84 | 133 |
| 85 return web_configuration; | 134 return web_configuration; |
| 86 } | 135 } |
| 87 | 136 |
| 88 WebMediaConfiguration ToWebMediaConfiguration( | 137 WebMediaConfiguration ToWebMediaConfiguration( |
| 89 const MediaConfiguration& configuration) { | 138 const MediaDecodingConfiguration& configuration) { |
| 90 WebMediaConfiguration web_configuration; | 139 WebMediaConfiguration web_configuration; |
| 91 | 140 |
| 141 // |type| is mandatory. | |
| 142 DCHECK(configuration.hasType()); | |
| 143 if (configuration.type() == "file") | |
| 144 web_configuration.type = MediaConfigurationType::kFile; | |
| 145 else if (configuration.type() == "media-source") | |
| 146 web_configuration.type = MediaConfigurationType::kMediaSource; | |
| 147 else | |
| 148 NOTREACHED(); | |
| 149 | |
| 92 if (configuration.hasAudio()) { | 150 if (configuration.hasAudio()) { |
| 93 web_configuration.audio_configuration = | 151 web_configuration.audio_configuration = |
| 94 ToWebAudioConfiguration(configuration.audio()); | 152 ToWebAudioConfiguration(configuration.audio()); |
| 153 } | |
| 154 | |
| 155 if (configuration.hasVideo()) { | |
| 156 web_configuration.video_configuration = | |
| 157 ToWebVideoConfiguration(configuration.video()); | |
| 158 } | |
| 159 | |
| 160 return web_configuration; | |
| 161 } | |
| 162 | |
| 163 WebMediaConfiguration ToWebMediaConfiguration( | |
| 164 const MediaEncodingConfiguration& configuration) { | |
| 165 WebMediaConfiguration web_configuration; | |
| 166 | |
| 167 // TODO(mcasas): parse and set the type for encoding. | |
| 168 | |
| 169 if (configuration.hasAudio()) { | |
| 170 web_configuration.audio_configuration = | |
| 171 ToWebAudioConfiguration(configuration.audio()); | |
| 95 } | 172 } |
| 96 | 173 |
| 97 if (configuration.hasVideo()) { | 174 if (configuration.hasVideo()) { |
| 98 web_configuration.video_configuration = | 175 web_configuration.video_configuration = |
| 99 ToWebVideoConfiguration(configuration.video()); | 176 ToWebVideoConfiguration(configuration.video()); |
| 100 } | 177 } |
| 101 | 178 |
| 102 return web_configuration; | 179 return web_configuration; |
| 103 } | 180 } |
| 104 | 181 |
| 105 } // anonymous namespace | 182 } // anonymous namespace |
| 106 | 183 |
| 107 MediaCapabilities::MediaCapabilities() = default; | 184 MediaCapabilities::MediaCapabilities() = default; |
| 108 | 185 |
| 109 ScriptPromise MediaCapabilities::decodingInfo( | 186 ScriptPromise MediaCapabilities::decodingInfo( |
| 110 ScriptState* script_state, | 187 ScriptState* script_state, |
| 111 const MediaDecodingConfiguration& configuration) { | 188 const MediaDecodingConfiguration& configuration) { |
| 112 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); | 189 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); |
| 113 ScriptPromise promise = resolver->Promise(); | 190 ScriptPromise promise = resolver->Promise(); |
| 114 | 191 |
| 115 // |type| is mandatory. | 192 if (!IsValidMediaConfiguration(configuration)) { |
| 116 DCHECK(configuration.hasType()); | 193 resolver->Reject(V8ThrowException::CreateTypeError( |
| 194 script_state->GetIsolate(), | |
| 195 "The configuration dictionary has neither |video| nor |audio| " | |
| 196 "specified and needs at least one of them.")); | |
| 197 return promise; | |
| 198 } | |
| 199 | |
| 200 if (configuration.hasVideo() && | |
| 201 !IsValidVideoConfiguration(configuration.video())) { | |
| 202 resolver->Reject(V8ThrowException::CreateTypeError( | |
| 203 script_state->GetIsolate(), | |
| 204 "The video configuration dictionary is not valid.")); | |
| 205 return promise; | |
| 206 } | |
| 207 | |
| 208 if (configuration.hasAudio() && | |
| 209 !IsValidAudioConfiguration(configuration.audio())) { | |
| 210 resolver->Reject(V8ThrowException::CreateTypeError( | |
| 211 script_state->GetIsolate(), | |
| 212 "The audio configuration dictionary is not valid.")); | |
| 213 return promise; | |
| 214 } | |
| 117 | 215 |
| 118 Platform::Current()->MediaCapabilitiesClient()->DecodingInfo( | 216 Platform::Current()->MediaCapabilitiesClient()->DecodingInfo( |
| 119 ToWebMediaConfiguration(configuration), | 217 ToWebMediaConfiguration(configuration), |
| 120 WTF::MakeUnique<CallbackPromiseAdapter<MediaCapabilitiesInfo, void>>( | 218 WTF::MakeUnique<CallbackPromiseAdapter<MediaCapabilitiesInfo, void>>( |
| 121 resolver)); | 219 resolver)); |
| 122 | 220 |
| 123 return promise; | 221 return promise; |
| 124 } | 222 } |
| 125 | 223 |
| 126 ScriptPromise MediaCapabilities::encodingInfo( | 224 ScriptPromise MediaCapabilities::encodingInfo( |
| 127 ScriptState* script_state, | 225 ScriptState* script_state, |
| 128 const MediaEncodingConfiguration& configuration) { | 226 const MediaEncodingConfiguration& configuration) { |
| 129 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); | 227 ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); |
| 130 ScriptPromise promise = resolver->Promise(); | 228 ScriptPromise promise = resolver->Promise(); |
| 131 | 229 |
| 132 if (!configuration.hasVideo() && !configuration.hasAudio()) { | 230 if (!IsValidMediaConfiguration(configuration)) { |
| 133 resolver->Reject(DOMException::Create( | 231 resolver->Reject(V8ThrowException::CreateTypeError( |
| 134 kSyntaxError, | 232 script_state->GetIsolate(), |
| 135 "The configuration dictionary has neither |video| nor |audio| " | 233 "The configuration dictionary has neither |video| nor |audio| " |
| 136 "specified and needs at least one of them.")); | 234 "specified and needs at least one of them.")); |
| 137 return promise; | 235 return promise; |
| 138 } | 236 } |
| 139 | 237 |
| 238 if (configuration.hasVideo() && | |
| 239 !IsValidVideoConfiguration(configuration.video())) { | |
| 240 resolver->Reject(V8ThrowException::CreateTypeError( | |
| 241 script_state->GetIsolate(), | |
| 242 "The video configuration dictionary is not valid.")); | |
| 243 return promise; | |
| 244 } | |
| 245 | |
| 246 if (configuration.hasAudio() && | |
| 247 !IsValidAudioConfiguration(configuration.audio())) { | |
| 248 resolver->Reject(V8ThrowException::CreateTypeError( | |
| 249 script_state->GetIsolate(), | |
| 250 "The audio configuration dictionary is not valid.")); | |
| 251 return promise; | |
| 252 } | |
| 253 | |
| 140 std::unique_ptr<WebMediaRecorderHandler> handler = | 254 std::unique_ptr<WebMediaRecorderHandler> handler = |
| 141 Platform::Current()->CreateMediaRecorderHandler(); | 255 Platform::Current()->CreateMediaRecorderHandler(); |
| 142 if (!handler) { | 256 if (!handler) { |
| 143 resolver->Reject(DOMException::Create( | 257 resolver->Reject(DOMException::Create( |
| 144 kInvalidStateError, | 258 kInvalidStateError, |
| 145 "Platform error: could not create MediaRecorderHandler.")); | 259 "Platform error: could not create MediaRecorderHandler.")); |
| 146 return promise; | 260 return promise; |
| 147 } | 261 } |
| 148 | 262 |
| 149 handler->EncodingInfo( | 263 handler->EncodingInfo( |
| 150 ToWebMediaConfiguration(configuration), | 264 ToWebMediaConfiguration(configuration), |
| 151 WTF::MakeUnique<CallbackPromiseAdapter<MediaCapabilitiesInfo, void>>( | 265 WTF::MakeUnique<CallbackPromiseAdapter<MediaCapabilitiesInfo, void>>( |
| 152 resolver)); | 266 resolver)); |
| 153 return promise; | 267 return promise; |
| 154 } | 268 } |
| 155 | 269 |
| 156 DEFINE_TRACE(MediaCapabilities) {} | 270 DEFINE_TRACE(MediaCapabilities) {} |
| 157 | 271 |
| 158 } // namespace blink | 272 } // namespace blink |
| OLD | NEW |