From 5204f00812390240230f9d4e8da0e1bc181657d0 Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Tue, 20 Jan 2026 07:28:49 +0200 Subject: [PATCH] h264 boost mode --- src/ustreamer/m2m.c | 26 +++++++++++++++++--------- src/ustreamer/m2m.h | 3 ++- src/ustreamer/options.c | 3 +++ src/ustreamer/stream.c | 8 +++++++- src/ustreamer/stream.h | 1 + 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/ustreamer/m2m.c b/src/ustreamer/m2m.c index f5344e6..f0b1b7d 100644 --- a/src/ustreamer/m2m.c +++ b/src/ustreamer/m2m.c @@ -43,7 +43,7 @@ static us_m2m_encoder_s *_m2m_encoder_init( const char *name, const char *path, uint output_format, - uint bitrate, uint gop, uint quality, bool allow_dma); + uint bitrate, uint gop, uint quality, bool allow_dma, bool boost); static void _m2m_encoder_ensure(us_m2m_encoder_s *enc, const us_frame_s *frame); @@ -63,9 +63,9 @@ static int _m2m_encoder_compress_raw(us_m2m_encoder_s *enc, const us_frame_s *sr #define _LOG_DEBUG(x_msg, ...) US_LOG_DEBUG("%s: " x_msg, enc->name, ##__VA_ARGS__) -us_m2m_encoder_s *us_m2m_h264_encoder_init(const char *name, const char *path, uint bitrate, uint gop) { +us_m2m_encoder_s *us_m2m_h264_encoder_init(const char *name, const char *path, uint bitrate, uint gop, bool boost) { bitrate *= 1000; // From Kbps - return _m2m_encoder_init(name, path, V4L2_PIX_FMT_H264, bitrate, gop, 0, true); + return _m2m_encoder_init(name, path, V4L2_PIX_FMT_H264, bitrate, gop, 0, true, boost); } us_m2m_encoder_s *us_m2m_mjpeg_encoder_init(const char *name, const char *path, uint quality) { @@ -76,12 +76,12 @@ us_m2m_encoder_s *us_m2m_mjpeg_encoder_init(const char *name, const char *path, bitrate = step * round(bitrate / step); bitrate *= 1000; // From Kbps assert(bitrate > 0); - return _m2m_encoder_init(name, path, V4L2_PIX_FMT_MJPEG, bitrate, 0, 0, true); + return _m2m_encoder_init(name, path, V4L2_PIX_FMT_MJPEG, bitrate, 0, 0, true, false); } us_m2m_encoder_s *us_m2m_jpeg_encoder_init(const char *name, const char *path, uint quality) { // FIXME: DMA не работает - return _m2m_encoder_init(name, path, V4L2_PIX_FMT_JPEG, 0, 0, quality, false); + return _m2m_encoder_init(name, path, V4L2_PIX_FMT_JPEG, 0, 0, quality, false, false); } void us_m2m_encoder_destroy(us_m2m_encoder_s *enc) { @@ -139,7 +139,7 @@ int us_m2m_encoder_compress(us_m2m_encoder_s *enc, const us_frame_s *src, us_fra static us_m2m_encoder_s *_m2m_encoder_init( const char *name, const char *path, uint output_format, - uint bitrate, uint gop, uint quality, bool allow_dma) { + uint bitrate, uint gop, uint quality, bool allow_dma, bool boost) { US_LOG_INFO("%s: Initializing encoder ...", name); @@ -161,6 +161,7 @@ static us_m2m_encoder_s *_m2m_encoder_init( enc->gop = gop; enc->quality = quality; enc->allow_dma = allow_dma; + enc->boost = boost; enc->run = run; return enc; } @@ -222,7 +223,11 @@ static void _m2m_encoder_ensure(us_m2m_encoder_s *enc, const us_frame_s *frame) SET_OPTION(V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, enc->gop); SET_OPTION(V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE); if (run->p_width * run->p_height <= 1920 * 1080) { // https://forums.raspberrypi.com/viewtopic.php?t=291447#p1762296 - SET_OPTION(V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + if (enc->boost) { + SET_OPTION(V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_4_2); + } else { + SET_OPTION(V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_4_0); + } } else { SET_OPTION(V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_5_1); } @@ -276,10 +281,13 @@ static void _m2m_encoder_ensure(us_m2m_encoder_s *enc, const us_frame_s *frame) } } - if (run->p_width * run->p_height <= 1280 * 720) { + if ( + (run->p_width * run->p_height <= 1280 * 720) + || ((enc->output_format == V4L2_PIX_FMT_H264) && enc->boost) + ) { // H264 требует каких-то лимитов. Больше 30 не поддерживается, а при 0 // через какое-то время начинает производить некорректные фреймы. - // Если же привысить fps, то резко увеличивается время кодирования. + // Если же превысить fps, то резко увеличивается время кодирования. run->fps_limit = 60; } else { run->fps_limit = 30; diff --git a/src/ustreamer/m2m.h b/src/ustreamer/m2m.h index e3eed90..d97ee64 100644 --- a/src/ustreamer/m2m.h +++ b/src/ustreamer/m2m.h @@ -58,12 +58,13 @@ typedef struct { uint gop; uint quality; bool allow_dma; + bool boost; us_m2m_encoder_runtime_s *run; } us_m2m_encoder_s; -us_m2m_encoder_s *us_m2m_h264_encoder_init(const char *name, const char *path, uint bitrate, uint gop); +us_m2m_encoder_s *us_m2m_h264_encoder_init(const char *name, const char *path, uint bitrate, uint gop, bool boost); us_m2m_encoder_s *us_m2m_mjpeg_encoder_init(const char *name, const char *path, uint quality); us_m2m_encoder_s *us_m2m_jpeg_encoder_init(const char *name, const char *path, uint quality); void us_m2m_encoder_destroy(us_m2m_encoder_s *enc); diff --git a/src/ustreamer/options.c b/src/ustreamer/options.c index d8f4134..b18bdba 100644 --- a/src/ustreamer/options.c +++ b/src/ustreamer/options.c @@ -100,6 +100,7 @@ enum _US_OPT_VALUES { _O_H264_BITRATE, _O_H264_GOP, _O_H264_M2M_DEVICE, + _O_H264_BOOST, # undef ADD_SINK # ifdef WITH_V4P @@ -206,6 +207,7 @@ static const struct option _LONG_OPTS[] = { {"h264-bitrate", required_argument, NULL, _O_H264_BITRATE}, {"h264-gop", required_argument, NULL, _O_H264_GOP}, {"h264-m2m-device", required_argument, NULL, _O_H264_M2M_DEVICE}, + {"h264-boost", no_argument, NULL, _O_H264_BOOST}, // Compatibility {"sink", required_argument, NULL, _O_JPEG_SINK}, {"sink-mode", required_argument, NULL, _O_JPEG_SINK_MODE}, @@ -469,6 +471,7 @@ int options_parse(us_options_s *options, us_capture_s *cap, us_encoder_s *enc, u case _O_H264_BITRATE: OPT_NUMBER("--h264-bitrate", stream->h264_bitrate, 25, 20000, 0); case _O_H264_GOP: OPT_NUMBER("--h264-gop", stream->h264_gop, 0, 60, 0); case _O_H264_M2M_DEVICE: OPT_SET(stream->h264_m2m_path, optarg); + case _O_H264_BOOST: OPT_SET(stream->h264_boost, true); # ifdef WITH_V4P case _O_V4P: diff --git a/src/ustreamer/stream.c b/src/ustreamer/stream.c index a220383..c8c9411 100644 --- a/src/ustreamer/stream.c +++ b/src/ustreamer/stream.c @@ -156,7 +156,13 @@ void us_stream_loop(us_stream_s *stream) { atomic_store(&run->http->last_request_ts, us_get_now_monotonic()); if (stream->h264_sink != NULL) { - run->h264_enc = us_m2m_h264_encoder_init("H264", stream->h264_m2m_path, stream->h264_bitrate, stream->h264_gop); + run->h264_enc = us_m2m_h264_encoder_init( + "H264", + stream->h264_m2m_path, + stream->h264_bitrate, + stream->h264_gop, + stream->h264_boost); + run->h264_tmp_src = us_frame_init(); run->h264_dest = us_frame_init(); } diff --git a/src/ustreamer/stream.h b/src/ustreamer/stream.h index 5c5279d..f8ac511 100644 --- a/src/ustreamer/stream.h +++ b/src/ustreamer/stream.h @@ -94,6 +94,7 @@ typedef struct { uint h264_bitrate; uint h264_gop; char *h264_m2m_path; + bool h264_boost; # ifdef WITH_V4P us_drm_s *drm;