diff -r 000000000000 -r 6474c204b198 content/media/wmf/WMFDecoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/media/wmf/WMFDecoder.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "WMF.h" +#include "WMFDecoder.h" +#include "WMFReader.h" +#include "WMFUtils.h" +#include "MediaDecoderStateMachine.h" +#include "mozilla/Preferences.h" +#include "mozilla/WindowsVersion.h" +#include "nsCharSeparatedTokenizer.h" + +#ifdef MOZ_DIRECTSHOW +#include "DirectShowDecoder.h" +#endif + +namespace mozilla { + +MediaDecoderStateMachine* WMFDecoder::CreateStateMachine() +{ + return new MediaDecoderStateMachine(this, new WMFReader(this)); +} + +/* static */ +bool +WMFDecoder::IsMP3Supported() +{ + MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); + if (!MediaDecoder::IsWMFEnabled()) { + return false; + } + // MP3 works fine in WMF on Windows Vista and Windows 8. + if (!IsWin7OrLater()) { + return true; + } + // MP3 support is disabled if we're on Windows 7 and no service packs are + // installed, since it's crashy. Win7 with service packs is not so crashy, + // so we enable it there. Note we prefer DirectShow for MP3 playback, but + // we still support MP3 in MP4 via WMF, or MP3 in WMF if DirectShow is + // disabled. + return IsWin7SP1OrLater(); +} + +static bool +IsSupportedH264Codec(const nsAString& aCodec) +{ + // According to the WMF documentation: + // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx + // "The Media Foundation H.264 video decoder is a Media Foundation Transform + // that supports decoding of Baseline, Main, and High profiles, up to level + // 5.1.". We also report that we can play Extended profile, as there are + // bitstreams that are Extended compliant that are also Baseline compliant. + + // H.264 codecs parameters have a type defined as avc1.PPCCLL, where + // PP = profile_idc, CC = constraint_set flags, LL = level_idc. + // We ignore the constraint_set flags, as it's not clear from the WMF + // documentation what constraints the WMF H.264 decoder supports. + // See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html + // for more details. + if (aCodec.Length() != strlen("avc1.PPCCLL")) { + return false; + } + + // Verify the codec starts with "avc1.". + const nsAString& sample = Substring(aCodec, 0, 5); + if (!sample.EqualsASCII("avc1.")) { + return false; + } + + // Extract the profile_idc and level_idc. Note: the constraint_set flags + // are ignored, it's not clear from the WMF documentation if they make a + // difference. + nsresult rv = NS_OK; + const int32_t profile = PromiseFlatString(Substring(aCodec, 5, 2)).ToInteger(&rv, 16); + NS_ENSURE_SUCCESS(rv, false); + + const int32_t level = PromiseFlatString(Substring(aCodec, 9, 2)).ToInteger(&rv, 16); + NS_ENSURE_SUCCESS(rv, false); + + return level >= eAVEncH264VLevel1 && + level <= eAVEncH264VLevel5_1 && + (profile == eAVEncH264VProfile_Base || + profile == eAVEncH264VProfile_Main || + profile == eAVEncH264VProfile_Extended || + profile == eAVEncH264VProfile_High); +} + +bool +WMFDecoder::CanPlayType(const nsACString& aType, + const nsAString& aCodecs) +{ + if (!MediaDecoder::IsWMFEnabled() || + NS_FAILED(LoadDLLs())) { + return false; + } + + // Assume that if LoadDLLs() didn't fail, we can playback the types that + // we know should be supported by Windows Media Foundation. + if ((aType.EqualsASCII("audio/mpeg") || aType.EqualsASCII("audio/mp3")) && + IsMP3Supported()) { + // Note: We block MP3 playback on Window 7 SP0 since it seems to crash + // in some circumstances. + return !aCodecs.Length() || aCodecs.EqualsASCII("mp3"); + } + + // AAC-LC or MP3 in M4A. + if (aType.EqualsASCII("audio/mp4") || aType.EqualsASCII("audio/x-m4a")) { + return !aCodecs.Length() || + aCodecs.EqualsASCII("mp4a.40.2") || + aCodecs.EqualsASCII("mp3"); + } + + if (!aType.EqualsASCII("video/mp4")) { + return false; + } + + // H.264 + AAC in MP4. Verify that all the codecs specifed are ones that + // we expect that we can play. + nsCharSeparatedTokenizer tokenizer(aCodecs, ','); + bool expectMoreTokens = false; + while (tokenizer.hasMoreTokens()) { + const nsSubstring& token = tokenizer.nextToken(); + expectMoreTokens = tokenizer.separatorAfterCurrentToken(); + if (token.EqualsASCII("mp4a.40.2") || // AAC-LC + token.EqualsASCII("mp3") || + IsSupportedH264Codec(token)) { + continue; + } + return false; + } + if (expectMoreTokens) { + // Last codec name was empty + return false; + } + return true; +} + +nsresult +WMFDecoder::LoadDLLs() +{ + return SUCCEEDED(wmf::LoadDLLs()) ? NS_OK : NS_ERROR_FAILURE; +} + +void +WMFDecoder::UnloadDLLs() +{ + wmf::UnloadDLLs(); +} + +/* static */ +bool +WMFDecoder::IsEnabled() +{ + // We only use WMF on Windows Vista and up + return IsVistaOrLater() && + Preferences::GetBool("media.windows-media-foundation.enabled"); +} + +} // namespace mozilla +