/******************************************************** AviWriteStream/AviWriteFile class implementation Copyright 2000 Eugene Kuznetsov (divx@euro.ru) *********************************************************/ #define _LARGEFILE64_SOURCE #include #include #include #include "AviWrite.h" #ifdef __FreeBSD__ #define lseek64 lseek #define O_LARGEFILE 0 #endif using namespace std; AviWriteFile::AviWriteFile(const char* name, int flags, int mask):m_fd(0) { try { m_status=0; m_fd=new FileBuffer(name, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, mask); const int junk_size=0x800; char* junk=new char[junk_size]; memset(junk, 0, junk_size); m_fd->write(junk, junk_size); delete junk; m_status=1; memset(&m_header, 0, sizeof(m_header)); m_header.dwFlags=flags; } catch(FatalError&) { delete m_fd; throw; } } IAviWriteStream* AviWriteFile::AddStream(AviStream::StreamType type, const char* format, Unsigned format_size, int handler, int frame_rate, int samplesize, int quality, int flags) { int ckid; ckid=MAKEAVICKID((type==AviWriteStream::Video)?cktypeDIBcompressed:cktypeWAVEbytes, m_streams.size()); AviWriteStream* result=new AviWriteStream(this, ckid, type, format, format_size, handler, frame_rate, samplesize, quality, flags); m_streams.push_back(result); return result; } IAviVideoWriteStream* AviWriteFile::AddVideoStream(int fourcc, BITMAPINFOHEADER* srchdr, int frame_rate, int flags) { int ckid; ckid=MAKEAVICKID(cktypeDIBcompressed, m_streams.size()); AviVideoWriteStream* result=new AviVideoWriteStream(this, ckid, fourcc, srchdr, frame_rate, flags); if(result==0) throw FATAL("Failed to create new video stream"); // result->Create(fourcc, srchdr); m_streams.push_back(result); return result; } IAviAudioWriteStream* AviWriteFile::AddAudioStream(int fourcc, WAVEFORMATEX* fmt, int bitrate, int flags) { int ckid; ckid=MAKEAVICKID(cktypeWAVEbytes, m_streams.size()); AviAudioWriteStream* result=new AviAudioWriteStream (this, ckid, fourcc, fmt, bitrate, flags); if(result==0) throw FATAL("Failed to create new video stream"); m_streams.push_back(result); return result; } #define write_int(X) m_fd->write_int(X) // temp=(X); // write(m_fd, &temp, 4); AviWriteFile::~AviWriteFile() { int temp; if(m_status==0) return; try { offset_t videoendpos=m_fd->lseek(0, SEEK_CUR); if(videoendpos&1) { int junk=-1; m_fd->write( &junk, 1); videoendpos++; } WriteHeaders(); write_int(ckidAVINEWINDEX); write_int(m_index.size()*sizeof(AVIINDEXENTRY)); m_fd->write( &m_index[0], m_index.size()*sizeof(AVIINDEXENTRY)); videoendpos=m_fd->lseek(0, SEEK_END); m_fd->lseek(4, SEEK_SET); write_int(videoendpos-8); _destruct(); } catch(...) { _destruct(); throw; } } void AviWriteFile::_destruct() { if(m_fd)delete m_fd; m_fd=0; for(int i=0; ilseek(0, SEEK_CUR); } AviWriteStream::AviWriteStream (AviWriteFile* file, int ckid, enum AviStream::StreamType type, const char* format, Unsigned format_size, int handler, int frame_rate, int samplesize, int quality, int flags) :m_file(file), m_ckid(ckid) { if(format==0) throw FATAL("Bad format"); if(type==Other) throw FATAL("Unsupported stream type"); m_type=type; m_fd=file->m_fd; m_header.dwLength=0; memset(&m_header, 0, sizeof(m_header)); m_header.fccType=((m_type==Video)?streamtypeVIDEO:streamtypeAUDIO); m_header.fccHandler=handler; m_header.dwFlags=flags; if(m_type==Video) { m_header.dwRate=1000000; m_header.dwScale=frame_rate; } else { m_header.dwRate=frame_rate; m_header.dwScale=samplesize; } m_header.dwSampleSize=samplesize; m_header.dwQuality=quality; m_header.dwFlags=flags; m_format=new char[format_size]; m_forsize=format_size; memcpy(m_format, format, format_size); if(m_type==Video) { m_header.rcFrame.right=*(int*)(format+4); m_header.rcFrame.bottom=*(int*)(format+8); } return; } AviWriteStream::AviWriteStream(AviWriteFile* file, int ckid, enum AviStream::StreamType type, int handler, int frame_rate, int flags) :m_file(file), m_ckid(ckid), m_format(0) { m_fd=file->m_fd; m_header.dwLength=0; memset(&m_header, 0, sizeof(m_header)); m_header.fccHandler=handler; m_header.dwFlags=flags; m_header.dwSampleSize=0; m_header.dwFlags=flags; switch(type) { case Other: throw FATAL("Bad type"); case Video: m_type=Video; m_header.fccType=streamtypeVIDEO; m_header.dwRate=1000000; m_header.dwScale=frame_rate; break; case Audio: m_type=Audio; m_header.fccType=streamtypeAUDIO; m_header.dwRate=frame_rate; m_header.dwScale=1; break; } return; } HRESULT AviWriteStream::AddChunk(const char* chunk, Unsigned size, Unsigned flags) { if((chunk==0) && (size!=0)) { cerr<<"Invalid argument to AviWriteStream::AddChunk()"<lseek(0, SEEK_CUR); if(offset>0x7f000000) return -1; m_fd->write( &m_ckid, 4); m_fd->write( &size, 4); if(chunk) { m_fd->write( chunk, size); if(size&1)m_fd->write( chunk, 1); } // fsync(m_fd); m_file->AddChunk(offset-0x7FC, size, m_ckid, flags); if(m_header.dwSampleSize==0) m_header.dwLength++; else m_header.dwLength+=size/m_header.dwSampleSize; return 0; } HRESULT AviWriteFile::Reserve(Unsigned size){return -1;} HRESULT AviWriteFile::WriteChunk(int fourcc, char* data, int size){return -1;} AviWriteStream::~AviWriteStream() { if(m_format) delete m_format; } IAviWriteStream::~IAviWriteStream(){} IAviVideoWriteStream::~IAviVideoWriteStream(){} IAviWriteFile::~IAviWriteFile(){} IAviWriteFile* CreateIAviWriteFile(const char* name, int flags, int mask) { return new AviWriteFile(name, flags, mask); } void AviWriteFile::WriteHeaders() { int i; Unsigned temp; // cerr<<"Writing headers"<GetType()==AviWriteStream::Video) { m_header.dwTotalFrames=m_streams[i]->GetLength(); m_header.dwMicroSecPerFrame=m_streams[i]->m_header.dwScale; m_header.dwWidth=m_streams[i]->m_header.rcFrame.right; m_header.dwHeight=m_streams[i]->m_header.rcFrame.bottom; break; } } if(m_header.dwTotalFrames==0) if(m_streams.size()) { m_header.dwTotalFrames=m_streams[0]->GetLength(); m_header.dwWidth=m_header.dwHeight=0; } m_header.dwStreams=m_streams.size(); offset_t endpos=m_fd->lseek( 0, SEEK_END); m_fd->lseek( 0, SEEK_SET); write_int(mmioFOURCC('R', 'I', 'F', 'F')); write_int(endpos-8); write_int(formtypeAVI);// Here goes chunk with all headers write_int(mmioFOURCC('L', 'I', 'S', 'T')); int hdr_pos=0x10; write_int(0);//here header chunk size hdr_size will be int hdr_size=12+sizeof(MainAVIHeader); write_int(listtypeAVIHEADER); write_int(ckidAVIMAINHDR); write_int(sizeof(MainAVIHeader)); m_fd->write( &m_header, sizeof(MainAVIHeader)); for(int i=0; im_forsize+(m_streams[i]->m_forsize&1)); write_int(listtypeSTREAMHEADER); write_int(ckidSTREAMHEADER); write_int(sizeof(AVIStreamHeader)); m_fd->write( &m_streams[i]->m_header, sizeof(AVIStreamHeader)); write_int(ckidSTREAMFORMAT); write_int(m_streams[i]->m_forsize); m_fd->write( m_streams[i]->m_format, m_streams[i]->m_forsize); if(m_streams[i]->m_forsize&1)m_fd->write( &m_fd, 1); hdr_size+=28+sizeof(AVIStreamHeader)+m_streams[i]->m_forsize+(m_streams[i]->m_forsize&1); } if(hdr_size>0x700) throw FATAL("Too large header. Aborting"); int curpos=m_fd->lseek( 0, SEEK_CUR); write_int(ckidAVIPADDING); write_int(0x7F4-(curpos+8)); m_fd->lseek( 0x7F4, SEEK_SET); write_int(mmioFOURCC('L', 'I', 'S', 'T')); write_int(endpos-0x7FC); write_int(listtypeAVIMOVIE); m_fd->lseek( hdr_pos, SEEK_SET); write_int(hdr_size); m_fd->lseek( 0, SEEK_END); }