在 RTMP 流上添加时间叠加的 Gstreamer 问题
Posted
技术标签:
【中文标题】在 RTMP 流上添加时间叠加的 Gstreamer 问题【英文标题】:Gstreamer issue with adding timeoverlay on RTMP stream 【发布时间】:2020-03-23 21:16:23 【问题描述】:我需要在 rtmp 流中添加时间覆盖,并保存到磁盘。以下管道,没有覆盖,工作正常:
gst-launch-1.0 -v \
rtmpsrc location=rtmp://192.168.x.x/live/0 do-timestamp=true ! queue2 ! flvdemux name=demux \
flvmux name=mux \
demux.video ! queue ! decodebin \
! nvvidconv \
! 'video/x-raw(memory:NVMM),width=1920,height=1080, format=(string)I420, framerate=50/1' \
! nvv4l2h264enc ! h264parse \
! mux.video \
demux.audio ! queue name="dmx_aud_q" ! mux.audio \
mux.src ! queue name="mux_q" ! filesink location="rtmp.flv"
一旦我添加了时间覆盖(甚至时钟覆盖),管道就不会运行:
gst-launch-1.0 -v \
rtmpsrc location=rtmp://192.168.0.168/x.x do-timestamp=true ! queue2 ! flvdemux name=demux \
flvmux name=mux \
demux.video ! queue ! decodebin \
! timeoverlay \
! nvvidconv \
! 'video/x-raw(memory:NVMM),width=1920,height=1080, format=(string)I420, framerate=50/1' \
! nvv4l2h264enc ! h264parse \
! mux.video \
demux.audio ! queue name="dmx_aud_q" ! mux.audio \
mux.src ! queue name="mux_q" ! filesink location="rtmp.flv"
最后添加的 GST_DEBUG=3 日志。流水线图如下。
据我了解,在decodebin
移交给timeoverlay
时,上限协商存在一些问题。我无法弄清楚如何以管道可以继续复用的方式使 timeoverlay 接受或输出数据。任何有助于了解这里发生的事情以及如何找到解决方案的帮助都会很棒。
这是在运行 Ubuntu 18.0 的 Nvidia Jetson Nano 板上。 (以“nv”开头的插件通常可以替换为其他系统上的常规插件,我相信 - nvvidconv
和 videoconvert
,nvv4l2h264enc
和 omxh264enc
等。
将管道设置为 PAUSED ... 以阻塞模式打开 0:00:00.119491546 834 0x55b9d05600 WARN v4l2 gstv4l2object.c:2370:gst_v4l2_object_add_interlace_mode:0x55b9cf2360 无法确定隔行模式 0:00:00.119570298 834 0x55b9d05600 警告 v4l2 gstv4l2object.c:2370:gst_v4l2_object_add_interlace_mode:0x55b9cf2360 无法确定隔行模式 0:00:00.119623164 834 0x55b9d05600 警告 v4l2 gstv4l2object.c:2370:gst_v4l2_object_add_interlace_mode:0x55b9cf2360 无法确定隔行模式 0:00:00.119721552 834 0x55b9d05600 警告 v4l2 gstv4l2object.c:4408:gst_v4l2_object_probe_caps: 无法使用 VIDIOC_CROPCAP 探测像素纵横比:未知错误 -1 管道正在预滚... 0:00:00.406155973 834 0x55b9a72370 WARN flvdemux gstflvdemux.c:659:gst_flv_demux_parse_tag_script: 失败 阅读标签,跳过 /GstPipeline:pipeline0/GstQueue:dmx_aud_q.GstPad:sink: caps = 音频/mpeg, mpegversion=(int)4, framed=(boolean)true, 流格式=(字符串)原始,速率=(int)44100,通道=(int)2, 编解码器数据=(缓冲区)1210 /GstPipeline:pipeline0/GstQueue:dmx_aud_q.GstPad:src: caps = 音频/mpeg, mpegversion=(int)4, framed=(boolean)true, 流格式=(字符串)原始,速率=(int)44100,通道=(int)2, 编解码器数据=(缓冲区)1210 /GstPipeline:pipeline0/GstFlvMux:mux.GstFlvMuxPad:sink_1: caps = 音频/mpeg, mpegversion=(int)4, framed=(boolean)true, 流格式=(字符串)原始,速率=(int)44100,通道=(int)2, 编解码器数据=(缓冲区)1210 /GstPipeline:pipeline0/GstQueue:queue0.GstPad:sink: caps = 视频/x-h264,流格式=(字符串)avc,宽度=(int)1920, 高度=(int)1080, codec_data=(缓冲区)0142002affe100166742002a95a81e0089f961000003000100000300648401000468ce3c80 /GstPipeline:pipeline0/GstQueue:queue0.GstPad:src: caps = 视频/x-h264,流格式=(字符串)avc,宽度=(int)1920, 高度=(int)1080, codec_data=(缓冲区)0142002affe100166742002a95a81e0089f961000003000100000300648401000468ce3c80 /GstPipeline:pipeline0/GstDecodeBin:decodebin0.GstGhostPad:sink.GstProxyPad:proxypad0: 大写=视频/x-h264,流格式=(字符串)avc,宽度=(int)1920, 高度=(int)1080, codec_data=(缓冲区)0142002affe100166742002a95a81e0089f961000003000100000300648401000468ce3c80 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstTypeFindElement:typefind.GstPad:src: 大写=视频/x-h264,流格式=(字符串)avc,宽度=(int)1920, 高度=(int)1080, codec_data=(缓冲区)0142002affe100166742002a95a81e0089f961000003000100000300648401000468ce3c80 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstH264Parse:h264parse1.GstPad:sink: 大写=视频/x-h264,流格式=(字符串)avc,宽度=(int)1920, 高度=(int)1080, codec_data=(缓冲区)0142002affe100166742002a95a81e0089f961000003000100000300648401000468ce3c80 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstTypeFindElement:typefind.GstPad:sink: 大写=视频/x-h264,流格式=(字符串)avc,宽度=(int)1920, 高度=(int)1080, codec_data=(缓冲区)0142002affe100166742002a95a81e0089f961000003000100000300648401000468ce3c80 /GstPipeline:pipeline0/GstDecodeBin:decodebin0.GstGhostPad:sink: caps =视频/x-h264,流格式=(字符串)avc,宽度=(int)1920,高度=(int)1080, codec_data=(缓冲区)0142002affe100166742002a95a81e0089f961000003000100000300648401000468ce3c80 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstH264Parse:h264parse1.GstPad:src: 大写=视频/x-h264,流格式=(字符串)字节流, 宽度=(整数)1920,高度=(整数)1080,帧率=(分数)50/1, 隔行模式=(字符串)渐进式,色度格式=(字符串)4:2:0, 位深度亮度=(uint)8,位深度色度=(uint)8, 解析=(布尔)真,对齐=(字符串)au,配置文件=(字符串)基线, level=(string)4.2 在阻塞模式下打开 0:00:00.823485062 834 0x55b9ce8a30 警告 v4l2 gstv4l2object.c:4408:gst_v4l2_object_probe_caps: 无法使用 VIDIOC_CROPCAP 探测像素纵横比:未知错误 -1 0:00:00.823543397 834 0x55b9ce8a30 WARN v4l2 gstv4l2object.c:2370:gst_v4l2_object_add_interlace_mode:0x7f6807a640 无法确定隔行扫描模式 NvMMLiteOpen : Block : BlockType = 261 NVMEDIA:读取 vendor.tegra.display-size:状态:6 NvMMLiteBlockCreate:块:BlockType = 261 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/nvv4l2decoder:nvv4l2decoder0.GstPad:sink: 大写=视频/x-h264,流格式=(字符串)字节流, 宽度=(整数)1920,高度=(整数)1080,帧率=(分数)50/1, 隔行模式=(字符串)渐进式,色度格式=(字符串)4:2:0, 位深度亮度=(uint)8,位深度色度=(uint)8, 解析=(布尔)真,对齐=(字符串)au,配置文件=(字符串)基线, 级别=(字符串)4.2 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstCapsFilter:capsfilter1.GstPad:src: 大写=视频/x-h264,流格式=(字符串)字节流, 宽度=(整数)1920,高度=(整数)1080,帧率=(分数)50/1, 隔行模式=(字符串)渐进式,色度格式=(字符串)4:2:0, 位深度亮度=(uint)8,位深度色度=(uint)8, 解析=(布尔)真,对齐=(字符串)au,配置文件=(字符串)基线, 级别=(字符串)4.2 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstCapsFilter:capsfilter1.GstPad:sink: 大写=视频/x-h264,流格式=(字符串)字节流, 宽度=(整数)1920,高度=(整数)1080,帧率=(分数)50/1, 隔行模式=(字符串)渐进式,色度格式=(字符串)4:2:0, 位深度亮度=(uint)8,位深度色度=(uint)8, 解析=(布尔)真,对齐=(字符串)au,配置文件=(字符串)基线, 级别=(字符串)4.2 0:00:00.932089228 834 0x55b9ce8a30 警告 v4l2 gstv4l2object.c:4408:gst_v4l2_object_probe_caps: 无法使用 VIDIOC_CROPCAP 探测像素纵横比:未知错误 -1 0:00:00.932560124 834 0x55b9ce8a30 WARN v4l2 gstv4l2object.c:2370:gst_v4l2_object_add_interlace_mode:0x7f6807a640 无法确定隔行模式 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/nvv4l2decoder:nvv4l2decoder0.GstPad:src: 大写=视频/x-raw(内存:NVMM),格式=(字符串)NV12,宽度=(int)1920, 高度=(int)1080,隔行模式=(字符串)渐进式, 多视图模式=(字符串)单声道, multiview-flags=(GstVideoMultiviewFlagsSet)0:ffffffff:/right-view-first/left-flipped/left-flopped/right-flipped/right-flopped/half-aspect/混合单声道, 像素纵横比=(分数)1/1,色度站点=(字符串)mpeg2, colorimetry=(string)bt709, framerate=(fraction)50/1
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.065: gst_mini_object_copy:断言 'mini_object != NULL' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.066: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.066: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.066: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.066: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.066: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.067: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.067: gst_mini_object_copy:断言 'mini_object != NULL' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.068: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.068: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.068: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.068: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.068: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.069: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败 0:00:00.942959420 834 0x55b9ce8a30 警告 GST_PADS gstpad.c:4226:gst_pad_peer_query:无法发送 粘性事件 0:00:00.943568965 834 0x55b9ce8a30 WARN v4l2videodec gstv4l2videodec.c:1433:gst_v4l2_video_dec_decide_allocation: 持续时间无效,未设置延迟 0:00:00.944316482 834 0x55b9ce8a30 警告 v4l2bufferpool gstv4l2bufferpool.c:1054:gst_v4l2_buffer_pool_start: 缓冲区不确定或不足,启用复制阈值
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.073: gst_mini_object_copy:断言 'mini_object != NULL' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.074: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.074: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.074: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.074: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.074: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.074: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败 0:00:00.948613871 834 0x55b9ce8a30 WARN basetransform gstbasetransform.c:1355:gst_base_transform_setcaps: transform 无法转换视频/x-h264, 流格式=(字符串)字节流,宽度=(整数)1920,高度=(整数)1080, framerate=(fraction)50/1, interlace-mode=(string)progressive, 色度格式=(字符串)4:2:0,位深度亮度=(uint)8, 位深度色度=(uint)8,解析=(布尔)真,对齐=(字符串)au, profile=(string)baseline, level=(string)4.2 在我们支持的任何东西中 0:00:00.948674601 834 0x55b9ce8a30 WARN basetransform gstbasetransform.c:1415:gst_base_transform_reconfigure: 警告:未协商 0:00:00.948709446 834 0x55b9ce8a30 WARN 碱基变换 gstbasetransform.c:1415:gst_base_transform_reconfigure: 警告:未协商警告:来自元素 /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstCapsFilter:capsfilter1: 未协商附加调试信息:gstbasetransform.c(1415): gst_base_transform_reconfigure (): /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstCapsFilter:capsfilter1: 未协商 0:00:00.971426937 834 0x7f70004a80 WARN basesrc gstbasesrc.c:3055:gst_base_src_loop:错误:内部 数据流错误。 0:00:00.971545793 834 0x7f70004a80 警告 basesrc gstbasesrc.c:3055:gst_base_src_loop: 错误: 流停止,原因未协商 (-4) 0:00:00.978535326 834 0x7f6807c8f0 WARN v4l2bufferpool gstv4l2bufferpool.c:1518:gst_v4l2_buffer_pool_dqbuf: 驱动程序永远不应将 v4l2_buffer.field 设置为 ANY
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.105: gst_mini_object_copy:断言 'mini_object != NULL' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.105: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.105: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.105: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.105: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.105: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.105: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_mini_object_copy:断言 'mini_object != NULL' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败 错误:来自元素 /GstPipeline:pipeline0/GstRTMPSrc:rtmpsrc0: 内部数据流错误。
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_mini_object_copy:断言 'mini_object != NULL' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.106: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.107: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.107: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.107: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败 附加调试信息:gstbasesrc.c(3055):gst_base_src_loop (): /GstPipeline:pipeline0/GstRTMPSrc:rtmpsrc0: 流停止,原因 未协商 (-4) 错误:管道不想预卷。环境 管道为 NULL ...
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.107: gst_mini_object_copy:断言 'mini_object != NULL' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_mini_object_copy:断言 'mini_object != NULL' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.108: gst_caps_get_structure: 断言 'GST_IS_CAPS (caps)' 失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.109: gst_structure_copy:断言“结构!= NULL”失败
(gst-launch-1.0:834): GStreamer-CRITICAL **: 14:19:35.109: gst_caps_append_structure_full:断言“GST_IS_CAPS(大写)”失败 释放管道...
【问题讨论】:
您可以通过GST_DEBUG=GST_CAPS:5
查看上限协商。在黑暗中拍摄 - nvv4l2decoder 产生 DMA 缓冲区的问题不是问题,但 timeoverlay 仅适用于普通缓冲区吗?我想没有 nvtimeoverlay 这样的东西。在时间覆盖之前添加 videoconvert 会发生什么(但我猜你会丢失 DMA 的东西)?
您好@nayana,感谢您的回复。你猜对了,这确实是我最终解决它的方式——即使时间覆盖源上限说 ANY,它也无法处理 NVVM 内存。 decodebin
在内部使用 nvv4l2decoder
,这会在其 src 上生成 'video/x-raw(memory:NVMM)'
。我在timeoverlay
之前添加了nvvidconv ! 'video/x-raw'
,现在可以使用了。您能否在此处添加它作为答案,以便我接受它作为答案?
我有一些想法.. 使用 nvcompositor 来合成解码的视频和时间覆盖怎么样,这样它可能会更快? timeoverlay 应该产生带有 alpha 的全屏帧。我不知道它是否确实以某种方式加快了速度。也许它会过于复杂。
【参考方案1】:
所以正如 Aswin 所说,它是通过在 timeoverlay 之前添加 convert 来解决的。
这是因为 timeoverlay 不能与 DMA 缓冲区一起使用(这就是 (memory:NVMM)
的意思)
所以管道看起来像原始的,除了这个变化:
... decodebin ! nvvidconv ! 'video/x-raw' ! timeoverlay ! nvvidconv ! 'video/x-raw(memory:NVMM)
这些错误基本上是关于 timeoverlay 无法链接到将缓冲区输出为 DMA 的 nvv4l2decoder。我们需要 nvvidconv 来复制这些缓冲区,以便我们可以在用户空间中使用它们。
详细说明:
根据我对 DMA/CPU 缓冲区的模糊理解(请正确)- 所有 nv* 元素都能够与 DMA 缓冲区一起工作(我猜更直接),这加快了进程。但是在nvv4l2decoder
和nvv4l2h264enc
之间,我们放置了timeoverlay 来为视频添加时间..
但不幸的是,timeoverlay 元素无法使用这些缓冲区。所以我们添加了 nvviddonv,它慢慢地将缓冲区(它通过 CPU)复制到用户空间,我们慢慢地进行更改,然后它慢慢地回到更快的“DMA 缓冲区空间”。但我看不出有什么办法。除非有一些花哨的自定义元素可以直接使用缓冲区。
在过去几年中,GStreamer 进行了一些工作以更好地使用这些缓冲区 - 我看到了 ndufresne 的一些关于 DMA 栅栏(异步使用 DMA 缓冲区)和零复制管道(不确定是否适用)的演示: 零拷贝:https://youtu.be/kNaa1fPv_uo DMA 围栏:https://youtu.be/HpmzJGHqObs
一些通用的 Linux 文章: https://01.org/linuxgraphics/gfx-docs/drm/driver-api/dma-buf.html
【讨论】:
以上是关于在 RTMP 流上添加时间叠加的 Gstreamer 问题的主要内容,如果未能解决你的问题,请参考以下文章