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ダウンロードページ