WebrtcVideoCodecFactory.cpp (7367B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "WebrtcVideoCodecFactory.h" 7 8 #include "GmpVideoCodec.h" 9 #include "MediaDataCodec.h" 10 #include "VideoConduit.h" 11 #include "mozilla/StaticPrefs_media.h" 12 13 // libwebrtc includes 14 #include "api/rtp_headers.h" 15 #include "api/video_codecs/video_codec.h" 16 #include "api/video_codecs/video_encoder_software_fallback_wrapper.h" 17 #include "media/engine/simulcast_encoder_adapter.h" 18 #include "modules/video_coding/codecs/av1/dav1d_decoder.h" 19 #include "modules/video_coding/codecs/av1/libaom_av1_encoder.h" 20 #include "modules/video_coding/codecs/vp8/include/vp8.h" 21 #include "modules/video_coding/codecs/vp9/include/vp9.h" 22 23 namespace mozilla { 24 25 std::unique_ptr<webrtc::VideoDecoder> WebrtcVideoDecoderFactory::Create( 26 const webrtc::Environment& aEnv, const webrtc::SdpVideoFormat& aFormat) { 27 std::unique_ptr<webrtc::VideoDecoder> decoder; 28 auto type = webrtc::PayloadStringToCodecType(aFormat.name); 29 30 // Attempt to create a decoder using MediaDataDecoder. 31 decoder.reset(MediaDataCodec::CreateDecoder(type, mTrackingId)); 32 if (decoder) { 33 return decoder; 34 } 35 36 switch (type) { 37 case webrtc::VideoCodecType::kVideoCodecH264: { 38 // Get an external decoder 39 auto gmpDecoder = 40 WrapUnique(GmpVideoCodec::CreateDecoder(mPCHandle, mTrackingId)); 41 mCreatedGmpPluginEvent.Forward(*gmpDecoder->InitPluginEvent()); 42 mReleasedGmpPluginEvent.Forward(*gmpDecoder->ReleasePluginEvent()); 43 decoder.reset(gmpDecoder.release()); 44 break; 45 } 46 47 // Use libvpx decoders as fallbacks. 48 case webrtc::VideoCodecType::kVideoCodecVP8: 49 if (!decoder) { 50 decoder = webrtc::CreateVp8Decoder(aEnv); 51 } 52 break; 53 case webrtc::VideoCodecType::kVideoCodecVP9: 54 decoder = webrtc::VP9Decoder::Create(); 55 break; 56 case webrtc::VideoCodecType::kVideoCodecAV1: 57 decoder = webrtc::CreateDav1dDecoder(); 58 break; 59 default: 60 break; 61 } 62 63 return decoder; 64 } 65 66 std::unique_ptr<webrtc::VideoEncoder> WebrtcVideoEncoderFactory::Create( 67 const webrtc::Environment& aEnv, const webrtc::SdpVideoFormat& aFormat) { 68 if (!mInternalFactory->Supports(aFormat)) { 69 return nullptr; 70 } 71 auto type = webrtc::PayloadStringToCodecType(aFormat.name); 72 switch (type) { 73 case webrtc::VideoCodecType::kVideoCodecGeneric: 74 case webrtc::VideoCodecType::kVideoCodecH265: 75 MOZ_CRASH("Unimplemented codec"); 76 case webrtc::VideoCodecType::kVideoCodecAV1: 77 if (StaticPrefs::media_webrtc_simulcast_av1_enabled()) { 78 return std::make_unique<webrtc::SimulcastEncoderAdapter>( 79 aEnv, mInternalFactory.get(), nullptr, aFormat); 80 } 81 break; 82 case webrtc::VideoCodecType::kVideoCodecH264: 83 if (StaticPrefs::media_webrtc_simulcast_h264_enabled()) { 84 return std::make_unique<webrtc::SimulcastEncoderAdapter>( 85 aEnv, mInternalFactory.get(), nullptr, aFormat); 86 } 87 break; 88 case webrtc::VideoCodecType::kVideoCodecVP8: 89 return std::make_unique<webrtc::SimulcastEncoderAdapter>( 90 aEnv, mInternalFactory.get(), nullptr, aFormat); 91 case webrtc::VideoCodecType::kVideoCodecVP9: 92 if (StaticPrefs::media_webrtc_simulcast_vp9_enabled()) { 93 return std::make_unique<webrtc::SimulcastEncoderAdapter>( 94 aEnv, mInternalFactory.get(), nullptr, aFormat); 95 } 96 break; 97 } 98 return mInternalFactory->Create(aEnv, aFormat); 99 } 100 101 bool WebrtcVideoEncoderFactory::InternalFactory::Supports( 102 const webrtc::SdpVideoFormat& aFormat) { 103 switch (webrtc::PayloadStringToCodecType(aFormat.name)) { 104 case webrtc::VideoCodecType::kVideoCodecVP8: 105 case webrtc::VideoCodecType::kVideoCodecVP9: 106 case webrtc::VideoCodecType::kVideoCodecH264: 107 case webrtc::VideoCodecType::kVideoCodecAV1: 108 return true; 109 default: 110 return false; 111 } 112 } 113 114 std::unique_ptr<webrtc::VideoEncoder> 115 WebrtcVideoEncoderFactory::InternalFactory::Create( 116 const webrtc::Environment& aEnv, const webrtc::SdpVideoFormat& aFormat) { 117 MOZ_ASSERT(Supports(aFormat)); 118 119 std::unique_ptr<webrtc::VideoEncoder> platformEncoder; 120 121 auto createPlatformEncoder = [&]() -> std::unique_ptr<webrtc::VideoEncoder> { 122 std::unique_ptr<webrtc::VideoEncoder> platformEncoder; 123 platformEncoder.reset(MediaDataCodec::CreateEncoder(aFormat)); 124 return platformEncoder; 125 }; 126 127 auto createWebRTCEncoder = 128 [this, &aEnv, &aFormat]() -> std::unique_ptr<webrtc::VideoEncoder> { 129 std::unique_ptr<webrtc::VideoEncoder> encoder; 130 switch (webrtc::PayloadStringToCodecType(aFormat.name)) { 131 case webrtc::VideoCodecType::kVideoCodecH264: { 132 // get an external encoder 133 auto gmpEncoder = 134 WrapUnique(GmpVideoCodec::CreateEncoder(aFormat, mPCHandle)); 135 mCreatedGmpPluginEvent.Forward(*gmpEncoder->InitPluginEvent()); 136 mReleasedGmpPluginEvent.Forward(*gmpEncoder->ReleasePluginEvent()); 137 encoder.reset(gmpEncoder.release()); 138 break; 139 } 140 // libvpx fallbacks. 141 case webrtc::VideoCodecType::kVideoCodecVP8: 142 encoder = webrtc::CreateVp8Encoder(aEnv); 143 break; 144 case webrtc::VideoCodecType::kVideoCodecVP9: 145 encoder = webrtc::CreateVp9Encoder(aEnv); 146 break; 147 case webrtc::VideoCodecType::kVideoCodecAV1: 148 encoder = webrtc::CreateLibaomAv1Encoder(aEnv); 149 break; 150 default: 151 break; 152 } 153 return encoder; 154 }; 155 156 // This is to be synced with the doc for the pref in StaticPrefs.yaml 157 enum EncoderCreationStrategy { 158 PreferWebRTCEncoder = 0, 159 PreferPlatformEncoder = 1 160 }; 161 162 std::unique_ptr<webrtc::VideoEncoder> encoder = nullptr; 163 EncoderCreationStrategy strategy = static_cast<EncoderCreationStrategy>( 164 StaticPrefs::media_webrtc_encoder_creation_strategy()); 165 switch (strategy) { 166 case EncoderCreationStrategy::PreferWebRTCEncoder: { 167 encoder = createWebRTCEncoder(); 168 // In a single case this happens: H264 is requested and OpenH264 isn't 169 // available yet (e.g. first run). Attempt to use a platform encoder in 170 // this case. They are not entirely ready yet but it's better than 171 // erroring out. 172 if (!encoder) { 173 NS_WARNING( 174 "Failed creating libwebrtc video encoder, falling back on platform " 175 "encoder"); 176 return createPlatformEncoder(); 177 } 178 return encoder; 179 } 180 case EncoderCreationStrategy::PreferPlatformEncoder: 181 platformEncoder = createPlatformEncoder(); 182 encoder = createWebRTCEncoder(); 183 if (encoder && platformEncoder) { 184 return webrtc::CreateVideoEncoderSoftwareFallbackWrapper( 185 aEnv, std::move(encoder), std::move(platformEncoder), false); 186 } 187 if (platformEncoder) { 188 NS_WARNING(nsPrintfCString("No WebRTC encoder to fall back to for " 189 "codec %s, only using platform encoder", 190 aFormat.name.c_str()) 191 .get()); 192 return platformEncoder; 193 } 194 return encoder; 195 }; 196 197 MOZ_ASSERT_UNREACHABLE("Bad enum value"); 198 199 return nullptr; 200 } 201 202 } // namespace mozilla