Skip to content

The 'pixel_format' option in moviepy.video.VideoClip.VideoCip.write_videofile() is ignored when video_codec is set to 'libx264' #2539

@kevinmagnopus

Description

@kevinmagnopus

The 'pixel_format' option in moviepy.video.VideoClip.VideoCip.write_videofile() is ignored when video_codec is set to 'libx264'. This can be seen on line 162 of moviepy/video/io/ffmpeg_writer.py in hash 7ffa4f0 on main.

Handling all potential translations would require a static mapping of all ffmpeg modes to libx264 supported modes, which is outside the scope of this issue. Given that a professional user would likely already know to specify a yuv format, a better solution would be to replace any format that is not a yuv derivative with the default and pass through specified yuv formats unchanged. As well, h264 does not support an alpha channel, so no need for yuva. A proposed patch would be:

diff --git a/moviepy/video/io/ffmpeg_writer.py b/moviepy/video/io/ffmpeg_writer.py
index 71c301c..7c528dd 100644
--- a/moviepy/video/io/ffmpeg_writer.py
+++ b/moviepy/video/io/ffmpeg_writer.py
@@ -159,7 +159,10 @@ class FFMPEG_VideoWriter:
             and (size[0] % 2 == 0)
             and (size[1] % 2 == 0)
         ):
-            cmd.extend(["-pix_fmt", "yuva420p"])
+            if pixel_format is None or not pixel_format.startswith('yuv'):
+                cmd.extend(["-pix_fmt", "yuv420p"])
+            else:
+                cmd.extend(["-pix_fmt", pixel_format])
         else:
             # For all other codecs, we use the pixel format specified by the user
             # or the default one.

Expected Behavior

The 'pixel_format' option should be honored when set, within the limitations of the codec.

Actual Behavior

The pixel format is always set to 'yuv420p'

Steps and code to Reproduce the Problem

import numpy as np
from PIL import Image
from moviepy import ImageClip
import ffmpeg
import os

image = Image.new('RGB', (512, 512), color=(255, 0, 0))
image_array = np.array(image)
clip = ImageClip(image_array).with_fps(24, change_duration=False).with_duration(5)
clip.write_videofile(filename='x264_yuv444_test.mp4', codec='libx264', pixel_format='yuv444p')
probe = ffmpeg.probe('x264_yuv444_test.mp4')
format = probe['streams'][0]['pix_fmt']
print(f'Pixel format used in the generated video: {format}')
os.remove('x264_yuv444_test.mp4')

Note that whatever you set 'pixel_format' to, it will always result in a 'yuv420' encoding.

Used medias

N/A

Specifications

  • Python Version: 3.12.11
  • MoviePy Version: 2.2.1
  • Platform Name: OSX
  • Platform Version: 15.6.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIssues that report (apparent) bugs.videoRelated to VideoClip and related classes, or handling of video in general.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions