|
From: NAKAJIMA T. <nak...@ni...> - 2013-05-02 13:40:47
|
中島です。ご無沙汰しております。
gstreamerサンプル移植について、steppingフォルダにある
framestep1.cに挑戦しているのですが、どうしてもうまくいかないので、
助言いただければ幸いです。
このサンプルはvideotestsrcにappsinkをつないだパイプラインに
指定した数フレームの再生をかけるものですが、まずはpauseする
ことから始まります。
ところが、以下のコードでパイプラインのステートは3秒待っても
2(READY)までで、3(PAUSED)になってくれません。
◆コード
Gst.init
# create a new bin to hold the elements
bin = Gst::Pipeline.new("pipeline")
raise "'pipeline' gstreamer plugin missing" if bin.nil?
# create a fake source
videotestsrc = Gst::ElementFactory.make("videotestsrc", "videotestsrc")
raise "'videotestsrc' gstreamer plugin missing" if videotestsrc.nil?
videotestsrc.num_buffers = 10
# and a fake sink
appsink = Gst::ElementFactory.make("appsink", "appsink")
raise "'appsink' gstreamer plugin missing" if appsink.nil?
appsink.emit_signals = true
appsink.sync = true
appsink.signal_connect("new-preroll") do |appsink|
# signalled when a new preroll buffer is available
# buffer = appsink.signal_emit_by_name("pull-preroll")
buffer = appsink.pull_preroll
puts "have new-preroll buffer #{buffer}, timestamp #{buffer}"
Gst::FlowReturn::OK
end
# add objects to the main pipeline
bin << videotestsrc << appsink
# link the elements
videotestsrc >> appsink
# go to the PAUSED state and wait for preroll
puts "prerolling first frame"
bin.pause
#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
(全コードは
https://github.com/ted-n/ruby-gnome2/blob/stepping/gstreamer/sample/framestep1.rb
です)
◆実行結果
prerolling first frame
state: 2, pending: 2
オリジナルのCコードでは、get_stateの前にappsinkにnew-preroll
シグナルが入った後に、ステート3が返ってくるのですが、こちらの
Rubyコードではnew-prerollが入らないようで、このためステートが
変わらないのではと考えています。
appsinkの使い方が間違っているのでしょうか?
|
|
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の方を使って動くはずです!
|
|
From: Takashi N. <nak...@ni...> - 2013-05-04 14:16:22
|
中島です。 (2013年05月03日 20:46), Kouhei Sutou wrote: > これまた難しいやつでした! > masterで対応したのでpull --rebaseしてglib2と > gobject-introspectionをmakeしてください。今回の対応のために > これらも変更しています。 ありがとうございます、ブロックしなくなりました! ただちょっと問題があって... Cコードの方はpauseをかけたあと、当該の gst_element_get_state(bin, &state, &pending, -1) で state = 3(PAUSED), pending = 0(NULL) が返ってくるのに対して、Rubyコード state, pending = bin.get_state(Gst::CLOCK_TIME_NONE) では state = 1(READY), pending = 3(PAUSED) が返ってきます。 ただ、Gst.init "--gst-debug=4" としてINFO出力を見てみると、直前に notifying about state-changed READY to PAUSED (VOID_PENDING pending) が出ており、内部ではPAUSEDに遷移しているようです。 あと質問です。Gst::Eventにnew_stepコンストラクタがないようですが、 Gst::Event.new()の引数の型が合っていれば、new_stepを選択してくれる のでしょうか? |
|
From: Takashi N. <nak...@ni...> - 2013-05-04 16:22:59
|
中島です。連投失礼します。 GStreamerサンプルstepping(ファイルframestep1.c)の移植について、 先のメールで報告したstate値を除き、以下のコードでほぼ希望どおりに 動くようになったと思います。 https://github.com/ted-n/ruby-gnome2/blob/stepping/gstreamer/sample/framestep1.rb ただし、上記コードは私の環境では、終了時に以下のエラーメッセージが出てし まいます。 (framestep1.rb:16972): GStreamer-CRITICAL **: gst_mini_object_unref: assertion `mini_object->refcount > 0' failed (framestep1.rb:16972): GStreamer-CRITICAL **: gst_mini_object_unref: assertion `mini_object->refcount > 0' failed どこかでカウントがずれてるんでしょうか。 |
|
From: Kouhei S. <ko...@co...> - 2013-05-05 14:27:22
|
須藤です。 In <518...@ni...> "[ruby-gnome2-devel-ja] GStreamerサンプルsteppingで参照カウントエラーメッセージ" on Sun, 05 May 2013 01:22:47 +0900, Takashi Nakajima <nak...@ni...> wrote: > GStreamerサンプルstepping(ファイルframestep1.c)の移植について、 > 先のメールで報告したstate値を除き、以下のコードでほぼ希望どおりに > 動くようになったと思います。 > > https://github.com/ted-n/ruby-gnome2/blob/stepping/gstreamer/sample/framestep1.rb おぉ!ありがとうございます! pull requestおねがいします! > ただし、上記コードは私の環境では、終了時に以下のエラーメッセージが出てし > まいます。 > > (framestep1.rb:16972): GStreamer-CRITICAL **: gst_mini_object_unref: > assertion `mini_object->refcount > 0' failed > > (framestep1.rb:16972): GStreamer-CRITICAL **: gst_mini_object_unref: > assertion `mini_object->refcount > 0' failed > > どこかでカウントがずれてるんでしょうか。 あぁ、これは、send_eventで渡すeventがtransfer fullなのに今の Ruby/GObjectIntrospectionはtransferをなんにも考慮していない のでカウントがずれてしまうからですね。これは、 Ruby/GObjectIntrospectionの問題なのでこのサンプルはこれで大 丈夫です! |
|
From: Kouhei S. <ko...@co...> - 2013-05-05 15:19:02
|
須藤です。 In <201...@co...> "Re: [ruby-gnome2-devel-ja] GStreamerサンプルsteppingで参照カウントエラーメッセージ" on Sun, 05 May 2013 23:27:09 +0900 (JST), Kouhei Sutou <ko...@co...> wrote: >> ただし、上記コードは私の環境では、終了時に以下のエラーメッセージが出てし >> まいます。 >> >> (framestep1.rb:16972): GStreamer-CRITICAL **: gst_mini_object_unref: >> assertion `mini_object->refcount > 0' failed >> >> (framestep1.rb:16972): GStreamer-CRITICAL **: gst_mini_object_unref: >> assertion `mini_object->refcount > 0' failed >> >> どこかでカウントがずれてるんでしょうか。 > > あぁ、これは、send_eventで渡すeventがtransfer fullなのに今の > Ruby/GObjectIntrospectionはtransferをなんにも考慮していない > のでカウントがずれてしまうからですね。これは、 > Ruby/GObjectIntrospectionの問題なのでこのサンプルはこれで大 > 丈夫です! こっちも対応しておきました。 これで、前にバッファーだったか何かで、カウントが2以上で writableにならないみたいなやつも直ったはずです。 |
|
From: Takashi N. <nak...@ni...> - 2013-05-06 15:09:55
|
中島です。 (2013年05月05日 23:16), Kouhei Sutou wrote: > あ、これは、stateとpendingだけじゃなく、GstStateChangeReturn > も返っているのです。なので、 > > state_change_return, state, pending = bin.get_state(Gst::CLOCK_TIME_NONE) > > とすると期待した動きになります。 > > http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-state > > みたいに、Cで戻り値と出力引数があるときは > > [戻り値, 出力引数1, 出力引数2, ...] > > というのがRubyの戻り値になります。 すみません、勘違いしてました。参照カウントの方もエラーが出なくなったのを 確認しました。問題なさそうなので、pull requestさせていただきます。 ご確認ください。 |
|
From: Kouhei S. <ko...@co...> - 2013-05-07 12:29:41
|
須藤です。 In <518...@ni...> "Re: [ruby-gnome2-devel-ja] GStreamerサンプルsteppingのappsink使用方法について" on Tue, 07 May 2013 00:04:23 +0900, Takashi Nakajima <nak...@ni...> wrote: >> あ、これは、stateとpendingだけじゃなく、GstStateChangeReturn >> も返っているのです。なので、 >> >> state_change_return, state, pending = bin.get_state(Gst::CLOCK_TIME_NONE) >> >> とすると期待した動きになります。 >> >> http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-state >> >> みたいに、Cで戻り値と出力引数があるときは >> >> [戻り値, 出力引数1, 出力引数2, ...] >> >> というのがRubyの戻り値になります。 > > すみません、勘違いしてました。参照カウントの方もエラーが出なくなったのを > 確認しました。問題なさそうなので、pull requestさせていただきます。 ありがとうございます! 取り込みました! |
|
From: Kouhei S. <ko...@co...> - 2013-05-05 14:16:53
|
須藤です。 In <518...@ni...> "Re: [ruby-gnome2-devel-ja] GStreamerサンプルsteppingのappsink使用方法について" on Sat, 04 May 2013 23:12:46 +0900, Takashi Nakajima <nak...@ni...> wrote: >> masterで対応したのでpull --rebaseしてglib2と >> gobject-introspectionをmakeしてください。今回の対応のために >> これらも変更しています。 > > ありがとうございます、ブロックしなくなりました! よかったです! > ただちょっと問題があって... > Cコードの方はpauseをかけたあと、当該の > gst_element_get_state(bin, &state, &pending, -1) > で > state = 3(PAUSED), pending = 0(NULL) > が返ってくるのに対して、Rubyコード > state, pending = bin.get_state(Gst::CLOCK_TIME_NONE) > では > state = 1(READY), pending = 3(PAUSED) > が返ってきます。 あ、これは、stateとpendingだけじゃなく、GstStateChangeReturn も返っているのです。なので、 state_change_return, state, pending = bin.get_state(Gst::CLOCK_TIME_NONE) とすると期待した動きになります。 http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/GstElement.html#gst-element-get-state みたいに、Cで戻り値と出力引数があるときは [戻り値, 出力引数1, 出力引数2, ...] というのがRubyの戻り値になります。 > あと質問です。Gst::Eventにnew_stepコンストラクタがないようですが、 > Gst::Event.new()の引数の型が合っていれば、new_stepを選択してくれる > のでしょうか? はい!そうです! |