From 0fe20dfb7871b54d47ee12ad88446c8f9a33296b Mon Sep 17 00:00:00 2001 From: zhangjiarui Date: Fri, 29 May 2026 15:39:11 +0800 Subject: [PATCH] =?UTF-8?q?fix(encoder):=20=E5=8A=A8=E6=80=81=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E8=BE=93=E5=87=BA=E7=BC=93=E5=86=B2=E5=8C=BA=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=EF=BC=8C=E8=A7=A3=E5=86=B3=E7=BC=96=E7=A0=81=E5=8C=85?= =?UTF-8?q?=E8=B6=85=E9=99=90=E6=97=B6=E9=9D=99=E9=BB=98=E4=B8=A2=E5=B8=A7?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20=20=20=E5=BD=93=E7=BC=96=E7=A0=81=E5=8C=85?= =?UTF-8?q?=E5=A4=A7=E5=B0=8F=E8=B6=85=E8=BF=87=E8=BE=93=E5=87=BA=E7=BC=93?= =?UTF-8?q?=E5=86=B2=E5=8C=BA=E6=97=B6=EF=BC=8C=E6=9B=BF=E6=8D=A2=E5=8E=9F?= =?UTF-8?q?=E6=9C=89=E7=9A=84=E9=9D=99=E9=BB=98=E4=B8=A2=E5=BC=83=E8=A1=8C?= =?UTF-8?q?=E4=B8=BA=E4=B8=BA=E5=8A=A8=E6=80=81=E6=89=A9=E5=AE=B9=EF=BC=88?= =?UTF-8?q?1.5=E5=80=8D=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=E5=A2=9E=E9=95=BF?= =?UTF-8?q?=EF=BC=89=EF=BC=8C=E6=9C=80=E5=A4=A7=E5=88=86=E9=85=8D=E4=B8=8A?= =?UTF-8?q?=E9=99=90=E4=B8=BA=20max(width*height/2,=202MB)=EF=BC=8C?= =?UTF-8?q?=E9=98=B2=E6=AD=A2=E5=86=85=E5=AD=98=E6=97=A0=E9=99=90=E5=A2=9E?= =?UTF-8?q?=E9=95=BF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Log: 修复编码器输出缓冲区溢出时静默丢帧的问题 Bug: https://pms.uniontech.com/bug-view-345769.html --- libcam/libcam_encoder/encoder.c | 73 +++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/libcam/libcam_encoder/encoder.c b/libcam/libcam_encoder/encoder.c index db9fe8fe..834e4779 100644 --- a/libcam/libcam_encoder/encoder.c +++ b/libcam/libcam_encoder/encoder.c @@ -1581,6 +1581,61 @@ static int libav_get_encode(AVCodecContext *avctx, AVPacket *pkt, int *got_packe // return ret; // } +/* + * Ensure output buffer is large enough for the encoded packet. + * Dynamically resizes the buffer if needed (1.5x reserved space, capped at + * max(width*height/2, 2MB)). Drops the frame if it exceeds the reasonable + * upper limit or if realloc fails. + * + * Returns: 1 if data was successfully copied to outbuf, + * 0 if frame was dropped (caller must continue to next iteration). + */ +static int resize_outbuf_if_needed(encoder_video_context_t *enc_video_ctx, + encoder_context_t *encoder_ctx, + AVPacket *pkt) +{ + /* Guard against invalid negative pkt->size to prevent memcpy overflow, + * since negative int is implicitly converted to a huge size_t value. */ + if (pkt->size < 0) { + fprintf(stderr, "ENCODER: invalid packet size %d, dropping frame\n", pkt->size); + return 0; + } + + if (pkt->size <= enc_video_ctx->outbuf_size) { + memcpy(enc_video_ctx->outbuf, pkt->data, pkt->size); + return 1; + } + + /* Buffer limit: width * height / 2, with 2MB minimum protection */ + int max_reasonable_size = encoder_ctx->video_width * encoder_ctx->video_height / 2; + if (max_reasonable_size < 2 * 1024 * 1024) + max_reasonable_size = 2 * 1024 * 1024; + + if (pkt->size > max_reasonable_size) { + fprintf(stderr, "ENCODER: packet size %d exceeds reasonable limit (%d), dropping frame\n", + pkt->size, max_reasonable_size); + return 0; + } + + /* Reserve extra space (1.5x) to avoid frequent reallocations */ + int alloc_size = pkt->size + (pkt->size >> 1); + if (alloc_size > max_reasonable_size) + alloc_size = max_reasonable_size; + + fprintf(stderr, "ENCODER: resizing output buffer (%i -> %i, reserved %i)\n", + enc_video_ctx->outbuf_size, pkt->size, alloc_size); + uint8_t *new_buf = realloc(enc_video_ctx->outbuf, alloc_size); + if (new_buf) { + enc_video_ctx->outbuf = new_buf; + enc_video_ctx->outbuf_size = alloc_size; + memcpy(enc_video_ctx->outbuf, pkt->data, pkt->size); + return 1; + } + + fprintf(stderr, "ENCODER: failed to allocate %d bytes, dropping frame\n", alloc_size); + return 0; +} + /* * encode video frame * args: @@ -1702,10 +1757,11 @@ int encoder_encode_video(encoder_context_t *encoder_ctx, void *input_frame) enc_video_ctx->flags = pkt->flags; enc_video_ctx->duration = pkt->duration; - if (pkt->size <= enc_video_ctx->outbuf_size) - memcpy(enc_video_ctx->outbuf, pkt->data, pkt->size); - else - fprintf(stderr, "video packet size is bigger than output buffer(%i>%i)\n", pkt->size, enc_video_ctx->outbuf_size); + if (!resize_outbuf_if_needed(enc_video_ctx, encoder_ctx, pkt)) { + last_video_pts = enc_video_ctx->pts; + getLoadLibsInstance()->m_av_packet_unref(pkt); + continue; + } /* free any side data since we cannot return it */ if (pkt->side_data_elems > 0) { @@ -2682,10 +2738,11 @@ int encoder_encode_video_vaapi(encoder_context_t *encoder_ctx, void *input_frame enc_video_ctx->flags = pkt->flags; enc_video_ctx->duration = pkt->duration; - if (pkt->size <= enc_video_ctx->outbuf_size) - memcpy(enc_video_ctx->outbuf, pkt->data, pkt->size); - else - fprintf(stderr, "video packet size is bigger than output buffer(%i>%i)\n", pkt->size, enc_video_ctx->outbuf_size); + if (!resize_outbuf_if_needed(enc_video_ctx, encoder_ctx, pkt)) { + last_video_pts = enc_video_ctx->pts; + getLoadLibsInstance()->m_av_packet_unref(pkt); + continue; + } /* free any side data since we cannot return it */ if (pkt->side_data_elems > 0) {