[xiph-commits] r15541 - in trunk/ffmpeg2theora: . frontend frontend/theoraenc

j at svn.xiph.org j at svn.xiph.org
Sun Nov 30 12:43:04 PST 2008


Author: j
Date: 2008-11-30 12:43:03 -0800 (Sun, 30 Nov 2008)
New Revision: 15541

Added:
   trunk/ffmpeg2theora/frontend/theoraenc/
   trunk/ffmpeg2theora/frontend/theoraenc/__init__.py
   trunk/ffmpeg2theora/frontend/theoraenc/addVideoDialog.py
   trunk/ffmpeg2theora/frontend/theoraenc/theoraenc.py
Removed:
   trunk/ffmpeg2theora/frontend/Simple Theora Encoder.rsrc.py
Modified:
   trunk/ffmpeg2theora/
   trunk/ffmpeg2theora/frontend/README
   trunk/ffmpeg2theora/frontend/Simple Theora Encoder.py
   trunk/ffmpeg2theora/frontend/setup.macosx.py
Log:
replace PythonCard with wxPython,
expose options in add video dialog,
needs cleanup to look ok but should work.



Property changes on: trunk/ffmpeg2theora
___________________________________________________________________
Name: bzr:revision-info
   - timestamp: 2008-11-26 15:32:59.141999960 +0100
committer: j
properties: 
	branch-nick: ffmpeg2theora

   + timestamp: 2008-11-30 17:59:03.082000017 +0100
committer: j
properties: 
	branch-nick: ffmpeg2theora

Name: bzr:file-ids
   - src/ffmpeg2theora.c	6863 at 0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:ffmpeg2theora.c

   + frontend/README	12816 at 0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:frontend%2FREADME
frontend/Simple%20Theora%20Encoder.py	12816 at 0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:frontend%2FSimple%20Theora%20Encoder.py
frontend/setup.macosx.py	12816 at 0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:frontend%2Fsetup.macosx.py
frontend/theoraenc	theoraenc-20081128172332-ubnthv3396j4y78u-1
frontend/theoraenc/__init__.py	__init__.py-20081128172332-ubnthv3396j4y78u-2
frontend/theoraenc/addVideoDialog.py	addvideodialog.py-20081128172332-ubnthv3396j4y78u-3
frontend/theoraenc/theoraenc.py	theoraenc.py-20081128172332-ubnthv3396j4y78u-5

Name: bzr:text-parents
   - src/ffmpeg2theora.c	j-20081126135201-8y0orpwbdzn0doai

   + frontend/README	svn-v3-single1-dHJ1bmsvZmZtcGVnMnRoZW9yYQ..:0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:12816
frontend/Simple%20Theora%20Encoder.py	svn-v3-single1-dHJ1bmsvZmZtcGVnMnRoZW9yYQ..:0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:14574
frontend/setup.macosx.py	svn-v3-single1-dHJ1bmsvZmZtcGVnMnRoZW9yYQ..:0101bb08-14d6-0310-b084-bc0e0c8e3800:trunk%2Fffmpeg2theora:13641

Name: bzr:revision-id:v3-single1-dHJ1bmsvZmZtcGVnMnRoZW9yYQ..
   - 191 j-20080517230830-he5x8v2m8yrfiw35
192 j-20080518224037-pkmoctzf4qce7tog
193 j-20080518224409-6hbfp3k2ssn6egqa
194 j-20080520111939-dhi52qwbqe7a47cu
195 j-20080523092252-gj9k9db0s67vl7dw
196 j-20080523092420-l0850yrq1qkgz9t0
197 j-20080523093057-l5g0ezzy5geu0pey
198 j-20080523094343-kcno1dm2e1lr38q4
199 j-20080523163006-kjl6ewea5sxawmq2
200 j-20080523165904-l2vm52qae0hlqkhp
201 j-20080523175432-2ed953iktnl8c7cr
202 j-20080525100939-7oja8pk08v9fquiw
203 j-20080526111321-nhzaqh6ivzn0vs7b
204 j-20080527100851-2v5eyxxrq1riqi50
205 j-20080527101341-9ynbgth2b15jw792
206 j-20080527205556-19tffvfrxgt3khld
207 j-20080527205840-zeestdde3v1zks9k
208 j-20080527210129-e73y56uwmzbcid00
209 j-20080527211813-5ll680ed1q4byp16
210 j-20080528102006-aeippim0tn70mz3f
211 j-20080528104907-40kiidjojvta8j61
212 j-20080528111329-vkqbt7xkat2o9h4z
213 j-20080529102940-q9xdwm5v9espzomv
214 j-20080529111405-nmh99aon1kmh22qm
215 j-20080530094948-ncq064s4uggd9z95
216 j-20080530095056-hko2vjfwipikwjyu
217 j-20080530171822-bab8sy8lpotf8081
218 j-20080603170442-v0pxspvfcucvsaex
219 j-20080617110355-xwbeg1xidmv8fubp
220 j-20080617110518-khqlhaan52kz3lii
221 j-20080723194934-63m20dc3zmkhwj4o
222 j-20080724140108-ntgbrk6913nvtk4b
223 j-20080802221321-3fcp0s6rehryx0n5
224 j-20080802221340-0s6mh8llk6nyon5d
225 j-20080901112127-tyeax385hwukjt13
226 j-20080915075112-fg3yc8radbplosnc
227 j-20080921103515-w89p8jqwt3oq5u20
228 j-20080921103703-prnl3ls2f6u4g177
229 j-20080921104137-otk3xx827h5cofwl
230 j-20080921104242-dswny7jm93stokej
231 j-20081001102101-rl2rf1x9u8e5zrqk
232 j-20081001103246-0uwni13nt5b2mqyw
233 j-20081001104039-68e6rbv58e743plv
234 j-20081001111423-31lxb69fs7023eqi
235 j-20081001112345-eo9e3eheszd68pkb
236 j-20081002180939-vwdafec5iu2ihyq6
237 j-20081003143408-49wdpdkvhnf719rq
238 j-20081003153911-nh2fzqikxgbm7tuk
239 j-20081006092929-7kh3399r2tkat0x8
240 j-20081006120928-dqhlormykse02wss
241 j-20081010131634-o5sswtynyozb0dmb
242 j-20081010134449-4i1ak9vg1yv4ix53
243 j-20081010154655-55t7kuwhmo8964ya
244 j-20081010171055-w0wdhrrxucgdpvn1
245 j-20081016143100-chii7fl38ao2h6rd
246 j-20081105200328-iez493l5o7o333ae
247 j-20081105202607-3vjd88uf5rgna3pi
248 j-20081105204931-zah2kekajc2u9czu
249 j-20081110173803-i116mo4960rnmsqt
250 j-20081110173921-b79zigtpvfvowzd6
251 j-20081122150642-x51oi8he4clq62kw
252 j-20081126135201-8y0orpwbdzn0doai
253 j-20081126135947-3cs80yi3e2gyrup2
254 j-20081126143259-i8qw0ht9sdq2reu5

   + 191 j-20080517230830-he5x8v2m8yrfiw35
192 j-20080518224037-pkmoctzf4qce7tog
193 j-20080518224409-6hbfp3k2ssn6egqa
194 j-20080520111939-dhi52qwbqe7a47cu
195 j-20080523092252-gj9k9db0s67vl7dw
196 j-20080523092420-l0850yrq1qkgz9t0
197 j-20080523093057-l5g0ezzy5geu0pey
198 j-20080523094343-kcno1dm2e1lr38q4
199 j-20080523163006-kjl6ewea5sxawmq2
200 j-20080523165904-l2vm52qae0hlqkhp
201 j-20080523175432-2ed953iktnl8c7cr
202 j-20080525100939-7oja8pk08v9fquiw
203 j-20080526111321-nhzaqh6ivzn0vs7b
204 j-20080527100851-2v5eyxxrq1riqi50
205 j-20080527101341-9ynbgth2b15jw792
206 j-20080527205556-19tffvfrxgt3khld
207 j-20080527205840-zeestdde3v1zks9k
208 j-20080527210129-e73y56uwmzbcid00
209 j-20080527211813-5ll680ed1q4byp16
210 j-20080528102006-aeippim0tn70mz3f
211 j-20080528104907-40kiidjojvta8j61
212 j-20080528111329-vkqbt7xkat2o9h4z
213 j-20080529102940-q9xdwm5v9espzomv
214 j-20080529111405-nmh99aon1kmh22qm
215 j-20080530094948-ncq064s4uggd9z95
216 j-20080530095056-hko2vjfwipikwjyu
217 j-20080530171822-bab8sy8lpotf8081
218 j-20080603170442-v0pxspvfcucvsaex
219 j-20080617110355-xwbeg1xidmv8fubp
220 j-20080617110518-khqlhaan52kz3lii
221 j-20080723194934-63m20dc3zmkhwj4o
222 j-20080724140108-ntgbrk6913nvtk4b
223 j-20080802221321-3fcp0s6rehryx0n5
224 j-20080802221340-0s6mh8llk6nyon5d
225 j-20080901112127-tyeax385hwukjt13
226 j-20080915075112-fg3yc8radbplosnc
227 j-20080921103515-w89p8jqwt3oq5u20
228 j-20080921103703-prnl3ls2f6u4g177
229 j-20080921104137-otk3xx827h5cofwl
230 j-20080921104242-dswny7jm93stokej
231 j-20081001102101-rl2rf1x9u8e5zrqk
232 j-20081001103246-0uwni13nt5b2mqyw
233 j-20081001104039-68e6rbv58e743plv
234 j-20081001111423-31lxb69fs7023eqi
235 j-20081001112345-eo9e3eheszd68pkb
236 j-20081002180939-vwdafec5iu2ihyq6
237 j-20081003143408-49wdpdkvhnf719rq
238 j-20081003153911-nh2fzqikxgbm7tuk
239 j-20081006092929-7kh3399r2tkat0x8
240 j-20081006120928-dqhlormykse02wss
241 j-20081010131634-o5sswtynyozb0dmb
242 j-20081010134449-4i1ak9vg1yv4ix53
243 j-20081010154655-55t7kuwhmo8964ya
244 j-20081010171055-w0wdhrrxucgdpvn1
245 j-20081016143100-chii7fl38ao2h6rd
246 j-20081105200328-iez493l5o7o333ae
247 j-20081105202607-3vjd88uf5rgna3pi
248 j-20081105204931-zah2kekajc2u9czu
249 j-20081110173803-i116mo4960rnmsqt
250 j-20081110173921-b79zigtpvfvowzd6
251 j-20081122150642-x51oi8he4clq62kw
252 j-20081126135201-8y0orpwbdzn0doai
253 j-20081126135947-3cs80yi3e2gyrup2
254 j-20081126143259-i8qw0ht9sdq2reu5
255 j-20081130165903-33vl4qmpoayhhqw5


Modified: trunk/ffmpeg2theora/frontend/README
===================================================================
--- trunk/ffmpeg2theora/frontend/README	2008-11-27 00:25:49 UTC (rev 15540)
+++ trunk/ffmpeg2theora/frontend/README	2008-11-30 20:43:03 UTC (rev 15541)
@@ -1,6 +1,5 @@
-Simple Theora Encoder a PythonCard based cross platform GUI
+Simple Theora Encoder a wxPython based cross platform GUI
 for ffmpeg2theora.
 
 for those that fear the command line
 
-FIXME: figure out how to get smaller binaries

Modified: trunk/ffmpeg2theora/frontend/Simple Theora Encoder.py
===================================================================
--- trunk/ffmpeg2theora/frontend/Simple Theora Encoder.py	2008-11-27 00:25:49 UTC (rev 15540)
+++ trunk/ffmpeg2theora/frontend/Simple Theora Encoder.py	2008-11-30 20:43:03 UTC (rev 15541)
@@ -1,213 +1,201 @@
-#!/usr/bin/env python
-
-"""
-__version__ = "1.0"
-"""
-
-from PythonCard import model, dialog
-import wx
-
-import os
-from os.path import join, dirname, basename
-
-import thread
-
-
-"""
-  Format seconds
-"""
-def sec2time(seconds):
-  seconds = int(seconds)
-  minutes = int(seconds / 60)
-  seconds = seconds % 60
-  hours = int(minutes / 60)
-  minutes = minutes % 60
-  return "%02d:%02d:%02d" % (hours, minutes, seconds)
-
-
-class Encoder:
-  working = False
-  inputfile = ''
-  outputfile = ''
-  settings = "-p preview"
-  ffmpeg2theora_path = os.path.abspath(join(dirname(__file__), 'ffmpeg2theora'))
-  
-  def commandline(self):
-    cmd = "'%s' --frontend %s '%s'" % (self.ffmpeg2theora_path, self.settings, self.inputfile.replace("'", "\'"))
-    if self.outputfile:
-      cmd += " -o '%s'" % self.outputfile.replace("'", "\'")
-    cmd += " 2>&1"
-    return cmd
-    
-    
-  def encodeItem(self, item):
-    self.inputfile = self.queuedata[item]['path']
-    self.settings = self.queuedata[item]['settings']
-    itemID = self.queuedata[item]['itemID']
-    self.itemStatus(itemID, 'encoding...')
-    cmd = self.commandline()
-    f = os.popen(cmd)
-    line = f.readline()
-    info = dict()
-    while line:
-      if line.startswith('f2t'):
-        for o in line.split(';')[1:]:
-          oo = o.split(': ')
-          if len(oo) >= 2:
-            info[oo[0]] = ": ".join(oo[1:]).strip()
-        if info.has_key('position'):
-          encoded = "encoded %s/" % sec2time(float(info['position']))
-          if info.has_key('duration') and float(info['duration']):
-            encoded =  "% 3d %% done,  " % ((float(info['position']) / float(info['duration'])) * 100)
-          line = encoded + 'remaining: '+ sec2time(float(info['remaining']))
-        else:
-          line = "encoding.."
-        self.itemStatus(itemID, line)
-      line = f.readline()
-    f.close()
-    if info.get('result', 'no') == 'ok':
-      self.itemStatus(itemID, 'Done.')
-    else:
-      self.itemStatus(itemID, info.get('result', 'Failed.'))
-      
-  def encodeQueueThread(self):
-    self.working = True 
-    for key in self.queuedata:
-      if self.queuedata[key]['status'] != 'Done.':
-        self.encodeItem(key)
-    self.working = False
-    self.encodingFinished()
-    
-  def encodeQueue(self, queuedata, itemStatus, encodingFinished):
-    self.itemStatus = itemStatus
-    self.encodingFinished = encodingFinished
-    self.queuedata = queuedata
-    encoding_thread = thread.start_new_thread(self.encodeQueueThread, ())
-  
-
-
-class SimpleTheoraEncoderBackground(model.Background):
-    encoder = Encoder()
-    queuedata = {}
-    encodingQueueInitialized = False
-    
-    def on_initialize(self,event):
-        list = self.components.encodingQueue
-        list.InsertColumn(0, "Name")
-        list.InsertColumn(1, "Status")
-        pass
-
-    # so how much to wrap and how much to leave raw wxPython?
-    def initializeEncodingQueue(self, select = 0):
-        list = self.components.encodingQueue
-        list.Clear()
-        items = self.queuedata.items()
-
-        for x in range(len(items)):
-            key, item = items[x]
-            self.queuedata[key]['itemID'] = x
-            list.InsertStringItem(x, item['path'])
-            list.SetStringItem(x, 0, item['display_path'])
-            list.SetStringItem(x, 1, item['status'])
-            list.SetItemData(x, key)
-
-        list.SetColumnWidth(0, 180)
-        list.SetColumnWidth(1, 250)
-
-        list.SetItemDataMap(self.queuedata)
-
-        # show how to select an item
-        self.currentItem = select
-        if items:
-          list.SetItemState(self.currentItem, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
-
-        self.encodingQueueInitialized = True
-        self.components.encodeQueue.enabled = True
-        
-    def setItemStatus(self, itemID, value):
-      key = self.components.encodingQueue.GetItemData(self.currentItem)
-      self.queuedata[key]['status'] = value
-      self.components.encodingQueue.SetStringItem(itemID, 1, value)
-      
-    def addItemToQueue(self, input_path, settings):
-      list = self.components.encodingQueue
-      display_path = input_path
-      if len(display_path) > 26:
-        display_path = "..." + input_path[-23:]
-      
-      item = dict(
-        path = input_path, 
-        settings = settings,
-        display_path = display_path, 
-        status = 'waiting...                 ',
-        listID = 0
-      )
-      if self.encodingQueueInitialized:
-        x = list.GetItemCount()
-        if self.queuedata:
-          key = max(self.queuedata.keys()) + 1
-        else:
-          key = 1
-        item['itemID'] = x
-        self.queuedata[key] = item
-        list.InsertStringItem(x, item['path'])
-        list.SetStringItem(x, 0, item['display_path'])
-        list.SetStringItem(x, 1, item['status'])
-        list.SetItemData(x, key)
-      else:
-        key = 1        
-        self.queuedata[key] = item
-        self.initializeEncodingQueue()
-              
-    def on_addItem_mouseClick(self, event):
-      wildcard = "Video files|*.AVI;*.avi;*.OGG;*.ogg;*.mov;*.MOV;*.dv;*.DV;*.mp4;*.MP4;*.mpg;*.mpeg;*.wmv;*.MPG;*.flv;*.FLV|All Files (*.*)|*.*"
-      
-      result = dialog.fileDialog(self, 'Add Video..', '', '', wildcard )
-      if result.accepted:
-        for input_path in result.paths:
-          settings = '-p preview'
-          self.addItemToQueue(input_path, settings)
-    
-    def on_removeItem_mouseClick(self, event):
-      list = self.components.encodingQueue
-      print "remove", self.currentItem
-      key = self.components.encodingQueue.GetItemData(self.currentItem)
-      self.queuedata.pop(key)
-      self.initializeEncodingQueue(self.currentItem)
-
-    def on_editItem_mouseClick(self, event):
-      print "edit settings here"
-      list = self.components.encodingQueue
-      key = self.components.encodingQueue.GetItemData(self.currentItem)
-      result = dialog.textEntryDialog(self, 
-                                  'These parameters are passed to ffmpeg2theora adjust to your needs',
-                                  'Encoding Settings', 
-                                  self.queuedata[key]['settings'])
-      if result.accepted:
-        self.queuedata[key]['settings'] = result.text
-      
-    def on_encodeQueue_mouseClick(self, event):
-      self.components.addItem.enabled = False
-      self.components.editItem.enabled = False
-      self.components.removeItem.enabled = False
-      self.components.encodeQueue.enabled = False
-      self.encoder.encodeQueue(self.queuedata, self.setItemStatus, self.encodingFinished)
-      
-    def encodingFinished(self):
-      self.components.addItem.enabled = True
-      self.components.editItem.enabled = True
-      self.components.removeItem.enabled = True
-      self.components.encodeQueue.enabled = True
-      
-      
-    def on_encodingQueue_select(self, event):
-        self.currentItem = event.m_itemIndex
-        key = self.components.encodingQueue.GetItemData(self.currentItem)
-        print self.queuedata[key]
-        self.components.editItem.enabled = True
-        self.components.removeItem.enabled = True
-
-
-if __name__ == '__main__':
-    app = model.Application(SimpleTheoraEncoderBackground)
-    app.MainLoop()
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# vi:si:et:sw=2:sts=2:ts=2
+# Written 2007 by j at v2v.cc
+#
+# see LICENSE.txt for license information
+#
+__version__ = "1.0"
+
+import os
+from os.path import join, dirname, basename, abspath
+import sys
+import time
+import thread
+import xmlrpclib
+
+import wx
+try:
+  from xml.etree.ElementTree import Element, SubElement, ElementTree, parse
+except:
+  from elementtree.ElementTree import Element, SubElement, ElementTree, parse
+
+from theoraenc.addVideoDialog import addVideoDialog
+from theoraenc import theoraenc
+
+#overwrite location of resources in submodules
+if os.name != 'nt':
+  theoraenc.resourcePath = abspath(dirname(__file__))
+
+class SimpleTheoraEncoder(wx.Frame):
+  queuedata = {}
+  _qd_key = {}
+  encodingQueueInitialized = False
+  inputFile = False
+
+  def initMainInterface(self):
+    #TODO: addd menue
+    
+    self.encodingQueue = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
+    self.encodingQueue.SetPosition(wx.Point(15,50))
+    self.encodingQueue.SetSize(wx.Size(435, 165))
+    self.encodingQueue.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
+    
+    buttonSize = wx.Size(88,-1)
+    self.addItem = wx.Button(self, wx.ID_ANY, "Add...", wx.Point(462, 71), buttonSize)
+    self.Bind(wx.EVT_BUTTON, self.OnClickAdd, self.addItem)
+    
+    self.removeItem = wx.Button(self, wx.ID_ANY, "Remove", wx.Point(462, 106), buttonSize)
+    self.Bind(wx.EVT_BUTTON, self.OnClickRemove, self.removeItem)
+    self.removeItem.Disable()
+    
+    self.buttonQuit = wx.Button(self, wx.ID_ANY, "Quit", wx.Point(462, 187), buttonSize)
+    self.Bind(wx.EVT_BUTTON, self.OnExit, self.buttonQuit)
+    
+    #Title
+    self.title = wx.StaticText(self, -1, "Simple Theora Encoder", wx.Point(15, 10))
+    
+  def __init__(self, parent, id, title, inputFile=None):
+    wx.Frame.__init__(self, parent, id, title, size=(559,260))
+    self.inputFile = inputFile
+    self.initMainInterface()
+    self.Show(True)
+    
+    if self.addItem.IsEnabled:
+      self.OnClickAdd(None)
+
+  def initializeUploadQueue(self, selectItem = 0):
+      q = self.encodingQueue
+      q.ClearAll()
+      q.InsertColumn(0, "Name")
+      q.InsertColumn(1, "Stats")
+      q.SetColumnWidth(0, 195)
+      q.SetColumnWidth(1, 240)
+      
+      q.itemDataMap = self.queuedata
+      
+      items = self.queuedata.items()
+      for x in range(len(items)):
+        key, item = items[x]
+        self.queuedata[key]['itemID'] = x
+        self._qd_key[item['name']] = key
+        q.InsertStringItem(x, item['path'])
+        q.SetStringItem(x, 0, item['display_path'])
+        q.SetStringItem(x, 1, item['status'])
+        q.SetItemData(x, key)
+      
+      
+      # show how to select an item
+      self.currentItem = selectItem
+      if items:
+        q.SetItemState(self.currentItem, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
+      else:
+        self.removeItem.Disable()
+      self.encodingQueueInitialized = True
+  
+  def setItemStatus(self, itemID, value):
+    key = self.encodingQueue.GetItemData(itemID)
+    self.queuedata[key]['status'] = value
+    self.encodingQueue.SetStringItem(itemID, 1, value)
+  
+  def updateItemStatus(self, name, status):
+    try:
+      item = self.queuedata[self._qd_key[name]]
+    except KeyError:
+      return
+    itemID = item['itemID']
+    if item['status'] != status:
+      item['status'] = status
+      self.encodingQueue.SetStringItem(itemID, 1, status)
+    now = time.mktime(time.localtime())
+
+  def getSettings(self, options):
+    settings = []
+    for key in ('width', 'height'):
+      if key in options and options[key]:
+        settings.append('--%s' % key)
+        settings.append("%s" % int(options[key]))
+    for key in ('videoquality', 'audioquality'):
+      if key in options and options[key]:
+        settings.append('--%s' % key)
+        settings.append("%s" % float(options[key]))
+    return settings
+
+  def addItemThread(self, item):
+    if not item['enc'].encode():
+      print  "encoding failed"
+      return
+    return True
+  
+  def addItemToQueue(self, videoFile, options):
+    name = os.path.basename(videoFile)
+    display_path = videoFile
+    if len(display_path) > 25:
+      display_path = "..." + display_path[-24:]
+    item = dict(
+      path = videoFile, 
+      options = options,
+      display_path = display_path, 
+      status = 'encoding...           ',
+      listID = 0,
+      name = name,
+    )
+    item['enc'] = theoraenc.TheoraEnc(videoFile, None, lambda x: self.updateItemStatus(name, x))
+    item['enc'].settings = self.getSettings(options)
+
+    if self.encodingQueueInitialized:
+      x = self.encodingQueue.GetItemCount()
+      if self.queuedata:
+        key = max(self.queuedata.keys()) + 1
+      else:
+        key = 1
+      item['itemID'] = x
+      self.queuedata[key] = item
+      self.encodingQueue.InsertStringItem(x, item['path'])
+      self.encodingQueue.SetStringItem(x, 0, item['display_path'])
+      self.encodingQueue.SetStringItem(x, 1, item['status'])
+      self.encodingQueue.SetItemData(x, key)
+    else:
+      key = 1
+      self.queuedata[key] = item
+      self.initializeUploadQueue()
+    self._qd_key[name] = key
+    thread.start_new_thread(self.addItemThread, (item, ))
+
+  def OnItemSelected(self, event):
+    self.currentItem = event.m_itemIndex
+    self.removeItem.Enable()
+  
+  def OnClickAdd(self, event):
+    result = addVideoDialog(self)
+    time.sleep(0.5)
+    if result['ok']:
+      self.addItemToQueue(result['videoFile'], result)
+  
+  def OnClickRemove(self, event):
+    key = self.encodingQueue.GetItemData(self.currentItem)
+    print key
+    if 'enc' in self.queuedata[key]:
+      self.queuedata[key]['enc'].cancel()
+    del self.queuedata[key]
+    self.initializeUploadQueue(self.currentItem)
+
+  def OnExit(self, event):
+    for key in self.queuedata:
+      if 'enc' in self.queuedata[key]:
+        try:
+          self.queuedata[key]['enc'].cancel()
+        except:
+          pass
+    sys.exit()
+
+def gui(inputFile = None):
+  app = wx.PySimpleApp()
+  frame=SimpleTheoraEncoder(None, wx.ID_ANY, 'Simple Theora Encoder', inputFile = inputFile)
+  app.MainLoop()
+  
+if __name__ == '__main__':
+  inputFile = None
+  if len(sys.argv) > 1 and not sys.argv[1].startswith('-'):
+    inputFile = sys.argv[1]
+  gui(inputFile)

Deleted: trunk/ffmpeg2theora/frontend/Simple Theora Encoder.rsrc.py
===================================================================
--- trunk/ffmpeg2theora/frontend/Simple Theora Encoder.rsrc.py	2008-11-27 00:25:49 UTC (rev 15540)
+++ trunk/ffmpeg2theora/frontend/Simple Theora Encoder.rsrc.py	2008-11-30 20:43:03 UTC (rev 15541)
@@ -1,76 +0,0 @@
-{'application':{'type':'Application',
-          'name':'SimpleTheoraEncoder',
-    'backgrounds': [
-    {'type':'Background',
-          'name':'bgTemplate',
-          'title':'Simple Theora Encoder',
-          'size':(559, 260),
-          'style':['resizeable'],
-
-        'menubar': {'type':'MenuBar',
-         'menus': [
-             {'type':'Menu',
-             'name':'menuFile',
-             'label':'&File',
-             'items': [
-                  {'type':'MenuItem',
-                   'name':'menuFileExit',
-                   'label':'E&xit',
-                   'command':'exit',
-                  },
-              ]
-             },
-         ]
-     },
-         'components': [
-
-{'type':'Button', 
-    'name':'encodeQueue', 
-    'position':(462, 187), 
-    'enabled':False, 
-    'label':u'Encode...', 
-    },
-
-{'type':'Button', 
-    'name':'editItem', 
-    'position':(461, 104), 
-    'enabled':False, 
-    'label':u'Edit...', 
-    },
-
-{'type':'Button', 
-    'name':'removeItem', 
-    'position':(461, 136), 
-    'enabled':False, 
-    'label':u'Remove', 
-    },
-
-{'type':'Button', 
-    'name':'addItem', 
-    'position':(462, 71), 
-    'label':u'Add...', 
-    },
-
-{'type':'StaticText', 
-    'name':'title', 
-    'position':(15, 9), 
-    'font':{'faceName': u'Lucida Grande', 'family': 'sansSerif', 'size': 28}, 
-    'text':u'Simple Theora Encoder', 
-    },
-
-{'type':'MultiColumnList', 
-    'name':'encodingQueue', 
-    'position':(15, 49), 
-    'size':(431, 164), 
-    'backgroundColor':(255, 255, 255), 
-    'columnHeadings':[], 
-    'font':{'faceName': u'Lucida Grande', 'family': 'default', 'size': 12}, 
-    'items':[], 
-    'maxColumns':20, 
-    'rules':1, 
-    },
-
-] # end components
-} # end background
-] # end backgrounds
-} }

Modified: trunk/ffmpeg2theora/frontend/setup.macosx.py
===================================================================
--- trunk/ffmpeg2theora/frontend/setup.macosx.py	2008-11-27 00:25:49 UTC (rev 15540)
+++ trunk/ffmpeg2theora/frontend/setup.macosx.py	2008-11-30 20:43:03 UTC (rev 15541)
@@ -10,8 +10,8 @@
     print ">>>>> installing ffmpeg2theora <<<<<<"
     resourcesRoot = os.path.join(self.dist_dir, 'Simple Theora Encoder.app/Contents/Resources')
     shutil.copy('ffmpeg2theora', os.path.join(resourcesRoot, 'ffmpeg2theora'))
-    rsrc_file = "Simple Theora Encoder.rsrc.py"
-    shutil.copy(rsrc_file, os.path.join(resourcesRoot, rsrc_file))
+    #rsrc_file = "Simple Theora Encoder.rsrc.py"
+    #shutil.copy(rsrc_file, os.path.join(resourcesRoot, rsrc_file))
 
     imgPath = os.path.join(self.dist_dir, "Simple Theora Encoder.dmg")
     os.system('''hdiutil create -srcfolder "%s" -volname "Simple Theora Encoder" -format UDZO "%s"''' %
@@ -27,7 +27,6 @@
 	'strip': True,
 	'optimize': 2,
 	'iconfile': 'Simple Theora Encoder.icns',
-	'packages': ['PythonCard', 'wx'],
 	'plist': {'CFBundleIconFile': 'Simple Theora Encoder.icns'},
   }},
   cmdclass = {'py2app': mypy2app }

Added: trunk/ffmpeg2theora/frontend/theoraenc/__init__.py
===================================================================
--- trunk/ffmpeg2theora/frontend/theoraenc/__init__.py	                        (rev 0)
+++ trunk/ffmpeg2theora/frontend/theoraenc/__init__.py	2008-11-30 20:43:03 UTC (rev 15541)
@@ -0,0 +1 @@
+import theoraenc

Added: trunk/ffmpeg2theora/frontend/theoraenc/addVideoDialog.py
===================================================================
--- trunk/ffmpeg2theora/frontend/theoraenc/addVideoDialog.py	                        (rev 0)
+++ trunk/ffmpeg2theora/frontend/theoraenc/addVideoDialog.py	2008-11-30 20:43:03 UTC (rev 15541)
@@ -0,0 +1,281 @@
+# -*- coding: utf-8 -*-
+# vi:si:et:sw=2:sts=2:ts=2
+
+import os
+from os.path import basename
+import time
+
+import wx
+
+class AddVideoDialog(wx.Dialog):
+  def __init__(
+          self, parent, ID, title, size=wx.DefaultSize, pos=wx.DefaultPosition, 
+          style=wx.DEFAULT_DIALOG_STYLE,
+          ):
+    
+    self.videoFile = ''
+    
+    pre = wx.PreDialog()
+    #pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)
+    pre.Create(parent, ID, title, pos, size, style)
+    self.PostCreate(pre)
+
+    # Now continue with the normal construction of the dialog
+    padding = 4
+    section_padding=60
+
+    mainBox = wx.BoxSizer(wx.VERTICAL)
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.AddSpacer((8, 8))
+
+    #Video File
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.Add(wx.StaticText(self, -1, "Video File"), 0, wx.EXPAND|wx.ALL, 16)
+  
+    self.btnVideoFile = wx.Button(self, size=(380, -1))
+    self.btnVideoFile.SetLabel('Select...')
+    self.Bind(wx.EVT_BUTTON, self.OnClickVideoFile, self.btnVideoFile)
+    hbox.Add(self.btnVideoFile, 0, wx.EXPAND|wx.ALL, padding)
+
+    #Quality
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+
+    label = wx.StaticText(self, -1, "Video")
+    hbox.AddSpacer((12, 10))
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.AddSpacer((section_padding, 10))
+
+    label = wx.StaticText(self, -1, "Quality:")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.videoquality = wx.TextCtrl(self, -1, '5.0', size=(32,-1))
+    hbox.Add(self.videoquality, 0, wx.EXPAND|wx.ALL, padding)
+    label = wx.StaticText(self, -1, "Bitrate (kbps):")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.videobitrate = wx.TextCtrl(self, -1, '', size=(65,-1))
+    hbox.Add(self.videobitrate, 0, wx.EXPAND|wx.ALL, padding)
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.AddSpacer((section_padding, 10))
+       
+    #Size
+    box=45
+    label = wx.StaticText(self, -1, "Size:")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.width = wx.TextCtrl(self, -1, '', size=(65,-1))
+    hbox.Add(self.width, 0, wx.EXPAND|wx.ALL, padding)
+    label = wx.StaticText(self, -1, "x")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.height = wx.TextCtrl(self, -1, '', size=(65,-1))
+    hbox.Add(self.height, 0, wx.EXPAND|wx.ALL, padding)
+
+    #Framerate
+    label = wx.StaticText(self, -1, "Framerate:")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.framerate = wx.TextCtrl(self, -1, '', size=(40,-1))
+    hbox.Add(self.framerate, 0, wx.EXPAND|wx.ALL, padding)
+
+    #Crop
+    box=35
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.AddSpacer((section_padding, 10))
+    label = wx.StaticText(self, -1, "Crop:")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+
+    label = wx.StaticText(self, -1, "Top")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.cropTop = wx.TextCtrl(self, -1, '', size=(box,-1))
+    hbox.Add(self.cropTop, 0, wx.EXPAND|wx.ALL, padding)
+
+    label = wx.StaticText(self, -1, "Left")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.cropLeft = wx.TextCtrl(self, -1, '', size=(box,-1))
+    hbox.Add(self.cropLeft, 0, wx.EXPAND|wx.ALL, padding)
+
+    label = wx.StaticText(self, -1, "Bottom")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.cropBottom = wx.TextCtrl(self, -1, '', size=(box,-1))
+    hbox.Add(self.cropBottom, 0, wx.EXPAND|wx.ALL, padding)
+
+    label = wx.StaticText(self, -1, "Right")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.cropRight = wx.TextCtrl(self, -1, '', size=(box,-1))
+    hbox.Add(self.cropRight, 0, wx.EXPAND|wx.ALL, padding)
+
+    box=45
+
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    label = wx.StaticText(self, -1, "Audio")
+    hbox.AddSpacer((12, 10))
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+
+    #Quality & Bitrate
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.AddSpacer((section_padding, 10))
+    label = wx.StaticText(self, -1, "Quality:")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.audioquality = wx.TextCtrl(self, -1, '1.0', size=(32,-1))
+    hbox.Add(self.audioquality, 0, wx.EXPAND|wx.ALL, padding)
+
+    label = wx.StaticText(self, -1, "Bitrate (kbps):")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.audiobitrate = wx.TextCtrl(self, -1, '', size=(box,-1))
+    hbox.Add(self.audiobitrate, 0, wx.EXPAND|wx.ALL, padding)
+
+    #Samplerate / Channels
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.AddSpacer((section_padding, 10))
+    label = wx.StaticText(self, -1, "Samplerate (Hz)")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.samplerate = wx.TextCtrl(self, -1, '', size=(56,-1))
+    hbox.Add(self.samplerate, 0, wx.EXPAND|wx.ALL, padding)
+    label = wx.StaticText(self, -1, "Channels")
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.channels = wx.TextCtrl(self, -1, '', size=(24,-1))
+    hbox.Add(self.channels, 0, wx.EXPAND|wx.ALL, padding)
+
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+
+    '''
+    #Metadata
+    label = wx.StaticText(self, -1, "Metadata")
+    hbox.AddSpacer((12, 10))
+    hbox.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+
+    mbox=180
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    labels = wx.BoxSizer(wx.VERTICAL)
+    inputs = wx.BoxSizer(wx.VERTICAL)
+    hbox.AddSpacer((section_padding, 10))
+    hbox.Add(labels, 0, wx.ALIGN_RIGHT|wx.EXPAND|wx.ALL)
+    hbox.Add(inputs,0, wx.ALIGN_LEFT|wx.EXPAND|wx.ALL)
+
+    #Title
+    label = wx.StaticText(self, -1, "Title")
+    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.title = wx.TextCtrl(self, -1, '', size=(mbox,-1))
+    inputs.Add(self.title, 0, wx.EXPAND|wx.ALL)
+
+    #Artist
+    label = wx.StaticText(self, -1, "Artist")
+    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.artist = wx.TextCtrl(self, -1, '', size=(mbox,-1))
+    inputs.Add(self.artist, 0, wx.EXPAND|wx.ALL)
+
+    #date
+    label = wx.StaticText(self, -1, "Date", size=(mbox,-1))
+    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.date = wx.TextCtrl(self, -1, '', size=(mbox,-1))
+    inputs.Add(self.date, 0, wx.EXPAND|wx.ALL)
+
+    #Location
+    label = wx.StaticText(self, -1, "Location")
+    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.location = wx.TextCtrl(self, -1, '', size=(mbox,-1))
+    inputs.Add(self.location, 0, wx.EXPAND|wx.ALL)
+
+    #Organization
+    label = wx.StaticText(self, -1, "Organization")
+    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.organization = wx.TextCtrl(self, -1, '', size=(mbox,-1))
+    inputs.Add(self.organization, 0, wx.EXPAND|wx.ALL)
+
+    #Copyright
+    label = wx.StaticText(self, -1, "Copyright")
+    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.copyright = wx.TextCtrl(self, -1, '', size=(mbox,-1))
+    inputs.Add(self.copyright, 0, wx.EXPAND|wx.ALL)
+
+    #License
+    label = wx.StaticText(self, -1, "License")
+    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.license = wx.TextCtrl(self, -1, '', size=(mbox,-1))
+    inputs.Add(self.license, 0, wx.EXPAND|wx.ALL)
+
+    #Contact
+    label = wx.StaticText(self, -1, "Contact")
+    labels.Add(label, 0, wx.EXPAND|wx.ALL, padding)
+    self.contact = wx.TextCtrl(self, -1, '', size=(mbox,-1))
+    inputs.Add(self.contact, 0, wx.EXPAND|wx.ALL)
+    '''
+
+    #Buttons
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.AddSpacer((8, 16))
+
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.AddSpacer((280, 10))
+    self.btnCancel = wx.Button(self, wx.ID_CANCEL)
+    self.btnCancel.SetLabel('Cancel')
+    hbox.Add(self.btnCancel, 0, wx.EXPAND|wx.ALL, padding)
+
+    self.btnOK = wx.Button(self, wx.ID_OK)
+    self.btnOK.SetDefault()
+    self.btnOK.Disable()
+    self.btnOK.SetLabel('Encode')
+    hbox.Add(self.btnOK, 0, wx.EXPAND|wx.ALL, padding)
+
+    hbox = wx.BoxSizer(wx.HORIZONTAL)
+    mainBox.Add(hbox)
+    hbox.AddSpacer((8, 8))
+        
+
+    self.SetSizerAndFit(mainBox)
+    
+    if parent.inputFile and os.path.exists(parent.inputFile):
+      self.selectVideoFile(parent.inputFile)
+    parent.inputFile = None
+    
+  def OnClickVideoFile(self, event):
+    #transcoding later...
+    wildcard = "Video files|*.OGG;*.ogg;*.OGV;*.ogv;*.AVI;*.avi;*.mov;*.MOV;*.dv;*.DV;*.mp4;*.MP4;*.m4v;*.mpg;*.mpeg;*.wmv;*.MPG;*.flv;*.FLV|All Files (*.*)|*.*"
+    dialogOptions = dict()
+    dialogOptions['message'] = 'Add Video..'
+    dialogOptions['wildcard'] = wildcard
+    dialog = wx.FileDialog(self, **dialogOptions)
+    if dialog.ShowModal() == wx.ID_OK:
+      filename = dialog.GetFilename()
+      dirname = dialog.GetDirectory()
+      self.selectVideoFile(os.path.join(dirname, filename))
+    else:
+      filename=None
+    dialog.Destroy()
+    return filename
+  
+  def selectVideoFile(self, videoFile):
+        self.videoFile = videoFile
+        lValue = videoFile
+        lLenght = 45
+        if len(lValue) > lLenght:
+          lValue = "..." + lValue[-lLenght:]
+        self.btnVideoFile.SetLabel(lValue)
+        self.btnOK.Enable()
+
+def addVideoDialog(parent):
+  dlg = AddVideoDialog(parent, -1, "Add Video", size=(490, 560), style=wx.DEFAULT_DIALOG_STYLE)
+  dlg.CenterOnScreen()
+  val = dlg.ShowModal()
+  result = dict()
+  if val == wx.ID_OK:
+    result['ok'] = True
+    result['videoFile'] = dlg.videoFile
+    for key in ('width', 'height', 'videoquality', 'videobitrate', 'framerate',
+                'audioquality', 'audiobitrate', 'samplerate'):
+      result[key] = getattr(dlg, key).GetValue()
+    print result
+  else:
+    result['ok'] = False
+  dlg.Destroy()
+  return result

Added: trunk/ffmpeg2theora/frontend/theoraenc/theoraenc.py
===================================================================
--- trunk/ffmpeg2theora/frontend/theoraenc/theoraenc.py	                        (rev 0)
+++ trunk/ffmpeg2theora/frontend/theoraenc/theoraenc.py	2008-11-30 20:43:03 UTC (rev 15541)
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+# vi:si:et:sw=2:sts=2:ts=2
+
+import os
+from os.path import exists, join, dirname, abspath
+import time
+import sys
+import signal
+import subprocess
+
+resourcePath = abspath(dirname(__file__))
+
+def timestr(seconds):
+  hours   = int(seconds/3600)
+  minutes = int((seconds-( hours*3600 ))/60)
+  seconds = (seconds-((hours*3600)+(minutes*60)))
+  return '%02d:%02d:%02d' % (hours, minutes, seconds)
+
+class TheoraEnc:
+  settings = []
+  p = None
+  def __init__(self, inputFile, outputFile, updateGUI):
+    self.inputFile = inputFile
+    self.outputFile = outputFile
+    self.updateGUI = updateGUI
+    appname = 'ffmpeg2theora'
+    if os.name == 'nt':
+      appname = appname + '.exe'
+    self.ffmpeg2theora = join(resourcePath, appname)
+    if not exists(self.ffmpeg2theora):
+      self.ffmpeg2theora = appname
+  
+  def commandline(self):
+    cmd = []
+    cmd.append(self.ffmpeg2theora)
+    cmd.append('--frontend')
+    for e in self.settings:
+      cmd.append(e)
+    cmd.append(self.inputFile)
+    if self.outputFile:
+      cmd.append('-o')
+      cmd.append(self.outputFile)
+    return cmd
+  
+  def cancel(self):
+    if self.p:
+      print self.p.pid
+      p = self.p.pid
+      os.kill(p, signal.SIGTERM)
+      t = 2.5  # max wait time in secs
+      while self.p.poll() < 0:
+        if t > 0.5:
+          t -= 0.25
+          time.sleep(0.25)
+        else:  # still there, force kill
+          try:
+            os.kill(p, signal.SIGKILL)
+            time.sleep(0.5)
+            p.poll() # final try
+          except:
+            pass
+          break
+      #self.p.terminate()
+ 
+  def encode(self):
+    cmd = self.commandline()
+    print cmd
+    p = subprocess.Popen(cmd, shell=False, stderr=subprocess.PIPE, close_fds=True)
+    self.p = p
+    f = p.stderr
+    line = f.readline()
+    info = dict()
+    status = ''
+    while line:
+      if line.startswith('f2t'):
+        for o in line.split(';')[1:]:
+          oo = o.split(': ')
+          if len(oo) >= 2:
+            info[oo[0]] = ": ".join(oo[1:]).strip()
+        if 'position' in info:
+          if 'duration' in info and float(info['duration']):
+            encoded =  "encoding % 3d %% done " % ((float(info['position']) / float(info['duration'])) * 100)
+          else:
+            encoded = "encoded %s/" % timestr(float(info['position']))
+          if float(info['remaining'])>0:
+            status = encoded + '/ '+ timestr(float(info['remaining']))
+          else:
+            status = encoded
+        else:
+          status = "encoding.."
+        self.updateGUI(status)
+      line = f.readline()
+    f.close()
+    if info.get('result', 'no') == 'ok':
+      self.updateGUI('Encoding done.')
+      return True
+    else:
+      self.updateGUI(info.get('result', 'Encoding failed.'))
+      return False
+



More information about the commits mailing list