3

我有一个 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成功。我总是可以再次重新录制录制的视频以获得正确的帧速率,但我宁愿首先编写正确的视频文件。dtspts

那么,如何让 pyAV 以产生正确标记为 30fps 的输出的方式重新混合视频?

4

0 回答 0