我有一个Python程序,该程序通过网络接收一系列H264视频帧,我想显示这些视频帧,也可以选择进行记录。摄像机以30FPS的速度记录并尽可能快地发送帧,由于网络条件的变化,它并不能始终保持30FPS的速度。有时它会掉下来然后追上,而很少完全掉落帧。
“显示”部分很简单;我不需要担心时间安排或流元数据,只需要在帧到达时尽快显示它们即可:
input = av.open(get_video_stream())
for packet in input.demux(video=0):
for frame in packet.decode():
# A bunch of numpy and pygame code here to convert the frame to RGB
# row-major and blit it to the screen
“记录”部分看起来像,这应该很容易:
input = av.open(get_video_stream())
output = av.open(filename, 'w')
output.add_stream(template=input.streams[0])
for packet in input.demux(video=0):
for frame in packet.decode():
# ...display code...
packet.stream = output.streams[0]
output.mux_one(packet)
output.close()
确实,这会产生一个包含所有帧的有效MP4文件,如果我用mplayer -fps 30
播放它,则可以正常工作。但是,-fps 30
是绝对必需的:
$ ffprobe output.mp4
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 960x720,
1277664 kb/s, 12800 fps, 12800 tbr, 12800 tbn, 25600 tbc (default)
请注意,每秒12,800帧。 应该看起来像这样(通过调用mencoder -fps 30
并将框架插入其中来产生):
$ ffprobe mencoder_test.mp4
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 960x720,
2998 kb/s, 30 fps, 30 tbr, 90k tbn, 180k tbc (default)
检查从输入流中获得的数据包和帧,我看到:
stream: time_base=1/1200000
codec: framerate=25 time_base=1/50
packet: dts=None pts=None duration=48000 time_base=1/1200000
frame: dst=None pts=None time=None time_base=1/1200000
因此,数据包和帧根本没有时间戳;它们的time_base与最终文件中的时基或摄像机的实际帧频都不匹配;编解码器的帧率和时基与最终文件,摄像机帧率或其他视频流元数据不匹配!
关于时间和帧率问题,几乎完全没有PyAV文档,但是我尝试手动设置流,包和帧time_base
,dts
和{ {1}}没有成功。我总是可以再次重新录制录像的视频 以获得正确的帧率,但是我宁愿首先写入正确的视频文件。
那么,如何让pyAV重新混合视频,使其产生正确标记为30fps的输出?