Gstreamer:如何在不重新编码的情况下将 rtpvp8depay 导入 webmmux?

Posted

技术标签:

【中文标题】Gstreamer:如何在不重新编码的情况下将 rtpvp8depay 导入 webmmux?【英文标题】:Gstreamer: How to pipe rtpvp8depay into webmmux without reencoding? 【发布时间】:2015-01-09 09:36:17 【问题描述】:

从提供 Webrtc 的浏览器中,我收到一个使用 janus 网关解密的 RTP 流。仅接收到视频 rtp 数据包后,会被中继到本地多播组以进行测试。

所以,假设我在 udp 端口​​上接收到 vp8 编码的 rtp 数据包。我也可以随时请求新的关键帧。

问题管道:

gst-launch-1.0 -v -v -v -v udpsrc multicast-group=224.1.1.1 auto-multicast=true port=1235 ! "application/x-rtp, payload=100, clock-rate=90000" ! rtpvp8depay ! webmmux streamable=true ! filesink location=/tmp/test.webm

产生错误

Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
/GstPipeline:pipeline0/GstCapsFilter:capsfilter0.GstPad:src: caps = "application/x-rtp\,\     payload\=\(int\)100\,\ clock-rate\=\(int\)90000\,\ media\=\(string\)video\,\ encoding-name\=\(string\)VP8-DRAFT-IETF-01"
/GstPipeline:pipeline0/GstRtpVP8Depay:rtpvp8depay0.GstPad:src: caps = "video/x-vp8\,\ framerate\=\(fraction\)0/1"
/GstPipeline:pipeline0/GstRtpVP8Depay:rtpvp8depay0.GstPad:sink: caps = "application/x-rtp\,\ payload\=\(int\)100\,\ clock-rate\=\(int\)90000\,\ media\=\(string\)video\,\ encoding-name\=\(string\)VP8-DRAFT-IETF-01"
ERROR: from element /GstPipeline:pipeline0/GstUDPSrc:udpsrc0: Internal data flow error.
Additional debug info:
gstbasesrc.c(2933): gst_base_src_loop (): /GstPipeline:pipeline0/GstUDPSrc:udpsrc0:
streaming task paused, reason not-negotiated (-4)
Execution ended after 0:00:00.039571113
Setting pipeline to PAUSED ...
/GstPipeline:pipeline0/GstWebMMux:webmmux0.GstPad:src: caps = video/webm
Setting pipeline to READY ...
Setting pipeline to NULL ...
Freeing pipeline ...

Kurento 项目提供了一个名为“vp8parse”的 gstreamer 插件来解决这个问题:

gst-launch-1.0 -v -v -v -v udpsrc multicast-group=224.1.1.1 auto-multicast=true port=1235 ! "application/x-rtp, payload=100, clock-rate=90000" ! rtpvp8depay ! vp8parse ! webmmux streamable=true ! filesink location=/tmp/test.webm
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
/GstPipeline:pipeline0/GstCapsFilter:capsfilter0.GstPad:src: caps = "application/x-rtp\,\ payload\=\(int\)100\,\ clock-rate\=\(int\)90000\,\ media\=\(string\)video\,\ encoding-name\=\(string\)VP8-DRAFT-IETF-01"
/GstPipeline:pipeline0/GstRtpVP8Depay:rtpvp8depay0.GstPad:src: caps = "video/x-vp8\,\ framerate\=\(fraction\)0/1"
/GstPipeline:pipeline0/KmsVp8Parse:kmsvp8parse0.GstPad:src: caps = "video/x-vp8\,\ framerate\=\(fraction\)0/1"
/GstPipeline:pipeline0/KmsVp8Parse:kmsvp8parse0.GstPad:sink: caps = "video/x-vp8\,\ framerate\=\(fraction\)0/1"
/GstPipeline:pipeline0/GstRtpVP8Depay:rtpvp8depay0.GstPad:sink: caps = "application/x-rtp\,\ payload\=\(int\)100\,\ clock-rate\=\(int\)90000\,\ media\=\(string\)video\,\ encoding-name\=\(string\)VP8-DRAFT-IETF-01"
HERE THE PIPELINE BLOCKS UNTIL A KEYFRAME IS RECEIVED
/GstPipeline:pipeline0/KmsVp8Parse:kmsvp8parse0.GstPad:src: caps = "video/x-vp8\,\ width\=\(int\)640\,\ height\=\(int\)480\,\ framerate\=\(fraction\)10/1"
/GstPipeline:pipeline0/GstWebMMux:webmmux0.GstMatroskamuxPad:video_0: caps = "video/x-vp8\,\ width\=\(int\)640\,\ height\=\(int\)480\,\ framerate\=\(fraction\)10/1"
/GstPipeline:pipeline0/GstWebMMux:webmmux0.GstPad:src: caps = video/webm
/GstPipeline:pipeline0/GstFileSink:filesink0.GstPad:sink: caps = video/webm
/GstPipeline:pipeline0/GstWebMMux:webmmux0.GstPad:src: caps = "video/webm\,\ streamheader\=\(buffer\)\<\ 1a45dfa301000000000000104282857765626d0042878102428581021853806701ffffffffffffff1549a96601000000000000502ad7b1830f42404d809f4753747265616d657220706c7567696e2076657273696f6e20312e342e31005741994753747265616d6572204d6174726f736b61206d7578657200446188062408b80e88c4001654ae6b010000000000003cae0100000000000033d7810183810173c588786b225315e5f279536e86566964656f00e00100000000000008b0820280ba8201e08686565f56503800\ \>"
/GstPipeline:pipeline0/GstFileSink:filesink0.GstPad:sink: caps = "video/webm\,\ streamheader\=\(buffer\)\<\ 1a45dfa301000000000000104282857765626d0042878102428581021853806701ffffffffffffff1549a96601000000000000502ad7b1830f42404d809f4753747265616d657220706c7567696e2076657273696f6e20312e342e31005741994753747265616d6572204d6174726f736b61206d7578657200446188062408b80e88c4001654ae6b010000000000003cae0100000000000033d7810183810173c588786b225315e5f279536e86566964656f00e00100000000000008b0820280ba8201e08686565f56503800\ \>"

看一下vp8parse source,似乎这个插件除了将 rtpvp8depay 提供的未触及的帧传送到其接收器之外别无其他,但也将 src 上限设置为视频宽度、高度和帧速率。

另一种可行的管道是:

gst-launch-1.0 -v -v -v -v udpsrc multicast-group=224.1.1.1 auto-multicast=true port=1235 ! "application/x-rtp, payload=100, clock-rate=90000" ! rtpvp8depay ! vp8dec ! vp8enc ! webmmux streamable=true ! filesink location=/tmp/test.webm

但使用 vp8dec ! vp8enc 显然没有多大意义,因为我已经收到了 vp8 编码流。

现在我的问题是如何在不重新编码流且不依赖 vp8parse 的情况下解决这个问题?如果没有其他选择,我似乎必须使用它,但由于这是目前无法通过标准 gstreamer 插件包获得的插件,我想避免这种情况。是否可以将上限强制为特定的宽度、高度、帧速率,以便 webmmux 不会抱怨?因为我认为这就是为什么第一个管道没有协商的原因。

我尝试使用像 rtpvp8depay 这样的 capsfilter ! capsfilter caps="video/x-vp8,width=640,height=480,framerate=10/1" ! webmmux 但它也不协商。

【问题讨论】:

你为什么反对使用Kurento的插件?发生这种情况的原因是因为 Chrome 出于带宽原因即时更改了 vp8 比特流,而我发现纠正它的方式是您已经提出的两种解决方案(使用该元素或重新编码流)。插件工作但你强制上限不起作用的部分原因是它从关键帧中读取值并动态设置上限,以便协商工作。放入 capsfilter 不会那样做。 我不确定我是否理解正确。这是否意味着,我可以使用 capsfilter 将帧速率设置为一个固定值,该值可能会工作几秒钟,然后因为 chrome 可能会改变流而中断?如果是,为什么在接收 udp 数据包时管道会立即中断?它不会等待关键帧。您的问题:主要是出于兴趣,我尝试了解编解码器、浏览器、gstreamer、kurento 插件如何协同工作。我希望有一个简单的解决方案来帮助更好地理解非 kurento-plugin 工作流程。 问题不仅在于帧率,还在于动态改变图片分辨率。 【参考方案1】:

这是错误747208,已经在上游修复, 但您系统中的 Gstreamer 版本可能较旧 (Ubuntu 14.04 中的 1.2.4)并且仍然受到影响。

作为此类旧版本的解决方法, 如果您知道视频的帧大小 您可以在 depayloader 之后使用 capssetter 元素 手动设置 depayloader 遗漏的上限:

gst-launch-1.0 -v \
  udpsrc multicast-group=224.1.1.1 auto-multicast=true port=1235 \
  ! "application/x-rtp, payload=100, clock-rate=90000" \
  ! rtpvp8depay ! capsetter caps="video/x-vp8,width=640,height=480" \
  ! webmmux streamable=true ! filesink location=/tmp/test.webm

【讨论】:

以上是关于Gstreamer:如何在不重新编码的情况下将 rtpvp8depay 导入 webmmux?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不知道编码的情况下将字节写入 Python 3 中的文件?

如何在不重新索引的情况下将项目添加到 laravel 列表集合中?

如何在不重新加载页面的情况下将任意 JSON 发送到 node.js?

如何在不重新加载网格的情况下将行添加到下一页中的 jqGrid?

PHP-如何在不重新启动 rds 的情况下将 aws.push git 到弹性 beantalk?

如何在不重新加载页面的情况下将用户重定向到 redux saga 上的另一个页面