使用swscale将1080p视频下采样至480p并编码为x265时画面异常
解决FFmpeg缩放后x265编码画面异常问题
问题复盘
- 处理流程:先将1920×1080输入帧通过SWS_BICUBIC算法缩放到854×480,再送入x265编码器
- 异常表现:
- 编码器设为1080p时,输出仍为1080p且画面故障
- 编码器改为854×480时,画面仅显示原帧顶部1/4区域
核心原因分析
新手常踩的三个坑:
- 缩放帧缓冲区未正确初始化:
sws_scale_frame需要目标帧已按目标分辨率、像素格式分配好独立缓冲区,直接复用输入帧缓冲区会导致数据写入越界或不完整 - 编码器参数与缩放帧不匹配:编码器上下文的
width/height/pix_fmt必须和缩放后的帧完全一致,否则编码器会按自身参数解析帧数据,导致画面错位 - 时间戳未做时间基转换:输入帧的时间基来自解码器,必须转换为编码器的时间基,否则可能引发编码逻辑异常
修复步骤
1. 正确初始化缩放帧缓冲区
在缩放前,确保scaled_frame已按目标参数分配缓冲区:
if (!scaled_frame->buf[0]) { scaled_frame->width = 854; scaled_frame->height = 480; scaled_frame->format = encoder->codec_ctx->pix_fmt; // 必须和编码器格式一致 if (av_frame_get_buffer(scaled_frame, 0) < 0) { fprintf(stderr, "Failed to allocate scaled frame buffer\n"); return -1; } }
2. 同步编码器与缩放帧参数
初始化编码器前,强制设置与缩放目标一致的参数:
// 编码器上下文配置 encoder->codec_ctx->width = 854; encoder->codec_ctx->height = 480; encoder->codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; // x265推荐格式,避免用RGB encoder->codec_ctx->time_base = av_make_q(1, 60); // 匹配测试视频60fps帧率
3. 正确创建缩放上下文
确保SWS上下文的源/目标参数完全对应:
encoder->sws_ctx = sws_getContext( 1920, 1080, decoder->codec_ctx->pix_fmt, // 源分辨率、格式 854, 480, encoder->codec_ctx->pix_fmt, // 目标分辨率、格式 SWS_BICUBIC, NULL, NULL, NULL ); if (!encoder->sws_ctx) { fprintf(stderr, "Failed to create SWS context\n"); return -1; }
4. 修正时间戳转换
将输入帧的时间戳转换为编码器的时间基,避免编码异常:
scaled_frame->pts = av_rescale_q(input_frame->pts, decoder->codec_ctx->time_base, encoder->codec_ctx->time_base); scaled_frame->pkt_dts = av_rescale_q(input_frame->pkt_dts, decoder->codec_ctx->time_base, encoder->codec_ctx->time_base);
调整后的核心代码
// 确保缩放帧缓冲区已正确分配 if (!scaled_frame->buf[0]) { scaled_frame->width = 854; scaled_frame->height = 480; scaled_frame->format = encoder->codec_ctx->pix_fmt; if (av_frame_get_buffer(scaled_frame, 0) < 0) { fprintf(stderr, "Failed to allocate scaled frame buffer\n"); return -1; } } // 转换时间戳并复制帧属性 scaled_frame->pts = av_rescale_q(input_frame->pts, decoder->codec_ctx->time_base, encoder->codec_ctx->time_base); scaled_frame->pkt_dts = av_rescale_q(input_frame->pkt_dts, decoder->codec_ctx->time_base, encoder->codec_ctx->time_base); scaled_frame->pict_type = input_frame->pict_type; // 执行缩放 sws_scale_frame(encoder->sws_ctx, scaled_frame, input_frame); // 编码 if (encode_video(decoder, encoder, scaled_frame)) return -1;
额外注意事项
- 不要直接复用输入帧的缓冲区,必须为缩放帧分配独立内存
- x265仅支持特定像素格式(如YUV420P),避免使用RGB格式作为输入
- 测试时确保编码器初始化完成后再开始缩放编码流程
内容的提问来源于stack exchange,提问作者user16570427
相关产品推荐
相关产品推荐

