Recover real GPU decoder failures on CPU without treating ordinary EAGAIN as frame loss
This commit is contained in:
1 parent
f9348ce36f
commit
a4a687be4c
3 files changed
+25
-5
No files matched your search
@@ -82,6 +82,11 @@ unsigned CallVideoDecoder::pendingFrames() const { return static_cast<unsigned>(
|
||||
unsigned CallVideoDecoder::pipelineFrames() const { return m->pipeline; }
|
||||
bool CallVideoDecoder::hardware() const { return m->gpu; }
|
||||
QString CallVideoDecoder::error() const { return m->error; }
|
||||
void CallVideoDecoder::useSoftware() {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_CALL, "video decoder switching to CPU after device failure pending=%zu; next input must be KEY",
|
||||
m->pending.size());
|
||||
close(); m->backend = Backend::SoftwareOnly;
|
||||
}
|
||||
void CallVideoDecoder::close() {
|
||||
#ifdef HAVE_FFMPEG
|
||||
if (m->codec) DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "video decoder close generation=%llu pending=%zu eos=%d",
|
||||
@@ -107,6 +112,8 @@ int CallVideoDecoder::submit(const call_video_frame& f) {
|
||||
#ifdef HAVE_FFMPEG
|
||||
if (!call_video_format_valid(&f.format) || !f.data || !f.size || f.size > CALL_VIDEO_MAX_FRAME)
|
||||
return m->failed("input format", AVERROR_INVALIDDATA);
|
||||
if (!m->pending.empty() && f.pts_us <= m->pending.back().pts_us)
|
||||
return m->failed("non-monotonic input PTS", AVERROR_INVALIDDATA);
|
||||
const uint8_t* data = f.data; unsigned size = f.size;
|
||||
if (f.flags & CALL_VIDEO_KEY) {
|
||||
if (call_video_check_key(&f.format, data, size)) return m->failed("KEY bitstream", AVERROR_INVALIDDATA);
|
||||
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
unsigned pipelineFrames() const; // Минимальный входной pipeline, измеренный отдельной paced пробой.
|
||||
bool hardware() const;
|
||||
QString error() const;
|
||||
void useSoftware(); // После реального отказа устройства: следующий KEY открывает CPU, без повторной GPU пробы.
|
||||
void close();
|
||||
static call_video_caps capabilities();
|
||||
private:
|
||||
|
||||
@@ -385,7 +385,7 @@ void CallVideoEngine::receive() {
|
||||
unsigned submitted = 0, acknowledged = 0;
|
||||
uint64_t reportedGeneration = 0, rejectedGeneration = 0;
|
||||
call_video_frame input{};
|
||||
bool wakeBound = false;
|
||||
bool wakeBound = false, waitingKey = false;
|
||||
while (m->running) {
|
||||
const uint64_t ticket = m->rxWake.ticket();
|
||||
if (requestedWake) wakeLateMax = std::max(wakeLateMax, nowUs() - requestedWake);
|
||||
@@ -416,7 +416,11 @@ void CallVideoEngine::receive() {
|
||||
const int64_t started = nowUs(); int result = decoder.receive(packet, image);
|
||||
decodeMax = std::max(decodeMax, nowUs() - started);
|
||||
if (result < 0) {
|
||||
m->report(decoder.error()); decoder.close(); call_video_port_request_key(m->id); break;
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video decoder recovery call=%llu lost_inputs=%u retained_ready=%zu awaiting=%d error=%s",
|
||||
(unsigned long long)m->id, decoder.pendingFrames(), pictures.size(), playout.awaiting, qPrintable(decoder.error()));
|
||||
m->report(decoder.error());
|
||||
if (decoder.hardware()) decoder.useSoftware(); else decoder.close();
|
||||
waitingKey = true; call_video_port_request_key(m->id); break;
|
||||
}
|
||||
if (!result) break;
|
||||
++decoded; worked = true; rxAgeMax = std::max(rxAgeMax, nowUs() - packet.received_us);
|
||||
@@ -428,15 +432,23 @@ void CallVideoEngine::receive() {
|
||||
if (pictures.size() + playout.awaiting < 3 && decoder.pendingFrames() < 8) {
|
||||
if (!input.data) call_video_port_pull(m->id, &input);
|
||||
if (input.data) {
|
||||
if (input.format.generation == rejectedGeneration || (waitingKey && !(input.flags & CALL_VIDEO_KEY))) {
|
||||
u_free((void*)input.data); input = {}; requestedWake = 0; continue;
|
||||
}
|
||||
const int64_t started = nowUs();
|
||||
int result = decoder.submit(input);
|
||||
decodeMax = std::max(decodeMax, nowUs() - started);
|
||||
if (result) {
|
||||
worked = true;
|
||||
if (result > 0) ++submitted;
|
||||
if (result > 0) { ++submitted; waitingKey = false; }
|
||||
else {
|
||||
rejectedGeneration = input.format.generation;
|
||||
call_video_port_decoded(m->id, rejectedGeneration, 0); m->report(decoder.error()); decoder.close();
|
||||
m->report(decoder.error());
|
||||
if (decoder.hardware()) decoder.useSoftware();
|
||||
else {
|
||||
rejectedGeneration = input.format.generation;
|
||||
call_video_port_decoded(m->id, rejectedGeneration, 0); decoder.close();
|
||||
}
|
||||
waitingKey = true; call_video_port_request_key(m->id);
|
||||
}
|
||||
u_free((void*)input.data); input = {};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user