当前位置: 首页 > article >正文

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是系统中间件两者分层清晰。

相关文章:

GStreamer:中间件定位与架构深度解析

一、GStreamer的准确定位 1.1 中间件定义与GStreamer的位置 /*** brief 中间件定义与GStreamer定位分析* * 核心:GStreamer是**多媒体框架**,属于**应用层中间件*** * 中间件分类:* ┌──────────────────────────…...

如何用视频解析工具高效获取B站视频资源

如何用视频解析工具高效获取B站视频资源 【免费下载链接】bilibili-parse bilibili Video API 项目地址: https://gitcode.com/gh_mirrors/bi/bilibili-parse 你是否曾遇到想保存B站精彩视频却无从下手的情况?作为一款专为普通用户设计的视频解析工具&#x…...

华为手机BottomSheetDialog底部导航栏变黑?一招教你改成白色(附完整代码)

华为手机BottomSheetDialog底部导航栏颜色适配实战指南 如果你是一名Android开发者,最近在华为手机上测试应用时,可能会遇到一个令人头疼的UI问题:BottomSheetDialog底部弹出的虚拟导航栏总是显示为黑色,与应用的明亮主题格格不入…...

文华财经期货指标实战解析-多空变色线与黄金分割自动画线策略源码详解

1. 多空变色线指标的核心逻辑 多空变色线是期货交易中非常实用的趋势判断工具,它的核心原理是通过MACD指标的金叉死叉结合均线系统来动态标记市场趋势。我最早接触这个指标是在2015年铜期货的一波大行情中,当时手动判断趋势总是慢半拍,后来发…...

零基础快速入门前端JavaScript 浏览器环境输入输出语句全解析:从弹框交互到控制台调试(可用于备赛蓝桥杯Web应用开发赛道)

一、JavaScript 核心输出语句详解输出语句的核心作用,是将程序的运行结果、提示信息展示给用户或开发者,浏览器环境中最常用的输出方式分为「弹窗类输出」和「控制台类输出」两大类。1.1 alert () 警告弹窗输出alert() 是 JS 入门最基础的弹窗输出语句&a…...

AI入门指南:盘点那些媲美ChatGPT的国产大模型工具

1. 国产AI大模型崛起:为什么你需要关注它们? 最近两年,AI大模型的发展速度让人瞠目结舌。作为AI领域的从业者,我亲眼见证了国产大模型从追赶到并驾齐驱的整个过程。很多人可能不知道,现在国内已经有好几款大模型在实际…...

电商开发者必看:如何用易支付+富友插件实现零配置支付通道(附PHP示例代码)

电商支付集成实战:零配置智能路由支付方案与PHP实现 当用户点击"立即支付"按钮时,一次成功的交易背后往往隐藏着复杂的支付通道调度逻辑。作为电商开发者,我们既希望提供流畅的支付体验,又不得不面对通道配置繁琐、故障…...

Ubuntu22.04下Qt6安装避坑指南:清华源加速+版本选择建议

Ubuntu 22.04下Qt6高效安装实战:从镜像加速到组件优化 在Linux环境下进行跨平台应用开发时,Qt框架始终是C开发者的首选工具链之一。随着Qt6系列的逐步成熟,越来越多的开发者开始将项目迁移到这个支持现代C特性的新版本上。然而对于国内开发者…...

ElementPlus表单布局陷阱:深度解析`unexpected width 0`的成因与实战规避策略

1. 问题现象与背景 最近在用Vue3ElementPlus开发后台管理系统时,遇到了一个奇怪的警告:ElementPlusError: [ElForm] unexpected width 0。这个警告会在切换登录表单时突然出现,虽然不影响功能,但控制台一片红看着实在闹心。 我当时…...

CentOS 7.6下NetBackup 9.1安装全攻略:从账号配置到许可证激活

CentOS 7.6企业级备份方案:NetBackup 9.1深度部署指南 在企业IT基础设施中,数据备份是确保业务连续性的最后防线。作为业界领先的企业级备份解决方案,Veritas NetBackup以其卓越的可靠性、广泛的平台兼容性和丰富的功能集,成为众多…...

热门网游推荐网站信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】

💡实话实说:有自己的项目库存,不需要找别人拿货再加价,所以能给到超低价格。摘要 随着互联网技术的快速发展,网络游戏已成为全球范围内的重要娱乐方式之一,玩家对游戏资讯的需求日益增长。热门网游推荐网站…...

Nanbeige 4.1-3B惊艳效果:加载动画采用8-bit风格进度条+像素音效同步

Nanbeige 4.1-3B惊艳效果:加载动画采用8-bit风格进度条像素音效同步 1. 复古像素风AI对话体验 Nanbeige 4.1-3B模型的全新"像素冒险聊天终端"彻底颠覆了传统AI对话界面的设计理念。这套专为游戏爱好者打造的前端界面,将现代大模型技术与复古…...

Kali Linux 2024.2 上 DVWA 靶场保姆级搭建教程(附常见错误排查)

Kali Linux 2024.2 上 DVWA 靶场深度搭建指南与疑难解析 在网络安全领域,实践是检验技能的唯一标准。DVWA(Damn Vulnerable Web Application)作为一款专为安全测试设计的脆弱Web应用,为安全爱好者提供了完美的实验平台。本文将带你…...

QLExpress语法实战:从基础操作到高级扩展

1. QLExpress入门:从零开始写脚本 第一次接触QLExpress时,我被它的轻量级设计惊艳到了。这个只有250KB的脚本引擎,却能处理复杂的业务规则计算。先来看个最简单的例子: ExpressRunner runner new ExpressRunner(); DefaultContex…...

Proxmox VE 在 Debian 9.x 上的完整部署与中文设置教程

Proxmox VE 在 Debian 9.x 上的企业级部署与中文优化指南 虚拟化技术已成为现代IT基础设施的核心组件,而Proxmox VE作为开源的服务器虚拟化管理平台,凭借其稳定性、功能丰富性和易用性,在中小企业和技术爱好者中广受欢迎。本文将详细介绍在De…...

Linux系统管理员必看:logrotate权限问题终极解决方案(附su指令详解)

Linux系统管理员必看:logrotate权限问题终极解决方案(附su指令详解) 在Linux系统运维的日常工作中,日志管理是每个管理员都无法回避的重要任务。而logrotate作为系统自带的日志轮转工具,其稳定性和可靠性直接关系到系统…...

《jQuery 滑动:深入浅出的探索与实践》

《jQuery 滑动:深入浅出的探索与实践》 引言 在Web开发中,滑动交互已经成为了用户操作网站、应用的重要组成部分。jQuery作为最流行的JavaScript库之一,提供了丰富的滑动插件和API,极大地简化了滑动效果的实现。本文将深入浅出地探…...

博士论文10万字降AI率怎么选?大篇幅论文的高效处理方案

博士论文10万字降AI率怎么选?大篇幅论文的高效处理方案 写这篇文章的起因是一个读博的朋友深夜发消息问我:“我论文11万字,AI率查出来39%,处理费用算下来好几百块,万一花了钱效果不行怎么办?” 这个顾虑太…...

Swift 类

Swift 类 在 Swift 语言中,类(Class)是一种用于定义自定义数据类型的蓝图,它包含数据(属性)和行为(方法)。类在面向对象编程(OOP)中扮演着核心角色,通过类,开发者可以创建对象,封装数据和行为,提高代码的复用性和可维护性。 类的定义与创建 在 Swift 中,定义…...

ThinkPHP高效学习路径全解析

好的,我们来梳理一条系统的 ThinkPHP 学习路径。ThinkPHP 是一个高效、简洁且功能丰富的 PHP 开发框架,学习它可以帮你快速构建 Web 应用程序。 学习路径概览 基础准备框架安装与环境配置核心概念与组件进阶功能与扩展项目实践与优化 1. 基础准备 PHP…...

Laravel学习指南:从入门到精通

好的,这是一份结构清晰的Laravel学习路径指南,希望能帮助你逐步掌握这个强大的PHP框架: Laravel 学习之路:循序渐进掌握现代 PHP 开发 🛠 阶段一:基础准备与环境搭建 PHP 基础巩固: 确保你对…...

英飞凌SMU安全管理单元:从基础到实战应用

1. 英飞凌SMU安全管理单元基础解析 第一次接触英飞凌SMU(Safety Management Unit)时,我完全被这个"安全管家"的设计理念所折服。简单来说,SMU就像汽车的中央行车电脑,实时监控着各个关键部件的运行状态。不同…...

斐讯R1音箱无屏联网终极指南:ADB命令+静态IP配置全流程

斐讯R1音箱无屏联网终极指南:ADB命令静态IP配置全流程 斐讯R1智能音箱作为一款曾经风靡一时的智能硬件产品,因其出色的音质和极具性价比的价格赢得了不少用户的青睐。然而,这款设备最大的痛点之一就是没有屏幕,导致初次配置联网变…...

ESP32C3开发实战:深入解析sdkconfig重构与Kconfig配置技巧

1. 为什么需要重构sdkconfig文件? 第一次接触ESP32C3开发的朋友可能会发现,当你从官方例程移植代码到自己项目时,经常会遇到各种莫名其妙的编译错误。最常见的就是"undefined reference"这类报错,明明代码一模一样&…...

HC-SRF04超声波测距传感器与Proteus仿真实战:从原理到代码实现

1. HC-SRF04超声波测距传感器基础解析 第一次接触超声波测距传感器时,我和很多人一样被它"隔空测距"的能力惊艳到了。这种不需要物理接触就能测量距离的技术,在机器人避障、停车辅助等场景中特别实用。HC-SRF04作为经典款超声波传感器&#xf…...

vue+python甜点蛋糕商城系统 团子烘焙销售服务系统

目录系统架构设计前端功能模块后端功能实现部署与优化测试与维护项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作系统架构设计 采用前后端分离架构,前端使用Vue.js框架构建用户界面,后端使用Python的Dja…...

TI官方PSpice for TI安装避坑指南:从申请Key到解决器件搜索栏空白(附详细步骤)

PSpice for TI安装与配置全攻略:从申请到实战避坑指南 第一次打开PSpice for TI时,那个空白的器件搜索栏让我差点以为下载了假软件——直到在安装目录深处找到一个不起眼的.ini文件。作为TI官方推出的免费电路仿真工具,PSpice for TI确实能帮…...

闲置Kindle变废为宝:手把手教你用树莓派驱动墨水屏(附固件降级指南)

闲置Kindle墨水屏改造指南:用树莓派打造极简信息终端 去年整理书房时翻出一台积灰的Kindle Paperwhite,屏幕完好却因系统卡顿早已闲置。作为硬件爱好者,我萌生了一个想法:能否将这块优质墨水屏改造成树莓派的外接显示器&#xff…...

基于Hadoop的航班分析系统的设计与实现(详细版)

基于Hadoop的航班分析系统的设计与实现(详细版) 摘要 随着航空业的快速发展,航班数据呈爆炸式增长。传统的单机数据处理方式难以满足海量航班数据的存储、计算与分析需求。本文设计并实现了一套基于Hadoop生态圈的航班分析系统。系统利用HDFS进行分布式存储,利用MapReduc…...

PLC与工控机通讯协议实战:从RS-485到Modbus TCP/IP的配置指南

PLC与工控机通讯协议实战:从RS-485到Modbus TCP/IP的配置指南 在工业自动化现场,PLC与工控机之间的稳定通讯是系统可靠运行的命脉。当某汽车焊接产线因信号干扰导致数据丢包时,工程师花了三天时间才发现是RS-485终端电阻配置不当——这类看似…...