tor-browser

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

AndroidDecoderModule.cpp (12501B)


      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 <jni.h>
      8 
      9 #ifdef MOZ_AV1
     10 #  include "AOMDecoder.h"
     11 #endif
     12 #include "MediaInfo.h"
     13 #include "RemoteDataDecoder.h"
     14 #include "VPXDecoder.h"
     15 #include "mozilla/ClearOnShutdown.h"
     16 #include "mozilla/Components.h"
     17 #include "mozilla/StaticPrefs_media.h"
     18 #include "mozilla/gfx/gfxVars.h"
     19 #include "mozilla/java/GeckoAppShellWrappers.h"
     20 #include "mozilla/java/HardwareCodecCapabilityUtilsWrappers.h"
     21 #include "nsIGfxInfo.h"
     22 #include "nsPromiseFlatString.h"
     23 #include "prlog.h"
     24 
     25 #undef LOG
     26 #define LOG(arg, ...)                                     \
     27  MOZ_LOG(                                                \
     28      sAndroidDecoderModuleLog, mozilla::LogLevel::Debug, \
     29      ("AndroidDecoderModule(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
     30 #define SLOG(arg, ...)                                        \
     31  MOZ_LOG(sAndroidDecoderModuleLog, mozilla::LogLevel::Debug, \
     32          ("%s: " arg, __func__, ##__VA_ARGS__))
     33 
     34 using namespace mozilla;
     35 using media::DecodeSupport;
     36 using media::DecodeSupportSet;
     37 using media::MCSInfo;
     38 using media::MediaCodec;
     39 using media::MediaCodecsSupport;
     40 using media::MediaCodecsSupported;
     41 using media::TimeUnit;
     42 
     43 namespace mozilla {
     44 
     45 mozilla::LazyLogModule sAndroidDecoderModuleLog("AndroidDecoderModule");
     46 
     47 nsCString TranslateMimeType(const nsACString& aMimeType) {
     48  if (VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP8)) {
     49    static constexpr auto vp8 = "video/x-vnd.on2.vp8"_ns;
     50    return vp8;
     51  }
     52  if (VPXDecoder::IsVPX(aMimeType, VPXDecoder::VP9)) {
     53    static constexpr auto vp9 = "video/x-vnd.on2.vp9"_ns;
     54    return vp9;
     55  }
     56  if (aMimeType.EqualsLiteral("video/av1")) {
     57    static constexpr auto av1 = "video/av01"_ns;
     58    return av1;
     59  }
     60  return nsCString(aMimeType);
     61 }
     62 
     63 AndroidDecoderModule::AndroidDecoderModule(CDMProxy* aProxy) {
     64  mProxy = static_cast<MediaDrmCDMProxy*>(aProxy);
     65 }
     66 
     67 /* static */ bool AndroidDecoderModule::AreSupportedMimeTypesReady() {
     68  StaticMutexAutoLock lock(sMutex);
     69  return sSupportedSwMimeTypes && sSupportedHwMimeTypes;
     70 }
     71 
     72 /* static */ bool AndroidDecoderModule::IsSupportedCodecsReady() {
     73  StaticMutexAutoLock lock(sMutex);
     74  return sSupportedCodecs;
     75 }
     76 
     77 /* static */
     78 media::MediaCodecsSupported AndroidDecoderModule::GetSupportedCodecs() {
     79  if (!AreSupportedMimeTypesReady() || !IsSupportedCodecsReady()) {
     80    SetSupportedMimeTypes();
     81  }
     82  StaticMutexAutoLock lock(sMutex);
     83  return *sSupportedCodecs;
     84 }
     85 
     86 DecodeSupportSet AndroidDecoderModule::SupportsMimeType(
     87    const nsACString& aMimeType) {
     88  if (!AreSupportedMimeTypesReady()) {
     89    SetSupportedMimeTypes();
     90  }
     91 
     92  // Handle per-codec logic if the codec type can be determined from
     93  // the MIME type string. GetMediaCodecFromMimeType should handle every
     94  // type string that was hardcoded in this function previously.
     95  MediaCodec codec = MCSInfo::GetMediaCodecFromMimeType(aMimeType);
     96  switch (codec) {
     97    case MediaCodec::VP8:
     98      if (!gfx::gfxVars::UseVP8HwDecode()) {
     99        return media::DecodeSupportSet{};
    100      }
    101      break;
    102 
    103    case MediaCodec::VP9:
    104      if (!gfx::gfxVars::UseVP9HwDecode()) {
    105        return media::DecodeSupportSet{};
    106      }
    107      break;
    108 
    109    // Prefer the gecko decoder for opus/vorbis; stagefright crashes
    110    // on content demuxed from mp4.
    111    // Not all android devices support FLAC even when they say they do.
    112    // Always use our own software decoder (in ffvpx) for audio except for AAC
    113    case MediaCodec::MP3:
    114      [[fallthrough]];
    115    case MediaCodec::Opus:
    116      [[fallthrough]];
    117    case MediaCodec::Vorbis:
    118      [[fallthrough]];
    119    case MediaCodec::Wave:
    120      [[fallthrough]];
    121    case MediaCodec::FLAC:
    122      SLOG("Rejecting audio of type %s", aMimeType.Data());
    123      return media::DecodeSupportSet{};
    124 
    125    // H264 always reports software decode
    126    case MediaCodec::H264:
    127      return DecodeSupport::SoftwareDecode;
    128 
    129    case MediaCodec::HEVC:
    130      if (!StaticPrefs::media_hevc_enabled()) {
    131        SLOG("Rejecting HEVC as the preference is disabled");
    132        return media::DecodeSupportSet{};
    133      }
    134      break;
    135 
    136    // AV1 doesn't need any special handling.
    137    case MediaCodec::AV1:
    138      break;
    139 
    140    case MediaCodec::SENTINEL:
    141      [[fallthrough]];
    142    default:
    143      SLOG("Support check using default logic for %s", aMimeType.Data());
    144      break;
    145  }
    146 
    147  // If a codec has no special handling or can't be determined from the
    148  // MIME type string, check if the MIME type string itself is supported.
    149  {
    150    StaticMutexAutoLock lock(sMutex);
    151    if (sSupportedHwMimeTypes &&
    152        sSupportedHwMimeTypes->Contains(TranslateMimeType(aMimeType))) {
    153      return DecodeSupport::HardwareDecode;
    154    }
    155    if (sSupportedSwMimeTypes &&
    156        sSupportedSwMimeTypes->Contains(TranslateMimeType(aMimeType))) {
    157      return DecodeSupport::SoftwareDecode;
    158    }
    159  }
    160  return media::DecodeSupportSet{};
    161 }
    162 
    163 nsTArray<nsCString> AndroidDecoderModule::GetSupportedMimeTypes() {
    164  mozilla::jni::ObjectArray::LocalRef supportedTypes = mozilla::java::
    165      HardwareCodecCapabilityUtils::GetDecoderSupportedMimeTypes();
    166 
    167  nsTArray<nsCString> st = nsTArray<nsCString>();
    168  for (size_t i = 0; i < supportedTypes->Length(); i++) {
    169    st.AppendElement(
    170        jni::String::LocalRef(supportedTypes->GetElement(i))->ToCString());
    171  }
    172 
    173  return st;
    174 }
    175 
    176 nsTArray<nsCString> AndroidDecoderModule::GetSupportedMimeTypesPrefixed() {
    177  mozilla::jni::ObjectArray::LocalRef supportedTypes = mozilla::java::
    178      HardwareCodecCapabilityUtils::GetDecoderSupportedMimeTypesWithAccelInfo();
    179 
    180  nsTArray<nsCString> st = nsTArray<nsCString>();
    181  for (size_t i = 0; i < supportedTypes->Length(); i++) {
    182    st.AppendElement(
    183        jni::String::LocalRef(supportedTypes->GetElement(i))->ToCString());
    184  }
    185 
    186  return st;
    187 }
    188 
    189 void AndroidDecoderModule::SetSupportedMimeTypes() {
    190  SetSupportedMimeTypes(GetSupportedMimeTypesPrefixed());
    191 }
    192 
    193 // Inbound MIME types prefixed with SW/HW need to be processed
    194 void AndroidDecoderModule::SetSupportedMimeTypes(
    195    nsTArray<nsCString>&& aSupportedTypes) {
    196  StaticMutexAutoLock lock(sMutex);
    197  // Return if support is already cached
    198  if (sSupportedSwMimeTypes && sSupportedHwMimeTypes && sSupportedCodecs) {
    199    return;
    200  }
    201  if (!sSupportedSwMimeTypes) {
    202    sSupportedSwMimeTypes = new nsTArray<nsCString>;
    203    if (NS_IsMainThread()) {
    204      ClearOnShutdown(&sSupportedSwMimeTypes);
    205    } else {
    206      (void)NS_DispatchToMainThread(NS_NewRunnableFunction(__func__, []() {
    207        StaticMutexAutoLock lock(sMutex);
    208        ClearOnShutdown(&sSupportedSwMimeTypes);
    209      }));
    210    }
    211  }
    212  if (!sSupportedHwMimeTypes) {
    213    sSupportedHwMimeTypes = new nsTArray<nsCString>;
    214    if (NS_IsMainThread()) {
    215      ClearOnShutdown(&sSupportedHwMimeTypes);
    216    } else {
    217      (void)NS_DispatchToMainThread(NS_NewRunnableFunction(__func__, []() {
    218        StaticMutexAutoLock lock(sMutex);
    219        ClearOnShutdown(&sSupportedHwMimeTypes);
    220      }));
    221    }
    222  }
    223  if (!sSupportedCodecs) {
    224    sSupportedCodecs = new MediaCodecsSupported();
    225    if (NS_IsMainThread()) {
    226      ClearOnShutdown(&sSupportedCodecs);
    227    } else {
    228      (void)NS_DispatchToMainThread(NS_NewRunnableFunction(__func__, []() {
    229        StaticMutexAutoLock lock(sMutex);
    230        ClearOnShutdown(&sSupportedCodecs);
    231      }));
    232    }
    233  }
    234 
    235  // Process each MIME type string
    236  for (const auto& s : aSupportedTypes) {
    237    // Verify MIME type string present
    238    if (s.Length() < 4) {
    239      SLOG("No SW/HW support prefix found in codec string %s", s.Data());
    240      continue;
    241    }
    242    const auto mimeType = Substring(s, 3);
    243    if (mimeType.Length() == 0) {
    244      SLOG("No MIME type information found in codec string %s", s.Data());
    245      continue;
    246    }
    247 
    248    // Extract SW/HW support prefix
    249    const auto caps = Substring(s, 0, 2);
    250    DecodeSupport support{};
    251    if (caps == "SW"_ns) {
    252      sSupportedSwMimeTypes->AppendElement(mimeType);
    253      support = DecodeSupport::SoftwareDecode;
    254    } else if (caps == "HW"_ns) {
    255      sSupportedHwMimeTypes->AppendElement(mimeType);
    256      support = DecodeSupport::HardwareDecode;
    257    } else {
    258      SLOG("Error parsing acceleration info from JNI codec string %s",
    259           s.Data());
    260      continue;
    261    }
    262    const MediaCodec codec = MCSInfo::GetMediaCodecFromMimeType(mimeType);
    263    if (codec == MediaCodec::SENTINEL) {
    264      SLOG("Did not parse string %s to specific codec", s.Data());
    265      continue;
    266    }
    267    *sSupportedCodecs += MCSInfo::GetMediaCodecsSupportEnum(codec, support);
    268  }
    269 }
    270 
    271 DecodeSupportSet AndroidDecoderModule::SupportsMimeType(
    272    const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const {
    273  return AndroidDecoderModule::SupportsMimeType(aMimeType);
    274 }
    275 
    276 bool AndroidDecoderModule::SupportsColorDepth(
    277    gfx::ColorDepth aColorDepth, DecoderDoctorDiagnostics* aDiagnostics) const {
    278  // 10-bit support is codec dependent so this is not entirely accurate.
    279  // Supports() will correct it.
    280  return aColorDepth == gfx::ColorDepth::COLOR_8 ||
    281         aColorDepth == gfx::ColorDepth::COLOR_10;
    282 }
    283 
    284 // Further check is needed because the base class uses the inaccurate
    285 // SupportsColorDepth().
    286 media::DecodeSupportSet AndroidDecoderModule::Supports(
    287    const SupportDecoderParams& aParams,
    288    DecoderDoctorDiagnostics* aDiagnostics) const {
    289  media::DecodeSupportSet support =
    290      PlatformDecoderModule::Supports(aParams, aDiagnostics);
    291 
    292  // Short-circuit.
    293  if (support.isEmpty()) {
    294    return support;
    295  }
    296 
    297 #ifdef MOZ_AV1
    298  // For AV1, only allow HW decoder.
    299  if (AOMDecoder::IsAV1(aParams.MimeType()) &&
    300      (!StaticPrefs::media_av1_enabled() ||
    301       !support.contains(media::DecodeSupport::HardwareDecode))) {
    302    return media::DecodeSupportSet{};
    303  }
    304 #endif
    305 
    306  // Check 10-bit video.
    307  const TrackInfo& trackInfo = aParams.mConfig;
    308  const VideoInfo* videoInfo = trackInfo.GetAsVideoInfo();
    309  if (!videoInfo || videoInfo->mColorDepth != gfx::ColorDepth::COLOR_10) {
    310    return support;
    311  }
    312 
    313  return java::HardwareCodecCapabilityUtils::Decodes10Bit(
    314             TranslateMimeType(aParams.MimeType()))
    315             ? support
    316             : media::DecodeSupportSet{};
    317 }
    318 
    319 already_AddRefed<MediaDataDecoder> AndroidDecoderModule::CreateVideoDecoder(
    320    const CreateDecoderParams& aParams) {
    321  // Temporary - forces use of VPXDecoder when alpha is present.
    322  // Bug 1263836 will handle alpha scenario once implemented. It will shift
    323  // the check for alpha to PDMFactory but not itself remove the need for a
    324  // check.
    325  if (aParams.VideoConfig().HasAlpha()) {
    326    return nullptr;
    327  }
    328 
    329  if (AOMDecoder::IsAV1(aParams.mConfig.mMimeType) &&
    330      !AOMDecoder::IsMainProfile(aParams.VideoConfig().mExtraData)) {
    331    return nullptr;
    332  }
    333 
    334  // Don't use SW VPX MediaCodecs. Prefering VPXDecoder over MediaCodec SW
    335  // decoder implementation allow us to have more consistent cross-platform VPX
    336  // playback experience and be able to get upstream bug fixes/improvements more
    337  // frequently.
    338  if (VPXDecoder::IsVPX(aParams.VideoConfig().mMimeType) &&
    339      !SupportsMimeType(aParams.VideoConfig().mMimeType)
    340           .contains(DecodeSupport::HardwareDecode)) {
    341    return nullptr;
    342  }
    343 
    344  nsString drmStubId;
    345  if (mProxy) {
    346    drmStubId = mProxy->GetMediaDrmStubId();
    347  }
    348 
    349  RefPtr<MediaDataDecoder> decoder =
    350      RemoteDataDecoder::CreateVideoDecoder(aParams, drmStubId, mProxy);
    351  return decoder.forget();
    352 }
    353 
    354 // static
    355 bool AndroidDecoderModule::IsJavaDecoderModuleAllowed() {
    356  return StaticPrefs::media_android_media_codec_enabled() &&
    357         !java::GeckoAppShell::IsIsolatedProcess();
    358 }
    359 
    360 already_AddRefed<MediaDataDecoder> AndroidDecoderModule::CreateAudioDecoder(
    361    const CreateDecoderParams& aParams) {
    362  const AudioInfo& config = aParams.AudioConfig();
    363  LOG("CreateAudioFormat with mimeType=%s, mRate=%d, channels=%d",
    364      config.mMimeType.Data(), config.mRate, config.mChannels);
    365 
    366  nsString drmStubId;
    367  if (mProxy) {
    368    drmStubId = mProxy->GetMediaDrmStubId();
    369  }
    370  RefPtr<MediaDataDecoder> decoder =
    371      RemoteDataDecoder::CreateAudioDecoder(aParams, drmStubId, mProxy);
    372  return decoder.forget();
    373 }
    374 
    375 /* static */
    376 already_AddRefed<PlatformDecoderModule> AndroidDecoderModule::Create(
    377    CDMProxy* aProxy) {
    378  return MakeAndAddRef<AndroidDecoderModule>(aProxy);
    379 }
    380 
    381 }  // namespace mozilla