#!/usr/bin/env python3
"""
ffmpeg methods to convert, rescale, and center crop a given video
"""
"""
This file is part of quat.
quat is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
quat is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with quat. If not, see <http://www.gnu.org/licenses/>.
Author: Steve Göring
"""
import os
import sys
import argparse
import glob
import shutil
from quat.log import *
[docs]def check_ffmpeg():
"""
checks if ffmpeg is installed in the system
Returns
-------
true if ffmpeg can be used, otherwise an Exception is thrown
"""
if shutil.which("ffmpeg") is None:
raise Exception("ffmpeg not found")
return True
def __run_multi_line_cmd(cmd):
"""
run a command that consists of several lines that are combined again
Parameters
----------
cmd : str
command to run, e.g. cmd="ls \n -la" will run "ls -la"
TODO: move to utils/system?
Returns
-------
in case of error an error is thrown
"""
# remove multiple spaces in cmd
cmd = " ".join(cmd.split())
ret = os.system(cmd)
if ret != 0:
raise Exception(f"error in running command {cmd}")
[docs]def crop_video(input_file, tmp_folder, ccheight=360):
"""
create a center cropped version of a video
Parameters
----------
input_file : str
input video file
tmp_folder : str
folder where center cropped version is store, this version gets "_cropped.mkv" as suffix
ccheight : int
default=360, height of the center crop
Returns
-------
filename and path of generated center cropped video
"""
check_ffmpeg()
os.makedirs(tmp_folder, exist_ok=True)
output_file = os.path.join(
tmp_folder, os.path.splitext(os.path.basename(input_file))[0] + "_cropped.mkv"
)
cmd = f"""
ffmpeg -nostdin -loglevel quiet
-y
-i {input_file}
-filter:v crop=ccheight*in_w/in_h:ccheight
-c:v ffvhuff -an
{output_file} 2>/dev/null"""
lInfo(f"crop video: {input_file} to {output_file}")
__run_multi_line_cmd(cmd)
return output_file
[docs]def rescale_video(input_file, tmp_folder, height=360):
"""
rescales a given video
"""
check_ffmpeg()
os.makedirs(tmp_folder, exist_ok=True)
output_file = os.path.join(
tmp_folder, os.path.splitext(os.path.basename(input_file))[0] + "_rescaled.mkv"
)
cmd = f"""
ffmpeg -nostdin -loglevel quiet
-y
-i {input_file}
-filter:v scale=-2:{height}
-c:v ffvhuff -an
{output_file} 2>/dev/null"""
lInfo(f"rescale video: {input_file} to {output_file}")
__run_multi_line_cmd(cmd)
return output_file
[docs]def convert_to_avpvs(
input_file, tmp_folder, framerate="60/1", width=3840, height=-2, pix_fmt="yuv422p10le"
):
"""
converts a video to a unified resolution, framerate and pixel format,
can be used, e.g. in case of a full reference model, to unify a distorted video with the source video
Parameters
----------
input_file : str
input video file
tmp_folder : str
folder where converted video is stored
framerate : str
framerate of final video
width : int
width of final video
height : int
height of final video, use -2 to automatically determine height based on width
pix_fmt : str
pixel format of final video
Returns
-------
filename and path of the converted video
"""
check_ffmpeg()
os.makedirs(tmp_folder, exist_ok=True)
output_file = os.path.join(
tmp_folder, os.path.splitext(os.path.basename(input_file))[0] + ".mkv"
)
cmd = f"""
ffmpeg -nostdin -loglevel quiet
-y
-i {input_file}
-filter:v scale={width}:{height},fps={framerate},setsar=1/1
-c:v ffvhuff
-an
-pix_fmt {target_pix_fmt}
{output_file} 2>/dev/null"""
lInfo(f"convert to avpvs: {input_file} to {output_file}")
__run_multi_line_cmd(cmd)
return output_file
[docs]def convert_to_avpvs_and_crop(
input_file,
tmp_folder,
framerate="60/1",
width=3840,
height=-2,
pix_fmt="yuv422p10le",
ccheight=360,
):
"""
converts a video to a unified resolution, framerate and pixel format and
performs afterwards a center cropping
can be used, e.g. in case of a full reference model, to unify a distorted video with the source video
Parameters
----------
input_file : str
input video file
tmp_folder : str
folder where converted video is stored
framerate : str
framerate of final video
width : int
width of final video
height : int
height of final video, use -2 to automatically determine height based on width
pix_fmt : str
pixel format of final video
ccheight : int
center crop height of final crop
Returns
-------
filename and path of the converted and center cropped video
"""
check_ffmpeg()
lInfo(
f"avpvs + cropping generation with: {width}x{height}@{framerate}-{pix_fmt} using ccheight:{ccheight}"
)
os.makedirs(tmp_folder, exist_ok=True)
output_file = os.path.join(
tmp_folder, os.path.splitext(os.path.basename(input_file))[0] + ".mkv"
)
cmd = f"""
ffmpeg -nostdin -loglevel quiet -threads 4
-y
-i {input_file}
-filter:v scale={width}:{height},fps={framerate},setsar=1/1
-an
-pix_fmt {pix_fmt}
-strict -1
-f yuv4mpegpipe pipe:
|
ffmpeg -nostdin -loglevel quiet -threads 4
-y -f yuv4mpegpipe
-i pipe:
-filter:v crop={ccheight}*in_w/in_h:{ccheight}
-c:v ffvhuff
-an
{output_file} 2>/dev/null"""
lInfo(f"convert to cropped-avpvs: {input_file} to {output_file}")
__run_multi_line_cmd(cmd)
return output_file