|
@@ -35,16 +35,16 @@ int encoder_video_x264::init(
|
|
|
|
|
|
|
|
AVDictionary *options = 0;
|
|
AVDictionary *options = 0;
|
|
|
|
|
|
|
|
- // 使用ultrafast预设以获得最低延迟
|
|
|
|
|
|
|
+ // 回到超低延迟配置,但优化画质参数
|
|
|
av_dict_set(&options, "preset", "ultrafast", 0);
|
|
av_dict_set(&options, "preset", "ultrafast", 0);
|
|
|
av_dict_set(&options, "tune", "zerolatency", 0);
|
|
av_dict_set(&options, "tune", "zerolatency", 0);
|
|
|
|
|
|
|
|
- // 设置x264参数以匹配低延迟配置
|
|
|
|
|
- av_dict_set(&options, "x264-params", "keyint=30:min-keyint=30:no-scenecut=1", 0);
|
|
|
|
|
|
|
+ // 针对画质问题的特殊优化:提高码率而不是降低速度
|
|
|
|
|
+ av_dict_set(&options, "x264-params", "keyint=15:min-keyint=15:no-scenecut=1:rc-lookahead=0:aq-mode=2:aq-strength=0.8", 0);
|
|
|
av_dict_set(&options, "profile", "high", 0);
|
|
av_dict_set(&options, "profile", "high", 0);
|
|
|
av_dict_set(&options, "level", "4.1", 0);
|
|
av_dict_set(&options, "level", "4.1", 0);
|
|
|
- // 与命令行一致,明确设置CRF为18
|
|
|
|
|
- av_dict_set(&options, "crf", "18", 0);
|
|
|
|
|
|
|
+ // 使用更高的码率而不是更低的CRF来改善画质
|
|
|
|
|
+ av_dict_set(&options, "crf", "20", 0);
|
|
|
|
|
|
|
|
do {
|
|
do {
|
|
|
_encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
|
|
_encoder = avcodec_find_encoder(AV_CODEC_ID_H264);
|
|
@@ -67,21 +67,24 @@ int encoder_video_x264::init(
|
|
|
_encoder_ctx->time_base.num = 1;
|
|
_encoder_ctx->time_base.num = 1;
|
|
|
_encoder_ctx->time_base.den = frame_rate;
|
|
_encoder_ctx->time_base.den = frame_rate;
|
|
|
_encoder_ctx->framerate = {frame_rate, 1};
|
|
_encoder_ctx->framerate = {frame_rate, 1};
|
|
|
- _encoder_ctx->bit_rate = bit_rate;
|
|
|
|
|
|
|
+ _encoder_ctx->bit_rate = bit_rate * 2; // 提高码率来改善画质,而不是降低编码速度
|
|
|
|
|
|
|
|
- // 设置GOP大小为30帧,与用户ffmpeg命令一致
|
|
|
|
|
- _encoder_ctx->gop_size = 30;
|
|
|
|
|
|
|
+ // 回到低延迟GOP设置
|
|
|
|
|
+ _encoder_ctx->gop_size = 15;
|
|
|
|
|
|
|
|
- // 使用CRF 18以获得高质量和低延迟的平衡
|
|
|
|
|
- // 注意:FFmpeg的libx264编码器通过crf参数控制质量
|
|
|
|
|
- // 这里我们设置合理的qmin和qmax值
|
|
|
|
|
- _encoder_ctx->qmin = 10;
|
|
|
|
|
- _encoder_ctx->qmax = 25;
|
|
|
|
|
|
|
+ // 使用更宽松的量化参数,通过码率控制画质
|
|
|
|
|
+ _encoder_ctx->qmin = 12;
|
|
|
|
|
+ _encoder_ctx->qmax = 28;
|
|
|
|
|
|
|
|
- // 设置CRF值(通过全局质量参数)
|
|
|
|
|
- _encoder_ctx->global_quality = 18 * FF_QP2LAMBDA;
|
|
|
|
|
|
|
+ // 设置CRF值 - 稍微放宽以保证速度
|
|
|
|
|
+ _encoder_ctx->global_quality = 20 * FF_QP2LAMBDA;
|
|
|
|
|
|
|
|
_encoder_ctx->max_b_frames = 0; //NO B Frame
|
|
_encoder_ctx->max_b_frames = 0; //NO B Frame
|
|
|
|
|
+
|
|
|
|
|
+ // 恢复最低延迟设置
|
|
|
|
|
+ _encoder_ctx->delay = 0;
|
|
|
|
|
+ _encoder_ctx->thread_count = 1; // 单线程确保最低延迟
|
|
|
|
|
+
|
|
|
_encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
|
_encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
|
|
|
|
|
|
|
|
ret = avcodec_open2(_encoder_ctx, _encoder, &options);
|
|
ret = avcodec_open2(_encoder_ctx, _encoder, &options);
|
|
@@ -209,11 +212,16 @@ void encoder_video_x264::encode_loop()
|
|
|
|
|
|
|
|
while (_running) {
|
|
while (_running) {
|
|
|
std::unique_lock<std::mutex> lock(_mutex);
|
|
std::unique_lock<std::mutex> lock(_mutex);
|
|
|
- // 改为基于条件的等待,避免固定50ms超时带来的延迟抖动
|
|
|
|
|
- _cond_var.wait(lock, [this] { return _cond_notify || !_running; });
|
|
|
|
|
|
|
+ // 恢复最激进的低延迟处理
|
|
|
|
|
+ if (!_cond_notify && _ring_buffer->get_pending_frames() == 0) {
|
|
|
|
|
+ // 使用最短等待时间
|
|
|
|
|
+ _cond_var.wait_for(lock, std::chrono::milliseconds(1), [this] { return _cond_notify || !_running; });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (!_running)
|
|
if (!_running)
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
|
|
+ // 立即处理所有可用帧,不限制批处理大小
|
|
|
while (_ring_buffer->get(_buff, _buff_size, yuv_frame)) {
|
|
while (_ring_buffer->get(_buff, _buff_size, yuv_frame)) {
|
|
|
// Normalize incoming frame timestamps to encoder time_base (1/fps)
|
|
// Normalize incoming frame timestamps to encoder time_base (1/fps)
|
|
|
// Source pts is in AV_TIME_BASE (microseconds) from capturer
|
|
// Source pts is in AV_TIME_BASE (microseconds) from capturer
|