content/media/wmf/WMFDecoder.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

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

mercurial