#include "livekit/video_decoder_factory.h"
#include <modules/video_coding/codecs/av1/av1_svc_config.h>
#include "api/environment/environment.h"
#include "api/video_codecs/av1_profile.h"
#include "api/video_codecs/sdp_video_format.h"
#include "livekit/objc_video_factory.h"
#include "media/base/media_constants.h"
#include "modules/video_coding/codecs/h264/include/h264.h"
#include "modules/video_coding/codecs/vp8/include/vp8.h"
#include "modules/video_coding/codecs/vp9/include/vp9.h"
#include "rtc_base/logging.h"
#if defined(RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY)
#include "modules/video_coding/codecs/av1/dav1d_decoder.h"
#endif
#ifdef WEBRTC_ANDROID
#include "livekit/android.h"
#endif
#if defined(USE_NVIDIA_VIDEO_CODEC)
#include "nvidia/nvidia_decoder_factory.h"
#endif
namespace livekit_ffi {
namespace {
bool IsInternalH264DecoderAvailable() {
if (!webrtc::H264Decoder::IsSupported()) {
RTC_LOG(LS_WARNING) << "Internal H264 decoder not compiled in "
"(WEBRTC_USE_H264 off)";
return false;
}
auto decoder = webrtc::H264Decoder::Create();
if (!decoder) {
RTC_LOG(LS_WARNING) << "H264Decoder::Create() returned null";
return false;
}
webrtc::VideoDecoder::Settings settings;
settings.set_codec_type(webrtc::kVideoCodecH264);
if (!decoder->Configure(settings)) {
RTC_LOG(LS_WARNING) << "Internal H264 decoder failed to configure; "
"FFmpeg likely lacks the H.264 codec";
return false;
}
return true;
}
}
VideoDecoderFactory::VideoDecoderFactory()
: internal_h264_decoder_works_(IsInternalH264DecoderAvailable()) {
#ifdef __APPLE__
factories_.push_back(livekit_ffi::CreateObjCVideoDecoderFactory());
#endif
#ifdef WEBRTC_ANDROID
factories_.push_back(CreateAndroidVideoDecoderFactory());
#endif
#if defined(USE_NVIDIA_VIDEO_CODEC)
if (webrtc::NvidiaVideoDecoderFactory::IsSupported()) {
factories_.push_back(std::make_unique<webrtc::NvidiaVideoDecoderFactory>());
}
#endif
if (!internal_h264_decoder_works_) {
RTC_LOG(LS_WARNING) << "Internal H264 decoder is unavailable, "
"not advertising its formats";
}
}
std::vector<webrtc::SdpVideoFormat> VideoDecoderFactory::GetSupportedFormats()
const {
std::vector<webrtc::SdpVideoFormat> formats;
for (const auto& factory : factories_) {
auto supported_formats = factory->GetSupportedFormats();
formats.insert(formats.end(), supported_formats.begin(),
supported_formats.end());
}
formats.push_back(webrtc::SdpVideoFormat(webrtc::kVp8CodecName));
for (const webrtc::SdpVideoFormat& format :
webrtc::SupportedVP9DecoderCodecs())
formats.push_back(format);
if (internal_h264_decoder_works_) {
for (const webrtc::SdpVideoFormat& h264_format :
webrtc::SupportedH264DecoderCodecs()) {
formats.push_back(h264_format);
}
}
formats.push_back(webrtc::SdpVideoFormat(
webrtc::SdpVideoFormat::AV1Profile0(),
webrtc::LibaomAv1EncoderSupportedScalabilityModes()));
return formats;
}
VideoDecoderFactory::CodecSupport VideoDecoderFactory::QueryCodecSupport(
const webrtc::SdpVideoFormat& format,
bool reference_scaling) const {
if (reference_scaling) {
webrtc::VideoCodecType codec =
webrtc::PayloadStringToCodecType(format.name);
if (codec != webrtc::kVideoCodecVP9 && codec != webrtc::kVideoCodecAV1) {
return {false, false};
}
}
CodecSupport codec_support;
codec_support.is_supported = format.IsCodecInList(GetSupportedFormats());
return codec_support;
}
std::unique_ptr<webrtc::VideoDecoder> VideoDecoderFactory::Create(
const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) {
for (const auto& factory : factories_) {
for (const auto& supported_format : factory->GetSupportedFormats()) {
if (supported_format.IsSameCodec(format))
return factory->Create(env, format);
}
}
if (absl::EqualsIgnoreCase(format.name, webrtc::kH264CodecName)) {
for (const auto& factory : factories_) {
for (const auto& sf : factory->GetSupportedFormats()) {
if (!absl::EqualsIgnoreCase(sf.name, webrtc::kH264CodecName))
continue;
auto adjusted = format;
auto it = sf.parameters.find("packetization-mode");
if (it != sf.parameters.end())
adjusted.parameters["packetization-mode"] = it->second;
else
adjusted.parameters.erase("packetization-mode");
if (sf.IsSameCodec(adjusted))
return factory->Create(env, adjusted);
}
}
}
if (absl::EqualsIgnoreCase(format.name, webrtc::kVp8CodecName))
return webrtc::CreateVp8Decoder(env);
if (absl::EqualsIgnoreCase(format.name, webrtc::kVp9CodecName))
return webrtc::VP9Decoder::Create();
if (absl::EqualsIgnoreCase(format.name, webrtc::kH264CodecName) &&
internal_h264_decoder_works_)
return webrtc::H264Decoder::Create();
#if defined(RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY)
if (absl::EqualsIgnoreCase(format.name, webrtc::kAv1CodecName)) {
return webrtc::CreateDav1dDecoder();
}
#endif
RTC_LOG(LS_ERROR) << "No VideoDecoder found for " << format.name;
return nullptr;
}
}