Organize some things
All checks were successful
eden-license / license-header (pull_request) Successful in 50s

This commit is contained in:
MaranBr 2025-07-21 17:19:15 -04:00
parent 91adee2f5b
commit 3b85b67944

View file

@ -27,17 +27,17 @@ constexpr AVPixelFormat PreferredGpuFormat = AV_PIX_FMT_NV12;
constexpr AVPixelFormat PreferredCpuFormat = AV_PIX_FMT_YUV420P; constexpr AVPixelFormat PreferredCpuFormat = AV_PIX_FMT_YUV420P;
constexpr std::array PreferredGpuDecoders = { constexpr std::array PreferredGpuDecoders = {
#if defined (_WIN32) #if defined (_WIN32)
AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_CUDA,
AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_D3D11VA,
AV_HWDEVICE_TYPE_DXVA2, AV_HWDEVICE_TYPE_DXVA2,
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
AV_HWDEVICE_TYPE_VDPAU, AV_HWDEVICE_TYPE_VDPAU,
#elif defined(__unix__) #elif defined(__unix__)
AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_CUDA,
AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VAAPI,
AV_HWDEVICE_TYPE_VDPAU, AV_HWDEVICE_TYPE_VDPAU,
#endif #endif
AV_HWDEVICE_TYPE_VULKAN, AV_HWDEVICE_TYPE_VULKAN,
}; };
AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* pix_fmts) { AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* pix_fmts) {
@ -66,38 +66,38 @@ AVPixelFormat GetGpuFormat(AVCodecContext* codec_context, const AVPixelFormat* p
LOG_INFO(HW_GPU, "Could not find supported GPU pixel format, falling back to CPU decoder"); LOG_INFO(HW_GPU, "Could not find supported GPU pixel format, falling back to CPU decoder");
av_buffer_unref(&codec_context->hw_device_ctx); av_buffer_unref(&codec_context->hw_device_ctx);
codec_context->pix_fmt = PreferredCpuFormat; codec_context->pix_fmt = PreferredCpuFormat;
return codec_context->pix_fmt; return codec_context->pix_fmt;
} }
std::string AVError(int errnum) { std::string AVError(int errnum) {
char errbuf[AV_ERROR_MAX_STRING_SIZE] = {}; char errbuf[AV_ERROR_MAX_STRING_SIZE] = {};
av_make_error_string(errbuf, sizeof(errbuf) - 1, errnum); av_make_error_string(errbuf, sizeof(errbuf) - 1, errnum);
return errbuf; return errbuf;
} }
} }
Packet::Packet(std::span<const u8> data) { Packet::Packet(std::span<const u8> data) {
m_packet = av_packet_alloc(); m_packet = av_packet_alloc();
m_packet->data = const_cast<u8*>(data.data()); m_packet->data = const_cast<u8*>(data.data());
m_packet->size = static_cast<s32>(data.size()); m_packet->size = static_cast<s32>(data.size());
} }
Packet::~Packet() { Packet::~Packet() {
av_packet_free(&m_packet); av_packet_free(&m_packet);
} }
Frame::Frame() { Frame::Frame() {
m_frame = av_frame_alloc(); m_frame = av_frame_alloc();
} }
Frame::~Frame() { Frame::~Frame() {
av_frame_free(&m_frame); av_frame_free(&m_frame);
} }
Decoder::Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec) { Decoder::Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec) {
const AVCodecID av_codec = [&] { const AVCodecID av_codec = [&] {
switch (codec) { switch (codec) {
case Tegra::Host1x::NvdecCommon::VideoCodec::H264: case Tegra::Host1x::NvdecCommon::VideoCodec::H264:
return AV_CODEC_ID_H264; return AV_CODEC_ID_H264;
case Tegra::Host1x::NvdecCommon::VideoCodec::VP8: case Tegra::Host1x::NvdecCommon::VideoCodec::VP8:
@ -108,137 +108,137 @@ Decoder::Decoder(Tegra::Host1x::NvdecCommon::VideoCodec codec) {
UNIMPLEMENTED_MSG("Unknown codec {}", codec); UNIMPLEMENTED_MSG("Unknown codec {}", codec);
return AV_CODEC_ID_NONE; return AV_CODEC_ID_NONE;
} }
}(); }();
m_codec = avcodec_find_decoder(av_codec); m_codec = avcodec_find_decoder(av_codec);
} }
bool Decoder::SupportsDecodingOnDevice(AVPixelFormat* out_pix_fmt, AVHWDeviceType type) const { bool Decoder::SupportsDecodingOnDevice(AVPixelFormat* out_pix_fmt, AVHWDeviceType type) const {
for (int i = 0;; i++) { for (int i = 0;; i++) {
const AVCodecHWConfig* config = avcodec_get_hw_config(m_codec, i); const AVCodecHWConfig* config = avcodec_get_hw_config(m_codec, i);
if (!config) { if (!config) {
LOG_DEBUG(HW_GPU, "{} decoder does not support device type {}", m_codec->name, av_hwdevice_get_type_name(type)); LOG_DEBUG(HW_GPU, "{} decoder does not support device type {}", m_codec->name, av_hwdevice_get_type_name(type));
break; break;
} }
if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == type) { if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && config->device_type == type) {
LOG_INFO(HW_GPU, "Using {} GPU Decoder", av_hwdevice_get_type_name(type)); LOG_INFO(HW_GPU, "Using {} GPU decoder", av_hwdevice_get_type_name(type));
*out_pix_fmt = config->pix_fmt; *out_pix_fmt = config->pix_fmt;
return true; return true;
} }
} }
return false; return false;
} }
std::vector<AVHWDeviceType> HardwareContext::GetSupportedDeviceTypes() { std::vector<AVHWDeviceType> HardwareContext::GetSupportedDeviceTypes() {
std::vector<AVHWDeviceType> types; std::vector<AVHWDeviceType> types;
AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE; AVHWDeviceType current_device_type = AV_HWDEVICE_TYPE_NONE;
while (true) { while (true) {
current_device_type = av_hwdevice_iterate_types(current_device_type); current_device_type = av_hwdevice_iterate_types(current_device_type);
if (current_device_type == AV_HWDEVICE_TYPE_NONE) { if (current_device_type == AV_HWDEVICE_TYPE_NONE) {
return types; return types;
} }
types.push_back(current_device_type); types.push_back(current_device_type);
} }
} }
HardwareContext::~HardwareContext() { HardwareContext::~HardwareContext() {
av_buffer_unref(&m_gpu_decoder); av_buffer_unref(&m_gpu_decoder);
} }
bool HardwareContext::InitializeForDecoder(DecoderContext& decoder_context, const Decoder& decoder) { bool HardwareContext::InitializeForDecoder(DecoderContext& decoder_context, const Decoder& decoder) {
const auto supported_types = GetSupportedDeviceTypes(); const auto supported_types = GetSupportedDeviceTypes();
for (const auto type : PreferredGpuDecoders) { for (const auto type : PreferredGpuDecoders) {
AVPixelFormat hw_pix_fmt; AVPixelFormat hw_pix_fmt;
if (std::ranges::find(supported_types, type) == supported_types.end()) { if (std::ranges::find(supported_types, type) == supported_types.end()) {
LOG_DEBUG(HW_GPU, "{} explicitly unsupported", av_hwdevice_get_type_name(type)); LOG_DEBUG(HW_GPU, "{} explicitly unsupported", av_hwdevice_get_type_name(type));
continue; continue;
} }
if (!this->InitializeWithType(type)) { if (!this->InitializeWithType(type)) {
continue; continue;
} }
if (decoder.SupportsDecodingOnDevice(&hw_pix_fmt, type)) { if (decoder.SupportsDecodingOnDevice(&hw_pix_fmt, type)) {
decoder_context.InitializeHardwareDecoder(*this, hw_pix_fmt); decoder_context.InitializeHardwareDecoder(*this, hw_pix_fmt);
return true; return true;
} }
} }
return false; return false;
} }
bool HardwareContext::InitializeWithType(AVHWDeviceType type) { bool HardwareContext::InitializeWithType(AVHWDeviceType type) {
av_buffer_unref(&m_gpu_decoder); av_buffer_unref(&m_gpu_decoder);
if (const int ret = av_hwdevice_ctx_create(&m_gpu_decoder, type, nullptr, nullptr, 0); ret < 0) { if (const int ret = av_hwdevice_ctx_create(&m_gpu_decoder, type, nullptr, nullptr, 0); ret < 0) {
LOG_DEBUG(HW_GPU, "av_hwdevice_ctx_create({}) failed: {}", av_hwdevice_get_type_name(type), AVError(ret)); LOG_DEBUG(HW_GPU, "av_hwdevice_ctx_create({}) failed: {}", av_hwdevice_get_type_name(type), AVError(ret));
return false; return false;
} }
#ifdef LIBVA_FOUND #ifdef LIBVA_FOUND
if (type == AV_HWDEVICE_TYPE_VAAPI) { if (type == AV_HWDEVICE_TYPE_VAAPI) {
// We need to determine if this is an impersonated VAAPI driver. // We need to determine if this is an impersonated VAAPI driver.
auto* hwctx = reinterpret_cast<AVHWDeviceContext*>(m_gpu_decoder->data); auto* hwctx = reinterpret_cast<AVHWDeviceContext*>(m_gpu_decoder->data);
auto* vactx = static_cast<AVVAAPIDeviceContext*>(hwctx->hwctx); auto* vactx = static_cast<AVVAAPIDeviceContext*>(hwctx->hwctx);
const char* vendor_name = vaQueryVendorString(vactx->display); const char* vendor_name = vaQueryVendorString(vactx->display);
if (strstr(vendor_name, "VDPAU backend")) { if (strstr(vendor_name, "VDPAU backend")) {
// VDPAU impersonated VAAPI impls are super buggy, we need to skip them. // VDPAU impersonated VAAPI impls are super buggy, we need to skip them.
LOG_DEBUG(HW_GPU, "Skipping VDPAU impersonated VAAPI driver"); LOG_DEBUG(HW_GPU, "Skipping VDPAU impersonated VAAPI driver");
return false; return false;
} else { } else {
// According to some user testing, certain VAAPI drivers (Intel?) could be buggy. // According to some user testing, certain VAAPI drivers (Intel?) could be buggy.
// Log the driver name just in case. // Log the driver name just in case.
LOG_DEBUG(HW_GPU, "Using VAAPI driver: {}", vendor_name); LOG_DEBUG(HW_GPU, "Using VAAPI driver: {}", vendor_name);
} }
} }
#endif #endif
return true; return true;
} }
DecoderContext::DecoderContext(const Decoder& decoder) : m_decoder{decoder} { DecoderContext::DecoderContext(const Decoder& decoder) : m_decoder{decoder} {
m_codec_context = avcodec_alloc_context3(m_decoder.GetCodec()); m_codec_context = avcodec_alloc_context3(m_decoder.GetCodec());
av_opt_set(m_codec_context->priv_data, "tune", "zerolatency", 0); av_opt_set(m_codec_context->priv_data, "tune", "zerolatency", 0);
m_codec_context->thread_count = 0; m_codec_context->thread_count = 0;
m_codec_context->thread_type &= ~FF_THREAD_FRAME; m_codec_context->thread_type &= ~FF_THREAD_FRAME;
} }
DecoderContext::~DecoderContext() { DecoderContext::~DecoderContext() {
av_buffer_unref(&m_codec_context->hw_device_ctx); av_buffer_unref(&m_codec_context->hw_device_ctx);
avcodec_free_context(&m_codec_context); avcodec_free_context(&m_codec_context);
} }
void DecoderContext::InitializeHardwareDecoder(const HardwareContext& context, AVPixelFormat hw_pix_fmt) { void DecoderContext::InitializeHardwareDecoder(const HardwareContext& context, AVPixelFormat hw_pix_fmt) {
m_codec_context->hw_device_ctx = av_buffer_ref(context.GetBufferRef()); m_codec_context->hw_device_ctx = av_buffer_ref(context.GetBufferRef());
m_codec_context->get_format = GetGpuFormat; m_codec_context->get_format = GetGpuFormat;
m_codec_context->pix_fmt = hw_pix_fmt; m_codec_context->pix_fmt = hw_pix_fmt;
} }
bool DecoderContext::OpenContext(const Decoder& decoder) { bool DecoderContext::OpenContext(const Decoder& decoder) {
if (const int ret = avcodec_open2(m_codec_context, decoder.GetCodec(), nullptr); ret < 0) { if (const int ret = avcodec_open2(m_codec_context, decoder.GetCodec(), nullptr); ret < 0) {
LOG_ERROR(HW_GPU, "avcodec_open2 error: {}", AVError(ret)); LOG_ERROR(HW_GPU, "avcodec_open2 error: {}", AVError(ret));
return false; return false;
} }
if (!m_codec_context->hw_device_ctx) { if (!m_codec_context->hw_device_ctx) {
LOG_INFO(HW_GPU, "Using FFmpeg CPU Decoder"); LOG_INFO(HW_GPU, "Using FFmpeg CPU decoder");
} }
return true; return true;
} }
bool DecoderContext::SendPacket(const Packet& packet) { bool DecoderContext::SendPacket(const Packet& packet) {
if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0 && ret != AVERROR_EOF) { if (const int ret = avcodec_send_packet(m_codec_context, packet.GetPacket()); ret < 0 && ret != AVERROR_EOF) {
LOG_ERROR(HW_GPU, "avcodec_send_packet error: {}", AVError(ret)); LOG_ERROR(HW_GPU, "avcodec_send_packet error: {}", AVError(ret));
return false; return false;
} }
return true; return true;
} }
std::shared_ptr<Frame> DecoderContext::ReceiveFrame() { std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
@ -270,39 +270,39 @@ std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
} }
void DecodeApi::Reset() { void DecodeApi::Reset() {
m_hardware_context.reset(); m_hardware_context.reset();
m_decoder_context.reset(); m_decoder_context.reset();
m_decoder.reset(); m_decoder.reset();
} }
bool DecodeApi::Initialize(Tegra::Host1x::NvdecCommon::VideoCodec codec) { bool DecodeApi::Initialize(Tegra::Host1x::NvdecCommon::VideoCodec codec) {
this->Reset(); this->Reset();
m_decoder.emplace(codec); m_decoder.emplace(codec);
m_decoder_context.emplace(*m_decoder); m_decoder_context.emplace(*m_decoder);
// Enable GPU decoding if requested. // Enable GPU decoding if requested.
if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::Gpu) { if (Settings::values.nvdec_emulation.GetValue() == Settings::NvdecEmulation::Gpu) {
m_hardware_context.emplace(); m_hardware_context.emplace();
m_hardware_context->InitializeForDecoder(*m_decoder_context, *m_decoder); m_hardware_context->InitializeForDecoder(*m_decoder_context, *m_decoder);
} }
// Open the decoder context. // Open the decoder context.
if (!m_decoder_context->OpenContext(*m_decoder)) { if (!m_decoder_context->OpenContext(*m_decoder)) {
this->Reset(); this->Reset();
return false; return false;
} }
return true; return true;
} }
bool DecodeApi::SendPacket(std::span<const u8> packet_data) { bool DecodeApi::SendPacket(std::span<const u8> packet_data) {
FFmpeg::Packet packet(packet_data); FFmpeg::Packet packet(packet_data);
return m_decoder_context->SendPacket(packet); return m_decoder_context->SendPacket(packet);
} }
std::shared_ptr<Frame> DecodeApi::ReceiveFrame() { std::shared_ptr<Frame> DecodeApi::ReceiveFrame() {
// Receive raw frame from decoder. // Receive raw frame from decoder.
return m_decoder_context->ReceiveFrame(); return m_decoder_context->ReceiveFrame();
} }
} }