#!/usr/bin/python3 from argparse import ArgumentParser from glob import glob import json import os import shutil import subprocess import sys cleanup = True def get_videoduration(video): cmd = [ 'ffprobe', '-show_format', '-show_chapters', '-show_streams', '-print_format', 'json', '-i', video ] p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stdin = p.communicate() data = json.loads(stdout.decode()) duration = float([s for s in data['streams'] if 'width' in s][0]['duration']) - 70/60 return '%0.3f' % duration def is_new(xml, mp4): if not os.path.exists(mp4): return True vtime = os.path.getmtime(mp4) xtime = max( os.path.getmtime(xml), os.path.getmtime('text.html'), os.path.getmtime('DRONES.json'), os.path.getmtime('VOCALS.json'), os.path.getmtime('encode.py'), ) return vtime < xtime def encode(xml, force=False, prefix='.'): item_json = xml.replace('.xml', '.json') audio_xml = xml.replace('.xml', '.audio.xml') vocals_xml = xml.replace('.xml', '.vocals.xml') mp4 = xml.replace('.xml', '.mp4') mp4_480p = mp4.replace('.mp4', '.480p.mp4') video = mp4 + '.v.mov' amix = mp4 + '.amix.mp4' audio = mp4 + '.wav' vocals = mp4 + '.vocals.wav' silence = 'silence_mono.wav' left = video + '_left.wav' right = video + '_right.wav' public_mp4 = os.path.join(prefix, 'public', mp4.split('/')[-1][0].lower() + mp4.split('/')[-2] + '.1080p.mp4') public_mp4_480p = public_mp4.replace('.1080p.mp4', '.480p.mp4') gongs = 'performance' in prefix gongs_wav = mp4.replace('.mp4', '.gongs.wav') gongs_left = mp4.replace('.mp4', '.gongs.right.wav') gongs_right = mp4.replace('.mp4', '.gongs.left.wav') force = True if force or is_new(xml, public_mp4): print(public_mp4) cmd = [ 'qmelt', xml, '-consumer', 'avformat:' + video, 'vcodec=libx264', 'acodec=pcm_s16le' ] if is_new(xml, video): subprocess.call(cmd) duration = get_videoduration(video) cmd = [ 'ffmpeg', '-y', '-i', video, '-map_channel', '0.1.0', left, '-map_channel', '0.1.1', right, ] subprocess.call(cmd) if gongs: cmd = [ 'ffmpeg', '-y', '-i', gongs_wav, '-map_channel', '0.0.0', gongs_left, '-map_channel', '0.0.1', gongs_right, ] subprocess.call(cmd) cmd = [ 'qmelt', vocals_xml, '-consumer', 'avformat:' + vocals, 'acodec=pcm_s16le', 'ac=1' ] if is_new(xml, vocals): subprocess.call(cmd) #for wav in (left, right, vocals): # cmd = ['normalize-audio', wav] # subprocess.call(cmd) front_left = left front_right = left front_center = vocals lfe = silence back_left = vocals back_right = vocals if gongs: back_left = gongs_left back_right = gongs_right cmd = [ 'ffmpeg', '-y', '-i', front_left, # FL '-i', front_right, # FR '-i', front_center, # FC '-i', lfe, # LFE '-i', back_left, # BL '-i', back_right, # BR '-filter_complex', '[0:0][1:0][2:0][3:0][4:0][5:0] amerge=inputs=6[aout]', '-map', "[aout]", '-strict', '-2', '-c:a', 'aac', amix ] subprocess.call(cmd) if cleanup: os.unlink(left) os.unlink(right) os.unlink(vocals) if gongs: os.unlink(gongs_left) os.unlink(gongs_right) cmd = [ 'ffmpeg', '-y', '-i', video, '-i', amix, '-t', duration, '-c:a', 'copy', '-c:v', 'copy', '-map', '0:v:0', '-map', '1:a:0', '-movflags', '+faststart', mp4 ] subprocess.call(cmd) if cleanup: os.unlink(video) os.unlink(amix) if is_new(mp4, public_mp4_480p): cmd = [ 'ffmpeg', '-y', '-i', mp4, '-c:a', 'copy', '-vf', 'scale=854:480', '-c:v', 'libx264', '-preset', 'medium', '-b:v', '750k', '-profile:v', 'high', '-movflags', '+faststart', mp4_480p ] subprocess.call(cmd) shutil.move(mp4_480p, public_mp4_480p) shutil.move(mp4, public_mp4) cmd = [ './subtitles.py', '--prefix', prefix, item_json ] subprocess.call(cmd) else: print('skip', public_mp4) def encode_all(prefix): for xml in sorted(glob(os.path.join(prefix, 'output/*/*.xml'))): parts = xml.split('.') if len(parts) > 2 and parts[-2] in ( 'audio', 'drones', 'music', 'source', 'vocals', ): continue encode(xml, prefix=prefix) if __name__ == '__main__': usage = "usage: %(prog)s [options] xml" parser = ArgumentParser(usage=usage) parser.add_argument('-p', '--prefix', dest='prefix', help='version prefix', default='.') parser.add_argument('files', metavar='path', type=str, nargs='*', help='xml files') opts = parser.parse_args() if opts.files: for xml in opts.files: encode(xml, True, prefix=opts.prefix) else: encode_all(prefix=opts.prefix)