void CAPTURE_VideoEvent(bool pressed) { if (!pressed) return; if (CaptureState & CAPTURE_VIDEO) { /* Close the video */ CaptureState &= ~CAPTURE_VIDEO; LOG_MSG("Stopped capturing video."); Bit8u avi_header[AVI_HEADER_SIZE]; Bitu main_list; Bitu header_pos=0; #define AVIOUT4(_S_) memcpy(&avi_header[header_pos],_S_,4);header_pos+=4; #define AVIOUTw(_S_) host_writew(&avi_header[header_pos], _S_);header_pos+=2; #define AVIOUTd(_S_) host_writed(&avi_header[header_pos], _S_);header_pos+=4; /* Try and write an avi header */ AVIOUT4("RIFF"); // Riff header AVIOUTd(AVI_HEADER_SIZE + capture.video.written - 8 + capture.video.indexused); AVIOUT4("AVI "); AVIOUT4("LIST"); // List header main_list = header_pos; AVIOUTd(0); // TODO size of list AVIOUT4("hdrl"); AVIOUT4("avih"); AVIOUTd(56); /* # of bytes to follow */ AVIOUTd((Bit32u)(1000000 / capture.video.fps)); /* Microseconds per frame */ AVIOUTd(0); AVIOUTd(0); /* PaddingGranularity (whatever that might be) */ AVIOUTd(0x110); /* Flags,0x10 has index, 0x100 interleaved */ AVIOUTd(capture.video.frames); /* TotalFrames */ AVIOUTd(0); /* InitialFrames */ AVIOUTd(2); /* Stream count */ AVIOUTd(0); /* SuggestedBufferSize */ AVIOUTd(capture.video.width); /* Width */ AVIOUTd(capture.video.height); /* Height */ AVIOUTd(0); /* TimeScale: Unit used to measure time */ AVIOUTd(0); /* DataRate: Data rate of playback */ AVIOUTd(0); /* StartTime: Starting time of AVI data */ AVIOUTd(0); /* DataLength: Size of AVI data chunk */ /* Video stream list */ AVIOUT4("LIST"); AVIOUTd(4 + 8 + 56 + 8 + 40); /* Size of the list */ AVIOUT4("strl"); /* video stream header */ AVIOUT4("strh"); AVIOUTd(56); /* # of bytes to follow */ AVIOUT4("vids"); /* Type */ AVIOUT4(CODEC_4CC); /* Handler */ AVIOUTd(0); /* Flags */ AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ AVIOUTd(0); /* InitialFrames */ AVIOUTd(1000000); /* Scale */ AVIOUTd((Bit32u)(1000000 * capture.video.fps)); /* Rate: Rate/Scale == samples/second */ AVIOUTd(0); /* Start */ AVIOUTd(capture.video.frames); /* Length */ AVIOUTd(0); /* SuggestedBufferSize */ AVIOUTd(~0); /* Quality */ AVIOUTd(0); /* SampleSize */ AVIOUTd(0); /* Frame */ AVIOUTd(0); /* Frame */ /* The video stream format */ AVIOUT4("strf"); AVIOUTd(40); /* # of bytes to follow */ AVIOUTd(40); /* Size */ AVIOUTd(capture.video.width); /* Width */ AVIOUTd(capture.video.height); /* Height */ // OUTSHRT(1); OUTSHRT(24); /* Planes, Count */ AVIOUTd(0); AVIOUT4(CODEC_4CC); /* Compression */ AVIOUTd(capture.video.width * capture.video.height*4); /* SizeImage (in bytes?) */ AVIOUTd(0); /* XPelsPerMeter */ AVIOUTd(0); /* YPelsPerMeter */ AVIOUTd(0); /* ClrUsed: Number of colors used */ AVIOUTd(0); /* ClrImportant: Number of colors important */ /* Audio stream list */ AVIOUT4("LIST"); AVIOUTd(4 + 8 + 56 + 8 + 16); /* Length of list in bytes */ AVIOUT4("strl"); /* The audio stream header */ AVIOUT4("strh"); AVIOUTd(56); /* # of bytes to follow */ AVIOUT4("auds"); AVIOUTd(0); /* Format (Optionally) */ AVIOUTd(0); /* Flags */ AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ AVIOUTd(0); /* InitialFrames */ AVIOUTd(4); /* Scale */ AVIOUTd(capture.video.audiorate*4); /* Rate, actual rate is scale/rate */ AVIOUTd(0); /* Start */ if (!capture.video.audiorate) capture.video.audiorate = 1; AVIOUTd(capture.video.audiowritten/4); /* Length */ AVIOUTd(0); /* SuggestedBufferSize */ AVIOUTd(~0); /* Quality */ AVIOUTd(4); /* SampleSize */ AVIOUTd(0); /* Frame */ AVIOUTd(0); /* Frame */ /* The audio stream format */ AVIOUT4("strf"); AVIOUTd(16); /* # of bytes to follow */ AVIOUTw(1); /* Format, WAVE_ZMBV_FORMAT_PCM */ AVIOUTw(2); /* Number of channels */ AVIOUTd(capture.video.audiorate); /* SamplesPerSec */ AVIOUTd(capture.video.audiorate*4); /* AvgBytesPerSec*/ AVIOUTw(4); /* BlockAlign */ AVIOUTw(16); /* BitsPerSample */ int nmain = header_pos - main_list - 4; /* Finish stream list, i.e. put number of bytes in the list to proper pos */ int njunk = AVI_HEADER_SIZE - 8 - 12 - header_pos; AVIOUT4("JUNK"); AVIOUTd(njunk); /* Fix the size of the main list */ header_pos = main_list; AVIOUTd(nmain); header_pos = AVI_HEADER_SIZE - 12; AVIOUT4("LIST"); AVIOUTd(capture.video.written+4); /* Length of list in bytes */ AVIOUT4("movi"); /* First add the index table to the end */ memcpy(capture.video.index, "idx1", 4); host_writed( capture.video.index+4, capture.video.indexused - 8 ); fwrite( capture.video.index, 1, capture.video.indexused, capture.video.handle); fseek(capture.video.handle, 0, SEEK_SET); fwrite(&avi_header, 1, AVI_HEADER_SIZE, capture.video.handle); fclose( capture.video.handle ); free( capture.video.index ); free( capture.video.buf ); delete capture.video.codec; capture.video.handle = 0; } else { CaptureState |= CAPTURE_VIDEO; } }
void run() { bool doDecode = false; static const int samples = 450*1024; static const int inputBufferSize = samples; static const int sampleSpaceBefore = 256; static const int sampleSpaceAfter = 256; FileHandle in = File("captured.zdr", true).openRead(); UInt64 inputFileSizeRemaining = in.size(); Array<Byte> inputBuffer(inputBufferSize); int inputBufferRemaining = 0; Byte* inputPointer = 0; z_stream zs; memset(&zs, 0, sizeof(z_stream)); if (inflateInit(&zs) != Z_OK) throw Exception("inflateInit failed"); Array<Byte> buffer(sampleSpaceBefore + samples + sampleSpaceAfter); Byte* b = &buffer[0] + sampleSpaceBefore; for (int i = 0; i < sampleSpaceBefore; ++i) b[i - sampleSpaceBefore] = 0; for (int i = 0; i < sampleSpaceAfter; ++i) b[i + samples] = 0; int outputBytesRemaining = samples; Vector outputSize; NTSCCaptureDecoder<UInt32> decoder; if (doDecode) outputSize = Vector(1280, 720); else outputSize = Vector(1824, 253); Bitmap<UInt32> decoded(outputSize); if (doDecode) decoder.setOutputBuffer( decoded.subBitmap(Vector(160, 0), Vector(960, 720))); else decoder.setOutputBuffer(decoded); decoded.fill(0); decoder.setInputBuffer(b); decoder.setOutputPixelsPerLine(1140); decoder.setYScale(3); decoder.setDoDecode(doDecode); _handle = fopen("u:\\captured2.avi","wb"); if (!_handle) throw Exception("Can't open file"); _VectorCount = 1; _VectorTable[0].x = _VectorTable[0].y = 0; for (int s = 1; s <= 10; ++s) { for (int y = -s; y <= s; ++y) for (int x = -s; x <= s; ++x) { if (abs(x) == s || abs(y) == s) { _VectorTable[_VectorCount].x = x; _VectorTable[_VectorCount].y = y; ++_VectorCount; } } } memset(&_zstream, 0, sizeof(_zstream)); _pitch = outputSize.x + 2*MAX_VECTOR; if (deflateInit(&_zstream, 4) != Z_OK) throw Exception("deflateInit failed"); _bufSize = 4*outputSize.x*outputSize.y + 2*(1+(outputSize.x/8)) * (1+(outputSize.y/8))+1024; _bufSize += _bufSize / 1000; _buf = malloc(_bufSize); if (!_buf) throw Exception("Out of memory"); _index = (UInt8*)malloc(16*4096); if (!_buf) throw Exception("Out of memory"); _indexsize = 16*4096; _indexused = 8; for (int i = 0; i < AVI_HEADER_SIZE; ++i) fputc(0, _handle); _frames = 0; _written = 0; _audioused = 0; _audiowritten = 0; int blockwidth = 16; int blockheight = 16; _pixelsize = 4; _bufsize = (outputSize.y + 2*MAX_VECTOR)*_pitch*_pixelsize+2048; _buf1.allocate(_bufsize); _buf2.allocate(_bufsize); _work.allocate(_bufsize); int xblocks = (outputSize.x/blockwidth); int xleft = outputSize.x % blockwidth; if (xleft) ++xblocks; int yblocks = (outputSize.y/blockheight); int yleft = outputSize.y % blockheight; if (yleft) ++yblocks; _blockcount = yblocks*xblocks; _blocks = new FrameBlock[_blockcount]; int i = 0; for (int y = 0; y < yblocks; ++y) { for (int x = 0; x < xblocks; ++x) { _blocks[i].start = ((y*blockheight) + MAX_VECTOR)*_pitch+ x*blockwidth + MAX_VECTOR; if (xleft && x == xblocks - 1) { _blocks[i].dx = xleft; } else { _blocks[i].dx = blockwidth; } if (yleft && y == yblocks - 1) { _blocks[i].dy = yleft; } else { _blocks[i].dy = blockheight; } ++i; } } memset(&_buf1[0], 0, _bufsize); memset(&_buf2[0], 0, _bufsize); memset(&_work[0], 0, _bufsize); _oldframe = &_buf1[0]; _newframe = &_buf2[0]; do { if (inputBufferRemaining == 0) { int bytesToRead = inputBufferSize; if (bytesToRead > inputFileSizeRemaining) bytesToRead = inputFileSizeRemaining; inputPointer = &inputBuffer[0]; in.read(inputPointer, bytesToRead); inputBufferRemaining = bytesToRead; inputFileSizeRemaining -= bytesToRead; } zs.avail_in = inputBufferRemaining; zs.next_in = inputPointer; zs.avail_out = outputBytesRemaining; zs.next_out = b + samples - outputBytesRemaining; int r = inflate(&zs, Z_SYNC_FLUSH); if (r != Z_STREAM_END && r != Z_OK) throw Exception("inflate failed"); outputBytesRemaining = zs.avail_out; inputPointer = zs.next_in; inputBufferRemaining = zs.avail_in; if (outputBytesRemaining == 0) { if (inflateReset(&zs) != Z_OK) throw Exception("inflateReset failed"); outputBytesRemaining = samples; console.write("."); decoder.decode(); bool keyFrame = false; if (_frames % 300 == 0) keyFrame = true; keyFrame = true; /* replace oldframe with new frame */ unsigned char* copyFrame = _newframe; _newframe = _oldframe; _oldframe = copyFrame; compress.linesDone = 0; compress.writeSize = _bufSize; compress.writeDone = 1; compress.writeBuf = (unsigned char *)_buf; /* Set a pointer to the first byte which will contain info about this frame */ unsigned char* firstByte = compress.writeBuf; *firstByte = 0; //Reset the work buffer _workUsed = 0; _workPos = 0; if (keyFrame) { /* Make a keyframe */ *firstByte |= Mask_KeyFrame; KeyframeHeader* header = (KeyframeHeader *)(compress.writeBuf + compress.writeDone); header->high_version = 0; // DBZV_VERSION_HIGH; header->low_version = 1; // DBZV_VERSION_LOW; header->compression = 1; // COMPRESSION_ZLIB header->format = 8; // ZMBV_FORMAT_32BPP header->blockwidth = 16; header->blockheight = 16; compress.writeDone += sizeof(KeyframeHeader); /* Copy the new frame directly over */ /* Restart deflate */ deflateReset(&_zstream); } for (int i = 0; i < outputSize.y; ++i) { void* rowPointer = decoded.data() + decoded.stride()*i; unsigned char* destStart = _newframe + _pixelsize*(MAX_VECTOR+(compress.linesDone+MAX_VECTOR)*_pitch); memcpy(destStart, rowPointer, outputSize.x * _pixelsize); destStart += _pitch * _pixelsize; compress.linesDone++; } if ((*compress.writeBuf) & Mask_KeyFrame) { /* Add the full frame data */ unsigned char* readFrame = _newframe + _pixelsize*(MAX_VECTOR+MAX_VECTOR*_pitch); for (int i = 0; i < outputSize.y; ++i) { memcpy(&_work[_workUsed], readFrame, outputSize.x*_pixelsize); readFrame += _pitch*_pixelsize; _workUsed += outputSize.x*_pixelsize; } } else { /* Add the delta frame data */ int written = 0; int lastvector = 0; signed char* vectors = (signed char*)&_work[_workUsed]; /* Align the following xor data on 4 byte boundary*/ _workUsed = (_workUsed + _blockcount*2 + 3) & ~3; int totalx = 0; int totaly = 0; for (int b = 0; b < _blockcount; ++b) { FrameBlock* block = &_blocks[b]; int bestvx = 0; int bestvy = 0; int bestchange = CompareBlock(0, 0, block); int possibles = 64; for (int v = 0; v < _VectorCount && possibles; ++v) { if (bestchange < 4) break; int vx = _VectorTable[v].x; int vy = _VectorTable[v].y; if (PossibleBlock(vx, vy, block) < 4) { --possibles; int testchange = CompareBlock(vx, vy, block); if (testchange < bestchange) { bestchange = testchange; bestvx = vx; bestvy = vy; } } } vectors[b*2+0] = (bestvx << 1); vectors[b*2+1] = (bestvy << 1); if (bestchange) { vectors[b*2+0] |= 1; long* pold=((long*)_oldframe) + block->start + bestvy*_pitch + bestvx; long* pnew=((long*)_newframe) + block->start; for (int y = 0; y < block->dy; ++y) { for (int x = 0; x < block->dx; ++x) { *((long*)&_work[_workUsed]) = pnew[x] ^ pold[x]; _workUsed += sizeof(long); } pold += _pitch; pnew += _pitch; } } } } /* Create the actual frame with compression */ _zstream.next_in = (Bytef *)&_work[0]; _zstream.avail_in = _workUsed; _zstream.total_in = 0; _zstream.next_out = (Bytef *)(compress.writeBuf + compress.writeDone); _zstream.avail_out = compress.writeSize - compress.writeDone; _zstream.total_out = 0; int res = deflate(&_zstream, Z_SYNC_FLUSH); int written = compress.writeDone + _zstream.total_out; CAPTURE_AddAviChunk( "00dc", written, _buf, keyFrame ? 0x10 : 0x0); ++_frames; //void CAPTURE_AddWave(UInt32 freq, UInt32 len, SInt16 * data) //{ // UInt left = WAVE_BUF - _audioused; // if (left > len) // left = len; // memcpy( &_audiobuf[_audioused], data, left*4); // _audioused += left; // _audiorate = freq; //} //if ( capture.video.audioused ) { // CAPTURE_AddAviChunk( "01wb", _audioused * 4, _audiobuf, 0); // _audiowritten = _audioused*4; // _audioused = 0; //} } } while (inputFileSizeRemaining != 0); if (inflateEnd(&zs) != Z_OK) throw Exception("inflateEnd failed"); int main_list; _header_pos = 0; /* Try and write an avi header */ AVIOUT4("RIFF"); // Riff header AVIOUTd(AVI_HEADER_SIZE + _written - 8 + _indexused); AVIOUT4("AVI "); AVIOUT4("LIST"); // List header main_list = _header_pos; AVIOUTd(0); // TODO size of list AVIOUT4("hdrl"); AVIOUT4("avih"); AVIOUTd(56); /* # of bytes to follow */ AVIOUTd((11*912*262*2)/315); /* Microseconds per frame */ // 1752256/105 ~= 16688 AVIOUTd(0); AVIOUTd(0); /* PaddingGranularity (whatever that might be) */ AVIOUTd(0x110); /* Flags,0x10 has index, 0x100 interleaved */ AVIOUTd(_frames); /* TotalFrames */ AVIOUTd(0); /* InitialFrames */ AVIOUTd(2); /* Stream count */ AVIOUTd(0); /* SuggestedBufferSize */ AVIOUTd(outputSize.x); /* Width */ AVIOUTd(outputSize.y); /* Height */ AVIOUTd(0); /* TimeScale: Unit used to measure time */ AVIOUTd(0); /* DataRate: Data rate of playback */ AVIOUTd(0); /* StartTime: Starting time of AVI data */ AVIOUTd(0); /* DataLength: Size of AVI data chunk */ /* Video stream list */ AVIOUT4("LIST"); AVIOUTd(4 + 8 + 56 + 8 + 40); /* Size of the list */ AVIOUT4("strl"); /* video stream header */ AVIOUT4("strh"); AVIOUTd(56); /* # of bytes to follow */ AVIOUT4("vids"); /* Type */ AVIOUT4(CODEC_4CC); /* Handler */ AVIOUTd(0); /* Flags */ AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ AVIOUTd(0); /* InitialFrames */ AVIOUTd(82137); /* Scale */ // 11*912*262 AVIOUTd(4921875); /* Rate: Rate/Scale == samples/second */ // 157500000 AVIOUTd(0); /* Start */ AVIOUTd(_frames); /* Length */ AVIOUTd(0); /* SuggestedBufferSize */ AVIOUTd(~0); /* Quality */ AVIOUTd(0); /* SampleSize */ AVIOUTd(0); /* Frame */ AVIOUTd(0); /* Frame */ /* The video stream format */ AVIOUT4("strf"); AVIOUTd(40); /* # of bytes to follow */ AVIOUTd(40); /* Size */ AVIOUTd(outputSize.x); /* Width */ AVIOUTd(outputSize.y); /* Height */ // OUTSHRT(1); OUTSHRT(24); /* Planes, Count */ AVIOUTd(0); AVIOUT4(CODEC_4CC); /* Compression */ AVIOUTd(outputSize.x*outputSize.y*4); /* SizeImage (in bytes?) */ AVIOUTd(0); /* XPelsPerMeter */ AVIOUTd(0); /* YPelsPerMeter */ AVIOUTd(0); /* ClrUsed: Number of colors used */ AVIOUTd(0); /* ClrImportant: Number of colors important */ /* Audio stream list */ AVIOUT4("LIST"); AVIOUTd(4 + 8 + 56 + 8 + 16); /* Length of list in bytes */ AVIOUT4("strl"); /* The audio stream header */ AVIOUT4("strh"); AVIOUTd(56); /* # of bytes to follow */ AVIOUT4("auds"); AVIOUTd(0); /* Format (Optionally) */ AVIOUTd(0); /* Flags */ AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ AVIOUTd(0); /* InitialFrames */ AVIOUTd(4); /* Scale */ AVIOUTd(_audiorate*4); /* Rate, actual rate is scale/rate */ AVIOUTd(0); /* Start */ if (!_audiorate) _audiorate = 1; AVIOUTd(_audiowritten/4); /* Length */ AVIOUTd(0); /* SuggestedBufferSize */ AVIOUTd(~0); /* Quality */ AVIOUTd(4); /* SampleSize */ AVIOUTd(0); /* Frame */ AVIOUTd(0); /* Frame */ /* The audio stream format */ AVIOUT4("strf"); AVIOUTd(16); /* # of bytes to follow */ AVIOUTw(1); /* Format, WAVE_ZMBV_FORMAT_PCM */ AVIOUTw(2); /* Number of channels */ AVIOUTd(_audiorate); /* SamplesPerSec */ AVIOUTd(_audiorate*4); /* AvgBytesPerSec*/ AVIOUTw(4); /* BlockAlign */ AVIOUTw(16); /* BitsPerSample */ int nmain = _header_pos - main_list - 4; /* Finish stream list, i.e. put number of bytes in the list to proper pos */ int njunk = AVI_HEADER_SIZE - 8 - 12 - _header_pos; AVIOUT4("JUNK"); AVIOUTd(njunk); /* Fix the size of the main list */ _header_pos = main_list; AVIOUTd(nmain); _header_pos = AVI_HEADER_SIZE - 12; AVIOUT4("LIST"); AVIOUTd(_written + 4); /* Length of list in bytes */ AVIOUT4("movi"); /* First add the index table to the end */ memcpy(_index, "idx1", 4); host_writed(_index+4, _indexused - 8 ); fwrite(_index, 1, _indexused, _handle); fseek(_handle, 0, SEEK_SET); fwrite(&_avi_header, 1, AVI_HEADER_SIZE, _handle); fclose(_handle); free(_index); free(_buf); _handle = 0; }
void AviWriter::EndWrite() { /* Close the video */ uint8_t avi_header[AviWriter::AviHeaderSize]; uint32_t main_list; uint32_t header_pos = 0; #define AVIOUT4(_S_) memcpy(&avi_header[header_pos],_S_,4);header_pos+=4; #define AVIOUTw(_S_) host_writew(&avi_header[header_pos], _S_);header_pos+=2; #define AVIOUTd(_S_) host_writed(&avi_header[header_pos], _S_);header_pos+=4; /* Try and write an avi header */ AVIOUT4("RIFF"); // Riff header AVIOUTd(AviWriter::AviHeaderSize + _written - 8 + (uint32_t)_aviIndex.size()); AVIOUT4("AVI "); AVIOUT4("LIST"); // List header main_list = header_pos; AVIOUTd(0); // TODO size of list AVIOUT4("hdrl"); AVIOUT4("avih"); AVIOUTd(56); /* # of bytes to follow */ AVIOUTd((uint32_t)(1000000 / _fps)); /* Microseconds per frame */ AVIOUTd(0); AVIOUTd(0); /* PaddingGranularity (whatever that might be) */ AVIOUTd(0x110); /* Flags,0x10 has index, 0x100 interleaved */ AVIOUTd(_frames); /* TotalFrames */ AVIOUTd(0); /* InitialFrames */ AVIOUTd(2); /* Stream count */ AVIOUTd(0); /* SuggestedBufferSize */ AVIOUTd(_width); /* Width */ AVIOUTd(_height); /* Height */ AVIOUTd(0); /* TimeScale: Unit used to measure time */ AVIOUTd(0); /* DataRate: Data rate of playback */ AVIOUTd(0); /* StartTime: Starting time of AVI data */ AVIOUTd(0); /* DataLength: Size of AVI data chunk */ /* Video stream list */ AVIOUT4("LIST"); AVIOUTd(4 + 8 + 56 + 8 + 40); /* Size of the list */ AVIOUT4("strl"); /* video stream header */ AVIOUT4("strh"); AVIOUTd(56); /* # of bytes to follow */ AVIOUT4("vids"); /* Type */ AVIOUT4(_codec->GetFourCC()); /* Handler */ AVIOUTd(0); /* Flags */ AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ AVIOUTd(0); /* InitialFrames */ AVIOUTd(1000000); /* Scale */ AVIOUTd(_fps); /* Rate: Rate/Scale == samples/second */ AVIOUTd(0); /* Start */ AVIOUTd(_frames); /* Length */ AVIOUTd(0); /* SuggestedBufferSize */ AVIOUTd(~0); /* Quality */ AVIOUTd(0); /* SampleSize */ AVIOUTd(0); /* Frame */ AVIOUTd(0); /* Frame */ /* The video stream format */ AVIOUT4("strf"); AVIOUTd(40); /* # of bytes to follow */ AVIOUTd(40); /* Size */ AVIOUTd(_width); /* Width */ AVIOUTd(_height); /* Height */ // OUTSHRT(1); OUTSHRT(24); /* Planes, Count */ AVIOUTw(1); //number of planes AVIOUTw(24); //bits for colors AVIOUT4(_codec->GetFourCC()); /* Compression */ AVIOUTd(_width * _height * 4); /* SizeImage (in bytes?) */ AVIOUTd(0); /* XPelsPerMeter */ AVIOUTd(0); /* YPelsPerMeter */ AVIOUTd(0); /* ClrUsed: Number of colors used */ AVIOUTd(0); /* ClrImportant: Number of colors important */ /* Audio stream list */ AVIOUT4("LIST"); AVIOUTd(4 + 8 + 56 + 8 + 16); /* Length of list in bytes */ AVIOUT4("strl"); /* The audio stream header */ AVIOUT4("strh"); AVIOUTd(56); /* # of bytes to follow */ AVIOUT4("auds"); AVIOUTd(0); /* Format (Optionally) */ AVIOUTd(0); /* Flags */ AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ AVIOUTd(0); /* InitialFrames */ AVIOUTd(4); /* Scale */ AVIOUTd(_audiorate * 4); /* Rate, actual rate is scale/rate */ AVIOUTd(0); /* Start */ if(!_audiorate) _audiorate = 1; AVIOUTd(_audiowritten / 4); /* Length */ AVIOUTd(0); /* SuggestedBufferSize */ AVIOUTd(~0); /* Quality */ AVIOUTd(4); /* SampleSize */ AVIOUTd(0); /* Frame */ AVIOUTd(0); /* Frame */ /* The audio stream format */ AVIOUT4("strf"); AVIOUTd(16); /* # of bytes to follow */ AVIOUTw(1); /* Format, WAVE_ZMBV_FORMAT_PCM */ AVIOUTw(2); /* Number of channels */ AVIOUTd(_audiorate); /* SamplesPerSec */ AVIOUTd(_audiorate * 4); /* AvgBytesPerSec*/ AVIOUTw(4); /* BlockAlign */ AVIOUTw(16); /* BitsPerSample */ int nmain = header_pos - main_list - 4; /* Finish stream list, i.e. put number of bytes in the list to proper pos */ int njunk = AviWriter::AviHeaderSize - 8 - 12 - header_pos; AVIOUT4("JUNK"); AVIOUTd(njunk); /* Fix the size of the main list */ header_pos = main_list; AVIOUTd(nmain); header_pos = AviWriter::AviHeaderSize - 12; AVIOUT4("LIST"); AVIOUTd(_written + 4); /* Length of list in bytes */ AVIOUT4("movi"); /* First add the index table to the end */ memcpy(_aviIndex.data(), "idx1", 4); host_writed(_aviIndex.data() + 4, (uint32_t)_aviIndex.size() - 8); _file.write((char*)_aviIndex.data(), _aviIndex.size()); _file.seekp(std::ios::beg); _file.write((char*)avi_header, AviWriter::AviHeaderSize); _file.close(); }