我有一个基本上是使用Raspberry Pis的自制视频会议系统。这是一个在过去几年中一直在使用的系统,而且大多数情况下,工作正常。
其中一项要求是保存音频和视频的副本以供以后播放。使用Gstreamer,Pi捕获H264视频和ac3音频,然后通过rtp发送到录制服务器。以下是当前的管道:
gst-launch-1.0 -v rtpbin name=rtpbin \
v4l2src do-timestamp=true device=/dev/video0 ! \
queue ! \
video/x-h264,width=1024,height=768,framerate=24/1,stream-format=byte-stream ! \
rtph264pay pt=96 config-interval=1 ! \
rtpbin.send_rtp_sink_0 \
rtpbin.send_rtp_src_0 ! multiudpsink clients=$Server:$RtspVideoPort,$Server:$ForwardVideoPort,$Server:$RecordVideoPort \
rtpbin.send_rtcp_src_0 ! udpsink host=$Server port=$RtcpVideoPort sync=false async=false \
alsasrc do-timestamp=true ! \
queue ! \
avenc_ac3_fixed ! \
rtpac3pay pt=97 ! \
rtpbin.send_rtp_sink_1 \
rtpbin.send_rtp_src_1 ! multiudpsink clients=$Server:$RtspAudioPort,$Server:$ForwardAudioPort,$Server:$RecordAudioPort \
rtpbin.send_rtcp_src_1 ! udpsink host=$Server port=$RtcpAudioPort sync=false async=false \
>> "logs/source_$(date +%Y-%m-%d_%H:%M).log" 2>&1 &
由于它是一个视频会议系统(在这种情况下只涉及两个参与者),因此有两个Pis运行此管道。
在服务器端,我为每个会议参与者提供以下两个管道:
gst-launch-1.0 -v -e udpsrc port=videorecordport1
! application/x-rtp, clock-rate=90000, encoding-name=H264
! rtph264depay
! video/x-h264,framerate=24/1
! mpegtsmux
! filesink location="recordedvideo1.mp4"
和
gst-launch-1.0 -v -e udpsrc port=audiorecordport1
! application/x-rtp, clock-rate=44100, encoding-name=AC3
! rtpac3depay
! ac3parse
! filesink location="recordedaudio1.ac3"
目的是这些会议持续一段时间。完成后,服务器将合并两个视频文件和两个音频文件。这是通过以下方式完成的......
gst-launch-1.0 filesrc location="recordedvideo1.mp4"
! tsdemux
! decodebin
! queue
! videomixer name=mix sink_0::xpos=0 sink_1::xpos=1024
! x264enc
! mpegtsmux name=mux
! filesink location="finalvideo.mp4" filesrc location="recordedvideo2.mp4"
! tsdemux
! decodebin
! queue
! mix. filesrc location="recordedaudio1.ac3"
! ac3parse
! a52dec
! queue
! audiomixer name=amix
! audioconvert
! avenc_ac3_fixed
! mux. filesrc location="recordedaudio2.ac3"
! ac3parse
! a52dec
! queue
! amix.
保存单独文件以供以后多路复用的原因是我们有足够的视频对话在服务器被淹没的同时进行。最好在不是这种情况下将它们组合在一起。
所以我已经阅读了一下这一切是如何工作的,但我仍然不确定我的实现是否正确。具体来说,将这些全部同步。如果我的理解是正确的,Pis将在为传出的a / v流生成时间戳时利用其系统时钟作为参考。我认为需要做时间戳。如果两个Pis都有相同的时钟,那么当我正在复用时,所有四个流都应该“匹配”。
这是我的困境。这在大多数情况下都可以正常工作。但是,我们偶尔会遇到一些问题。观看多路复用视频时,您有时会看到同步问题。而且经常可以看到两个源视频的长度几乎完全相同,但最终视频缩短了10秒。在某些情况下,我们的最终视频时间缩短了几分钟。
我对此的初步研究更倾向于确保Pis具有匹配的时钟。我们有两个AD控制器,默认情况下显然是Pis有时间的地方。其中一个是随机上升到20分钟左右的漂移,这可能每天发生几次。不用说,这不是一件好事。
我的修复方法是更改Pis以忽略从内部网络获取时间,而是依赖默认的ntp配置。我认为这有很大的帮助,但我仍然注意到我们有一些复制的视频,其中有10个左右的差异是不可预期的。
我想我想知道的是一个完整性检查我是否正确地做了这个,或者它是否只是在大多数情况下都能正常工作。在我付出更多努力来证明我们的Pis上仍然存在时钟同步问题之前,这将有所帮助。
我想知道的最重要的事情是时间戳是否按照我的想法运作。
我将传入的流保存到文件的方式有什么问题吗?
我正在复制这些文件的方式有什么问题吗?
将流保存到文件的服务器上的管道都是独立的。这些都应该合并为一个gstreamer过程吗?我不能认为这会有所帮助,因为如果服务器添加时间戳会更好吗?
根据建议,我试图在接收端使用rtpbin。没有太大的成功。这可能就是我首先没有使用它的原因。例如,这有效......
gst-launch-1.0 -v udpsrc port=5000
! application/x-rtp, clock-rate=90000, payload=96, encoding-name=H264
! rtph264depay
! video/x-h264,framerate=24/1
! decodebin
! autovideosink
但这不是:
gst-launch-1.0 -v rtpbin name=rtpbin udpsrc port=5000
! application/x-rtp, clock-rate=90000, payload=96, encoding-name=H264
! rtpbin.recv_rtp_sink_0 rtpbin.
! rtph264depay
! video/x-h264,framerate=24/1
! decodebin
! autovideosink
错误是“内部数据流错误”,后面是“流媒体任务暂停,原因未协商”。 rtpbin管道基于gstreamer文档中的示例,但根据我的情况进行了修改。我删除了所有rtcp的东西来简化它。我在这条管道上尝试了很多变种而没有运气。这是在Gstreamer 1.8.2的Windows版本上测试的
另一种编辑......有点奇怪,但rtpbin显然需要在封面中使用media = video,而不使用rtpbin则不需要。我猜我现在正在工作。