Last active
December 14, 2015 06:39
-
-
Save GitRay/5044601 to your computer and use it in GitHub Desktop.
Python script to convert any video file into a number of other kind of files: DIVX-compatible file no more than 640x480 in size, MP4 that works with the original iPhone/iPod no more than 480x320 in size, and MP4 that works with the Kindle Fire HD no more than 1280x800 in size. You can hardcode subtitles if you want. Limitations: ffmpeg v1 is req…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/local/bin/python | |
# convert any video file recognized by ffmpeg to divx | |
import subprocess, json, argparse, tempfile, os | |
import pprint | |
# Check arguments | |
parser = argparse.ArgumentParser(description="Convert any video file recognized by ffmpeg into a legacy DIVX") | |
parser.add_argument('--iphone',help='Convert to iPhone-compatible mp4 instead of Divx',action='store_true') | |
parser.add_argument('--kindlefirehd', help='Convert to Kindle Fire compatible mp4 instead of Divx', action='store_true') | |
parser.add_argument('--subtitles', help='Name of subtitles file to burn into video.') | |
parser.add_argument('input_file') | |
parser.add_argument('output_file') | |
args = parser.parse_args() | |
pprint.pprint(args) | |
ffprobe_loc = '/usr/local/bin/ffprobe1' | |
ffmpeg_loc = '/usr/local/bin/ffmpeg1' | |
#file_to_convert = '/Volumes/Downloads/A.Hard.Days.Night.1964.720p.BluRay.x264-CiNEFiLE/a.hard.days.night.1964.720p.bluray.x264.sample-cinefile.mkv' | |
# for now, make some assumptions about desired divx | |
#ok_audio_formats = ['mp3', 'aac'] | |
mp4_video_args = ['-c:v', 'libx264', '-preset:v', 'slow', '-crf:v', '23', '-profile:v', 'baseline'] | |
mp4_audio_args = ['-c:a', 'libfdk_aac', '-ac', '2', '-vbr', '3'] | |
if args.iphone == True: | |
max_width = 480 | |
max_height = 320 | |
video_args = mp4_video_args | |
audio_args = mp4_audio_args | |
elif args.kindlefirehd == True: | |
max_width = 1280 | |
max_height = 800 | |
video_args = mp4_video_args | |
audio_args = mp4_audio_args | |
else: | |
max_width = 640 | |
max_height = 480 | |
video_args = ['-c:v', 'mpeg4', '-q:v', '4', '-tag:v', 'DIVX' ] | |
audio_args = ['-c:a', 'libmp3lame', '-q:a', '5', '-ac', '2', '-ar', '44100'] | |
if args.subtitles != None: | |
# get a temp location for the subtitle file | |
sub_file = tempfile.NamedTemporaryFile(delete=False,suffix='.ass') | |
sub_filename = sub_file.name | |
sub_file.close() | |
subprocess.call([ffmpeg_loc,'-y', '-i', args.subtitles, sub_filename]) | |
video_args = video_args + ['-vf:v', 'ass='+sub_filename] | |
# get current info | |
file_info = subprocess.check_output([ffprobe_loc,'-v','quiet', '-print_format', 'json', '-show_format', '-show_streams' ,args.input_file]) | |
j_file_info = json.loads(file_info) | |
# for now, just force the audio to mp3 | |
video_exists = False | |
audio_exists = False | |
for this_stream in j_file_info['streams']: | |
print this_stream['codec_type'] | |
print this_stream['codec_name'] | |
if this_stream['codec_type'] == 'audio': | |
if 'tags' in this_stream and 'language' in this_stream['tags'] and this_stream['tags']['language'] == 'eng': | |
if audio_exists: | |
print 'error: more than one English audio stream not supported' | |
exit() | |
audio_exists = True | |
audio_index = this_stream['index'] | |
print 'english audio stream detected' | |
if this_stream['codec_type'] == 'video': | |
if video_exists: | |
print 'error: more than one video stream not supported' | |
exit() | |
video_exists = True | |
video_index = this_stream['index'] | |
print 'video stream detected' | |
# first limit the video size, if necessary | |
width_ratio = float(max_width) / float(this_stream['width']) | |
height_ratio = float(max_height) / float(this_stream['height']) | |
if width_ratio < 1 or height_ratio < 1: | |
if width_ratio >= height_ratio: | |
# limit based on height | |
print 'limiting height of %s to %s' % (this_stream['height'], max_height) | |
new_width = this_stream['width'] * height_ratio | |
new_height = this_stream['height'] * height_ratio | |
else: | |
# limit based on width | |
print 'limiting width of %s to %s' % (this_stream['width'], max_width) | |
new_width = this_stream['width'] * width_ratio | |
new_height = this_stream['height'] * width_ratio | |
print 'new width: %s new height: %s' % (new_width, new_height) | |
new_width = int(16 * ((new_width + 8) // 16)) | |
new_height = int(16 * ((new_height + 8) // 16)) | |
print 'rounded to closest 16: %sx%s' % (new_width, new_height) | |
video_args = video_args + ['-s','%sx%s' % (new_width, new_height)] | |
# if the audio and video streams are known, do the mapping. Otherwise just leave it to fate | |
if video_exists and audio_exists: | |
mapping_args = ['-map','0:%i' % video_index,'-map','0:%i' % audio_index] | |
else: | |
mapping_args = [] | |
pprint.pprint(mapping_args) | |
pprint.pprint(audio_args) | |
pprint.pprint(video_args) | |
subprocess.call([ffmpeg_loc,'-i', args.input_file] + mapping_args + video_args + audio_args + [args.output_file]) | |
if args.subtitles != None: | |
os.remove(sub_filename) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment