Bug 1772053 - Enable dynamic code disable mitigations only on Windows 10 1703+ r...
[gecko.git] / dom / media / DecoderTraits.cpp
blobad64dca729c9616e2ffa15fec2aa0d85d291cfb6
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 "MediaContainerType.h"
9 #include "mozilla/Preferences.h"
11 #include "OggDecoder.h"
12 #include "OggDemuxer.h"
14 #include "WebMDecoder.h"
15 #include "WebMDemuxer.h"
17 #ifdef MOZ_ANDROID_HLS_SUPPORT
18 # include "HLSDecoder.h"
19 #endif
20 #ifdef MOZ_FMP4
21 # include "MP4Decoder.h"
22 # include "MP4Demuxer.h"
23 #endif
24 #include "MediaFormatReader.h"
26 #include "MP3Decoder.h"
27 #include "MP3Demuxer.h"
29 #include "WaveDecoder.h"
30 #include "WaveDemuxer.h"
32 #include "ADTSDecoder.h"
33 #include "ADTSDemuxer.h"
35 #include "FlacDecoder.h"
36 #include "FlacDemuxer.h"
38 #include "nsPluginHost.h"
40 namespace mozilla {
42 /* static */
43 bool DecoderTraits::IsHttpLiveStreamingType(const MediaContainerType& aType) {
44 const auto& mimeType = aType.Type();
45 return // For m3u8.
46 // https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-10
47 mimeType == MEDIAMIMETYPE("application/vnd.apple.mpegurl") ||
48 // Some sites serve these as the informal m3u type.
49 mimeType == MEDIAMIMETYPE("application/x-mpegurl") ||
50 mimeType == MEDIAMIMETYPE("audio/mpegurl") ||
51 mimeType == MEDIAMIMETYPE("audio/x-mpegurl");
54 /* static */
55 bool DecoderTraits::IsMatroskaType(const MediaContainerType& aType) {
56 const auto& mimeType = aType.Type();
57 // https://matroska.org/technical/specs/notes.html
58 return mimeType == MEDIAMIMETYPE("audio/x-matroska") ||
59 mimeType == MEDIAMIMETYPE("video/x-matroska");
62 /* static */
63 bool DecoderTraits::IsMP4SupportedType(const MediaContainerType& aType,
64 DecoderDoctorDiagnostics* aDiagnostics) {
65 #ifdef MOZ_FMP4
66 return MP4Decoder::IsSupportedType(aType, aDiagnostics);
67 #else
68 return false;
69 #endif
72 static CanPlayStatus CanHandleCodecsType(
73 const MediaContainerType& aType, DecoderDoctorDiagnostics* aDiagnostics) {
74 // We should have been given a codecs string, though it may be empty.
75 MOZ_ASSERT(aType.ExtendedType().HaveCodecs());
77 // Container type with the MIME type, no codecs.
78 const MediaContainerType mimeType(aType.Type());
80 if (OggDecoder::IsSupportedType(mimeType)) {
81 if (OggDecoder::IsSupportedType(aType)) {
82 return CANPLAY_YES;
84 // We can only reach this position if a particular codec was requested,
85 // ogg is supported and working: the codec must be invalid.
86 return CANPLAY_NO;
88 if (WaveDecoder::IsSupportedType(MediaContainerType(mimeType))) {
89 if (WaveDecoder::IsSupportedType(aType)) {
90 return CANPLAY_YES;
92 // We can only reach this position if a particular codec was requested, wave
93 // is supported and working: the codec must be invalid or not supported.
94 return CANPLAY_NO;
96 if (WebMDecoder::IsSupportedType(mimeType)) {
97 if (WebMDecoder::IsSupportedType(aType)) {
98 return CANPLAY_YES;
100 // We can only reach this position if a particular codec was requested,
101 // webm is supported and working: the codec must be invalid.
102 return CANPLAY_NO;
104 #ifdef MOZ_FMP4
105 if (MP4Decoder::IsSupportedType(mimeType,
106 /* DecoderDoctorDiagnostics* */ nullptr)) {
107 if (MP4Decoder::IsSupportedType(aType, aDiagnostics)) {
108 return CANPLAY_YES;
110 // We can only reach this position if a particular codec was requested,
111 // fmp4 is supported and working: the codec must be invalid.
112 return CANPLAY_NO;
114 #endif
115 if (MP3Decoder::IsSupportedType(mimeType)) {
116 if (MP3Decoder::IsSupportedType(aType)) {
117 return CANPLAY_YES;
119 // We can only reach this position if a particular codec was requested,
120 // mp3 is supported and working: the codec must be invalid.
121 return CANPLAY_NO;
123 if (ADTSDecoder::IsSupportedType(mimeType)) {
124 if (ADTSDecoder::IsSupportedType(aType)) {
125 return CANPLAY_YES;
127 // We can only reach this position if a particular codec was requested,
128 // adts is supported and working: the codec must be invalid.
129 return CANPLAY_NO;
131 if (FlacDecoder::IsSupportedType(mimeType)) {
132 if (FlacDecoder::IsSupportedType(aType)) {
133 return CANPLAY_YES;
135 // We can only reach this position if a particular codec was requested,
136 // flac is supported and working: the codec must be invalid.
137 return CANPLAY_NO;
140 return CANPLAY_MAYBE;
143 static CanPlayStatus CanHandleMediaType(
144 const MediaContainerType& aType, DecoderDoctorDiagnostics* aDiagnostics) {
145 if (DecoderTraits::IsHttpLiveStreamingType(aType)) {
146 Telemetry::Accumulate(Telemetry::MEDIA_HLS_CANPLAY_REQUESTED, true);
148 #ifdef MOZ_ANDROID_HLS_SUPPORT
149 if (HLSDecoder::IsSupportedType(aType)) {
150 Telemetry::Accumulate(Telemetry::MEDIA_HLS_CANPLAY_SUPPORTED, true);
151 return CANPLAY_MAYBE;
153 #endif
155 if (DecoderTraits::IsMatroskaType(aType)) {
156 Telemetry::Accumulate(Telemetry::MEDIA_MKV_CANPLAY_REQUESTED, true);
159 if (aType.ExtendedType().HaveCodecs()) {
160 CanPlayStatus result = CanHandleCodecsType(aType, aDiagnostics);
161 if (result == CANPLAY_NO || result == CANPLAY_YES) {
162 return result;
166 // Container type with just the MIME type/subtype, no codecs.
167 const MediaContainerType mimeType(aType.Type());
169 if (OggDecoder::IsSupportedType(mimeType)) {
170 return CANPLAY_MAYBE;
172 if (WaveDecoder::IsSupportedType(mimeType)) {
173 return CANPLAY_MAYBE;
175 #ifdef MOZ_FMP4
176 if (MP4Decoder::IsSupportedType(mimeType, aDiagnostics)) {
177 return CANPLAY_MAYBE;
179 #endif
180 if (WebMDecoder::IsSupportedType(mimeType)) {
181 return CANPLAY_MAYBE;
183 if (MP3Decoder::IsSupportedType(mimeType)) {
184 return CANPLAY_MAYBE;
186 if (ADTSDecoder::IsSupportedType(mimeType)) {
187 return CANPLAY_MAYBE;
189 if (FlacDecoder::IsSupportedType(mimeType)) {
190 return CANPLAY_MAYBE;
192 return CANPLAY_NO;
195 /* static */
196 CanPlayStatus DecoderTraits::CanHandleContainerType(
197 const MediaContainerType& aContainerType,
198 DecoderDoctorDiagnostics* aDiagnostics) {
199 return CanHandleMediaType(aContainerType, aDiagnostics);
202 /* static */
203 bool DecoderTraits::ShouldHandleMediaType(
204 const char* aMIMEType, DecoderDoctorDiagnostics* aDiagnostics) {
205 Maybe<MediaContainerType> containerType = MakeMediaContainerType(aMIMEType);
206 if (!containerType) {
207 return false;
210 if (WaveDecoder::IsSupportedType(*containerType)) {
211 // We should not return true for Wave types, since there are some
212 // Wave codecs actually in use in the wild that we don't support, and
213 // we should allow those to be handled by plugins or helper apps.
214 // Furthermore people can play Wave files on most platforms by other
215 // means.
216 return false;
219 // If an external plugin which can handle quicktime video is available
220 // (and not disabled), prefer it over native playback as there several
221 // codecs found in the wild that we do not handle.
222 if (containerType->Type() == MEDIAMIMETYPE("video/quicktime")) {
223 RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
224 if (pluginHost &&
225 pluginHost->HavePluginForType(containerType->Type().AsString())) {
226 return false;
230 return CanHandleMediaType(*containerType, aDiagnostics) != CANPLAY_NO;
233 /* static */
234 already_AddRefed<MediaDataDemuxer> DecoderTraits::CreateDemuxer(
235 const MediaContainerType& aType, MediaResource* aResource) {
236 MOZ_ASSERT(NS_IsMainThread());
237 RefPtr<MediaDataDemuxer> demuxer;
239 #ifdef MOZ_FMP4
240 if (MP4Decoder::IsSupportedType(aType,
241 /* DecoderDoctorDiagnostics* */ nullptr)) {
242 demuxer = new MP4Demuxer(aResource);
243 } else
244 #endif
245 if (MP3Decoder::IsSupportedType(aType)) {
246 demuxer = new MP3Demuxer(aResource);
247 } else if (ADTSDecoder::IsSupportedType(aType)) {
248 demuxer = new ADTSDemuxer(aResource);
249 } else if (WaveDecoder::IsSupportedType(aType)) {
250 demuxer = new WAVDemuxer(aResource);
251 } else if (FlacDecoder::IsSupportedType(aType)) {
252 demuxer = new FlacDemuxer(aResource);
253 } else if (OggDecoder::IsSupportedType(aType)) {
254 demuxer = new OggDemuxer(aResource);
255 } else if (WebMDecoder::IsSupportedType(aType)) {
256 demuxer = new WebMDemuxer(aResource);
259 return demuxer.forget();
262 /* static */
263 MediaFormatReader* DecoderTraits::CreateReader(const MediaContainerType& aType,
264 MediaFormatReaderInit& aInit) {
265 MOZ_ASSERT(NS_IsMainThread());
267 RefPtr<MediaDataDemuxer> demuxer = CreateDemuxer(aType, aInit.mResource);
268 if (!demuxer) {
269 return nullptr;
272 MediaFormatReader* decoderReader = new MediaFormatReader(aInit, demuxer);
274 if (OggDecoder::IsSupportedType(aType)) {
275 static_cast<OggDemuxer*>(demuxer.get())
276 ->SetChainingEvents(&decoderReader->TimedMetadataProducer(),
277 &decoderReader->MediaNotSeekableProducer());
280 return decoderReader;
283 /* static */
284 bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType) {
285 // Forbid playing media in video documents if the user has opted
286 // not to, using either the legacy WMF specific pref, or the newer
287 // catch-all pref.
288 if (!Preferences::GetBool("media.wmf.play-stand-alone", true) ||
289 !Preferences::GetBool("media.play-stand-alone", true)) {
290 return false;
293 Maybe<MediaContainerType> type = MakeMediaContainerType(aType);
294 if (!type) {
295 return false;
298 return OggDecoder::IsSupportedType(*type) ||
299 WebMDecoder::IsSupportedType(*type) ||
300 #ifdef MOZ_FMP4
301 MP4Decoder::IsSupportedType(*type,
302 /* DecoderDoctorDiagnostics* */ nullptr) ||
303 #endif
304 MP3Decoder::IsSupportedType(*type) ||
305 ADTSDecoder::IsSupportedType(*type) ||
306 FlacDecoder::IsSupportedType(*type) ||
307 #ifdef MOZ_ANDROID_HLS_SUPPORT
308 HLSDecoder::IsSupportedType(*type) ||
309 #endif
310 false;
313 /* static */
314 nsTArray<UniquePtr<TrackInfo>> DecoderTraits::GetTracksInfo(
315 const MediaContainerType& aType) {
316 // Container type with just the MIME type/subtype, no codecs.
317 const MediaContainerType mimeType(aType.Type());
319 if (OggDecoder::IsSupportedType(mimeType)) {
320 return OggDecoder::GetTracksInfo(aType);
322 if (WaveDecoder::IsSupportedType(mimeType)) {
323 return WaveDecoder::GetTracksInfo(aType);
325 #ifdef MOZ_FMP4
326 if (MP4Decoder::IsSupportedType(mimeType, nullptr)) {
327 return MP4Decoder::GetTracksInfo(aType);
329 #endif
330 if (WebMDecoder::IsSupportedType(mimeType)) {
331 return WebMDecoder::GetTracksInfo(aType);
333 if (MP3Decoder::IsSupportedType(mimeType)) {
334 return MP3Decoder::GetTracksInfo(aType);
336 if (ADTSDecoder::IsSupportedType(mimeType)) {
337 return ADTSDecoder::GetTracksInfo(aType);
339 if (FlacDecoder::IsSupportedType(mimeType)) {
340 return FlacDecoder::GetTracksInfo(aType);
342 return nsTArray<UniquePtr<TrackInfo>>();
345 } // namespace mozilla