Skip to content

Instantly share code, notes, and snippets.

@GitRay
Last active December 14, 2015 06:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GitRay/5044601 to your computer and use it in GitHub Desktop.
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…
#!/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