]> git.plutz.net Git - viper/blob - fileExport.py
implemeted most basic cropping controls
[viper] / fileExport.py
1 #encoding: utf-8
2 #Copyright 2009 Paul Hänsch
3
4 #This file is part of Viper.
5
6 #Viper is free software: you can redistribute it and/or modify
7 #it under the terms of the GNU General Public License as published by
8 #the Free Software Foundation, either version 3 of the License, or
9 #(at your option) any later version.
10
11 #Viper is distributed in the hope that it will be useful,
12 #but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 #GNU General Public License for more details.
15
16 #You should have received a copy of the GNU General Public License
17 #along with Viper.  If not, see <http://www.gnu.org/licenses/>
18
19 from Tkinter import *
20 from plugin import *
21 import tkFileDialog
22 import threading
23 import sys
24 import os
25
26 class ExportDialog(Tk):
27     """
28     Dialog Window for exporting a video.
29
30     This dialog provides handles for the whole video export engine,
31     including plugin support for codec configuration plugins.
32     The actual video encoder will be executed by this dialog.
33     """
34
35     def __init__(self, commands = []):
36         """
37         Constructor
38
39         "Commands" is a list of mplayer subcommand lists for playing the video chunks.
40         The very same subcommands are given to the video encoder.
41         """
42
43         Tk.__init__(self)
44         self.title('Viper Export')
45
46         self.enclabel = None
47         self.encoder = None
48         self.commands = commands
49
50         self.container = []
51         self.vcodec = []
52         self.acodec = []
53         self.subgets = {}
54
55         self.subgets['f_filename'] = LabelFrame(self, text = 'Filename:')
56         self.subgets['f_filename'].pack( side = TOP, expand = True, fill = X)
57         self.subgets['b_filename'] = Button(self.subgets['f_filename'], 
58                                             text = 'Select', command = self.select_file)
59         self.subgets['b_filename'].pack( side = LEFT )
60         self.subgets['e_filename'] = Entry(self.subgets['f_filename'], width = 64)
61         self.subgets['e_filename'].pack( side = LEFT, expand = True, fill = X)
62
63         self.subgets['f_actions'] = Frame(self)
64         self.subgets['f_actions'].pack( side = BOTTOM, expand = True, fill = X)
65         self.subgets['b_encode'] = Button(self.subgets['f_actions'], text = 'Encode!',
66                                           command = self.encode)
67         self.subgets['b_encode'].pack( side = RIGHT)
68         self.subgets['b_store'] = Button(self.subgets['f_actions'], text = 'Store Defaults',
69                                          command = self.store, state = 'disabled')
70         self.subgets['b_store'].pack( side = RIGHT)
71
72         self.subgets['f_vcodec'] = LabelFrame(self, text = 'Video Codec')
73         self.subgets['f_vcodec'].pack( side = BOTTOM, expand = True, fill = X)
74         self.subgets['lb_vcodec'] = Listbox(self.subgets['f_vcodec'], height = 5, width = 10)
75         self.subgets['lb_vcodec'].pack(side = LEFT)
76         self.subgets['sb_vcodec'] = Scrollbar(self.subgets['f_vcodec'], orient = VERTICAL,
77                                                command = self.subgets['lb_vcodec'].yview)
78         self.subgets['lb_vcodec'].config(yscrollcommand = self.subgets['sb_vcodec'].set)
79         self.subgets['sb_vcodec'].pack( side = LEFT, fill = Y)
80         self.subgets['cfg_vcodec'] = None
81
82         self.subgets['f_acodec'] = LabelFrame(self, text = 'Audio Codec')
83         self.subgets['f_acodec'].pack( side = BOTTOM, expand = True, fill = X)
84         self.subgets['lb_acodec'] = Listbox(self.subgets['f_acodec'], height = 5, width = 10)
85         self.subgets['lb_acodec'].pack(side = LEFT)
86         self.subgets['sb_acodec'] = Scrollbar(self.subgets['f_acodec'], orient = VERTICAL,
87                                                command = self.subgets['lb_acodec'].yview)
88         self.subgets['lb_acodec'].config(yscrollcommand = self.subgets['sb_acodec'].set)
89         self.subgets['sb_acodec'].pack( side = LEFT, fill = Y)
90         self.subgets['cfg_acodec'] = None
91
92         self.subgets['f_container'] = LabelFrame(self, text = 'Container Format')
93         self.subgets['f_container'].pack( side = BOTTOM, expand = True, fill = X)
94         self.subgets['lb_container'] = Listbox(self.subgets['f_container'], height = 5, width = 10)
95         self.subgets['lb_container'].pack(side = LEFT)
96         self.subgets['sb_container'] = Scrollbar(self.subgets['f_container'], orient = VERTICAL,
97                                                command = self.subgets['lb_container'].yview)
98         self.subgets['lb_container'].config(yscrollcommand = self.subgets['sb_container'].set)
99         self.subgets['sb_container'].pack( side = LEFT, fill = Y)
100         self.subgets['cfg_container'] = None
101
102         self.load_plugins()
103         self.select_plugin()
104
105     def encode(self):
106         """
107         The method executed when the 'Encode' button is pressed.
108
109         This will initialize the video encoder and build the status window.
110         """
111         command = ['mencoder']
112         self.encoder = []
113
114         for cmd in self.commands:
115             command.extend(cmd)
116
117         if self.subgets['e_filename'].get() != '':
118             command.extend(['-o', self.subgets['e_filename'].get()])
119         else:
120             command.extend(['-o', tkFileDialog.asksaveasfilename()])
121         if self.subgets['cfg_container'] != None:
122             command.extend(self.subgets['cfg_container'].subcommand())
123         else:
124             command.extend(['-of','avi'])
125         if self.subgets['cfg_vcodec'] != None:
126             command.extend(self.subgets['cfg_vcodec'].subcommand())
127         else:
128             command.extend(['-ovc','copy'])
129         if self.subgets['cfg_acodec'] != None:
130             command.extend(self.subgets['cfg_acodec'].subcommand())
131         else:
132             command.extend(['-oac','copy'])
133
134         self.encoder = os.popen2(command)
135
136         self.subgets['enc_win'] = Tk()
137         self.subgets['enc_win'].title('Encoding ' + self.subgets['e_filename'].get())
138         self.enclabel = Label(self.subgets['enc_win'], width = 64, height = 3)
139         self.enclabel.pack( side = TOP, expand = True, fill = X)
140         self.subgets['enc_b_exit'] =  Button(self.subgets['enc_win'],
141                                              text = 'Cancel',
142                                              command = self.subgets['enc_win'].destroy)
143         self.subgets['enc_b_exit'].pack( side = BOTTOM, anchor = E )
144
145         self.wm_withdraw()
146         threading.Thread( target = self.encstat ).start()
147         self.subgets['enc_win'].mainloop()
148
149     def encstat(self):
150         """
151         Internal methos for providing the status display.
152
153         This methos is executed in its own thread to read the mencoder
154         status line and display it in the encoding window.
155         It is possible to rewrite it to display a status bar instead.
156         """
157         line = '#'
158         char = '#'
159         try:
160             while line != ' ':
161                 line = ' '
162                 while char != '' and line[-1] != '\r' and line[-1] != '\n':
163                     char = self.encoder[1].read(1)
164                     line += char
165                 self.enclabel.config( text = line.strip() )
166             self.enclabel.config( text = 'Ready' )
167         except:
168             print 'Reading from pipe impossible'
169             self.enclabel.config( text = 'Ready' )
170         self.subgets['enc_b_exit'].configure(text = 'Close Window')
171         self.destroy()
172
173     def store(self):
174         """
175         This method is executed when the "Store" butten is pressed.
176
177         It will store the codec configuration. It is not yet implemented.
178         """
179         pass
180
181     def select_plugin(self):
182         """
183         Internal method.
184
185         This method is regularly called to display the configuration dialog of a
186         selected codec plugin.
187         """
188         if self.subgets['lb_container'].curselection() != ():
189             c_plugin = int(self.subgets['lb_container'].curselection()[0])
190             if self.subgets['cfg_container'] != self.container[c_plugin]:
191                 if self.subgets['cfg_container'] != None:
192                     self.subgets['cfg_container'].pack_forget()
193                 self.subgets['cfg_container'] = self.container[c_plugin]
194                 self.subgets['cfg_container'].pack(side = LEFT, expand = True, fill = BOTH)
195
196         if self.subgets['lb_vcodec'].curselection() != ():
197             v_plugin = int(self.subgets['lb_vcodec'].curselection()[0])
198             if self.subgets['cfg_vcodec'] != self.vcodec[v_plugin]:
199                 if self.subgets['cfg_vcodec'] != None:
200                     self.subgets['cfg_vcodec'].pack_forget()
201                 self.subgets['cfg_vcodec'] = self.vcodec[v_plugin]
202                 self.subgets['cfg_vcodec'].pack(side = LEFT, expand = True, fill = BOTH)
203
204         if self.subgets['lb_acodec'].curselection() != ():
205             a_plugin = int(self.subgets['lb_acodec'].curselection()[0])
206             if self.subgets['cfg_acodec'] != self.acodec[a_plugin]:
207                 if self.subgets['cfg_acodec'] != None:
208                     self.subgets['cfg_acodec'].pack_forget()
209                 self.subgets['cfg_acodec'] = self.acodec[a_plugin]
210                 self.subgets['cfg_acodec'].pack(side = LEFT, expand = True, fill = BOTH)
211
212         self.after(50, self.select_plugin)
213
214     def select_file(self):
215         """
216         Bring up the file selection dialog.
217         """
218         self.subgets['e_filename'].insert(0, tkFileDialog.asksaveasfilename())
219
220     def load_plugins(self):
221         """
222         Load all codec plugins from plugin directory.
223         """
224         sys.path.insert(0, 'plugins/')
225         for plugin in os.listdir(sys.path[0]):
226             if plugin[-3:] == '.py':
227                 __import__(plugin[:-3], None, None, ['*'])
228
229         for c_class in C_Plugin.__subclasses__():
230             self.container.append(c_class(self.subgets['f_container']))
231         for c_class in self.container:
232             if c_class.is_available():
233                 self.subgets['lb_container'].insert(END, c_class.name())
234
235         for a_class in A_Plugin.__subclasses__():
236             self.acodec.append(a_class(self.subgets['f_acodec']))
237         for a_class in self.acodec:
238             if a_class.is_available():
239                 self.subgets['lb_acodec'].insert(END, a_class.name())
240
241         for v_class in V_Plugin.__subclasses__():
242             self.vcodec.append(v_class(self.subgets['f_vcodec']))
243         for v_class in self.vcodec:
244             if v_class.is_available():
245                 self.subgets['lb_vcodec'].insert(END, v_class.name())
246
247 def export(chunklist):
248     """
249     Easy to call export function.
250
251     Calling this will build and handle the whole dialog.
252     """
253
254     enclist = []
255     for vc in chunklist:
256         if vc.played.get():
257             enclist.append(vc.slave_subcommand())
258
259     diag = ExportDialog(commands = enclist)
260     diag.mainloop()