1# -*- coding: utf-8 -*- 2# vi:si:et:sw=2:sts=2:ts=2 3 4import os 5from os.path import basename 6import time 7from addSubtitlesDialog import addSubtitlesPropertiesDialog, SubtitlesList 8 9import wx 10 11import theoraenc 12 13class AddVideoDialog(wx.Dialog): 14 def __init__( 15 self, parent, ID, title, hasKate, hasIconv, 16 size=wx.DefaultSize, pos=wx.DefaultPosition, 17 style=wx.DEFAULT_DIALOG_STYLE, 18 ): 19 20 self.videoFile = '' 21 self.hasKate = hasKate 22 self.hasIconv = hasIconv 23 24 pre = wx.PreDialog() 25 #pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP) 26 pre.Create(parent, ID, title, pos, size, style) 27 self.PostCreate(pre) 28 29 # Now continue with the normal construction of the dialog 30 padding = 4 31 section_padding=60 32 33 mainBox = wx.BoxSizer(wx.VERTICAL) 34 hbox = wx.BoxSizer(wx.HORIZONTAL) 35 mainBox.Add(hbox) 36 hbox.AddSpacer((8, 8)) 37 38 #Video File 39 hbox = wx.BoxSizer(wx.HORIZONTAL) 40 mainBox.Add(hbox) 41 hbox.Add(wx.StaticText(self, -1, "Video File"), 0, wx.EXPAND|wx.ALL, 16) 42 43 self.btnVideoFile = wx.Button(self, size=(380, -1)) 44 self.btnVideoFile.SetLabel('Select...') 45 self.Bind(wx.EVT_BUTTON, self.OnClickVideoFile, self.btnVideoFile) 46 hbox.Add(self.btnVideoFile, 0, wx.EXPAND|wx.ALL, padding) 47 48 #Quality 49 hbox = wx.BoxSizer(wx.HORIZONTAL) 50 mainBox.Add(hbox) 51 52 label = wx.StaticText(self, -1, "Video") 53 hbox.AddSpacer((12, 10)) 54 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 55 hbox = wx.BoxSizer(wx.HORIZONTAL) 56 mainBox.Add(hbox) 57 hbox.AddSpacer((section_padding, 10)) 58 59 label = wx.StaticText(self, -1, "Quality:") 60 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 61 self.videoquality = wx.TextCtrl(self, -1, '5.0', size=(32,-1)) 62 hbox.Add(self.videoquality, 0, wx.EXPAND|wx.ALL, padding) 63 label = wx.StaticText(self, -1, "Bitrate (kbps):") 64 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 65 self.videobitrate = wx.TextCtrl(self, -1, '', size=(65,-1)) 66 hbox.Add(self.videobitrate, 0, wx.EXPAND|wx.ALL, padding) 67 hbox = wx.BoxSizer(wx.HORIZONTAL) 68 mainBox.Add(hbox) 69 hbox.AddSpacer((section_padding, 10)) 70 71 #Size 72 box=45 73 label = wx.StaticText(self, -1, "Size:") 74 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 75 self.width = wx.TextCtrl(self, -1, '', size=(65,-1)) 76 hbox.Add(self.width, 0, wx.EXPAND|wx.ALL, padding) 77 label = wx.StaticText(self, -1, "x") 78 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 79 self.height = wx.TextCtrl(self, -1, '', size=(65,-1)) 80 hbox.Add(self.height, 0, wx.EXPAND|wx.ALL, padding) 81 82 #Framerate 83 label = wx.StaticText(self, -1, "Framerate:") 84 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 85 self.framerate = wx.TextCtrl(self, -1, '', size=(40,-1)) 86 hbox.Add(self.framerate, 0, wx.EXPAND|wx.ALL, padding) 87 88 #Crop 89 box=35 90 hbox = wx.BoxSizer(wx.HORIZONTAL) 91 mainBox.Add(hbox) 92 hbox.AddSpacer((section_padding, 10)) 93 label = wx.StaticText(self, -1, "Crop:") 94 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 95 96 label = wx.StaticText(self, -1, "Top") 97 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 98 self.cropTop = wx.TextCtrl(self, -1, '', size=(box,-1)) 99 hbox.Add(self.cropTop, 0, wx.EXPAND|wx.ALL, padding) 100 101 label = wx.StaticText(self, -1, "Left") 102 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 103 self.cropLeft = wx.TextCtrl(self, -1, '', size=(box,-1)) 104 hbox.Add(self.cropLeft, 0, wx.EXPAND|wx.ALL, padding) 105 106 label = wx.StaticText(self, -1, "Bottom") 107 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 108 self.cropBottom = wx.TextCtrl(self, -1, '', size=(box,-1)) 109 hbox.Add(self.cropBottom, 0, wx.EXPAND|wx.ALL, padding) 110 111 label = wx.StaticText(self, -1, "Right") 112 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 113 self.cropRight = wx.TextCtrl(self, -1, '', size=(box,-1)) 114 hbox.Add(self.cropRight, 0, wx.EXPAND|wx.ALL, padding) 115 116 box=45 117 118 hbox = wx.BoxSizer(wx.HORIZONTAL) 119 mainBox.Add(hbox) 120 label = wx.StaticText(self, -1, "Audio") 121 hbox.AddSpacer((12, 10)) 122 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 123 124 #Quality & Bitrate 125 hbox = wx.BoxSizer(wx.HORIZONTAL) 126 mainBox.Add(hbox) 127 hbox.AddSpacer((section_padding, 10)) 128 label = wx.StaticText(self, -1, "Quality:") 129 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 130 self.audioquality = wx.TextCtrl(self, -1, '1.0', size=(32,-1)) 131 hbox.Add(self.audioquality, 0, wx.EXPAND|wx.ALL, padding) 132 133 label = wx.StaticText(self, -1, "Bitrate (kbps):") 134 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 135 self.audiobitrate = wx.TextCtrl(self, -1, '', size=(box,-1)) 136 hbox.Add(self.audiobitrate, 0, wx.EXPAND|wx.ALL, padding) 137 138 #Samplerate / Channels 139 hbox = wx.BoxSizer(wx.HORIZONTAL) 140 mainBox.Add(hbox) 141 hbox.AddSpacer((section_padding, 10)) 142 label = wx.StaticText(self, -1, "Samplerate (Hz)") 143 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 144 self.samplerate = wx.TextCtrl(self, -1, '', size=(56,-1)) 145 hbox.Add(self.samplerate, 0, wx.EXPAND|wx.ALL, padding) 146 label = wx.StaticText(self, -1, "Channels") 147 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 148 self.channels = wx.TextCtrl(self, -1, '', size=(24,-1)) 149 hbox.Add(self.channels, 0, wx.EXPAND|wx.ALL, padding) 150 151 hbox = wx.BoxSizer(wx.HORIZONTAL) 152 mainBox.Add(hbox) 153 154 # subtitles ('add' button and list) 155 hbox = wx.BoxSizer(wx.HORIZONTAL) 156 mainBox.Add(hbox) 157 label = wx.StaticText(self, -1, "Subtitles") 158 hbox.AddSpacer((12, 10)) 159 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 160 161 hbox = wx.BoxSizer(wx.HORIZONTAL) 162 mainBox.Add(hbox) 163 164 hbox.AddSpacer((section_padding, 10)) 165 166 if hasKate: 167 vbox = wx.BoxSizer(wx.VERTICAL) 168 hbox.Add(vbox) 169 170 subtitlesButtons_hbox = wx.BoxSizer(wx.HORIZONTAL) 171 vbox.Add(subtitlesButtons_hbox) 172 173 self.btnSubtitlesAdd = wx.Button(self, size=(120, -1)) 174 self.btnSubtitlesAdd.SetLabel('Add...') 175 self.Bind(wx.EVT_BUTTON, self.OnClickSubtitlesAdd, self.btnSubtitlesAdd) 176 subtitlesButtons_hbox.Add(self.btnSubtitlesAdd, 0, wx.EXPAND|wx.ALL, padding) 177 178 self.btnSubtitlesRemove = wx.Button(self, size=(120, -1)) 179 self.btnSubtitlesRemove.SetLabel('Remove') 180 self.Bind(wx.EVT_BUTTON, self.OnClickSubtitlesRemove, self.btnSubtitlesRemove) 181 self.btnSubtitlesRemove.Disable() 182 subtitlesButtons_hbox.Add(self.btnSubtitlesRemove, 0, wx.EXPAND|wx.ALL, padding) 183 184 self.btnSubtitlesProperties = wx.Button(self, size=(120, -1)) 185 self.btnSubtitlesProperties.SetLabel('Properties') 186 self.Bind(wx.EVT_BUTTON, self.OnClickSubtitlesProperties, self.btnSubtitlesProperties) 187 self.btnSubtitlesProperties.Disable() 188 subtitlesButtons_hbox.Add(self.btnSubtitlesProperties, 0, wx.EXPAND|wx.ALL, padding) 189 190 #self.subtitles = wx.ListCtrl(self, -1, style=wx.LC_REPORT) 191 self.subtitles = SubtitlesList(self) 192 self.subtitles.Bind(wx.EVT_LIST_ITEM_SELECTED, self.CheckSubtitlesSelection) 193 self.subtitles.Bind(wx.EVT_LEFT_DCLICK, self.OnClickSubtitlesProperties) 194 self.subtitles.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.CheckSubtitlesSelection) 195 self.subtitles.Bind(wx.EVT_KILL_FOCUS, self.CheckSubtitlesSelection) 196 vbox.Add(self.subtitles, 0, wx.EXPAND|wx.ALL, padding) 197 198 else: 199 self.subtitles = None 200 hbox.Add(wx.StaticText(self, -1, "ffmpeg2theora doesn't seem to be built with subtitles support.\nSee documentation for how to enable subtitles.\n")) 201 202 ''' 203 #Metadata 204 label = wx.StaticText(self, -1, "Metadata") 205 hbox.AddSpacer((12, 10)) 206 hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding) 207 208 mbox=180 209 hbox = wx.BoxSizer(wx.HORIZONTAL) 210 mainBox.Add(hbox) 211 labels = wx.BoxSizer(wx.VERTICAL) 212 inputs = wx.BoxSizer(wx.VERTICAL) 213 hbox.AddSpacer((section_padding, 10)) 214 hbox.Add(labels, 0, wx.ALIGN_RIGHT|wx.EXPAND|wx.ALL) 215 hbox.Add(inputs,0, wx.ALIGN_LEFT|wx.EXPAND|wx.ALL) 216 217 #Title 218 label = wx.StaticText(self, -1, "Title") 219 labels.Add(label, 0, wx.EXPAND|wx.ALL, padding) 220 self.title = wx.TextCtrl(self, -1, '', size=(mbox,-1)) 221 inputs.Add(self.title, 0, wx.EXPAND|wx.ALL) 222 223 #Artist 224 label = wx.StaticText(self, -1, "Artist") 225 labels.Add(label, 0, wx.EXPAND|wx.ALL, padding) 226 self.artist = wx.TextCtrl(self, -1, '', size=(mbox,-1)) 227 inputs.Add(self.artist, 0, wx.EXPAND|wx.ALL) 228 229 #date 230 label = wx.StaticText(self, -1, "Date", size=(mbox,-1)) 231 labels.Add(label, 0, wx.EXPAND|wx.ALL, padding) 232 self.date = wx.TextCtrl(self, -1, '', size=(mbox,-1)) 233 inputs.Add(self.date, 0, wx.EXPAND|wx.ALL) 234 235 #Location 236 label = wx.StaticText(self, -1, "Location") 237 labels.Add(label, 0, wx.EXPAND|wx.ALL, padding) 238 self.location = wx.TextCtrl(self, -1, '', size=(mbox,-1)) 239 inputs.Add(self.location, 0, wx.EXPAND|wx.ALL) 240 241 #Organization 242 label = wx.StaticText(self, -1, "Organization") 243 labels.Add(label, 0, wx.EXPAND|wx.ALL, padding) 244 self.organization = wx.TextCtrl(self, -1, '', size=(mbox,-1)) 245 inputs.Add(self.organization, 0, wx.EXPAND|wx.ALL) 246 247 #Copyright 248 label = wx.StaticText(self, -1, "Copyright") 249 labels.Add(label, 0, wx.EXPAND|wx.ALL, padding) 250 self.copyright = wx.TextCtrl(self, -1, '', size=(mbox,-1)) 251 inputs.Add(self.copyright, 0, wx.EXPAND|wx.ALL) 252 253 #License 254 label = wx.StaticText(self, -1, "License") 255 labels.Add(label, 0, wx.EXPAND|wx.ALL, padding) 256 self.license = wx.TextCtrl(self, -1, '', size=(mbox,-1)) 257 inputs.Add(self.license, 0, wx.EXPAND|wx.ALL) 258 259 #Contact 260 label = wx.StaticText(self, -1, "Contact") 261 labels.Add(label, 0, wx.EXPAND|wx.ALL, padding) 262 self.contact = wx.TextCtrl(self, -1, '', size=(mbox,-1)) 263 inputs.Add(self.contact, 0, wx.EXPAND|wx.ALL) 264 ''' 265 266 #Buttons 267 hbox = wx.BoxSizer(wx.HORIZONTAL) 268 mainBox.Add(hbox) 269 hbox.AddSpacer((8, 16)) 270 271 hbox = wx.BoxSizer(wx.HORIZONTAL) 272 mainBox.Add(hbox) 273 hbox.AddSpacer((280, 10)) 274 self.btnCancel = wx.Button(self, wx.ID_CANCEL) 275 self.btnCancel.SetLabel('Cancel') 276 hbox.Add(self.btnCancel, 0, wx.EXPAND|wx.ALL, padding) 277 278 self.btnOK = wx.Button(self, wx.ID_OK) 279 self.btnOK.SetDefault() 280 self.btnOK.Disable() 281 self.btnOK.SetLabel('Add to queue') 282 hbox.Add(self.btnOK, 0, wx.EXPAND|wx.ALL, padding) 283 284 hbox = wx.BoxSizer(wx.HORIZONTAL) 285 mainBox.Add(hbox) 286 hbox.AddSpacer((8, 8)) 287 288 289 self.SetSizerAndFit(mainBox) 290 291 if parent.inputFile and os.path.exists(parent.inputFile): 292 self.selectVideoFile(parent.inputFile) 293 parent.inputFile = None 294 295 def OnClickVideoFile(self, event): 296 #transcoding later... 297 wildcard = "Video files|*.OGG;*.ogg;*.OGV;*.ogv;*.AVI;*.avi;*.mov;*.MOV;*.dv;*.DV;*.mp4;*.MP4;*.m4v;*.mpg;*.mpeg;*.wmv;*.MPG;*.flv;*.FLV|All Files (*.*)|*.*" 298 dialogOptions = dict() 299 dialogOptions['message'] = 'Add Video..' 300 dialogOptions['wildcard'] = wildcard 301 dialog = wx.FileDialog(self, **dialogOptions) 302 if dialog.ShowModal() == wx.ID_OK: 303 filename = dialog.GetFilename() 304 dirname = dialog.GetDirectory() 305 self.selectVideoFile(os.path.join(dirname, filename)) 306 else: 307 filename=None 308 dialog.Destroy() 309 return filename 310 311 def selectVideoFile(self, videoFile): 312 self.info = theoraenc.fileInfo(videoFile) 313 if self.info: 314 #FIXME: enable/disable options based on input 315 """ 316 if "video" in self.info: #source has video 317 #enable video options 318 if "audio" in self.info: #source has audio 319 #enable audio options 320 if "audio" in self.info: #source has audio 321 322 """ 323 self.videoFile = videoFile 324 lValue = videoFile 325 lLength = 45 326 if len(lValue) > lLength: 327 lValue = "..." + lValue[-lLength:] 328 self.btnVideoFile.SetLabel(lValue) 329 self.btnOK.Enable() 330 331 def CheckSubtitlesSelection(self, event): 332 idx=self.subtitles.GetFirstSelected() 333 if idx<0: 334 self.btnSubtitlesRemove.Disable() 335 self.btnSubtitlesProperties.Disable() 336 else: 337 self.btnSubtitlesRemove.Enable() 338 self.btnSubtitlesProperties.Enable() 339 self.subtitles.ResizeFilenameColumn() 340 341 def OnClickSubtitlesAdd(self, event): 342 self.subtitles.Append(['', '', '', '']) 343 if not self.ChangeSubtitlesProperties(self.subtitles.GetItemCount()-1): 344 self.subtitles.DeleteItem(self.subtitles.GetItemCount()-1) 345 self.subtitles.ResizeFilenameColumn() 346 347 def OnClickSubtitlesRemove(self, event): 348 while 1: 349 idx=self.subtitles.GetFirstSelected() 350 if idx<0: 351 break 352 self.subtitles.DeleteItem(idx) 353 self.CheckSubtitlesSelection(event) 354 355 def OnClickSubtitlesProperties(self, event): 356 idx=self.subtitles.GetFirstSelected() 357 if idx<0: 358 return 359 self.ChangeSubtitlesProperties(idx) 360 361 def ChangeSubtitlesProperties(self, idx): 362 language = self.subtitles.GetItem(idx, 0).GetText() 363 category = self.subtitles.GetItem(idx, 1).GetText() 364 encoding = self.subtitles.GetItem(idx, 2).GetText() 365 file = self.subtitles.GetItem(idx, 3).GetText() 366 result = addSubtitlesPropertiesDialog(self, language, category, encoding, file, self.hasIconv) 367 time.sleep(0.5) # why ? race condition ? 368 if result['ok']: 369 self.subtitles.SetStringItem(idx, 0, result['subtitlesLanguage']) 370 self.subtitles.SetStringItem(idx, 1, result['subtitlesCategory']) 371 self.subtitles.SetStringItem(idx, 2, result['subtitlesEncoding']) 372 self.subtitles.SetStringItem(idx, 3, result['subtitlesFile']) 373 return True 374 else: 375 return False 376 377 378def addVideoDialog(parent, hasKate, hasIconv): 379 dlg = AddVideoDialog(parent, -1, "Add Video", hasKate, hasIconv, size=(490, 560), style=wx.DEFAULT_DIALOG_STYLE) 380 dlg.CenterOnScreen() 381 val = dlg.ShowModal() 382 result = dict() 383 if val == wx.ID_OK: 384 result['ok'] = True 385 result['videoFile'] = dlg.videoFile 386 for key in ('width', 'height', 'videoquality', 'videobitrate', 'framerate', 387 'audioquality', 'audiobitrate', 'samplerate'): 388 result[key] = getattr(dlg, key).GetValue() 389 # subtitles 390 if dlg.subtitles: 391 for idx in range(dlg.subtitles.GetItemCount()): 392 if not 'subtitles' in result: 393 result['subtitles'] = [] 394 language = dlg.subtitles.GetItem(idx, 0).GetText() 395 category = dlg.subtitles.GetItem(idx, 1).GetText() 396 encoding = dlg.subtitles.GetItem(idx, 2).GetText() 397 file = dlg.subtitles.GetItem(idx, 3).GetText() 398 result['subtitles'].append({'encoding':encoding, 'language':language, 'category':category, 'file':file}) 399 else: 400 result['ok'] = False 401 dlg.Destroy() 402 return result 403if __name__ == "__main__": 404 import sys 405 class Frame(wx.Frame): 406 inputFile = None 407 def __init__(self): 408 wx.Frame.__init__(self, None, wx.ID_ANY, "add video test", size=(559,260)) 409 self.Show(True) 410 411 app = wx.PySimpleApp() 412 frame=Frame() 413 if len(sys.argv) > 1: 414 frame.inputFile = sys.argv[1] 415 result = addVideoDialog(frame, True) 416 print result 417 418