You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GStreamer:使用gst::Buffer传递H264包时NAL异常,gst::Sample正常

解决GStreamer中AppSink提取Buffer推送到AppSrc时H264 NAL单元损坏的问题

问题场景

用Rust实现了两个GStreamer管道:

  • 采集管道:以appsink结尾,输出AVC格式的H264流
  • 输出管道:以appsrc开头,将流推送到RTMP服务器

直接拉取Sample推送到输出管道时一切正常,但提取Buffer(尝试copy_deep和clone)推送时,出现H264 NAL单元损坏的错误,日志提示:

[NULL @ 0x11de05440] missing picture in access unit with size 22553
[extract_extradata @ 0x11de058f0] No start code is found.
rtmp://localhost/live/out: Invalid data found when processing input

插入h264parse后会报错未收到有效H264包,需要解决该问题以添加SEI消息。

采集管道代码:

let ingestPipeline = gst::parse_launch(
        "videotestsrc !  videoconvert !  videoscale ! videorate  \
! video/x-raw,width=1280,height=720,format=BGRx,framerate=30/1  \
! videoconvert  ! queue name=queuein ! timeoverlay time-mode=running-time \
! x264enc speed-preset=ultrafast key-int-max=25 bitrate=2500 ! video/x-h264 ,profile=baseline,stream-format=(string)avc,alignment=(string)au,framerate=30/1,width=1280,height=720  ! appsink name=sink  "
    )?.downcast::<gst::Pipeline>()
        .expect("Expected a gst::Pipeline");

输出管道代码:

let egressPipeline = gst::parse_launch(
        "appsrc is-live=true name=source caps=\"video/x-h264, profile=baseline,stream-format=avc,width=1280,height=720,framerate=30/1,alignment=au\"    ! flvmux name=mux streamable=true  ! queue ! rtmpsink location=rtmp://localhost/live/out")?.downcast::<gst::Pipeline>()
        .expect("Expected a gst::Pipeline");

问题原因

直接推送Buffer时丢失了Sample中的关键元数据:

  1. Caps与Extradata:H264的SPS/PPS等配置信息存储在Sample的Caps中(作为extradata),下游管道(如flvmux、h264parse)需要这些信息来正确解析NAL单元
  2. 时间戳与单元边界:Sample包含PTS/DTS、duration等时间信息,以及访问单元(AU)的边界标记,直接推Buffer会丢失这些信息,导致下游无法正确识别帧结构
  3. AVC格式要求:原管道输出的是AVC格式(带4字节长度前缀的NAL单元),如果处理Buffer时破坏了这种格式,会导致解析失败

解决方案

核心是保留Sample的完整元数据,处理Buffer后重新构建包含所有必要信息的Sample再推送:

1. 正确处理Buffer并重建Sample

从Sample中提取Buffer后,处理完成(如添加SEI),必须用原Sample的Caps、时间戳等元数据构建新的Sample,再推送到AppSrc。

修改后的回调代码:

appsink.set_callbacks(
    gst_app::AppSinkCallbacks::builder()
        .new_sample(move |appsink| {
            // 拉取原始Sample
            let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?;
            let orig_caps = sample.caps().ok_or(gst::FlowError::Error)?;
            let orig_buffer = sample.buffer().ok_or(gst::FlowError::Error)?;

            // 深拷贝Buffer用于处理(保留所有内存区域和元数据)
            let mut modified_buffer = orig_buffer.copy_deep().map_err(|_| gst::FlowError::Error)?;

            // --------------------------
            // 在这里添加SEI消息处理逻辑
            // 示例:获取H264的extradata,构造SEI NAL单元并插入Buffer
            // 注意:必须遵循AVC格式,用4字节长度前缀标记NAL单元
            // let video_caps = orig_caps.downcast_ref::<gst_video::VideoCaps>().unwrap();
            // let h264_info = video_caps.info().downcast_ref::<gst_video::VideoCodecFrameH264>().unwrap();
            // let sei_nal = create_sei_nal_unit(); // 自定义函数生成SEI NAL
            // insert_avc_nal_into_buffer(&mut modified_buffer, sei_nal); // 插入到Buffer中
            // --------------------------

            // 用原Sample的元数据构建新Sample
            let new_sample = gst::Sample::builder()
                .buffer(&modified_buffer)
                .caps(&orig_caps)
                .pts(sample.pts())
                .dts(sample.dts())
                .duration(sample.duration())
                .build()
                .map_err(|_| gst::FlowError::Error)?;

            // 推送新Sample到AppSrc
            appsrc.push_sample(&new_sample).map_err(|_| gst::FlowError::Error)?;

            Ok(gst::FlowSuccess::Ok)
        })
        .build(),
);

2. 确保SEI插入符合AVC格式

添加SEI时需注意:

  • 原管道输出的是AVC格式(stream-format=avc),NAL单元前是4字节大端长度前缀,而非0x00000001起始码
  • SEI NAL单元的类型是6,构造时要符合H.264规范,插入时要保证不破坏原有AU的结构
  • 如果需要在关键帧前插入SEI,要确保插入位置正确,不影响SPS/PPS的传递

3. 正确配置h264parse(可选)

如果要使用h264parse,需要确保:

  • AppSrc的Caps中包含正确的extradata(可从采集管道的Sample Caps中提取)
  • 推送的第一个Sample必须包含SPS/PPS,或者在AppSrc启动前设置带有extradata的Caps
  • 修改输出管道为:
appsrc is-live=true name=source caps="..." ! h264parse config-interval=1 ! flvmux ...

关键注意点

  • 永远不要单独推送Buffer,必须用Sample包裹,保留所有元数据
  • 处理H264 Buffer时,严格遵循当前流的格式(AVC/Byte-Stream)
  • 调试时可以用gst-inspect-1.0 h264parse查看参数,用gst-launch-1.0测试管道的正确性

内容的提问来源于stack exchange,提问作者lennel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:54:54