[Video]: Add timeout protection for hardware frame transfer
This commit is contained in:
parent
9847eeb2af
commit
1289ee2e98
2 changed files with 32 additions and 6 deletions
|
|
@ -4,6 +4,9 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
|
#include <future>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "video_core/host1x/ffmpeg/ffmpeg.h"
|
#include "video_core/host1x/ffmpeg/ffmpeg.h"
|
||||||
|
|
@ -22,6 +25,8 @@ namespace {
|
||||||
|
|
||||||
constexpr AVPixelFormat PreferredGpuFormat = AV_PIX_FMT_NV12;
|
constexpr AVPixelFormat PreferredGpuFormat = AV_PIX_FMT_NV12;
|
||||||
constexpr AVPixelFormat PreferredCpuFormat = AV_PIX_FMT_YUV420P;
|
constexpr AVPixelFormat PreferredCpuFormat = AV_PIX_FMT_YUV420P;
|
||||||
|
// Timeout for hardware frame transfer to prevent driver freezes
|
||||||
|
constexpr auto HW_TRANSFER_TIMEOUT_MS = std::chrono::milliseconds(500);
|
||||||
constexpr std::array PreferredGpuDecoders = {
|
constexpr std::array PreferredGpuDecoders = {
|
||||||
AV_HWDEVICE_TYPE_CUDA,
|
AV_HWDEVICE_TYPE_CUDA,
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
@ -440,7 +445,7 @@ std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (m_codec_context->hw_device_ctx) {
|
if (m_codec_context->hw_device_ctx && !m_hw_decoder_failed.load()) {
|
||||||
// If we have a hardware context, make a separate frame here to receive the
|
// If we have a hardware context, make a separate frame here to receive the
|
||||||
// hardware result before sending it to the output.
|
// hardware result before sending it to the output.
|
||||||
Frame intermediate_frame;
|
Frame intermediate_frame;
|
||||||
|
|
@ -450,14 +455,33 @@ std::shared_ptr<Frame> DecoderContext::ReceiveFrame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
m_temp_frame->SetFormat(PreferredGpuFormat);
|
m_temp_frame->SetFormat(PreferredGpuFormat);
|
||||||
if (const int ret = av_hwframe_transfer_data(m_temp_frame->GetFrame(),
|
|
||||||
intermediate_frame.GetFrame(), 0);
|
// Execute hardware transfer with timeout to prevent driver freezes
|
||||||
ret < 0) {
|
auto transfer_future = std::async(std::launch::async, [&]() {
|
||||||
LOG_ERROR(HW_GPU, "av_hwframe_transfer_data error: {}", AVError(ret));
|
return av_hwframe_transfer_data(m_temp_frame->GetFrame(),
|
||||||
|
intermediate_frame.GetFrame(), 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto status = transfer_future.wait_for(HW_TRANSFER_TIMEOUT_MS);
|
||||||
|
|
||||||
|
if (status == std::future_status::timeout) {
|
||||||
|
LOG_ERROR(HW_GPU,
|
||||||
|
"av_hwframe_transfer_data timed out after {}ms, disabling hardware decoder",
|
||||||
|
HW_TRANSFER_TIMEOUT_MS.count());
|
||||||
|
m_hw_decoder_failed.store(true);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const int ret = transfer_future.get();
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR(HW_GPU,
|
||||||
|
"av_hwframe_transfer_data error: {}, falling back to software decoder",
|
||||||
|
AVError(ret));
|
||||||
|
m_hw_decoder_failed.store(true);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, decode the frame as normal.
|
// Otherwise, decode the frame as normal (or HW decoder failed).
|
||||||
if (!ReceiveImpl(m_temp_frame->GetFrame())) {
|
if (!ReceiveImpl(m_temp_frame->GetFrame())) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
@ -190,6 +191,7 @@ private:
|
||||||
AVCodecContext* m_codec_context{};
|
AVCodecContext* m_codec_context{};
|
||||||
s32 m_got_frame{};
|
s32 m_got_frame{};
|
||||||
std::shared_ptr<Frame> m_temp_frame{};
|
std::shared_ptr<Frame> m_temp_frame{};
|
||||||
|
std::atomic<bool> m_hw_decoder_failed{false};
|
||||||
bool m_decode_order{};
|
bool m_decode_order{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue