content/media/DecoderTraits.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     7 #include "DecoderTraits.h"
     8 #include "MediaDecoder.h"
     9 #include "nsCharSeparatedTokenizer.h"
    10 #include "mozilla/Preferences.h"
    12 #ifdef MOZ_MEDIA_PLUGINS
    13 #include "MediaPluginHost.h"
    14 #endif
    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
    67 namespace mozilla
    68 {
    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 }
    81 #ifdef MOZ_RAW
    82 static const char* gRawTypes[3] = {
    83   "video/x-raw",
    84   "video/x-raw-yuv",
    85   nullptr
    86 };
    88 static const char* gRawCodecs[1] = {
    89   nullptr
    90 };
    92 static bool
    93 IsRawType(const nsACString& aType)
    94 {
    95   if (!MediaDecoder::IsRawEnabled()) {
    96     return false;
    97   }
    99   return CodecListContains(gRawTypes, aType);
   100 }
   101 #endif
   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 };
   112 static char const *const gOggCodecs[3] = {
   113   "vorbis",
   114   "theora",
   115   nullptr
   116 };
   118 static char const *const gOggCodecsWithOpus[4] = {
   119   "vorbis",
   120   "opus",
   121   "theora",
   122   nullptr
   123 };
   125 static bool
   126 IsOggType(const nsACString& aType)
   127 {
   128   if (!MediaDecoder::IsOggEnabled()) {
   129     return false;
   130   }
   132   return CodecListContains(gOggTypes, aType);
   133 }
   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 };
   147 static char const *const gWaveCodecs[2] = {
   148   "1", // Microsoft PCM Format
   149   nullptr
   150 };
   152 static bool
   153 IsWaveType(const nsACString& aType)
   154 {
   155   if (!MediaDecoder::IsWaveEnabled()) {
   156     return false;
   157   }
   159   return CodecListContains(gWaveTypes, aType);
   160 }
   161 #endif
   163 #ifdef MOZ_WEBM
   164 static const char* const gWebMTypes[3] = {
   165   "video/webm",
   166   "audio/webm",
   167   nullptr
   168 };
   170 static char const *const gWebMCodecs[7] = {
   171   "vp8",
   172   "vp8.0",
   173   "vp9",
   174   "vp9.0",
   175   "vorbis",
   176   "opus",
   177   nullptr
   178 };
   180 static bool
   181 IsWebMType(const nsACString& aType)
   182 {
   183   if (!MediaDecoder::IsWebMEnabled()) {
   184     return false;
   185   }
   187   return CodecListContains(gWebMTypes, aType);
   188 }
   189 #endif
   191 #ifdef MOZ_GSTREAMER
   192 static bool
   193 IsGStreamerSupportedType(const nsACString& aMimeType)
   194 {
   195   if (!MediaDecoder::IsGStreamerEnabled())
   196     return false;
   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;
   205   return GStreamerDecoder::CanHandleMediaType(aMimeType, nullptr);
   206 }
   207 #endif
   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 };
   220 static bool
   221 IsOmxSupportedType(const nsACString& aType)
   222 {
   223   if (!MediaDecoder::IsOmxEnabled()) {
   224     return false;
   225   }
   227   return CodecListContains(gOmxTypes, aType);
   228 }
   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 };
   242 static char const *const gMpegAudioCodecs[2] = {
   243   "mp3",          // MP3
   244   nullptr
   245 };
   246 #endif
   248 #ifdef NECKO_PROTOCOL_rtsp
   249 static const char* const gRtspTypes[2] = {
   250     "RTSP",
   251     nullptr
   252 };
   254 static bool
   255 IsRtspSupportedType(const nsACString& aMimeType)
   256 {
   257   return MediaDecoder::IsRtspEnabled() &&
   258     CodecListContains(gRtspTypes, aMimeType);
   259 }
   260 #endif
   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 }
   271 #ifdef MOZ_MEDIA_PLUGINS
   272 static bool
   273 IsMediaPluginsType(const nsACString& aType)
   274 {
   275   if (!MediaDecoder::IsMediaPluginsEnabled()) {
   276     return false;
   277   }
   279   static const char* supportedTypes[] = {
   280     "audio/mpeg", "audio/mp4", "video/mp4", nullptr
   281   };
   282   return CodecListContains(supportedTypes, aType);
   283 }
   284 #endif
   286 #ifdef MOZ_WMF
   287 static bool
   288 IsWMFSupportedType(const nsACString& aType)
   289 {
   290   return WMFDecoder::CanPlayType(aType, NS_LITERAL_STRING(""));
   291 }
   292 #endif
   294 #ifdef MOZ_DIRECTSHOW
   295 static bool
   296 IsDirectShowSupportedType(const nsACString& aType)
   297 {
   298   return DirectShowDecoder::GetSupportedCodecs(aType, nullptr);
   299 }
   300 #endif
   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
   311 #ifdef MOZ_APPLEMEDIA
   312 static const char * const gAppleMP3Types[] = {
   313   "audio/mp3",
   314   "audio/mpeg",
   315   nullptr,
   316 };
   318 static const char * const gAppleMP3Codecs[] = {
   319   "mp3",
   320   nullptr
   321 };
   323 static bool
   324 IsAppleMediaSupportedType(const nsACString& aType,
   325                      const char * const ** aCodecs = nullptr)
   326 {
   327   if (MediaDecoder::IsAppleMP3Enabled()
   328       && CodecListContains(gAppleMP3Types, aType)) {
   330     if (aCodecs) {
   331       *aCodecs = gAppleMP3Codecs;
   332     }
   334     return true;
   335   }
   337   // TODO MP4
   339   return false;
   340 }
   341 #endif
   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 }
   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   }
   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();
   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 }
   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;
   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
   559   NS_ENSURE_TRUE(decoder != nullptr, nullptr);
   560   NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
   561   return nullptr;
   562 }
   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);
   572   return decoder.forget();
   573 }
   575 /* static */
   576 MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, AbstractMediaDecoder* aDecoder)
   577 {
   578   MediaDecoderReader* decoderReader = nullptr;
   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
   638   return decoderReader;
   639 }
   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 }
   679 }

mercurial