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

j at svn.xiph.org j at svn.xiph.org
Wed Mar 28 11:02:59 PDT 2007


Author: j
Date: 2007-03-28 11:02:54 -0700 (Wed, 28 Mar 2007)
New Revision: 12816

Added:
   trunk/ffmpeg2theora/frontend/
   trunk/ffmpeg2theora/frontend/README
   trunk/ffmpeg2theora/frontend/Simple Theora Encoder.py
   trunk/ffmpeg2theora/frontend/Simple Theora Encoder.rsrc.py
   trunk/ffmpeg2theora/frontend/setup.macosx.py
Modified:
   trunk/ffmpeg2theora/ffmpeg2theora.c
   trunk/ffmpeg2theora/theorautils.c
   trunk/ffmpeg2theora/theorautils.h
Log:
- frontend mode that prints out stats in a way that can be parsed better.
- minimal PythonCard based frontend with encoding queue



Modified: trunk/ffmpeg2theora/ffmpeg2theora.c
===================================================================
--- trunk/ffmpeg2theora/ffmpeg2theora.c	2007-03-28 13:50:40 UTC (rev 12815)
+++ trunk/ffmpeg2theora/ffmpeg2theora.c	2007-03-28 18:02:54 UTC (rev 12816)
@@ -58,6 +58,7 @@
 #define INPUTFPS_FLAG       11
 #define AUDIOSTREAM_FLAG    12
 #define VHOOK_FLAG          13
+#define FRONTEND_FLAG       14
 
 #define V2V_PRESET_PRO 1
 #define V2V_PRESET_PREVIEW 2
@@ -285,7 +286,6 @@
         this->frame_rightBand=0;
         
         this->pix_fmt = PIX_FMT_YUV420P;
-        
     }
     return this;
 }
@@ -1099,6 +1099,7 @@
       {"endtime",required_argument,NULL,'e'},
       {"sync",0,&flag,SYNC_FLAG},
       {"optimize",0,&flag,OPTIMIZE_FLAG},
+      {"frontend",0,&flag,FRONTEND_FLAG},
 
       {"artist",required_argument,&metadata_flag,10},
       {"title",required_argument,&metadata_flag,11},
@@ -1154,6 +1155,10 @@
                             convert->quick_p = 0;
                             flag = -1;
                             break;
+                        case FRONTEND_FLAG:
+                            info.frontend = 1;
+                            flag = -1;
+                            break;
 #ifdef VIDEO4LINUX_ENABLED
                         case V4L_FLAG:
                             formatParams = malloc(sizeof(AVFormatParameters));
@@ -1453,7 +1458,12 @@
                 }
                 info.outfile = fopen(outputfile_name,"wb");
 #endif
-                dump_format (convert->context, 0,inputfile_name, 0);
+                if(info.frontend) {
+                  fprintf(stderr, "\nf2t ;duration: %d;\n", convert->context->duration / AV_TIME_BASE);                
+                }
+                else {
+                  dump_format (convert->context, 0,inputfile_name, 0);                  
+                }
                 if(convert->disable_audio){
                     fprintf(stderr,"  [audio disabled].\n");
                 }
@@ -1464,7 +1474,10 @@
                 convert->pts_offset = 
                     (double) convert->context->start_time / AV_TIME_BASE;
                 if(!info.outfile) {
-                    fprintf (stderr,"\nUnable to open output file `%s'.\n", outputfile_name);
+                    if(info.frontend)
+                        fprintf(stderr, "\nf2t ;result: Unable to open output file.;\n");                
+                    else
+                      fprintf (stderr,"\nUnable to open output file `%s'.\n", outputfile_name);
                     return(1);
                 }
                 if (convert->context->duration != AV_NOPTS_VALUE) {
@@ -1474,8 +1487,11 @@
                 convert->audio_index =convert->video_index = -1;
             }
             else{
-                fprintf (stderr,"\nUnable to decode input.\n");
-                return(1);
+              if(info.frontend)
+                  fprintf(stderr, "\nf2t ;result: input format not suported.;\n");                
+              else
+                  fprintf (stderr,"\nUnable to decode input.\n");
+              return(1);
             }
             av_close_input_file (convert->context);
         }
@@ -1486,9 +1502,11 @@
     ff2theora_close (convert);
     fprintf(stderr,"\n");
     
-    if (*pidfile_name) 
-    {
+    if (*pidfile_name)
         unlink(pidfile_name);
-    }
+    
+    if(info.frontend)
+        fprintf(stderr, "\nf2t ;result: ok;\n");                
+    
     return(0);
 }

Added: trunk/ffmpeg2theora/frontend/README
===================================================================
--- trunk/ffmpeg2theora/frontend/README	2007-03-28 13:50:40 UTC (rev 12815)
+++ trunk/ffmpeg2theora/frontend/README	2007-03-28 18:02:54 UTC (rev 12816)
@@ -0,0 +1,6 @@
+Simple Theora Encoder a PythonCard based cross platform GUI
+for ffmpeg2theora.
+
+for those that fear the command line
+
+FIXME: figure out how to get smaller binaries

Added: trunk/ffmpeg2theora/frontend/Simple Theora Encoder.py
===================================================================
--- trunk/ffmpeg2theora/frontend/Simple Theora Encoder.py	2007-03-28 13:50:40 UTC (rev 12815)
+++ trunk/ffmpeg2theora/frontend/Simple Theora Encoder.py	2007-03-28 18:02:54 UTC (rev 12816)
@@ -0,0 +1,213 @@
+#!/usr/bin/envpython
+
+"""
+__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, 
+                                  'This parametes 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()


Property changes on: trunk/ffmpeg2theora/frontend/Simple Theora Encoder.py
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/ffmpeg2theora/frontend/Simple Theora Encoder.rsrc.py
===================================================================
--- trunk/ffmpeg2theora/frontend/Simple Theora Encoder.rsrc.py	2007-03-28 13:50:40 UTC (rev 12815)
+++ trunk/ffmpeg2theora/frontend/Simple Theora Encoder.rsrc.py	2007-03-28 18:02:54 UTC (rev 12816)
@@ -0,0 +1,76 @@
+{'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
+} }

Added: trunk/ffmpeg2theora/frontend/setup.macosx.py
===================================================================
--- trunk/ffmpeg2theora/frontend/setup.macosx.py	2007-03-28 13:50:40 UTC (rev 12815)
+++ trunk/ffmpeg2theora/frontend/setup.macosx.py	2007-03-28 18:02:54 UTC (rev 12816)
@@ -0,0 +1,34 @@
+from distutils.core import setup
+from py2app.build_app import py2app
+
+import os
+import shutil
+
+class mypy2app(py2app):
+  def run(self):
+    py2app.run(self)
+    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))
+
+    imgPath = os.path.join(self.dist_dir, "Simple Theora Encoder.dmg")
+    os.system('''hdiutil create -srcfolder "%s" -volname "Simple Theora Encoder" -format UDZO "%s"''' %
+                (self.dist_dir, os.path.join(self.dist_dir, "Simple Theora Encoder.tmp.dmg")))
+    os.system('''hdiutil convert -format UDZO -imagekey zlib-level=9 -o "%s" "%s"''' %
+                (imgPath, os.path.join(self.dist_dir, "Simple Theora Encoder.tmp.dmg")))
+    os.remove(os.path.join(self.dist_dir,"Simple Theora Encoder.tmp.dmg"))
+
+setup(
+  app=['Simple Theora Encoder.py'],
+  name='Simple Theora Encoder',
+  options={'py2app': {
+	'strip': True,
+	'packages': ['PythonCard', 'wx']
+  }},
+  cmdclass = {'py2app': mypy2app }
+  
+)
+
+

Modified: trunk/ffmpeg2theora/theorautils.c
===================================================================
--- trunk/ffmpeg2theora/theorautils.c	2007-03-28 13:50:40 UTC (rev 12815)
+++ trunk/ffmpeg2theora/theorautils.c	2007-03-28 18:02:54 UTC (rev 12816)
@@ -43,6 +43,7 @@
 
 void init_info(oggmux_info *info) {
     info->with_skeleton = 0; /* skeleton is disabled by default	*/
+    info->frontend = 0; /*frontend mode*/
     info->videotime =  0;
     info->audiotime = 0;
     info->audio_bytesout = 0;
@@ -395,12 +396,21 @@
     int remaining_seconds = (long) remaining % 60;
     int remaining_minutes = ((long) remaining / 60) % 60;
     int remaining_hours = (long) remaining / 3600;
-    
-    fprintf (stderr,"\r      %d:%02d:%02d.%02d audio: %dkbps video: %dkbps, time remaining: %02d:%02d:%02d      ",
-         hours, minutes, seconds, hundredths,
-         info->akbps, info->vkbps,
-         remaining_hours, remaining_minutes, remaining_seconds
-         );
+    if(info->frontend) {
+        fprintf (stderr,"\nf2t ;position: %.02lf;audio_kbps: %d;video_kbps: %d;remaining: %.02lf\n",
+           timebase,
+           info->akbps, info->vkbps,
+           remaining
+           );
+      
+    }
+    else {
+      fprintf (stderr,"\r      %d:%02d:%02d.%02d audio: %dkbps video: %dkbps, time remaining: %02d:%02d:%02d      ",
+           hours, minutes, seconds, hundredths,
+           info->akbps, info->vkbps,
+           remaining_hours, remaining_minutes, remaining_seconds
+           );
+    }
 }
 
 static int write_audio_page(oggmux_info *info)

Modified: trunk/ffmpeg2theora/theorautils.h
===================================================================
--- trunk/ffmpeg2theora/theorautils.h	2007-03-28 13:50:40 UTC (rev 12815)
+++ trunk/ffmpeg2theora/theorautils.h	2007-03-28 18:02:54 UTC (rev 12816)
@@ -41,7 +41,7 @@
     int audio_only;
     int video_only;
     int with_skeleton;
-
+    int frontend;
     /* vorbis settings */
     int sample_rate;
     int channels;



More information about the commits mailing list