5 Commits
v1.0 ... v2.0

View File

@ -6,6 +6,7 @@ import subprocess
import logging import logging
from os import listdir, remove from os import listdir, remove
def get_infos(file): def get_infos(file):
''' '''
Cette fonction extrait les informations du film à l'aide de ffprobe et les stocke Cette fonction extrait les informations du film à l'aide de ffprobe et les stocke
@ -49,8 +50,12 @@ def get_infos(file):
'index': a_stream['index'], 'index': a_stream['index'],
'channels': a_stream['channels'], 'channels': a_stream['channels'],
'channel_layout': a_stream['channel_layout'], 'channel_layout': a_stream['channel_layout'],
'language': a_stream['tags']['language'], 'language': a_stream['tags']['language']
'title': a_stream['tags']['title']} }
try:
a_stream_infos.update({'title': a_stream['tags']['title']})
except KeyError:
a_stream_infos.update({'title': 'No title'})
a_infos.append(a_stream_infos) a_infos.append(a_stream_infos)
s_infos = [] s_infos = []
for s_stream in full_s_infos['streams']: for s_stream in full_s_infos['streams']:
@ -63,10 +68,11 @@ def get_infos(file):
duration = float(duration['format']['duration']) duration = float(duration['format']['duration'])
hdr10_v_cmd = f'ffmpeg -loglevel panic -i {file} -c:v copy -vbsf hevc_mp4toannexb -f hevc - | hdr10plus_parser -o metadata.json --verify -' hdr10_v_cmd = f'ffmpeg -loglevel panic -i {file} -c:v copy -vbsf hevc_mp4toannexb -f hevc - | hdr10plus_parser -o metadata.json --verify -'
hdr10_v_raw = subprocess.getoutput(hdr10_v_cmd) hdr10_v_raw = subprocess.getoutput(hdr10_v_cmd)
# logging.debug(hdr10_v_raw)
if 'metadata detected' in hdr10_v_raw: if 'metadata detected' in hdr10_v_raw:
hdr10_cmd = f'ffmpeg -loglevel panic -i {file} -c:v copy -vbsf hevc_mp4toannexb -f hevc - | hdr10plus_parser -o /tmp/{file}_hdr10_metadata.json -' hdr10_cmd = f'ffmpeg -loglevel panic -i {file} -c:v copy -vbsf hevc_mp4toannexb -f hevc - | hdr10plus_parser -o /tmp/{file}_hdr10_metadata.json -'
v_infos.update({'hdr10': True, 'hdr10_metdata': f'/tmp/{file}_hdr10_metadata.json'}) hdr10_cmd_res = subprocess.getoutput(hdr10_cmd)
logging.debug(hdr10_cmd_res)
v_infos.update({'hdr10plus': True, 'hdr10plus_metadata': f'/tmp/{file}_hdr10_metadata.json'})
infos = {'duration': duration, 'video': v_infos, 'audio': a_infos, 'subtitles': s_infos} infos = {'duration': duration, 'video': v_infos, 'audio': a_infos, 'subtitles': s_infos}
logging.debug("Informations du film : \n" + json.dumps(infos, indent=True)) logging.debug("Informations du film : \n" + json.dumps(infos, indent=True))
return infos return infos
@ -91,7 +97,7 @@ def is_interlaced(file, infos):
except ZeroDivisionError: except ZeroDivisionError:
pct = 100 pct = 100
if pct > 10: if pct > 10:
logging.debug("Vidéo entrelacée à {pct}%") logging.debug(f"Vidéo entrelacée à {pct}%")
return True return True
else: else:
logging.debug("Vidéo non entrelacée") logging.debug("Vidéo non entrelacée")
@ -142,34 +148,40 @@ def stabilization(file):
def extract_subs(file, track, lang): def extract_subs(file, track, lang):
command = f'ffmpeg -loglevel error -i {file} -map 0:{track} -map_metadata -1 -vn -an -c:s copy -metadata language="{lang}" -y {file}_subtitle_{track}_{lang}.mkv' command = f'ffmpeg -loglevel error -i {file} -map 0:{track} -map_metadata -1 -vn -an -c:s copy -metadata language="{lang}" -y {file}_subtitle_{track}_{lang}.mkv'
logging.info(f"Extractio du sous-titre {track}, langue : {lang}...") logging.info(f"Extraction du sous-titre {track}, langue : {lang}...")
logging.debug(command) logging.debug(command)
result = subprocess.getoutput(command) result = subprocess.getoutput(command)
if result != "": if result != "":
logging.info(result) logging.error(result)
def convert_audio(file, track, volume_adj, channels, channel_layout, language, title): def convert_audio(file, track, volume_adj, channels, channel_layout, language, title):
bitrate = f'{64*channels}k'
if channel_layout == "5.1(side)": if channel_layout == "5.1(side)":
channel_layout = "5.1" channel_layout = "5.1"
codec = 'libopus' codec = 'libfdk_aac -vbr 5'
metadatas = f'-metadata language="{language}" -metadata title="{title}"' metadatas = f'-metadata language="{language}" -metadata title="{title}"'
command = f'ffmpeg -loglevel error -i {file} -map 0:{track} -map_metadata -1 -vn -sn -c:a {codec} -b:a {bitrate} -mapping_family 1 -filter:a volume={volume_adj},aformat=channel_layouts={channel_layout} {metadatas} -y {file}_audio_{track}_{language}.mka' command = f'ffmpeg -loglevel error -i {file} -map 0:{track} -map_metadata -1 -vn -sn -c:a {codec} -mapping_family 1 -filter:a volume={volume_adj},aformat=channel_layouts={channel_layout} {metadatas} -y {file}_audio_{track}_{language}.mka'
logging.debug(command) logging.debug(command)
result = subprocess.getoutput(command) result = subprocess.getoutput(command)
logging.info(result) if result != "":
logging.error(result)
def convert_video(file, infos, start, crop, crf): def convert_video(file, infos, start, crop, crf, animation, interlaced, vhs):
str_start = "{:05d}".format(start) str_start = "{:05d}".format(start)
output = f'{file}_video_t{str_start}.mkv' output = f'{file}_video_t{str_start}.mkv'
fmt = infos['video']['pix_fmt'] fmt = "yuv420p10le"
if fmt == "yuv420p":
fmt = "yuv420p10le"
track = infos['video']['index'] track = infos['video']['index']
codec = 'libx265 -preset slow' codec = 'libx265 -preset slower'
hdr = '' hdr = ''
if animation:
tune = "-tune animation"
else:
tune = ""
if interlaced:
crop = f"{crop},yadif"
if vhs:
crop = f"{crop},hqdn3d,unsharp=5:5:0.8:3:3:0.4"
if 'side_data_list' in infos['video'].keys(): if 'side_data_list' in infos['video'].keys():
try: try:
light_level = f"{infos['video']['side_data_list'][1]['max_content']},{infos['video']['side_data_list'][1]['max_average']}" light_level = f"{infos['video']['side_data_list'][1]['max_content']},{infos['video']['side_data_list'][1]['max_average']}"
@ -203,12 +215,13 @@ def convert_video(file, infos, start, crop, crf):
luminance = f'L\({max_luminance},{min_luminance}\)' luminance = f'L\({max_luminance},{min_luminance}\)'
master_display = green + blue + red + white_point + luminance master_display = green + blue + red + white_point + luminance
hdr = f'-x265-params hdr-opt=1:repeat-headers=1:colorprim={color_primaries}:transfer={color_transfer}:colormatrix={color_space}:master-display={master_display}:max-cll={light_level}' hdr = f'-x265-params hdr-opt=1:repeat-headers=1:colorprim={color_primaries}:transfer={color_transfer}:colormatrix={color_space}:master-display={master_display}:max-cll={light_level}'
except: except Exception as err:
logging.debug("Aucune information HDR") logging.debug(f"Aucune information HDR : {err}")
command = f'ffmpeg -loglevel error -i {file} -map 0:{track} -ss {start} -t 300 -an -sn -c:v {codec} {hdr} -crf {crf} -pix_fmt {fmt} -filter:v {crop} -y {output}' command = f'ffmpeg -loglevel error -i {file} -map 0:{track} -ss {start} -t 300 -an -sn -c:v {codec} {tune} {hdr} -crf {crf} -pix_fmt {fmt} -filter:v {crop} -y {output}'
logging.debug(command) logging.debug(command)
result = subprocess.getoutput(command) result = subprocess.getoutput(command)
logging.info(result) if result != "":
logging.error(result)
def create_mkv(filename): def create_mkv(filename):
@ -220,34 +233,19 @@ def create_mkv(filename):
json_data.append("--no-track-tags") json_data.append("--no-track-tags")
json_data.append("--no-global-tags") json_data.append("--no-global-tags")
json_data.append("--no-chapters") json_data.append("--no-chapters")
if not "t00000" in file: if "t00000" not in file:
json_data.append("+") json_data.append("+")
json_data.append("(") json_data.append("(")
json_data.append(file) json_data.append(file)
json_data.append(")") json_data.append(")")
for file in listdir(): for file in listdir():
if f"{filename}_audio" in file: if f"{filename}_audio" in file:
lang = file[-7:][:-4]
json_data.append("--no-track-tags") json_data.append("--no-track-tags")
json_data.append("--no-global-tags") json_data.append("--no-global-tags")
json_data.append("--no-chapters") json_data.append("--no-chapters")
if "fra" in file: json_data.append("--language")
json_data.append("--language") json_data.append(f"0:{lang}")
json_data.append("0:fr")
elif "eng" in file:
json_data.append("--language")
json_data.append("0:en")
elif "deu" in file:
json_data.append("--language")
json_data.append("0:de")
elif "nld" in file:
json_data.append("--language")
json_data.append("0:nl")
elif "spa" in file:
json_data.append("--language")
json_data.append("0:es")
elif "ita" in file:
json_data.append("--language")
json_data.append("0:it")
json_data.append("(") json_data.append("(")
json_data.append(file) json_data.append(file)
json_data.append(")") json_data.append(")")
@ -256,24 +254,9 @@ def create_mkv(filename):
json_data.append("--no-track-tags") json_data.append("--no-track-tags")
json_data.append("--no-global-tags") json_data.append("--no-global-tags")
json_data.append("--no-chapters") json_data.append("--no-chapters")
if "fra" in file: lang = file[-7:][:-4]
json_data.append("--language") json_data.append("--language")
json_data.append("0:fr") json_data.append(f"0:{lang}")
elif "eng" in file:
json_data.append("--language")
json_data.append("0:en")
elif "deu" in file:
json_data.append("--language")
json_data.append("0:de")
elif "nld" in file:
json_data.append("--language")
json_data.append("0:nl")
elif "spa" in file:
json_data.append("--language")
json_data.append("0:es")
elif "ita" in file:
json_data.append("--language")
json_data.append("0:it")
json_data.append("(") json_data.append("(")
json_data.append(file) json_data.append(file)
json_data.append(")") json_data.append(")")
@ -293,6 +276,16 @@ def create_mkv(filename):
remove(file) remove(file)
def mkv_to_mp4(filename):
options = "-c:a copy -c:v copy -c:s copy -movflags faststart"
command = f"ffmpeg -loglevel error -i {filename}_FINAL.mkv -map 0 {options} -y NEW_{filename}.mp4"
result = subprocess.getoutput(command)
if result != "":
logging.error(result)
else:
remove(f"{filename}_FINAL.mkv")
if __name__ == '__main__': if __name__ == '__main__':
import argparse import argparse
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
@ -300,6 +293,8 @@ if __name__ == '__main__':
parser.add_argument("-d", "--debug", dest="debug", action="store_true") parser.add_argument("-d", "--debug", dest="debug", action="store_true")
parser.add_argument("-s", "--stabilise", dest="stab", action="store_true") parser.add_argument("-s", "--stabilise", dest="stab", action="store_true")
parser.add_argument("-t", "--starttime", dest="starttime") parser.add_argument("-t", "--starttime", dest="starttime")
parser.add_argument("-a", "--animation", dest="animation", action="store_true")
parser.add_argument("-c", "--vhs", dest="vhs", action="store_true")
args = parser.parse_args() args = parser.parse_args()
if args.debug: if args.debug:
logging.basicConfig(format='[%(asctime)s]\n%(message)s', level=logging.DEBUG, datefmt='%d/%m/%Y %H:%M:%S') logging.basicConfig(format='[%(asctime)s]\n%(message)s', level=logging.DEBUG, datefmt='%d/%m/%Y %H:%M:%S')
@ -307,11 +302,15 @@ if __name__ == '__main__':
logging.basicConfig(format='[%(asctime)s]\n%(message)s', level=logging.INFO, datefmt='%d/%m/%Y %H:%M:%S') logging.basicConfig(format='[%(asctime)s]\n%(message)s', level=logging.INFO, datefmt='%d/%m/%Y %H:%M:%S')
file = args.f_input file = args.f_input
infos = get_infos(file) infos = get_infos(file)
# interlaced = is_interlaced(file, infos) interlaced = is_interlaced(file, infos)
cropsize = cropping(file, infos) cropsize = cropping(file, infos)
volumes = volume_audio(file, infos) volumes = volume_audio(file, infos)
if args.stab: if args.stab:
stabilization(file) stabilization(file)
if args.animation:
animation = True
else:
animation = False
if not args.starttime: if not args.starttime:
for track in infos['subtitles']: for track in infos['subtitles']:
extract_subs(file, track['index'], track['language']) extract_subs(file, track['index'], track['language'])
@ -323,6 +322,7 @@ if __name__ == '__main__':
vid_part_time = 0 vid_part_time = 0
while vid_part_time < infos['duration']: while vid_part_time < infos['duration']:
crf = 19 crf = 19
convert_video(file, infos, vid_part_time, cropsize, crf) convert_video(file, infos, vid_part_time, cropsize, crf, animation, interlaced, args.vhs)
vid_part_time += 300 vid_part_time += 300
create_mkv(file) create_mkv(file)
mkv_to_mp4(file)