2011-09-30 2 views
1

내 작업은 웨이브 파일을 녹음하고, 그것을 ogg로 변환하여 리프 컨테이너에 압축하는 것입니다. 첫 번째 두 부분이 완료되었지만 세 번째 부분에 문제가 있습니다. 내 문제를 해결할 수있는 소스 코드를 찾았지만 제대로 작동하지 않습니다.Ogg to Riff/Acm으로 웨이브 인코딩

#include <windows.h> 
#include <windowsx.h> 
#include <mmsystem.h> 
#include <memory.h> 
#include <stdlib.h> 
#include <mmreg.h> 
#include <msacm.h> 
#include <assert.h> 
#include <math.h> 
#include <time.h> 
#include <sys/types.h> 
#include <sys/stat.h> 

#define INPUT  "record.wav" 
#define OUTPUT "output_ogg.wav" 


/* The following taken from the vorbis.acm sources */ 
/* Defines modes for encoding. Set this in 'fmt ' */ 

#define WAVE_FORMAT_VORBIS1  ((WORD)'O'+((WORD)'g'<<8)) // 0x674f("Og") ... Original stream compatible 
#define WAVE_FORMAT_VORBIS2  ((WORD)'P'+((WORD)'g'<<8)) // 0x6750("Pg") ... Have independent header 
#define WAVE_FORMAT_VORBIS3  ((WORD)'Q'+((WORD)'g'<<8)) // 0x6751("Qg") ... Have no codebook header 
#define WAVE_FORMAT_VORBIS1P ((WORD)'o'+((WORD)'g'<<8)) // 0x676f("og") ... Original stream compatible 
#define WAVE_FORMAT_VORBIS2P ((WORD)'p'+((WORD)'g'<<8)) // 0x6770("pg") ... Have independent header 
#define WAVE_FORMAT_VORBIS3P ((WORD)'q'+((WORD)'g'<<8)) // 0x6771("qg") ... Have no codebook header 


/* The 'fact' chunk required for compressed WAV files */ 
struct FACT { 
unsigned long dwID; 
unsigned long dwSize; 
unsigned long dwSamples; 
}; 

int main() 
{ 
/* Open source file */ 
HMMIO hSrcWaveFile=mmioOpen(INPUT,NULL,MMIO_READ); 
assert(hSrcWaveFile); 

MMCKINFO SrcWaveFile; 
mmioDescend(hSrcWaveFile,&SrcWaveFile,NULL,0); 

assert(SrcWaveFile.ckid==mmioStringToFOURCC("RIFF",MMIO_TOUPPER)); 
assert(SrcWaveFile.fccType==mmioStringToFOURCC("WAVE",MMIO_TOUPPER)); 

MMCKINFO SrcWaveFmt; 

/* Go to RIFF-WAVE*/ 
mmioDescend(hSrcWaveFile,&SrcWaveFmt,&SrcWaveFile,0); 

assert(SrcWaveFmt.ckid==mmioStringToFOURCC("fmt ",0)); 

int SrcHeaderSize=SrcWaveFmt.cksize; 

if(SrcHeaderSize<sizeof(WAVEFORMATEX)) 
    SrcHeaderSize=sizeof(WAVEFORMATEX); 

WAVEFORMATEX *SrcHeader=(WAVEFORMATEX *)new char[SrcHeaderSize]; 
ZeroMemory(SrcHeader,SrcHeaderSize); 

/* Read fmt */ 
mmioRead(hSrcWaveFile,(char*)SrcHeader,SrcWaveFmt.cksize); 

/* Leave the chunk */ 
mmioAscend(hSrcWaveFile,&SrcWaveFmt,0); 

MMCKINFO SrcWaveData; 
while(1){ 
    MMRESULT Result=mmioDescend(hSrcWaveFile,&SrcWaveData,&SrcWaveFile,0); 
    assert(Result==0); 
    if(SrcWaveData.ckid==mmioStringToFOURCC("data",0)) 
     break; 
    Result=mmioAscend(hSrcWaveFile,&SrcWaveData, 0); 
    assert(Result==0); 
} 

/* Destination header */ 
WAVEFORMATEX *DstHeader=(WAVEFORMATEX *)malloc(1024); 
ZeroMemory(DstHeader,1024); 

printf ("Going ACM!\n"); 

/* Suggest a format for us        */ 
/* Try to coose the nmber 3 mode (whatever that is) */ 

DstHeader->wFormatTag  =  WAVE_FORMAT_VORBIS3; 
DstHeader->nChannels  =  2; 
DstHeader->wBitsPerSample =  16; 
DstHeader->nSamplesPerSec =  44100; 

printf ("->acmFormatSuggest()\n"); 
if (acmFormatSuggest(NULL,SrcHeader,DstHeader,1024,ACM_FORMATSUGGESTF_WFORMATTAG)) 
    printf ("ERROR: acmFormatSuggest()\n"); 

/* We shoudl have the DstHeader filled with data byt the ACM now */ 

/* Open destination */ 
HMMIO hDstWaveFile; 

/* open the destination file */ 
hDstWaveFile=mmioOpen(OUTPUT,NULL,MMIO_CREATE|MMIO_WRITE); 
assert(hDstWaveFile); 
printf ("->mmioOpen() output.wav\n"); 

/* Create chunks */ 
MMCKINFO DstWaveFile; 
DstWaveFile.fccType=mmioStringToFOURCC("WAVE",MMIO_TOUPPER); 
mmioCreateChunk(hDstWaveFile,&DstWaveFile,MMIO_CREATERIFF); 
printf ("->mmioCreateChunk() WAVE\n"); 

/* Create format chunk */ 
MMCKINFO DstWaveFmt; 
DstWaveFmt.ckid=mmioStringToFOURCC("fmt ",0); 

/* Create chunk write data and Ascend out of it */ 
mmioCreateChunk(hDstWaveFile,&DstWaveFmt,0); 
printf ("->mmioCreateChunk() fmt\n"); 
mmioWrite(hDstWaveFile,(char*)DstHeader,sizeof(WAVEFORMATEX)+DstHeader->cbSize); 
printf ("->mmioWrite() fmt header\n"); 
mmioAscend(hDstWaveFile,&DstWaveFmt,0); 
printf ("->mmioAscend()\n"); 


/* fact chunk            */ 
/* this is only my idea of what it should look like   */ 
/* i found that some WAV files had more data than i write */ 
/* but that seems enough for most of apps i tested   */ 

FACT DstFactChunk; 
MMCKINFO FactChunk; 

DstFactChunk.dwID  = mmioStringToFOURCC ("fact", 0); 
DstFactChunk.dwSamples = SrcWaveData.cksize/4; 
DstFactChunk.dwSize  = sizeof (DstFactChunk) - sizeof (DstFactChunk.dwID) - sizeof (DstFactChunk.dwSize); 
FactChunk.ckid = mmioStringToFOURCC ("fact", 0); 
FactChunk.cksize = DstFactChunk.dwSize; 

/* Calculate the time */ 
float TIME; 
if (SrcHeader->nSamplesPerSec == 44100) 
    TIME = DstFactChunk.dwSamples/44100.f; 

mmioWrite (hDstWaveFile, (char *)&DstFactChunk, sizeof (DstFactChunk)); 

/* This ascend produced an error when i added this whole code    */ 
/* to my Dialog based MFC full feature super duper app      */ 
/* Don't know why really but i think that Write already moves the pointer */ 
/* past the chun sok this is unnecessery         */ 
/* mmioAscend (hDstWaveFile, &FactChunk, 0);        */ 


/* Create Data chunk */ 
MMCKINFO DstWaveData; 
DstWaveData.ckid=mmioStringToFOURCC("data",0); 

mmioCreateChunk(hDstWaveFile,&DstWaveData,0); 
mmioAscend (hDstWaveFile, &DstWaveData, 0); 

printf ("->mmioCreateChunk() data\n"); 

/* Print the data we have gathered so far */ 
printf ("------------Source-----------\n"); 
printf ("Format: \t\t%X\n", SrcHeader->wFormatTag); 
printf ("Channels: \t\t%d\n", SrcHeader->nChannels); 
printf ("Samples/Sec: \t\t%d\n", SrcHeader->nSamplesPerSec); 
printf ("AverageBytes/Sec: \t%d\n", SrcHeader->nAvgBytesPerSec); 
printf ("Bits/Sample: \t\t%d\n", SrcHeader->wBitsPerSample); 
printf ("BlockAlign: \t\t%d\n", SrcHeader->nBlockAlign); 
printf ("DataSize: \t\t%d\n", SrcWaveData.cksize); 
printf ("Time: \t\t\t%.3f\n", TIME); 
printf ("Samples: \t\t%d\n", DstFactChunk.dwSamples); 
printf ("Extra: \t\t\t%d\n", SrcHeader->cbSize); 
printf ("------------------------------\n"); 

printf ("\n------------Destination------\n"); 
printf ("Format: \t\t%X\n", DstHeader->wFormatTag); 
printf ("Channels: \t\t%d\n", DstHeader->nChannels); 
printf ("Samples/Sec: \t\t%d\n", DstHeader->nSamplesPerSec); 
printf ("AverageBytes/Sec: \t%d\n", DstHeader->nAvgBytesPerSec); 
printf ("Bits/Sample: \t\t%d\n", DstHeader->wBitsPerSample); 
printf ("BlockAlign: \t\t%d\n", DstHeader->nBlockAlign); 
printf ("Extra: \t\t\t%d\n", DstHeader->cbSize); 
printf ("------------------------------\n"); 


DWORD maxFormatSize = 0; 
MMRESULT ACMres; 

/* Get the max possbile size from the system this really no necessery */ 
/* but i was experimenting a bit and so I left it here    */ 

ACMres = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &maxFormatSize); 

if (ACMres != MMSYSERR_NOERROR){ 
    printf ("ERROR: acmMetrics()\n"); 
} 

/* Open ACM stream */ 
HACMSTREAM acm = NULL; 
MMRESULT Result=acmStreamOpen(&acm,NULL,SrcHeader,DstHeader,NULL,0,0,0); 
printf ("->acmStreamOpen()\n"); 

if (Result != MMSYSERR_NOERROR){ 
    printf ("ERROR: acmStreamOpen()\n"); 
    exit (-1); 
} 


/* This is where the problem's begin, first the buffers */ 
/* Size of the dest/src is based on the size of src/dest */ 
DWORD DefaultWriteSize; 
DWORD DefaultReadSize = SrcHeader->nBlockAlign * 1024; 

/* If we know the dest */ 
/* Result=acmStreamSize(acm, DefaultWriteSize, &DefaultReadSize, ACM_STREAMSIZEF_DESTINATION); */ 


printf ("->acmStreamSize()\n"); 

/* If we know the source, well stay with the source PCM is less problematic */ 

Result = acmStreamSize (acm, DefaultReadSize, &DefaultWriteSize, ACM_STREAMSIZEF_SOURCE); 

printf ("->acmStreamSize() gave us buffer size [%d]\n", DefaultWriteSize); 

if (Result != MMSYSERR_NOERROR){ 
    printf ("ERROR: acmStreamSize()\n"); 
    exit (-1); 
} 

/* Allocate memory */ 
ACMSTREAMHEADER stream; 
ZeroMemory(&stream,sizeof(stream)); 
stream.cbStruct=sizeof(stream); 
stream.pbSrc=(BYTE*)GlobalAlloc(GMEM_FIXED,DefaultReadSize); 
stream.cbSrcLength=DefaultReadSize; 
stream.pbDst=(BYTE*)GlobalAlloc(GMEM_FIXED,DefaultWriteSize); 
stream.cbDstLength=DefaultWriteSize; 

/* Prepare header */ 
printf ("->acmStreamPrepareHeader()\n"); 
Result=acmStreamPrepareHeader(acm, &stream,0); 
if (Result != MMSYSERR_NOERROR){ 
    printf ("ERROR: acmStreamPrepareHeader()\n"); 
    exit (-1); 
} 


/* The main encoding loop              */ 
/* I'm pretty sure that before the actual reading of samples from the source */ 
/* I should feed the ACM some junk so that it would write the necessery headers */ 
/* that Ogg Vorbis requires              */ 
/* but i dont know how much of that 'junk' i would have to write there   */ 
/* i don't know if it can be junk            */ 
/* well i'm pretty clueless here            */ 

for(int RemainSize=SrcWaveData.cksize;RemainSize>0;){ 
    // ???? 
    int ReadSize=DefaultReadSize; 

    if(ReadSize>RemainSize) 
     ReadSize=RemainSize; 

    RemainSize-=ReadSize; 


    ReadSize=mmioRead(hSrcWaveFile,(char*)stream.pbSrc,ReadSize); 
    if (ReadSize == -1){ 
     printf ("Can't read\n"); 
     break; 
    } 

    stream.cbSrcLength=ReadSize; 

    /* Convert */ 
    Result=acmStreamConvert(acm,&stream,0); 
    if (Result) 
     printf ("ERROR: acmStreamConvert()\n"); 

    int WriteSize=stream.cbDstLengthUsed; 

    /* Wrtie data */ 
    Result=mmioWrite(hDstWaveFile,(char*)stream.pbDst,WriteSize); 

    if (Result == -1){ 
     printf ("Can't Write"); 
     break; 
    } 

    /* Uncomment this if you want to see the buffer sizes */ 
    /* printf ("READ[%d] :: WRITE[%d]\n", stream.cbSrcLengthUsed, stream.cbDstLengthUsed); */ 

    } 


/* Cleaup on Isle 5 !!! */ 

    GlobalFree(stream.pbSrc); 
    GlobalFree(stream.pbDst); 
    acmStreamUnprepareHeader(acm,&stream,0); 

    acmStreamClose(acm,0); 

    mmioAscend(hSrcWaveFile,&SrcWaveData,0); 
    mmioAscend(hSrcWaveFile,&SrcWaveFile,0); 

    mmioAscend(hDstWaveFile,&DstWaveData,0); 
    mmioAscend(hDstWaveFile,&DstWaveFile,0); 

    free(DstHeader); 

    mmioClose(hSrcWaveFile,0); 
    mmioClose(hDstWaveFile,0); 

    delete[] SrcHeader; 

    return 0; 
} 

나는이 프로그램을 실행하기 위해 노력하고있어, 그것은()도 실패한 나 그 acmFormatSuggest()와 acmStreamOpen을 보여줍니다. 제발, 제가 오류를 찾는 데 도움이됩니다.

답변

2

acmFormatSuggest (그런데 오류 코드는 무엇입니까?)이 형식을 지원하는 ACM 오디오 코덱이 설치된 경우 성공할 수 있습니다. 기본적으로 사용할 수있는 사람이 없으며 실제로 설치되어 있습니까?

+0

ogg acm 코덱이 설치되어 있어야하나요? –

+0

물론입니다. ACM API는 Vorbis에 대해 아무것도 모릅니다. Windows SDK에는 Vorbis에 대해 더 잘 알지 못합니다 (코드에서 # Vorbis 형식을 정의해야 함). 따라서 코덱 가용성이 필수적입니다. –

+0

Vorbis ACM 코덱을 시스템에 추가했지만 아무 것도 변경되지 않았습니다. 다시 시작한 후에도. 어쩌면 다른 문제가있을 수 있습니까? –