Table of Contents
1 はじめに
GstBuffer
が完結している場合は良いのですが、Parser を通す前だと、必要以上のデーターが入っていたり、逆に全然データーが足りない場合があります。そんな時に活躍するのが GstAdapter
です。今回は、このクラスを覗いてみましょう。
2 Adapt してくれる物
Adapter は、「Adapt する物」という意味です。 GstBuffer
を Adapt する、つまり要求に「合わせて」くれるクラスです。ここで言う GstBuffer
への要求とは、大きさ/サイズの変更です。
四の五の言わずに、さっそくサンプルコードを見てみましょう。
#include <gst/base/gstadapter.h> int main(int argc, char *argv[]) { GstAdapter *a; GstBuffer *b; gst_init(&argc, &argv); a = gst_adapter_new(); b = gst_buffer_new_allocate(NULL, 10, NULL); gst_adapter_push(a, b); b = gst_buffer_new_allocate(NULL, 5, NULL); gst_adapter_push(a, b); g_print("size: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a)); b = gst_adapter_take_buffer(a, 2); g_print("size: %" G_GSIZE_FORMAT ", buffer: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a), gst_buffer_get_size(b)); gst_adapter_flush(a, 3); g_print("size: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a)); gst_adapter_clear(a); g_print("size: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a)); return 0; }
$ gcc -Wall -Wextra -g $(pkg-config --cflags --libs gstreamer-base-1.0) a.c $ ./a.out size: 15 size: 13, buffer: 2 size: 10 size: 0
GstAdapter
には gst_adapter_push()
することで、バッファーを入れることができます。 GstBuffer
に入っているバッファーの総バイト数を gst_adapter_available()
することで取得できます。
入れたバッファーを取り出すには、 gst_adapter_take_buffer()
が便利です。 指定したバイト数入った GstBuffer
が貰えます。
他にも、 GstAdapter
の先頭から指定バイト数捨てる (flushする) gst_adapter_flush()
や、中に入っているすべてのデーターを捨ててしまう、 gst_adapter_clear()
があります。このあたりは、リファレンスマニュアルにも詳しく書いてあるので参考にしてください。
3 Take vs Get
GstAdapter
には take 系の関数群と get 系の関数群があります。
- take 系
gst_adapter_take()
gst_adapter_take_buffer()
gst_adapter_take_buffer_fast()
gst_adapter_take_list()
gst_adapter_take_buffer_list()
- get 系
gst_adapter_get_buffer()
gst_adapter_get_buffer_fast()
gst_adapter_get_list()
gst_adapter_get_buffer_list()
take でも get でも同じような意味なので、英語に慣れていないと、どっちがどっちなのか分らなくなりそうです。 英語では take の方が若干「奪う」意味が入ります。でも、オブジェクト指向で書いている時に getter として良く使うのは名前の通り get じゃないでしょうか?
GstAdapter
のメソッドでは、
take()
- 実際にデーターを Adapter から抜きとる
get()
- 実データーは Adapter に残したまま
になります。そうすると get()
した時には、何が帰ってくるのかというと、 GstAdapter
内にあるデーターのコピーです。実装上は、 戻ってくる GstBuffer
と GstAdapter
内にある GstMemory
がシェアーされている状態になります。または、 take()
の方は get()
した後に flush()
していると考えても良いかもしれません。
#include <gst/base/gstadapter.h> int main(int argc, char *argv[]) { GstAdapter *a; GstBuffer *b, *b1, *b2; gst_init(&argc, &argv); a = gst_adapter_new(); b1 = gst_buffer_new_allocate(NULL, 10, NULL); g_print("b1 %p\n", b1); b2 = gst_buffer_new_allocate(NULL, 20, NULL); gst_adapter_push(a, b1); gst_adapter_push(a, b2); g_print("size: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a)); b = gst_adapter_get_buffer(a, 5); g_print("size: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a)); g_print("b %p\n", b); b = gst_adapter_take_buffer(a, 5); g_print("size: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a)); g_print("b %p\n", b); return 0; }
$ gcc -Wall -Wextra -g $(pkg-config --cflags --libs gstreamer-base-1.0) take_vs_get.c $ ./a.out b1 0x55eb735c20b0 size: 30 size: 30 b 0x55eb735c22d0 size: 25 b 0x55eb735c23e0
GstBuffer
と GstMemory
の関係については、こちら を参照してください。
さて、take/get の関数ですが、リファレンスマニュアルにも記載があるので簡単にだけ。
take_buffer()
/get_buffer()
GstBuffer
を返します。take_buffer()
の場合は、GstAdapter
内からデーターを取り出してしまいます。take_buffer_fast()
/get_buffer_fast()
- 戻ってきた
GstBuffer
が複数のGstMemory
で構成されている可能性があります。つまりGstMemory
が merge されていません。大きなデーターになると merge する時間、つまりデーターコピーの時間が問題になることがあります。そのため_fast()
を使って merge されない状態でGstBuffer
を貰います。逆に言うとtake_buffer()
やget_buffer()
では merge されていることが保証されています。 take_list()
/get_list()
- 指定したバイト数分の
GstBuffer
がGList
に繋がれた状態で貰えます。take_buffer_fast()
のようにGstBuffer
内にGstMemory
が連なっているのではなく、GstMemory
がGList
に連なっているわけですね take_buffer_list()
/get_buffer_list()
GList
ではなく、~GstBufferList~ に繋がれた状態で貰えますtake()
- 生の takeメソッドです。戻り値はメモリーアドレスなので、読んだり書いたりできます。このタイプだけ生の
get()
はありません。理由は以下で。
用途に合わせて、どの getter を使うのか決めることができます。
4 map / unmap
GstAdapter
も GstBuffer
や GstMemory
と同じように map()
/ unmap()
メソッドを持っています。しかし、 map()
メソッドの使い方は GstBuffer
とは異なります。 map()
/ unmap()
は get()
の汎用型のメソッドになっています。
gconstpointer gst_adapter_map (GstAdapter *adapter, gsize size);
関数のシグネチャーから分る通り map()
は、指定した size
分のデーターが書込まれたメモリーアドレスを返してくれます。メモリアドレスは gconstpointer
で読み専用で、書き込む事はできません。
gst_adapter_take()
があるのに、 gst_adapter_get()
がない理由がこれです。 gst_adapter_map()
は gst_adapter_get()
に alias されていても良いですね。
メモリーを使い終ったら unmap()
してください。
#include <stdio.h> #include <gst/base/gstadapter.h> int main(int argc, char *argv[]) { GstAdapter *a; GstBuffer *b; char *buf; char const * p; GstMapInfo i; gst_init(&argc, &argv); a = gst_adapter_new(); buf = g_malloc0(10); sprintf(buf, "abc"); b = gst_buffer_new_wrapped(buf, 10); gst_adapter_push(a, b); g_print("size: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a)); p = gst_adapter_map(a, 4); g_print("%s\n", p); gst_adapter_unmap(a); g_print("size: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a)); b = gst_adapter_take_buffer(a, 4); gst_buffer_map(b, &i, GST_MAP_READ); g_print("%s\n", i.data); gst_buffer_unmap(b, &i); g_print("size: %" G_GSIZE_FORMAT "\n", gst_adapter_available(a)); return 0; }
$ gcc -Wall -Wextra -g $(pkg-config --cflags --libs gstreamer-base-1.0) map.c $ ./a.out size: 10 abc size: 10 abc size: 6
5 おわりに
Parser を作る時 に重宝する GstAdapter
を紹介しました。 GstBaseParse
でも実際に内部で使われています。 GstBaseParse
の子クラスで実装しなければいけない handle_frame()
メソッド に渡ってくる frame->buffer
は、実は gst_adapter_get_buffer()
したバッファーです。そう take_buffer()
じゃないんですね。 finish_frame()
した時にはじめて flush()
されるようになっています。
No comments:
Post a Comment