[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