tor-browser

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

PEMFactory.cpp (17114B)


      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 "PEMFactory.h"
      8 
      9 #include "PlatformEncoderModule.h"
     10 
     11 #ifdef MOZ_APPLEMEDIA
     12 #  include "AppleEncoderModule.h"
     13 #endif
     14 
     15 #ifdef MOZ_WIDGET_ANDROID
     16 #  include "AndroidDecoderModule.h"
     17 #  include "AndroidEncoderModule.h"
     18 #endif
     19 
     20 #ifdef XP_WIN
     21 #  include "WMFEncoderModule.h"
     22 #endif
     23 
     24 #ifdef MOZ_FFMPEG
     25 #  include "FFmpegRuntimeLinker.h"
     26 #endif
     27 
     28 #include "FFVPXRuntimeLinker.h"
     29 #include "GMPEncoderModule.h"
     30 #include "mozilla/RemoteEncoderModule.h"
     31 #include "mozilla/StaticMutex.h"
     32 #include "mozilla/StaticPrefs_media.h"
     33 #include "mozilla/gfx/gfxVars.h"
     34 
     35 using namespace mozilla::media;
     36 
     37 namespace mozilla {
     38 
     39 LazyLogModule sPEMLog("PlatformEncoderModule");
     40 
     41 #define LOGE(fmt, ...)                       \
     42  MOZ_LOG(sPEMLog, mozilla::LogLevel::Error, \
     43          ("[PEMFactory] %s: " fmt, __func__, ##__VA_ARGS__))
     44 #define LOG(fmt, ...)                        \
     45  MOZ_LOG(sPEMLog, mozilla::LogLevel::Debug, \
     46          ("[PEMFactory] %s: " fmt, __func__, ##__VA_ARGS__))
     47 
     48 static CodecType MediaCodecToCodecType(MediaCodec aCodec) {
     49  switch (aCodec) {
     50    case MediaCodec::H264:
     51      return CodecType::H264;
     52    case MediaCodec::VP8:
     53      return CodecType::VP8;
     54    case MediaCodec::VP9:
     55      return CodecType::VP9;
     56    case MediaCodec::AV1:
     57      return CodecType::AV1;
     58    case MediaCodec::HEVC:
     59      return CodecType::H265;
     60    case MediaCodec::AAC:
     61      return CodecType::AAC;
     62    case MediaCodec::FLAC:
     63      return CodecType::Flac;
     64    case MediaCodec::Opus:
     65      return CodecType::Opus;
     66    case MediaCodec::Vorbis:
     67      return CodecType::Vorbis;
     68    case MediaCodec::MP3:
     69    case MediaCodec::Wave:
     70    case MediaCodec::SENTINEL:
     71      return CodecType::Unknown;
     72    default:
     73      MOZ_ASSERT_UNREACHABLE("Unhandled MediaCodec type!");
     74      return CodecType::Unknown;
     75  }
     76 }
     77 
     78 void PEMFactory::InitGpuPEMs() {
     79  if (!StaticPrefs::media_use_remote_encoder_video()) {
     80    return;
     81  }
     82 
     83 #ifdef MOZ_APPLEMEDIA
     84  if (StaticPrefs::media_gpu_process_encoder()) {
     85    RefPtr<PlatformEncoderModule> m(new AppleEncoderModule());
     86    mCurrentPEMs.AppendElement(m);
     87  }
     88 #endif
     89 
     90 #ifdef XP_WIN
     91  if (StaticPrefs::media_wmf_enabled() &&
     92      StaticPrefs::media_gpu_process_encoder()) {
     93    mCurrentPEMs.AppendElement(new WMFEncoderModule());
     94  }
     95 #endif
     96 
     97 #ifndef MOZ_FFVPX_AUDIOONLY
     98  if (StaticPrefs::media_ffmpeg_encoder_enabled() &&
     99      StaticPrefs::media_gpu_process_encoder()) {
    100    if (RefPtr<PlatformEncoderModule> pem =
    101            FFVPXRuntimeLinker::CreateEncoder()) {
    102      mCurrentPEMs.AppendElement(pem);
    103    }
    104  }
    105 #endif
    106 
    107 #ifdef MOZ_FFMPEG
    108  if (StaticPrefs::media_ffmpeg_encoder_enabled() &&
    109      StaticPrefs::media_gpu_process_encoder()) {
    110    if (RefPtr<PlatformEncoderModule> pem =
    111            FFmpegRuntimeLinker::CreateEncoder()) {
    112      mCurrentPEMs.AppendElement(pem);
    113    }
    114  }
    115 #endif
    116 }
    117 
    118 void PEMFactory::InitRddPEMs() {
    119 #ifdef MOZ_APPLEMEDIA
    120  if (StaticPrefs::media_use_remote_encoder_video() &&
    121      StaticPrefs::media_rdd_applemedia_enabled()) {
    122    RefPtr<PlatformEncoderModule> m(new AppleEncoderModule());
    123    mCurrentPEMs.AppendElement(m);
    124  }
    125 #endif
    126 
    127 #ifdef XP_WIN
    128  if (StaticPrefs::media_use_remote_encoder_video() &&
    129      StaticPrefs::media_wmf_enabled() &&
    130      StaticPrefs::media_rdd_wmf_enabled()) {
    131    mCurrentPEMs.AppendElement(new WMFEncoderModule());
    132  }
    133 #endif
    134 
    135 #ifdef MOZ_FFVPX_AUDIOONLY
    136  if (StaticPrefs::media_use_remote_encoder_audio() &&
    137      StaticPrefs::media_ffmpeg_encoder_enabled() &&
    138      !StaticPrefs::media_utility_process_enabled() &&
    139      StaticPrefs::media_rdd_ffvpx_enabled())
    140 #else
    141  if (((StaticPrefs::media_use_remote_encoder_audio() &&
    142        !StaticPrefs::media_utility_process_enabled()) ||
    143       StaticPrefs::media_use_remote_encoder_video()) &&
    144      StaticPrefs::media_ffmpeg_encoder_enabled() &&
    145      StaticPrefs::media_rdd_ffvpx_enabled())
    146 #endif
    147  {
    148    if (RefPtr<PlatformEncoderModule> pem =
    149            FFVPXRuntimeLinker::CreateEncoder()) {
    150      mCurrentPEMs.AppendElement(pem);
    151    }
    152  }
    153 
    154 #ifdef MOZ_FFMPEG
    155 #  ifdef MOZ_FFVPX_AUDIOONLY
    156  if (StaticPrefs::media_use_remote_encoder_audio() &&
    157      StaticPrefs::media_ffmpeg_encoder_enabled() &&
    158      !StaticPrefs::media_utility_process_enabled() &&
    159      StaticPrefs::media_rdd_ffmpeg_enabled())
    160 #  else
    161  if (((StaticPrefs::media_use_remote_encoder_audio() &&
    162        !StaticPrefs::media_utility_process_enabled()) ||
    163       StaticPrefs::media_use_remote_encoder_video()) &&
    164      StaticPrefs::media_ffmpeg_encoder_enabled() &&
    165      StaticPrefs::media_rdd_ffmpeg_enabled())
    166 #  endif
    167  {
    168    if (StaticPrefs::media_ffmpeg_enabled()) {
    169      if (RefPtr<PlatformEncoderModule> pem =
    170              FFmpegRuntimeLinker::CreateEncoder()) {
    171        mCurrentPEMs.AppendElement(pem);
    172      }
    173    }
    174  }
    175 #endif
    176 }
    177 
    178 void PEMFactory::InitUtilityPEMs() {
    179  if (StaticPrefs::media_use_remote_encoder_audio() &&
    180      StaticPrefs::media_ffmpeg_encoder_enabled()) {
    181    if (RefPtr<PlatformEncoderModule> pem =
    182            FFVPXRuntimeLinker::CreateEncoder()) {
    183      mCurrentPEMs.AppendElement(pem);
    184    }
    185  }
    186 
    187 #ifdef MOZ_FFMPEG
    188  if (StaticPrefs::media_use_remote_encoder_audio() &&
    189      StaticPrefs::media_ffmpeg_enabled()) {
    190    if (RefPtr<PlatformEncoderModule> pem =
    191            FFmpegRuntimeLinker::CreateEncoder()) {
    192      mCurrentPEMs.AppendElement(pem);
    193    }
    194  }
    195 #endif
    196 }
    197 
    198 void PEMFactory::InitContentPEMs() {
    199  if ((StaticPrefs::media_use_remote_encoder_video() ||
    200       StaticPrefs::media_use_remote_encoder_audio()) &&
    201      StaticPrefs::media_rdd_process_enabled()) {
    202    if (RefPtr<PlatformEncoderModule> pem =
    203            RemoteEncoderModule::Create(RemoteMediaIn::RddProcess)) {
    204      mCurrentPEMs.AppendElement(std::move(pem));
    205    }
    206  }
    207 
    208  if (StaticPrefs::media_use_remote_encoder_audio() &&
    209      StaticPrefs::media_utility_process_enabled()) {
    210 #ifdef MOZ_APPLEMEDIA
    211    if (RefPtr<PlatformEncoderModule> pem = RemoteEncoderModule::Create(
    212            RemoteMediaIn::UtilityProcess_AppleMedia)) {
    213      mCurrentPEMs.AppendElement(std::move(pem));
    214    }
    215 #endif
    216 
    217 #ifdef XP_WIN
    218    if (RefPtr<PlatformEncoderModule> pem =
    219            RemoteEncoderModule::Create(RemoteMediaIn::UtilityProcess_WMF)) {
    220      mCurrentPEMs.AppendElement(std::move(pem));
    221    }
    222 #endif
    223 
    224    if (RefPtr<PlatformEncoderModule> pem = RemoteEncoderModule::Create(
    225            RemoteMediaIn::UtilityProcess_Generic)) {
    226      mCurrentPEMs.AppendElement(std::move(pem));
    227    }
    228  }
    229 
    230  if (!StaticPrefs::media_use_remote_encoder_video()) {
    231 #ifdef MOZ_APPLEMEDIA
    232    RefPtr<PlatformEncoderModule> m(new AppleEncoderModule());
    233    mCurrentPEMs.AppendElement(m);
    234 #endif
    235 
    236 #ifdef MOZ_WIDGET_ANDROID
    237    if (AndroidDecoderModule::IsJavaDecoderModuleAllowed()) {
    238      mCurrentPEMs.AppendElement(new AndroidEncoderModule());
    239    }
    240 #endif
    241 
    242 #ifdef XP_WIN
    243    mCurrentPEMs.AppendElement(new WMFEncoderModule());
    244 #endif
    245  }
    246 
    247 #ifdef MOZ_FFVPX_AUDIOONLY
    248  if (!StaticPrefs::media_use_remote_encoder_audio() &&
    249      StaticPrefs::media_ffmpeg_encoder_enabled())
    250 #else
    251  if ((!StaticPrefs::media_use_remote_encoder_audio() ||
    252       !StaticPrefs::media_use_remote_encoder_video()) &&
    253      StaticPrefs::media_ffmpeg_encoder_enabled())
    254 #endif
    255  {
    256    if (RefPtr<PlatformEncoderModule> pem =
    257            FFVPXRuntimeLinker::CreateEncoder()) {
    258      mCurrentPEMs.AppendElement(pem);
    259    }
    260  }
    261 
    262 #ifdef MOZ_FFMPEG
    263 #  ifdef MOZ_FFVPX_AUDIOONLY
    264  if (!StaticPrefs::media_use_remote_encoder_audio() &&
    265      StaticPrefs::media_ffmpeg_enabled() &&
    266      StaticPrefs::media_ffmpeg_encoder_enabled())
    267 #  else
    268  if ((!StaticPrefs::media_use_remote_encoder_audio() ||
    269       !StaticPrefs::media_use_remote_encoder_video()) &&
    270      StaticPrefs::media_ffmpeg_enabled() &&
    271      StaticPrefs::media_ffmpeg_encoder_enabled())
    272 #  endif
    273  {
    274    if (RefPtr<PlatformEncoderModule> pem =
    275            FFmpegRuntimeLinker::CreateEncoder()) {
    276      mCurrentPEMs.AppendElement(pem);
    277    }
    278  }
    279 #endif
    280 
    281  if (StaticPrefs::media_gmp_encoder_enabled()) {
    282    auto pem = MakeRefPtr<GMPEncoderModule>();
    283    if (StaticPrefs::media_gmp_encoder_preferred()) {
    284      mCurrentPEMs.InsertElementAt(0, std::move(pem));
    285    } else {
    286      mCurrentPEMs.AppendElement(std::move(pem));
    287    }
    288  }
    289 }
    290 
    291 void PEMFactory::InitDefaultPEMs() {
    292 #ifdef MOZ_APPLEMEDIA
    293  RefPtr<PlatformEncoderModule> m(new AppleEncoderModule());
    294  mCurrentPEMs.AppendElement(m);
    295 #endif
    296 
    297 #ifdef MOZ_WIDGET_ANDROID
    298  if (AndroidDecoderModule::IsJavaDecoderModuleAllowed()) {
    299    mCurrentPEMs.AppendElement(new AndroidEncoderModule());
    300  }
    301 #endif
    302 
    303 #ifdef XP_WIN
    304  mCurrentPEMs.AppendElement(new WMFEncoderModule());
    305 #endif
    306 
    307  if (StaticPrefs::media_ffmpeg_encoder_enabled()) {
    308    if (RefPtr<PlatformEncoderModule> pem =
    309            FFVPXRuntimeLinker::CreateEncoder()) {
    310      mCurrentPEMs.AppendElement(pem);
    311    }
    312  }
    313 
    314 #ifdef MOZ_FFMPEG
    315  if (StaticPrefs::media_ffmpeg_enabled() &&
    316      StaticPrefs::media_ffmpeg_encoder_enabled()) {
    317    if (RefPtr<PlatformEncoderModule> pem =
    318            FFmpegRuntimeLinker::CreateEncoder()) {
    319      mCurrentPEMs.AppendElement(pem);
    320    }
    321  }
    322 #endif
    323 
    324  if (StaticPrefs::media_gmp_encoder_enabled()) {
    325    auto pem = MakeRefPtr<GMPEncoderModule>();
    326    if (StaticPrefs::media_gmp_encoder_preferred()) {
    327      mCurrentPEMs.InsertElementAt(0, std::move(pem));
    328    } else {
    329      mCurrentPEMs.AppendElement(std::move(pem));
    330    }
    331  }
    332 }
    333 
    334 PEMFactory::PEMFactory() {
    335  gfx::gfxVars::Initialize();
    336 
    337  if (XRE_IsGPUProcess()) {
    338    InitGpuPEMs();
    339  } else if (XRE_IsRDDProcess()) {
    340    InitRddPEMs();
    341  } else if (XRE_IsUtilityProcess()) {
    342    InitUtilityPEMs();
    343  } else if (XRE_IsContentProcess()) {
    344    InitContentPEMs();
    345  } else {
    346    InitDefaultPEMs();
    347  }
    348 }
    349 
    350 already_AddRefed<MediaDataEncoder> PEMFactory::CreateEncoder(
    351    const EncoderConfig& aConfig, const RefPtr<TaskQueue>& aTaskQueue) {
    352  RefPtr<PlatformEncoderModule> m = FindPEM(aConfig);
    353  if (!m) {
    354    return nullptr;
    355  }
    356 
    357  return aConfig.IsVideo() ? m->CreateVideoEncoder(aConfig, aTaskQueue)
    358                           : nullptr;
    359 }
    360 
    361 RefPtr<PlatformEncoderModule::CreateEncoderPromise>
    362 PEMFactory::CreateEncoderAsync(const EncoderConfig& aConfig,
    363                               const RefPtr<TaskQueue>& aTaskQueue) {
    364  return CheckAndMaybeCreateEncoder(aConfig, 0, aTaskQueue);
    365 }
    366 
    367 RefPtr<PlatformEncoderModule::CreateEncoderPromise>
    368 PEMFactory::CheckAndMaybeCreateEncoder(const EncoderConfig& aConfig,
    369                                       uint32_t aIndex,
    370                                       const RefPtr<TaskQueue>& aTaskQueue) {
    371  for (uint32_t i = aIndex; i < mCurrentPEMs.Length(); i++) {
    372    if (mCurrentPEMs[i]->Supports(aConfig).isEmpty()) {
    373      continue;
    374    }
    375    return CreateEncoderWithPEM(mCurrentPEMs[i], aConfig, aTaskQueue)
    376        ->Then(
    377            GetCurrentSerialEventTarget(), __func__,
    378            [](RefPtr<MediaDataEncoder>&& aEncoder) {
    379              return PlatformEncoderModule::CreateEncoderPromise::
    380                  CreateAndResolve(std::move(aEncoder), __func__);
    381            },
    382            [self = RefPtr{this}, i, config = aConfig,
    383             aTaskQueue](const MediaResult& aError) mutable {
    384              // Try the next PEM.
    385              return self->CheckAndMaybeCreateEncoder(config, i + 1,
    386                                                      aTaskQueue);
    387            });
    388  }
    389  return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject(
    390      MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
    391                  nsPrintfCString("Error no encoder found for %s",
    392                                  EnumValueToString(aConfig.mCodec))
    393                      .get()),
    394      __func__);
    395 }
    396 
    397 RefPtr<PlatformEncoderModule::CreateEncoderPromise>
    398 PEMFactory::CreateEncoderWithPEM(PlatformEncoderModule* aPEM,
    399                                 const EncoderConfig& aConfig,
    400                                 const RefPtr<TaskQueue>& aTaskQueue) {
    401  MOZ_ASSERT(aPEM);
    402  MediaResult result = NS_OK;
    403 
    404  if (aConfig.IsAudio()) {
    405    return aPEM->AsyncCreateEncoder(aConfig, aTaskQueue)
    406        ->Then(
    407            GetCurrentSerialEventTarget(), __func__,
    408            [config = aConfig](RefPtr<MediaDataEncoder>&& aEncoder) {
    409              RefPtr<MediaDataEncoder> decoder = std::move(aEncoder);
    410              return PlatformEncoderModule::CreateEncoderPromise::
    411                  CreateAndResolve(decoder, __func__);
    412            },
    413            [](const MediaResult& aError) {
    414              return PlatformEncoderModule::CreateEncoderPromise::
    415                  CreateAndReject(aError, __func__);
    416            });
    417  }
    418 
    419  if (!aConfig.IsVideo()) {
    420    return PlatformEncoderModule::CreateEncoderPromise::CreateAndReject(
    421        MediaResult(
    422            NS_ERROR_DOM_MEDIA_FATAL_ERR,
    423            RESULT_DETAIL(
    424                "Encoder configuration error, expected audio or video.")),
    425        __func__);
    426  }
    427 
    428  return aPEM->AsyncCreateEncoder(aConfig, aTaskQueue);
    429 }
    430 
    431 EncodeSupportSet PEMFactory::Supports(const EncoderConfig& aConfig) const {
    432  RefPtr<PlatformEncoderModule> found;
    433  for (const auto& m : mCurrentPEMs) {
    434    EncodeSupportSet supports = m->Supports(aConfig);
    435    if (!supports.isEmpty()) {
    436      // TODO name
    437      LOG("Checking if %s supports codec %s: yes", m->GetName(),
    438          EnumValueToString(aConfig.mCodec));
    439      return supports;
    440    }
    441    LOG("Checking if %s supports codec %s: no", m->GetName(),
    442        EnumValueToString(aConfig.mCodec));
    443  }
    444  return EncodeSupportSet{};
    445 }
    446 
    447 EncodeSupportSet PEMFactory::SupportsCodec(CodecType aCodec) const {
    448  EncodeSupportSet supports{};
    449  for (const auto& m : mCurrentPEMs) {
    450    EncodeSupportSet pemSupports = m->SupportsCodec(aCodec);
    451    // TODO name
    452    LOG("Checking if %s supports codec %d: %s", m->GetName(),
    453        static_cast<int>(aCodec), pemSupports.isEmpty() ? "no" : "yes");
    454    supports += pemSupports;
    455  }
    456  if (supports.isEmpty()) {
    457    LOG("No PEM support %d", static_cast<int>(aCodec));
    458  }
    459  return supports;
    460 }
    461 
    462 already_AddRefed<PlatformEncoderModule> PEMFactory::FindPEM(
    463    const EncoderConfig& aConfig) const {
    464  RefPtr<PlatformEncoderModule> found;
    465  for (const auto& m : mCurrentPEMs) {
    466    if (!m->Supports(aConfig).isEmpty()) {
    467      found = m;
    468      break;
    469    }
    470  }
    471  return found.forget();
    472 }
    473 
    474 StaticMutex PEMFactory::sSupportedMutex;
    475 
    476 /* static */
    477 MediaCodecsSupported PEMFactory::Supported(bool aForceRefresh) {
    478  StaticMutexAutoLock lock(sSupportedMutex);
    479 
    480  static auto calculate = []() {
    481    auto pem = MakeRefPtr<PEMFactory>();
    482    MediaCodecsSupported supported;
    483    for (const auto& cd : MCSInfo::GetAllCodecDefinitions()) {
    484      auto codecType = MediaCodecToCodecType(cd.codec);
    485      if (codecType == CodecType::Unknown) {
    486        continue;
    487      }
    488      supported += MCSInfo::GetEncodeMediaCodecsSupported(
    489          cd.codec, pem->SupportsCodec(codecType));
    490    }
    491    return supported;
    492  };
    493 
    494  static MediaCodecsSupported supported = calculate();
    495  if (aForceRefresh) {
    496    supported = calculate();
    497  }
    498 
    499  return supported;
    500 }
    501 
    502 /* static */
    503 media::EncodeSupportSet PEMFactory::SupportsCodec(
    504    CodecType aCodec, const MediaCodecsSupported& aSupported,
    505    RemoteMediaIn aLocation) {
    506  const TrackSupportSet supports =
    507      RemoteMediaManagerChild::GetTrackSupport(aLocation);
    508 
    509  if (supports.contains(TrackSupport::EncodeVideo)) {
    510    switch (aCodec) {
    511      case CodecType::H264:
    512        return media::MCSInfo::GetEncodeSupportSet(MediaCodec::H264,
    513                                                   aSupported);
    514      case CodecType::H265:
    515        return media::MCSInfo::GetEncodeSupportSet(MediaCodec::HEVC,
    516                                                   aSupported);
    517      case CodecType::VP8:
    518        return media::MCSInfo::GetEncodeSupportSet(MediaCodec::VP8, aSupported);
    519      case CodecType::VP9:
    520        return media::MCSInfo::GetEncodeSupportSet(MediaCodec::VP9, aSupported);
    521 #ifdef MOZ_AV1
    522      case CodecType::AV1:
    523        return media::MCSInfo::GetEncodeSupportSet(MediaCodec::AV1, aSupported);
    524 #endif
    525      default:
    526        break;
    527    }
    528  }
    529 
    530  if (supports.contains(TrackSupport::EncodeAudio)) {
    531    switch (aCodec) {
    532      case CodecType::Opus:
    533        return media::MCSInfo::GetEncodeSupportSet(MediaCodec::Opus,
    534                                                   aSupported);
    535      case CodecType::Vorbis:
    536        return media::MCSInfo::GetEncodeSupportSet(MediaCodec::Vorbis,
    537                                                   aSupported);
    538      case CodecType::Flac:
    539        return media::MCSInfo::GetEncodeSupportSet(MediaCodec::FLAC,
    540                                                   aSupported);
    541      case CodecType::AAC:
    542        return media::MCSInfo::GetEncodeSupportSet(MediaCodec::AAC, aSupported);
    543      case CodecType::PCM:
    544      case CodecType::G722:
    545      default:
    546        break;
    547    }
    548  }
    549 
    550  return media::EncodeSupportSet{};
    551 }
    552 
    553 }  // namespace mozilla
    554 
    555 #undef LOGE
    556 #undef LOG