Prepare and cache desktop video codecs once at application startup
This commit is contained in:
1 parent
0cd1955606
commit
e3b74de7ef
3 files changed
+53
-5
No files matched your search
@@ -9,6 +9,7 @@
|
||||
#include "../../../src/call/call_audio.h"
|
||||
#include "debug_config.h"
|
||||
#include "mem.h"
|
||||
#include <QThread>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
@@ -252,10 +253,26 @@ void CallVideoEngine::setVideo(bool enabled, const QByteArray& cameraId, int wid
|
||||
#endif
|
||||
}
|
||||
|
||||
void CallVideoEngine::transmit() {
|
||||
call_video_caps caps = CallVideoDecoder::capabilities(&m->running);
|
||||
call_video_caps CallVideoEngine::capabilities(const std::atomic<bool>* running) {
|
||||
static std::mutex lock;
|
||||
static call_video_caps verified{};
|
||||
static bool initialized = false;
|
||||
const int64_t started = nowUs();
|
||||
auto cancelled = [running] {
|
||||
if (!running || running->load()) return false;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "video codec preparation cancelled; completed cache retained"); return true;
|
||||
};
|
||||
std::unique_lock<std::mutex> guard(lock, std::defer_lock);
|
||||
while (!guard.try_lock()) { if (cancelled()) return {}; QThread::usleep(1000); }
|
||||
if (cancelled()) return {};
|
||||
if (initialized) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "video codec capabilities cache hit wait_us=%lld", (long long)(nowUs() - started));
|
||||
return verified;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "video codec preparation begin; camera and network unused");
|
||||
call_video_caps caps = CallVideoDecoder::capabilities(running);
|
||||
// Не связываем приём с наличием собственного encoder.
|
||||
for (unsigned codec = 1; codec <= 2 && m->running; ++codec) {
|
||||
for (unsigned codec = 1; codec <= 2; ++codec) {
|
||||
for (const QSize size : {QSize(1920, 1080), QSize(1280, 720)}) {
|
||||
for (unsigned fps : {30u, 50u, 60u}) {
|
||||
const bool fullhd = size.width() == 1920;
|
||||
@@ -264,14 +281,15 @@ void CallVideoEngine::transmit() {
|
||||
: (fullhd ? (fps > 30 ? 123 : 120) : (fps > 30 ? 120 : 93))), 4000000,
|
||||
(uint8_t)(codec == 1 ? CALL_VIDEO_CONSTRAINED_BASELINE : CALL_VIDEO_MAIN)};
|
||||
bool bothOrientations = true;
|
||||
for (int portrait = 0; portrait <= 1 && bothOrientations && m->running; ++portrait) {
|
||||
for (int portrait = 0; portrait <= 1 && bothOrientations; ++portrait) {
|
||||
if (cancelled()) return {};
|
||||
probe.width = portrait ? size.height() : size.width(); probe.height = portrait ? size.width() : size.height();
|
||||
CallVideoEncoder encoder;
|
||||
bothOrientations = encoder.open(probe, 1000000);
|
||||
if (!bothOrientations) DEBUG_WARN(DEBUG_CATEGORY_CALL, "call codec probe unavailable codec=%u size=%ux%u: %s",
|
||||
codec, probe.width, probe.height, qPrintable(encoder.error()));
|
||||
}
|
||||
if (bothOrientations && m->running) {
|
||||
if (bothOrientations) {
|
||||
auto& limit = caps.encode[codec - 1];
|
||||
limit.width = std::max<int>(limit.width, size.width()); limit.height = std::max<int>(limit.height, size.height());
|
||||
limit.fps = std::max<unsigned>(limit.fps, fps);
|
||||
@@ -284,6 +302,16 @@ void CallVideoEngine::transmit() {
|
||||
}
|
||||
if (caps.encode[codec - 1].profiles && call_video_limit_orientations(&caps.encode[codec - 1], codec)) caps.encode[codec - 1] = {};
|
||||
}
|
||||
if (cancelled()) return {};
|
||||
verified = caps; initialized = true;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "video codec preparation complete elapsed_us=%lld encode=%u/%u decode=%u/%u",
|
||||
(long long)(nowUs() - started), caps.encode[0].profiles, caps.encode[1].profiles,
|
||||
caps.decode[0].profiles, caps.decode[1].profiles);
|
||||
return verified;
|
||||
}
|
||||
|
||||
void CallVideoEngine::transmit() {
|
||||
const call_video_caps caps = capabilities(&m->running);
|
||||
if (!m->running) return;
|
||||
if (call_video_port_open(m->id, &caps) < 0) { m->report(tr("Video transport is unavailable")); return; }
|
||||
CallVideoEncoder encoder;
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#include <QImage>
|
||||
#include <QTimer>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include "call_camera_capture.h"
|
||||
#include "../../../src/call/call_video.h"
|
||||
|
||||
// Камера изолирована в процессе. TX/decoder владеют codec; отдельный playout получает готовые CPU-изображения.
|
||||
class CallVideoEngine : public QObject {
|
||||
@@ -11,6 +13,9 @@ class CallVideoEngine : public QObject {
|
||||
public:
|
||||
explicit CallVideoEngine(QObject* parent = nullptr);
|
||||
~CallVideoEngine() override;
|
||||
// Блокирующая подготовка только в worker: один общий кэш encoder/decoder на процесс, без камеры и сети.
|
||||
// running отменяет ожидание/пробу; частичный результат не кэшируется. nullptr — без отмены.
|
||||
static call_video_caps capabilities(const std::atomic<bool>* running = nullptr);
|
||||
void start(quint64 id);
|
||||
void stop();
|
||||
void setVideo(bool enabled, const QByteArray& camera, int width, int height, int codec, int fps = 30);
|
||||
|
||||
@@ -19,11 +19,13 @@
|
||||
#include <QVBoxLayout>
|
||||
#include "gui_language.h"
|
||||
#include "call_camera_capture.h"
|
||||
#include "call_video_engine.h"
|
||||
#include "single_instance.h"
|
||||
#include "config_parser.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <future>
|
||||
#ifdef _WIN32
|
||||
#include <QStandardPaths>
|
||||
#include <windows.h>
|
||||
@@ -342,6 +344,14 @@ int main(int argc, char *argv[]) {
|
||||
cfg.debugLevel(), cfg.debugCategories());
|
||||
instance.setWindow(&w);
|
||||
if (minimized) w.showMinimized(); else w.show();
|
||||
// Пробы не используют камеры и сеть; будущие звонки берут общий кэш без повторной подготовки.
|
||||
std::atomic<bool> prepareVideo{true};
|
||||
std::future<void> videoPreparation;
|
||||
try {
|
||||
videoPreparation = std::async(std::launch::async, [&prepareVideo] { CallVideoEngine::capabilities(&prepareVideo); });
|
||||
} catch (const std::exception& error) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video codec background preparation could not start: %s", error.what());
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "GUI startup: minimized_requested=%d minimized=%d activation_server=%s",
|
||||
minimized, w.isMinimized(), qPrintable(instance.serverName()));
|
||||
|
||||
@@ -352,6 +362,11 @@ int main(int argc, char *argv[]) {
|
||||
#endif
|
||||
|
||||
int ret = app.exec();
|
||||
prepareVideo = false;
|
||||
if (videoPreparation.valid()) {
|
||||
try { videoPreparation.get(); }
|
||||
catch (const std::exception& error) { DEBUG_ERROR(DEBUG_CATEGORY_CALL, "video codec background preparation failed: %s", error.what()); }
|
||||
}
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_GENERAL, "main: app.exec() returned %d", ret);
|
||||
return ret;
|
||||
}
|
||||
Reference in new issue
Block a user