I've been trying to create a Python app that takes an mp4 file, an mp3 file, and a dictionary of captions to produce an output mp4 file.
I got it to work well but I found the libx264
codec to be quite slow when calling write_videofile()
, especially with the CompositeVideoClip
objects. I wanted to use my GPU to accelerate the encoding process, so after doing a lot of research I did the following:
ffmpeg -codecs
)FFMPEG_BINARY
in my Python code to what I have on my PATHI'm using Windows 10 and write_videofile()
with works just fine with the libx264
codec, even after changing the FFMPEG_BINARY
. However, when I set codec='h264_nvenc'
, even though moviepy
finishes successfully, the resulting mp4 file seems corrupted. It's totally black and I cannot play it.
Here is my code:
GPU_ACCELERATION = True
if GPU_ACCELERATION:
os.environ["FFMPEG_BINARY"] = FFMPEG_BINARY
...
# save the file
if GPU_ACCELERATION:
print("using GPU to accelerate video write")
video.write_videofile(output_path,
codec='h264_nvenc', # use NVENC for encoding
audio_codec='aac',
verbose=True)
else:
print("no GPU acceleration. expect longer times.")
video.write_videofile(output_path,
codec='libx264',
audio_codec='aac',
preset='fast',
ffmpeg_params=['-crf', '18'])
I spent a long time passing different values in ffmpeg_params
but to no avail. I also tried this using change_settings()
from moviepy.config
to change the FFMPEG_BINARY
. I read both the docs for ffmpeg and moviepy but I could not find the issue with my code. I also tested using ffmpeg directly in PowerShell using the following command and it worked fine:
ffmpeg -i input.mp4 -c:v h264_nvenc -preset fast -b:v 1M -c:a aac output.mp4
I also ran ffprobe on my corrupted output mp4 and couldn't see any issues with it from the meta data:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\path\to\final.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf61.1.100
Duration: 00:00:59.50, start: 0.000000, bitrate: 4011 kb/s
Stream #0:0[0x1](und): Video: h264 (High 4:4:4 Predictive) (avc1 / 0x31637661), gbrp(pc, gbr/unknown/unknown, progressive), 606x1080 [SAR 1:1 DAR 101:180], 3870 kb/s, 60 fps, 60 tbr, 15360 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
encoder : Lavc61.3.100 h264_nvenc
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 127 kb/s (default)
Metadata:
handler_name : SoundHandler
vendor_id : [0][0][0][0]
I'm considering just doing the video processing directly with ffmpeg using a PowerShell script but if I can somehow get my Python code to work with GPU acceleration, I'd prefer that. Any help is appreciated.
The moviepy output's video stream has High 4:4:4 Predictive
profile. This is not widely supported in players. The command line option -pix_fmt yuv420p
should be added.