Fri, 24 Nov 2017 16:16:50 +0100
added autocrop and 720p rescaler
#!/usr/bin/env python import subprocess from eit import readeit import os, shlex def filter_lines(data, search): ret = [] for line in data.split("\n"): if line.find(search) == -1: continue ret.append(line) return "\n".join(ret) def run_command(command): process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if output: print output.strip() rc = process.poll() return rc class ts2mkv(object): def __init__(self): self.msg_prepare = "" self.msg_eit = "" self.msg_ffmpeg = "" self.command = None self.scaleto_720p = True self.video_options = [ "-c:v libx264", "-preset faster", # slow "-tune film", # film / animation "-crf 19" # 21, better 19 ] self.audio_options = [ "-c:a copy", ] def get_stream_index(self, data): idx = data.find("Stream #") if idx == -1: return "" idx += 8 self.msg_prepare += "Selecting: %s\n" % data return data[idx:idx+3] def get_movie_description(self, filename): # read the EIT file # TODO: fallback to meta file if no EIT # TODO: is there a way to get the imdb for the movie automagically? # http://www.omdbapi.com/apikey.aspx self.msg_eit = readeit(os.path.splitext(filename)[0] + ".eit") def get_crop_option(self): lines = filter_lines(self.msg_ffmpeg, "[Parsed_cropdetect").split("\n") option = None for line in lines: tmp = line[line.find(" crop="):].strip() #print "DEBUG: " + tmp if not option: option = tmp else: if option != tmp: self.msg_prepare += "WARNING: cropdetect inconsistent over scan time, disabling autocrop\n" return None self.msg_prepare += "Crop detected: %s\n" % option return option def get_ffmpeg_command(self, filename): commands = [] fn = "\\'".join(p for p in filename.split("'")) # ffmpeg -ss 00:05:00 -t 2 -i testfiles/chappie.ts -vf "cropdetect=24:16:0" -f null - cmd = ["ffmpeg", "-ss 00:05:00", "-t 1", # search to 5 minutes, analyze 1 second "-i %s" % fn, "-vf \"cropdetect=24:2:0\"", # detect black bar crop on top and bottom "-f null", "-" # no output file ] print " ".join(cmd) p = subprocess.Popen(shlex.split(" ".join(cmd)), stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() print "Command return code: ", p.poll() self.msg_ffmpeg = out + "\n" + err self.msg_ffmpeg = self.msg_ffmpeg[self.msg_ffmpeg.find("Input #0"):] # find "Stream #0:" lines info = filter_lines(self.msg_ffmpeg, "Stream #0:") fn = fn.replace(" ", "\\ ") # CRAP! ffmpeg cannot decode dvb_teletext streams to srt :( # are there any subtitle streams?! #s = filter_lines(info, "Subtitle:") #s = filter_lines(s, "(deu):") #if s != "": # s = self.get_stream_index(s.split("\n")[0]) # commands.append([ # "ffmpeg", # "-txt_format text", # "-i %s" % fn, # "-map %s" % s, # "%s.srt" % os.path.splitext(fn)[0] # ]) v = self.get_stream_index( filter_lines(info, "Video:")) if v == "": print "No video stream found" return None audioall = filter_lines(info, "Audio:") audio = filter_lines(audioall, "(deu):") a = self.get_stream_index( filter_lines(audio, "ac3")) # TODO: wenn kein ac3 stream dann dts oder mpeg fallback audiomap = [a] if a == "": print "No suitable german audio stream found" return None audio = filter_lines(audioall, "(eng):") a = self.get_stream_index( filter_lines(audio, "ac3")) if a != "": # append english audio too! audiomap.append(a) self.msg_prepare += "Video Stream selected: Stream #%s\n" % v cmd = [ "ffmpeg", "-i %s" % fn, "-map %s" % v, ] flt = [] crop = self.get_crop_option() if crop: flt.append(crop) if self.scaleto_720p: flt.append("scale='min(1280,iw)':-2'") # -2 ensures division by two for codec self.msg_prepare += "Scaling cropped output stream to 720p\n" if len(flt) > 0: # append video filters cmd.append('-filter:v "%s"' % ",".join(flt)) for a in audiomap: self.msg_prepare += "Audio Stream selected: Stream #%s\n" % a cmd.append("-map %s" % a) cmd.extend(self.video_options) cmd.extend(self.audio_options) cmd.append(os.path.splitext(fn)[0] + ".mkv") commands.append(" ".join(cmd)) return commands def load(self, filename): self.filename = filename self.get_movie_description(filename) self.command = self.get_ffmpeg_command(filename) if __name__ == "__main__": import sys os.system('cls' if os.name == 'nt' else 'clear') # TODO: get file from commandline #filename = "testfiles/chappie.ts" filename = "/srv/storage0/DREAMBOX/Science Fiction/THE_ISLAND.ts" mkv = ts2mkv() mkv.load(filename) if mkv.command: fd = open(os.path.splitext(filename)[0] + ".txt", "wb") fd.write(mkv.msg_eit) fd.write("\n\n# ---DEBUG---\n\n") fd.write(mkv.msg_prepare) fd.write(mkv.msg_ffmpeg) fd.close() print mkv.msg_ffmpeg for cmd in mkv.command: print "Executing ffmpeg:\n%s\n" % cmd run_command(cmd)