pandora_render/ffmpeg.py
2017-09-06 14:48:37 +02:00

111 lines
2.8 KiB
Python
Executable file

#!/usr/bin/python3
import math
import json
import os
import subprocess
import sys
import ox
def run(cmd):
#print(' '.join('"%s"' % c for c in cmd))
subprocess.call(cmd)
edit_json = sys.argv[1]
edit = json.load(open(edit_json))
render = './cache'
output = os.path.splitext(edit_json)[0] + '.mp4'
height = 480
aspect = 16/9
width = int(height * aspect)
width -= width % 2
if not os.path.exists(render):
os.makedirs(render)
files = []
edit_duration = 0
subtitles = []
position = 0
for clip in edit:
out = render + '/%s_%0.3f-%0.3f.ts' % (clip['oshash'], clip['in'], clip['out'])
edit_duration += (clip['out']-clip['in'])
files.append(out)
if os.path.exists(out):
duration = ox.avinfo(out)['duration']
if clip['subtitles']:
subtitles.append({
'in': position,
'out': position+duration,
'value': clip['subtitles']
})
position += duration
print(out, duration, (clip['out'] - clip['in']))
continue
clip_aspect = clip['resolution'][0] / clip['resolution'][1]
if clip_aspect < aspect:
x = width
y = int(x / clip_aspect)
y -= y % 2
else:
y = height
x = int(y * clip_aspect)
x -= x % 2
vf = 'scale=%s:%s' % (x, y)
if x != width:
vf += ',crop=%s:%s' % (width, height) # crop center
elif y != height:
offset = int(((y - height) / 3))
vf += ',crop=w=%s:h=%s:x=0:y=%s' % (width, height, offset)
options = [
'-map_metadata', '-1',
'-vf', vf,
'-aspect', str(aspect),
'-c:v', 'libx264',
'-b:v', '2M',
'-preset:v', 'medium', '-profile:v', 'high', '-level:v', '4.0',
'-map', '0:0,0:0', '-map', '0:1,0:1',
'-r', '25',
'-c:a', 'aac',
'-ar', '48000',
'-ac', '2',
'-b:a', '192k',
]
clip_duration = math.ceil((clip['out'] - clip['in']) / (1/25)) * 1/25
cmd = [
'ffmpeg',
'-nostats', '-loglevel', 'error',
'-ss', str(clip['in']),
'-i', clip['path']
] + options + [
'-t', str(clip_duration),
out
]
run(cmd)
duration = ox.avinfo(out)['duration']
if clip['subtitles']:
subtitles.append({
'in': position,
'out': position+duration,
'value': clip['subtitles']
})
position += duration
print(out, duration, (clip['out'] - clip['in']))
txt = output + '.txt'
with open(txt, 'w') as fd:
fd.write('file ' + '\nfile '.join(files))
cmd = ['ffmpeg', '-y', '-f', 'concat', '-safe', '0', '-i', txt, '-c', 'copy', output]
run(cmd)
os.unlink(txt)
srt = output.replace('.mp4', '.srt')
with open(srt, 'wb') as fd:
fd.write(ox.srt.encode(subtitles))
duration = ox.avinfo(output)['duration']
print('file is %d, edit should be %d' % (duration, edit_duration))