Ffmpeg wrapper for transcoding between video formats with an emphasis on maintaining quality and color depth in video production pipelines
Project description
vtcff
🚧 This project is a draft and is not intended to be used by anyone.
vtcff
is a library for transcoding between video formats with an emphasis on
maintaining quality and color depth in video production pipelines. In studio
tasks, video seconds take up gigabytes and quality compromises are least
desirable.
vtcff
tends to maximize quality, sacrificing speed and disk space.
vtcff
is actually a wrapper for ffmpeg
– the least intuitive video tool ever
created.
Install
$ pip3 install vtcff
This command will install the package, but not ffmpeg itself.
other options
Install pre-release from GitHub:
$ pip3 install git+https://github.com/rtmigo/vtcff_py@staging#egg=vtcff
Basic example
import subprocess
from vtcff import FfmpegCommand, Scale, Transpose, Hevc
cmd = FfmpegCommand()
cmd.src_file = '/path/to/source.mov'
cmd.dst_file = '/path/to/target.mov'
# set set some filters
cmd.scale = Scale(1920, 1080)
cmd.transpose = Transpose.CLOCKWISE
# set compression format
cmd.dst_codec_video = Hevc(mbps=100)
# run command
subprocess.check_call(list(cmd))
Getting the generated arguments
import subprocess, os
from vtcff import FfmpegCommand, Prores
cmd = FfmpegCommand()
cmd.src_file = 'source.mov'
cmd.dst_file = 'target.mov'
cmd.dst_codec_video = Prores()
print(str(cmd))
# ffmpeg -i source.mov -codec:v prores_ks target.mov
print(list(cmd))
# ['ffmpeg', '-i', 'source.mov', '-codec:v', 'prores_ks', 'target.mov']
# running in different ways:
os.system(str(cmd))
subprocess.run(list(cmd))
Custom arguments
The object allows you to manually specify ffmpeg arguments. Arguments given in this way take precedence over arguments generated by the object.
from vtcff import FfmpegCommand
cmd = FfmpegCommand()
# set arguments as string
cmd.custom.video.string = "-codec:v libx265"
cmd.custom.video.string += "-x265-params lossless=1"
# or as list
cmd.custom.video.list = ["-codec:v", "libx265"]
cmd.custom.video.list.extend(["-x265-params", "lossless=1"])
The cmd.custom
contains four fields, that can be modified independently.
Arguments to be inserted before -i source
:
custom.before_i
Arguments to be inserted after -i source
:
custom.after_i
custom.video
custom.audio
zscale vs scale
ffmpeg
has two video filters for color and frame size conversions:
scale
(libswscale) is more versatilezscale
(zimg) gives a more predictable quality
By default, vtcff
uses zscale
. Sometimes it may lead to error "no path
between colorspaces". If other methods do not help, you can simply replace zscale
with scale
.
cmd.use_zscale == True
meanszscale
is usedcmd.use_zscale == False
meansscale
is used
from vtcff import FfmpegCommand, Scale
cmd = FfmpegCommand()
assert cmd.use_zscale == True # by default, it's 'zscale' (zimg)
cmd.use_zscale = False # switching to 'scale' (libswscale)
# properties affected:
cmd.scale = Scale(1920, 1080)
cmd.src_color_space = 'bt709'
cmd.dst_color_space = 'bt2020ncl'
cmd.src_range_full = True
cmd.dst_range_full = False
use_zscale=True
, means that zimg will be used for conversions
explicitly set by object properties. This is good because these conversions
will be of high quality.
However, implicit conversions may also be required. For example, before
processing 16-bit PNG with zscale
, we need to convert the pixel format from
rgba64be
to gbrap16le
🤪. Ffmpeg will do it automatically with libswscale
regardless of the use_zscale
property.
Crop and scale
from vtcff import FfmpegCommand, Scale, Crop
# crop 10 pixels, then scale
a = FfmpegCommand()
a.crop = Crop(left=10)
a.scale = Scale(1920, 1080)
# scale, then crop 10 pixels
b = FfmpegCommand()
b.scale = Scale(1920, 1080)
b.crop = Crop(left=10)
Scale proportionally
from vtcff import FfmpegCommand, Scale
cmd = FfmpegCommand()
# set height to 1080, automatically compute width
cmd.scale = Scale(-1, 1080)
# set height to 1080, select the width as the closest factor
# of two to the proportional size
cmd.scale = Scale(-2, 1080)
Change color range
from vtcff import FfmpegCommand
cmd = FfmpegCommand()
# Full/Data/PC range to Limited/Video/TV
cmd.src_range_full = True
cmd.dst_range_full = False
# rec.709 to rec.2020
cmd.src_color_space = 'bt709'
cmd.dst_color_space = 'bt2020ncl'
Target formats
Encoding to Apple ProRes
from vtcff import FfmpegCommand, Prores, ProresProfile
cmd = FfmpegCommand()
# by default it will encode to ProRes 4:2:2
cmd.dst_codec_video = Prores()
# encode to ProRes 4:2:2 HQ instead
cmd.dst_codec_video = Prores(profile=ProresProfile.HQ)
Encoding to HEVC (H.265)
from vtcff import FfmpegCommand, Hevc, VcPreset
cmd = FfmpegCommand()
# ideal quality
cmd.dst_codec_video = Hevc(lossless=True)
# best for bitrate quality
cmd.dst_codec_video = Hevc(near_lossless=True, mbps=100)
# default quality
cmd.dst_codec_video = Hevc(mbps=100)
# all modes can be tweaked with optional speed presets:
cmd.dst_codec_video = Hevc(mbps=100,
preset=VcPreset.N7_SLOW)
By default, the near_lossless
is set to slowest possible
VcPreset.N10_PLACEBO
, because we are trying to maximize quality. You may
want to choose a faster preset so that the result appears within a
lifetime.
By default, the lossless
is set to fastest possible
VcPreset.N1_ULTRAFAST
, because we are not losing any quality here. The
resulting size will be roughly comparable to ProRes HQ/XQ and the encoding time
is reasonable.
Copying streams
The media streams can be copied without re-encoding and without quality loss.
However, there may be some loss of metadata – for example, information about color ranges and color spaces.
from vtcff import FfmpegCommand, VideoCopy, NoAudio
cmd = FfmpegCommand()
# changing container from mp4 to mov
cmd.src_file = "source.mp4"
cmd.dst_file = "source.mov"
# keeping video, removing audio
cmd.dst_codec_video = VideoCopy()
cmd.dst_codec_audio = NoAudio()
Images to videos
Converting timelapses or CGI frame sequences to ProRes video file.
import subprocess
from vtcff import FfmpegCommand, Prores, ProresProfile
cmd = FfmpegCommand()
# input directory will be automatically transformed
# to a pattern like '/my/dir_with_frames/img_%04.png'
cmd.src_file = '/my/dir_with_frames'
cmd.src_fps = 29.97
cmd.dst_file = '/videos/timelapse.mov'
cmd.dst_codec_video = Prores(profile=ProresProfile.HQ)
# images usually have Full/Data/PC color range,
# but most NLEs assume that videos have Limited/Video/TV range
cmd.src_range_full = True
cmd.dst_range_full = False
# we will treat sRGB like Rec.709,
# although it's a little sad
cmd.src_color_space = 'bt709'
cmd.dst_color_space = 'bt709'
# run command
subprocess.check_call(list(cmd))
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.