wxPythonで自由工作:作品No.001
久々のPythonネタ!
と思ったら、GAEネタも書いてましたねそう言えば。
まあ、あれはカテゴリ別なんで無視です。
と言う訳で、久方ぶりのwxPythonです。
本日取り扱うのは、みんな大好きwx.media.MediaCtrlです。
要するに、メディアプレイヤーですね。
まあ、GUIを使って何か作ろうとしたとき、大抵は頭の隅をよぎる代物ではないかと思います。
世にどれだけのメディアプレイヤーが溢れているかなんて見向きもせずに。
いいんですけどね。
実際、作りたいというのが本音であって、実用的なものに昇華しようというのは二の次です。
さて。
そんな訳で、そういうことなんですが、その前に。
どんなものでもそうですが、マルチメディアを扱うというのは、準備段階から結構手間が掛かるものです。それが実利を求めるものなら、尚のこと。僕のように遊び半分で手を出す輩程度でも、それなりに面倒なことがあります。
では。
その面倒で手間のかかる準備から、僕の失敗談も交えつつ、話を始めましょう。
環境は、Ubuntu 10.10(amd64) minimal CDでのインストールですよ。
wxPythonのwx.media.MediaCtrlを使う準備:
世の中には実に様々な方がいらっしゃいましてですね、サンプルコードなんて探そうと思えば山のようにあるものなんです。
実際、僕の場合も苦もなくサンプルコードは見つけられました。
見つけること『は』できました。
ということは、そこで何かしらの問題があったということです。
第一の問題、それが旧バージョンにおける機能未実装です。
サンプルコードを実行したら、
Not Implement Error
とか出て止まる……。
何でプログラムすぐ止まってしまうん?
原因は、wxPythonのバージョンにありました。
Pythonインタプリタを起動して、
>>> import wx >>> wx.VERSION
としてみてください。(2, 8, 11, 0, '')とか出たら見事にアウトです!
やったね!キラッ☆
てな訳で、バージョンをアップしなければなりません。
ところで、Ubuntu10.10、すなわちmaverickではどのバージョンが使えるのか?
詳しくは、下記を参考にしてください。
wxPythonのWiki
基本、ここに書いてあること実行すればいいのです。
一例を。
% sudo apt-get install curl (インストールしてないのなら) % sudo apt-get remove --purge python-wxgtk2.8 python-wxtools wx2.8-i18n (古いものが入っていたら消す) % curl -x http://proxy.hogehoge:8080 http://apt.wxwidgets.org/key.asc | sudo apt-key add - (curlでプロキシを使うには、-xオプションで) % sudo vi /etc/apt/sources.list(ページ参考に編集を) % sudo apt-get update % sudo apt-get install python-wxgtk2.8 python-wxtools wx2.8-i18n
これで、バージョンが(2, 8, 12, 0, '')ならオッケーです。
さて。
これでめでたくwx.media.MediaCtrl()が使えるようになりましたかね?
おやおや?今度は別のエラーが出ているぞ?
このエラー量産機が……。
ああ、一応言っておきますよ。
僕のことではありません。
Got an invalid playbin
で。
これは、バックエンドのライブラリ不足が問題でした。
MediaCtrlは、WindowsならDirectShow、MacならQuickTime、LinuxならGStreamerをバックエンドで利用しているそうです。
つまり、wxPython単体の環境を揃えても、それらが整っていないとMediaCtrlが機能しないということです。
なので。
Ubuntuな僕は以下をインストールしときました。
% sudo apt-get install libgstreamer{-plugins-base0.10-0,0.10-0} gstreamer0.10-{alsa,fluendo-mp3,ffmpeg,nice,plugins-{base,bad,good},pulseaudio,tools,x}
これで、mp3やmp4ぐらいは再生できるようになります。
少なくとも、mp3の再生は確認済です。
ただし。
Linuxにおいては、(もしかしたらMacでも)wmaやwmvはこのままでは出来ません。
出きるようにしていないので何とも言えませんが、おそらくそれなりの設定やライブラリが必要になります。
なんたって、Windows Media AudioにWindows Media Videoだもの。
そんなこんなで。
大体、躓いたのはこんなところですね。
僕の場合は、これでサンプルコード動きました。
サンプルコード:
と言う訳で。
僕がちょっと手を加えた、けれどもほとんど参考にしたまんまのサンプルコードが以下です。
#!/usr/bin/python import wx import wx.media import os class MediaPlayerPanel(wx.Panel): def __init__(self, parent,id): wx.Panel.__init__(self,parent,-1,style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN) self.SetBackgroundColour("#BCFFCD") try: self.mc = wx.media.MediaCtrl(self, style=wx.SUNKEN_BORDER) except NotImplementedError: self.Destroy() raise # program exit. loadButton = wx.Button(self, wx.ID_ANY, "Load File") self.Bind(wx.EVT_BUTTON, self.onLoadFile, loadButton) playButton = wx.Button(self, wx.ID_ANY, "Play") playButton.SetToolTip(wx.ToolTip("load a file first")) # message when on mouse self.Bind(wx.EVT_BUTTON, self.onPlay, playButton) pauseButton = wx.Button(self, wx.ID_ANY, "Pause") pauseButton.SetToolTip(wx.ToolTip("press Play to resume")) self.Bind(wx.EVT_BUTTON, self.onPause, pauseButton) stopButton = wx.Button(self, wx.ID_ANY, "Stop") stopButton.SetToolTip(wx.ToolTip("also resets to start")) self.Bind(wx.EVT_BUTTON, self.onStop, stopButton) self.slider = wx.Slider(self, wx.ID_ANY, 1000000, 0, 1000000, size=(410, -1), style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS) self.slider.Bind(wx.EVT_SLIDER, self.onSeek) ext = "load .mp3 .mpg .mid .wav .wma .au or .avi files" self.st_info = wx.StaticText(self, wx.ID_ANY, ext, size=(300,-1)) sizer = wx.GridBagSizer(vgap=5, hgap=5) sizer.Add(loadButton, pos=(1,1)) sizer.Add(self.st_info, pos=(1,2), span=(1,2)) sizer.Add(self.slider, pos=(2,1), span=(2,3)) sizer.Add(playButton, pos=(4,1)) sizer.Add(pauseButton, pos=(4,2)) sizer.Add(stopButton, pos=(4,3)) # for .avi or .mpg video files use lower grid area sizer.Add(self.mc, pos=(5,1), span=(7,3)) self.SetSizer(sizer) self.timer = wx.Timer(self) self.Bind(wx.EVT_TIMER, self.onTimer) # update every 100 milliseconds self.timer.Start(100) def onLoadFile(self, evt): mask = "Media Files|*.mp3;*.mpg;*.mid;*.wav;*.au;*.avi|All (.*)|*.*" dlg = wx.FileDialog(self, message="Choose a media file (.mp3 .mpg .mid .wav .wma .au .avi)", defaultDir=os.getcwd(), defaultFile="", wildcard=mask, style=wx.OPEN|wx.CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() self.doLoadFile(path) dlg.Destroy() def doLoadFile(self, path): if not self.mc.Load(path): wx.MessageBox("Unable to load %s: Unsupported format?" % path, "ERROR", wx.ICON_ERROR|wx.OK) else: folder, self.filename = os.path.split(path) self.st_info.SetLabel(" %s" % self.filename) # set the slider range min to max self.slider.SetRange(0, self.mc.Length()) self.mc.Play() def onPlay(self, evt): self.slider.SetRange(0, self.mc.Length()) s1 = " %s" % self.filename s2 = " size: %s ms" % self.mc.Length() self.st_info.SetLabel(s1+s2) self.mc.Play() def onPause(self, evt): self.mc.Pause() def onStop(self, evt): self.mc.Stop() def onSeek(self, evt): """allows dragging the slider pointer to this position""" offset = self.slider.GetValue() self.mc.Seek(offset) def onTimer(self, evt): """moves the slider pointer""" offset = self.mc.Tell() self.slider.SetValue(offset) def main(): app = wx.PySimpleApp() frame = wx.Frame(None, -1, "play audio and video files", size = (500, 500)) MediaPlayerPanel(frame, -1) frame.Show(True) app.MainLoop() if __name__ == "__main__": main()
まあ、細かい説明は省きましょう。
プログラム載せたものだから、相当長い上に重い記事になってしまいましたし。
GitHubでも使えばいいんですかね?同じことかな?
ともかく。
シンプルなプレイヤーの一例です。この雛形さえあれば、後はカスタマイズし放題ですね。
イヤッフゥ!
あとがき:
ちなみに。
なんで、上記のサンプルコードがFrameではなくPanelなのかというと、その方が汎用性が高いと思うからです。
Notebookとかにも使えるし。
なので、僕は基本的にはPanel上でアプリケーションの作り込みをしています。
で、必要に応じて他プログラムでimportして使う。
そういう背景から、if __name__〜の記述があるという訳なのです。
こんな感じで。
今日はお暇させていただきます。