動画ファイル(AVI)中からWAVE音声(PCM)の抽出

動画ファイル(AVI)中からWAVE音声(PCM)を抽出しファイル保存する例題です。AVIのコーデックに対する対応等は今回は無しということで。。

Video for Windows(VFW)を利用してAVI中の音声データにアクセスしているため、そのための準備が必要です。ヘッダファイルには(windows.h, vfw.h)を追加し、libvfw_avi32.a を追加してください。また、再生中にPlaySound()関数により音声を出力するようにしているため、mmsystem.h, libwinmm.a も追加して下さい(mmsystem.h は vfw.h 中に記載済み)。

コンパイル例:(-fvtable-thunks はgccでのコンパイル時に必要になるみたいです。。)
Gami[84]% gcc -o aviwave aviwave.cpp -lwinmm -lvfw_avi32 -fvtable-thunks

動画ファイル(AVI)中からWAVE音声(PCM)の抽出(aviwave.cpp)
//-----------------------------------------------------------------
// aviwave.cpp:
//      動画ファイル(AVI)中からWAVE音声(PCM)の抽出
//                Last Update: <2005/01/27 04:12:21 A.Murakami>
//-----------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <vfw.h>
//-----------------------------------------------------------------
// for VC++
#pragma comment(lib,"winmm")
#pragma comment(lib,"vfw32")
//-----------------------------------------------------------------
#define WAVBUFFER 4096
#define AVIFILE   "sample.avi"
//-----------------------------------------------------------------
char* swrite(char* fp,char* su,int n);
char* nwrite(char* fp,int v,int n);
void set_wavefmt(char* pfmt,WAVEFORMATEX wfx);
void set_wavelen(char* pfmt,DWORD lLength);
//-----------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
                   LPSTR lpszCmdLine,int nCmdShow)
{
    AVICOMPRESSOPTIONS opt;
    PAVISTREAM pstm,ptmp;
    WAVEFORMATEX wfx;
    FILE *fp;
    DWORD dwSize=0,fmtLen,dwTmp;
    LONG i,lStart,lEnd,lLength,lSample;
    LPBYTE p,pp;
    char *pbuf,*pfmt,*avifile;
    if(strlen(lpszCmdLine)) avifile = lpszCmdLine;
    else avifile = AVIFILE;
    //--------------------------------------------------
    // read AVI
    //--------------------------------------------------
    AVIFileInit();
    if(AVIStreamOpenFromFile(&pstm,avifile,streamtypeAUDIO,0,
                             OF_READ | OF_SHARE_DENY_NONE,NULL)!=0)
        return 0;
    if(AVIStreamReadFormat(pstm,lStart,NULL,&lLength)!=0)
        return 0;
    if((p=(LPBYTE)malloc(lLength))==NULL)
        return 0;
    if(AVIStreamReadFormat(pstm,lStart,p,&lLength)!=0)
        return 0;
    //--------------------------------------------------
    // set wave format
    //--------------------------------------------------
    wfx=*(LPWAVEFORMATEX)p;
    wfx.wFormatTag      = WAVE_FORMAT_PCM;
    wfx.wBitsPerSample  = wfx.wBitsPerSample<12?8:16;
    wfx.nBlockAlign     = wfx.nChannels*wfx.wBitsPerSample/8;
    wfx.nAvgBytesPerSec = wfx.nSamplesPerSec*wfx.nBlockAlign;
    wfx.cbSize          = 0;
    pbuf = (char*)malloc(sizeof(wfx));
    //--------------------------------------------------
    // set compression
    //--------------------------------------------------
    memset(&opt,0,sizeof(AVICOMPRESSOPTIONS));
    opt.fccType  = streamtypeAUDIO;
    opt.lpFormat = &wfx;
    opt.cbFormat = sizeof(WAVEFORMATEX)-sizeof(WORD);
    if(AVIMakeCompressedStream(&ptmp,pstm,&opt,NULL)!=AVIERR_OK){
        fprintf(stderr,"avi make compress\n");
        return 0;
    }
    lStart = AVIStreamStart(ptmp);
    lEnd   = lStart+AVIStreamLength(ptmp)-1;
    //--------------------------------------------------
    // write wave format
    //--------------------------------------------------
    if((fp=fopen("wavout.wav","wb"))==NULL){
        fprintf(stderr,"wave open\n");
        return 0;
    }
    fmtLen = sizeof(DWORD)*7+opt.cbFormat;
    pfmt = (char*)malloc(fmtLen);
    set_wavefmt(pfmt,wfx);
    fwrite(pfmt,fmtLen,1,fp);
    //--------------------------------------------------
    // read wave
    //--------------------------------------------------
    for(i=lStart;i<=lEnd;i+=lSample) {
        if(AVIStreamRead(
            ptmp,i,AVISTREAMREAD_CONVENIENT,NULL,0,&lLength,&lSample)!=0)
            return 0;
        if((lLength<=0 || lSample<=0) &&
            AVIStreamRead(ptmp,i,WAVBUFFER,NULL,0,&lLength,&lSample)!=0)
            return 0;
        if((p=(LPBYTE)realloc(p,lLength))==NULL)
            return 0;
        if(AVIStreamRead(ptmp,i,lSample,p,lLength,&lLength,&lSample)!=0)
            return 0;
        if(fwrite(p,lLength,1,fp)!=1)
            return 0;
        // set wave sound
        pbuf = (char*)realloc(pbuf,fmtLen+lLength);
        memset(pbuf,0,fmtLen+lLength);
        set_wavelen(pfmt,lLength);
        memcpy(pbuf,pfmt,fmtLen);
        memcpy(pbuf+fmtLen,p,lLength);
        // play sound
        PlaySound((char*)pbuf,NULL,SND_MEMORY|SND_SYNC);
        dwSize+=lLength;
    }
    //--------------------------------------------------
    // write wave size
    //--------------------------------------------------
    fseek(fp,-(LONG)(dwSize+sizeof(DWORD)),SEEK_END);
    fwrite(&dwSize,sizeof(DWORD),1,fp);
    fseek(fp,sizeof(DWORD),SEEK_SET);
    dwSize+=sizeof(DWORD)*5+opt.cbFormat;
    fwrite(&dwSize,sizeof(DWORD),1,fp);
    fclose(fp);
    // clean up
    free(pfmt);
    free(p);
    free(pbuf);
    AVIStreamRelease(ptmp);
    AVIStreamRelease(pstm);
    AVIFileExit();
    return 0;
}
//-----------------------------------------------------------------
// 多バイト列の設定
//-----------------------------------------------------------------
char* swrite(char* fp,char* su,int n)
{
    for(int i=0;i<n;i++,su++,fp++) *fp = *su;
    return fp;
}
char* nwrite(char* fp,int v,int n)
{
    for(int i=0;i<n;i++,fp++) *fp = (v>>8*i) & 0xff;
    return fp;
}
//-----------------------------------------------------------------
// WAVE format の設定
//-----------------------------------------------------------------
void set_wavefmt(char* pfmt,WAVEFORMATEX wfx)
{
    DWORD dwTmp,fmtlen=sizeof(WAVEFORMATEX)-sizeof(WORD);
    char* p= pfmt;
    dwTmp = mmioFOURCC('R','I','F','F');
    p = nwrite(p,dwTmp,sizeof(DWORD));
    p = nwrite(p,0,sizeof(DWORD));
    dwTmp = mmioFOURCC('W','A','V','E');
    p = nwrite(p,dwTmp,sizeof(DWORD));
    dwTmp = mmioFOURCC('f','m','t',' ');
    p = nwrite(p,dwTmp,sizeof(DWORD));
    p = nwrite(p,fmtlen,sizeof(DWORD));
    p = swrite(p,(char*)&wfx,fmtlen);
    dwTmp = mmioFOURCC('d','a','t','a');
    p = nwrite(p,dwTmp,sizeof(DWORD));
    p = nwrite(p,0,sizeof(DWORD));
}
void set_wavelen(char* pfmt,DWORD lLength)
{
    DWORD dwlen;
    char* p=pfmt+sizeof(DWORD);
    dwlen = sizeof(DWORD)*5+sizeof(WAVEFORMATEX)-sizeof(WORD)+lLength;
    p = nwrite(p,dwlen,sizeof(DWORD));
    p = pfmt+sizeof(DWORD)*6+sizeof(WAVEFORMATEX)-sizeof(WORD);
    p = nwrite(p,lLength,sizeof(DWORD));
}
inserted by FC2 system