1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/wmf/WMFDecoder.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,163 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "WMF.h" 1.11 +#include "WMFDecoder.h" 1.12 +#include "WMFReader.h" 1.13 +#include "WMFUtils.h" 1.14 +#include "MediaDecoderStateMachine.h" 1.15 +#include "mozilla/Preferences.h" 1.16 +#include "mozilla/WindowsVersion.h" 1.17 +#include "nsCharSeparatedTokenizer.h" 1.18 + 1.19 +#ifdef MOZ_DIRECTSHOW 1.20 +#include "DirectShowDecoder.h" 1.21 +#endif 1.22 + 1.23 +namespace mozilla { 1.24 + 1.25 +MediaDecoderStateMachine* WMFDecoder::CreateStateMachine() 1.26 +{ 1.27 + return new MediaDecoderStateMachine(this, new WMFReader(this)); 1.28 +} 1.29 + 1.30 +/* static */ 1.31 +bool 1.32 +WMFDecoder::IsMP3Supported() 1.33 +{ 1.34 + MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); 1.35 + if (!MediaDecoder::IsWMFEnabled()) { 1.36 + return false; 1.37 + } 1.38 + // MP3 works fine in WMF on Windows Vista and Windows 8. 1.39 + if (!IsWin7OrLater()) { 1.40 + return true; 1.41 + } 1.42 + // MP3 support is disabled if we're on Windows 7 and no service packs are 1.43 + // installed, since it's crashy. Win7 with service packs is not so crashy, 1.44 + // so we enable it there. Note we prefer DirectShow for MP3 playback, but 1.45 + // we still support MP3 in MP4 via WMF, or MP3 in WMF if DirectShow is 1.46 + // disabled. 1.47 + return IsWin7SP1OrLater(); 1.48 +} 1.49 + 1.50 +static bool 1.51 +IsSupportedH264Codec(const nsAString& aCodec) 1.52 +{ 1.53 + // According to the WMF documentation: 1.54 + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx 1.55 + // "The Media Foundation H.264 video decoder is a Media Foundation Transform 1.56 + // that supports decoding of Baseline, Main, and High profiles, up to level 1.57 + // 5.1.". We also report that we can play Extended profile, as there are 1.58 + // bitstreams that are Extended compliant that are also Baseline compliant. 1.59 + 1.60 + // H.264 codecs parameters have a type defined as avc1.PPCCLL, where 1.61 + // PP = profile_idc, CC = constraint_set flags, LL = level_idc. 1.62 + // We ignore the constraint_set flags, as it's not clear from the WMF 1.63 + // documentation what constraints the WMF H.264 decoder supports. 1.64 + // See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html 1.65 + // for more details. 1.66 + if (aCodec.Length() != strlen("avc1.PPCCLL")) { 1.67 + return false; 1.68 + } 1.69 + 1.70 + // Verify the codec starts with "avc1.". 1.71 + const nsAString& sample = Substring(aCodec, 0, 5); 1.72 + if (!sample.EqualsASCII("avc1.")) { 1.73 + return false; 1.74 + } 1.75 + 1.76 + // Extract the profile_idc and level_idc. Note: the constraint_set flags 1.77 + // are ignored, it's not clear from the WMF documentation if they make a 1.78 + // difference. 1.79 + nsresult rv = NS_OK; 1.80 + const int32_t profile = PromiseFlatString(Substring(aCodec, 5, 2)).ToInteger(&rv, 16); 1.81 + NS_ENSURE_SUCCESS(rv, false); 1.82 + 1.83 + const int32_t level = PromiseFlatString(Substring(aCodec, 9, 2)).ToInteger(&rv, 16); 1.84 + NS_ENSURE_SUCCESS(rv, false); 1.85 + 1.86 + return level >= eAVEncH264VLevel1 && 1.87 + level <= eAVEncH264VLevel5_1 && 1.88 + (profile == eAVEncH264VProfile_Base || 1.89 + profile == eAVEncH264VProfile_Main || 1.90 + profile == eAVEncH264VProfile_Extended || 1.91 + profile == eAVEncH264VProfile_High); 1.92 +} 1.93 + 1.94 +bool 1.95 +WMFDecoder::CanPlayType(const nsACString& aType, 1.96 + const nsAString& aCodecs) 1.97 +{ 1.98 + if (!MediaDecoder::IsWMFEnabled() || 1.99 + NS_FAILED(LoadDLLs())) { 1.100 + return false; 1.101 + } 1.102 + 1.103 + // Assume that if LoadDLLs() didn't fail, we can playback the types that 1.104 + // we know should be supported by Windows Media Foundation. 1.105 + if ((aType.EqualsASCII("audio/mpeg") || aType.EqualsASCII("audio/mp3")) && 1.106 + IsMP3Supported()) { 1.107 + // Note: We block MP3 playback on Window 7 SP0 since it seems to crash 1.108 + // in some circumstances. 1.109 + return !aCodecs.Length() || aCodecs.EqualsASCII("mp3"); 1.110 + } 1.111 + 1.112 + // AAC-LC or MP3 in M4A. 1.113 + if (aType.EqualsASCII("audio/mp4") || aType.EqualsASCII("audio/x-m4a")) { 1.114 + return !aCodecs.Length() || 1.115 + aCodecs.EqualsASCII("mp4a.40.2") || 1.116 + aCodecs.EqualsASCII("mp3"); 1.117 + } 1.118 + 1.119 + if (!aType.EqualsASCII("video/mp4")) { 1.120 + return false; 1.121 + } 1.122 + 1.123 + // H.264 + AAC in MP4. Verify that all the codecs specifed are ones that 1.124 + // we expect that we can play. 1.125 + nsCharSeparatedTokenizer tokenizer(aCodecs, ','); 1.126 + bool expectMoreTokens = false; 1.127 + while (tokenizer.hasMoreTokens()) { 1.128 + const nsSubstring& token = tokenizer.nextToken(); 1.129 + expectMoreTokens = tokenizer.separatorAfterCurrentToken(); 1.130 + if (token.EqualsASCII("mp4a.40.2") || // AAC-LC 1.131 + token.EqualsASCII("mp3") || 1.132 + IsSupportedH264Codec(token)) { 1.133 + continue; 1.134 + } 1.135 + return false; 1.136 + } 1.137 + if (expectMoreTokens) { 1.138 + // Last codec name was empty 1.139 + return false; 1.140 + } 1.141 + return true; 1.142 +} 1.143 + 1.144 +nsresult 1.145 +WMFDecoder::LoadDLLs() 1.146 +{ 1.147 + return SUCCEEDED(wmf::LoadDLLs()) ? NS_OK : NS_ERROR_FAILURE; 1.148 +} 1.149 + 1.150 +void 1.151 +WMFDecoder::UnloadDLLs() 1.152 +{ 1.153 + wmf::UnloadDLLs(); 1.154 +} 1.155 + 1.156 +/* static */ 1.157 +bool 1.158 +WMFDecoder::IsEnabled() 1.159 +{ 1.160 + // We only use WMF on Windows Vista and up 1.161 + return IsVistaOrLater() && 1.162 + Preferences::GetBool("media.windows-media-foundation.enabled"); 1.163 +} 1.164 + 1.165 +} // namespace mozilla 1.166 +