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

如何将H.264帧传入Gstreamermm API实现YUV420格式解码

Gstreamermm H.264帧解码为YUV420实现指南

实现逻辑

你需要搭建的GStreamer流水线结构如下:
appsrc -> h264parse -> avdec_h264 -> videoconvert -> video/x-raw,format=I420 -> appsink

  • appsrc 负责接收你从自定义协议拿到的H.264帧数据,推入流水线
  • h264parse 解析H.264码流格式,适配解码器输入要求
  • avdec_h264 完成H.264解码
  • videoconvert 确保输出格式对齐为标准YUV420(即I420格式)
  • appsink 负责取出解码后的原始YUV420帧数据

API文档说明

Gstreamermm是GStreamer的C封装版本,所有API逻辑和C版GStreamer完全对应,仅做了类和方法的封装,你可以直接对照C版GStreamer的功能逻辑匹配对应C接口:

  • 所有C版的GstElement对应Gstreamermm里的Gst::Element派生类
  • 流水线操作、属性设置、缓冲区操作的方法命名和参数逻辑和C版保持一致,仅替换为C++的成员函数调用形式

极简实现示例

#include <gstreamermm.h>
#include <iostream>

// 全局的appsrc和appsink指针,实际项目可以封装到类里
Glib::RefPtr<Gst::AppSrc> appsrc;
Glib::RefPtr<Gst::AppSink> appsink;

// 处理appsink收到的解码后YUV帧
Gst::FlowReturn on_new_sample() {
    auto sample = appsink->pull_sample();
    auto buffer = sample->get_buffer();
    Gst::MapInfo map_info;
    buffer->map(map_info, Gst::MAP_READ);
    
    // 这里map_info.get_data()就是YUV420原始数据,可自行保存或处理
    auto caps = sample->get_caps();
    auto structure = caps->get_structure(0);
    int width, height;
    structure.get_int("width", width);
    structure.get_int("height", height);
    
    // 分量长度:Y = width*height, U = width*height/4, V = width*height/4
    std::cout << "解码到YUV帧,分辨率:" << width << "x" << height << std::endl;
    
    buffer->unmap(map_info);
    return Gst::FLOW_OK;
}

int main(int argc, char* argv[]) {
    Gst::init(argc, argv);
    
    // 创建流水线
    auto pipeline = Gst::Pipeline::create("h264_decode_pipeline");
    
    // 创建所有元素
    appsrc = Gst::AppSrc::create("appsrc");
    auto h264parse = Gst::ElementFactory::create_element("h264parse");
    auto decoder = Gst::ElementFactory::create_element("avdec_h264");
    auto convert = Gst::ElementFactory::create_element("videoconvert");
    appsink = Gst::AppSink::create("appsink");
    
    // 把元素加入流水线
    pipeline->add(appsrc)->add(h264parse)->add(decoder)->add(convert)->add(appsink);
    
    // 链接元素
    appsrc->link(h264parse)->link(decoder)->link(convert);
    
    // 配置convert到appsink的caps强制输出YUV420
    auto caps = Gst::Caps::create_simple("video/x-raw", "format", Glib::ustring("I420"));
    convert->link(appsink, caps);
    
    // 配置appsrc属性
    appsrc->set_property("stream-type", 0); // GST_APP_STREAM_TYPE_STREAM
    appsrc->set_property("format", Gst::FORMAT_BYTES);
    auto h264_caps = Gst::Caps::create_simple("video/x-h264", "stream-format", Glib::ustring("byte-stream"));
    appsrc->set_property("caps", h264_caps);
    
    // 配置appsink回调
    appsink->set_property("emit-signals", true);
    appsink->signal_new_sample().connect(sigc::ptr_fun(&on_new_sample));
    
    // 启动流水线
    pipeline->set_state(Gst::STATE_PLAYING);
    
    // 这里模拟你收到H264帧的逻辑,实际替换为你自定义协议的收包逻辑
    while (true) {
        // 假设received_h264_data是你收到的H264帧数据指针,data_len是帧长度
        // uint8_t* received_h264_data;
        // gsize data_len;
        
        // 创建buffer并拷贝数据
        // auto buffer = Gst::Buffer::create(data_len);
        // Gst::MapInfo write_map;
        // buffer->map(write_map, Gst::MAP_WRITE);
        // memcpy(write_map.get_data(), received_h264_data, data_len);
        // buffer->unmap(write_map);
        
        // 推入appsrc
        // appsrc->push_buffer(buffer);
        
        // 此处可加退出逻辑
        break;
    }
    
    // 清理资源
    pipeline->set_state(Gst::STATE_NULL);
    return 0;
}

注意事项

  • 推入appsrc的H.264数据需要带标准NALU起始码(0x000001或0x00000001),如果你的自定义协议传输的是长度前缀的NALU,需要先手动替换为起始码再推入
  • 首次推入数据前必须先推SPS和PPS帧,否则解码器会初始化失败,无法正常解码
  • 编译时需要链接gstreamermm-1.0、gstreamer-app-1.0对应的库,pkg-config依赖为gstreamermm-1.0 gstreamer-app-1.0

内容的提问来源于stack exchange,提问作者Малюта Скуратов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 23:45:08