いものやま。

雑多な知識の寄せ集め

Ruby-FFIについて調べてみた。(その1)

ニコニコ動画のダウンロードツールを作ってみたものの、ちょっと不満点が。

それは何かと言うと、RTMPで配信されている動画をダウンロードする場合、

  • ダウンロードの進捗が細かく表示されない
  • ダウンロードの進捗度合いが分からない

というもの。

これは、ダウンロードにrtmpdumpを使っていて、

  • -qオプションをつけるないとログが大分うるさいので、-qオプションをつけてる
  • その場合、細かい進捗具合が表示されない
  • 何度かrtmpdumpを呼び出す必要があるので、そのタイミングで進捗具合を表示している
  • しかし、ファイル全体の最終的なサイズが分からないので、進捗度合いが表示できない

という理由から。

ただ、進捗具合をちゃんと表示できるようにすると、RTMPプロトコルに従って通信を行うプログラムを自前で書く必要が出てきて、それはかなり大変。
けど、rtmpdumpではlibrtmpというCインタフェースのライブラリが提供されているので、このライブラリを使えば、もう少し簡単に進捗度合いの表示の実現が出来るはず。

調べてみると、Ruby-FFIというのを使うと、比較的簡単にCインタフェースのライブラリをRubyから利用することが出来るようなので、これについて調べてみた。

Ruby-FFIとは

Ruby-FFIは、以下のページで公開されている。

インストール

Ruby-FFIのgemをインストールするには、次のようにする。

$ gem install ffi

なお、Ruby-FFIを使ってCライブラリを使う場合にはCコンパイラは不要なものの、Ruby-FFIをインストールするときにはCコンパイラが必要(なはず)なので、注意。

基本的な使い方

Ruby-FFIを使うときの基本的な流れは、次のような感じになる。

  1. 'ffi'をrequireする。
  2. 自作のモジュールをFFI::Libraryでextendする。
  3. FFI::Library#ffi_libで、ロードするライブラリを指定する
  4. Ruby-FFIで提供されている機能を使って、ライブラリとの結びつけを行う。
  5. ライブラリの機能を呼び出す。

簡単な例として挙げられているコードは、実際この流れになっている。

# 1. 'ffi'をrequireする。
require 'ffi'

module MyLib
  # 2. 自作のモジュールをFFI::Libraryでextendする。
  extend FFI::Library

  # 3. FFI::Libray#ffi_libで、ロードするライブラリを指定する。
  ffi_lib 'c'

  # 4. Ruby-FFIで提供されている機能を使って、
  #    ライブラリのインタフェースとの結びつけを行う。
  attach_function :puts, [ :string ], :int
end

# 5. ライブラリの機能を呼び出す。
MyLib.puts 'Hello, World using libc!'

結びつけを行うための機能

Ruby-FFIでは、Cライブラリのインタフェースとの結びづけを行うための機能をいくつか提供している。

具体的には、以下。

  • Cの標準的な型を表すシンボル
  • 構造体や共用体の記述
  • 列挙型の記述
  • グローバル変数の結びつけ
  • 関数の結びつけ

こういった機能によって、構造体の内部にアクセスしたり、ライブラリのグローバル変数(例えばerrnoなど)にアクセスしたり、ライブラリの関数を呼び出したりといったことが可能になる。

今日はここまで!