"상용게임에 들어갈 mp3의 라이센스 비용이 걱정 되십니까?
Wave파일의 용량이 부담스러우시다구요? 그렇다면, 여기 Ogg Vorbis가 여러분의 고민을
해결해 드릴 것입니다 :)"
광고가 아닙니다 :) 게시판에서도 종종 보이는 mp3의 라이센스가 걱정스러운 회사라면,
Ogg Vorbis는 꽤나 쓸만한 녀석이 될 것 입니다. 저희 회사에서도, mp3대신 Ogg를 사용하려고
준비중에 있습니다. 들어가기에 앞서서 Ogg와 Ogg Vorbis에 대해서 설명해보죠.
Ogg Vorbis는 mp3와 같은 상용 오디오 포맷을 대체하기 위해서 나온, 공개 오디오 포맷 입니다.
최근에 이르러서야, 사용자도 늘어나고 있고, 국내외 최신게임들에서도 채택하고 있습니다.
같은 비트레이트의 음악일 경우, Ogg Vorbis쪽이 음질이 더 좋다고 해서, 좋은 음질로 음악을
듣고 싶으신 분들이 많이 찾는 것 같더군요.. 여하간 Ogg Vorbis는 Ogg 프로젝트의 하나인
공개 손실압축 오디오 포맷 프로젝트 입니다. http://www.ogg.org(Ogg공식 홈페이지)를
방문하시면, 다른 프로젝트들도 보실 수 있습니다. 음성전용 포맷이나 인터넷방송용 프로젝트도
보이더군요.
----------------
1. 우선 Ogg Vorbis 포맷을 가지고 놀기위해서는, SDK를 설치해야 합니다. SDK는 현재 1.0이
최신 버전인듯 하구요. Ogg Vorbis의 공식 홈페이지(http://www.vorbis.com)에서 다운
받으실 수 있습니다. SDK받으시는 김에 Ogg Vorbis인코더/디코더가 없으신 분들은
OggDropXPd라는 녀석도 같이 받아놓으시면, 편리 합니다.
2. SDK는 압축 풀어놓으시고, Visual C++을 셋팅해야 합니다.
Tools -> Options -> Directories에서 라이브러리와 인쿨루드에 아까 압축 풀어놓은 SDK폴더
내에 해당 폴더를 지정해주시면 됩니다.
3. 다음에는 라이브러리 링크 입니다. SDK폴더안에 lib폴더에 보시면, lib파일들이 있습니다.
하나 예로들면, ogg.lib ogg_d.lib ogg_static.lib ogg_static_d.lib 이렇게 됩니다.
_d 가 붙은 녀석은 디버그전용 입니다. 릴리즈버전에는 _d가 없는 녀석을 선택해주면 되구요.
static이 붙은 녀석은 설명할 필요도 없이 정적라이브러리입니다. dll파일은 bin폴더에 있으니
동적라이브러리 사용하실 분들은 그렇게 하시구요 :)
** 우리가 링크할 라이브러리는 ogg_static.lib vorbis_static.lib vorbisfile_static.lib 이렇게
세개입니다. 저는 정적라이브러리를 사용 했습죠.
#include "vorbis/codec.h" #include "vorbis/vorbisfile.h"
헤더도 잊지 마세요 :)
4.Ogg Vorbis 파일 오픈
을 해보죠. 저는 vorbisfile이라는 고수준입출력라이브러리를 사용했습니다. 저수준입출력라이브러리
도 있던데, 설명이 전혀 안돼있더군요-_-;
//OggVorbis 파일 구조체 선언
OggVorbis_File vf;
//Ogg파일을 Open
FILE * File = fopen( szName, "rb" );
//ov_open 함수를 사용해서 Ogg파일을 오픈
int res = ov_open( File, &vf, NULL, 0 );
if ( res < 0 )
{
switch( res ) //에러처리
{
case OV_EREAD:
break;
case OV_ENOTVORBIS:
break;
case OV_EVERSION:
break;
case OV_EBADHEADER:
break;
case OV_EFAULT:
break;
}
ov_clear( &vf );
fclose(File);
}
대충 껍질만 있는 코드입니다-_-;; 어려울 것도 없는 코드입니다. ov_open이라는 함수를
사용한다는 사실과 OggVorbis_File를 이용한다는 사실만 기억해두세요.
당연히 OggVorbis_File를 해제하면, Ogg파일을 다시 열어야 합니다.
open함수는 ov_open이외에도 ov_open_callbacks이라는 녀석이 있습니다.
내부에서 돌아가는 4개의 함수에 대해서 직접 정의가 가능하게 되어있습니다.
4개의 함수는 seek, tell, read, close 입니다. 설명안해도 아실듯.. 현재 작성중인
스트리밍방식의 Ogg재생기에서 문제가 조금 있어서 아무래도 callback함수를
직접 작성해줘야 할 듯 합니다-_-;; 그건 나중에 또 기회되면;;
5. Ogg Vorbis 정보 얻어오기
vorbis_info * vi;
vi = ov_info( &vf, -1 );
if( vi == NULL )
{
ov_clear( &vf );
return FALSE;
}
끝입니다-_-;;; vorbis_info라는 구조체에 ov_info라는 함수를 이용해서 오픈한 파일의 정보를
채워넣습니다. 구조체안에 내용을 살펴보면..
typedef struct vorbis_info{
int version;
int channels;
long rate;
long bitrate_upper;
long bitrate_nominal;
long bitrate_lower;
long bitrate_window;
void *codec_setup;
} vorbis_info;
이렇습니다-_-;; 아래쪽 bitrate_ 들은 VBR과 관련된 항목같습니다만, 사용안해봐서 우선 넘어가죠-_-;;
단순히 디코딩해서 wave로 변환하거나, 재생할 목적이면, channels와 rate만 있으면 충분 합니다.
5. 디코딩해서 wave파일로 저장하기..
벌써 마지막 단계..-_-;; 디코딩해서 wave파일로 저장해 보겠습니다.
char DECBUF[4096]; // 디코딩된 데이터 버퍼
FILE * fp;
fp = fopen(szWaveFile,"w+b");
//WAVEHEADER 저장
fwrite(&wh.RIFF, sizeof(wh.RIFF),1,fp);
fwrite(&wh.RIFFSIZE, sizeof(wh.RIFFSIZE),1,fp);
fwrite(&wh.Type, sizeof(wh.Type),1,fp);
fwrite(&wh.Fmt, sizeof(wh.Fmt),1,fp);
fwrite(&wh.FmtSIZE, sizeof(wh.FmtSIZE),1,fp);
fwrite(&wh.WaveFmt, sizeof(wh.WaveFmt),1,fp);
fwrite(&wh.Data, sizeof(wh.Data),1,fp);
fwrite(&wh.SizeofData, sizeof(wh.SizeofData),1,fp);
LONG WriteData = 0L;
LONG ReadData = 0L;
int bitstream;
while( 1 )
{
memset(DECBUF,0,4096);
WriteData = ov_read( &vf, DECBUF, 4096, 0, 2, 1, &bitstream );
if( WriteData == 0 ) // 데이터 완료
{
break;
}
else if ( WriteData < 0 )
{
ov_clear( &vf );
fclose(fp);
return;
}
if(wh.SizeofData - ReadData >= 0 )
{
ReadData += WriteData;
fwrite(&DECBUF,1,WriteData,fp);
}else
{
break; // 데이터 완료
}
}//*/
fclose(fp);
우선 읽어온 데이터를 저장할 버퍼를 만들어줍니다.
그리고 저장할 파일을 오픈.
그리고 청크등을 포함한 WAVE파일의 헤더를 순서에 맞게 저장합니다. 웨이브파일의 구조를 모르신다면..(무념;;)
저중에서 확인하셔야 할 부분은 SizeofData입니다. 순수데이터의 사이즈인데요. vi와 다른 함수하나를 이용하시면
쉽게 구할 수 있습니다.
DataSize = vi->channels * vi->rate * Samplebit * ov_time_total( &vf,-1 );
ov_time_total 함수를 이용하면, 재생시간이 리턴됩니다. 이로서 데이터사이즈도 쉽게 구할 수 있습니다.(편해라;;)
while문 안으로 들어가서,
WriteData = ov_read( &vf, DECBUF, 4096, 0, 2, 1, &bitstream );
ov_read함수는 리턴값으로 디코딩된 순수데이터의 사이즈를 넘겨줍니다. 세번째 인자가 읽어들이라고 넣어준
데이터 사이즈입니다. 첫번째 인자는 설명할필요도 없는 파일구조체, 두번째는 데이터가 저장될 버퍼,
네번째 인자는 little endian인가 Big endian인가입니다. 0은 little endian 1은 Big endian 입니다.
다섯번째 인자는 1일경우 8비트 샘플 2일경우 16비트..저는 모두 16비트로..
여섯번째는 signed 데이터인지 unsigned인지를 정해주는 플레그 입니다. 0은 signed 1은 unsigned 입니다.
일곱번째는 현재의 비트스트림을 해당 변수로 넘겨줍니다.
ov_read함수의 리턴값이 0 일 경우에는 데이터를 모두 디코딩했다는 뜻 입니다.
저장된 파일을 재생해보는 일 만 남았겠군요 :)
kgda에서 퍼왔습니다