//---------------------------------------------------------------------------
#pragma hdrstop
#include "Avi.h"
#pragma package(smart_init)
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <vfw.h>
//#include "win32_LastError.h"
#include <stdio.h>
//---------------------------------------------------------------------------
AviBitmap::AviBitmap() : bitmap_(0) {}
AviBitmap::AviBitmap(std::string const& file_name) {
bitmap_ = static_cast<HBITMAP>(::LoadImage(0, file_name.c_str(), IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION));
}
AviBitmap::AviBitmap(HBITMAP bmp) : bitmap_(bmp) {
}
AviBitmap::operator HBITMAP() const {
return bitmap_;
}
// First, we'll define the WAV file format.
#include <pshpack1.h>
#pragma pack(2)
struct FmtChunk {
char id[4]; //="fmt "
unsigned long size; //=16
short wFormatTag; //=WAVE_FORMAT_PCM=1
unsigned short wChannels; //=1 or 2 for mono or stereo
unsigned long dwSamplesPerSec; //=11025 or 22050 or 44100
unsigned long dwAvgBytesPerSec; //=wBlockAlign * dwSamplesPerSec
unsigned short wBlockAlign; //=wChannels * (wBitsPerSample==8?1:2)
unsigned short wBitsPerSample; //=8 or 16, for bits per sample
// char what[14];//14字节含义???
};
struct FactChunk{ //
char id[4]; //fact
unsigned long size;
char data[4];
};
struct DataChunk {
char id[4]; //="data"
unsigned long size; //=datsize, size of the following array
unsigned char data[1]; //=the raw data goes here
};
struct WavChunk {
char id[4]; //="RIFF"
unsigned long size; //=datsize+8+16+4
char type[4]; //="WAVE"
FmtChunk fmt;
DataChunk dat;
};
#include <poppack.h>
struct TAviUtil {
IAVIFile* pfile; // created by CreateAvi
WAVEFORMATEX wfx; // as given to CreateAvi (.nChanels=0 if none was given). Used when audio stream is first created.
int period; // specified in CreateAvi, used when the video stream is first created
IAVIStream* as; // audio stream, initialised when audio stream is first created
IAVIStream* ps;
IAVIStream* psCompressed; // video stream, when first created
unsigned long nframe, nsamp; // which frame will be added next, which sample will be added next
bool iserr; // if true, then no function will do anything
};
#pragma pack(8)
Avi::Avi(AnsiString file_name, int frame_period, const WAVEFORMATEX* wfx) {
IAVIFile *pfile;
::AVIFileInit();
HRESULT hr = ::AVIFileOpen(&pfile, file_name.c_str(), OF_WRITE|OF_CREATE, 0);
if (hr != AVIERR_OK) {
::AVIFileExit();
throw "AVIERR_OK";
}
TAviUtil *au = new TAviUtil;
au->pfile = pfile;
if (wfx==0) ::ZeroMemory(&au->wfx,sizeof(WAVEFORMATEX)); else ::CopyMemory(&au->wfx,wfx,sizeof(WAVEFORMATEX));
au->period = frame_period;
au->as=0;
au->ps=0;
au->psCompressed=0;
au->nframe=0;
au->nsamp=0;
au->iserr=false;
avi_ = (HANDLE*) au;
}
Avi::~Avi() {
if (avi_ == 0) return;
TAviUtil *au = (TAviUtil*)avi_;
if (au->as!=0) AVIStreamRelease(au->as); au->as=0;
if (au->psCompressed!=0) AVIStreamRelease(au->psCompressed); au->psCompressed=0;
if (au->ps!=0) AVIStreamRelease(au->ps); au->ps=0;
if (au->pfile!=0) AVIFileRelease(au->pfile); au->pfile=0;
AVIFileExit();
delete au;
}
HRESULT Avi::compression(AviBitmap const& bmp, AVICOMPRESSOPTIONS *opts, bool ShowDialog, HWND hparent) {
if (avi_==0) return AVIERR_BADHANDLE;
DIBSECTION dibs;
//::GetObject(bmp,sizeof(dibs),&dibs);
// printf("Avi::compression going to GetObject 1\n");
// if( ! ::GetObject(bmp, sizeof(dibs), &dibs)) {
// printf("GetObject: %s\n", Win32_LastError().c_str());
//return -1;
// }
// printf("Avi::compression went to GetObject 1\n");
TAviUtil *au = (TAviUtil*)avi_;
if (au->iserr) return AVIERR_ERROR;
if (au->psCompressed!=0) return AVIERR_COMPRESSOR;
// create the stream, if it wasn't there before
if (au->ps==0) {
AVISTREAMINFO strhdr;
::ZeroMemory(&strhdr,sizeof(strhdr));
strhdr.fccType = streamtypeVIDEO;
strhdr.fccHandler = 0;
strhdr.dwScale = au->period;
strhdr.dwRate = 1000;
strhdr.dwSuggestedBufferSize = dibs.dsBmih.biSizeImage;
SetRect(&strhdr.rcFrame, 0, 0, dibs.dsBmih.biWidth, dibs.dsBmih.biHeight);
HRESULT hr = ::AVIFileCreateStream(au->pfile, &au->ps, &strhdr);
if (hr!=AVIERR_OK) {au->iserr=true; return hr;}
}
// set the compression, prompting dialog if necessary
if (au->psCompressed==0) {
AVICOMPRESSOPTIONS myopts;
::ZeroMemory(&myopts,sizeof(myopts));
AVICOMPRESSOPTIONS *aopts[1];
if (opts!=0) aopts[0]=opts;
else aopts[0]=&myopts;
if (ShowDialog) {
BOOL res = (BOOL) ::AVISaveOptions(hparent,0,1,&au->ps,aopts);
if (!res) {
::AVISaveOptionsFree(1,aopts);
au->iserr=true;
return AVIERR_USERABORT;
}
}
// printf("fccType: %d\n",static_cast<int>(myopts.fccType));
// printf("fccHandler: %d\n",static_cast<int>(myopts.fccHandler));
// printf("dwKeyFrameEvery: %d\n",static_cast<int>(myopts.dwKeyFrameEvery));
// printf("dwQuality: %d\n",static_cast<int>(myopts.dwQuality));
// printf("dwFlags %d\n",static_cast<int>(myopts.dwFlags));
// printf("dwBytesPerSecond %d\n",static_cast<int>(myopts.dwBytesPerSecond));
//printf("lpFormat: %d\n",static_cast<int>(myopts.lpFormat));
// printf("cbFormat: %d\n",static_cast<int>(myopts.cbFormat));
//printf("lpParms: %d\n",static_cast<int>(myopts.lpParms ));
// printf("cbParms: %d\n",static_cast<int>(myopts.cbParms ));
// printf("dwInterleaveEvery%d\n",static_cast<int>(myopts.dwInterleaveEvery ));
HRESULT hr = ::AVIMakeCompressedStream(&au->psCompressed, au->ps, aopts[0], 0);
if (hr != AVIERR_OK) {
au->iserr=true;
return hr;
}
::AVISaveOptionsFree(1,aopts);
printf("Avi::compression after AVISaveOptionsFree\n");
/*
DIBSECTION dibs;
printf("Avi::compression going to GetObject\n");
if( !::GetObject(bmp, sizeof(dibs), &dibs)) {
printf("GetObject: %s\n", Win32_LastError());
return -1;
}
*/
hr = ::AVIStreamSetFormat(au->psCompressed, 0, &dibs.dsBmih, dibs.dsBmih.biSize+dibs.dsBmih.biClrUsed*sizeof(RGBQUAD));
if( hr != AVIERR_OK ) {
au->iserr=true;
return hr;
}
}
return AVIERR_OK;
}
HRESULT Avi::add_frame(AviBitmap const& bmp) {
if (avi_ == 0) return AVIERR_BADHANDLE;
DIBSECTION dibs;
int sbm = ::GetObject(bmp, sizeof(dibs), &dibs);
if( sbm!=sizeof(DIBSECTION) )
return AVIERR_BADPARAM;
TAviUtil *au = (TAviUtil*)avi_;
if( au->iserr ) return AVIERR_ERROR;
// TODO... Get Width and Height from Bitmap...
if( au->ps == 0 ) {
AVISTREAMINFO strhdr;
::ZeroMemory(&strhdr,sizeof(strhdr));
strhdr.fccType = streamtypeVIDEO;
strhdr.fccHandler = 0;
// strhdr.dwQuality =50;
//strhdr.dwFlags =AVISTREAMINFO_FORMATCHANGES;
strhdr.dwScale = au->period;
strhdr.dwRate = 1000;
strhdr.dwSuggestedBufferSize = dibs.dsBmih.biSizeImage;
SetRect(&strhdr.rcFrame, 0, 0, dibs.dsBmih.biWidth, dibs.dsBmih.biHeight);
HRESULT hr= ::AVIFileCreateStream(au->pfile, &au->ps, &strhdr);
if (hr!=AVIERR_OK) {
au->iserr=true;
return hr;
}
}
// create an empty compression, if the user hasn't set any
if (au->psCompressed==0) {
AVICOMPRESSOPTIONS opts;
::ZeroMemory(&opts,sizeof(opts));
opts.fccHandler=mmioFOURCC('D','I','B',' ');
HRESULT hr = AVIMakeCompressedStream(&au->psCompressed, au->ps, &opts, 0);
if (hr !=