tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MP4Decoder.cpp (7310B)


      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 
      7 #include "MP4Decoder.h"
      8 
      9 #include "H264.h"
     10 #include "VPXDecoder.h"
     11 #ifdef MOZ_AV1
     12 #  include "AOMDecoder.h"
     13 #endif
     14 #include "MP4Demuxer.h"
     15 #include "MediaContainerType.h"
     16 #include "PDMFactory.h"
     17 #include "PlatformDecoderModule.h"
     18 #include "VideoUtils.h"
     19 #include "mozilla/StaticPrefs_media.h"
     20 #include "mozilla/gfx/Tools.h"
     21 #include "nsMimeTypes.h"
     22 #include "nsReadableUtils.h"
     23 
     24 namespace mozilla {
     25 
     26 static bool IsTypeValid(const MediaContainerType& aType) {
     27  // Whitelist MP4 types, so they explicitly match what we encounter on
     28  // the web, as opposed to what we use internally (i.e. what our demuxers
     29  // etc output).
     30  return aType.Type() == MEDIAMIMETYPE("audio/mp4") ||
     31         aType.Type() == MEDIAMIMETYPE("audio/x-m4a") ||
     32         aType.Type() == MEDIAMIMETYPE("video/mp4") ||
     33         aType.Type() == MEDIAMIMETYPE("video/quicktime") ||
     34         aType.Type() == MEDIAMIMETYPE("video/x-m4v");
     35 }
     36 
     37 /* statis */
     38 nsTArray<UniquePtr<TrackInfo>> MP4Decoder::GetTracksInfo(
     39    const MediaContainerType& aType, MediaResult& aError) {
     40  nsTArray<UniquePtr<TrackInfo>> tracks;
     41 
     42  if (!IsTypeValid(aType)) {
     43    aError = MediaResult(
     44        NS_ERROR_DOM_MEDIA_FATAL_ERR,
     45        RESULT_DETAIL("Invalid type:%s", aType.Type().AsString().get()));
     46    return tracks;
     47  }
     48 
     49  aError = NS_OK;
     50 
     51  const MediaCodecs& codecs = aType.ExtendedType().Codecs();
     52  if (codecs.IsEmpty()) {
     53    return tracks;
     54  }
     55 
     56  const bool isVideo = aType.Type() == MEDIAMIMETYPE("video/mp4") ||
     57                       aType.Type() == MEDIAMIMETYPE("video/quicktime") ||
     58                       aType.Type() == MEDIAMIMETYPE("video/x-m4v");
     59 
     60  for (const auto& codec : codecs.Range()) {
     61    if (IsAACCodecString(codec)) {
     62      tracks.AppendElement(
     63          CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
     64              "audio/mp4a-latm"_ns, aType));
     65      continue;
     66    }
     67    if (codec.EqualsLiteral("mp3")) {
     68      tracks.AppendElement(
     69          CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
     70              "audio/mpeg"_ns, aType));
     71      continue;
     72    }
     73    // The valid codecs parameter value with mp4 MIME types should be "Opus" and
     74    // "fLaC", but "opus" and "flac" are acceptable due to historical reasons.
     75    if (codec.EqualsLiteral("opus") || codec.EqualsLiteral("Opus") ||
     76        codec.EqualsLiteral("flac") || codec.EqualsLiteral("fLaC")) {
     77      NS_ConvertUTF16toUTF8 c(codec);
     78      ToLowerCase(c);
     79      tracks.AppendElement(
     80          CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
     81              "audio/"_ns + c, aType));
     82      continue;
     83    }
     84    if (IsVP9CodecString(codec)) {
     85      auto trackInfo =
     86          CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
     87              "video/vp9"_ns, aType);
     88      VPXDecoder::SetVideoInfo(trackInfo->GetAsVideoInfo(), codec);
     89      tracks.AppendElement(std::move(trackInfo));
     90      continue;
     91    }
     92 #ifdef MOZ_AV1
     93    if (StaticPrefs::media_av1_enabled() && IsAV1CodecString(codec)) {
     94      auto trackInfo =
     95          CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
     96              "video/av1"_ns, aType);
     97      AOMDecoder::SetVideoInfo(trackInfo->GetAsVideoInfo(), codec);
     98      tracks.AppendElement(std::move(trackInfo));
     99      continue;
    100    }
    101 #endif
    102    if (StaticPrefs::media_hevc_enabled() && IsH265CodecString(codec)) {
    103      auto trackInfo =
    104          CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
    105              "video/hevc"_ns, aType);
    106      tracks.AppendElement(std::move(trackInfo));
    107      continue;
    108    }
    109    if (isVideo && IsAllowedH264Codec(codec)) {
    110      auto trackInfo =
    111          CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
    112              "video/avc"_ns, aType);
    113      uint8_t profile = 0, constraint = 0;
    114      H264_LEVEL level;
    115      MOZ_ALWAYS_TRUE(
    116          ExtractH264CodecDetails(codec, profile, constraint, level,
    117                                  H264CodecStringStrictness::Lenient));
    118      uint32_t width = aType.ExtendedType().GetWidth().refOr(1280);
    119      uint32_t height = aType.ExtendedType().GetHeight().refOr(720);
    120      trackInfo->GetAsVideoInfo()->mExtraData =
    121          H264::CreateExtraData(profile, constraint, level, {width, height});
    122      tracks.AppendElement(std::move(trackInfo));
    123      continue;
    124    }
    125    // Unknown codec
    126    aError = MediaResult(
    127        NS_ERROR_DOM_MEDIA_FATAL_ERR,
    128        RESULT_DETAIL("Unknown codec:%s", NS_ConvertUTF16toUTF8(codec).get()));
    129  }
    130  return tracks;
    131 }
    132 
    133 /* static */
    134 bool MP4Decoder::IsSupportedType(const MediaContainerType& aType,
    135                                 DecoderDoctorDiagnostics* aDiagnostics) {
    136  if (!IsEnabled()) {
    137    return false;
    138  }
    139 
    140  MediaResult rv = NS_OK;
    141  auto tracks = GetTracksInfo(aType, rv);
    142  if (NS_FAILED(rv)) {
    143    return false;
    144  }
    145 
    146  if (!tracks.IsEmpty()) {
    147    // Look for exact match as we know used codecs.
    148    RefPtr<PDMFactory> platform = new PDMFactory();
    149    for (const auto& track : tracks) {
    150      if (!track ||
    151          platform->Supports(SupportDecoderParams(*track), aDiagnostics)
    152              .isEmpty()) {
    153        return false;
    154      }
    155    }
    156    return true;
    157  }
    158 
    159  // We have only container info so try to guess the content type.
    160  // Assume H.264/AV1 or AAC
    161  if (aType.Type() == MEDIAMIMETYPE("audio/mp4") ||
    162      aType.Type() == MEDIAMIMETYPE("audio/x-m4a")) {
    163    tracks.AppendElement(
    164        CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
    165            "audio/mp4a-latm"_ns, aType));
    166  } else {
    167    tracks.AppendElement(
    168        CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
    169            "video/avc"_ns, aType));
    170    if (StaticPrefs::media_av1_enabled()) {
    171      tracks.AppendElement(
    172          CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
    173              "video/av1"_ns, aType));
    174    }
    175    if (StaticPrefs::media_hevc_enabled()) {
    176      tracks.AppendElement(
    177          CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
    178              "video/hevc"_ns, aType));
    179    }
    180  }
    181 
    182  // Check that something is supported at least.
    183  RefPtr<PDMFactory> platform = new PDMFactory();
    184  for (const auto& track : tracks) {
    185    if (track && !platform->Supports(SupportDecoderParams(*track), aDiagnostics)
    186                      .isEmpty()) {
    187      return true;
    188    }
    189  }
    190  return false;
    191 }
    192 
    193 /* static */
    194 bool MP4Decoder::IsH264(const nsACString& aMimeType) {
    195  return aMimeType.EqualsLiteral("video/mp4") ||
    196         aMimeType.EqualsLiteral("video/avc");
    197 }
    198 
    199 /* static */
    200 bool MP4Decoder::IsAAC(const nsACString& aMimeType) {
    201  return aMimeType.EqualsLiteral("audio/mp4a-latm");
    202 }
    203 
    204 /* static */
    205 bool MP4Decoder::IsHEVC(const nsACString& aMimeType) {
    206  return aMimeType.EqualsLiteral("video/hevc");
    207 }
    208 
    209 /* static */
    210 bool MP4Decoder::IsEnabled() { return StaticPrefs::media_mp4_enabled(); }
    211 
    212 /* static */
    213 nsTArray<UniquePtr<TrackInfo>> MP4Decoder::GetTracksInfo(
    214    const MediaContainerType& aType) {
    215  MediaResult rv = NS_OK;
    216  return GetTracksInfo(aType, rv);
    217 }
    218 
    219 }  // namespace mozilla