LoginSignup
2
2

More than 5 years have passed since last update.

wxRubyで重たい処理を別スレッドで処理しながら進捗を表示

Posted at

wxRubyのGUIからffmpegを呼び出してmp4の動画からmp3を抽出変換するサンプル。
わからないなりに頑張って書いたのでまずい所があれば教えて下さい。

困ったこと
1. まず単純にffmpegを呼び出すと処理が終わるまでGUIが固まる
→解決策:Threadを作る。

  1. 別スレッドからはメインスレッドのGUIに手を出せないのでステータスバーに進捗が表示できない。
    →解決策:Queueをつかって受け渡しする。
    (説明してるサイトには何故か別のThreadから直接GUIの部品を変更してたので、古いバージョンではそこらへん管理がされてないのかもしれない。)

  2. wxRubyはGUIがメインスレッドを強烈に縛って他のスレッドに処理をよこさないらしい。
    →解決策:Timerで定期的にsleepして強制的にCPUを明け渡す。

ffmpeg_encode.rb
require 'wx'
require 'thread'
class MyApp < Wx::App
  def on_init
    MyFrame.new.show
  end
end

class MyFrame < Wx::Frame
  def initialize
    super(nil, -1, "Thread Test")
    @status_bar = create_status_bar
    @q = Queue.new
    toolbar = Wx::ToolBar.new(self)
    toolbar.add_tool(Wx::ID_NEW, 'NEW', Wx::ArtProvider.bitmap(Wx::ART_NEW), 'Toolbar')
    toolbar.realize
    evt_tool(Wx::ID_NEW){|event| on_button_click(event)}
    self.set_tool_bar(toolbar)
    Wx::Timer.every(100) do
      if not @q.empty?
        @status_bar.set_status_text(@q.pop)
      end
      sleep 0.05
    end
  end
  def execute_ffmpeg(command)
    duration = 0
    IO.popen(command){|pipe|
      pipe.each{|line|
        if line =~ /Duration: (\d{2}):(\d{2}):(\d{2}).(\d+)/
          duration = (($1.to_i * 60 + $2.to_i) * 60 + $3.to_i) * 100 + $4.to_i
        end
        if line =~ /time=(\d{2}):(\d{2}):(\d{2}).(\d+)/
          time = ($1.to_i * 60*60 + $2.to_i * 60 + $3.to_i) * 100 + $4.to_i
          if  duration != 0
            @q.push "Encoding : ...#{time*100/duration}%"
          end
        end
      }
    }
    raise "Could not encode by ffmpeg!" if $?.exitstatus != 0
  end

  def on_button_click(event)
    command_ffmpeg = "ffmpeg -y -i input.mp4 -vn -ab 96k output.mp3 2>&1"
    t = Thread.new do
      execute_ffmpeg(command_ffmpeg)
    end
  end
end

MyApp.new.main_loop

あとffmpegは何故か出力結果を標準出力ではなく標準エラー出力に吐き出すので 2>&1 で標準出力に吐き戻させてる点に注意。

参考

wxRubyでThread使うときの注意事項 - 狼ニコ生うらやまけしからん日記 http://d.hatena.ne.jp/kesikaran/20100410/1270919896

Ruby for Scientific Research: Keeping wxRuby GUI Working with Threads http://rubyforscientificresearch.blogspot.jp/2009/11/keeping-wxruby-gui-working-with-threads.html

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2