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