tor-browser

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

MediaCodecsSupport.cpp (12556B)


      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 <array>
      7 
      8 #ifdef MOZ_AV1
      9 #  include "AOMDecoder.h"
     10 #endif
     11 #include "MP4Decoder.h"
     12 #include "MediaCodecsSupport.h"
     13 #include "PDMFactory.h"
     14 #include "PEMFactory.h"
     15 #include "PlatformDecoderModule.h"
     16 #include "VPXDecoder.h"
     17 #include "VideoUtils.h"
     18 #include "mozilla/AppShutdown.h"
     19 #include "mozilla/gfx/gfxVars.h"
     20 #include "nsTHashMap.h"
     21 
     22 using MediaCodecsSupport = mozilla::media::MediaCodecsSupport;
     23 
     24 namespace mozilla::media {
     25 
     26 static StaticAutoPtr<MCSInfo> sInstance;
     27 static StaticMutex sInitMutex;
     28 static StaticMutex sUpdateMutex;
     29 
     30 #define CODEC_SUPPORT_LOG(msg, ...) \
     31  MOZ_LOG(sPDMLog, LogLevel::Debug, ("MediaCodecsSupport, " msg, ##__VA_ARGS__))
     32 
     33 /* static */
     34 MediaCodecsSupported MCSInfo::GetSupportFromFactory(
     35    bool aForceRefresh /* = false */) {
     36  return PDMFactory::Supported(aForceRefresh) +
     37         PEMFactory::Supported(aForceRefresh);
     38 }
     39 
     40 void MCSInfo::AddSupport(const MediaCodecsSupported& aSupport) {
     41  StaticMutexAutoLock lock(sUpdateMutex);
     42  MCSInfo* instance = GetInstance();
     43  if (!instance) {
     44    CODEC_SUPPORT_LOG("Can't add codec support without a MCSInfo instance!");
     45    return;
     46  }
     47  instance->mSupport += aSupport;
     48 }
     49 
     50 MediaCodecsSupported MCSInfo::GetSupport() {
     51  StaticMutexAutoLock lock(sUpdateMutex);
     52  MCSInfo* instance = GetInstance();
     53  if (!instance) {
     54    CODEC_SUPPORT_LOG("Can't get codec support without a MCSInfo instance!");
     55    return MediaCodecsSupported{};
     56  }
     57  return instance->mSupport;
     58 }
     59 
     60 void MCSInfo::ResetSupport() {
     61  StaticMutexAutoLock lock(sUpdateMutex);
     62  MCSInfo* instance = GetInstance();
     63  if (!instance) {
     64    CODEC_SUPPORT_LOG("Can't reset codec support without a MCSInfo instance!");
     65    return;
     66  }
     67  instance->mSupport.clear();
     68 }
     69 
     70 DecodeSupportSet MCSInfo::GetDecodeSupportSet(
     71    const MediaCodec& aCodec, const MediaCodecsSupported& aSupported) {
     72  DecodeSupportSet support;
     73  const auto supportInfo = GetCodecDefinition(aCodec);
     74  if (aSupported.contains(supportInfo.swDecodeSupport)) {
     75    support += DecodeSupport::SoftwareDecode;
     76  }
     77  if (aSupported.contains(supportInfo.hwDecodeSupport)) {
     78    support += DecodeSupport::HardwareDecode;
     79  }
     80  return support;
     81 }
     82 
     83 EncodeSupportSet MCSInfo::GetEncodeSupportSet(
     84    const MediaCodec& aCodec, const MediaCodecsSupported& aSupported) {
     85  EncodeSupportSet support;
     86  const auto supportInfo = GetCodecDefinition(aCodec);
     87  if (aSupported.contains(supportInfo.swEncodeSupport)) {
     88    support += EncodeSupport::SoftwareEncode;
     89  }
     90  if (aSupported.contains(supportInfo.hwEncodeSupport)) {
     91    support += EncodeSupport::HardwareEncode;
     92  }
     93  return support;
     94 }
     95 
     96 MediaCodecsSupported MCSInfo::GetDecodeMediaCodecsSupported(
     97    const MediaCodec& aCodec, const DecodeSupportSet& aSupportSet) {
     98  MediaCodecsSupported support;
     99  const auto supportInfo = GetCodecDefinition(aCodec);
    100  if (aSupportSet.contains(DecodeSupport::SoftwareDecode)) {
    101    support += supportInfo.swDecodeSupport;
    102  }
    103  if (aSupportSet.contains(DecodeSupport::HardwareDecode)) {
    104    support += supportInfo.hwDecodeSupport;
    105  }
    106  if (aSupportSet.contains(DecodeSupport::UnsureDueToLackOfExtension)) {
    107    support += supportInfo.lackOfHWExtenstion;
    108  }
    109  return support;
    110 }
    111 
    112 MediaCodecsSupported MCSInfo::GetEncodeMediaCodecsSupported(
    113    const MediaCodec& aCodec, const EncodeSupportSet& aSupportSet) {
    114  MediaCodecsSupported support;
    115  const auto supportInfo = GetCodecDefinition(aCodec);
    116  if (aSupportSet.contains(EncodeSupport::SoftwareEncode)) {
    117    support += supportInfo.swEncodeSupport;
    118  }
    119  if (aSupportSet.contains(EncodeSupport::HardwareEncode)) {
    120    support += supportInfo.hwEncodeSupport;
    121  }
    122  if (aSupportSet.contains(EncodeSupport::UnsureDueToLackOfExtension)) {
    123    support += supportInfo.lackOfHWExtenstion;
    124  }
    125  return support;
    126 }
    127 
    128 bool MCSInfo::SupportsSoftwareDecode(
    129    const MediaCodecsSupported& aSupportedCodecs, const MediaCodec& aCodec) {
    130  return (
    131      aSupportedCodecs.contains(GetCodecDefinition(aCodec).swDecodeSupport));
    132 }
    133 
    134 bool MCSInfo::SupportsHardwareDecode(
    135    const MediaCodecsSupported& aSupportedCodecs, const MediaCodec& aCodec) {
    136  return (
    137      aSupportedCodecs.contains(GetCodecDefinition(aCodec).hwDecodeSupport));
    138 }
    139 
    140 bool MCSInfo::SupportsSoftwareEncode(
    141    const MediaCodecsSupported& aSupportedCodecs, const MediaCodec& aCodec) {
    142  return (
    143      aSupportedCodecs.contains(GetCodecDefinition(aCodec).swEncodeSupport));
    144 }
    145 
    146 bool MCSInfo::SupportsHardwareEncode(
    147    const MediaCodecsSupported& aSupportedCodecs, const MediaCodec& aCodec) {
    148  return (
    149      aSupportedCodecs.contains(GetCodecDefinition(aCodec).hwEncodeSupport));
    150 }
    151 
    152 void MCSInfo::GetMediaCodecsSupportedString(
    153    nsCString& aSupportString, const MediaCodecsSupported& aSupportedCodecs) {
    154  CodecDefinition supportInfo;
    155  aSupportString = ""_ns;
    156  MCSInfo* instance = GetInstance();
    157  if (!instance) {
    158    CODEC_SUPPORT_LOG("Can't get codec support string w/o a MCSInfo instance!");
    159    return;
    160  }
    161  for (const auto& it : GetAllCodecDefinitions()) {
    162    if (it.codec == MediaCodec::SENTINEL) {
    163      break;
    164    }
    165    if (!instance->mHashTableCodec->Get(it.codec, &supportInfo)) {
    166      CODEC_SUPPORT_LOG("Can't find codec for MediaCodecsSupported enum: %d",
    167                        static_cast<int>(it.codec));
    168      continue;
    169    }
    170    aSupportString.Append(supportInfo.commonName);
    171    bool foundSupport = false;
    172    if (aSupportedCodecs.contains(it.swDecodeSupport)) {
    173      aSupportString.Append(" SWDEC"_ns);
    174      foundSupport = true;
    175    }
    176    if (aSupportedCodecs.contains(it.hwDecodeSupport)) {
    177      aSupportString.Append(" HWDEC"_ns);
    178      foundSupport = true;
    179    }
    180    if (aSupportedCodecs.contains(it.swEncodeSupport)) {
    181      aSupportString.Append(" SWENC"_ns);
    182      foundSupport = true;
    183    }
    184    if (aSupportedCodecs.contains(it.hwEncodeSupport)) {
    185      aSupportString.Append(" HWENC"_ns);
    186      foundSupport = true;
    187    }
    188    if (aSupportedCodecs.contains(it.lackOfHWExtenstion)) {
    189      aSupportString.Append(" LACK_OF_EXTENSION"_ns);
    190      foundSupport = true;
    191    }
    192    if (!foundSupport) {
    193      aSupportString.Append(" NONE"_ns);
    194    }
    195    aSupportString.Append("\n"_ns);
    196  }
    197  // Remove any trailing newline characters
    198  if (!aSupportString.IsEmpty()) {
    199    aSupportString.Truncate(aSupportString.Length() - 1);
    200  }
    201 }
    202 
    203 MCSInfo* MCSInfo::GetInstance() {
    204  StaticMutexAutoLock lock(sInitMutex);
    205  if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
    206    CODEC_SUPPORT_LOG("In XPCOM shutdown - not returning MCSInfo instance!");
    207    return nullptr;
    208  }
    209  if (!sInstance) {
    210    sInstance = new MCSInfo();
    211  }
    212  return sInstance.get();
    213 }
    214 
    215 MCSInfo::MCSInfo() {
    216  // Initialize hash tables
    217  mHashTableMCS.reset(new nsTHashMap<MediaCodecsSupport, CodecDefinition>());
    218  mHashTableCodec.reset(new nsTHashMap<MediaCodec, CodecDefinition>());
    219 
    220  for (const auto& it : GetAllCodecDefinitions()) {
    221    // Insert MediaCodecsSupport values as keys
    222    mHashTableMCS->InsertOrUpdate(it.swDecodeSupport, it);
    223    mHashTableMCS->InsertOrUpdate(it.hwDecodeSupport, it);
    224    // Insert codec enum values as keys
    225    mHashTableCodec->InsertOrUpdate(it.codec, it);
    226  }
    227 
    228  GetMainThreadSerialEventTarget()->Dispatch(
    229      NS_NewRunnableFunction("MCSInfo::MCSInfo", [&] {
    230        // Ensure hash tables freed on shutdown
    231        RunOnShutdown(
    232            [&] {
    233              mHashTableMCS.reset();
    234              mHashTableString.reset();
    235              mHashTableCodec.reset();
    236              sInstance = nullptr;
    237            },
    238            ShutdownPhase::XPCOMShutdown);
    239      }));
    240 }
    241 
    242 CodecDefinition MCSInfo::GetCodecDefinition(const MediaCodec& aCodec) {
    243  CodecDefinition info;
    244  MCSInfo* instance = GetInstance();
    245  if (!instance) {
    246    CODEC_SUPPORT_LOG("Can't get codec definition without a MCSInfo instance!");
    247  } else if (!instance->mHashTableCodec->Get(aCodec, &info)) {
    248    CODEC_SUPPORT_LOG("Could not find codec definition for codec enum: %d!",
    249                      static_cast<int>(aCodec));
    250  }
    251  return info;
    252 }
    253 
    254 MediaCodecsSupport MCSInfo::GetMediaCodecsSupportEnum(
    255    const MediaCodec& aCodec, const DecodeSupport& aSupport) {
    256  const CodecDefinition cd = GetCodecDefinition(aCodec);
    257  if (aSupport == DecodeSupport::SoftwareDecode) {
    258    return cd.swDecodeSupport;
    259  }
    260  if (aSupport == DecodeSupport::HardwareDecode) {
    261    return cd.hwDecodeSupport;
    262  }
    263  return MediaCodecsSupport::SENTINEL;
    264 }
    265 
    266 MediaCodecsSupport MCSInfo::GetMediaCodecsSupportEnum(
    267    const MediaCodec& aCodec, const EncodeSupport& aSupport) {
    268  const CodecDefinition cd = GetCodecDefinition(aCodec);
    269  if (aSupport == EncodeSupport::SoftwareEncode) {
    270    return cd.swEncodeSupport;
    271  }
    272  if (aSupport == EncodeSupport::HardwareEncode) {
    273    return cd.hwEncodeSupport;
    274  }
    275  return MediaCodecsSupport::SENTINEL;
    276 }
    277 
    278 MediaCodecSet MCSInfo::GetMediaCodecSetFromMimeTypes(
    279    const nsTArray<nsCString>& aCodecStrings) {
    280  MediaCodecSet support;
    281  for (const auto& ms : aCodecStrings) {
    282    const MediaCodec codec = MCSInfo::GetMediaCodecFromMimeType(ms);
    283    if (codec == MediaCodec::SENTINEL) {
    284      continue;
    285    }
    286    MOZ_ASSERT(codec < MediaCodec::SENTINEL);
    287    support += codec;
    288  }
    289  return support;
    290 }
    291 
    292 MediaCodec MCSInfo::GetMediaCodecFromMimeType(const nsACString& aMimeType) {
    293  // Video codecs
    294  if (MP4Decoder::IsH264(aMimeType)) {
    295    return MediaCodec::H264;
    296  }
    297  if (VPXDecoder::IsVP8(aMimeType)) {
    298    return MediaCodec::VP8;
    299  }
    300  if (VPXDecoder::IsVP9(aMimeType)) {
    301    return MediaCodec::VP9;
    302  }
    303  if (MP4Decoder::IsHEVC(aMimeType)) {
    304    return MediaCodec::HEVC;
    305  }
    306 #ifdef MOZ_AV1
    307  if (AOMDecoder::IsAV1(aMimeType)) {
    308    return MediaCodec::AV1;
    309  }
    310  if (aMimeType.EqualsLiteral("video/av01")) {
    311    return MediaCodec::AV1;
    312  }
    313 #endif
    314  // TODO: Should this be Android only?
    315 #ifdef ANDROID
    316  if (aMimeType.EqualsLiteral("video/x-vnd.on2.vp8")) {
    317    return MediaCodec::VP8;
    318  }
    319  if (aMimeType.EqualsLiteral("video/x-vnd.on2.vp9")) {
    320    return MediaCodec::VP9;
    321  }
    322 #endif
    323  // Audio codecs
    324  if (MP4Decoder::IsAAC(aMimeType)) {
    325    return MediaCodec::AAC;
    326  }
    327  if (aMimeType.EqualsLiteral("audio/vorbis")) {
    328    return MediaCodec::Vorbis;
    329  }
    330  if (aMimeType.EqualsLiteral("audio/flac")) {
    331    return MediaCodec::FLAC;
    332  }
    333  if (IsWaveMimetype(aMimeType)) {
    334    return MediaCodec::Wave;
    335  }
    336  if (aMimeType.EqualsLiteral("audio/opus")) {
    337    return MediaCodec::Opus;
    338  }
    339  if (aMimeType.EqualsLiteral("audio/mpeg")) {
    340    return MediaCodec::MP3;
    341  }
    342 
    343  CODEC_SUPPORT_LOG("No specific codec enum for MIME type string: %s",
    344                    nsCString(aMimeType).get());
    345  return MediaCodec::SENTINEL;
    346 }
    347 
    348 #define MEDIA_CODEC_DEF_ENTRY_META(name, mimeType, lackOfExt) \
    349  {MediaCodec::name,                                          \
    350   #name,                                                     \
    351   mimeType,                                                  \
    352   MediaCodecsSupport::name##SoftwareDecode,                  \
    353   MediaCodecsSupport::name##HardwareDecode,                  \
    354   MediaCodecsSupport::name##SoftwareEncode,                  \
    355   MediaCodecsSupport::name##HardwareEncode,                  \
    356   MediaCodecsSupport::lackOfExt}
    357 
    358 #define MEDIA_CODEC_DEF_ENTRY(name, mimeType) \
    359  MEDIA_CODEC_DEF_ENTRY_META(name, mimeType, SENTINEL)
    360 
    361 #define MEDIA_CODEC_DEF_ENTRY_LACKOFEXT(name, mimeType) \
    362  MEDIA_CODEC_DEF_ENTRY_META(name, mimeType, name##LackOfExtension)
    363 
    364 std::array<CodecDefinition, 13> MCSInfo::GetAllCodecDefinitions() {
    365  static constexpr std::array<CodecDefinition, 13> codecDefinitions = {
    366      {MEDIA_CODEC_DEF_ENTRY(H264, "video/avc"),
    367       MEDIA_CODEC_DEF_ENTRY(VP9, "video/vp9"),
    368       MEDIA_CODEC_DEF_ENTRY(VP8, "video/vp8"),
    369       MEDIA_CODEC_DEF_ENTRY_LACKOFEXT(AV1, "video/av1"),
    370       MEDIA_CODEC_DEF_ENTRY(HEVC, "video/hevc"),
    371       MEDIA_CODEC_DEF_ENTRY(AAC, "audio/mp4a-latm"),
    372       MEDIA_CODEC_DEF_ENTRY(MP3, "audio/mpeg"),
    373       MEDIA_CODEC_DEF_ENTRY(Opus, "audio/opus"),
    374       MEDIA_CODEC_DEF_ENTRY(Vorbis, "audio/vorbis"),
    375       MEDIA_CODEC_DEF_ENTRY(FLAC, "audio/flac"),
    376       MEDIA_CODEC_DEF_ENTRY(Wave, "audio/x-wav")}};
    377  return codecDefinitions;
    378 }
    379 
    380 #undef MEDIA_CODEC_DEF_ENTRY_LACKOFEXT
    381 #undef MEDIA_CODEC_DEF_ENTRY
    382 #undef MEDIA_CODEC_DEF_ENTRY_META
    383 
    384 }  // namespace mozilla::media
    385 
    386 #undef CODEC_SUPPORT_LOG