Random change to test post commit hook.
[pyTivo.git] / transcode.py
blob8ed17ce83b95ca3854fca3a79de30d122527f63a
1 import subprocess, shutil, os, re, sys
3 SCRIPTDIR = os.path.dirname(__file__)
4 FFMPEG = os.path.join(SCRIPTDIR, 'ffmpeg_mp2.exe')
6 # XXX BIG HACK
7 # subprocess is broken for me on windows so super hack
8 def patchSubprocess():
9 o = subprocess.Popen._make_inheritable
11 def _make_inheritable(self, handle):
12 if not handle: return subprocess.GetCurrentProcess()
13 return o(self, handle)
15 subprocess.Popen._make_inheritable = _make_inheritable
16 mswindows = (sys.platform == "win32")
17 if mswindows:
18 patchSubprocess()
20 def output_video(inFile, outFile):
21 if tivo_compatable(inFile):
22 f = file(inFile, 'rb')
23 shutil.copyfileobj(f, outFile)
24 f.close()
25 else:
26 transcode(inFile, outFile)
28 def transcode(inFile, outFile):
30 cmd = [FFMPEG, '-i', inFile, '-vcodec', 'mpeg2video', '-r', '29.97', '-b', '4096'] + select_aspect(inFile) + ['-ac', '2', '-ab', '192', '-f', 'vob', '-' ]
31 ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE)
32 try:
33 shutil.copyfileobj(ffmpeg.stdout, outFile)
34 except:
35 win32kill(ffmpeg.pid)
37 def select_aspect(inFile):
38 type, height, width, fps = video_info(inFile)
40 d = gcd(height,width)
42 rheight, rwidth = height/d, width/d
44 if (rheight, rwidth) in [(4, 3), (10, 11), (15, 11), (59, 54), (59, 72), (59, 36), (59, 54)]:
45 return ['-aspect', '4:3', '-s', '720x480']
46 elif (rheight, rwidth) in [(16, 9), (20, 11), (40, 33), (118, 81), (59, 27)]:
47 return ['-aspect', '16:9', '-s', '720x480']
48 else:
49 settings = []
50 settings.append('-aspect')
51 settings.append('16:9')
53 endHeight = (720*width)/height
54 if endHeight % 2:
55 endHeight -= 1
57 settings.append('-s')
58 settings.append('720x' + str(endHeight))
60 topPadding = ((480 - endHeight)/2)
61 if topPadding % 2:
62 topPadding -= 1
64 settings.append('-padtop')
65 settings.append(str(topPadding))
66 bottomPadding = (480 - endHeight) - topPadding
67 settings.append('-padbottom')
68 settings.append(str(bottomPadding))
70 return settings
72 def tivo_compatable(inFile):
73 suportedModes = [[720, 480], [704, 480], [544, 480], [480, 480], [352, 480]]
74 type, height, width, fps = video_info(inFile)
76 if not type == 'mpeg2video':
77 return False
79 if not fps == '29.97':
80 return False
82 for mode in suportedModes:
83 if (mode[0], mode[1]) == (height, width):
84 return True
85 return False
87 def video_info(inFile):
88 cmd = [FFMPEG, '-i', inFile ]
89 ffmpeg = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
90 output = ffmpeg.stderr.read()
92 rezre = re.compile(r'.*Video: (.+), (\d+)x(\d+), (.+) fps.*')
93 m = rezre.search(output)
94 if m:
95 return m.group(1), int(m.group(2)), int(m.group(3)), m.group(4)
96 else:
97 return None, None, None, None
99 def suported_format(inFile):
100 if video_info(inFile)[0]:
101 return True
102 else:
103 return False
105 def win32kill(pid):
106 import ctypes
107 handle = ctypes.windll.kernel32.OpenProcess(1, False, pid)
108 ctypes.windll.kernel32.TerminateProcess(handle, -1)
109 ctypes.windll.kernel32.CloseHandle(handle)
111 def gcd(a,b):
112 while b:
113 a, b = b, a % b
114 return a