Carry selected video frame rate through desktop call settings
This commit is contained in:
1 parent
f6701f81f9
commit
0830fe4461
2 files changed
+36
-22
No files matched your search
@@ -45,7 +45,7 @@ struct CallVideoEngine::Impl {
|
||||
std::atomic<bool> running{false};
|
||||
uint64_t id = 0, revision = 1;
|
||||
bool enabled = false;
|
||||
int width = 640, height = 480, codec = 0;
|
||||
int width = 640, height = 480, codec = 0, fps = 30;
|
||||
int64_t pts = -1;
|
||||
int64_t clockCorrection = 0;
|
||||
QImage capturedImage;
|
||||
@@ -215,7 +215,7 @@ void CallVideoEngine::start(quint64 id) {
|
||||
}
|
||||
void CallVideoEngine::closeCamera() {
|
||||
#ifdef HAVE_STREAM_CAPTURE
|
||||
if (m->captureActive) m->capture->configure(false, m->cameraId, m->width, m->height);
|
||||
if (m->captureActive) m->capture->configure(false, m->cameraId, m->width, m->height, m->fps);
|
||||
#endif
|
||||
m->captureActive = false;
|
||||
{ std::lock_guard<std::mutex> guard(m->lock); m->capturedImage = {}; m->pts = -1; ++m->wakeSerial; }
|
||||
@@ -234,19 +234,19 @@ void CallVideoEngine::stop() {
|
||||
while (const auto* event = m->logEvents.readSlot()) { call_video_playout_log_event(event); m->logEvents.release(); }
|
||||
m->id = 0; m->enabled = false; emit imageChanged({}, 0);
|
||||
}
|
||||
void CallVideoEngine::setVideo(bool enabled, const QByteArray& cameraId, int width, int height, int codec) {
|
||||
void CallVideoEngine::setVideo(bool enabled, const QByteArray& cameraId, int width, int height, int codec, int fps) {
|
||||
const bool active = enabled && m->running;
|
||||
const bool captureChanged = active != m->captureActive || cameraId != m->cameraId || width != m->width || height != m->height;
|
||||
const bool captureChanged = active != m->captureActive || cameraId != m->cameraId || width != m->width || height != m->height || fps != m->fps;
|
||||
{ std::lock_guard<std::mutex> guard(m->lock);
|
||||
if (m->enabled == enabled && cameraId == m->cameraId && width == m->width && height == m->height && codec == m->codec
|
||||
if (m->enabled == enabled && cameraId == m->cameraId && width == m->width && height == m->height && codec == m->codec && fps == m->fps
|
||||
&& !captureChanged) return;
|
||||
m->enabled = enabled; m->width = width; m->height = height; m->codec = codec; ++m->revision; ++m->wakeSerial;
|
||||
m->enabled = enabled; m->width = width; m->height = height; m->codec = codec; m->fps = fps; ++m->revision; ++m->wakeSerial;
|
||||
if (captureChanged) { m->capturedImage = {}; m->pts = -1; } }
|
||||
m->cameraId = cameraId; m->captureActive = active; m->wake.notify_one();
|
||||
if (!captureChanged) return;
|
||||
emit localImageChanged({});
|
||||
#ifdef HAVE_STREAM_CAPTURE
|
||||
m->capture->configure(active, cameraId, width, height);
|
||||
m->capture->configure(active, cameraId, width, height, fps);
|
||||
#else
|
||||
if (active) m->report(tr("Video capture is unavailable in this build"));
|
||||
#endif
|
||||
@@ -257,9 +257,11 @@ void CallVideoEngine::transmit() {
|
||||
// Не связываем приём с наличием собственного encoder.
|
||||
for (unsigned codec = 1; codec <= 2 && m->running; ++codec) {
|
||||
for (const QSize size : {QSize(1920, 1080), QSize(1280, 720)}) {
|
||||
for (unsigned fps : {30u, 60u}) {
|
||||
const bool fullhd = size.width() == 1920;
|
||||
call_video_format probe{1, (uint16_t)size.width(), (uint16_t)size.height(), 30, 0, (uint8_t)codec,
|
||||
(uint8_t)(codec == 1 ? (fullhd ? 40 : 31) : (fullhd ? 120 : 93)), 4000000,
|
||||
call_video_format probe{1, (uint16_t)size.width(), (uint16_t)size.height(), (uint16_t)fps, 0, (uint8_t)codec,
|
||||
(uint8_t)(codec == 1 ? (fullhd ? (fps > 30 ? 42 : 40) : (fps > 30 ? 32 : 31))
|
||||
: (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) {
|
||||
@@ -270,12 +272,17 @@ void CallVideoEngine::transmit() {
|
||||
codec, probe.width, probe.height, qPrintable(encoder.error()));
|
||||
}
|
||||
if (bothOrientations && m->running) {
|
||||
call_video_limit limit{(uint16_t)size.width(), (uint16_t)size.height(), 30,
|
||||
(uint32_t)(size.width() * size.height() * 30), 4000000, probe.profile, probe.level};
|
||||
if (!call_video_limit_orientations(&limit, codec)) caps.encode[codec - 1] = limit;
|
||||
break;
|
||||
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);
|
||||
limit.pixels_per_second = std::max<unsigned>(limit.pixels_per_second, size.width() * size.height() * fps);
|
||||
limit.maximum_bps = 4000000; limit.profiles = probe.profile; limit.level = std::max(limit.level, probe.level);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "call encoder probe codec=%u size=%dx%d fps=%u level=%u verified=1",
|
||||
codec, size.width(), size.height(), fps, probe.level);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (caps.encode[codec - 1].profiles && call_video_limit_orientations(&caps.encode[codec - 1], codec)) caps.encode[codec - 1] = {};
|
||||
}
|
||||
if (!m->running) return;
|
||||
if (call_video_port_open(m->id, &caps) < 0) { m->report(tr("Video transport is unavailable")); return; }
|
||||
@@ -302,11 +309,12 @@ void CallVideoEngine::transmit() {
|
||||
struct call_video_port_status state{};
|
||||
if (call_video_port_status(m->id, &state) < 0) break;
|
||||
if (state.error) { m->report(tr("Core rejected video format")); break; }
|
||||
uint64_t revision, captured; bool enabled; int width, height, codec; int64_t pts, clockCorrection;
|
||||
uint64_t revision, captured; bool enabled; int width, height, codec, fps; int64_t pts, clockCorrection;
|
||||
QImage image;
|
||||
{ std::lock_guard<std::mutex> guard(m->lock);
|
||||
revision = m->revision; enabled = m->enabled; width = m->width; height = m->height; codec = m->codec; pts = m->pts;
|
||||
captured = m->captured;
|
||||
fps = m->fps;
|
||||
clockCorrection = m->clockCorrection; image = m->capturedImage; wakeSerial = m->wakeSerial;
|
||||
}
|
||||
int64_t now = nowUs();
|
||||
@@ -345,7 +353,7 @@ void CallVideoEngine::transmit() {
|
||||
if (format.generation && state.have_peer && !call_video_format_supported(&caps, &state.peer, &format)) appliedRevision = 0;
|
||||
if (!enabled || !state.have_peer || pts < 0) { idle(); continue; }
|
||||
if (revision != appliedRevision) {
|
||||
call_video_format next{format.generation + 1, (uint16_t)width, (uint16_t)height, 30, 0, (uint8_t)codec, 0, 4000000, 0};
|
||||
call_video_format next{format.generation + 1, (uint16_t)width, (uint16_t)height, (uint16_t)fps, 0, (uint8_t)codec, 0, 4000000, 0};
|
||||
bool opened = false;
|
||||
uint32_t minimum = state.minimum_bps ? state.minimum_bps : 300000;
|
||||
uint32_t maximum = state.maximum_bps ? state.maximum_bps : 4000000;
|
||||
|
||||
@@ -343,26 +343,31 @@ CallWindow::CallWindow(QWidget* parent)
|
||||
m_resolution = new QComboBox(this);
|
||||
auto refreshModes = [this] {
|
||||
QSize wanted = m_resolution->currentData().toSize();
|
||||
const int wantedFps = m_resolution->currentData(Qt::UserRole + 1).toInt() ?: 30;
|
||||
if (wanted.isEmpty()) wanted = QSize(640, 480);
|
||||
m_resolution->clear();
|
||||
for (const auto& value : m_camera->currentData(Qt::UserRole + 1).toList()) {
|
||||
const QSize size = value.toSize();
|
||||
m_resolution->addItem(QStringLiteral("%1×%2").arg(size.width()).arg(size.height()), size);
|
||||
const auto mode = value.toList(); const QSize size = mode[0].toSize(); const int fps = mode[1].toInt();
|
||||
m_resolution->addItem(QStringLiteral("%1×%2 · %3 fps").arg(size.width()).arg(size.height()).arg(fps), size);
|
||||
m_resolution->setItemData(m_resolution->count() - 1, fps, Qt::UserRole + 1);
|
||||
}
|
||||
int index = m_resolution->findData(wanted);
|
||||
int index = -1;
|
||||
for (int i = 0; i < m_resolution->count(); ++i)
|
||||
if (m_resolution->itemData(i).toSize() == wanted && m_resolution->itemData(i, Qt::UserRole + 1).toInt() == wantedFps) index = i;
|
||||
if (index < 0) index = m_resolution->findData(QSize(640, 480));
|
||||
if (index < 0) index = m_resolution->count() - 1;
|
||||
m_resolution->setCurrentIndex(index); m_resolution->setEnabled(index >= 0);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "call camera resolutions device=%s count=%d requested=%dx%d selected=%dx%d fps=30",
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "call camera resolutions device=%s count=%d requested=%dx%d selected=%dx%d fps=%d",
|
||||
m_camera->currentData().toByteArray().constData(), m_resolution->count(), wanted.width(), wanted.height(),
|
||||
m_resolution->currentData().toSize().width(), m_resolution->currentData().toSize().height());
|
||||
m_resolution->currentData().toSize().width(), m_resolution->currentData().toSize().height(),
|
||||
m_resolution->currentData(Qt::UserRole + 1).toInt());
|
||||
};
|
||||
connect(m_video, &CallVideoEngine::camerasChanged, this, [this, refreshModes](const CallCameraDevices& cameras) {
|
||||
const auto selected = m_camera->currentData();
|
||||
m_camera->clear();
|
||||
for (const auto& camera : cameras) {
|
||||
QVariantList sizes;
|
||||
for (const auto& mode : camera.modes) sizes.append(mode.size);
|
||||
for (const auto& mode : camera.modes) sizes.append(QVariant(QVariantList{mode.size, mode.fps}));
|
||||
m_camera->addItem(camera.name, camera.id);
|
||||
m_camera->setItemData(m_camera->count() - 1, sizes, Qt::UserRole + 1);
|
||||
}
|
||||
@@ -568,7 +573,8 @@ void CallWindow::applyVideo() {
|
||||
m_videoStatus->setText(callText("No supported video modes")); m_videoStatus->show();
|
||||
}
|
||||
if (size.isEmpty()) size = QSize(640, 480);
|
||||
m_video->setVideo(enabled, m_camera->currentData().toByteArray(), size.width(), size.height(), m_codec->currentData().toInt());
|
||||
const int fps = m_resolution->currentData(Qt::UserRole + 1).toInt();
|
||||
m_video->setVideo(enabled, m_camera->currentData().toByteArray(), size.width(), size.height(), m_codec->currentData().toInt(), fps ? fps : 30);
|
||||
}
|
||||
|
||||
void CallWindow::postCallFn(void (*fn)(void*), uint64_t callId) {
|
||||
|
||||
Reference in new issue
Block a user