pyTivo
[pyTivo/krkeegan.git] / transcode.py
blob9de1a7afb8a53dea62659b0a371f4ce8ae53a1a2
1 import subprocess, shutil, os, re
3 def output_video(inFile, outFile):
4 if tivo_compatable(inFile):
5 f = file(inFile, 'rb')
6 shutil.copyfileobj(f, outFile)
7 f.close()
8 else:
9 transcode(inFile, outFile)
11 def transcode(inFile, outFile):
13 cmd = "ffmpeg_mp2.exe -i \"%s\" -vcodec mpeg2video -r 29.97 -b 4096 %s -ac 2 -ab 192 -f vob -" % (inFile, select_aspect(inFile))
14 print cmd
15 ffmpeg = subprocess.Popen(cmd, stdout=subprocess.PIPE)
16 try:
17 shutil.copyfileobj(ffmpeg.stdout, outFile)
18 except:
19 win32kill(ffmpeg.pid)
21 def select_aspect(inFile):
22 type, height, width, fps = video_info(inFile)
23 print type, height, width, fps
25 d = gcd(height,width)
27 rheight, rwidth = height/d, width/d
28 print height, width
30 if (rheight, rwidth) == (4, 3):
31 return '-aspect 4:3 -s 720x480'
32 elif (rheight, rwidth) == (16, 9):
33 return '-aspect 16:9 -s 720x480'
34 else:
35 settings = []
36 settings.apppend('-aspect 16:9')
38 endHeight = (720*width)/height
39 if endHeight % 2:
40 endHeight -= 1
41 print endHeight
43 settings.append('-s 720x' + str(endHeight))
45 topPadding = ((480 - endHeight)/2)
46 if topPadding % 2:
47 topPadding -= 1
49 settings.append('-padtop ' + str(topPadding))
50 bottomPadding = (480 - endHeight) - topPadding
51 settings.append('-padbottom ' + str(bottomPadding))
53 return ' '.join(settings)
55 def tivo_compatable(inFile):
56 suportedModes = [[720, 480], [704, 480], [544, 480], [480, 480], [352, 480]]
57 type, height, width, fps = video_info(inFile)
59 if not type == 'mpeg2video':
60 return False
62 if not fps == '29.97':
63 return False
65 for mode in suportedModes:
66 if (mode[0], mode[1]) == (height, width):
67 return True
68 return False
70 def video_info(inFile):
71 cmd = "ffmpeg_mp2.exe -i \"%s\"" % inFile
72 ffmpeg = subprocess.Popen(cmd, stderr=subprocess.PIPE)
73 output = ffmpeg.stderr.read()
75 rezre = re.compile(r'.*Video: (.+), (\d+)x(\d+), (.+) fps.*')
76 m = rezre.search(output)
77 if m:
78 return m.group(1), int(m.group(2)), int(m.group(3)), m.group(4)
79 else:
80 return None, None, None, None
82 def win32kill(pid):
83 import ctypes
84 handle = ctypes.windll.kernel32.OpenProcess(1, False, pid)
85 ctypes.windll.kernel32.TerminateProcess(handle, -1)
86 ctypes.windll.kernel32.CloseHandle(handle)
88 def gcd(a,b):
89 while b:
90 a, b = b, a % b
91 return a