content/media/wmf/WMFDecoder.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

     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 "WMF.h"
     8 #include "WMFDecoder.h"
     9 #include "WMFReader.h"
    10 #include "WMFUtils.h"
    11 #include "MediaDecoderStateMachine.h"
    12 #include "mozilla/Preferences.h"
    13 #include "mozilla/WindowsVersion.h"
    14 #include "nsCharSeparatedTokenizer.h"
    16 #ifdef MOZ_DIRECTSHOW
    17 #include "DirectShowDecoder.h"
    18 #endif
    20 namespace mozilla {
    22 MediaDecoderStateMachine* WMFDecoder::CreateStateMachine()
    23 {
    24   return new MediaDecoderStateMachine(this, new WMFReader(this));
    25 }
    27 /* static */
    28 bool
    29 WMFDecoder::IsMP3Supported()
    30 {
    31   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
    32   if (!MediaDecoder::IsWMFEnabled()) {
    33     return false;
    34   }
    35   // MP3 works fine in WMF on Windows Vista and Windows 8.
    36   if (!IsWin7OrLater()) {
    37     return true;
    38   }
    39   // MP3 support is disabled if we're on Windows 7 and no service packs are
    40   // installed, since it's crashy. Win7 with service packs is not so crashy,
    41   // so we enable it there. Note we prefer DirectShow for MP3 playback, but
    42   // we still support MP3 in MP4 via WMF, or MP3 in WMF if DirectShow is
    43   // disabled.
    44   return IsWin7SP1OrLater();
    45 }
    47 static bool
    48 IsSupportedH264Codec(const nsAString& aCodec)
    49 {
    50   // According to the WMF documentation:
    51   // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx
    52   // "The Media Foundation H.264 video decoder is a Media Foundation Transform
    53   // that supports decoding of Baseline, Main, and High profiles, up to level
    54   // 5.1.". We also report that we can play Extended profile, as there are
    55   // bitstreams that are Extended compliant that are also Baseline compliant.
    57   // H.264 codecs parameters have a type defined as avc1.PPCCLL, where
    58   // PP = profile_idc, CC = constraint_set flags, LL = level_idc.
    59   // We ignore the constraint_set flags, as it's not clear from the WMF
    60   // documentation what constraints the WMF H.264 decoder supports.
    61   // See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html
    62   // for more details.
    63   if (aCodec.Length() != strlen("avc1.PPCCLL")) {
    64     return false;
    65   }
    67   // Verify the codec starts with "avc1.".
    68   const nsAString& sample = Substring(aCodec, 0, 5);
    69   if (!sample.EqualsASCII("avc1.")) {
    70     return false;
    71   }
    73   // Extract the profile_idc and level_idc. Note: the constraint_set flags
    74   // are ignored, it's not clear from the WMF documentation if they make a
    75   // difference.
    76   nsresult rv = NS_OK;
    77   const int32_t profile = PromiseFlatString(Substring(aCodec, 5, 2)).ToInteger(&rv, 16);
    78   NS_ENSURE_SUCCESS(rv, false);
    80   const int32_t level = PromiseFlatString(Substring(aCodec, 9, 2)).ToInteger(&rv, 16);
    81   NS_ENSURE_SUCCESS(rv, false);
    83   return level >= eAVEncH264VLevel1 &&
    84          level <= eAVEncH264VLevel5_1 &&
    85          (profile == eAVEncH264VProfile_Base ||
    86           profile == eAVEncH264VProfile_Main ||
    87           profile == eAVEncH264VProfile_Extended ||
    88           profile == eAVEncH264VProfile_High);
    89 }
    91 bool
    92 WMFDecoder::CanPlayType(const nsACString& aType,
    93                         const nsAString& aCodecs)
    94 {
    95   if (!MediaDecoder::IsWMFEnabled() ||
    96       NS_FAILED(LoadDLLs())) {
    97     return false;
    98   }
   100   // Assume that if LoadDLLs() didn't fail, we can playback the types that
   101   // we know should be supported by Windows Media Foundation.
   102   if ((aType.EqualsASCII("audio/mpeg") || aType.EqualsASCII("audio/mp3")) &&
   103       IsMP3Supported()) {
   104     // Note: We block MP3 playback on Window 7 SP0 since it seems to crash
   105     // in some circumstances.
   106     return !aCodecs.Length() || aCodecs.EqualsASCII("mp3");
   107   }
   109   // AAC-LC or MP3 in M4A.
   110   if (aType.EqualsASCII("audio/mp4") || aType.EqualsASCII("audio/x-m4a")) {
   111     return !aCodecs.Length() ||
   112            aCodecs.EqualsASCII("mp4a.40.2") ||
   113            aCodecs.EqualsASCII("mp3");
   114   }
   116   if (!aType.EqualsASCII("video/mp4")) {
   117     return false;
   118   }
   120   // H.264 + AAC in MP4. Verify that all the codecs specifed are ones that
   121   // we expect that we can play.
   122   nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
   123   bool expectMoreTokens = false;
   124   while (tokenizer.hasMoreTokens()) {
   125     const nsSubstring& token = tokenizer.nextToken();
   126     expectMoreTokens = tokenizer.separatorAfterCurrentToken();
   127     if (token.EqualsASCII("mp4a.40.2") || // AAC-LC
   128         token.EqualsASCII("mp3") ||
   129         IsSupportedH264Codec(token)) {
   130       continue;
   131     }
   132     return false;
   133   }
   134   if (expectMoreTokens) {
   135     // Last codec name was empty
   136     return false;
   137   }
   138   return true;
   139 }
   141 nsresult
   142 WMFDecoder::LoadDLLs()
   143 {
   144   return SUCCEEDED(wmf::LoadDLLs()) ? NS_OK : NS_ERROR_FAILURE;
   145 }
   147 void
   148 WMFDecoder::UnloadDLLs()
   149 {
   150   wmf::UnloadDLLs();
   151 }
   153 /* static */
   154 bool
   155 WMFDecoder::IsEnabled()
   156 {
   157   // We only use WMF on Windows Vista and up
   158   return IsVistaOrLater() &&
   159          Preferences::GetBool("media.windows-media-foundation.enabled");
   160 }
   162 } // namespace mozilla

mercurial