-static void SCR_CaptureVideo_RIFF_Start(void)
-{
- memset(&cls.capturevideo.riffbuffer, 0, sizeof(sizebuf_t));
- cls.capturevideo.riffbuffer.maxsize = sizeof(cls.capturevideo.riffbufferdata);
- cls.capturevideo.riffbuffer.data = cls.capturevideo.riffbufferdata;
-}
-
-static void SCR_CaptureVideo_RIFF_Flush(void)
-{
- if (cls.capturevideo.riffbuffer.cursize > 0)
- {
- if (!FS_Write(cls.capturevideo.videofile, cls.capturevideo.riffbuffer.data, cls.capturevideo.riffbuffer.cursize))
- cls.capturevideo.error = true;
- cls.capturevideo.riffbuffer.cursize = 0;
- cls.capturevideo.riffbuffer.overflowed = false;
- }
-}
-
-static void SCR_CaptureVideo_RIFF_WriteBytes(const unsigned char *data, size_t size)
-{
- SCR_CaptureVideo_RIFF_Flush();
- if (!FS_Write(cls.capturevideo.videofile, data, size))
- cls.capturevideo.error = true;
-}
-
-static void SCR_CaptureVideo_RIFF_Write32(int n)
-{
- if (cls.capturevideo.riffbuffer.cursize + 4 > cls.capturevideo.riffbuffer.maxsize)
- SCR_CaptureVideo_RIFF_Flush();
- MSG_WriteLong(&cls.capturevideo.riffbuffer, n);
-}
-
-static void SCR_CaptureVideo_RIFF_Write16(int n)
-{
- if (cls.capturevideo.riffbuffer.cursize + 2 > cls.capturevideo.riffbuffer.maxsize)
- SCR_CaptureVideo_RIFF_Flush();
- MSG_WriteShort(&cls.capturevideo.riffbuffer, n);
-}
-
-static void SCR_CaptureVideo_RIFF_WriteFourCC(const char *chunkfourcc)
-{
- if (cls.capturevideo.riffbuffer.cursize + (int)strlen(chunkfourcc) > cls.capturevideo.riffbuffer.maxsize)
- SCR_CaptureVideo_RIFF_Flush();
- MSG_WriteUnterminatedString(&cls.capturevideo.riffbuffer, chunkfourcc);
-}
-
-static void SCR_CaptureVideo_RIFF_WriteTerminatedString(const char *string)
-{
- if (cls.capturevideo.riffbuffer.cursize + (int)strlen(string) > cls.capturevideo.riffbuffer.maxsize)
- SCR_CaptureVideo_RIFF_Flush();
- MSG_WriteString(&cls.capturevideo.riffbuffer, string);
-}
-
-static fs_offset_t SCR_CaptureVideo_RIFF_GetPosition(void)
-{
- SCR_CaptureVideo_RIFF_Flush();
- return FS_Tell(cls.capturevideo.videofile);
-}
-
-static void SCR_CaptureVideo_RIFF_Push(const char *chunkfourcc, const char *listtypefourcc)
-{
- SCR_CaptureVideo_RIFF_WriteFourCC(chunkfourcc);
- SCR_CaptureVideo_RIFF_Write32(0);
- SCR_CaptureVideo_RIFF_Flush();
- cls.capturevideo.riffstackstartoffset[cls.capturevideo.riffstacklevel++] = SCR_CaptureVideo_RIFF_GetPosition();
- if (listtypefourcc)
- SCR_CaptureVideo_RIFF_WriteFourCC(listtypefourcc);
-}
-
-static void SCR_CaptureVideo_RIFF_Pop(void)
-{
- fs_offset_t offset;
- int x;
- unsigned char sizebytes[4];
- // write out the chunk size and then return to the current file position
- cls.capturevideo.riffstacklevel--;
- offset = SCR_CaptureVideo_RIFF_GetPosition();
- x = (int)(offset - (cls.capturevideo.riffstackstartoffset[cls.capturevideo.riffstacklevel]));
- sizebytes[0] = (x) & 0xff;sizebytes[1] = (x >> 8) & 0xff;sizebytes[2] = (x >> 16) & 0xff;sizebytes[3] = (x >> 24) & 0xff;
- FS_Seek(cls.capturevideo.videofile, -(x + 4), SEEK_END);
- FS_Write(cls.capturevideo.videofile, sizebytes, 4);
- FS_Seek(cls.capturevideo.videofile, 0, SEEK_END);
- if (offset & 1)
- {
- unsigned char c = 0;
- FS_Write(cls.capturevideo.videofile, &c, 1);
- }
-}
-
-static void GrowBuf(sizebuf_t *buf, int extralen)
-{
- if(buf->cursize + extralen > buf->maxsize)
- {
- int oldsize = buf->maxsize;
- unsigned char *olddata;
- olddata = buf->data;
- buf->maxsize = max(buf->maxsize * 2, 4096);
- buf->data = Mem_Alloc(tempmempool, buf->maxsize);
- if(olddata)
- {
- memcpy(buf->data, olddata, oldsize);
- Mem_Free(olddata);
- }
- }
-}
-
-static void SCR_CaptureVideo_RIFF_IndexEntry(const char *chunkfourcc, int chunksize, int flags)
-{
- if (cls.capturevideo.riffstacklevel != 2)
- Sys_Error("SCR_Capturevideo_RIFF_IndexEntry: RIFF stack level is %i (should be 2)\n", cls.capturevideo.riffstacklevel);
- GrowBuf(&cls.capturevideo.riffindexbuffer, 16);
- SCR_CaptureVideo_RIFF_Flush();
- MSG_WriteUnterminatedString(&cls.capturevideo.riffindexbuffer, chunkfourcc);
- MSG_WriteLong(&cls.capturevideo.riffindexbuffer, flags);
- MSG_WriteLong(&cls.capturevideo.riffindexbuffer, (int)FS_Tell(cls.capturevideo.videofile) - cls.capturevideo.riffstackstartoffset[1]);
- MSG_WriteLong(&cls.capturevideo.riffindexbuffer, chunksize);
-}
-
-static void SCR_CaptureVideo_RIFF_MakeIxChunk(const char *fcc, const char *dwChunkId, fs_offset_t masteridx_counter, int *masteridx_count, fs_offset_t masteridx_start)
-{
- int nMatching;
- int i;
- fs_offset_t ix = SCR_CaptureVideo_RIFF_GetPosition();
- fs_offset_t pos;
-
- if(*masteridx_count >= AVI_MASTER_INDEX_SIZE)
- return;
-
- nMatching = 0; // go through index and enumerate them
- for(i = 0; i < cls.capturevideo.riffindexbuffer.cursize; i += 16)
- if(!memcmp(cls.capturevideo.riffindexbuffer.data + i, dwChunkId, 4))
- ++nMatching;
-
- SCR_CaptureVideo_RIFF_Push(fcc, NULL);
- SCR_CaptureVideo_RIFF_Write16(2); // wLongsPerEntry
- SCR_CaptureVideo_RIFF_Write16(0x0100); // bIndexType=1, bIndexSubType=0
- SCR_CaptureVideo_RIFF_Write32(nMatching); // nEntriesInUse
- SCR_CaptureVideo_RIFF_WriteFourCC(dwChunkId); // dwChunkId
- SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.videofile_ix_movistart & (fs_offset_t) 0xFFFFFFFFu);
- SCR_CaptureVideo_RIFF_Write32(((fs_offset_t) cls.capturevideo.videofile_ix_movistart) >> 32);
- SCR_CaptureVideo_RIFF_Write32(0); // dwReserved
-
- for(i = 0; i < cls.capturevideo.riffindexbuffer.cursize; i += 16)
- if(!memcmp(cls.capturevideo.riffindexbuffer.data + i, dwChunkId, 4))
- {
- unsigned int *p = (unsigned int *) (cls.capturevideo.riffindexbuffer.data + i);
- unsigned int flags = p[1];
- unsigned int rpos = p[2];
- unsigned int size = p[3];
- size &= ~0x80000000;
- if(!(flags & 0x10)) // no keyframe?
- size |= 0x80000000;
- SCR_CaptureVideo_RIFF_Write32(rpos + 8);
- SCR_CaptureVideo_RIFF_Write32(size);
- }
-
- SCR_CaptureVideo_RIFF_Pop();
- pos = SCR_CaptureVideo_RIFF_GetPosition();
- SCR_CaptureVideo_RIFF_Flush();
-
- FS_Seek(cls.capturevideo.videofile, masteridx_start + 16 * *masteridx_count, SEEK_SET);
- SCR_CaptureVideo_RIFF_Write32(ix & (fs_offset_t) 0xFFFFFFFFu);
- SCR_CaptureVideo_RIFF_Write32(((fs_offset_t) ix) >> 32);
- SCR_CaptureVideo_RIFF_Write32(pos - ix);
- SCR_CaptureVideo_RIFF_Write32(nMatching);
- SCR_CaptureVideo_RIFF_Flush();
-
- FS_Seek(cls.capturevideo.videofile, masteridx_counter, SEEK_SET);
- SCR_CaptureVideo_RIFF_Write32(++*masteridx_count);
- SCR_CaptureVideo_RIFF_Flush();
-
- FS_Seek(cls.capturevideo.videofile, 0, SEEK_END);
-}
-
-static void SCR_CaptureVideo_RIFF_Finish(qboolean final)
-{
- // close the "movi" list
- SCR_CaptureVideo_RIFF_Pop();
- if(cls.capturevideo.videofile_ix_master_video_inuse_offset)
- SCR_CaptureVideo_RIFF_MakeIxChunk("ix00", "00dc", cls.capturevideo.videofile_ix_master_video_inuse_offset, &cls.capturevideo.videofile_ix_master_video_inuse, cls.capturevideo.videofile_ix_master_video_start_offset);
- if(cls.capturevideo.videofile_ix_master_audio_inuse_offset)
- SCR_CaptureVideo_RIFF_MakeIxChunk("ix01", "01wb", cls.capturevideo.videofile_ix_master_audio_inuse_offset, &cls.capturevideo.videofile_ix_master_audio_inuse, cls.capturevideo.videofile_ix_master_audio_start_offset);
- // write the idx1 chunk that we've been building while saving the frames (for old style players)
- if(final && cls.capturevideo.videofile_firstchunkframes_offset)
- // TODO replace index creating by OpenDML ix##/##ix/indx chunk so it works for more than one AVI part too
- {
- SCR_CaptureVideo_RIFF_Push("idx1", NULL);
- SCR_CaptureVideo_RIFF_WriteBytes(cls.capturevideo.riffindexbuffer.data, cls.capturevideo.riffindexbuffer.cursize);
- SCR_CaptureVideo_RIFF_Pop();
- }
- cls.capturevideo.riffindexbuffer.cursize = 0;
- // pop the RIFF chunk itself
- while (cls.capturevideo.riffstacklevel > 0)
- SCR_CaptureVideo_RIFF_Pop();
- SCR_CaptureVideo_RIFF_Flush();
- if(cls.capturevideo.videofile_firstchunkframes_offset)
- {
- Con_DPrintf("Finishing first chunk (%d frames)\n", cls.capturevideo.frame);
- FS_Seek(cls.capturevideo.videofile, cls.capturevideo.videofile_firstchunkframes_offset, SEEK_SET);
- SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.frame);
- SCR_CaptureVideo_RIFF_Flush();
- FS_Seek(cls.capturevideo.videofile, 0, SEEK_END);
- cls.capturevideo.videofile_firstchunkframes_offset = 0;
- }
- else
- Con_DPrintf("Finishing another chunk (%d frames)\n", cls.capturevideo.frame);
-}
-
-static void SCR_CaptureVideo_RIFF_OverflowCheck(int framesize)
-{
- fs_offset_t cursize, curfilesize;
- if (cls.capturevideo.riffstacklevel != 2)
- Sys_Error("SCR_CaptureVideo_RIFF_OverflowCheck: chunk stack leakage!\n");
- // check where we are in the file
- SCR_CaptureVideo_RIFF_Flush();
- cursize = SCR_CaptureVideo_RIFF_GetPosition() - cls.capturevideo.riffstackstartoffset[0];
- curfilesize = SCR_CaptureVideo_RIFF_GetPosition();
-
- // if this would overflow the windows limit of 1GB per RIFF chunk, we need
- // to close the current RIFF chunk and open another for future frames
- if (8 + cursize + framesize + cls.capturevideo.riffindexbuffer.cursize + 8 + cls.capturevideo.riffindexbuffer.cursize + 64 > 1<<30) // note that the Ix buffer takes less space... I just don't dare to / 2 here now... sorry, maybe later
- {
- SCR_CaptureVideo_RIFF_Finish(false);
- // begin a new 1GB extended section of the AVI
- SCR_CaptureVideo_RIFF_Push("RIFF", "AVIX");
- SCR_CaptureVideo_RIFF_Push("LIST", "movi");
- cls.capturevideo.videofile_ix_movistart = cls.capturevideo.riffstackstartoffset[1];
- }
-}
-
-static void FindFraction(double val, int *num, int *denom, int denomMax)
-{
- int i;
- double bestdiff;
- // initialize
- bestdiff = fabs(val);
- *num = 0;
- *denom = 1;
-
- for(i = 1; i <= denomMax; ++i)
- {
- int inum = floor(0.5 + val * i);
- double diff = fabs(val - inum / (double)i);
- if(diff < bestdiff)
- {
- bestdiff = diff;
- *num = inum;
- *denom = i;
- }
- }
-}
-