I am writing frames from OpenCV using the following method. These code works totally fine when using a perfectly square resolution like 1000x1000 or 500x500, but when trying to do 1920x1200 or any other rectangular resolution, the written MP4 contains what is seen in the attached image. The MP4 file plays that still frame for the exact number of excepted seconds.
What could possibly be causing this kind of behavior?
- The camera width and height match the output resolution
- What is seen in the attachment is actually a frame from the camera, its just corrupted in the way seen.
- File size matches excpected output roughly
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()
Attached is the ffprobe log
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
CodePudding user response:
The described behavior definitely points to piping the frame data in a wrong order.
Given a (row-)contiguous numpy array (i.e., a C-ordered array), np.uint8
RGB24/BGR24 frame should be stored so frame.shape = (height, width, ncomp=3)
. If the ordering is not correct, use np.transpose
to reorder the array dimensions.
Meanwhile, FFmpeg's size input option is specified as -s widthxheight
. So first make sure the width and height matches the frame shape.
If your frame dimension is correct, then it is likely that your numpy array is formatted in Fortran order, or column contiguous order. For this representation, the correct shape is ncomp x width x height
. Sending a height x width x ncomp
array to the ffmpeg's stdin
pipe also screws up the image. For this, an easy fix is to use frame.tobytes('C')
to reorder the bytes.
In any case, it would be the most efficient to fix the dimension issues upstream so frame
is produced in the correct shape for the FFmpeg.