I am trying convert from HDR to SDR by using the following ffmpeg command, which works
ffmpeg -i input.mov -vf zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p -c:v libx264 -crf 0 -preset ultrafast -tune fastdecode output.mp4
However, I have trouble converting this in ffmpeg-python format. Could you give me guidance on how to deal with semicolons, equals and weird = = cases?
ffmpeg.input("input.mov", r=fps).filter('zscale', t='linear:npl').filter('format', 'gbrpf32le') ...
The conversion is quite straightforward:
ffmpeg.input('input.mov')\
.video.filter('zscale', t='linear', npl=100)\
.filter('format', pix_fmts='gbrpf32le')\
.filter('zscale', p='bt709')\
.filter('tonemap', tonemap='hable', desat=0)\
.filter('zscale', t='bt709', m='bt709', r='tv')\
.filter('format', pix_fmts='yuv420p')\
.output('output.mp4', vcodec='libx264', crf=0, preset='ultrafast', tune='fastdecode')\
.run()
ffmpeg.input(...)
begins with input file name followed by input arguments..video
followed by .filter(...).filter(...).filter(...)
applies chain of video filters.filter(...)
begins with filter name followed by filter parameters as arguments.The only caveat is the format
filter.
The parameter name of format
filter is pix_fmts
(we usually skip it).
One way for getting the parameter name is using FFmpeg help (in command line):
ffmpeg -h filter=format
Output:
Filter format
Convert the input video to one of the specified pixel formats.
Inputs:
#0: default (video)
Outputs:
#0: default (video)
(no)format AVOptions:
pix_fmts <string> ..FV....... A '|'-separated list of pixel formats
Here we can see that the parameter name is pix_fmts
.
When using ffmpeg-python, it is recommended to add .overwrite_output()
(equivalent to -y
argument).
For testing it is recommended to add .global_args('-report')
for creating a log file (remove .global_args('-report')
after finish testing).
ffmpeg.input('input.mov')\
.video.filter('zscale', t='linear', npl=100)\
.filter('format', pix_fmts='gbrpf32le')\
.filter('zscale', p='bt709')\
.filter('tonemap', tonemap='hable', desat=0)\
.filter('zscale', t='bt709', m='bt709', r='tv')\
.filter('format', pix_fmts='yuv420p')\
.output('output.mp4', vcodec='libx264', crf=0, preset='ultrafast', tune='fastdecode')\
.global_args('-report').overwrite_output().run()
The log shows us the actual FFmpeg command:
ffmpeg -i input.mov -filter_complex "[0:v]zscale=npl=100:t=linear[s0];[s0]format=pix_fmts=gbrpf32le[s1];[s1]zscale=p=bt709[s2];[s2]tonemap=desat=0:tonemap=hable[s3];[s3]zscale=m=bt709:r=tv:t=bt709[s4];[s4]format=pix_fmts=yuv420p[s5]" -map "[s5]" -crf 0 -preset ultrafast -tune fastdecode -vcodec libx264 output.mp4 -report -y
As you can see, ffmpeg-python uses -filter_complex
instead of -vf
, and uses temporary naming as [s0]
, [s1]
, [s2]
...
The result is equivalent to your original command.