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 基本命令
一些基本的 GStreamer CLI。
gst-play-1.0:简化的媒体播放器,内部自动构建 pplgst-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 messageGST_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 discardedGST_EVENT_FLUSH_STOP: data is allowed againGST_EVENT_CAPS: Format information about the following buffersGST_EVENT_SEGMENT: timing information for the following buffersGST_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:文件地址,支持绝对/相对路径。
- e.g.
filesink:将收到的数据保存为文件。- e.g.
gst-launch-1.0 filesrc location=/tmp/test ! filesink location=/tmp/test2
- e.g.
gst1-plugins-base
appsrc:从外部导入数据,在 CLI 中使用很少,主要是在代码中使用。appsink:用于导出 GStreamer 数据,同样很少在 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:非常常用的插件,用于图像格式转换。它是 GStreamer base 插件中的纯软件转换器。在 Rockchip 平台上,通常有专门的硬件加速插件来调用 RGA(Raster Graphic Acceleration Unit)进行加速,可用于加速点/线绘制,执行图像缩放、旋转、bitBlt、alpha 混合等常见的 2D 图形操作。videotestsrc:生成不同格式和分辨率的视频流。xvimagesink:在 XVideo 环境下渲染图像,通常利用硬件进行 YUV→RGB 的颜色空间转换和缩放。
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-camera0min-buffers:驱动最低缓存大小。num-buffers:指定输出固定帧数的数据。
- e.g.
rtspsrc:从 RTSP 服务器获取视频流。- e.g.
gst-launch-1.0 rtspsrc location=rtsp://192.168.1.105:8554/ ! rtph264depay ! h264parse ! mppvideodec ! waylandsink location:指定码流地址
- e.g.
videoflip:视频翻转。- e.g.
gst-launch-1.0 videotestsrc ! videoflip video-direction=90r ! waylandsink
- e.g.
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 结束的属性名-属性值键值对列表,可以一次性设置多个属性。在这里,是为已经被创建为 v4l2src 的 src 元素设置 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_connect:将 appsink 元素(sink)的 new-sample 信号与回调函数 on_new_sample 相连接。当 appsink 接收到新的视频样本时,就会触发 new-sample 信号,进而调用 on_new_sample 回调函数来处理该样本。gst_bin_add_many:把多个 GStreamer 元素 src、jpegdec、videoconvert、capsfilter、sink 添加到 ppl 中。GST_BIN 是一个宏,用于将 GstElement 指针转换为 GstBin 指针。
参考文章
- Difference Between JPEG and MPEG
- Gstreamer中的视频处理与硬件加速-腾讯云开发者社区-腾讯云
- 【gstreamer之messages和events】_gstreamer 发送message-CSDN博客
- gstreamer信号、属性、消息、事件、问询、状态的详细梳理_gstreamer 信号-CSDN博客
- GStreamer 简明教程(五):Pad 相关概念介绍,Pad Capabilities/Templates_gstcaps信息打印-CSDN博客
- RockChip的RGA硬件图像处理加速器使用小例子 - 知乎
- Building an Application | GStreamer中文教程
- rockchip-linux/mpp: Media Process Platform (MPP) module
- URL和URI的区别-麦子的博客
- gstreamer学习笔记---v4l2src-CSDN博客
- Basic tutorial 2: GStreamer concepts
评论