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 emailexample.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通过webrtcbinLive555RTSP/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是系统中间件两者分层清晰。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2437503.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!