28 self.msg_prepare = "" |
28 self.msg_prepare = "" |
29 self.msg_eit = "" |
29 self.msg_eit = "" |
30 self.msg_ffmpeg = "" |
30 self.msg_ffmpeg = "" |
31 self.command = None |
31 self.command = None |
32 |
32 |
|
33 self.scaleto_720p = True |
|
34 |
33 self.video_options = [ |
35 self.video_options = [ |
34 "-c:v libx264", |
36 "-c:v libx264", |
35 "-preset slow", |
37 "-preset faster", # slow |
36 "-crf 21" |
38 "-tune film", # film / animation |
|
39 "-crf 19" # 21, better 19 |
37 ] |
40 ] |
38 self.audio_options = [ |
41 self.audio_options = [ |
39 "-c:a copy", |
42 "-c:a copy", |
40 ] |
43 ] |
41 |
|
42 |
44 |
43 def get_stream_index(self, data): |
45 def get_stream_index(self, data): |
44 idx = data.find("Stream #") |
46 idx = data.find("Stream #") |
45 if idx == -1: |
47 if idx == -1: |
46 return "" |
48 return "" |
53 # TODO: fallback to meta file if no EIT |
55 # TODO: fallback to meta file if no EIT |
54 # TODO: is there a way to get the imdb for the movie automagically? |
56 # TODO: is there a way to get the imdb for the movie automagically? |
55 # http://www.omdbapi.com/apikey.aspx |
57 # http://www.omdbapi.com/apikey.aspx |
56 self.msg_eit = readeit(os.path.splitext(filename)[0] + ".eit") |
58 self.msg_eit = readeit(os.path.splitext(filename)[0] + ".eit") |
57 |
59 |
|
60 def get_crop_option(self): |
|
61 lines = filter_lines(self.msg_ffmpeg, "[Parsed_cropdetect").split("\n") |
|
62 option = None |
|
63 for line in lines: |
|
64 tmp = line[line.find(" crop="):].strip() |
|
65 #print "DEBUG: " + tmp |
|
66 if not option: |
|
67 option = tmp |
|
68 else: |
|
69 if option != tmp: |
|
70 self.msg_prepare += "WARNING: cropdetect inconsistent over scan time, disabling autocrop\n" |
|
71 return None |
|
72 self.msg_prepare += "Crop detected: %s\n" % option |
|
73 return option |
|
74 |
58 def get_ffmpeg_command(self, filename): |
75 def get_ffmpeg_command(self, filename): |
59 commands = [] |
76 commands = [] |
60 fn = "\\'".join(p for p in filename.split("'")) |
77 fn = "\\'".join(p for p in filename.split("'")) |
61 |
78 |
62 p = subprocess.Popen(["ffmpeg", "-i", fn], |
79 # ffmpeg -ss 00:05:00 -t 2 -i testfiles/chappie.ts -vf "cropdetect=24:16:0" -f null - |
63 stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
80 |
|
81 cmd = ["ffmpeg", |
|
82 "-ss 00:05:00", "-t 1", # search to 5 minutes, analyze 1 second |
|
83 "-i %s" % fn, |
|
84 "-vf \"cropdetect=24:2:0\"", # detect black bar crop on top and bottom |
|
85 "-f null", "-" # no output file |
|
86 ] |
|
87 print " ".join(cmd) |
|
88 p = subprocess.Popen(shlex.split(" ".join(cmd)), stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
64 out, err = p.communicate() |
89 out, err = p.communicate() |
|
90 print "Command return code: ", p.poll() |
65 self.msg_ffmpeg = out + "\n" + err |
91 self.msg_ffmpeg = out + "\n" + err |
66 self.msg_ffmpeg = self.msg_ffmpeg[self.msg_ffmpeg.find("Input #0"):] |
92 self.msg_ffmpeg = self.msg_ffmpeg[self.msg_ffmpeg.find("Input #0"):] |
|
93 |
67 # find "Stream #0:" lines |
94 # find "Stream #0:" lines |
68 info = filter_lines(self.msg_ffmpeg, "Stream #0:") |
95 info = filter_lines(self.msg_ffmpeg, "Stream #0:") |
69 |
96 |
70 fn = fn.replace(" ", "\\ ") |
97 fn = fn.replace(" ", "\\ ") |
71 |
98 |
105 if a != "": |
132 if a != "": |
106 # append english audio too! |
133 # append english audio too! |
107 audiomap.append(a) |
134 audiomap.append(a) |
108 |
135 |
109 |
136 |
|
137 |
110 self.msg_prepare += "Video Stream selected: Stream #%s\n" % v |
138 self.msg_prepare += "Video Stream selected: Stream #%s\n" % v |
111 cmd = [ |
139 cmd = [ |
112 "ffmpeg", |
140 "ffmpeg", |
113 "-i %s" % fn, |
141 "-i %s" % fn, |
114 "-map %s" % v, |
142 "-map %s" % v, |
115 ] |
143 ] |
|
144 flt = [] |
|
145 crop = self.get_crop_option() |
|
146 if crop: |
|
147 flt.append(crop) |
|
148 if self.scaleto_720p: |
|
149 flt.append("scale='min(1280,iw)':-2'") # -2 ensures division by two for codec |
|
150 self.msg_prepare += "Scaling cropped output stream to 720p\n" |
|
151 if len(flt) > 0: |
|
152 # append video filters |
|
153 cmd.append('-filter:v "%s"' % ",".join(flt)) |
116 for a in audiomap: |
154 for a in audiomap: |
117 self.msg_prepare += "Audio Stream selected: Stream #%s\n" % a |
155 self.msg_prepare += "Audio Stream selected: Stream #%s\n" % a |
118 cmd.append("-map %s" % a) |
156 cmd.append("-map %s" % a) |
119 cmd.extend(self.video_options) |
157 cmd.extend(self.video_options) |
120 cmd.extend(self.audio_options) |
158 cmd.extend(self.audio_options) |
131 if __name__ == "__main__": |
169 if __name__ == "__main__": |
132 import sys |
170 import sys |
133 os.system('cls' if os.name == 'nt' else 'clear') |
171 os.system('cls' if os.name == 'nt' else 'clear') |
134 |
172 |
135 # TODO: get file from commandline |
173 # TODO: get file from commandline |
136 filename = "testfiles/chappie.ts" |
174 #filename = "testfiles/chappie.ts" |
|
175 filename = "/srv/storage0/DREAMBOX/Science Fiction/THE_ISLAND.ts" |
137 |
176 |
138 mkv = ts2mkv() |
177 mkv = ts2mkv() |
139 mkv.load(filename) |
178 mkv.load(filename) |
140 if mkv.command: |
179 if mkv.command: |
141 fd = open(os.path.splitext(filename)[0] + ".txt", "wb") |
180 fd = open(os.path.splitext(filename)[0] + ".txt", "wb") |