AppleDecoderModule.cpp (10026B)
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 "AppleDecoderModule.h" 8 9 #include <dlfcn.h> 10 11 #include "AOMDecoder.h" 12 #include "AppleATDecoder.h" 13 #include "AppleVTDecoder.h" 14 #include "H265.h" 15 #include "MP4Decoder.h" 16 #include "VPXDecoder.h" 17 #include "VideoUtils.h" 18 #include "mozilla/Logging.h" 19 #include "mozilla/ScopeExit.h" 20 #include "mozilla/StaticPrefs_media.h" 21 #include "mozilla/gfx/gfxVars.h" 22 23 extern "C" { 24 // Only exists from MacOS 11 25 extern void VTRegisterSupplementalVideoDecoderIfAvailable( 26 CMVideoCodecType codecType) __attribute__((weak_import)); 27 } 28 29 namespace mozilla { 30 31 using media::DecodeSupport; 32 using media::DecodeSupportSet; 33 using media::MCSInfo; 34 using media::MediaCodec; 35 36 static inline CMVideoCodecType GetCMVideoCodecType(const MediaCodec& aCodec) { 37 switch (aCodec) { 38 case MediaCodec::H264: 39 return kCMVideoCodecType_H264; 40 case MediaCodec::AV1: 41 return kCMVideoCodecType_AV1; 42 case MediaCodec::VP9: 43 return kCMVideoCodecType_VP9; 44 case MediaCodec::HEVC: 45 return kCMVideoCodecType_HEVC; 46 default: 47 return static_cast<CMVideoCodecType>(0); 48 } 49 } 50 51 /* static */ 52 void AppleDecoderModule::Init() { 53 if (sInitialized) { 54 return; 55 } 56 57 // Initialize all values to false first. 58 for (auto& support : sCanUseHWDecoder) { 59 support = false; 60 } 61 62 // H264 HW is supported since 10.6. 63 sCanUseHWDecoder[MediaCodec::H264] = CanCreateHWDecoder(MediaCodec::H264); 64 // HEVC HW is supported since 10.13. 65 sCanUseHWDecoder[MediaCodec::HEVC] = CanCreateHWDecoder(MediaCodec::HEVC); 66 // VP9 HW is supported since 11.0 on Apple silicon. 67 sCanUseHWDecoder[MediaCodec::VP9] = 68 RegisterSupplementalDecoder(MediaCodec::VP9) && 69 CanCreateHWDecoder(MediaCodec::VP9); 70 // AV1 HW is supported since 14.0 on Apple silicon. 71 sCanUseHWDecoder[MediaCodec::AV1] = 72 RegisterSupplementalDecoder(MediaCodec::AV1) && 73 CanCreateHWDecoder(MediaCodec::AV1); 74 75 sInitialized = true; 76 } 77 78 nsresult AppleDecoderModule::Startup() { 79 if (!sInitialized) { 80 return NS_ERROR_FAILURE; 81 } 82 return NS_OK; 83 } 84 85 already_AddRefed<MediaDataDecoder> AppleDecoderModule::CreateVideoDecoder( 86 const CreateDecoderParams& aParams) { 87 if (Supports(SupportDecoderParams(aParams), nullptr /* diagnostics */) 88 .isEmpty()) { 89 return nullptr; 90 } 91 RefPtr<MediaDataDecoder> decoder; 92 if (IsVideoSupported(aParams.VideoConfig(), aParams.mOptions)) { 93 decoder = new AppleVTDecoder(aParams.VideoConfig(), aParams.mImageContainer, 94 aParams.mOptions, aParams.mKnowsCompositor, 95 aParams.mTrackingId); 96 } 97 return decoder.forget(); 98 } 99 100 already_AddRefed<MediaDataDecoder> AppleDecoderModule::CreateAudioDecoder( 101 const CreateDecoderParams& aParams) { 102 if (Supports(SupportDecoderParams(aParams), nullptr /* diagnostics */) 103 .isEmpty()) { 104 return nullptr; 105 } 106 RefPtr<MediaDataDecoder> decoder = new AppleATDecoder(aParams.AudioConfig()); 107 return decoder.forget(); 108 } 109 110 DecodeSupportSet AppleDecoderModule::SupportsMimeType( 111 const nsACString& aMimeType, DecoderDoctorDiagnostics* aDiagnostics) const { 112 bool checkSupport = 113 aMimeType.EqualsLiteral("audio/mp4a-latm") || 114 MP4Decoder::IsH264(aMimeType) || VPXDecoder::IsVP9(aMimeType) || 115 AOMDecoder::IsAV1(aMimeType) || MP4Decoder::IsHEVC(aMimeType); 116 DecodeSupportSet supportType{}; 117 118 if (checkSupport) { 119 UniquePtr<TrackInfo> trackInfo = CreateTrackInfoWithMIMEType(aMimeType); 120 if (trackInfo && trackInfo->IsAudio()) { 121 supportType = DecodeSupport::SoftwareDecode; 122 } else if (trackInfo && trackInfo->IsVideo()) { 123 supportType = Supports(SupportDecoderParams(*trackInfo), aDiagnostics); 124 } 125 } 126 127 MOZ_LOG(sPDMLog, LogLevel::Debug, 128 ("Apple decoder %s requested type '%s'", 129 supportType.isEmpty() ? "rejects" : "supports", 130 aMimeType.BeginReading())); 131 return supportType; 132 } 133 134 DecodeSupportSet AppleDecoderModule::Supports( 135 const SupportDecoderParams& aParams, 136 DecoderDoctorDiagnostics* aDiagnostics) const { 137 const auto& trackInfo = aParams.mConfig; 138 if (trackInfo.IsAudio()) { 139 return SupportsMimeType(trackInfo.mMimeType, aDiagnostics); 140 } 141 const bool checkSupport = trackInfo.GetAsVideoInfo() && 142 IsVideoSupported(*trackInfo.GetAsVideoInfo()); 143 DecodeSupportSet dss{}; 144 if (!checkSupport) { 145 return dss; 146 } 147 const MediaCodec codec = 148 MCSInfo::GetMediaCodecFromMimeType(trackInfo.mMimeType); 149 if (sCanUseHWDecoder[codec]) { 150 dss += DecodeSupport::HardwareDecode; 151 } 152 switch (codec) { 153 case MediaCodec::VP8: 154 [[fallthrough]]; 155 case MediaCodec::VP9: 156 if (StaticPrefs::media_rdd_vpx_enabled()) { 157 dss += DecodeSupport::SoftwareDecode; 158 } 159 break; 160 default: 161 dss += DecodeSupport::SoftwareDecode; 162 break; 163 } 164 return dss; 165 } 166 167 bool AppleDecoderModule::IsVideoSupported( 168 const VideoInfo& aConfig, 169 const CreateDecoderParams::OptionSet& aOptions) const { 170 if (MP4Decoder::IsH264(aConfig.mMimeType)) { 171 return true; 172 } 173 if (MP4Decoder::IsHEVC(aConfig.mMimeType)) { 174 return StaticPrefs::media_hevc_enabled(); 175 } 176 if (AOMDecoder::IsAV1(aConfig.mMimeType)) { 177 if (!sCanUseHWDecoder[MediaCodec::AV1] || 178 aOptions.contains( 179 CreateDecoderParams::Option::HardwareDecoderNotAllowed)) { 180 return false; 181 } 182 183 // HW AV1 decoder only supports 8 or 10 bit color. 184 if (aConfig.mColorDepth != gfx::ColorDepth::COLOR_8 && 185 aConfig.mColorDepth != gfx::ColorDepth::COLOR_10) { 186 return false; 187 } 188 189 if (aConfig.mColorSpace.isSome()) { 190 if (*aConfig.mColorSpace == gfx::YUVColorSpace::Identity) { 191 // HW AV1 decoder doesn't support RGB 192 return false; 193 } 194 } 195 196 if (aConfig.mExtraData && aConfig.mExtraData->Length() < 2) { 197 return true; // Assume it's okay. 198 } 199 // top 3 bits are the profile. 200 int profile = aConfig.mExtraData->ElementAt(1) >> 5; 201 // 0 is main profile 202 return profile == 0; 203 } 204 205 if (!VPXDecoder::IsVP9(aConfig.mMimeType) || 206 !sCanUseHWDecoder[MediaCodec::VP9] || 207 aOptions.contains( 208 CreateDecoderParams::Option::HardwareDecoderNotAllowed)) { 209 return false; 210 } 211 if (VPXDecoder::IsVP9(aConfig.mMimeType) && 212 aOptions.contains(CreateDecoderParams::Option::LowLatency)) { 213 // SVC layers are unsupported, and may be used in low latency use cases 214 // (WebRTC). 215 return false; 216 } 217 if (aConfig.HasAlpha()) { 218 return false; 219 } 220 221 // HW VP9 decoder only supports 8 or 10 bit color. 222 if (aConfig.mColorDepth != gfx::ColorDepth::COLOR_8 && 223 aConfig.mColorDepth != gfx::ColorDepth::COLOR_10) { 224 return false; 225 } 226 227 // See if we have a vpcC box, and check further constraints. 228 // HW VP9 Decoder supports Profile 0 & 2 (YUV420) 229 if (aConfig.mExtraData && aConfig.mExtraData->Length() < 5) { 230 return true; // Assume it's okay. 231 } 232 int profile = aConfig.mExtraData->ElementAt(4); 233 234 return profile == 0 || profile == 2; 235 } 236 237 /* static */ 238 bool AppleDecoderModule::CanCreateHWDecoder(const MediaCodec& aCodec) { 239 // Check whether HW decode should even be enabled 240 if (!gfx::gfxVars::CanUseHardwareVideoDecoding() || XRE_IsUtilityProcess()) { 241 return false; 242 } 243 244 if (!VTIsHardwareDecodeSupported(GetCMVideoCodecType(aCodec))) { 245 return false; 246 } 247 248 // H264 hardware decoding has been supported since macOS 10.6 on most Intel 249 // GPUs (Sandy Bridge and later, 2011). If VTIsHardwareDecodeSupported is 250 // already true, there's no need for further verification. 251 if (aCodec == MediaCodec::H264) { 252 return true; 253 } 254 255 // Build up a fake extradata to create an actual decoder to verify 256 VideoInfo info(1920, 1080); 257 if (aCodec == MediaCodec::AV1) { 258 info.mMimeType = "video/av1"; 259 bool hasSeqHdr; 260 AOMDecoder::AV1SequenceInfo seqInfo; 261 AOMDecoder::OperatingPoint op; 262 seqInfo.mOperatingPoints.AppendElement(op); 263 seqInfo.mImage = {1920, 1080}; 264 AOMDecoder::WriteAV1CBox(seqInfo, info.mExtraData, hasSeqHdr); 265 } else if (aCodec == MediaCodec::VP9) { 266 info.mMimeType = "video/vp9"; 267 VPXDecoder::GetVPCCBox(info.mExtraData, VPXDecoder::VPXStreamInfo()); 268 } else if (aCodec == MediaCodec::HEVC) { 269 // Although HEVC hardware decoding is supported starting with macOS 10.13 270 // and we only support macOS 10.15+, Intel GPUs (Skylake and later, 2015) 271 // that support HEVC are not old enough to skip verification. 272 info.mMimeType = "video/hevc"; 273 info.mExtraData = H265::CreateFakeExtraData(); 274 } 275 276 RefPtr<AppleVTDecoder> decoder = 277 new AppleVTDecoder(info, nullptr, {}, nullptr, Nothing()); 278 auto release = MakeScopeExit([&]() { decoder->Shutdown(); }); 279 if (NS_FAILED(decoder->InitializeSession())) { 280 MOZ_LOG(sPDMLog, LogLevel::Debug, 281 ("Failed to initializing VT HW decoder session")); 282 return false; 283 } 284 nsAutoCString failureReason; 285 bool hwSupport = decoder->IsHardwareAccelerated(failureReason); 286 if (!hwSupport) { 287 MOZ_LOG( 288 sPDMLog, LogLevel::Debug, 289 ("VT decoder failed to use HW : '%s'", failureReason.BeginReading())); 290 } 291 return hwSupport; 292 } 293 294 /* static */ 295 bool AppleDecoderModule::RegisterSupplementalDecoder(const MediaCodec& aCodec) { 296 #ifdef XP_MACOSX 297 static bool sRegisterIfAvailable = [&]() { 298 if (__builtin_available(macos 11.0, *)) { 299 VTRegisterSupplementalVideoDecoderIfAvailable( 300 GetCMVideoCodecType(aCodec)); 301 return true; 302 } 303 return false; 304 }(); 305 return sRegisterIfAvailable; 306 #else // iOS 307 return false; 308 #endif 309 } 310 311 /* static */ 312 already_AddRefed<PlatformDecoderModule> AppleDecoderModule::Create() { 313 return MakeAndAddRef<AppleDecoderModule>(); 314 } 315 316 } // namespace mozilla