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

news2026/3/26 16:59:40
一、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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…