如何将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,提问作者Малюта Скуратов
相关产品推荐
相关产品推荐

