FFMPEG 视频在不完美正方形时损坏

FFMPEG Video Corrupt When Not Perfect Square

我正在使用以下方法从 OpenCV 写入帧。这些代码在使用像 1000x1000 或 500x500 这样的完美正方形分辨率时工作得很好,但是当尝试使用 1920x1200 或任何其他矩形分辨率时,写入的 MP4 包含所附图像中看到的内容。 MP4 文件播放该静止帧的确切秒数。

什么可能导致这种行为?

process = sp.Popen(shlex.split(f'ffmpeg -y -hide_banner -loglevel error
 -s {fwidth}x{fheight} -pixel_format bgr24 -f rawvideo 
-r {self.fps} -i pipe: -vcodec libx265 -pix_fmt yuv420p 
-crf 24 {filename}'), stdin=sp.PIPE)

for frame in frameList:
    process.stdin.write(frame.tobytes())

# Close and flush stdin
process.stdin.close()

# Wait for sub-process to finish
process.wait()

# Terminate the sub-process
process.terminate()

附件是ffprobe日志

ffprobe version 3.4.8-0ubuntu0.2 Copyright (c) 2007-2020 the FFmpeg developers
  built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
  configuration: --prefix=/usr --extra-version=0ubuntu0.2 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
  WARNING: library configuration mismatch
  avcodec     configuration: --prefix=/usr --extra-version=0ubuntu0.2 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared --enable-version3 --disable-doc --disable-programs --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libtesseract --enable-libvo_amrwbenc
  libavutil      55. 78.100 / 55. 78.100
  libavcodec     57.107.100 / 57.107.100
  libavformat    57. 83.100 / 57. 83.100
  libavdevice    57. 10.100 / 57. 10.100
  libavfilter     6.107.100 /  6.107.100
  libavresample   3.  7.  0 /  3.  7.  0
  libswscale      4.  8.100 /  4.  8.100
  libswresample   2.  9.100 /  2.  9.100
  libpostproc    54.  7.100 / 54.  7.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/var/www/html/students/RH-PITCH_VIDEO.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2mp41
    encoder         : Lavf57.83.100
  Duration: 00:00:03.13, start: 0.000000, bitrate: 452 kb/s
    Stream #0:0(und): Video: hevc (Main) (hev1 / 0x31766568), yuv420p(tv, progressive), 1200x1100, 432 kb/s, 160 fps, 160 tbr, 10240 tbn, 160 tbc (default)
    Metadata:
      handler_name    : VideoHandler

所描述的行为肯定表明以错误的顺序传输帧数据。

给定一个(行)连续的 numpy 数组(即 C-ordered 数组),np.uint8 RGB24/BGR24 帧应该被存储,所以 frame.shape = (height, width, ncomp=3)。如果顺序不正确,请使用 np.transpose 对数组维度重新排序。

同时,FFmpeg 的大小输入选项被指定为-s widthxheight。所以首先确保宽度和高度与框架形状匹配。

如果你的框架维度是正确的,那么你的 numpy 数组很可能是按 Fortran 顺序或列连续顺序格式化的。对于此表示,正确的形状是 ncomp x width x height。将 height x width x ncomp 数组发送到 ffmpeg 的 stdin 管道也会破坏图像。为此,一个简单的解决方法是使用 frame.tobytes('C') 重新排序字节。

无论如何,最有效的方法是在上游解决尺寸问题,因此 frame 以正确的 FFmpeg 形状生成。