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