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 |