Oggとは
Oggの普及率?
WindowsでOggを楽しむには
OggVorbisを作る
OggVorbisデコーダを作る
OggVorbisエンコーダを作る
OggVorbisプレーヤーを作る
メモリ上のOgg Vorbisをデコードする
インターネット上のOgg Vorbisを再生する
関連リンク集
注意!以下、2010年以前のクッソ古い内容。って誰も見てないか・・・
最近流行りのOpusへの置き換えはopusfileを使えば簡単で、ov_???()をop_???()に変えれば良い(はず)
OggとはVorbis(非可逆圧縮)、FLAC(可逆圧縮)、Speex(音声向け)、等の入れ物のこと。
AVIファイルといっても非圧縮からDivXとかVP6とかCINEPAKがあるのと同じ。
まあ一般にOggといったらVorbisを指すけどね。(以下OggVorbisをOggと表記)
ライセンスフリーなので、私のような貧乏人や一部の方に人気ですね。
あとはライブラリの使いやすさです。私でもエンコード、デコードプログラム作れたし。
まあサンプルコード丸写しですが。
5年くらいになるんかな。SDKが出て。
実際のとこ、どれくらい普及してるんだろうか。
デジタルオーディオプレイヤーでもmp3とwmaはほとんど対応だろうけどOggはね。
PCで再生できる環境の人はどれくらいいるんだろうか?
結構音質良いのに。みんなmp3で満足なんだろうか?ただLAMEだと結構音いいからなあ。
せっかくだからOggを聴く方法を書いておきます。当方WinXPしかないんで他のOSはわからん。
ライブラリを自分でコンパイルすれば、どのOSでも(pc88+N88BASICでも)Oggを作れるはずだけど。
WindowsMediaPlayerでOggを聴くにはOggDSとかのDirectShowフィルタを入れればいいだけ。
ついでにDirectShowを使ったアプリでも聴けるようになります。(コーデックをインストールするとも言う。)
うちとしては、拙作のMusicPlayerを勧めます。もれなくエンコーダもついてくるしね。
聞く方法がわかっても肝心のoggがなけりゃどうにもなりませんね。
Oggを作るソフトっていってもそんなに無いけど。低ビットレート(96kbps以下?)ならaoTuVが良いですね。
配布されているエンコーダはコンソールだからバッチ処理もできるし。ただGUIな人は困るかも。
AudioEncoder(現在2.04d:開発停止)はもの凄く便利ですね。
ただ使ってるエンコードライブラリが古いのが難点。
それから問題点がいくつかあります。
0,前提として.netを入れる必要があります。
1,oggエンコードでクオリティを-1.00にすると尻切れをおこします。
2,WMP10を入れるとwmaに変換できなくなります。(回避方法はあるみたいです。)
他にもVectorからダウンロードできると思います。
私はデコードさえ出来ればかまわないので、vorbisfileを使います。
デコードに必要な関数はov_open , ov_read , ov_clearの3つだけです。だから私でも再生するだけなら出来ました。
ogg_static.lib, vorbis_static.lib, vorbisfile_static.libをリンクします。
デコードするプログラムです。SDK等に含まれるvorbisfile_example.cを少しいじっています。
使い方はコンパイルしてvdec <oggファイル >wavファイル です。
/*
vdec.c oggvorsisデコード
libogg,libvorbisの著作権はXiphophorusにあります。
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
#include <io.h>
#include <fcntl.h>
#include<windows.h>
//ライブラリのリンク
#pragma comment(lib , "ogg_static")
#pragma comment(lib , "vorbis_static")
#pragma comment(lib , "vorbisfile_static")
//wavファイルのヘッダ
typedef struct{
char RIFF[4];//"RIFF"
DWORD bytes;//(ファイルのバイト数)-8
char WAVE[4];// "WAVE"
char fmt[4];// "fmt "
DWORD siz_wf;//PCMWAVEFORMAT構造体のバイト数=常に16
//PCMWAVEFORMAT構造
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
char data[4];//"data"
DWORD pcmbytes;//波形データのバイト数
} WAVHEADER;
int main(){
OggVorbis_File vf;
vorbis_info *vi;
int ret = 0;
int current_section;
char pcmout[4096]; /* take 4k out of the data segment, not the stack */
WAVHEADER wh;
DWORD bytes;
DWORD pos = 0;
_setmode( _fileno( stdin ), _O_BINARY );
_setmode( _fileno( stdout ), _O_BINARY );
//ファイルを開く
if(ov_open(stdin, &vf, NULL, 0) < 0) {
fprintf(stderr,"Oggではありません\n");
exit(1);
}
//必要な情報を取得
vi=ov_info(&vf,-1);
bytes = vi->channels * 2 * ov_pcm_total(&vf,-1);
//wavヘッダを作る
memcpy(wh.RIFF , "RIFF" , 4);
wh.bytes = bytes + 44 - 8;
memcpy(wh.WAVE , "WAVE", 4);
memcpy(wh.fmt , "fmt ", 4);
wh.siz_wf = 16;
wh.wFormatTag = WAVE_FORMAT_PCM;//=1
wh.nChannels = vi->channels;
wh.nSamplesPerSec = vi->rate;
wh.wBitsPerSample = 16;
wh.nBlockAlign = wh.nChannels * wh.wBitsPerSample/8;
wh.nAvgBytesPerSec = wh.nSamplesPerSec * wh.nBlockAlign;
memcpy(wh.data , "data", 4);
wh.pcmbytes= bytes;
fwrite(&wh,44,1,stdout);//書き込む
//デコード
fprintf(stderr,"デコード中...\n");
do{
ret = ov_read(&vf,pcmout,sizeof(pcmout),0,2,1,¤t_section);
if (ret > 0) fwrite(pcmout,1,ret,stdout);
//進捗状況表示(無いほうがいいかも)
pos += ret;
fprintf(stderr,"%d / %d (%d%%)\r" , pos , bytes , pos/(bytes/100));
}while(ret != 0);
//後始末
ov_clear(&vf);
fprintf(stderr,"\n終わり\n");
return(0);
}
私はエンコードさえ出来ればかまわないので、vorbisencを使います。
中でどのようなことが行われているのかよく分からないので、サンプル丸写しです。
使い方はコマンドラインでvenc wavファイル oggファイルです。
エラーチェックはまったくといっていいほどしていません。
/*
* venc.c Ogg Vorbis エンコーダ
* libogg,libvorbisはXiph.orgに著作権があります。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include "vorbis/vorbisenc.h"
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#pragma comment(lib , "ogg_static")
#pragma comment(lib , "vorbis_static")
#pragma comment(lib , "vorbisenc_static")
#define READ 1024
//wavファイルのヘッダ
typedef struct{
char RIFF[4];//"RIFF"
DWORD bytes;//(ファイルのバイト数)-8
char WAVE[4];// "WAVE"
char fmt[4];// "fmt "
int siz_wf;//PCMWAVEFORMAT構造体のバイト数=常に16
//PCMWAVEFORMAT構造
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
char data[4];//"data"
DWORD pcmbytes;//波形データのバイト数
} WAVHEADER;
signed char readbuffer[READ*4+44]; /* out of the data segment, not the stack */
void usage()
{
fprintf(stderr , "venc 入力ファイル 出力ファイル");
exit(0);
}
int main(int argc,char**argv){
ogg_stream_state os; /* take physical pages, weld into a logical
stream of packets */
ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
ogg_packet op; /* one raw packet of data for decode */
vorbis_info vi; /* struct that stores all the static vorbis bitstream
settings */
vorbis_comment vc; /* struct that stores all the user comments */
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
vorbis_block vb; /* local working space for packet->PCM decode */
int eos=0,ret;
int i, founddata;
int ch , hz;
int n;
DWORD pos = 0;
FILE *infile , *outfile ;
WAVHEADER wh;
if(argc<3) usage();
infile = fopen(argv[1] , "rb");
outfile = fopen(argv[2] , "wb");
if(infile == NULL || outfile == NULL) usage();
fread(&wh , 1 , sizeof(WAVHEADER), infile);
ch = wh.nChannels;
hz = wh.nSamplesPerSec;
//エンコード情報
fprintf(stderr , "%s -> %s %dch %dHz\n" , argv[1] , argv[2] , ch , hz);
vorbis_info_init(&vi);
ret=vorbis_encode_init_vbr(&vi,ch,hz,.5);
if(ret)exit(1);
vorbis_comment_init(&vc);
vorbis_comment_add_tag(&vc,"ENCODER","encoder_example.c");
vorbis_analysis_init(&vd,&vi);
vorbis_block_init(&vd,&vb);
srand(time(NULL));
ogg_stream_init(&os,rand());
{
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
ogg_stream_packetin(&os,&header); /* automatically placed in its own
page */
ogg_stream_packetin(&os,&header_comm);
ogg_stream_packetin(&os,&header_code);
/* This ensures the actual
* audio data will start on a new page, as per spec
*/
while(!eos){
int result=ogg_stream_flush(&os,&og);
if(result==0)break;
fwrite(og.header,1,og.header_len,outfile);
fwrite(og.body,1,og.body_len,outfile);
}
}
fprintf(stderr , "エンコード中...\n");
while(!eos){
long i;
long bytes=fread(readbuffer,1,READ*4,infile); /* stereo hardwired here */
//進捗状況表示
pos += bytes;
fprintf(stderr , "%d / %d (%d%%)\r" , pos , wh.pcmbytes , pos/(wh.pcmbytes/100));
if(bytes==0){
/* end of file. this can be done implicitly in the mainline,
but it's easier to see here in non-clever fashion.
Tell the library we're at end of stream so that it can handle
the last frame and mark end of stream in the output properly */
vorbis_analysis_wrote(&vd,0);
}else{
/* data to encode */
/* expose the buffer to submit data */
float **buffer=vorbis_analysis_buffer(&vd,READ);
/* uninterleave samples */
for(i=0;i<bytes/(ch*2);i++){
for(n=0;n<ch;n++){
buffer[n][i]=((readbuffer[i*(ch*2)+n*2+1]<<8)|
(0x00ff&(int)readbuffer[i*(ch*2)+n*2]))/32768.f;
}
}
/* tell the library how much we actually submitted */
vorbis_analysis_wrote(&vd,i);
}
/* vorbis does some data preanalysis, then divvies up blocks for
more involved (potentially parallel) processing. Get a single
block for encoding now */
while(vorbis_analysis_blockout(&vd,&vb)==1){
/* analysis, assume we want to use bitrate management */
vorbis_analysis(&vb,NULL);
vorbis_bitrate_addblock(&vb);
while(vorbis_bitrate_flushpacket(&vd,&op)){
/* weld the packet into the bitstream */
ogg_stream_packetin(&os,&op);
/* write out pages (if any) */
while(!eos){
int result=ogg_stream_pageout(&os,&og);
if(result==0)break;
fwrite(og.header,1,og.header_len,outfile);
fwrite(og.body,1,og.body_len,outfile);
/* this could be set above, but for illustrative purposes, I do
it here (to show that vorbis does know where the stream ends) */
if(ogg_page_eos(&og))eos=1;
}
}
}
}
/* clean up and exit. vorbis_info_clear() must be called last */
ogg_stream_clear(&os);
vorbis_block_clear(&vb);
vorbis_dsp_clear(&vd);
vorbis_comment_clear(&vc);
vorbis_info_clear(&vi);
/* ogg_page and ogg_packet structs always point to storage in
libvorbis. They're never freed or manipulated directly */
fprintf(stderr,"\n終わり\n");
return(0);
}
実際に音が出ないと面白くないので、プレーヤーを作ってみました。windows専用です。 使い方は引数にogg vorbisのファイルを指定するだけです。 あとは勝手に再生します。途中でやめるときは[Ctrl]+[C]ですね。 デコード後のサイズが4096*100*10000バイトを超える場合、どうなるか分かりません。
/*
* ovp.c Ogg Vorbis プレイヤー
* libogg,libvorbisはXiph.orgに著作権があります。
*/
#include <windows.h>
#include <mmsystem.h>
#include <stdlib.h>
#include <math.h>
#include "vorbis/vorbisfile.h"
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"ogg_static.lib")
#pragma comment(lib,"vorbis_static.lib")
#pragma comment(lib,"vorbisfile_static.lib")
#define conv 4096
#define bufsiz (conv*100)
#define MAXBUF 10000
HWAVEOUT hwo;
char *buf[MAXBUF];
WAVEHDR *wh[MAXBUF];
OggVorbis_File vf;
int play, played,cleared, flag;
/* コールバック関数 */
void CALLBACK call( HWAVEOUT hwo, UINT msg,DWORD inst, DWORD p1, DWORD p2 ){
if (msg == WOM_DONE) played++;
}
/* デコード準備 */
int hajime(const char *filename)
{
FILE *fp;
int ret;
vorbis_info *vi;
WAVEFORMATEX wfe;
fp = fopen(filename, "rb");
if (fp == NULL) {
printf("ファイル[%s]開けません\n", filename);
return FALSE;
}
ret = ov_open(fp, &vf, NULL, 0);
if (ret < 0 ) {
printf("ov_open関数失敗\n");
return FALSE;
}
vi = ov_info(&vf,-1);
printf("再生ファイル=%s (%dHz %dch)\n再生時間=%d(秒) 平均ビットレート=%d(bps)\n",
filename, vi->rate, vi->channels, (int)ov_time_total(&vf, -1), vi->bitrate_nominal);
wfe.wFormatTag=WAVE_FORMAT_PCM;
wfe.nChannels=vi->channels;
wfe.wBitsPerSample=16;
wfe.nBlockAlign=wfe.nChannels * wfe.wBitsPerSample/8;
wfe.nSamplesPerSec=vi->rate;
wfe.nAvgBytesPerSec=wfe.nSamplesPerSec * wfe.nBlockAlign;
waveOutOpen(&hwo,WAVE_MAPPER,&wfe,(DWORD)call,0, WAVE_ALLOWSYNC | CALLBACK_FUNCTION);/* デバイスオープン */
dec();/* デコード開始 */
return TRUE;
}
/* デコード */
int dec()
{
int siz, read, current_section;
play = flag = 0;
do {
buf[play] = malloc(bufsiz+conv);
wh[play] = calloc(sizeof(WAVEHDR), 1);
siz = current_section = 0;
while (siz < bufsiz) {
read=ov_read(&vf,&buf[play][siz],conv,0,2,1,¤t_section);
if (read != 0) {
siz += read;
} else {
flag = 1; /* 終了のフラグ立てる */
break;
}
}
wh[play]->lpData = buf[play];
wh[play]->dwBufferLength = siz;
waveOutPrepareHeader (hwo,wh[play],sizeof(WAVEHDR));
waveOutWrite(hwo,wh[play],sizeof(WAVEHDR));/* 再生 */
while (fabs(play - played) > 1) Sleep(100);/* 待つ */
for (; cleared < played; cleared++) {/* バッファがあいていれば削除しておく */
waveOutUnprepareHeader (hwo,wh[cleared],sizeof(WAVEHDR));
free(buf[cleared]);
free(wh[cleared]);
}
play++;
} while (flag == 0 && play < MAXBUF);
while (play != played) Sleep(100);/* 再生終了まで待つ。*/
owari();/* 終わり*/
printf("終わり\n");
return TRUE;
}
/* 後始末する */
int owari()
{
for (;cleared < played ; cleared++) {
waveOutUnprepareHeader(hwo,wh[cleared],sizeof(WAVEHDR));
free(buf[cleared]);
free(wh[cleared]);
}
waveOutReset(hwo);
waveOutClose(hwo);
ov_clear(&vf);
return TRUE;
}
/* main関数 ここから。*/
main(int argc, char **argv)
{
if (argc < 2) {
puts("引数にogg vorbisファイルを入れましょう");
return 0;
}
hajime(argv[1]);
}
vorbisfileを使うと、簡単にメモリ上に展開されたOgg Vorbisを再生できるそうです。 私には大変難解でしたが、とりあえず出来てうれしかったので、書いておきます。 ov_openは、コールバック関数にfread,fseek, ftell,fclseを入れて、ov_open_callbacksを呼んでいるだけです。 だから、同じようにメモリ上のデータに対する関数を作ればメモリ上のデータをデコードできるわけです。 様々方法がありますが、私はFILEのように構造体(OVMEM)を使うことにしました。
使い方はDOS窓で ovmd oggファイル です。勝手にデコードしwavファイルを作ります。
/*
ovmd.c oggvorsisデコード(メモリ版)
libogg,libvorbisの著作権はXiphophorusにあります。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
#include <windows.h>
//ライブラリのリンク
#pragma comment(lib , "ogg_static")
#pragma comment(lib , "vorbis_static")
#pragma comment(lib , "vorbisfile_static")
//wavファイルのヘッダ
typedef struct{
char RIFF[4];//"RIFF"
DWORD bytes;//(ファイルのバイト数)-8
char WAVE[4];// "WAVE"
char fmt[4];//"fmt "
DWORD siz_wf;//PCMWAVEFORMAT構造体のバイト数=常に16
//PCMWAVEFORMAT構造
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
char data[4];//"data"
DWORD pcmbytes;//波形データのバイト数
} WAVHEADER;
typedef struct {
char *buf;//メモリ上のogg vorbis
int siz;//サイズ
int pos;//現在位置
} OVMEM;
//ファイル名(fnam)をmodeで開き OVMEM構造体にいれ、それをポインタで返す。
OVMEM *mopen(const char *fnam, char *mode)
{
FILE *fp;
int rsiz;
OVMEM *pom;
fp = fopen(fnam, mode);
if(fp == NULL) {
puts("mopen : fopenエラー");
return NULL;
}
pom = malloc(sizeof(OVMEM));
pom->pos = 0;
fseek(fp, 0, SEEK_END);
pom->siz = ftell(fp);
pom->buf = malloc(pom->siz);
rewind(fp);
rsiz =fread(pom->buf, 1, pom->siz, fp);
if (rsiz != pom->siz) {
puts("mopen : freadエラー 指定量を読み込めん");
return NULL;
}
fclose(fp);
return pom;
}
/* コールバック関数 以下4つ */
size_t mread(char *ptr, size_t size, size_t nmemb, OVMEM *pom)
{
if (pom == NULL) return -1;
if ((pom->pos >= pom->siz) || (pom->pos == -1)) return 0;
if (pom->pos + size*nmemb >= pom->siz) {
int ret;
memcpy(ptr, &pom->buf[pom->pos], pom->siz - pom->pos);
ret = (pom->siz - pom->pos)/size;
pom->pos = pom->siz;
return ret;
}
memcpy(ptr, &pom->buf[pom->pos], nmemb * size);
pom->pos += (nmemb * size);
return nmemb;
}
int mseek(OVMEM *pom, ogg_int64_t offset, int whence)
{
int newpos;
if (pom == NULL || pom->pos < 0) return -1;
if (offset < 0) {
pom->pos = -1;
return -1;
}
switch (whence) {
case SEEK_SET:
newpos = offset;
break;
case SEEK_CUR:
newpos = pom->pos + offset;
break;
case SEEK_END:
newpos = pom->siz + offset;
break;
default:
return -1;
}
if (newpos < 0) return -1;
pom->pos = newpos;
return 0;
}
long mtell(OVMEM *pom)
{
if (pom == NULL) return -1;
return pom->pos;
}
int mclose(OVMEM *pom)
{
if (pom == NULL) return -1;
free(pom->buf);
free(pom);
return 0;
}
// mainです。ここからスタート
main(int argc, char **argv)
{
OggVorbis_File vf;
vorbis_info *vi;
ov_callbacks oc;
FILE *of;
OVMEM *pom;
WAVHEADER wh;
DWORD bytes;
DWORD pos = 0;
int ret = 0;
int current_section;
char *buf;
char pcmout[4096]; //take 4k out of the data segment, not the stack
char outfile[MAX_PATH];//出力ファイル名
if (argc < 2) {
puts("引数無いよ。 ovmd 入力oggファイル (出力wavファイル)");
return ;
}
//コールバック関数を指定
oc.read_func = mread;
oc.seek_func = mseek;
oc.close_func = mclose;
oc.tell_func = mtell;
pom = mopen(argv[1], "rb");//argv[1]のファイルをメモリに展開
ret = ov_open_callbacks(pom, &vf, NULL, 0, oc);
switch (ret) {
case OV_EREAD:{printf("A read from media returned an error.\n");exit(1);}
case OV_ENOTVORBIS:{printf("Bitstream is not Vorbis data. \n");exit(1);}
case OV_EVERSION :{printf("Vorbis version mismatch. \n");exit(1);}
case OV_EBADHEADER:{printf("Invalid Vorbis bitstream header. \n");exit(1);}
case OV_EFAULT:{printf("Internal logic fault; indicates a bug or heap/stack corruption. \n");exit(1);}
}
//出力wavファイルを開く
if (argc > 2) {
if (!strcmp(&argv[2][strlen(argv[2])-4] , ".wav")) {
//お尻が.wavかな?
strcpy(outfile, argv[2]);
} else {
sprintf(outfile, "%s.wav", argv[2]);
}
} else {
sprintf(outfile, "%s.wav", argv[1]);
}
if ((of = fopen(outfile ,"wb")) == NULL) {
puts("出力ファイル開けん。エラーですよ");
return ;
}
vi=ov_info(&vf,-1);
bytes = vi->channels * 2 * ov_pcm_total(&vf, -1);
//wavヘッダを作る
memcpy(wh.RIFF , "RIFF" , 4);
wh.bytes = bytes + 44 - 8;
memcpy(wh.WAVE , "WAVE", 4);
memcpy(wh.fmt , "fmt ", 4);
wh.siz_wf = 16;
wh.wFormatTag = WAVE_FORMAT_PCM;//=1
wh.nChannels = vi->channels;
wh.nSamplesPerSec = vi->rate;
wh.wBitsPerSample = 16;
wh.nBlockAlign = wh.nChannels * wh.wBitsPerSample/8;
wh.nAvgBytesPerSec = wh.nSamplesPerSec * wh.nBlockAlign;
memcpy(wh.data , "data", 4);
wh.pcmbytes= bytes;
//ヘッダを書き込む
fwrite(&wh,44,1,of);
//デコード
printf("デコード中...\n");
do{
ret = ov_read(&vf,pcmout,4096,0,2,1,¤t_section);
if (ret > 0) fwrite(pcmout,1,ret,of);
pos += ret; printf("%d / %d\r", pos, bytes);
}while(ret != 0);
fclose(of);
//後始末
ov_clear(&vf);
printf("\n終わり\n");
return(0);
}
いわゆるストリーミング再生とは違うかもしれませんが、インターネット上にあるOgg Vorbisを再生するプログラムです。
/*
ovst.c インターネット上のoggvorsisを再生する。
libogg,libvorbisの著作権はXiphophorusにあります。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
#include<windows.h>
#include<wininet.h>
#include <mmsystem.h>
//ライブラリのリンク
#pragma comment(lib , "ogg_static")
#pragma comment(lib , "vorbis_static")
#pragma comment(lib , "vorbisfile_static")
#pragma comment(lib , "wininet")
#pragma comment(lib , "winmm")
#define conv 4096
#define bufsiz (conv*100)
#define MAXBUF 10000
typedef struct {
HINTERNET hINET;
HINTERNET hURL;
DWORD read;
} INET;
HWAVEOUT hwo;
char *buf[MAXBUF];
WAVEHDR *wh[MAXBUF];
OggVorbis_File vf;
int play, played,cleared, flag;
//URLを入れる
INET *iopen(const char *url)
{
HINTERNET hInternet;
HINTERNET hUrl;
INET *inet;
inet = malloc(sizeof(INET));
/* WININET初期化 */
hInternet = InternetOpen("Ogg Vorbis Streaming Test",INTERNET_OPEN_TYPE_PRECONFIG, NULL,NULL,0);
if(hInternet == NULL) return NULL;
/* URLのオープン */
hUrl = InternetOpenUrl(hInternet,url,NULL,0,0,0);
if(hUrl == NULL) return NULL;
inet->hINET = hInternet;
inet->hURL = hUrl;
inet->read = 0;
return inet;
}
/* コールバック関数 以下4つ */
size_t iread(char *ptr, size_t size, size_t nmemb, INET *inet)
{
int readsize, ret;
if (inet == NULL) return -1;
ret = InternetReadFile(inet->hURL, ptr, size*nmemb ,&readsize);
if (ret == FALSE) {
puts("InternetReadFileエラー");
exit(0);
}
if (readsize == 0) return 0;
inet->read += readsize;
return (readsize / size);
}
int iseek(INET *inet, ogg_int64_t offset, int whence)
{
return -1;//シーク不可能
}
long itell(INET *inet)
{
if (inet == NULL) return -1;
return inet->read;
}
int iclose(INET *inet)
{
if (inet == NULL) return -1;
InternetCloseHandle(inet->hURL);
InternetCloseHandle(inet->hINET);
free(inet);
return 0;
}
/* コールバック関数 */
void CALLBACK call( HWAVEOUT hwo, UINT msg,DWORD inst, DWORD p1, DWORD p2 ){
if (msg == WOM_DONE) played++;
}
/* デコード準備 */
int hajime(const char *filename)
{
int ret;
vorbis_info *vi;
WAVEFORMATEX wfe;
ov_callbacks oc;
INET *inet;
//コールバック関数を指定
oc.read_func = iread;
oc.seek_func = iseek;
oc.close_func = iclose;
oc.tell_func = itell;
inet = iopen(filename);
ret = ov_open_callbacks(inet, &vf, NULL, 0, oc);
switch (ret) {
case OV_EREAD:{printf("A read from media returned an error.\n");exit(1);}
case OV_ENOTVORBIS:{printf("Bitstream is not Vorbis data. \n");exit(1);}
case OV_EVERSION :{printf("Vorbis version mismatch. \n");exit(1);}
case OV_EBADHEADER:{printf("Invalid Vorbis bitstream header. \n");exit(1);}
case OV_EFAULT:{printf("Internal logic fault; indicates a bug or heap/stack corruption. \n");exit(1);}
}
vi=ov_info(&vf,-1);
printf("再生ファイル=%s (%dHz %dch)\n平均ビットレート=%d(bps)\n",
filename, vi->rate, vi->channels, vi->bitrate_nominal);
wfe.wFormatTag=WAVE_FORMAT_PCM;
wfe.nChannels=vi->channels;
wfe.wBitsPerSample=16;
wfe.nBlockAlign=wfe.nChannels * wfe.wBitsPerSample/8;
wfe.nSamplesPerSec=vi->rate;
wfe.nAvgBytesPerSec=wfe.nSamplesPerSec * wfe.nBlockAlign;
waveOutOpen(&hwo,WAVE_MAPPER,&wfe,(DWORD)call,0, WAVE_ALLOWSYNC | CALLBACK_FUNCTION);/* デバイスオープン */
dec();/* デコード開始 */
return TRUE;
}
/* デコード */
int dec()
{
int siz, read, current_section;
play = flag = 0;
do {
buf[play] = malloc(bufsiz+conv);
wh[play] = calloc(sizeof(WAVEHDR), 1);
siz = current_section = 0;
while (siz < bufsiz) {
read=ov_read(&vf,&buf[play][siz],conv,0,2,1,¤t_section);
if (read != 0) {
siz += read;
} else {
flag = 1; /* 終了のフラグ立てる */
break;
}
}
wh[play]->lpData = buf[play];
wh[play]->dwBufferLength = siz;
waveOutPrepareHeader (hwo,wh[play],sizeof(WAVEHDR));
waveOutWrite(hwo,wh[play],sizeof(WAVEHDR));/* 再生 */
/* バッファがあいていれば削除しておく */
for (; cleared < played; cleared++) {
waveOutUnprepareHeader (hwo,wh[cleared],sizeof(WAVEHDR));
free(buf[cleared]);
free(wh[cleared]);
}
play++;
} while (flag == 0 && play < MAXBUF);
while (play != played) Sleep(100);/* 再生終了まで待つ。*/
owari();
puts("終わり");
return TRUE;
}
/* 後始末する */
int owari()
{
for (;cleared < played ; cleared++) {
waveOutUnprepareHeader(hwo,wh[cleared],sizeof(WAVEHDR));
free(buf[cleared]);
free(wh[cleared]);
}
waveOutReset(hwo);
waveOutClose(hwo);
ov_clear(&vf);
return TRUE;
}
/* main関数 ここから。*/
main(int argc, char **argv)
{
if (argc < 2) {
puts("引数にOgg VorbisのURLをいれる。");
return 0;
}
hajime(argv[1]);
}
Xiph.org←oggとかvorbisの親玉。(英語)
aoTuV←最高音質のOgg Vorbisを生成可能。
vectorのOGGOGOダウンロードページ