Browse Source

Preserve video color range and handle capture worker failures

master
evgeny 6 days ago
parent
commit
50fad4ceff
  1. 20
      tools/chatgui/src/stream_publish_engine.cpp
  2. 1
      tools/chatgui/src/stream_publish_window.cpp
  3. 7
      tools/chatgui/src/stream_video_encoder.cpp

20
tools/chatgui/src/stream_publish_engine.cpp

@ -12,6 +12,8 @@
#include <condition_variable>
#include <chrono>
#include <atomic>
#include <cstring>
#include <climits>
#include <algorithm>
extern "C" {
#include "opus_codec.h"
@ -61,10 +63,14 @@ struct StreamPublishEngine::Impl {
StreamPublishEngine::StreamPublishEngine(QObject* parent) : QObject(parent), m(std::make_unique<Impl>()) {
m_timer.setInterval(100); connect(&m_timer, &QTimer::timeout, this, &StreamPublishEngine::tick); m_timer.start();
m->probeThread = std::thread([this] {
auto codecs = supported() ? StreamVideoEncoder::available() : QList<int>();
std::lock_guard<std::mutex> guard(m->lock); m->codecs = std::move(codecs); m->probeReady = true;
});
try {
m->probeThread = std::thread([this] {
auto codecs = supported() ? StreamVideoEncoder::available() : QList<int>();
std::lock_guard<std::mutex> guard(m->lock); m->codecs = std::move(codecs); m->probeReady = true;
});
} catch (const std::system_error& error) {
DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "desktop codec probe worker failed: %s", error.what()); m->probeReady = true;
}
auto* sound = SoundManager::instance();
connect(sound, &SoundManager::contextAboutToReset, this, [this] { m_capture.close(); });
connect(sound, &SoundManager::contextRestored, this, [this] { if (m->running && m->wanted.audio) openMicrophone(); });
@ -315,8 +321,8 @@ void StreamPublishEngine::audioLoop() {
unsigned take = std::min(960 - used, record.frames - offset);
memcpy(pcm + 2 * used, record.pcm + 2 * offset, take * 2 * sizeof(int16_t)); used += take; offset += take;
if (used < 960) continue;
stream_publisher_status stats;
{ std::lock_guard<std::mutex> guard(m->lock); stats = m->stats; }
stream_publisher_status stats{};
gui_stream_publish_status(m->id, stats);
int wanted[] = {stats.compressor_enabled, stats.compressor_max_gain_db ? stats.compressor_max_gain_db : 15,
stats.compressor_rise_rate ? stats.compressor_rise_rate : 2};
if (!std::equal(wanted, wanted + 3, settings)) {
@ -378,7 +384,7 @@ void StreamPublishEngine::videoLoop() {
if (lastImage.isNull()) { DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "desktop captured frame conversion failed"); continue; }
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
if (frame.rotation() != QtVideo::Rotation::None) lastImage = lastImage.transformed(QTransform().rotate(static_cast<int>(frame.rotation())));
if (frame.mirrored()) lastImage = lastImage.mirrored(true, false);
if (frame.mirrored()) lastImage = lastImage.transformed(QTransform().scale(-1, 1));
#else
if (frame.rotationAngle()) lastImage = lastImage.transformed(QTransform().rotate(frame.rotationAngle()));
#endif

1
tools/chatgui/src/stream_publish_window.cpp

@ -2,6 +2,7 @@
#include "sound_manager.h"
#include "debug_config.h"
#include <QVBoxLayout>
#include <QCoreApplication>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QComboBox>

7
tools/chatgui/src/stream_video_encoder.cpp

@ -2,6 +2,7 @@
#include "debug_config.h"
#include <QPainter>
#include <algorithm>
#include <cstring>
extern "C" {
#include "../../../src/stream/stream_media.h"
#ifdef HAVE_FFMPEG
@ -172,11 +173,13 @@ bool StreamVideoEncoder::encode(const QImage& image, uint64_t pts, bool key, QLi
{ QPainter painter(&canvas); painter.drawImage(QRect(QPoint((canvas.width() - fitted.width()) / 2,
(canvas.height() - fitted.height()) / 2), fitted), image); }
int result = av_frame_make_writable(m->frame);
m->scale = sws_getCachedContext(m->scale, canvas.width(), canvas.height(), AV_PIX_FMT_BGRA,
m->scale = sws_getCachedContext(m->scale, canvas.width(), canvas.height(), AV_PIX_FMT_RGB32,
m->frame->width, m->frame->height, static_cast<AVPixelFormat>(m->frame->format), SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
if (!m->scale) result = AVERROR(ENOMEM);
if (result >= 0) {
const uint8_t* input[] = {canvas.constBits()}; int stride[] = {canvas.bytesPerLine()};
const int* coefficients = sws_getCoefficients(SWS_CS_ITU709);
sws_setColorspaceDetails(m->scale, coefficients, 1, coefficients, 0, 0, 1 << 16, 1 << 16);
const uint8_t* input[] = {canvas.constBits()}; int stride[] = {static_cast<int>(canvas.bytesPerLine())};
result = sws_scale(m->scale, input, stride, 0, canvas.height(), m->frame->data, m->frame->linesize);
}
m->frame->pts = static_cast<int64_t>(pts); m->frame->pict_type = key ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_NONE;

Loading…
Cancel
Save