FunnyWii
FunnyWii
Published on 2025-04-03 / 10 Visits
0
0

GStreamer学习

GStreamer在我看来更像是视频编解码领域的内容。

JPEG和MPEG

先区分一下这两个格式[1]

JPEG全称Joint Photographic Experts Group,文件拓展名一般为.jpg或者.jpeg,是一种静态图像压缩标准,压缩比能达到10:1。

MPEG全称Moving Picture Experts Group,分为mpeg-1、mpeg-2、mpeg-4三种格式,,是一种视音频编码标准,压缩比能达到20:1。

GStreamer

GStreamer主要是通过插件的方式去构建pipeline,本文用ppl简写指代。ppl相当于一个大的容器,里面每一个元素都是element,也叫做plugin(插件)。

NVIDIA 的 deepstream 便是基于 GStreamer开发的 SDK。

一个最基本的GStreamer ppl如下,音视频流先经过demuxer解封装为视频流和音频流。视频流经过解码器 video decoder(如 mppvideodec 或 mppjpegdec)解码,音频流通过audio decoder解码。最后使用显示插件如 xvimagesink 和 waylandsink 显示图像,其中xvimagesink 会调用 X11接口对接X11显示架构,waylandsink 调用 Wayland 接口对接 Wayland 显示架构,使用音频播放插件如 alsasink 播放音频。

gstreamer-base-ppl.png

GStreamer基本命令

一些基本的GStreamer CLI。

  • gst-play-1.0: 简化的媒体播放器,内部自动构建ppl

  • gst-launch-1.0: 底层工具,需显式构建完整ppl,灵活性更高

  • gst-inspect-1.0 : 打印指定element或plugin的信息

  • gst-discoverer-1.0: 可以对提供的URL进行分析,查看是否缺少plugin。比如gst-discoverer-1.0 rtsp://127.0.0.1:8554

顺便说一下URI(Uniform Resource Identifier)和URL(Uniform Resource Locator)。URI是统一资源标识符,用一个字符串用来标示抽象或物理资源;URL是统一资源定位符,是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。

URI 属于 URL 更高层次的抽象,一种字符串文本标准。URI 表示请求服务器的路径,定义这么一个资源。而 URL 同时说明要如何访问这个资源(rtsp://xxxxxxxxx)

GStreamer插件

GStreamer插件(元素)主要分为3类:

  • 源插件source: 只产生数据,不接受数据。

  • 过滤器插件filter:处理数据,然后向后一级传送

  • 接收插件 sink:只接受数据,不再产生数据。比如保存文件,显示画面。

在 GStreamer 中,Pad 是连接不同元素之间的接口,允许它们相互通信和传递数据的概念。每个 GStreamer 元素都包含一个或多个 Pad,其中的数据流通过 Pad 传递。Pad 可以是输入 Pad,用来接收数据,也可以是输出 Pad,用于发送数据。Pads 是元素间数据流动的接口,而Pad Capabilities 是这些接口所能处理的数据类型和属性的详细描述[5]

上下游 element 间通过Event(事件)同步状态,通过query(询问)来同步信息

一些内部机制

GStreamer的内部机制除了上面提及的还有:

  • Message:全称Bus Message,用于pipeline和Application之间的交互。默认情况下,每个pipeline都会包含一个Bus,因此在编写Application程序时不需要创建Bus。Application唯一需要做的是在Bus上设置Message处理函数。Message具体类型可以参照 GstMessage,随便列几个:

    • GST_MESSAGE_UNKNOWN – an undefined message

    • GST_MESSAGE_EOS – end - of - stream reached in a pipeline. The application will only receive this message in the PLAYING state and every time it sets a pipeline to PLAYING that is in the EOS state. The application can perform a flushing seek in the pipeline, which will undo the EOS state again.

    • GST_MESSAGE_ERROR – an error occurred. When the application receives an error message it should stop playback of the pipeline and not assume that more data will be played. It is possible to specify a redirection url to the error messages by setting a redirect - location field into the error message, application or high level bins might use the information as required.

    • GST_MESSAGE_WARNING – a warning occurred.

    • GST_MESSAGE_INFO – an info message occurred

  • Signal:Signal源于GObject体系,属于GObject通用机制,用于特定交互。在GStreamer中,element也属于GObject,所以通过Signal就可以将Application和element联系起来。

  • Event:Event与Buffer一起在pipeline的up and downstream中传播,在 elements 之间进行传递events,换句话说,Message用于app和和ppl的通信;Event用于ppl内部的通信。具体类型可以参照 GstEvent,也是随便列几个:

    • GST_EVENT_FLUSH_START : data is to be discarded

    • GST_EVENT_FLUSH_STOP : data is allowed again

    • GST_EVENT_CAPS : Format information about the following buffers

    • GST_EVENT_SEGMENT : timing information for the following buffers

    • GST_EVENT_TAG : Stream metadata.

    • GST_EVENT_BUFFERSIZE : Buffer size requirements. Currently not used yet.

  • Query:Query是向一个 element 或者 Pad 查询信息。若我们有一个display,可以在屏幕上显示 video(假设只支持RGB格式),而decoder的输出大多是NV12或者I420格式的。所以,我们要在decoder跟display之间接一个videoproc(video post processing视频后处理)的element来进行格式转换。在此,我们并不需要指定videoproc的输入输出格式,它会自动的通过query的方式询问上下游所支持的格式,从而判断出其要做一个NV12→RGB的格式转换。这种方式也就是Gstreamer里面的的自动协商[2]

  • Property:属性也是GObject的一种机制,就是对象的属性,在GStreamer中用于行为和参数控制。

插件介绍

Core Elements

  • fakesink :将收到的数据全部丢弃。

  • filesrc:从文件读取数据。

    • e.g. gst-launch-1.0 filesrc location=nv12_640x320.yuv blocksize=307200! video/x-raw,format=NV12,width=640,height=320! mpph264enc! filesink location=out.h264

    • blocksize:帧大小,读取YUV格式裸流编码时会用到。

    • location:文件地址,支持绝对/相对路径。

  • filesink:将收到的数据保存为文件。

    • e.g. gst-launch-1.0 filesrc location=/tmp/test ! filesink location=/tmp/test2

gst1-plugins-base

  • appsrc:从外部导入数据,在CLI用使用很少,主要是在代码中使用。

  • appsink:用于导出gst数据,同样很少在CLI中使用。通常配合appsrc 使用。

  • decodebin/decodebin3:自动动查找合适的解码插件。bin 可以将一系列elements组合形成一个逻辑上的element。举个例子,!a!b!c!d 这4个element放到一个bin里,然后调用这个bin就等同于调用!a!b!c!d

  • playbin/playbin3 :集成了decodebin ,会自动查找合适的sink插件。

  • uridecodebin/uridecodebin3:集成了decodebin ,根据提供的URI自动查找source插件。

  • videoconvert :非常常用的插件,用于图像格式转换。在我使用的RK3588开发板上,适配了RGA(Raster Graphic Acceleration Unit)加速,可用于加速点/线绘制,执行图像缩放、旋转、bitBlt、alpha混合等常见的2D图形操作。

  • videotestsrc:生成不同格式和分辨率的视频流。

  • xvimagesink :在XV环境下渲染图像,由GPU进行合成。

gst1-plugins-good

  • v4l2src :从v4l2设备获取视频数据。

    • e.g. gst-launch-1.0 v4l2src! video/x-raw,width=1920,height=1080,format=NV12! waylandsink

    • device:指定设备节点。Default: "/dev/video-camera0"

    • min-buffers:驱动最低缓存大小。

    • num-buffers:指定输出固定帧数的数据。

  • rtspsrc:从RTSP服务器获取视频流。

    • e.g. gst-launch-1.0 rtspsrc location=rtsp://192.168.1.105:8554/! rtph264depay! h264parse! mppvideodec! waylandsink

    • location:指定码流地址

  • videoflip:视频翻转。

    • e.g. gst-launch-1.0 videotestsrc ! videoflip video-direction=90r ! waylandsink

C++ 例程

创建一个GStreamer element

// 创建新的 GStreamer 管道
capture_pipeline = gst_pipeline_new("capture-pipeline");

// 创建管道中的各个元素
GstElement *src = gst_element_factory_make("v4l2src", "src");
GstElement *jpegdec = gst_element_factory_make("mppjpegdec", "dec");
GstElement *videoconvert = gst_element_factory_make("videoconvert", "videoconvert");
GstElement *capsfilter = gst_element_factory_make("capsfilter", "caps");
GstElement *sink = gst_element_factory_make("appsink", "sink");
if (!src || !jpegdec || !videoconvert || !capsfilter || !sink) {
  LOG_ERR("Not all elements could be created.\n");
  return;
}
  • gst_pipeline_new 是 GStreamer 库提供的一个函数,参数是设置ppl的名称。

  • gst_element_factory_make 的定义为:GstElement gst_element_factory_make(const gchar factoryname, const gchar *name);

    • 返回一个GstElement 类型的变量,如果创建成功返回创建元素的指针;如果创建失败返回NULL。

    • factoryname 代表要创建的 GStreamer element的工厂名称,每个element都有一个工厂。e.g."v4l2src" 指的是 Video4Linux2 source的元素工厂,能创建从 Video4Linux2 设备捕获视频数据的元素。

    • name 用于为新创建的元素指定一个名称,以用于Debug和Log。

 // 配置 v4l2src 元素,指定视频设备
g_object_set(src, "device", device, NULL);

// 配置 capsfilter 元素,设置视频的格式、宽度和高度
GstCaps *caps = gst_caps_new_simple("video/x-raw",
                                    "format", G_TYPE_STRING, "RGB",         // 使用RGB、BGR、NV12格式
                                    "width", G_TYPE_INT, user_data->FRAME_WIDTH,              
                                    "height", G_TYPE_INT, user_data->FRAME_HEIGHT,
                                    "framerate", GST_TYPE_FRACTION, 30, 1,  // 设置帧率为 30fps
                                    NULL);
g_object_set(capsfilter, "caps", caps, NULL);
gst_caps_unref(caps);

// 配置 appsink 元素
g_object_set(sink,
    "emit-signals", TRUE,
    "sync", FALSE,
    "max-buffers", 20,
    "drop", TRUE,
    NULL);
  • g_object_set :先看GObject的继承关系,可以看出,GstElement 是 GObject 的派生类,因此可以使用 g_object_set 来设置 GStreamer element的属性。g_object_set 可以接受一个以NULL结束的属性名-属性值键值对列表,可以一次性设置多个属性。在这里,是为已经被创建为v4l2srcsrc 元素设置"device"属性。

GObject
    ╰──GInitiallyUnowned
        ╰──GstObject
            ╰──GstElement
                ╰──GstBin
                    ╰──GstPipeline
  • gst_caps_new_simple :用于创建一个简单的caps 。也接受可变参数列表,后面的参数成对出现。"video/x-raw" 代表未经压缩的视频。G_TYPE_STRING 代表字符串类型,G_TYPE_INT 代表整型,GST_TYPE_FRACTION 代表分数类型,后面的两个参数分别是分子和分母。

// 连接 appsink 的 "new-sample" 信号到回调函数
g_signal_connect(sink, "new-sample", G_CALLBACK(on_new_sample), (gpointer)user_data);

// 将所有元素添加到管道中
gst_bin_add_many(GST_BIN(capture_pipeline), src, jpegdec, videoconvert, capsfilter, sink, NULL);

// 链接管道中的各个元素
if (!gst_element_link_many(src, jpegdec, videoconvert, capsfilter, sink, NULL)) {
  LOG_ERR("Failed to link elements in the pipeline\n");
  return;
}

// 启动管道
if (gst_element_set_state(GST_ELEMENT(capture_pipeline), GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
  LOG_ERR("Failed to set pipeline to playing state\n");
  return;
}
  • g_signal_connectappsink 元素(sink)的 "new-sample" 信号与回调函数 on_new_sample 相连接。当 appsink 接收到新的视频样本时,就会触发 "new-sample" 信号,进而调用 on_new_sample 回调函数来处理该样本。

  • gst_bin_add_many把多个 GStreamer 元素srcjpegdecvideoconvertcapsfiltersink添加到ppl中。GST_BIN 是一个宏,用于将 GstElement 指针转换为 GstBin 指针。

参考文章

  1. Difference Between JPEG and MPEG

  2. Gstreamer中的视频处理与硬件加速-腾讯云开发者社区-腾讯云

  3. 【gstreamer之messages和events】_gstreamer 发送message-CSDN博客

  4. gstreamer信号、属性、消息、事件、问询、状态的详细梳理_gstreamer 信号-CSDN博客

  5. GStreamer 简明教程(五):Pad 相关概念介绍,Pad Capabilities/Templates_gstcaps信息打印-CSDN博客

  6. RockChip的RGA硬件图像处理加速器使用小例子 - 知乎

  7. Building an Application | GStreamer中文教程

  8. rockchip-linux/mpp: Media Process Platform (MPP) module

  9. URL和URI的区别-麦子的博客

  10. gstreamer学习笔记---v4l2src-CSDN博客

  11. Basic tutorial 2: GStreamer concepts


Comment