Tuesday, December 6, 2016

GStreamer でテキスト処理 1: Core機能だけで cat, cp, dd, & tee

1 はじめに

GStreamer は、パイプラインでエレメントを繋いでいく形でデーターを処理する、マルチメディアフレームワークです。この仕組み、Unix のパイプと似ていると思ったことはありませんか?

cat /tmp/a.txt | grep foo
echo foo | tee /tmp/a.txt
cat /tmp/a.txt /tmp/b.txt >> /tmp/c.txt

Doug McIlroy が述べたように Unix の Philosophy の1つに、"Write programs to handle text streams, because that is a universal interface." 「テキストのストリームを扱うプログラムを書こう。だってそれが共通のインターフェイスなのだから。」というのがあります。 Unix がテキストストリームを共通インターフェイスとしているパイプラインならば、GStreamer は GstBuffer を共通インターフェイスにしたパイプライン構造です。GStreamer は Multimedia Stream を扱うことに特化していますが、テキストもまたメディアデーターの1形態だとすれば テキストファイルも GStreamer でも扱えるはずです。

このシリーズでは、テキスト処理を題材に GStreamer Plugin の作成方法を紹介したいと思います。

第1回目は、おさらいという意味も含め Plugin を作成しなくてもできる cat と cp、dd、tee の紹介です。

2 cat & cp

  • cat a.txt

    gst-launch-1.0 -q filesrc location=a.txt ! fdsink
    

    最初は簡単に、a.txt を cat します。cat は指定されたファイルを標準出力に書き出します。GStreamer でファイルを指定するには filesrc を、標準出力を指定するには fdsink を使います。

  • cat a.txt | cat

    gst-launch-1.0 -q filesrc location=a.txt ! identity ! fdsink
    

    次は cat したデーターを cat に渡してみましょう。cat コマンドは、標準入力から受けたデーターをそのまま標準出力に書き出します。GStreamer では identity というエレメントがアップストリームから受けたデーターをそのままダウンストリームに渡します。identity はそのまま受け渡す以外にも いろいろ使える機能 が入っているので、マニュアルを確認してみると面白いです。

  • cat a.txt > b.txt; cp a.txt b.txt

    gst-launch-1.0 -q filesrc location=a.txt ! filesink location=b.txt
    

    今度は、リダイレクトしてみましょう。これは cp と同じ結果になります。標準出力ではなく、ファイルに書き出す場合は filesink を使います。

  • cat a.txt >> b.txt

    gst-launch-1.0 -q filesrc location=a.txt ! filesink append=true location=b.txt
    

    もちろん、追記も可能です。 filesink の append プロパティを true にします。

  • cat a.txt b.txt > c.txt

    gst-launch-1.0 -q concat name=c ! filesink location=c.txt  filesrc location=a.txt ! c.  filesrc location=b.txt ! c.
    

    cat コマンドは、複数のファイルを concat (連結) するところから名前が付きました。GStreamer にも concat するエレメントがあります。2つの filesrc で指定された a.txt と b.txt が concat エレメントによって1つになり c.txt に書き出されます。

  • cat *.txt > all

    gst-launch-1.0 -q splitfilesrc location='*.txt' ! filesink location=all
    

    いちいちファイルを指定するのが面倒なとき、よく wildcard 「*」を使いますよね? GStreamer でも可能です。splitfilesrc は「*」に対応しています。shellが「*」を展開しないように、シングルクオート「'」でくくってください。

  • cat a-01.txt a-02.txt a-03.txt > b.txt

    gst-launch-1.0 -q multifilesrc location=a-%02d.txt ! filesink location=b.txt
    

    もしファイルに連番が振られているなら multifilesrc が便利です。「%d」を使ってファイル名の連番部分を指定します。「%d」は printf() と同じ表記です。

  • cat a.txt > /dev/null

    gst-launch-1.0 -q filesrc location=a.txt ! fakesink
    

    出力を捨てたいときも良くありますよね。そんな時は /dev/null の代りに fakesink に捨てましょう。

  • cat /dev/null > a.txt

    gst-launch-1.0 -q fakesrc num-buffers=0 ! filesink location=a.txt
    

    逆にファイルを空っぽにしたいこともあります。そんな時は fakesrc を使うことができます。

3 dd

  • dd if=a.txt bs=1 count=1

    gst-launch-1.0 -q filesrc location=/tmp/a.txt blocksize=1 num-buffers=1 ! fdsink
    

    ddは cat と違いファイルの一部を取り出すときに良く使います。最初の1バイトだけ取り出したい時は blocksize を 1 にして num-buffers で一枚だけ取り出します。

  • dd if=/dev/zero bs=100 count=2

    gst-launch-1.0 -q fakesrc sizetype=fixed sizemax=100 num-buffers=2 ! filesink location=/tmp/a.txt
    

    ゼロ埋めされたファイルを作成するときも、dd は活躍します。200バイトのゼロ埋めされたファイルは、100バイトのバッファー2枚という指定でも作成できます。

4 tee

  • cat a.txt | tee b.txt

    gst-launch-1.0 filesrc location=/tmp/a.txt ! tee name=t t.src_0 ! queue ! fdsink  t.src_1 ! filesink location=/tmp/b.txt
    

    標準出力にもファイルにも書き出したいときに tee コマンドはとても便利です。GStreamer の tee エレメントは2ストリーム以上にも対応しているので、もっと多くの場所に同時に書き出すことも可能です。

5 おわりに

このように、テキストファイルも所詮データーなので、GstBuffer に格納すれば GStreamer のパイプラインを流すことが可能です。マルチメディアデーターとテキストデーターが違う点と言えば、処理をする単位が画像や映像のフレームや音のサンプル毎ではなく、「行」毎に処理をするという点です。 grep コマンドが行毎に検索することを考えても Unixコマンドは、行を基本単位として動いています。

GStreamer には「行」という概念がありません。正確には、フレームやサンプルという概念もなく、フレームに分けるパーサーエレメントがあるだけです。つまり行毎に分けるパーサーを作れば、テキストデーターを行毎に処理できるようになります。次回は、テキストデーターを行に分ける Plugin の作成から入ってみようと思います。

No comments:

Post a Comment