Browse Source

Extract live video encoder naming for reuse by calls and broadcasts

master
evgeny 5 days ago
parent
commit
dca1adc173
  1. 32
      tools/chatgui/src/live_video_encoder.cpp
  2. 20
      tools/chatgui/src/live_video_encoder.h

32
tools/chatgui/src/stream_video_encoder.cpp → tools/chatgui/src/live_video_encoder.cpp

@ -1,4 +1,4 @@
#include "stream_video_encoder.h"
#include "live_video_encoder.h"
#include "debug_config.h"
#include <QPainter>
#include <algorithm>
@ -14,9 +14,9 @@ extern "C" {
#endif
}
struct StreamVideoEncoder::Impl {
struct LiveVideoEncoder::Impl {
QString error, name;
StreamVideoConfig config;
LiveVideoConfig config;
#ifdef HAVE_FFMPEG
AVCodecContext* codec = nullptr;
AVBSFContext* filter = nullptr;
@ -29,12 +29,12 @@ struct StreamVideoEncoder::Impl {
}
#endif
};
StreamVideoEncoder::StreamVideoEncoder() : m(std::make_unique<Impl>()) {}
StreamVideoEncoder::~StreamVideoEncoder() = default;
void StreamVideoEncoder::close() { m = std::make_unique<Impl>(); }
QString StreamVideoEncoder::error() const { return m->error; }
QString StreamVideoEncoder::name() const { return m->name; }
QString StreamVideoEncoder::codecName(int codec) {
LiveVideoEncoder::LiveVideoEncoder() : m(std::make_unique<Impl>()) {}
LiveVideoEncoder::~LiveVideoEncoder() = default;
void LiveVideoEncoder::close() { m = std::make_unique<Impl>(); }
QString LiveVideoEncoder::error() const { return m->error; }
QString LiveVideoEncoder::name() const { return m->name; }
QString LiveVideoEncoder::codecName(int codec) {
static const char* names[] = {"", "H.264", "H.265", "VP9", "AV1", "H.266"};
return codec >= 1 && codec <= 5 ? QString::fromLatin1(names[codec]) : QString();
}
@ -69,7 +69,7 @@ AVPixelFormat softwareFormat(const AVCodec* codec) {
}
#endif
bool StreamVideoEncoder::open(const StreamVideoConfig& config) {
bool LiveVideoEncoder::open(const LiveVideoConfig& config) {
close();
if (config.width < 16 || config.height < 16 || config.width > 4096 || config.height > 4096
|| config.width % 2 || config.height % 2 || config.fps < 1 || config.fps > 60
@ -152,7 +152,7 @@ bool StreamVideoEncoder::open(const StreamVideoConfig& config) {
}
if (!pass) {
QImage probe(config.width, config.height, QImage::Format_RGB32); probe.fill(Qt::black);
QList<StreamEncodedFrame> output;
QList<LiveEncodedFrame> output;
if (!encode(probe, 0, true, output) || output.isEmpty() || !output.front().key) {
DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "desktop encoder probe lacks immediate KEY name=%s error=%s", name.constData(), qPrintable(m->error));
break;
@ -176,7 +176,7 @@ bool StreamVideoEncoder::open(const StreamVideoConfig& config) {
DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "desktop encoder open failed: %s", qPrintable(m->error)); return false;
}
bool StreamVideoEncoder::encode(const QImage& image, uint64_t pts, bool key, QList<StreamEncodedFrame>& output) {
bool LiveVideoEncoder::encode(const QImage& image, uint64_t pts, bool key, QList<LiveEncodedFrame>& output) {
#ifdef HAVE_FFMPEG
if (!m->codec || !m->frame || image.isNull() || pts > INT64_MAX) {
m->error = "Invalid video frame"; DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "desktop encode invalid frame/state"); return false;
@ -217,7 +217,7 @@ bool StreamVideoEncoder::encode(const QImage& image, uint64_t pts, bool key, QLi
if (result >= 0) result = av_bsf_receive_packet(m->filter, packet);
if (result < 0) break;
}
StreamEncodedFrame encoded; encoded.key = (packet->flags & AV_PKT_FLAG_KEY) != 0;
LiveEncodedFrame encoded; encoded.key = (packet->flags & AV_PKT_FLAG_KEY) != 0;
encoded.pts = packet->pts >= 0 ? static_cast<uint64_t>(packet->pts) : pts;
if (key) DEBUG_DEBUG(DEBUG_CATEGORY_VIDEO, "desktop requested KEY name=%s input_PTS=%llu output_PTS=%llu key=%d flags=%x bytes=%d",
qPrintable(m->name), (unsigned long long)pts, (unsigned long long)encoded.pts, encoded.key, packet->flags, packet->size);
@ -246,7 +246,7 @@ bool StreamVideoEncoder::encode(const QImage& image, uint64_t pts, bool key, QLi
#endif
}
QList<int> StreamVideoEncoder::available() {
QList<int> LiveVideoEncoder::available() {
QList<int> result;
for (int codec = 1; codec <= 5; codec++) {
#ifdef HAVE_FFMPEG
@ -254,13 +254,13 @@ QList<int> StreamVideoEncoder::available() {
for (const auto& name : encoders(codec)) if (avcodec_find_encoder_by_name(name.constData())) { installed = true; break; }
if (!installed) { DEBUG_DEBUG(DEBUG_CATEGORY_VIDEO, "desktop codec has no installed encoder codec=%d", codec); continue; }
#endif
StreamVideoEncoder encoder; StreamVideoConfig config; config.width = 320; config.height = 180; config.codec = codec;
LiveVideoEncoder encoder; LiveVideoConfig config; config.width = 320; config.height = 180; config.codec = codec;
if (encoder.open(config)) result.push_back(codec);
}
return result;
}
bool StreamVideoEncoder::setBitrate(int bitrate) {
bool LiveVideoEncoder::setBitrate(int bitrate) {
if (bitrate < 64000 || bitrate > 16000000) { DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "desktop live bitrate invalid value=%d", bitrate); return false; }
#ifdef HAVE_FFMPEG
// libx264 перечитывает эти три значения через reconfig_encoder при подаче следующего кадра.

20
tools/chatgui/src/stream_video_encoder.h → tools/chatgui/src/live_video_encoder.h

@ -9,19 +9,23 @@
#include <memory>
#include <cstdint>
struct StreamVideoConfig {
enum class LiveVideoProfile { Automatic, H264ConstrainedBaseline, H265Main };
struct LiveVideoConfig {
int width = 1280, height = 720, fps = 30, bitrate = 2500000, codec = 1, rotation = 0;
bool operator==(const StreamVideoConfig&) const = default;
LiveVideoProfile profile = LiveVideoProfile::Automatic;
int level = 0, references = 0, vbvBits = 0; // level: AVC level_idc / HEVC general_level_idc; 0 — auto.
QString backend; // Пусто — проба доступных; непусто — только уже проверенный encoder.
bool operator==(const LiveVideoConfig&) const = default;
};
struct StreamEncodedFrame { QByteArray data; uint64_t pts = 0; bool key = false; };
class StreamVideoEncoder {
struct LiveEncodedFrame { QByteArray data; uint64_t pts = 0; bool key = false; };
class LiveVideoEncoder {
public:
StreamVideoEncoder();
~StreamVideoEncoder();
bool open(const StreamVideoConfig& config);
LiveVideoEncoder();
~LiveVideoEncoder();
bool open(const LiveVideoConfig& config);
bool setBitrate(int bitrate); // true — изменение на следующем кадре; false — нужна смена видеоконтекста
void close();
bool encode(const QImage& image, uint64_t pts, bool key, QList<StreamEncodedFrame>& output);
bool encode(const QImage& image, uint64_t pts, bool key, QList<LiveEncodedFrame>& output);
QString error() const;
QString name() const;
static QList<int> available(); // реальная проба открытия и первого KEY; вызывать вне GUI
Loading…
Cancel
Save