Browse Source

Trace HEVC key frame quantization and reduce AMF log noise

stream-multiview
evgeny 6 days ago
parent
commit
f7853f145c
  1. 38
      src/video/video.c
  2. 33
      tools/chatgui/src/live_video_encoder.cpp

38
src/video/video.c

@ -15,6 +15,7 @@
#ifdef HAVE_FFMPEG #ifdef HAVE_FFMPEG
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavcodec/bsf.h>
#include <libavutil/avutil.h> #include <libavutil/avutil.h>
#include <libavutil/imgutils.h> #include <libavutil/imgutils.h>
#include <libavutil/opt.h> #include <libavutil/opt.h>
@ -66,24 +67,43 @@ int video_extract_thumbnail(const char* src, const char* jpg_out, int max_w) {
static pthread_once_t g_ffmpeg_once = PTHREAD_ONCE_INIT; static pthread_once_t g_ffmpeg_once = PTHREAD_ONCE_INIT;
/* AMF передаёт свой внутренний трейс через AV_LOG_DEBUG. Остальные подробные логи FFmpeg отсекаем. */ /* Пропускаем диагностику AMF и существенные поля trace_headers, остальные подробности FFmpeg отсекаем. */
static void video_av_log_cb(void* avcl, int level, const char* fmt, va_list vl) { static void video_av_log_cb(void* avcl, int level, const char* fmt, va_list vl) {
const char *encoder = NULL; const char *encoder = NULL;
int headers = 0;
if (level > AV_LOG_WARNING) { if (level > AV_LOG_WARNING) {
if (!debug_should_output(DEBUG_LEVEL_TRACE, DEBUG_CATEGORY_DEBUG)) return; if (!debug_should_output(DEBUG_LEVEL_TRACE, DEBUG_CATEGORY_DEBUG)) return;
if (!avcl || *(const AVClass **)avcl != avcodec_get_class()) return; if (!avcl) return;
const AVCodecContext *codec = avcl; if (*(const AVClass **)avcl == av_bsf_get_class()) {
if (!codec->codec || !codec->codec->name) return; const AVBSFContext *filter = avcl;
const char *name = codec->codec->name; if (!filter->filter || strcmp(filter->filter->name, "trace_headers")) return;
size_t length = strlen(name); headers = 1;
if (length < 4 || strcmp(name + length - 4, "_amf")) return; } else {
encoder = name; if (*(const AVClass **)avcl != avcodec_get_class()) return;
const AVCodecContext *codec = avcl;
if (!codec->codec || !codec->codec->name) return;
const char *name = codec->codec->name;
size_t length = strlen(name);
if (length < 4 || strcmp(name + length - 4, "_amf")) return;
encoder = name;
}
} }
char buf[1024]; char buf[1024];
vsnprintf(buf, sizeof(buf), fmt, vl); vsnprintf(buf, sizeof(buf), fmt, vl);
size_t len = strlen(buf); size_t len = strlen(buf);
while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r')) buf[--len] = '\0'; while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r')) buf[--len] = '\0';
if (encoder) DEBUG_TRACE(DEBUG_CATEGORY_DEBUG, "ffmpeg AMF encoder=%s: %s", encoder, buf); if (headers) {
if (!strstr(buf, "Packet:") && !strstr(buf, "init_qp_minus26") && !strstr(buf, "slice_qp_delta")
&& !strstr(buf, "pic_width_in_luma_samples") && !strstr(buf, "pic_height_in_luma_samples")
&& !strstr(buf, "pic_parameter_set_id") && !strstr(buf, "cu_qp_delta_enabled_flag")
&& !strstr(buf, "diff_cu_qp_delta_depth") && !strstr(buf, "slice_type")) return;
DEBUG_TRACE(DEBUG_CATEGORY_DEBUG, "ffmpeg headers: %s", buf);
} else if (encoder) {
if (!strstr(buf, "Warning:") && !strstr(buf, "Error:")
&& (strstr(buf, "::SubmitInput() : format") || strstr(buf, "SubmitToEncoder() End: frame pts=")
|| strstr(buf, "::QueryOutput()") || strstr(buf, "QueryOutput() End: frame pts="))) return;
DEBUG_TRACE(DEBUG_CATEGORY_DEBUG, "ffmpeg AMF encoder=%s: %s", encoder, buf);
}
else if (level <= AV_LOG_ERROR) DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "ffmpeg: %s", buf); else if (level <= AV_LOG_ERROR) DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "ffmpeg: %s", buf);
else DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "ffmpeg: %s", buf); else DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "ffmpeg: %s", buf);
} }

33
tools/chatgui/src/live_video_encoder.cpp

@ -32,11 +32,13 @@ struct LiveVideoEncoder::Impl {
#ifdef HAVE_FFMPEG #ifdef HAVE_FFMPEG
AVCodecContext* codec = nullptr; AVCodecContext* codec = nullptr;
AVBSFContext* filter = nullptr; AVBSFContext* filter = nullptr;
AVBSFContext* headers = nullptr; // Только чтение заголовков KEY при debug=trace, исходный пакет не меняется.
bool headersAttempted = false;
AVFrame* frame = nullptr; AVFrame* frame = nullptr;
AVBufferRef* device = nullptr; AVBufferRef* device = nullptr;
SwsContext* scale = nullptr; SwsContext* scale = nullptr;
~Impl() { ~Impl() {
av_bsf_free(&filter); avcodec_free_context(&codec); av_frame_free(&frame); av_bsf_free(&headers); av_bsf_free(&filter); avcodec_free_context(&codec); av_frame_free(&frame);
av_buffer_unref(&device); sws_freeContext(scale); av_buffer_unref(&device); sws_freeContext(scale);
} }
#endif #endif
@ -423,6 +425,35 @@ bool LiveVideoEncoder::encode(const QImage& image, uint64_t pts, bool key, QList
if (result >= 0) result = av_bsf_receive_packet(m->filter, packet); if (result >= 0) result = av_bsf_receive_packet(m->filter, packet);
if (result < 0) break; if (result < 0) break;
} }
if (m->config.codec == STREAM_MEDIA_H265 && (packet->flags & AV_PKT_FLAG_KEY)
&& debug_should_output(DEBUG_LEVEL_TRACE, DEBUG_CATEGORY_DEBUG)) {
int diagnostic = 0;
if (!m->headersAttempted) {
m->headersAttempted = true;
const auto* trace = av_bsf_get_by_name("trace_headers");
diagnostic = trace ? av_bsf_alloc(trace, &m->headers) : AVERROR(ENOSYS);
if (diagnostic >= 0) diagnostic = m->filter ? avcodec_parameters_copy(m->headers->par_in, m->filter->par_out)
: avcodec_parameters_from_context(m->headers->par_in, m->codec);
if (diagnostic >= 0) {
m->headers->time_base_in = m->codec->time_base;
diagnostic = av_bsf_init(m->headers);
}
if (diagnostic >= 0) DEBUG_INFO(DEBUG_CATEGORY_DEBUG,
"HEVC KEY header diagnostics enabled name=%s; slice_QP=26+init_qp_minus26+slice_qp_delta",
qPrintable(m->name));
}
if (m->headers && diagnostic >= 0) {
AVPacket* copy = av_packet_clone(packet);
diagnostic = copy ? av_bsf_send_packet(m->headers, copy) : AVERROR(ENOMEM);
if (diagnostic >= 0) diagnostic = av_bsf_receive_packet(m->headers, copy);
av_packet_free(&copy);
}
if (diagnostic < 0) {
DEBUG_WARN(DEBUG_CATEGORY_VIDEO, "HEVC header diagnostics disabled name=%s pts=%lld error=%s",
qPrintable(m->name), (long long)packet->pts, qPrintable(ffError(diagnostic)));
av_bsf_free(&m->headers);
}
}
LiveEncodedFrame 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; encoded.pts = packet->pts >= 0 ? static_cast<uint64_t>(packet->pts) : pts;
if (constrained) { if (constrained) {

Loading…
Cancel
Save