content/media/DecoderTraits.cpp

branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
equal deleted inserted replaced
-1:000000000000 0:42497996c110
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "DecoderTraits.h"
8 #include "MediaDecoder.h"
9 #include "nsCharSeparatedTokenizer.h"
10 #include "mozilla/Preferences.h"
11
12 #ifdef MOZ_MEDIA_PLUGINS
13 #include "MediaPluginHost.h"
14 #endif
15
16 #include "OggDecoder.h"
17 #include "OggReader.h"
18 #ifdef MOZ_WAVE
19 #include "WaveDecoder.h"
20 #include "WaveReader.h"
21 #endif
22 #ifdef MOZ_WEBM
23 #include "WebMDecoder.h"
24 #include "WebMReader.h"
25 #endif
26 #ifdef MOZ_RAW
27 #include "RawDecoder.h"
28 #include "RawReader.h"
29 #endif
30 #ifdef MOZ_GSTREAMER
31 #include "GStreamerDecoder.h"
32 #include "GStreamerReader.h"
33 #endif
34 #ifdef MOZ_MEDIA_PLUGINS
35 #include "MediaPluginHost.h"
36 #include "MediaPluginDecoder.h"
37 #include "MediaPluginReader.h"
38 #include "MediaPluginHost.h"
39 #endif
40 #ifdef MOZ_OMX_DECODER
41 #include "MediaOmxDecoder.h"
42 #include "MediaOmxReader.h"
43 #include "nsIPrincipal.h"
44 #include "mozilla/dom/HTMLMediaElement.h"
45 #endif
46 #ifdef NECKO_PROTOCOL_rtsp
47 #include "RtspOmxDecoder.h"
48 #include "RtspOmxReader.h"
49 #endif
50 #ifdef MOZ_WMF
51 #include "WMFDecoder.h"
52 #include "WMFReader.h"
53 #endif
54 #ifdef MOZ_DIRECTSHOW
55 #include "DirectShowDecoder.h"
56 #include "DirectShowReader.h"
57 #endif
58 #ifdef MOZ_APPLEMEDIA
59 #include "AppleDecoder.h"
60 #include "AppleMP3Reader.h"
61 #endif
62 #ifdef MOZ_FMP4
63 #include "MP4Reader.h"
64 #include "MP4Decoder.h"
65 #endif
66
67 namespace mozilla
68 {
69
70 template <class String>
71 static bool
72 CodecListContains(char const *const * aCodecs, const String& aCodec)
73 {
74 for (int32_t i = 0; aCodecs[i]; ++i) {
75 if (aCodec.EqualsASCII(aCodecs[i]))
76 return true;
77 }
78 return false;
79 }
80
81 #ifdef MOZ_RAW
82 static const char* gRawTypes[3] = {
83 "video/x-raw",
84 "video/x-raw-yuv",
85 nullptr
86 };
87
88 static const char* gRawCodecs[1] = {
89 nullptr
90 };
91
92 static bool
93 IsRawType(const nsACString& aType)
94 {
95 if (!MediaDecoder::IsRawEnabled()) {
96 return false;
97 }
98
99 return CodecListContains(gRawTypes, aType);
100 }
101 #endif
102
103 // See http://www.rfc-editor.org/rfc/rfc5334.txt for the definitions
104 // of Ogg media types and codec types
105 static const char* const gOggTypes[4] = {
106 "video/ogg",
107 "audio/ogg",
108 "application/ogg",
109 nullptr
110 };
111
112 static char const *const gOggCodecs[3] = {
113 "vorbis",
114 "theora",
115 nullptr
116 };
117
118 static char const *const gOggCodecsWithOpus[4] = {
119 "vorbis",
120 "opus",
121 "theora",
122 nullptr
123 };
124
125 static bool
126 IsOggType(const nsACString& aType)
127 {
128 if (!MediaDecoder::IsOggEnabled()) {
129 return false;
130 }
131
132 return CodecListContains(gOggTypes, aType);
133 }
134
135 #ifdef MOZ_WAVE
136 // See http://www.rfc-editor.org/rfc/rfc2361.txt for the definitions
137 // of WAVE media types and codec types. However, the audio/vnd.wave
138 // MIME type described there is not used.
139 static const char* const gWaveTypes[5] = {
140 "audio/x-wav",
141 "audio/wav",
142 "audio/wave",
143 "audio/x-pn-wav",
144 nullptr
145 };
146
147 static char const *const gWaveCodecs[2] = {
148 "1", // Microsoft PCM Format
149 nullptr
150 };
151
152 static bool
153 IsWaveType(const nsACString& aType)
154 {
155 if (!MediaDecoder::IsWaveEnabled()) {
156 return false;
157 }
158
159 return CodecListContains(gWaveTypes, aType);
160 }
161 #endif
162
163 #ifdef MOZ_WEBM
164 static const char* const gWebMTypes[3] = {
165 "video/webm",
166 "audio/webm",
167 nullptr
168 };
169
170 static char const *const gWebMCodecs[7] = {
171 "vp8",
172 "vp8.0",
173 "vp9",
174 "vp9.0",
175 "vorbis",
176 "opus",
177 nullptr
178 };
179
180 static bool
181 IsWebMType(const nsACString& aType)
182 {
183 if (!MediaDecoder::IsWebMEnabled()) {
184 return false;
185 }
186
187 return CodecListContains(gWebMTypes, aType);
188 }
189 #endif
190
191 #ifdef MOZ_GSTREAMER
192 static bool
193 IsGStreamerSupportedType(const nsACString& aMimeType)
194 {
195 if (!MediaDecoder::IsGStreamerEnabled())
196 return false;
197
198 #ifdef MOZ_WEBM
199 if (IsWebMType(aMimeType) && !Preferences::GetBool("media.prefer-gstreamer", false))
200 return false;
201 #endif
202 if (IsOggType(aMimeType) && !Preferences::GetBool("media.prefer-gstreamer", false))
203 return false;
204
205 return GStreamerDecoder::CanHandleMediaType(aMimeType, nullptr);
206 }
207 #endif
208
209 #ifdef MOZ_OMX_DECODER
210 static const char* const gOmxTypes[7] = {
211 "audio/mpeg",
212 "audio/mp4",
213 "audio/amr",
214 "video/mp4",
215 "video/3gpp",
216 "video/quicktime",
217 nullptr
218 };
219
220 static bool
221 IsOmxSupportedType(const nsACString& aType)
222 {
223 if (!MediaDecoder::IsOmxEnabled()) {
224 return false;
225 }
226
227 return CodecListContains(gOmxTypes, aType);
228 }
229
230 static char const *const gH264Codecs[9] = {
231 "avc1.42E01E", // H.264 Constrained Baseline Profile Level 3.0
232 "avc1.42001E", // H.264 Baseline Profile Level 3.0
233 "avc1.58A01E", // H.264 Extended Profile Level 3.0
234 "avc1.4D401E", // H.264 Main Profile Level 3.0
235 "avc1.64001E", // H.264 High Profile Level 3.0
236 "avc1.64001F", // H.264 High Profile Level 3.1
237 "mp4v.20.3", // 3GPP
238 "mp4a.40.2", // AAC-LC
239 nullptr
240 };
241
242 static char const *const gMpegAudioCodecs[2] = {
243 "mp3", // MP3
244 nullptr
245 };
246 #endif
247
248 #ifdef NECKO_PROTOCOL_rtsp
249 static const char* const gRtspTypes[2] = {
250 "RTSP",
251 nullptr
252 };
253
254 static bool
255 IsRtspSupportedType(const nsACString& aMimeType)
256 {
257 return MediaDecoder::IsRtspEnabled() &&
258 CodecListContains(gRtspTypes, aMimeType);
259 }
260 #endif
261
262 /* static */
263 bool DecoderTraits::DecoderWaitsForOnConnected(const nsACString& aMimeType) {
264 #ifdef NECKO_PROTOCOL_rtsp
265 return CodecListContains(gRtspTypes, aMimeType);
266 #else
267 return false;
268 #endif
269 }
270
271 #ifdef MOZ_MEDIA_PLUGINS
272 static bool
273 IsMediaPluginsType(const nsACString& aType)
274 {
275 if (!MediaDecoder::IsMediaPluginsEnabled()) {
276 return false;
277 }
278
279 static const char* supportedTypes[] = {
280 "audio/mpeg", "audio/mp4", "video/mp4", nullptr
281 };
282 return CodecListContains(supportedTypes, aType);
283 }
284 #endif
285
286 #ifdef MOZ_WMF
287 static bool
288 IsWMFSupportedType(const nsACString& aType)
289 {
290 return WMFDecoder::CanPlayType(aType, NS_LITERAL_STRING(""));
291 }
292 #endif
293
294 #ifdef MOZ_DIRECTSHOW
295 static bool
296 IsDirectShowSupportedType(const nsACString& aType)
297 {
298 return DirectShowDecoder::GetSupportedCodecs(aType, nullptr);
299 }
300 #endif
301
302 #ifdef MOZ_FMP4
303 static bool
304 IsMP4SupportedType(const nsACString& aType)
305 {
306 return Preferences::GetBool("media.fragmented-mp4.exposed", false) &&
307 MP4Decoder::GetSupportedCodecs(aType, nullptr);
308 }
309 #endif
310
311 #ifdef MOZ_APPLEMEDIA
312 static const char * const gAppleMP3Types[] = {
313 "audio/mp3",
314 "audio/mpeg",
315 nullptr,
316 };
317
318 static const char * const gAppleMP3Codecs[] = {
319 "mp3",
320 nullptr
321 };
322
323 static bool
324 IsAppleMediaSupportedType(const nsACString& aType,
325 const char * const ** aCodecs = nullptr)
326 {
327 if (MediaDecoder::IsAppleMP3Enabled()
328 && CodecListContains(gAppleMP3Types, aType)) {
329
330 if (aCodecs) {
331 *aCodecs = gAppleMP3Codecs;
332 }
333
334 return true;
335 }
336
337 // TODO MP4
338
339 return false;
340 }
341 #endif
342
343 /* static */
344 bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType)
345 {
346 #ifdef MOZ_WAVE
347 if (IsWaveType(nsDependentCString(aMIMEType))) {
348 // We should not return true for Wave types, since there are some
349 // Wave codecs actually in use in the wild that we don't support, and
350 // we should allow those to be handled by plugins or helper apps.
351 // Furthermore people can play Wave files on most platforms by other
352 // means.
353 return false;
354 }
355 #endif
356 return CanHandleMediaType(aMIMEType, false, EmptyString()) != CANPLAY_NO;
357 }
358
359 /* static */
360 CanPlayStatus
361 DecoderTraits::CanHandleMediaType(const char* aMIMEType,
362 bool aHaveRequestedCodecs,
363 const nsAString& aRequestedCodecs)
364 {
365 char const* const* codecList = nullptr;
366 CanPlayStatus result = CANPLAY_NO;
367 #ifdef MOZ_RAW
368 if (IsRawType(nsDependentCString(aMIMEType))) {
369 codecList = gRawCodecs;
370 result = CANPLAY_MAYBE;
371 }
372 #endif
373 if (IsOggType(nsDependentCString(aMIMEType))) {
374 codecList = MediaDecoder::IsOpusEnabled() ? gOggCodecsWithOpus : gOggCodecs;
375 result = CANPLAY_MAYBE;
376 }
377 #ifdef MOZ_WAVE
378 if (IsWaveType(nsDependentCString(aMIMEType))) {
379 codecList = gWaveCodecs;
380 result = CANPLAY_MAYBE;
381 }
382 #endif
383 #ifdef MOZ_WEBM
384 if (IsWebMType(nsDependentCString(aMIMEType))) {
385 codecList = gWebMCodecs;
386 result = CANPLAY_MAYBE;
387 }
388 #endif
389 #ifdef MOZ_GSTREAMER
390 if (GStreamerDecoder::CanHandleMediaType(nsDependentCString(aMIMEType),
391 aHaveRequestedCodecs ? &aRequestedCodecs : nullptr)) {
392 if (aHaveRequestedCodecs)
393 return CANPLAY_YES;
394 return CANPLAY_MAYBE;
395 }
396 #endif
397 #ifdef MOZ_OMX_DECODER
398 if (IsOmxSupportedType(nsDependentCString(aMIMEType))) {
399 result = CANPLAY_MAYBE;
400 if (nsDependentCString(aMIMEType).EqualsASCII("audio/mpeg")) {
401 codecList = gMpegAudioCodecs;
402 } else {
403 codecList = gH264Codecs;
404 }
405 }
406 #endif
407 #ifdef MOZ_DIRECTSHOW
408 // Note: DirectShow should come before WMF, so that we prefer DirectShow's
409 // MP3 support over WMF's.
410 if (DirectShowDecoder::GetSupportedCodecs(nsDependentCString(aMIMEType), &codecList)) {
411 result = CANPLAY_MAYBE;
412 }
413 #endif
414 #ifdef MOZ_WMF
415 if (IsWMFSupportedType(nsDependentCString(aMIMEType))) {
416 if (!aHaveRequestedCodecs) {
417 return CANPLAY_MAYBE;
418 }
419 return WMFDecoder::CanPlayType(nsDependentCString(aMIMEType),
420 aRequestedCodecs)
421 ? CANPLAY_YES : CANPLAY_NO;
422 }
423 #endif
424 #ifdef MOZ_APPLEMEDIA
425 if (IsAppleMediaSupportedType(nsDependentCString(aMIMEType), &codecList)) {
426 result = CANPLAY_MAYBE;
427 }
428 #endif
429 #ifdef MOZ_MEDIA_PLUGINS
430 if (MediaDecoder::IsMediaPluginsEnabled() &&
431 GetMediaPluginHost()->FindDecoder(nsDependentCString(aMIMEType), &codecList))
432 result = CANPLAY_MAYBE;
433 #endif
434 #ifdef NECKO_PROTOCOL_rtsp
435 if (IsRtspSupportedType(nsDependentCString(aMIMEType))) {
436 result = CANPLAY_MAYBE;
437 }
438 #endif
439 if (result == CANPLAY_NO || !aHaveRequestedCodecs || !codecList) {
440 return result;
441 }
442
443 // See http://www.rfc-editor.org/rfc/rfc4281.txt for the description
444 // of the 'codecs' parameter
445 nsCharSeparatedTokenizer tokenizer(aRequestedCodecs, ',');
446 bool expectMoreTokens = false;
447 while (tokenizer.hasMoreTokens()) {
448 const nsSubstring& token = tokenizer.nextToken();
449
450 if (!CodecListContains(codecList, token)) {
451 // Totally unsupported codec
452 return CANPLAY_NO;
453 }
454 expectMoreTokens = tokenizer.separatorAfterCurrentToken();
455 }
456 if (expectMoreTokens) {
457 // Last codec name was empty
458 return CANPLAY_NO;
459 }
460 return CANPLAY_YES;
461 }
462
463 // Instantiates but does not initialize decoder.
464 static
465 already_AddRefed<MediaDecoder>
466 InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
467 {
468 nsRefPtr<MediaDecoder> decoder;
469
470 #ifdef MOZ_GSTREAMER
471 if (IsGStreamerSupportedType(aType)) {
472 decoder = new GStreamerDecoder();
473 return decoder.forget();
474 }
475 #endif
476 #ifdef MOZ_RAW
477 if (IsRawType(aType)) {
478 decoder = new RawDecoder();
479 return decoder.forget();
480 }
481 #endif
482 if (IsOggType(aType)) {
483 decoder = new OggDecoder();
484 return decoder.forget();
485 }
486 #ifdef MOZ_WAVE
487 if (IsWaveType(aType)) {
488 decoder = new WaveDecoder();
489 return decoder.forget();
490 }
491 #endif
492 #ifdef MOZ_OMX_DECODER
493 if (IsOmxSupportedType(aType)) {
494 // AMR audio is enabled for MMS, but we are discouraging Web and App
495 // developers from using AMR, thus we only allow AMR to be played on WebApps.
496 if (aType.EqualsASCII("audio/amr")) {
497 dom::HTMLMediaElement* element = aOwner->GetMediaElement();
498 if (!element) {
499 return nullptr;
500 }
501 nsIPrincipal* principal = element->NodePrincipal();
502 if (!principal) {
503 return nullptr;
504 }
505 if (principal->GetAppStatus() < nsIPrincipal::APP_STATUS_PRIVILEGED) {
506 return nullptr;
507 }
508 }
509 decoder = new MediaOmxDecoder();
510 return decoder.forget();
511 }
512 #endif
513 #ifdef NECKO_PROTOCOL_rtsp
514 if (IsRtspSupportedType(aType)) {
515 decoder = new RtspOmxDecoder();
516 return decoder.forget();
517 }
518 #endif
519 #ifdef MOZ_MEDIA_PLUGINS
520 if (MediaDecoder::IsMediaPluginsEnabled() &&
521 GetMediaPluginHost()->FindDecoder(aType, nullptr)) {
522 decoder = new MediaPluginDecoder(aType);
523 return decoder.forget();
524 }
525 #endif
526 #ifdef MOZ_WEBM
527 if (IsWebMType(aType)) {
528 decoder = new WebMDecoder();
529 return decoder.forget();
530 }
531 #endif
532 #ifdef MOZ_DIRECTSHOW
533 // Note: DirectShow should come before WMF, so that we prefer DirectShow's
534 // MP3 support over WMF's.
535 if (IsDirectShowSupportedType(aType)) {
536 decoder = new DirectShowDecoder();
537 return decoder.forget();
538 }
539 #endif
540 #ifdef MOZ_FMP4
541 if (IsMP4SupportedType(aType)) {
542 decoder = new MP4Decoder();
543 return decoder.forget();
544 }
545 #endif
546 #ifdef MOZ_WMF
547 if (IsWMFSupportedType(aType)) {
548 decoder = new WMFDecoder();
549 return decoder.forget();
550 }
551 #endif
552 #ifdef MOZ_APPLEMEDIA
553 if (IsAppleMediaSupportedType(aType)) {
554 decoder = new AppleDecoder();
555 return decoder.forget();
556 }
557 #endif
558
559 NS_ENSURE_TRUE(decoder != nullptr, nullptr);
560 NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
561 return nullptr;
562 }
563
564 /* static */
565 already_AddRefed<MediaDecoder>
566 DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
567 {
568 nsRefPtr<MediaDecoder> decoder(InstantiateDecoder(aType, aOwner));
569 NS_ENSURE_TRUE(decoder != nullptr, nullptr);
570 NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
571
572 return decoder.forget();
573 }
574
575 /* static */
576 MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, AbstractMediaDecoder* aDecoder)
577 {
578 MediaDecoderReader* decoderReader = nullptr;
579
580 #ifdef MOZ_GSTREAMER
581 if (IsGStreamerSupportedType(aType)) {
582 decoderReader = new GStreamerReader(aDecoder);
583 } else
584 #endif
585 #ifdef MOZ_RAW
586 if (IsRawType(aType)) {
587 decoderReader = new RawReader(aDecoder);
588 } else
589 #endif
590 if (IsOggType(aType)) {
591 decoderReader = new OggReader(aDecoder);
592 } else
593 #ifdef MOZ_WAVE
594 if (IsWaveType(aType)) {
595 decoderReader = new WaveReader(aDecoder);
596 } else
597 #endif
598 #ifdef MOZ_OMX_DECODER
599 if (IsOmxSupportedType(aType)) {
600 decoderReader = new MediaOmxReader(aDecoder);
601 } else
602 #endif
603 #ifdef MOZ_MEDIA_PLUGINS
604 if (MediaDecoder::IsMediaPluginsEnabled() &&
605 GetMediaPluginHost()->FindDecoder(aType, nullptr)) {
606 decoderReader = new MediaPluginReader(aDecoder, aType);
607 } else
608 #endif
609 #ifdef MOZ_WEBM
610 if (IsWebMType(aType)) {
611 decoderReader = new WebMReader(aDecoder);
612 } else
613 #endif
614 #ifdef MOZ_DIRECTSHOW
615 // Note: DirectShowReader is preferred for MP3, but if it's disabled we
616 // fallback to the WMFReader.
617 if (IsDirectShowSupportedType(aType)) {
618 decoderReader = new DirectShowReader(aDecoder);
619 } else
620 #endif
621 #ifdef MOZ_FMP4
622 if (IsMP4SupportedType(aType)) {
623 decoderReader = new MP4Reader(aDecoder);
624 } else
625 #endif
626 #ifdef MOZ_WMF
627 if (IsWMFSupportedType(aType)) {
628 decoderReader = new WMFReader(aDecoder);
629 } else
630 #endif
631 #ifdef MOZ_APPLEMEDIA
632 if (IsAppleMediaSupportedType(aType)) {
633 decoderReader = new AppleMP3Reader(aDecoder);
634 } else
635 #endif
636 if (false) {} // dummy if to take care of the dangling else
637
638 return decoderReader;
639 }
640
641 /* static */
642 bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
643 {
644 return
645 IsOggType(aType) ||
646 #ifdef MOZ_OMX_DECODER
647 // We support amr inside WebApps on firefoxOS but not in general web content.
648 // Ensure we dont create a VideoDocument when accessing amr URLs directly.
649 (IsOmxSupportedType(aType) && !aType.EqualsASCII("audio/amr")) ||
650 #endif
651 #ifdef MOZ_WEBM
652 IsWebMType(aType) ||
653 #endif
654 #ifdef MOZ_GSTREAMER
655 IsGStreamerSupportedType(aType) ||
656 #endif
657 #ifdef MOZ_MEDIA_PLUGINS
658 (MediaDecoder::IsMediaPluginsEnabled() && IsMediaPluginsType(aType)) ||
659 #endif
660 #ifdef MOZ_FMP4
661 IsMP4SupportedType(aType) ||
662 #endif
663 #ifdef MOZ_WMF
664 (IsWMFSupportedType(aType) &&
665 Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true)) ||
666 #endif
667 #ifdef MOZ_DIRECTSHOW
668 IsDirectShowSupportedType(aType) ||
669 #endif
670 #ifdef MOZ_APPLEMEDIA
671 IsAppleMediaSupportedType(aType) ||
672 #endif
673 #ifdef NECKO_PROTOCOL_rtsp
674 IsRtspSupportedType(aType) ||
675 #endif
676 false;
677 }
678
679 }

mercurial