Skip to content

Instantly share code, notes, and snippets.

@nkrabben
Last active April 8, 2019 14:24
Show Gist options
  • Save nkrabben/9576531b16787ee23c5cb38765b1d3c9 to your computer and use it in GitHub Desktop.
Save nkrabben/9576531b16787ee23c5cb38765b1d3c9 to your computer and use it in GitHub Desktop.
PAL/NTSC aware v210/MOV to FFV1/MKV recipe
#!/usr/bin/env/python
import os
import argparse
import subprocess
import multiprocessing
### For extra utitily when running this script remotely
# nohup transcode.py -d directory/of/mov -e mov -o directory/of/future/mkv &
# The & puts the job in the background
# The nohup autologs ffmpeg output to a nohup.out file and keeps the process alive even when the ssh session stops
# Turn into command line script
def _make_parser():
parser = argparse.ArgumentParser()
parser.description = "survey designated folder and child folders for files by extensions"
parser.add_argument("-d", "--directory",
help = "path of directory to survey",
required = True
)
parser.add_argument("-e", "--extension",
help = "type of extension to find",
required = True
)
parser.add_argument("-o", "--output",
help = "directory to store stuff",
required = True
)
return parser
# Create ffmpeg recipe based on height of video
def get_transcode_video_cmd(fn, height, output):
ffv1_command = [
'ffmpeg',
'-vsync', '0',
'-i', fn,
'-map', '0',
'-dn',
'-c:v', 'ffv1',
'-level', '3',
'-coder', '1',
'-context', '1',
'-g', '1',
'-slicecrc', '1',
'-slices', '24',
'-c:a', 'flac',
]
if height == '486':
ffv1_command += [
'-field_order', 'bt',
'-vf', 'setfield=bff,setdar=4/3',
'-color_primaries', 'smpte170m',
'-color_range', 'tv',
'-color_trc', 'bt709',
'-colorspace', 'smpte170m',
]
if height == '576':
ffv1_command += [
'-field_order', 'tb',
'-vf', 'setfield=tff,setdar=4/3',
'-color_primaries', 'bt470bg',
'-color_range', 'tv',
'-color_trc', 'bt709',
'-colorspace', 'bt470bg',
]
ffv1_command += [os.path.join(output, os.path.splitext(os.path.basename(fn))[0] + '.mkv',)]
return ffv1_command
# function to run the ffmpeg command
def work(cmd):
subprocess.check_call(cmd)
return
# This is where the script actually starts
def main():
# Get the arguments entered on the command line
args = _make_parser().parse_args()
# Create a list to hold a whole bunch of transcode commands
queue = []
# Generate a command for every file in a directory that matches the extension.
for dirpath, dirnames, filenames in os.walk(args.directory):
for filename in [f for f in filenames if f.endswith(args.extension)]:
# Make sure to use full path so we don't deal with working directory hijinks
full_path = os.path.join(dirpath, filename)
# Run MediaInfo to check height of video (and so NTSCness or PALness)
# Might be good to use pymediainfo in the future, but .rstrip().decode('UTF-8') works well enough to get the data we want
height = subprocess.check_output(
['mediainfo', '--Language=raw', '--Full',
"--Inform=Video;%Height%", full_path]).rstrip().decode('UTF-8')
# Use the input file name, height, and output path to generate an ffmpeg command, and then append that line to the list
queue.append(get_transcode_video_cmd(full_path, height, args.output))
# Quick sanity check for fun
print(queue)
# Use multiprocess to manage the queue of transcode work.
# It will take one command from the list at-a-time, run the command, and on completion take the next one
# ffmpeg already know how to parallize work well, so it's probably not useful to use processes= >1
pool = multiprocessing.Pool(processes=1)
r = pool.map_async(work, queue)
r.wait()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment