|
From: Kouhei S. <ko...@co...> - 2013-05-03 11:46:54
|
須藤です。
In <518...@ni...>
"[ruby-gnome2-devel-ja] GStreamerサンプルsteppingのappsink使用方法について" on Thu, 02 May 2013 22:30:53 +0900,
NAKAJIMA Takashi <nak...@ni...> wrote:
> gstreamerサンプル移植について、steppingフォルダにある
> framestep1.cに挑戦しているのですが、どうしてもうまくいかないので、
> 助言いただければ幸いです。
これまた難しいやつでした!
masterで対応したのでpull --rebaseしてglib2と
gobject-introspectionをmakeしてください。今回の対応のために
これらも変更しています。
以下、詳細です。
GStreamerは非同期だったり並列していろいろやるために、裏側で
こっそり別スレッドを立てて、必要ならそこで処理をしたりしてい
ます。そのため、GStreamerに登録したコールバックが別スレッド
から呼ばれることもあります。ただ、Rubyは自分で作ったスレッド
以外ではメソッドを呼んだりできません。呼び出すとクラッシュし
てしまいます。
そこで、旧Ruby/GStreamerではGStreamerから受け取ったコールバッ
クを一度Rubyのスレッドに投げてそこで処理した結果をまた
GStreamerに返す、ということをしていました。
が、新Ruby/GStreamerではそこらへんをがんばりきれていなくて、
今回の問題が発生していました。具体的には
get_state(Ruby) ->
get_state(GStreamer) ->
appsink.signal_emit("new-preroll")(GStreamerの別スレッド) ->
signal_connect("new-preroll")のブロック呼び出し(Ruby) ← ここでブロック
というように別スレッドからnew-prerollのコールバックが呼び出
されているところでブロックしていました。これは、Rubyの
GVL(Giant VM Lock)に関連しています。get_state(Ruby)のとこ
ろでロックをもったまま進んでいたのですが、その中で別の処理
(new-prerollのブロック)をしようとしていました。なので、そ
の別の処理もロックを取ろうとしてデットロックになっていました。
今回の対応では、get_state(GStreamer)を呼び出すときにGVLのロッ
クを外しました。これで、get_state(GStreamer)内でRubyのコード
が呼ばれるようになっても動くようになりました。
今回は、Gst::Element#get_state/set_state/query/send_eventはロッ
クを外して実行するようにしました。が、もしかしたら他にもロッ
クを外さないといけないやつがあるかもしれないので、またうまく
動かないやつがあったら教えてください!
> #bin.get_state(Gst::CLOCK_TIME_NONE)
> state, pending = bin.get_state(Gst::SECOND * 3)
> puts "state: #{state.to_i}, pending: #{pending.to_i}"
> exit 1 if state != Gst::State::PAUSED
今はNONEの方を使って動くはずです!
|