DecoderTraits.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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/. */
  6. #include "DecoderTraits.h"
  7. #include "MediaContentType.h"
  8. #include "MediaDecoder.h"
  9. #include "nsCharSeparatedTokenizer.h"
  10. #include "nsMimeTypes.h"
  11. #include "mozilla/Preferences.h"
  12. #include "OggDecoder.h"
  13. #include "OggDemuxer.h"
  14. #include "WebMDecoder.h"
  15. #include "WebMDemuxer.h"
  16. #ifdef MOZ_FMP4
  17. #include "MP4Decoder.h"
  18. #include "MP4Demuxer.h"
  19. #endif
  20. #include "MediaFormatReader.h"
  21. #include "MP3Decoder.h"
  22. #include "MP3Demuxer.h"
  23. #include "WaveDecoder.h"
  24. #include "WaveDemuxer.h"
  25. #include "ADTSDecoder.h"
  26. #include "ADTSDemuxer.h"
  27. #include "FlacDecoder.h"
  28. #include "FlacDemuxer.h"
  29. #include "nsPluginHost.h"
  30. #include "MediaPrefs.h"
  31. namespace mozilla
  32. {
  33. template <class String>
  34. static bool
  35. CodecListContains(char const *const * aCodecs, const String& aCodec)
  36. {
  37. for (int32_t i = 0; aCodecs[i]; ++i) {
  38. if (aCodec.EqualsASCII(aCodecs[i]))
  39. return true;
  40. }
  41. return false;
  42. }
  43. static bool
  44. IsOggSupportedType(const nsACString& aType,
  45. const nsAString& aCodecs = EmptyString())
  46. {
  47. return OggDecoder::CanHandleMediaType(aType, aCodecs);
  48. }
  49. static bool
  50. IsOggTypeAndEnabled(const nsACString& aType)
  51. {
  52. return IsOggSupportedType(aType);
  53. }
  54. static bool
  55. IsWebMSupportedType(const nsACString& aType,
  56. const nsAString& aCodecs = EmptyString())
  57. {
  58. return WebMDecoder::CanHandleMediaType(aType, aCodecs);
  59. }
  60. /* static */ bool
  61. DecoderTraits::IsWebMTypeAndEnabled(const nsACString& aType)
  62. {
  63. return IsWebMSupportedType(aType);
  64. }
  65. /* static */ bool
  66. DecoderTraits::IsWebMAudioType(const nsACString& aType)
  67. {
  68. return aType.EqualsASCII("audio/webm");
  69. }
  70. #ifdef MOZ_FMP4
  71. static bool
  72. IsMP4SupportedType(const MediaContentType& aParsedType,
  73. DecoderDoctorDiagnostics* aDiagnostics)
  74. {
  75. return MP4Decoder::CanHandleMediaType(aParsedType, aDiagnostics);
  76. }
  77. static bool
  78. IsMP4SupportedType(const nsACString& aType,
  79. DecoderDoctorDiagnostics* aDiagnostics)
  80. {
  81. MediaContentType contentType{aType};
  82. return IsMP4SupportedType(contentType, aDiagnostics);
  83. }
  84. #endif
  85. /* static */ bool
  86. DecoderTraits::IsMP4TypeAndEnabled(const nsACString& aType,
  87. DecoderDoctorDiagnostics* aDiagnostics)
  88. {
  89. #ifdef MOZ_FMP4
  90. return IsMP4SupportedType(aType, aDiagnostics);
  91. #else
  92. return false;
  93. #endif
  94. }
  95. static bool
  96. IsMP3SupportedType(const nsACString& aType,
  97. const nsAString& aCodecs = EmptyString())
  98. {
  99. return MP3Decoder::CanHandleMediaType(aType, aCodecs);
  100. }
  101. static bool
  102. IsAACSupportedType(const nsACString& aType,
  103. const nsAString& aCodecs = EmptyString())
  104. {
  105. return ADTSDecoder::CanHandleMediaType(aType, aCodecs);
  106. }
  107. static bool
  108. IsWaveSupportedType(const nsACString& aType,
  109. const nsAString& aCodecs = EmptyString())
  110. {
  111. return WaveDecoder::CanHandleMediaType(aType, aCodecs);
  112. }
  113. static bool
  114. IsFlacSupportedType(const nsACString& aType,
  115. const nsAString& aCodecs = EmptyString())
  116. {
  117. return FlacDecoder::CanHandleMediaType(aType, aCodecs);
  118. }
  119. static
  120. CanPlayStatus
  121. CanHandleCodecsType(const MediaContentType& aType,
  122. DecoderDoctorDiagnostics* aDiagnostics)
  123. {
  124. MOZ_ASSERT(aType.IsValid());
  125. // We should have been given a codecs string, though it may be empty.
  126. MOZ_ASSERT(aType.HaveCodecs());
  127. char const* const* codecList = nullptr;
  128. if (IsOggTypeAndEnabled(aType.GetMIMEType())) {
  129. if (IsOggSupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
  130. return CANPLAY_YES;
  131. } else {
  132. // We can only reach this position if a particular codec was requested,
  133. // ogg is supported and working: the codec must be invalid.
  134. return CANPLAY_NO;
  135. }
  136. }
  137. if (IsWaveSupportedType(aType.GetMIMEType())) {
  138. if (IsWaveSupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
  139. return CANPLAY_YES;
  140. } else {
  141. // We can only reach this position if a particular codec was requested,
  142. // ogg is supported and working: the codec must be invalid.
  143. return CANPLAY_NO;
  144. }
  145. }
  146. #if !defined(MOZ_OMX_WEBM_DECODER)
  147. if (DecoderTraits::IsWebMTypeAndEnabled(aType.GetMIMEType())) {
  148. if (IsWebMSupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
  149. return CANPLAY_YES;
  150. } else {
  151. // We can only reach this position if a particular codec was requested,
  152. // webm is supported and working: the codec must be invalid.
  153. return CANPLAY_NO;
  154. }
  155. }
  156. #endif
  157. #ifdef MOZ_FMP4
  158. if (DecoderTraits::IsMP4TypeAndEnabled(aType.GetMIMEType(), aDiagnostics)) {
  159. if (IsMP4SupportedType(aType, aDiagnostics)) {
  160. return CANPLAY_YES;
  161. } else {
  162. // We can only reach this position if a particular codec was requested,
  163. // fmp4 is supported and working: the codec must be invalid.
  164. return CANPLAY_NO;
  165. }
  166. }
  167. #endif
  168. if (IsMP3SupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
  169. return CANPLAY_YES;
  170. }
  171. if (IsAACSupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
  172. return CANPLAY_YES;
  173. }
  174. if (IsFlacSupportedType(aType.GetMIMEType(), aType.GetCodecs())) {
  175. return CANPLAY_YES;
  176. }
  177. if (!codecList) {
  178. return CANPLAY_MAYBE;
  179. }
  180. // See http://www.rfc-editor.org/rfc/rfc4281.txt for the description
  181. // of the 'codecs' parameter
  182. nsCharSeparatedTokenizer tokenizer(aType.GetCodecs(), ',');
  183. bool expectMoreTokens = false;
  184. while (tokenizer.hasMoreTokens()) {
  185. const nsSubstring& token = tokenizer.nextToken();
  186. if (!CodecListContains(codecList, token)) {
  187. // Totally unsupported codec
  188. return CANPLAY_NO;
  189. }
  190. expectMoreTokens = tokenizer.separatorAfterCurrentToken();
  191. }
  192. if (expectMoreTokens) {
  193. // Last codec name was empty
  194. return CANPLAY_NO;
  195. }
  196. return CANPLAY_YES;
  197. }
  198. static
  199. CanPlayStatus
  200. CanHandleMediaType(const MediaContentType& aType,
  201. DecoderDoctorDiagnostics* aDiagnostics)
  202. {
  203. MOZ_ASSERT(NS_IsMainThread());
  204. if (aType.HaveCodecs()) {
  205. CanPlayStatus result = CanHandleCodecsType(aType, aDiagnostics);
  206. if (result == CANPLAY_NO || result == CANPLAY_YES) {
  207. return result;
  208. }
  209. }
  210. if (IsOggTypeAndEnabled(aType.GetMIMEType())) {
  211. return CANPLAY_MAYBE;
  212. }
  213. if (IsWaveSupportedType(aType.GetMIMEType())) {
  214. return CANPLAY_MAYBE;
  215. }
  216. if (DecoderTraits::IsMP4TypeAndEnabled(aType.GetMIMEType(), aDiagnostics)) {
  217. return CANPLAY_MAYBE;
  218. }
  219. #if !defined(MOZ_OMX_WEBM_DECODER)
  220. if (DecoderTraits::IsWebMTypeAndEnabled(aType.GetMIMEType())) {
  221. return CANPLAY_MAYBE;
  222. }
  223. #endif
  224. if (IsMP3SupportedType(aType.GetMIMEType())) {
  225. return CANPLAY_MAYBE;
  226. }
  227. if (IsAACSupportedType(aType.GetMIMEType())) {
  228. return CANPLAY_MAYBE;
  229. }
  230. if (IsFlacSupportedType(aType.GetMIMEType())) {
  231. return CANPLAY_MAYBE;
  232. }
  233. return CANPLAY_NO;
  234. }
  235. /* static */
  236. CanPlayStatus
  237. DecoderTraits::CanHandleContentType(const MediaContentType& aContentType,
  238. DecoderDoctorDiagnostics* aDiagnostics)
  239. {
  240. if (!aContentType.IsValid()) {
  241. return CANPLAY_NO;
  242. }
  243. return CanHandleMediaType(aContentType, aDiagnostics);
  244. }
  245. /* static */
  246. bool DecoderTraits::ShouldHandleMediaType(const char* aMIMEType,
  247. DecoderDoctorDiagnostics* aDiagnostics)
  248. {
  249. if (IsWaveSupportedType(nsDependentCString(aMIMEType))) {
  250. // We should not return true for Wave types, since there are some
  251. // Wave codecs actually in use in the wild that we don't support, and
  252. // we should allow those to be handled by plugins or helper apps.
  253. // Furthermore people can play Wave files on most platforms by other
  254. // means.
  255. return false;
  256. }
  257. // If an external plugin which can handle quicktime video is available
  258. // (and not disabled), prefer it over native playback as there several
  259. // codecs found in the wild that we do not handle.
  260. if (nsDependentCString(aMIMEType).EqualsASCII("video/quicktime")) {
  261. RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
  262. if (pluginHost &&
  263. pluginHost->HavePluginForType(nsDependentCString(aMIMEType))) {
  264. return false;
  265. }
  266. }
  267. MediaContentType parsed{nsDependentCString(aMIMEType)};
  268. return CanHandleMediaType(parsed, aDiagnostics)
  269. != CANPLAY_NO;
  270. }
  271. // Instantiates but does not initialize decoder.
  272. static
  273. already_AddRefed<MediaDecoder>
  274. InstantiateDecoder(const nsACString& aType,
  275. MediaDecoderOwner* aOwner,
  276. DecoderDoctorDiagnostics* aDiagnostics)
  277. {
  278. MOZ_ASSERT(NS_IsMainThread());
  279. RefPtr<MediaDecoder> decoder;
  280. #ifdef MOZ_FMP4
  281. if (IsMP4SupportedType(aType, aDiagnostics)) {
  282. decoder = new MP4Decoder(aOwner);
  283. return decoder.forget();
  284. }
  285. #endif
  286. if (IsMP3SupportedType(aType)) {
  287. decoder = new MP3Decoder(aOwner);
  288. return decoder.forget();
  289. }
  290. if (IsAACSupportedType(aType)) {
  291. decoder = new ADTSDecoder(aOwner);
  292. return decoder.forget();
  293. }
  294. if (IsOggSupportedType(aType)) {
  295. decoder = new OggDecoder(aOwner);
  296. return decoder.forget();
  297. }
  298. if (IsWaveSupportedType(aType)) {
  299. decoder = new WaveDecoder(aOwner);
  300. return decoder.forget();
  301. }
  302. if (IsFlacSupportedType(aType)) {
  303. decoder = new FlacDecoder(aOwner);
  304. return decoder.forget();
  305. }
  306. if (IsWebMSupportedType(aType)) {
  307. decoder = new WebMDecoder(aOwner);
  308. return decoder.forget();
  309. }
  310. return nullptr;
  311. }
  312. /* static */
  313. already_AddRefed<MediaDecoder>
  314. DecoderTraits::CreateDecoder(const nsACString& aType,
  315. MediaDecoderOwner* aOwner,
  316. DecoderDoctorDiagnostics* aDiagnostics)
  317. {
  318. MOZ_ASSERT(NS_IsMainThread());
  319. return InstantiateDecoder(aType, aOwner, aDiagnostics);
  320. }
  321. /* static */
  322. MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, AbstractMediaDecoder* aDecoder)
  323. {
  324. MOZ_ASSERT(NS_IsMainThread());
  325. MediaDecoderReader* decoderReader = nullptr;
  326. if (!aDecoder) {
  327. return decoderReader;
  328. }
  329. #ifdef MOZ_FMP4
  330. if (IsMP4SupportedType(aType, /* DecoderDoctorDiagnostics* */ nullptr)) {
  331. decoderReader = new MediaFormatReader(aDecoder, new MP4Demuxer(aDecoder->GetResource()));
  332. } else
  333. #endif
  334. if (IsMP3SupportedType(aType)) {
  335. decoderReader = new MediaFormatReader(aDecoder, new MP3Demuxer(aDecoder->GetResource()));
  336. } else
  337. if (IsAACSupportedType(aType)) {
  338. decoderReader = new MediaFormatReader(aDecoder, new ADTSDemuxer(aDecoder->GetResource()));
  339. } else
  340. if (IsWaveSupportedType(aType)) {
  341. decoderReader = new MediaFormatReader(aDecoder, new WAVDemuxer(aDecoder->GetResource()));
  342. } else
  343. if (IsFlacSupportedType(aType)) {
  344. decoderReader = new MediaFormatReader(aDecoder, new FlacDemuxer(aDecoder->GetResource()));
  345. } else
  346. if (IsOggSupportedType(aType)) {
  347. decoderReader = new MediaFormatReader(aDecoder, new OggDemuxer(aDecoder->GetResource()));
  348. } else
  349. if (IsWebMSupportedType(aType)) {
  350. decoderReader =
  351. new MediaFormatReader(aDecoder, new WebMDemuxer(aDecoder->GetResource()));
  352. }
  353. return decoderReader;
  354. }
  355. /* static */
  356. bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
  357. {
  358. // Forbid playing media in video documents if the user has opted
  359. // not to, using either the legacy WMF specific pref, or the newer
  360. // catch-all pref.
  361. if (!Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true) ||
  362. !Preferences::GetBool("media.play-stand-alone", true)) {
  363. return false;
  364. }
  365. return
  366. IsOggSupportedType(aType) ||
  367. IsWebMSupportedType(aType) ||
  368. #ifdef MOZ_FMP4
  369. IsMP4SupportedType(aType, /* DecoderDoctorDiagnostics* */ nullptr) ||
  370. #endif
  371. IsMP3SupportedType(aType) ||
  372. IsAACSupportedType(aType) ||
  373. IsFlacSupportedType(aType) ||
  374. false;
  375. }
  376. } // namespace mozilla