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