GStreamer:中间件定位与架构深度解析
·
一、GStreamer的准确定位
1.1 中间件定义与GStreamer的位置
/** * @brief 中间件定义与GStreamer定位分析 * * 核心:GStreamer是**多媒体框架**,属于**应用层中间件** * * 中间件分类: * ┌─────────────────────────────────────────────────────────────────────────────────┐ * │ 中间件分层定位 │ * ├─────────────────────────────────────────────────────────────────────────────────┤ * │ │ * │ ┌─────────────────────────────────────────────────────────────────────────┐ │ * │ │ 业务应用层 (Application) │ │ * │ │ 视频会议App │ 安防监控平台 │ 直播平台 │ 视频编辑器 │ │ * │ └─────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────┐ │ * │ │ 应用层中间件 (Application Middleware) │ │ * │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ GStreamer │ FFmpeg │ DirectShow │ MediaFoundation │ │ │ * │ │ │ (多媒体框架) (编解码库) (Windows) (Windows) │ │ │ * │ │ └─────────────────────────────────────────────────────────────────┘ │ │ * │ │ 职责: Pipeline构建、插件管理、媒体同步、格式转换 │ │ * │ └─────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────┐ │ * │ │ 通信中间件 (Communication Middleware) │ │ * │ │ DDS │ ZeroMQ │ RabbitMQ │ Kafka │ │ * │ └─────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────┐ │ * │ │ 系统中间件 (System Middleware) │ │ * │ │ Android HAL │ V4L2 │ ALSA │ OpenMAX │ VAAPI │ │ * │ └─────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────┐ │ * │ │ 操作系统内核 (Kernel) │ │ * │ │ Linux Kernel │ Drivers │ DMA │ V4L2 Core │ ALSA Core │ │ * │ └─────────────────────────────────────────────────────────────────────────┘ │ * └─────────────────────────────────────────────────────────────────────────────────┘ * @endverbatim */ /** * @brief GStreamer作为中间件的核心特征 * * 1. 抽象硬件差异: 统一API屏蔽V4L2/ALSA/VAAPI等底层差异 * 2. 提供标准接口: Element/Pad/Bin/Pipeline等编程模型 * 3. 插件化架构: 动态加载,功能可扩展 * 4. 跨平台: Linux/Windows/macOS/iOS/Android * 5. 语言绑定: C/C++/Python/JavaScript/Go等 */
二、GStreamer架构深度剖析
2.1 GStreamer核心架构图
/** * @brief GStreamer完整架构 -深度 * * @verbatim * ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐ * │ GStreamer 架构全景图 │ * ├─────────────────────────────────────────────────────────────────────────────────────────────────┤ * │ │ * │ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ │ * │ │ Application Layer │ │ * │ │ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ gst-launch-1.0 │ 自定义C程序 │ Python (gi) │ JavaScript (WebRTC) │ │ │ * │ │ └─────────────────────────────────────────────────────────────────────────────────┘ │ │ * │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ │ * │ │ GStreamer Core Library │ │ * │ │ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ GstObject (基类) │ │ │ * │ │ │ ├── GstElement (元素) ── 基本处理单元 │ │ │ * │ │ │ │ ├── GstBin (箱子) ── 容器,包含多个元素 │ │ │ * │ │ │ │ └── GstPipeline (管道) ── 顶层容器,管理时钟和总线 │ │ │ * │ │ │ ├── GstPad (垫) ── 元素的输入输出端口 │ │ │ * │ │ │ └── GstBuffer (缓冲区) ── 数据容器 │ │ │ * │ │ └─────────────────────────────────────────────────────────────────────────────────┘ │ │ * │ │ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ GstBus (总线) ── 消息传递机制 │ │ │ * │ │ │ GstClock (时钟) ── 全局时间同步 │ │ │ * │ │ │ GstRegistry (注册表) ── 插件管理 │ │ │ * │ │ │ GstContext (上下文) ── 共享资源管理 (如GPU上下文) │ │ │ * │ │ └─────────────────────────────────────────────────────────────────────────────────┘ │ │ * │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ │ * │ │ Plugin System (插件系统) │ │ * │ │ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ gst-plugins-base (核心插件) │ │ │ * │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ * │ │ │ │ audiosrc │ │ videotestsrc │ │ audiosink │ │ │ │ * │ │ │ │ videosrc │ │ appsrc │ │ videosink │ │ │ │ * │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ * │ │ └─────────────────────────────────────────────────────────────────────────────────┘ │ │ * │ │ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ gst-plugins-good (高质量插件) │ │ │ * │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ * │ │ │ │ v4l2src │ │ alsasrc │ │ videoconvert │ │ │ │ * │ │ │ │ v4l2sink │ │ alsasink │ │ videoscale │ │ │ │ * │ │ │ │ rtpmanager │ │ rtspclientsink │ │ matroskamux │ │ │ │ * │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ * │ │ └─────────────────────────────────────────────────────────────────────────────────┘ │ │ * │ │ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ gst-plugins-bad (高质量/专利限制) │ │ │ * │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ * │ │ │ │ h264parse │ │ mpegtsmux │ │ webrtcdsp │ │ │ │ * │ │ │ │ h265parse │ │ dashsink │ │ voaacenc │ │ │ │ * │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ * │ │ └─────────────────────────────────────────────────────────────────────────────────┘ │ │ * │ │ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ gst-plugins-ugly (许可证问题) │ │ │ * │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ * │ │ │ │ x264enc │ │ lame │ │ mpeg2dec │ │ │ │ * │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ * │ │ └─────────────────────────────────────────────────────────────────────────────────┘ │ │ * │ │ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ gst-omx (硬件加速) │ │ │ * │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ * │ │ │ │ omxh264enc │ │ omxh264dec │ │ omxh265enc │ │ │ │ * │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ * │ │ └─────────────────────────────────────────────────────────────────────────────────┘ │ │ * │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ │ * │ │ Hardware Abstraction Layer │ │ * │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ * │ │ │ V4L2 │ │ ALSA │ │ VAAPI │ │ OpenMAX │ │ │ * │ │ │ (Video4Linux) │ │ (Advanced │ │ (Video │ │ (Hardware │ │ │ * │ │ │ │ │ Linux Sound) │ │ Acceleration) │ │ Acceleration) │ │ │ * │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ * │ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ * └─────────────────────────────────────────────────────────────────────────────────────────────────┘ * @endverbatim */
2.2 GStreamer核心数据结构
/**
* @file gst/gst.h
* @brief GStreamer核心数据结构
*/
/**
* @struct GstElement
* @brief 元素 - Pipeline中的基本处理单元
*
* 元素类型:
* - Source: 数据源 (v4l2src, alsasrc, filesrc)
* - Filter: 数据处理 (videoconvert, videoscale, x264enc)
* - Sink: 数据汇 (autovideosink, filesink, rtspclientsink)
*/
struct _GstElement {
GstObject parent; // 父对象
/* 工厂信息 */
GstElementFactory *factory; // 元素工厂
gchar *name; // 元素名称
/* Pad管理 */
GList *sinkpads; // 输入Pad列表
GList *srcpads; // 输出Pad列表
/* 状态管理 */
GstState current_state; // 当前状态
GstState pending_state; // 待处理状态
GstState target_state; // 目标状态
/* 总线 */
GstBus *bus; // 消息总线
/* 线程管理 */
GstTask *task; // 异步任务
/* 时钟 */
GstClock *clock; // 元素时钟
/* 锁 */
GMutex *state_lock;
GCond *state_cond;
};
/**
* @struct GstPad
* @brief 垫 - 元素的连接点
*
* Pad类型:
* - Sink Pad: 接收数据 (元素输入端)
* - Source Pad: 发送数据 (元素输出端)
*/
struct _GstPad {
GstObject parent;
/* Pad信息 */
gchar *name; // Pad名称
GstPadDirection direction; // 方向 (SRC/SINK)
GstPadTemplate *padtemplate; // Pad模板
/* 所属元素 */
GstElement *parent; // 所属元素
/* 连接信息 */
GstPad *peer; // 连接的对面Pad
/* 数据流 */
GstCaps *caps; // 支持的格式
GstPadMode mode; // 激活模式 (PUSH/POLL)
/* 回调函数 */
GstPadEventFunction eventfunc; // 事件处理
GstPadQueryFunction queryfunc; // 查询处理
GstPadLinkFunction linkfunc; // 链接处理
/* 数据流处理 */
GstPadChainFunction chainfunc; // PUSH模式回调
GstPadGetRangeFunction getrangefunc; // POLL模式回调
};
/**
* @struct GstBuffer
* @brief 缓冲区 - 数据容器
*
* GStreamer的缓冲区管理:
* - 零拷贝: 通过引用计数共享数据
* - 内存池: 预分配减少分配开销
* - 元数据: 时间戳、标志位等
*/
struct _GstBuffer {
GstMiniObject mini_object; // 引用计数基类
/* 时间戳 */
GstClockTime pts; // 显示时间戳
GstClockTime dts; // 解码时间戳
GstClockTime duration; // 持续时间
/* 缓冲区标志 */
GstBufferFlags flags; // 关键帧、不连续等标志
/* 内存管理 */
GstMemory *memory; // 内存块链表
guint n_memory; // 内存块数量
/* 元数据 */
GList *metadata; // 元数据列表 (如ROI信息)
/* 缓冲区池 */
GstBufferPool *pool; // 所属缓冲区池
gsize size; // 数据大小
/* 偏移量 */
gsize offset; // 数据偏移
gsize offset_end; // 数据结束偏移
};
三、GStreamer插件系统与中间件集成
3.1 自定义GStreamer插件 - 集成V4L2多路摄像头
/**
* @file gst-rkcamsrc.c
* @brief 自定义GStreamer Source元素 - 集成16路摄像头
*
* 理解如何将底层驱动封装为GStreamer插件
*/
#include <gst/gst.h>
#include <gst/video/video.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
GST_DEBUG_CATEGORY_STATIC(gst_rkcamsrc_debug);
#define GST_CAT_DEFAULT gst_rkcamsrc_debug
/**
* @struct GstRkCamSrc
* @brief 自定义Source元素 - 封装RK3588多路摄像头
*/
typedef struct _GstRkCamSrc {
GstElement element; // 父元素
/* 属性 */
gchar *device; // 设备路径 (/dev/video0-15)
guint stream_id; // 流ID (0-15)
guint width; // 宽度
guint height; // 高度
guint framerate_n; // 帧率分子
guint framerate_d; // 帧率分母
/* 内部状态 */
gint video_fd; // V4L2文件描述符
gboolean is_open; // 是否已打开
/* 缓冲区管理 */
struct v4l2_buffer v4l2_buf; // V4L2缓冲区
struct v4l2_format v4l2_fmt; // V4L2格式
/* GStreamer特有 */
GstPad *srcpad; // 源Pad
GstBufferPool *pool; // 缓冲区池
GstAllocator *allocator; // 内存分配器
/* 统计 */
guint64 frames_produced; // 已产生帧数
guint64 frames_dropped; // 丢帧数
} GstRkCamSrc;
typedef struct _GstRkCamSrcClass {
GstElementClass parent_class; // 父类
} GstRkCamSrcClass;
/* 元素工厂注册 */
GType gst_rkcamsrc_get_type(void);
GST_ELEMENT_REGISTER_DECLARE(rkcamsrc);
/* 支持的格式列表 */
static const struct {
gint v4l2_pixfmt;
gint gst_video_format;
} format_map[] = {
{V4L2_PIX_FMT_NV12, GST_VIDEO_FORMAT_NV12},
{V4L2_PIX_FMT_YUYV, GST_VIDEO_FORMAT_YUY2},
{V4L2_PIX_FMT_UYVY, GST_VIDEO_FORMAT_UYVY},
};
/**
* @brief 元素状态改变处理 - 打开/关闭设备
*/
static GstStateChangeReturn gst_rkcamsrc_change_state(GstElement *element,
GstStateChange transition)
{
GstRkCamSrc *src = GST_RKCAMSRC(element);
GstStateChangeReturn ret;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
/* 打开V4L2设备 */
src->video_fd = open(src->device, O_RDWR);
if (src->video_fd < 0) {
GST_ELEMENT_ERROR(src, RESOURCE, OPEN_READ,
("Failed to open device %s", src->device),
("%s", g_strerror(errno)));
return GST_STATE_CHANGE_FAILURE;
}
/* 查询设备能力 */
struct v4l2_capability cap;
if (ioctl(src->video_fd, VIDIOC_QUERYCAP, &cap) < 0) {
GST_ELEMENT_ERROR(src, RESOURCE, READ,
("Failed to query capabilities"),
("%s", g_strerror(errno)));
close(src->video_fd);
return GST_STATE_CHANGE_FAILURE;
}
GST_INFO("Opened device: %s, driver: %s",
src->device, cap.driver);
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
/* 配置格式 */
memset(&src->v4l2_fmt, 0, sizeof(src->v4l2_fmt));
src->v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
src->v4l2_fmt.fmt.pix.width = src->width;
src->v4l2_fmt.fmt.pix.height = src->height;
src->v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
src->v4l2_fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (ioctl(src->video_fd, VIDIOC_S_FMT, &src->v4l2_fmt) < 0) {
GST_ELEMENT_ERROR(src, RESOURCE, SETTINGS,
("Failed to set format"),
("%s", g_strerror(errno)));
return GST_STATE_CHANGE_FAILURE;
}
/* 请求缓冲区 */
struct v4l2_requestbuffers reqbuf;
memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.count = 8;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
if (ioctl(src->video_fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
GST_ELEMENT_ERROR(src, RESOURCE, NO_SPACE_LEFT,
("Failed to request buffers"),
("%s", g_strerror(errno)));
return GST_STATE_CHANGE_FAILURE;
}
GST_INFO("Allocated %d buffers", reqbuf.count);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
/* 启动流 */
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(src->video_fd, VIDIOC_STREAMON, &type) < 0) {
GST_ELEMENT_ERROR(src, RESOURCE, FAILED,
("Failed to start streaming"),
("%s", g_strerror(errno)));
return GST_STATE_CHANGE_FAILURE;
}
GST_INFO("Stream started for camera %d", src->stream_id);
break;
default:
break;
}
ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
switch (transition) {
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
/* 停止流 */
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(src->video_fd, VIDIOC_STREAMOFF, &type);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
/* 释放缓冲区 */
struct v4l2_requestbuffers reqbuf;
memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.count = 0;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.memory = V4L2_MEMORY_MMAP;
ioctl(src->video_fd, VIDIOC_REQBUFS, &reqbuf);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
/* 关闭设备 */
close(src->video_fd);
break;
default:
break;
}
return ret;
}
/**
* @brief 创建缓冲区 - 从V4L2获取一帧
*/
static GstFlowReturn gst_rkcamsrc_create(GstPad *pad,
GstObject *parent,
GstBuffer **buffer)
{
GstRkCamSrc *src = GST_RKCAMSRC(parent);
struct v4l2_buffer v4l2_buf;
struct v4l2_plane planes[VIDEO_MAX_PLANES];
GstMemory *mem;
int ret;
/* 从V4L2出队缓冲区 */
memset(&v4l2_buf, 0, sizeof(v4l2_buf));
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buf.memory = V4L2_MEMORY_MMAP;
v4l2_buf.m.planes = planes;
v4l2_buf.length = 1;
ret = ioctl(src->video_fd, VIDIOC_DQBUF, &v4l2_buf);
if (ret < 0) {
if (errno == EAGAIN) {
return GST_FLOW_EOS;
}
GST_ELEMENT_ERROR(src, RESOURCE, READ,
("Failed to dequeue buffer"),
("%s", g_strerror(errno)));
return GST_FLOW_ERROR;
}
/* 创建GStreamer缓冲区 - 零拷贝 */
*buffer = gst_buffer_new();
/* 包装V4L2缓冲区到GStreamer内存 */
mem = gst_memory_new_wrapped(GST_MEMORY_FLAG_PHYSICALLY_CONTIGUOUS,
src->v4l2_buf.start,
src->v4l2_buf.bytesused,
0,
src->v4l2_buf.bytesused,
NULL, NULL);
gst_buffer_append_memory(*buffer, mem);
/* 设置时间戳 */
GST_BUFFER_PTS(*buffer) = v4l2_buf.timestamp.tv_sec * GST_SECOND +
v4l2_buf.timestamp.tv_usec * GST_USECOND;
GST_BUFFER_DURATION(*buffer) = gst_util_uint64_scale_int(
GST_SECOND, src->framerate_d, src->framerate_n);
/* 设置标志 */
if (v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
GST_BUFFER_FLAG_SET(*buffer, GST_BUFFER_FLAG_DELTA_UNIT);
}
/* 重新入队缓冲区 */
ret = ioctl(src->video_fd, VIDIOC_QBUF, &v4l2_buf);
if (ret < 0) {
GST_WARNING("Failed to requeue buffer: %s", g_strerror(errno));
}
src->frames_produced++;
return GST_FLOW_OK;
}
/**
* @brief 元素初始化
*/
static void gst_rkcamsrc_init(GstRkCamSrc *src)
{
/* 创建源Pad */
src->srcpad = gst_pad_new("src", GST_PAD_SRC);
gst_pad_set_chain_function(src->srcpad, NULL);
gst_pad_set_getrange_function(src->srcpad, gst_rkcamsrc_create);
gst_element_add_pad(GST_ELEMENT(src), src->srcpad);
/* 设置默认值 */
src->device = g_strdup("/dev/video0");
src->width = 1920;
src->height = 1080;
src->framerate_n = 30;
src->framerate_d = 1;
src->frames_produced = 0;
src->frames_dropped = 0;
}
/**
* @brief 元素工厂注册
*/
static void gst_rkcamsrc_class_init(GstRkCamSrcClass *klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
GstPadTemplate *templ;
/* 设置元素信息 */
gst_element_class_set_static_metadata(element_class,
"RK3588 Camera Source",
"Source/Video",
"Captures video from RK3588 camera interface",
"Your Name <email@example.com>");
/* 创建Pad模板 */
templ = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS,
gst_caps_from_string(
"video/x-raw, "
"format=(string)NV12, "
"width=(int)[1,4096], "
"height=(int)[1,4096], "
"framerate=(fraction)[0/1,240/1]"));
gst_element_class_add_pad_template(element_class, templ);
/* 设置属性 */
g_object_class_install_property(
G_OBJECT_CLASS(klass),
PROP_DEVICE,
g_param_spec_string("device", "Device",
"V4L2 device path",
"/dev/video0",
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/* 设置状态转换函数 */
element_class->change_state = GST_DEBUG_FUNCPTR(gst_rkcamsrc_change_state);
}
/* 注册插件 */
static gboolean plugin_init(GstPlugin *plugin)
{
return gst_element_register(plugin, "rkcamsrc", GST_RANK_PRIMARY,
GST_TYPE_RKCAMSRC);
}
GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR,
rkcamsrc, "RK3588 Camera Source Plugin",
plugin_init, VERSION, "LGPL", "GStreamer", "https://gstreamer.freedesktop.org")
3.2 16路摄像头GStreamer Pipeline构建
/**
* @brief 构建16路摄像头 + 音频 + 推流的GStreamer Pipeline
*
* 展示如何用GStreamer组合复杂媒体流
*/
static GstElement *build_16cam_pipeline(void)
{
GstElement *pipeline;
GstElement *rtsp_sink;
GstElement *audio_src, *audio_convert, *audio_encode;
GstElement *video_src[16];
GstElement *video_convert[16];
GstElement *video_encode[16];
GstElement *tee[16];
GstElement *queue[16];
GstElement *compositor; // 视频合成器
pipeline = gst_pipeline_new("16cam-pipeline");
/* 创建视频合成器 - 将16路合成一个画面 */
compositor = gst_element_factory_make("compositor", "compositor");
g_object_set(compositor, "background", "black", NULL);
/* 创建RTSP sink */
rtsp_sink = gst_element_factory_make("rtspclientsink", "rtsp-sink");
g_object_set(rtsp_sink, "location", "rtsp://0.0.0.0:8554/stream", NULL);
/* 创建16路视频源 */
for (int i = 0; i < 16; i++) {
char name[32];
/* 创建元素 */
sprintf(name, "camera%d", i);
video_src[i] = gst_element_factory_make("rkcamsrc", name);
g_object_set(video_src[i], "device", "/dev/video%d", i, NULL);
g_object_set(video_src[i], "stream-id", i, NULL);
sprintf(name, "convert%d", i);
video_convert[i] = gst_element_factory_make("videoconvert", name);
sprintf(name, "encode%d", i);
video_encode[i] = gst_element_factory_make("x264enc", name);
g_object_set(video_encode[i],
"bitrate", 2000,
"speed-preset", "ultrafast",
"tune", "zerolatency",
NULL);
sprintf(name, "tee%d", i);
tee[i] = gst_element_factory_make("tee", name);
sprintf(name, "queue%d", i);
queue[i] = gst_element_factory_make("queue", name);
g_object_set(queue[i],
"max-size-buffers", 10,
"leaky", 2, // 丢帧策略
NULL);
/* 添加到Pipeline */
gst_bin_add_many(GST_BIN(pipeline),
video_src[i], video_convert[i],
video_encode[i], tee[i], queue[i], NULL);
/* 链接 */
gst_element_link_many(video_src[i], video_convert[i],
video_encode[i], tee[i], NULL);
/* 从tee到合成器 */
GstPad *tee_pad = gst_element_get_request_pad(tee[i], "src_%u");
GstPad *comp_sink = gst_element_get_static_pad(compositor, "sink_%u");
gst_pad_link(tee_pad, comp_sink);
gst_object_unref(tee_pad);
/* 从tee到单独的RTSP流 (可选) */
GstPad *tee_pad2 = gst_element_get_request_pad(tee[i], "src_%u");
GstPad *queue_sink = gst_element_get_static_pad(queue[i], "sink");
gst_pad_link(tee_pad2, queue_sink);
gst_object_unref(tee_pad2);
}
/* 创建音频源 */
audio_src = gst_element_factory_make("alsasrc", "audio-src");
audio_convert = gst_element_factory_make("audioconvert", "audio-convert");
audio_encode = gst_element_factory_make("faac", "audio-encode");
gst_bin_add_many(GST_BIN(pipeline), audio_src, audio_convert,
audio_encode, compositor, NULL);
/* 链接音频 */
gst_element_link_many(audio_src, audio_convert, audio_encode, NULL);
/* 链接视频合成器到RTSP sink */
gst_element_link(compositor, rtsp_sink);
return pipeline;
}
四、GStreamer与其他中间件的关系
4.1 中间件集成架构图
/** * @brief GStreamer在多媒体生态中的位置 * * @verbatim * ┌─────────────────────────────────────────────────────────────────────────────────┐ * │ 多媒体应用生态 │ * ├─────────────────────────────────────────────────────────────────────────────────┤ * │ │ * │ ┌─────────────────────────────────────────────────────────────────────────┐ │ * │ │ Application Layer │ │ * │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ * │ │ │ 视频会议App │ │ 安防监控平台│ │ 直播平台 │ │ 视频编辑器 │ │ │ * │ │ │ (Zoom/Teams)│ │ (IVS平台) │ │ (OBS/Twitch)│ │ (Kdenlive) │ │ │ * │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │ * │ └─────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────┐ │ * │ │ High-Level Frameworks │ │ * │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ WebRTC │ FFmpeg │ OpenCV │ Qt Multimedia │ Android MediaCodec │ │ │ * │ │ └─────────────────────────────────────────────────────────────────┘ │ │ * │ └─────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────┐ │ * │ │ GStreamer (应用层中间件) │ │ * │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ * │ │ │ Pipeline │ Element │ Pad │ Buffer │ Clock │ Bus │ Registry │ │ │ * │ │ └─────────────────────────────────────────────────────────────────┘ │ │ * │ └─────────────────────────────────────────────────────────────────────────┘ │ * │ │ │ * │ ┌───────────────────────────┼───────────────────────────┐ │ * │ ▼ ▼ ▼ │ * │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ * │ │ System APIs │ │ Hardware APIs │ │ Network APIs │ │ * │ │ V4L2/ALSA/ │ │ VAAPI/OpenMAX/ │ │ RTP/RTSP/ │ │ * │ │ UVC/PA │ │ OpenGL/Vulkan │ │ WebRTC/HLS │ │ * │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ * │ │ │ │ │ * │ ▼ ▼ ▼ │ * │ ┌─────────────────────────────────────────────────────────────────────────┐ │ * │ │ Kernel / Hardware │ │ * │ │ Camera │ Microphone │ GPU │ VPU │ NPU │ Network │ │ * │ └─────────────────────────────────────────────────────────────────────────┘ │ * └─────────────────────────────────────────────────────────────────────────────────┘ * @endverbatim */
4.2 开源中间件对比
| 中间件 | 类型 | 定位 | 与GStreamer关系 |
|---|---|---|---|
| GStreamer | 多媒体框架 | 应用层中间件 | 自身就是中间件 |
| FFmpeg | 编解码库 | 底层库 | GStreamer可作为前端调用FFmpeg插件 |
| WebRTC | 实时通信框架 | 应用层中间件 | GStreamer可集成WebRTC(通过webrtcbin) |
| Live555 | RTSP/RTP库 | 协议栈 | GStreamer的rtspclientsink内部使用 |
| PulseAudio | 音频服务 | 系统中间件 | GStreamer通过pulsesrc/pulsesink调用 |
| OpenMAX | 硬件加速API | 系统中间件 | GStreamer通过omx插件调用 |
| VAAPI | 视频加速API | 系统中间件 | GStreamer通过vaapi插件调用 |
五、思路
Q: GStreamer到底算不算中间件?
标准思路:
GStreamer 是中间件,具体来说是应用层多媒体中间件。
理由如下:
1. 定义符合:中间件是位于操作系统和应用层之间的软件层,GStreamer正好在这个位置——它封装了V4L2/ALSA/VAAPI等系统API,向上提供统一的编程接口。
2. 抽象硬件差异:GStreamer屏蔽了底层硬件的差异,同一份代码可以在RK3588、树莓派、x86上运行,只需底层插件不同。
3. 提供标准接口:GStreamer定义了Element/Pad/Bin/Pipeline等编程模型,应用层只需关注Pipeline构建,无需关心底层实现。
4. 插件化架构:GStreamer采用插件系统,动态加载不同的Source/Filter/Sink,这是中间件的典型特征。
5. 与系统中间件的关系:
系统中间件(V4L2/ALSA):与内核直接交互
GStreamer(应用中间件):调用系统中间件,提供更高层抽象
所以,GStreamer是应用层中间件,而V4L2/ALSA是系统中间件,两者分层清晰。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)