音轨压制 With FFmpeg & neroAacEnc —- 我的第二个 wxPython 程序(ffnraudio)

我的第二个在 Boa Constructor 下写的 wxPython 程序…

基本功能:
1, 拖入含音轨的媒体文件(任意格式), 列出音轨, 选中需要压制的音轨, 选择压缩选项, 然后单击”Go”即可开始压制.

***ChangeLog***
20100617 0.1a 发布

下载请移步: http://code.google.com/p/ffnraudio/downloads/list


以下是全部代码:

#Boa:Frame:Frame1
# -*- coding: utf-8 -*-

import wx
import re
import time
import sys, os
import threading
import subprocess

#if cmp(sys.platform[:3],'win')!=0:
#    reload(sys)
#    sys.setdefaultencoding('utf8')

f=[] #File List
fd=[] #File Duration List
s=[] #Stream List
sf=[] #Stream to File
arg = ''
arg2 = ''
fn = 0 #File Index

def create(parent):
    return Frame1(parent)

[wxID_FRAME1, wxID_FRAME1BUTTON1, wxID_FRAME1CHECKBOX1, wxID_FRAME1LISTBOX1, 
 wxID_FRAME1RADIOBUTTON1, wxID_FRAME1RADIOBUTTON2, wxID_FRAME1STATICTEXT1, 
 wxID_FRAME1TEXTCTRL1, wxID_FRAME1TEXTCTRL2, 
] = [wx.NewId() for _init_ctrls in range(9)]

class Frame1(wx.Frame):
    def _init_coll_flexGridSizer1_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.staticText1, 0, border=5, flag=wx.ALL)
        parent.AddWindow(self.textCtrl1, 1, border=5,
              flag=wx.GROW | wx.ALL | wx.EXPAND)
        parent.AddWindow(self.button1, 0, border=5, flag=wx.ALL)
        parent.AddWindow(self.checkBox1, 0, border=5, flag=wx.ALL)

    def _init_coll_flexGridSizer2_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.radioButton1, 0, border=5, flag=wx.ALL)
        parent.AddWindow(self.radioButton2, 0, border=5, flag=wx.ALL)
        parent.AddWindow(self.textCtrl2, 0, border=5, flag=wx.ALL)

    def _init_coll_boxSizer1_Items(self, parent):
        # generated method, don't edit

        parent.AddWindow(self.listBox1, 2, border=5,
              flag=wx.ALL | wx.GROW | wx.EXPAND)
        parent.AddSizer(self.flexGridSizer1, 0, border=0, flag=0)
        parent.AddSizer(self.flexGridSizer2, 0, border=0, flag=0)

    def _init_sizers(self):
        # generated method, don't edit
        self.boxSizer1 = wx.BoxSizer(orient=wx.VERTICAL)

        self.flexGridSizer1 = wx.FlexGridSizer(cols=0, hgap=0, rows=1, vgap=0)

        self.flexGridSizer2 = wx.FlexGridSizer(cols=0, hgap=0, rows=1, vgap=0)

        self._init_coll_boxSizer1_Items(self.boxSizer1)
        self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
        self._init_coll_flexGridSizer2_Items(self.flexGridSizer2)

        self.SetSizer(self.boxSizer1)

    def _init_ctrls(self, prnt):
        # generated method, don't edit
        wx.Frame.__init__(self, id=wxID_FRAME1, name='', parent=prnt,
              pos=wx.Point(766, 341), size=wx.Size(518, 349),
              style=wx.DEFAULT_FRAME_STYLE,
              title=u'\u97f3\u8f68\u538b\u5236 v0.1a - By Felix Yan')
        self.SetClientSize(wx.Size(518, 349))
        self.SetBackgroundColour(wx.Colour(222, 222, 222))
        self.Bind(wx.EVT_CLOSE, self.OnFrame1Close)

        self.listBox1 = wx.ListBox(choices=[], id=wxID_FRAME1LISTBOX1,
              name='listBox1', parent=self, pos=wx.Point(5, 5),
              size=wx.Size(508, 267), style=0)
        self.listBox1.Bind(wx.EVT_LISTBOX, self.OnListBox1Listbox,
              id=wxID_FRAME1LISTBOX1)

        self.staticText1 = wx.StaticText(id=wxID_FRAME1STATICTEXT1,
              label=u'\u8f93\u51fa\u6587\u4ef6\u540d:', name='staticText1',
              parent=self, pos=wx.Point(5, 282), size=wx.Size(69, 17), style=0)

        self.textCtrl1 = wx.TextCtrl(id=wxID_FRAME1TEXTCTRL1, name='textCtrl1',
              parent=self, pos=wx.Point(84, 282), size=wx.Size(160, 27),
              style=0, value=u'')

        self.button1 = wx.Button(id=wxID_FRAME1BUTTON1, label=u'Go',
              name='button1', parent=self, pos=wx.Point(254, 282),
              size=wx.Size(85, 27), style=0)
        self.button1.Bind(wx.EVT_BUTTON, self.OnButton1Button,
              id=wxID_FRAME1BUTTON1)

        self.checkBox1 = wx.CheckBox(id=wxID_FRAME1CHECKBOX1,
              label=u'\u964d\u52302.0\u58f0\u9053', name='checkBox1',
              parent=self, pos=wx.Point(349, 282), size=wx.Size(122, 22),
              style=0)
        self.checkBox1.SetValue(True)

        self.radioButton1 = wx.RadioButton(id=wxID_FRAME1RADIOBUTTON1,
              label=u'\u5b9a\u8d28\u91cf(-q)', name='radioButton1', parent=self,
              pos=wx.Point(5, 319), size=wx.Size(90, 21), style=0)
        self.radioButton1.SetValue(True)
        self.radioButton1.Bind(wx.EVT_RADIOBUTTON,
              self.OnRadioButton1Radiobutton, id=wxID_FRAME1RADIOBUTTON1)

        self.radioButton2 = wx.RadioButton(id=wxID_FRAME1RADIOBUTTON2,
              label=u'\u5b9a\u7801\u7387(-br)(\u5355\u4f4d:Kbps)',
              name='radioButton2', parent=self, pos=wx.Point(105, 319),
              size=wx.Size(191, 21), style=0)
        self.radioButton2.Bind(wx.EVT_RADIOBUTTON,
              self.OnRadioButton2Radiobutton, id=wxID_FRAME1RADIOBUTTON2)

        self.textCtrl2 = wx.TextCtrl(id=wxID_FRAME1TEXTCTRL2, name='textCtrl2',
              parent=self, pos=wx.Point(306, 319), size=wx.Size(80, 25),
              style=0, value=u'0.25')

        self._init_sizers()

    def __init__(self, parent):
        self._init_ctrls(parent)
        dt = MyFileDropTarget(self.listBox1)
        self.listBox1.SetDropTarget(dt)

    def OnFrame1Close(self, event):
        exit()

    def updateProgress(self, i):
        self.flag = self.progress.Update(i)
        
    def destroyProgress(self):
        self.flag = self.progress.Destroy()

    def OnButton1Button(self, event):
        global sf,f,s,arg,arg2,fn
        a = self.listBox1.GetSelections()[:]
        if len(a)>0:
            pstream = re.compile('\#(\d\.\d)')
            map=pstream.findall(s[a[0]/3].encode(sys.getfilesystemencoding()))[0].replace('.',':')
            if self.checkBox1.GetValue():
                ac = ' -ac 2 '
            else:
                ac = ' '
            if cmp(sys.platform[:3],'win')==0:
                path = "\\".join(f[sf[a[0]/3]].split("\\")[:-1]) + "\\"
            else:
                path = "/".join(f[sf[a[0]/3]].split("/")[:-1]) + "/"
            if self.radioButton1.GetValue():
                q='-q '+self.textCtrl2.GetValue().encode(sys.getfilesystemencoding())
            else:
                q='-br '+self.textCtrl2.GetValue().encode(sys.getfilesystemencoding())
            arg =  'ffmpeg -i \"' + f[sf[a[0]/3]].encode(sys.getfilesystemencoding()) + '\" -vn -f wav -map ' 
            arg += map + ac + '-'
            arg2 = 'neroAacEnc -ignorelength ' + q + ' -if - -of \"' + path.encode(sys.getfilesystemencoding()) + self.textCtrl1.GetValue().encode(sys.getfilesystemencoding()) +'\"'
            fn = a[0]/3
            #wx.MessageBox(arg)
            print arg
            self.progress = wx.ProgressDialog(u"Working...", u"正在压制音轨, 请稍候…", 100,  style=wx.PD_AUTO_HIDE)
            self.t = TRun(self)
            self.t.setDaemon(True)
            self.t.start()
        event.Skip()

    def OnListBox1Listbox(self, event):
        global sf,f
        a = self.listBox1.GetSelections()
        if len(a)>0:
            self.listBox1.SetSelection(a[0]/3*3+1)
            self.textCtrl1.SetValue('.'.join(f[sf[a[0]/3]].split("\\")[-1].split("/")[-1].split('.')[:-1])+'.m4a')
        event.Skip()

    def OnRadioButton1Radiobutton(self, event):
        self.textCtrl2.SetValue('0.25')
        event.Skip()

    def OnRadioButton2Radiobutton(self, event):
        self.textCtrl2.SetValue('64')
        event.Skip()

class BoaApp1(wx.App):
    def OnInit(self):
        self.main = create(None)
        self.main.Show()
        self.SetTopWindow(self.main)
        return True
    
class TRun(threading.Thread):
    def __init__(self, caller):
        threading.Thread.__init__(self)
        self.caller = caller
        self.flag = True

    def run(self):
        global arg,arg2,fd,fn
        import subprocess
        p = subprocess.Popen(args=arg, stdout=subprocess.PIPE, shell=True)
        p2 = subprocess.Popen(args=arg2, stdin=p.stdout, stderr = subprocess.PIPE, shell=True)
        r1 = re.compile('Processed\s(\d+)\ssecond')
        all = fd[fn]
        #print all
        ans = ''
        while p2.poll()==None:
            ans+=p2.stderr.read(100)
            #print ans
            #wx.MessageBox(ans)
            k = r1.findall(ans)
            if len(k)>0:
                #print int(float(k[-1])/all)
                wx.CallAfter(self.caller.updateProgress, int(float(k[-1])*100/all))
            time.sleep(0.01)
        
        wx.CallAfter(self.caller.destroyProgress)

class MyFileDropTarget(wx.FileDropTarget):
    def __init__(self, window):
        wx.FileDropTarget.__init__(self)
        self.window = window
    def OnDropFiles(self, x, y, filenames):
        global f,s,sf
        #print "\n%d file(s) dropped at (%d,%d):\n" % (len(filenames), x, y)
        for file in filenames:
            #file = file.decode(sys.getfilesystemencoding())
            #print file,sys.getfilesystemencoding()
            arg='ffmpeg -i \"'+file.encode(sys.getfilesystemencoding())+'\"'
            #print arg
            p = subprocess.Popen(args=arg,stderr=subprocess.PIPE, shell=True)
            a = p.communicate()[1]
            pd = re.compile("Duration:\s(\d\d)\:(\d\d)\:(\d\d)\.(\d\d)\,")
            b = a.split('Stream')
            d = pd.findall(b[0])
            fd.append(int(d[0][0])*60*60+int(d[0][1])*60+int(d[0][2]))
            f.append(file)
            for c in b[1:]:
                if c.find(': Audio:')>=0:
                    d = c.split('\n')
                    while len(d) <= 2:
                        d.append(' ')
                    s.append(file+'\n'+d[0]+'\n'+d[2])
                    sf.append(len(f)-1)
        k=[]
        for m in s:
            n = m.split('\n')
            for o in n:
                k.append(o)
                
        self.window.Set(k)
        return

def main():
    application = BoaApp1(0)
    application.MainLoop()

if __name__ == '__main__':
    main()

27 thoughts on “音轨压制 With FFmpeg & neroAacEnc —- 我的第二个 wxPython 程序(ffnraudio)”

  1. 对于windows 和linux文件\和/的区别,python有自己的系统来管理,我忘了是哪一个,你不用硬写的。仔细google一下。

  2. 看你在shlug里的发言了,所以到这里来看看。BOA这个东西比较老了吧。开发人员也不是很活跃。我还是比较倾向用gtk or PyQt.

      1. eric4是个传说。别信这种不成熟的IDE。直接用qt design 画界面,然后用 vim/emacs/eclipse/gedit 之类的写逻辑。

        1. 我对这个逻辑很郁闷,pyuic4貌似不能转含中文的.ui文件…
          还是想找类似VB6的开发方式,后来的都习惯不了

            1. 后来的各种方式都有尝试过. 用起来觉得没有VB6那样的方便, 仅此而已.
              另外, 反对以年龄论事.

  3. 不熟neo的软件。是把音频提出成wav, 然后再压成MP3?
    如果是,为什么不用lame 把wav 压成 mp3? lame是自由软件。

      1. 首先你的软件真的要有人用,最好先考虑清楚版权。lame之类的比较好的地方就是GPL的。你自己的软件如果是GPL的,你把lame放在一起用就可以了。现在你这个所谓跨平台,因为neo的打原因也只能在windows中用吧。

      2. AAC可以有很多自由软件压吧。handbrake, gstream应该也可以吧。这都是非常出名的自由软件。尤其gstream,现在几乎成了多媒体的底层标准。要多看前沿的东西啊。

          1. 你是有组织的人啊,那就当我没有说。不过也应该,跳开组织,有点自己的思考。

            1. 您说的几个都是用的faac,而faac是nero的前身.
              现在我在看aacplusenc,这个是另一个开源解决方案:)

  4. label 用 gettext 之类的localization 方案比较好。这样硬写进去不是很好。

Leave a Reply to Felix Yan Cancel reply

Your email address will not be published. Required fields are marked *

QR Code Business Card