no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / media / DecoderTraits.cpp
blobaf4d08ae4bdb1ee84bae0909cab3ac40672349c4
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 #include "MP4Decoder.h"
21 #include "MP4Demuxer.h"
22 #include "MediaFormatReader.h"
24 #include "MP3Decoder.h"
25 #include "MP3Demuxer.h"
27 #include "WaveDecoder.h"
28 #include "WaveDemuxer.h"
30 #include "ADTSDecoder.h"
31 #include "ADTSDemuxer.h"
33 #include "FlacDecoder.h"
34 #include "FlacDemuxer.h"
36 namespace mozilla {
38 /* static */
39 bool DecoderTraits::IsHttpLiveStreamingType(const MediaContainerType& aType) {
40 const auto& mimeType = aType.Type();
41 return // For m3u8.
42 // https://tools.ietf.org/html/draft-pantos-http-live-streaming-19#section-10
43 mimeType == MEDIAMIMETYPE("application/vnd.apple.mpegurl") ||
44 // Some sites serve these as the informal m3u type.
45 mimeType == MEDIAMIMETYPE("application/x-mpegurl") ||
46 mimeType == MEDIAMIMETYPE("audio/mpegurl") ||
47 mimeType == MEDIAMIMETYPE("audio/x-mpegurl");
50 /* static */
51 bool DecoderTraits::IsMatroskaType(const MediaContainerType& aType) {
52 const auto& mimeType = aType.Type();
53 // https://matroska.org/technical/specs/notes.html
54 return mimeType == MEDIAMIMETYPE("audio/x-matroska") ||
55 mimeType == MEDIAMIMETYPE("video/x-matroska");
58 static CanPlayStatus CanHandleCodecsType(
59 const MediaContainerType& aType, DecoderDoctorDiagnostics* aDiagnostics) {
60 // We should have been given a codecs string, though it may be empty.
61 MOZ_ASSERT(aType.ExtendedType().HaveCodecs());
63 // Container type with the MIME type, no codecs.
64 const MediaContainerType mimeType(aType.Type());
66 if (OggDecoder::IsSupportedType(mimeType)) {
67 if (OggDecoder::IsSupportedType(aType)) {
68 return CANPLAY_YES;
70 // We can only reach this position if a particular codec was requested,
71 // ogg is supported and working: the codec must be invalid.
72 return CANPLAY_NO;
74 if (WaveDecoder::IsSupportedType(MediaContainerType(mimeType))) {
75 if (WaveDecoder::IsSupportedType(aType)) {
76 return CANPLAY_YES;
78 // We can only reach this position if a particular codec was requested, wave
79 // is supported and working: the codec must be invalid or not supported.
80 return CANPLAY_NO;
82 if (WebMDecoder::IsSupportedType(mimeType)) {
83 if (WebMDecoder::IsSupportedType(aType)) {
84 return CANPLAY_YES;
86 // We can only reach this position if a particular codec was requested,
87 // webm is supported and working: the codec must be invalid.
88 return CANPLAY_NO;
90 if (MP4Decoder::IsSupportedType(mimeType,
91 /* DecoderDoctorDiagnostics* */ nullptr)) {
92 if (MP4Decoder::IsSupportedType(aType, aDiagnostics)) {
93 return CANPLAY_YES;
95 // We can only reach this position if a particular codec was requested,
96 // fmp4 is supported and working: the codec must be invalid.
97 return CANPLAY_NO;
99 if (MP3Decoder::IsSupportedType(mimeType)) {
100 if (MP3Decoder::IsSupportedType(aType)) {
101 return CANPLAY_YES;
103 // We can only reach this position if a particular codec was requested,
104 // mp3 is supported and working: the codec must be invalid.
105 return CANPLAY_NO;
107 if (ADTSDecoder::IsSupportedType(mimeType)) {
108 if (ADTSDecoder::IsSupportedType(aType)) {
109 return CANPLAY_YES;
111 // We can only reach this position if a particular codec was requested,
112 // adts is supported and working: the codec must be invalid.
113 return CANPLAY_NO;
115 if (FlacDecoder::IsSupportedType(mimeType)) {
116 if (FlacDecoder::IsSupportedType(aType)) {
117 return CANPLAY_YES;
119 // We can only reach this position if a particular codec was requested,
120 // flac is supported and working: the codec must be invalid.
121 return CANPLAY_NO;
124 return CANPLAY_MAYBE;
127 static CanPlayStatus CanHandleMediaType(
128 const MediaContainerType& aType, DecoderDoctorDiagnostics* aDiagnostics) {
129 if (DecoderTraits::IsHttpLiveStreamingType(aType)) {
130 Telemetry::Accumulate(Telemetry::MEDIA_HLS_CANPLAY_REQUESTED, true);
132 #ifdef MOZ_ANDROID_HLS_SUPPORT
133 if (HLSDecoder::IsSupportedType(aType)) {
134 Telemetry::Accumulate(Telemetry::MEDIA_HLS_CANPLAY_SUPPORTED, true);
135 return CANPLAY_MAYBE;
137 #endif
139 if (DecoderTraits::IsMatroskaType(aType)) {
140 Telemetry::Accumulate(Telemetry::MEDIA_MKV_CANPLAY_REQUESTED, true);
143 if (aType.ExtendedType().HaveCodecs()) {
144 CanPlayStatus result = CanHandleCodecsType(aType, aDiagnostics);
145 if (result == CANPLAY_NO || result == CANPLAY_YES) {
146 return result;
150 // Container type with just the MIME type/subtype, no codecs.
151 const MediaContainerType mimeType(aType.Type());
153 if (OggDecoder::IsSupportedType(mimeType)) {
154 return CANPLAY_MAYBE;
156 if (WaveDecoder::IsSupportedType(mimeType)) {
157 return CANPLAY_MAYBE;
159 if (MP4Decoder::IsSupportedType(mimeType, aDiagnostics)) {
160 return CANPLAY_MAYBE;
162 if (WebMDecoder::IsSupportedType(mimeType)) {
163 return CANPLAY_MAYBE;
165 if (MP3Decoder::IsSupportedType(mimeType)) {
166 return CANPLAY_MAYBE;
168 if (ADTSDecoder::IsSupportedType(mimeType)) {
169 return CANPLAY_MAYBE;
171 if (FlacDecoder::IsSupportedType(mimeType)) {
172 return CANPLAY_MAYBE;
174 return CANPLAY_NO;
177 /* static */
178 CanPlayStatus DecoderTraits::CanHandleContainerType(
179 const MediaContainerType& aContainerType,
180 DecoderDoctorDiagnostics* aDiagnostics) {
181 return CanHandleMediaType(aContainerType, aDiagnostics);
184 /* static */
185 bool DecoderTraits::ShouldHandleMediaType(
186 const char* aMIMEType, DecoderDoctorDiagnostics* aDiagnostics) {
187 Maybe<MediaContainerType> containerType = MakeMediaContainerType(aMIMEType);
188 if (!containerType) {
189 return false;
192 if (WaveDecoder::IsSupportedType(*containerType)) {
193 // We should not return true for Wave types, since there are some
194 // Wave codecs actually in use in the wild that we don't support, and
195 // we should allow those to be handled by plugins or helper apps.
196 // Furthermore people can play Wave files on most platforms by other
197 // means.
198 return false;
201 return CanHandleMediaType(*containerType, aDiagnostics) != CANPLAY_NO;
204 /* static */
205 already_AddRefed<MediaDataDemuxer> DecoderTraits::CreateDemuxer(
206 const MediaContainerType& aType, MediaResource* aResource) {
207 MOZ_ASSERT(NS_IsMainThread());
208 RefPtr<MediaDataDemuxer> demuxer;
210 if (MP4Decoder::IsSupportedType(aType,
211 /* DecoderDoctorDiagnostics* */ nullptr)) {
212 demuxer = new MP4Demuxer(aResource);
213 } else if (MP3Decoder::IsSupportedType(aType)) {
214 demuxer = new MP3Demuxer(aResource);
215 } else if (ADTSDecoder::IsSupportedType(aType)) {
216 demuxer = new ADTSDemuxer(aResource);
217 } else if (WaveDecoder::IsSupportedType(aType)) {
218 demuxer = new WAVDemuxer(aResource);
219 } else if (FlacDecoder::IsSupportedType(aType)) {
220 demuxer = new FlacDemuxer(aResource);
221 } else if (OggDecoder::IsSupportedType(aType)) {
222 demuxer = new OggDemuxer(aResource);
223 } else if (WebMDecoder::IsSupportedType(aType)) {
224 demuxer = new WebMDemuxer(aResource);
227 return demuxer.forget();
230 /* static */
231 MediaFormatReader* DecoderTraits::CreateReader(const MediaContainerType& aType,
232 MediaFormatReaderInit& aInit) {
233 MOZ_ASSERT(NS_IsMainThread());
235 RefPtr<MediaDataDemuxer> demuxer = CreateDemuxer(aType, aInit.mResource);
236 if (!demuxer) {
237 return nullptr;
240 MediaFormatReader* decoderReader = new MediaFormatReader(aInit, demuxer);
242 if (OggDecoder::IsSupportedType(aType)) {
243 static_cast<OggDemuxer*>(demuxer.get())
244 ->SetChainingEvents(&decoderReader->TimedMetadataProducer(),
245 &decoderReader->MediaNotSeekableProducer());
248 return decoderReader;
251 /* static */
252 bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType) {
253 // Forbid playing media in video documents if the user has opted
254 // not to, using either the legacy WMF specific pref, or the newer
255 // catch-all pref.
256 if (!Preferences::GetBool("media.wmf.play-stand-alone", true) ||
257 !Preferences::GetBool("media.play-stand-alone", true)) {
258 return false;
261 Maybe<MediaContainerType> type = MakeMediaContainerType(aType);
262 if (!type) {
263 return false;
266 return OggDecoder::IsSupportedType(*type) ||
267 WebMDecoder::IsSupportedType(*type) ||
268 MP4Decoder::IsSupportedType(*type,
269 /* DecoderDoctorDiagnostics* */ nullptr) ||
270 MP3Decoder::IsSupportedType(*type) ||
271 ADTSDecoder::IsSupportedType(*type) ||
272 FlacDecoder::IsSupportedType(*type) ||
273 #ifdef MOZ_ANDROID_HLS_SUPPORT
274 HLSDecoder::IsSupportedType(*type) ||
275 #endif
276 false;
279 /* static */
280 nsTArray<UniquePtr<TrackInfo>> DecoderTraits::GetTracksInfo(
281 const MediaContainerType& aType) {
282 // Container type with just the MIME type/subtype, no codecs.
283 const MediaContainerType mimeType(aType.Type());
285 if (OggDecoder::IsSupportedType(mimeType)) {
286 return OggDecoder::GetTracksInfo(aType);
288 if (WaveDecoder::IsSupportedType(mimeType)) {
289 return WaveDecoder::GetTracksInfo(aType);
291 if (MP4Decoder::IsSupportedType(mimeType, nullptr)) {
292 return MP4Decoder::GetTracksInfo(aType);
294 if (WebMDecoder::IsSupportedType(mimeType)) {
295 return WebMDecoder::GetTracksInfo(aType);
297 if (MP3Decoder::IsSupportedType(mimeType)) {
298 return MP3Decoder::GetTracksInfo(aType);
300 if (ADTSDecoder::IsSupportedType(mimeType)) {
301 return ADTSDecoder::GetTracksInfo(aType);
303 if (FlacDecoder::IsSupportedType(mimeType)) {
304 return FlacDecoder::GetTracksInfo(aType);
306 return nsTArray<UniquePtr<TrackInfo>>();
309 } // namespace mozilla