代码实现

#include <stdio.h>
#include <gst/gst.h>

int main(int argc, char* argv[])
{
    GstElement* pipeline;
    GstElement* v4l2;
    GstElement* v_cvert;
    GstElement* x264;
    GstElement* h264parse;
    GstElement* tsmux;
    GstElement* mysink;
    GstElement* udpsink;
    GstElement* srtsink;
    GstBus* bus;
    GstMessage* msg;
    
    g_print("this is for u!\n");
    gst_init(&argc, &argv);

    pipeline = gst_pipeline_new("test_pipeline");
    v4l2 = gst_element_factory_make ("v4l2src", "sourceq");
    v_cvert = gst_element_factory_make ("videoconvert", "v_cvertq");
    x264 = gst_element_factory_make ("x264enc", "x264encq");
    h264parse = gst_element_factory_make ("h264parse", "h264parseq");
    tsmux = gst_element_factory_make ("mpegtsmux", "mpegtsmuxq");
    mysink = gst_element_factory_make ("filesink", "filesinkq");
    // 创建 udpsink 元素
    udpsink = gst_element_factory_make("udpsink", "udpsink");
    srtsink = gst_element_factory_make("srtsink", "srtsink");

    // srt://127.0.0.1:8088?mode=listener


    GstElement *capsfilter1 = gst_element_factory_make("capsfilter", "capsfilter1");
    GstElement *capsfilter2 = gst_element_factory_make("capsfilter", "capsfilter2");

    if (!pipeline || !v4l2 || !capsfilter1 ||!v_cvert ||!capsfilter1 || !x264 || !h264parse || !tsmux || !mysink || !srtsink) {
        g_printerr ("Not all elements could be created.\n");
        return -1;
      }
    g_object_set(udpsink, "host", "127.0.0.1", "port", 6015, NULL);
    g_object_set(mysink, "location", "./test.ts", NULL);
    g_object_set(srtsink, "uri", "srt://127.0.0.1:8088?mode=listener", NULL);
    //这个函数返回值为void
    gst_bin_add_many(GST_BIN(pipeline), v4l2, capsfilter1, v_cvert, capsfilter2, x264, h264parse, tsmux, srtsink, NULL);
    //这个函数返回值为gboolean
    gst_element_link_many(v4l2, capsfilter1, v_cvert, capsfilter2, x264, h264parse, tsmux, srtsink, NULL);


    g_object_set(x264, "bitrate", 5000, "key-int-max", 15, "speed-preset", 2, "tune", 0x00000004, NULL);
    
    GstStateChangeReturn ret_state = gst_element_set_state(pipeline, GST_STATE_PLAYING);
    if(ret_state == GST_STATE_CHANGE_FAILURE)
    {
        g_printerr("Unable to set the pipeline to the playing state.\n");
        gst_object_unref(pipeline);
        return -1;
    }
    g_object_set(v4l2, "device", "/dev/video0", NULL);



  // 配置第一个 capsfilter (YUY2)
  GstCaps *src_caps = gst_caps_new_simple("video/x-raw",
    "width", G_TYPE_INT, 1280,
    "height", G_TYPE_INT, 720,
    "framerate", GST_TYPE_FRACTION, 30, 1,
    "format", G_TYPE_STRING, "YUY2",
    NULL); //这种方法,如何分辨率不支持,不会自动降低配置,但会报错:sourceq: streaming stopped
    //gst_element_link_filtered()这种方法,不会报错,也不会推流成功
    g_object_set(G_OBJECT(capsfilter1), "caps", src_caps, NULL);
    gst_caps_unref(src_caps);

    // 配置第二个 capsfilter (I420)
    GstCaps *convert_caps = gst_caps_new_simple("video/x-raw",
        "format", G_TYPE_STRING, "I420",
        NULL);//I420
    g_object_set(G_OBJECT(capsfilter2), "caps", convert_caps, NULL);
    gst_caps_unref(convert_caps);





    
    bus = gst_element_get_bus(pipeline);
    GstMessageType msg_types = (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
    msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, msg_types);
    if(msg != NULL)
    {
        GError* err;
        gchar* debug_info;
        switch(GST_MESSAGE_TYPE(msg))
        {
            case GST_MESSAGE_ERROR:
            gst_message_parse_error(msg, &err, &debug_info);
            g_printerr("Error received from element %s: %s\n",
            GST_OBJECT_NAME(msg->src), err->message);
            g_printerr("Debugging information %s\n",
            debug_info ? debug_info : "none");
            g_clear_error(&err);
            g_free(debug_info);
            break;
                
            case GST_MESSAGE_EOS:
            g_print("End-Of-Stream reached.\n");
            break;
            default:
            g_printerr("Unexpected message received.\n");
            break;
        }

        gst_message_unref(msg);
    }
    gst_object_unref(bus);
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);
    return 0;

    // tune=zerolatency bitrate=500 speed-preset=superfast key-int-max=15
}

/*
ffmpeg -video_size 640x480 -framerate 30 -pixel_format yuyv422 -i /dev/video0 -pix_fmt yuv420p  -c:v h264 -g 15 -b:v 500000 -tune zerolatency -preset superfast -f mpegts udp://127.0.0.1:6015

以上ffmpeg与下面的gst方法延时相同都是1s左右
指定对摄像头采集参数,指定对编码器的输入参数,videoconvert是实际去作参数各种参数转换的element
gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=640,height=480,framerate=30/1,format=YUY2 ! videoconvert ! video/x-raw,format=I420 ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast key-int-max=15 ! h264parse ! mpegtsmux ! filesink location=test.ts
让v4l2src和x264enc自动协商,有出错的风险
gst-launch-1.0 v4l2src device=/dev/video0 ! videoconvert ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast key-int-max=15 ! h264parse ! mpegtsmux ! filesink location=test.ts

gcc Capture-udp-2.c -o CCap `pkg-config --cflags --libs gstreamer-1.0`
ffplay -fflags nobuffer 'udp://127.0.0.1:6015'

等价于
gcc Capture-udp-2.c -o CCap `pkg-config --cflags --libs gstreamer-1.0`
// 它会去找gstreamer-1.0.pc,在这个文件可以看到它其实只添加了一个库也就是 /lib/x86_64-linux-gnu/libgstreamer-1.0

pkg-config --cflags gstreamer-1.0
-pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include

pkg-config --libs gstreamer-1.0
-lgstreamer-1.0 -lgobject-2.0 -lglib-2.0

ldd CCap 
	linux-vdso.so.1 (0x00007ffe12536000)
	libgstreamer-1.0.so.0 => /lib/x86_64-linux-gnu/libgstreamer-1.0.so.0 (0x000077706e928000)
	libgobject-2.0.so.0 => /lib/x86_64-linux-gnu/libgobject-2.0.so.0 (0x000077706e8c8000)
	libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x000077706e78e000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000077706e400000)
	libgmodule-2.0.so.0 => /lib/x86_64-linux-gnu/libgmodule-2.0.so.0 (0x000077706e787000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x000077706e69e000)
	libffi.so.8 => /lib/x86_64-linux-gnu/libffi.so.8 (0x000077706e691000)
	libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x000077706e38a000)
	/lib64/ld-linux-x86-64.so.2 (0x000077706ea92000)


或者:
gcc -v Capture-udp-2.c -o CCap `pkg-config --cflags --libs gstreamer-1.0`
*/


// gst-inspect-1.0 version 1.25.90
// srt
// gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=640,height=480,framerate=30/1,format=YUY2 ! videoconvert ! video/x-raw,format=I420 ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast key-int-max=15 ! h264parse ! mpegtsmux ! srtsink uri=srt://127.0.0.1:8088?mode=listener


// ffplay -fflags nobuffer srt://127.0.0.1:8088?mode=caller
// ffplay -f alsa sysdefault:CARD=U0x46d0x825


//audio
// gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=640,height=480,framerate=30/1,format=YUY2 ! videoconvert ! video/x-raw,format=I420 ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast key-int-max=15 ! h264parse ! mpegtsmux name=mux ! srtsink uri=srt://127.0.0.1:8088?mode=listener alsasrc device=sysdefault:CARD=U0x46d0x825 ! audio/x-raw,rate=44100,channels=2 ! audioconvert ! audioresample ! avenc_aac bitrate=128000 ! aacparse ! mux.

对应的makefile

# 使用动态获取 pkg-config 配置的版本(推荐)
# --------------------------------------------------
#CC = gcc
#CFLAGS = $(shell pkg-config --cflags gstreamer-1.0)
#LDLIBS = $(shell pkg-config --libs gstreamer-1.0)
#TARGET = CCap
#SRC = Capture-udp-2.c

# 静态配置版本(基于您提供的参数)
# --------------------------------------------------
 CC = g++
 CFLAGS = -pthread -I/usr/include/gstreamer-1.0 \
          -I/usr/include/glib-2.0 \
          -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
 LDLIBS = -lgstreamer-1.0 -lgobject-2.0 -lglib-2.0
 TARGET = CCap
 SRC = Capture-udp-2.cpp

all: $(TARGET)

$(TARGET): $(SRC)
	$(CC) $(CFLAGS) $< -o $@ $(LDLIBS)

clean:
	rm -f $(TARGET)

.PHONY: all clean

对应的CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(CCap)

# 设置C标准(如果需要)
set(CMAKE_C_STANDARD 11)

# 手动指定包含路径
include_directories(
    /usr/include/gstreamer-1.0
    /usr/include/glib-2.0
    /usr/lib/x86_64-linux-gnu/glib-2.0/include
)

# 添加-pthread编译选项
# add_compile_options(-pthread)

# 创建可执行文件
add_executable(CCap Capture-udp-2.cpp)

# 手动链接库
target_link_libraries(CCap
    pthread
    gstreamer-1.0
    gobject-2.0
    glib-2.0
)

补充与命令实现:

/*
ffmpeg -video_size 640x480 -framerate 30 -pixel_format yuyv422 -i /dev/video0 -pix_fmt yuv420p  -c:v h264 -g 15 -b:v 500000 -tune zerolatency -preset superfast -f mpegts udp://127.0.0.1:6015
以上ffmpeg与下面的gst方法延时相同都是1s左右

gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=640,height=480,framerate=30/1,format=YUY2 ! videoconvert ! video/x-raw,format=I420 ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast key-int-max=15 ! h264parse ! mpegtsmux ! filesink location=test.ts
video/x-raw,width=640,height=480,framerate=30/1,format=YUY2:指定摄像头的采集格式
videoconvert是实际去作参数各种参数转换的element
video/x-raw,format=I420:指定编码器的格式
bitrate=500:指定编码为500kbps
h264parse:解析编码好的264流,进行调整,使它符合标准的h264结构
mpegtsmux:复用器,流封装为ts流


//下面让v4l2src和x264enc自动协商,有出错的风险
gst-launch-1.0 v4l2src device=/dev/video0 ! videoconvert ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast key-int-max=15 ! h264parse ! mpegtsmux ! filesink location=test.ts

gcc Capture-udp-2.c -o CCap `pkg-config --cflags --libs gstreamer-1.0`
ffplay -fflags nobuffer 'udp://127.0.0.1:6015'

等价于
gcc Capture-udp-2.c -o CCap `pkg-config --cflags --libs gstreamer-1.0`
// 它会去找gstreamer-1.0.pc,在这个文件可以看到它其实只添加了一个库也就是 /lib/x86_64-linux-gnu/libgstreamer-1.0

pkg-config --cflags gstreamer-1.0
-pthread -I/usr/include/gstreamer-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include

pkg-config --libs gstreamer-1.0
-lgstreamer-1.0 -lgobject-2.0 -lglib-2.0

ldd CCap 
	linux-vdso.so.1 (0x00007ffe12536000)
	libgstreamer-1.0.so.0 => /lib/x86_64-linux-gnu/libgstreamer-1.0.so.0 (0x000077706e928000)
	libgobject-2.0.so.0 => /lib/x86_64-linux-gnu/libgobject-2.0.so.0 (0x000077706e8c8000)
	libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x000077706e78e000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000077706e400000)
	libgmodule-2.0.so.0 => /lib/x86_64-linux-gnu/libgmodule-2.0.so.0 (0x000077706e787000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x000077706e69e000)
	libffi.so.8 => /lib/x86_64-linux-gnu/libffi.so.8 (0x000077706e691000)
	libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x000077706e38a000)
	/lib64/ld-linux-x86-64.so.2 (0x000077706ea92000)


或者:
gcc -v Capture-udp-2.c -o CCap `pkg-config --cflags --libs gstreamer-1.0`
*/

再补充:

//推流本地usb摄像头,264编码,udp推流

gst-launch-1.0   v4l2src device=/dev/video0 !   videoconvert !   video/x-raw,format=I420 !   x264enc tune=zerolatency bitrate=2000 speed-preset=ultrafast !   h264parse !   rtph264pay !   udpsink host=127.0.0.1 port=6015

播放上个推流地址,注意上个使用的是rtp封装264,如果是补充1中的mpegtsmux,那么下面的播放将会报错,Received invalid RTP payload, dropping导致无法播放

gst-launch-1.0   udpsrc port=6015 address=127.0.0.1 !   application/x-rtp,media=video,encoding-name=H264,payload=96 !   rtph264depay !   avdec_h264 !   videoconvert !   autovideosink


srt:
// gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=640,height=480,framerate=30/1,format=YUY2 ! videoconvert ! video/x-raw,format=I420 ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast key-int-max=15 ! h264parse ! mpegtsmux ! srtsink uri=srt://127.0.0.1:8088?mode=listener

// ffplay -fflags nobuffer srt://127.0.0.1:8088?mode=caller
Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐