概要
Ogg と libogg について書く。Ogg フォーマットについては http://en.wikipedia.org/wiki/Ogg に本家ドキュメントよりもわかりやすい説明が図入りで書いてあるので、そちら参照。Ogg Vorbis と言えば mp3 に変わる音楽フォーマットとして要注目なんだけど、Ogg それ自体はバイナリの情報を細切れにして保存するだけの物。次のような専門用語がある。
- 物理ストリーム (physical bitstream)
- ひとつの ogg ファイル(またはバイト列)の事
- 論理ストリーム (logical bitstream)
- ひとつの物理ストリームには複数の論理ストリームが入ってる場合がある。
- ひとつの論理ストリームにひとつの音声や映像が入ってる。
- 音声と映像をまとめたファイルを作成出来る。
- ページ (page)
- 物理ストリームは複数のページで出来ている。
- ひとつのページはどれかの論理ストリームに属している。
- パケット (packet)
- ひとつのページには複数のパケットが入っている。
- パケットは、ページをまたぐ事もある。
- アプリケーションは、パケットごとにエンコード/デコードする。
libogg
Ogg の参照実装として、libogg が公開されている。libogg で使うおもな構造は以下の通り。
サンプル
サンプルとして、ogg をダンプするプログラムを作ってみる。
/* * Ogg file dump program. * $ cc -Wall -g -o oggdump -logg oggdump.c */ #include <stdio.h> #include <ogg/ogg.h> #define BUFSIZE 4096 int main(){ ogg_sync_state sync_state; /* ページの同期状態 */ ogg_stream_state stream_state; /* 論理ストリームの状態 */ ogg_page page; /* ページ */ ogg_packet packet; /* 生パケット */ int eos= 0; int initialized = 0; ogg_sync_init(&sync_state); /* 同期状態の初期化 */ while(!eos) { char * buffer= ogg_sync_buffer(&sync_state,BUFSIZE); /* 作業用バッファを取得する */ int bytes= fread(buffer, 1, BUFSIZE, stdin); /* 標準入力から作業用バッファに書き込み */ ogg_sync_wrote(&sync_state,bytes); /* ogg に渡したサイズを伝える */ if (bytes == 0) eos= 1; int result= ogg_sync_pageout(&sync_state,&page); /* ページ取り出し */ if (result == 0) continue; /* データ不足。さらに読み込み */ printf("serialno = %i, pageno = %li, packets = %i\n", ogg_page_serialno(&page), ogg_page_pageno(&page), ogg_page_packets(&page)); if (!initialized) { ogg_stream_init(&stream_state,ogg_page_serialno(&page)); /* 論理ストリームを初期化 */ initialized = 1; } /* ページからパケットを取り出す */ ogg_stream_pagein(&stream_state, &page); /* ページをパケットに分けておく */ while(1) { int result= ogg_stream_packetout(&stream_state,&packet); /* パケットを取り出す */ if (result == 0) break; /* もっとデータを読む */ if (result < 0) continue; /* データ不足。さらに読み込み */ printf("\tgranulepos = %lli, packetno = %lli, size = %li\n", packet.granulepos, packet.packetno, packet.bytes); } if(ogg_page_eos(&page)) eos= 1; } ogg_stream_clear(&stream_state); ogg_sync_clear(&sync_state); return 0; }