H.265摄像头流解析异常:解码后画面半绿如何解决?
问题描述
我正在解析H.265摄像头流,通过live555的afterGettingFrame()获取帧数据,通过起始码0x00 0x00 0x00 0x01拆分NALU,并用以下代码判断I帧:
auto t = (buf[0] >> 1) & 0x3f; return t == 19 || t == 20;
得到的NALU流日志如下(存在同时间戳帧):
log info Frame: time=1691746190593, key=true, duration=25230, size=50338 log info Frame: time=1691746190593, key=true, duration=3163, size=3464 log info Frame: time=1691746190713, key=false, duration=37765, size=480 log info Frame: time=1691746190713, key=false, duration=998, size=3274 log info Frame: time=1691746190713, key=false, duration=711, size=420 log info Frame: time=1691746190793, key=false, duration=115679, size=322 log info Frame: time=1691746190793, key=false, duration=1533, size=2437 log info Frame: time=1691746190793, key=false, duration=842, size=286 log info Frame: time=1691746190913, key=false, duration=77556, size=287 log info Frame: time=1691746190913, key=false, duration=1322, size=2693 log info Frame: time=1691746190913, key=false, duration=2059, size=216 log info Frame: time=1691746190993, key=false, duration=117100, size=258 log info Frame: time=1691746190993, key=false, duration=3076, size=2486 log info Frame: time=1691746190993, key=false, duration=396, size=211 log info Frame: time=1691746191113, key=false, duration=81118, size=23 log info Frame: time=1691746191113, key=false, duration=377, size=64 log info Frame: time=1691746191113, key=false, duration=3962, size=10 log info Frame: time=1691746191113, key=true, duration=5140, size=5069 log info Frame: time=1691746191113, key=true, duration=2797, size=49916 log info Frame: time=1691746191113, key=true, duration=1949, size=3493 log info Frame: time=1691746191193, key=false, duration=101536, size=429 log info Frame: time=1691746191193, key=false, duration=1158, size=3186 log info Frame: time=1691746191193, key=false, duration=1146, size=350 log info Frame: time=1691746191313, key=false, duration=77701, size=332
尝试过按时间戳拼接或单独解析,均未成功。使用原H.264解码代码:
AVPacket avpkt; av_init_packet(&avpkt); avpkt.pts = 0; avpkt.dts = 0; avpkt.data = data; avpkt.size = size; int gotFrame = false; while (avpkt.size > 0) { // We must use positive result to move through the data buffer auto len = avcodec_decode_video2(av_context_, av_frame_, &gotFrame, &avpkt); if (len < 0) { break; } avpkt.data += len; avpkt.size -= len; }
代码返回gotFrame=true,但生成的JPEG画面出现半绿情况,求正确的H.265流解析方式。
正确的H.265流解析及解码方案
1. 优先处理关键参数集(VPS/SPS/PPS)
H.265解码必须先获取并送入**VPS(视频参数集)、SPS(序列参数集)、PPS(图像参数集)**三类NALU,否则解码器无法完成初始化,直接导致画面异常(如半绿):
- 三类NALU的类型标识分别为:VPS=32,SPS=33,PPS=34
- 通过
(buf[0] >> 1) & 0x3f判断类型,在解码前先将这些参数集送入解码器。
2. 正确处理同时间戳的NALU
同时间戳的帧是同一编码帧的分片NALU,必须按顺序拼接成完整帧数据后再送入解码器,不能单独解析:
- 拼接时保留每个NALU的起始码
0x00 0x00 0x00 0x01,或直接拼接起始码后的payload部分,解码器两种方式均支持,保留起始码兼容性更好。
3. 替换为H.265专用解码器
原代码针对H.264设计,必须修改解码器初始化逻辑:
- 指定codec_id为
AV_CODEC_ID_HEVC - 示例初始化代码:
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_HEVC); AVCodecContext* av_context_ = avcodec_alloc_context3(codec); av_context_->thread_count = 4; // 根据CPU核心数调整 if (avcodec_open2(av_context_, codec, nullptr) < 0) { // 初始化失败处理逻辑 }
4. 使用新版解码API替代废弃接口
avcodec_decode_video2已被废弃,H.265解码建议使用avcodec_send_packet和avcodec_receive_frame,流程更稳定:
AVPacket avpkt; av_init_packet(&avpkt); // 将live555时间戳转换为FFmpeg时间基准单位 avpkt.pts = av_rescale_q(live555_timestamp, AV_TIME_BASE_Q, av_context_->time_base); avpkt.dts = avpkt.pts; // 无B帧场景下dts与pts一致 avpkt.data = data; avpkt.size = size; int ret = avcodec_send_packet(av_context_, &avpkt); if (ret == 0) { while (ret >= 0) { ret = avcodec_receive_frame(av_context_, av_frame_); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { // 解码错误处理逻辑 break; } // 处理解码后的帧(如转换为JPEG) convert_frame_to_jpeg(av_frame_); } } av_packet_unref(&avpkt);
5. 禁止硬设时间戳为0
必须使用live555获取的原始时间戳,转换为FFmpeg的时间基准(AV_TIME_BASE),否则解码器时序逻辑异常,会导致画面问题。
内容的提问来源于stack exchange,提问作者denn
相关产品推荐
相关产品推荐

