我正在使用 gstreamer 通过模仿 UdpSink 的自定义 AppSink 进行流式传输。我们这样做是为了能够合并在其他端口上监听一些元数据。另外,原有的 UdpSink 坏了。无论如何,我已经成功流式传输了视频,但 UDP 数据包似乎没有正确打包。我想知道我是否错过了一些步骤。
这是我的发送管道:
filesrc (mpeg TS file) ! displayQueue ! streamTee ! tsdemux ! decoder ! videosink
streamTee ! sendQueue ! udpSink (our custom one)
接收端:
UdpSrc (custom) ! queue ! mpegtsdemux ! queue ! (mpegdecode || h264decode) ! ... ! videosink
流媒体可以工作。但它似乎非常脆弱。有时它会停止。有很多瑕疵。
因此,我尝试了 VLC。我将其设置为通过 UDP 单播进行流式传输。效果很好。我注意到 VLC 发送的视频方式与我的管道不同。我使用 Wireshark 分析了数据包:
使用的协议:VLC:(IP:UDP:MP2T
以及PET
、PMT
数据包和所有其他类型的 TS 相关内容)
矿:IP:UDP:Data
看起来我使用的管道只是通过 UDP 发送原始视频,没有任何错误更正。我错过了什么?使用的视频是 h264 或 mpeg 编码.mpg
文件。
我正在使用 gstreamer-java 来编程自定义 UdpSink 和 UdpSrc 元素,但无法在控制台中使用 gstreamer 进行测试,因为库存UdpSink 插件损坏我在 Linux VM 中尝试了一个简单的管道,并得到了一组与 VLC 类似的数据包:
gst-launch-0.10 -v videotestsrc ! mpeg2enc ! mpegtsmux ! udpsink host=192.168.2.100 port=1234
答案1
这只是一个想法,我对 gstreamer 不是很熟悉,所以我不知道它是如何filesrc
工作的,但我假设它不理解 MPEG-TS。MPEG-TS 要求数据包在特定边界内进入(通常为 188 字节)。我会尝试将您的 tee 放在 demux 之后,然后在您的 之前添加一个 mpegtsmux udpSink
。
我意识到这会做比实际需要更多的工作(解复用只是为了再次复用),但它将确保数据包正确对齐。如果它有效并且您需要消除开销,您可能需要考虑实施更智能的文件源。
答案2
你已经接近了。filesrc 插件对它正在读取的文件的内容一无所知。GStreamer 需要知道数据是传输流才能正确地传输它。虽然解复用和复用流可以完成这项工作,但还有更好的方法:
Source: gst-launch -v filesrc location=myvideo.ts ! tsparse set-timestamps=true ! udpsink host=192.168.2.100 port=1234
Dest: gst-launch udpsrc caps="video/mpegts, systemstream=(boolean)true, packetsize=(int)188" port=1234 ! tsdemux ! (video decoder) ! autovideosink
插件 tsparse 读取流并解析有关流的信息。它还将输出标识为传输流。这本身可能足以满足您的流媒体需求,因为它允许 udpsink 知道数据在 188 字节数据包中。在接收端,需要 tsdemux 来解析实际的视频流。元素“set-timestamps”告诉 tsparse 在传出数据包上设置时间戳,以便 udpsink 按时发送每一帧,而不是尽可能快地发送。
您还可以使用 rtpmp2tpay 和 rptmp2depay,它们将数据打包以供 udpsink 发送。它还将编码名称设置为 MP2T。您可以两种方式都尝试一下。
Source: gst-launch -v filesrc location=myvideo.ts ! tsparse set-timestamps=true ! rtpmp2tpay ! udpsink host=192.168.2.100 port=1234
Dest: gst-launch udpsrc caps="application/x-rtp, systemstream=(boolean)true, packetsize=(int)188" port=1234 ! rtpmp2tdepay ! tsdemux ! (video decoder) ! autovideosink