Probe desktop decoders independently at 30 and 60 fps

This commit is contained in:
evgeny committed 2026-10-20 00:07:08 +02:00
1 parent 0d08c21330
commit f6701f81f9
2 files changed
+27 -22

No files matched your search

+26 -21
View File
@@ -16,8 +16,8 @@ extern "C" {
}
namespace {
// Отдельная проверка для 720p и Full HD: CPU-резерв 1080p не отключает GPU на 720p.
std::atomic<unsigned> gpuProfiles[2][2]{};
std::atomic<unsigned> gpuPipeline[2][2]{};
std::atomic<unsigned> gpuProfiles[2][2][2]{};
std::atomic<unsigned> gpuPipeline[2][2][2]{};
QString ffError(int value) { char text[AV_ERROR_MAX_STRING_SIZE]; av_strerror(value, text, sizeof(text)); return text; }
#ifdef _WIN32
constexpr AVHWDeviceType DeviceType = AV_HWDEVICE_TYPE_D3D11VA;
@@ -59,10 +59,11 @@ struct CallVideoDecoder::Impl {
if (!codec) { failed("allocation", AVERROR(ENOMEM)); return false; }
unsigned verifiedPipeline = 0; bool verifiedGpu = false;
for (unsigned tier = 0; tier < 2; ++tier) {
const unsigned rate = f.fps > 30 ? 1 : 0;
const unsigned width = tier ? 1920 : 1280, height = tier ? 1080 : 720;
if (std::max(f.width, f.height) <= width && uint64_t(f.width) * f.height <= width * height
&& (gpuProfiles[f.codec - 1][tier].load() & f.profile)) {
verifiedGpu = true; verifiedPipeline = std::max(verifiedPipeline, gpuPipeline[f.codec - 1][tier].load());
&& (gpuProfiles[f.codec - 1][tier][rate].load() & f.profile)) {
verifiedGpu = true; verifiedPipeline = std::max(verifiedPipeline, gpuPipeline[f.codec - 1][tier][rate].load());
break;
}
}
@@ -243,10 +244,14 @@ call_video_caps CallVideoDecoder::capabilities(const std::atomic<bool>* running)
if (initialized) return caps;
call_video_caps probed{};
for (unsigned codec = 1; codec <= 2; ++codec) {
unsigned profiles = 0, maximumTier = 0;
call_video_limit limit{};
for (unsigned profile = 1; profile <= 2; ++profile) {
for (unsigned tier = 0; tier < 2; ++tier) {
for (unsigned rate = 0; rate < 2; ++rate) {
const unsigned fps = rate ? 60 : 30;
const unsigned width = tier ? 1920 : 1280, height = tier ? 1080 : 720;
const uint8_t level = codec == 1 ? (tier ? (rate ? 42 : 40) : (rate ? 32 : 31))
: (tier ? (rate ? 123 : 120) : (rate || profile == 2 ? 120 : 93));
for (Backend backend : {Backend::HardwareOnly, Backend::SoftwareOnly}) {
if (cancelled()) return {};
bool bothOrientations = true;
@@ -254,27 +259,27 @@ call_video_caps CallVideoDecoder::capabilities(const std::atomic<bool>* running)
for (int portrait = 0; portrait <= 1 && bothOrientations; ++portrait) {
if (cancelled()) return {};
const unsigned w = portrait ? height : width, h = portrait ? width : height;
uint8_t bytes[8192]; int size = call_video_probe_key(codec, profile, w, h, bytes, sizeof(bytes));
uint8_t bytes[8192]; int size = call_video_probe_key(codec, profile, w, h, fps, bytes, sizeof(bytes));
if (size < 0) { bothOrientations = false; break; }
CallVideoDecoder decoder(backend);
call_video_frame input{}; input.call_id = 1; input.flags = CALL_VIDEO_KEY;
input.data = bytes; input.size = input.length = size;
input.format = {1, (uint16_t)w, (uint16_t)h, 30, 0,
(uint8_t)codec, (uint8_t)(codec == 1 ? (tier ? 40 : 31) : (tier || profile == 2 ? 120 : 93)),
input.format = {1, (uint16_t)w, (uint16_t)h, (uint16_t)fps, 0,
(uint8_t)codec, level,
4000000, (uint8_t)profile};
unsigned sent = 0, received = 0; bool valid = true, outputBeforeEos = false;
const int64_t start = call_video_playout_now_us();
while (valid && received < 8 && call_video_playout_now_us() - start < 1500000) {
if (cancelled()) return {};
if (sent < 8 && call_video_playout_now_us() - start >= sent * 33333ll) {
input.frame_id = sent + 1; input.pts_us = 1000000 + sent * 33333ll;
if (sent < 8 && call_video_playout_now_us() - start >= sent * 1000000ll / fps) {
input.frame_id = sent + 1; input.pts_us = 1000000 + sent * 1000000ll / fps;
int result = decoder.submit(input); if (result < 0) valid = false; else if (result) ++sent;
}
call_video_frame output{}; QImage image;
int result = decoder.receive(output, image);
if (result < 0) valid = false;
else if (result) {
valid = output.pts_us == 1000000 + received * 33333ll;
valid = output.pts_us == 1000000 + received * 1000000ll / fps;
if (!decoder.m->eos) outputBeforeEos = true;
++received;
}
@@ -282,29 +287,29 @@ call_video_caps CallVideoDecoder::capabilities(const std::atomic<bool>* running)
if (valid && received < 8) QThread::usleep(1000);
}
valid = valid && received == 8 && outputBeforeEos;
DEBUG_INFO(DEBUG_CATEGORY_CALL, "video decoder probe codec=%u profile=%u size=%ux%u backend=%d valid=%d inputs=%u outputs=%u pipeline=%u",
codec, profile, w, h, int(backend), valid, sent, received, decoder.pipelineFrames());
DEBUG_INFO(DEBUG_CATEGORY_CALL, "video decoder probe codec=%u profile=%u size=%ux%u fps=%u backend=%d valid=%d inputs=%u outputs=%u pipeline=%u",
codec, profile, w, h, fps, int(backend), valid, sent, received, decoder.pipelineFrames());
bothOrientations = valid; backendPipeline = std::max(backendPipeline, decoder.pipelineFrames());
}
if (bothOrientations) {
profiles |= profile;
maximumTier = std::max(maximumTier, tier);
limit.width = std::max<unsigned>(limit.width, width); limit.height = std::max<unsigned>(limit.height, height);
limit.fps = std::max<unsigned>(limit.fps, fps);
limit.pixels_per_second = std::max(limit.pixels_per_second, width * height * fps);
limit.maximum_bps = 4000000; limit.profiles |= profile; limit.level = std::max(limit.level, level);
#ifdef HAVE_FFMPEG
if (backend == Backend::HardwareOnly) {
gpuProfiles[codec - 1][tier].fetch_or(profile);
gpuPipeline[codec - 1][tier].store(std::max(gpuPipeline[codec - 1][tier].load(), backendPipeline));
gpuProfiles[codec - 1][tier][rate].fetch_or(profile);
gpuPipeline[codec - 1][tier][rate].store(std::max(gpuPipeline[codec - 1][tier][rate].load(), backendPipeline));
}
#endif
break;
}
}
}
}
}
if (profiles) {
const uint16_t width = maximumTier ? 1920 : 1280, height = maximumTier ? 1080 : 720;
call_video_limit limit{width, height, 30, uint32_t(width) * height * 30, 4000000, (uint8_t)profiles,
(uint8_t)(codec == 1 ? (maximumTier ? 40 : 31) : (maximumTier || (profiles & CALL_VIDEO_MAIN_HIGH_TIER) ? 120 : 93))};
if (limit.profiles) {
if (!call_video_limit_orientations(&limit, codec)) probed.decode[codec - 1] = limit;
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ public:
~CallVideoEngine() override;
void start(quint64 id);
void stop();
void setVideo(bool enabled, const QByteArray& camera, int width, int height, int codec);
void setVideo(bool enabled, const QByteArray& camera, int width, int height, int codec, int fps = 30);
void setPresentationDriven(bool enabled); // GUI-поток: окно подтверждает рисование, иначе достаточно доставки signal.
void imagePresented(quint64 serial); // GUI-поток; повторный/старый ACK безопасно игнорируется.
signals: