X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=cap_avi.c;h=ea0e35445a4be10f3959c012cd9955f7eb2f11eb;hp=df75c7d32eb7b9cc875b0cc8e234f1b35cf0f34a;hb=727c2cbec73fbd199cef8e78c5403ae607f56347;hpb=c4e92b9982882076e7b35e55fb43bd1a0dbd340d diff --git a/cap_avi.c b/cap_avi.c index df75c7d3..ea0e3544 100644 --- a/cap_avi.c +++ b/cap_avi.c @@ -18,7 +18,7 @@ typedef struct capturevideostate_avi_formatspecific_s fs_offset_t videofile_ix_master_video_start_offset; fs_offset_t videofile_ix_movistart; fs_offset_t position; - qboolean canseek; + qbool canseek; sizebuf_t riffbuffer; unsigned char riffbufferdata[128]; sizebuf_t riffindexbuffer; @@ -52,6 +52,18 @@ static void SCR_CaptureVideo_RIFF_Flush(void) } } +static void SCR_CaptureVideo_RIFF_FlushNoIncrease(void) +{ + LOAD_FORMATSPECIFIC_AVI(); + if (format->riffbuffer.cursize > 0) + { + if (!FS_Write(cls.capturevideo.videofile, format->riffbuffer.data, format->riffbuffer.cursize)) + cls.capturevideo.error = true; + format->riffbuffer.cursize = 0; + format->riffbuffer.overflowed = false; + } +} + static void SCR_CaptureVideo_RIFF_WriteBytes(const unsigned char *data, size_t size) { LOAD_FORMATSPECIFIC_AVI(); @@ -135,7 +147,7 @@ static void SCR_CaptureVideo_RIFF_Pop(void) if(sizehint != -1) { int i; - Con_Printf("WARNING: invalid size hint %d when writing video data (actual size: %d)\n", (int) sizehint, x); + Con_Printf(CON_WARN "WARNING: invalid size hint %d when writing video data (actual size: %d)\n", (int) sizehint, x); for(i = 0; i <= format->riffstacklevel; ++i) { Con_Printf(" RIFF level %d = %s\n", i, format->riffstackfourcc[i]); @@ -176,7 +188,7 @@ static void SCR_CaptureVideo_RIFF_IndexEntry(const char *chunkfourcc, int chunks { LOAD_FORMATSPECIFIC_AVI(); if(!format->canseek) - Host_Error("SCR_CaptureVideo_RIFF_IndexEntry called on non-seekable AVI"); + Sys_Error("SCR_CaptureVideo_RIFF_IndexEntry called on non-seekable AVI"); if (format->riffstacklevel != 2) Sys_Error("SCR_Capturevideo_RIFF_IndexEntry: RIFF stack level is %i (should be 2)\n", format->riffstacklevel); @@ -197,7 +209,7 @@ static void SCR_CaptureVideo_RIFF_MakeIxChunk(const char *fcc, const char *dwChu fs_offset_t pos, sz; if(!format->canseek) - Host_Error("SCR_CaptureVideo_RIFF_MakeIxChunk called on non-seekable AVI"); + Sys_Error("SCR_CaptureVideo_RIFF_MakeIxChunk called on non-seekable AVI"); if(*masteridx_count >= AVI_MASTER_INDEX_SIZE) return; @@ -245,19 +257,19 @@ static void SCR_CaptureVideo_RIFF_MakeIxChunk(const char *fcc, const char *dwChu SCR_CaptureVideo_RIFF_Write32(((fs_offset_t) ix) >> 32); SCR_CaptureVideo_RIFF_Write32(pos - ix); SCR_CaptureVideo_RIFF_Write32(nMatching); - SCR_CaptureVideo_RIFF_Flush(); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); } if(FS_Seek(cls.capturevideo.videofile, masteridx_counter, SEEK_SET) >= 0) { SCR_CaptureVideo_RIFF_Write32(++*masteridx_count); - SCR_CaptureVideo_RIFF_Flush(); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); } FS_Seek(cls.capturevideo.videofile, 0, SEEK_END); // return value doesn't matter here } -static void SCR_CaptureVideo_RIFF_Finish(qboolean final) +static void SCR_CaptureVideo_RIFF_Finish(qbool final) { LOAD_FORMATSPECIFIC_AVI(); // close the "movi" list @@ -285,7 +297,7 @@ static void SCR_CaptureVideo_RIFF_Finish(qboolean final) if(FS_Seek(cls.capturevideo.videofile, format->videofile_firstchunkframes_offset, SEEK_SET) >= 0) { SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.frame); - SCR_CaptureVideo_RIFF_Flush(); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); } FS_Seek(cls.capturevideo.videofile, 0, SEEK_END); format->videofile_firstchunkframes_offset = 0; @@ -297,7 +309,8 @@ static void SCR_CaptureVideo_RIFF_Finish(qboolean final) static void SCR_CaptureVideo_RIFF_OverflowCheck(int framesize) { LOAD_FORMATSPECIFIC_AVI(); - fs_offset_t cursize, curfilesize; + fs_offset_t cursize; + //fs_offset_t curfilesize; if (format->riffstacklevel != 2) Sys_Error("SCR_CaptureVideo_RIFF_OverflowCheck: chunk stack leakage!\n"); @@ -307,7 +320,7 @@ static void SCR_CaptureVideo_RIFF_OverflowCheck(int framesize) // check where we are in the file SCR_CaptureVideo_RIFF_Flush(); cursize = SCR_CaptureVideo_RIFF_GetPosition() - format->riffstackstartoffset[0]; - curfilesize = SCR_CaptureVideo_RIFF_GetPosition(); + //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 @@ -339,7 +352,7 @@ static void SCR_CaptureVideo_ConvertFrame_BGRA_to_I420_flip(int width, int heigh blockb = b[0]; *out = cls.capturevideo.yuvnormalizetable[0][cls.capturevideo.rgbtoyuvscaletable[0][0][blockr] + cls.capturevideo.rgbtoyuvscaletable[0][1][blockg] + cls.capturevideo.rgbtoyuvscaletable[0][2][blockb]]; } - if ((y & 1) == 0) + if ((y & 1) == 0 && y/2 < height/2) // if h is odd, this skips the last row { // 2x2 Cr and Cb planes int inpitch = width*4; @@ -391,7 +404,7 @@ static void SCR_CaptureVideo_Avi_VideoFrames(int num) } } -void SCR_CaptureVideo_Avi_EndVideo() +static void SCR_CaptureVideo_Avi_EndVideo(void) { LOAD_FORMATSPECIFIC_AVI(); @@ -405,13 +418,13 @@ void SCR_CaptureVideo_Avi_EndVideo() if(FS_Seek(cls.capturevideo.videofile, format->videofile_totalframes_offset1, SEEK_SET) >= 0) { SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.frame); - SCR_CaptureVideo_RIFF_Flush(); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); } if(format->videofile_totalframes_offset2) if(FS_Seek(cls.capturevideo.videofile, format->videofile_totalframes_offset2, SEEK_SET) >= 0) { SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.frame); - SCR_CaptureVideo_RIFF_Flush(); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); } if (cls.capturevideo.soundrate) { @@ -419,7 +432,7 @@ void SCR_CaptureVideo_Avi_EndVideo() if(FS_Seek(cls.capturevideo.videofile, format->videofile_totalsampleframes_offset, SEEK_SET) >= 0) { SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.soundsampleframe); - SCR_CaptureVideo_RIFF_Flush(); + SCR_CaptureVideo_RIFF_FlushNoIncrease(); } } } @@ -436,7 +449,7 @@ void SCR_CaptureVideo_Avi_EndVideo() Mem_Free(format); } -void SCR_CaptureVideo_Avi_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length) +static void SCR_CaptureVideo_Avi_SoundFrame(const portable_sampleframe_t *paintbuffer, size_t length) { LOAD_FORMATSPECIFIC_AVI(); int x; @@ -449,18 +462,18 @@ void SCR_CaptureVideo_Avi_SoundFrame(const portable_sampleframe_t *paintbuffer, { int n0, n1; - n0 = paintbuffer[i].sample[0]; + n0 = paintbuffer[i].sample[0] * 32768.0f; n0 = bound(-32768, n0, 32767); out_ptr[0] = (unsigned char)n0; out_ptr[1] = (unsigned char)(n0 >> 8); - n1 = paintbuffer[i].sample[1]; + n1 = paintbuffer[i].sample[1] * 32768.0f; n1 = bound(-32768, n1, 32767); out_ptr[2] = (unsigned char)n1; out_ptr[3] = (unsigned char)(n1 >> 8); } - x = length*4; + x = (int)length*4; if(format->canseek) { SCR_CaptureVideo_RIFF_OverflowCheck(8 + x); @@ -482,18 +495,20 @@ void SCR_CaptureVideo_Avi_SoundFrame(const portable_sampleframe_t *paintbuffer, } } -void SCR_CaptureVideo_Avi_BeginVideo() +void SCR_CaptureVideo_Avi_BeginVideo(void) { int width = cls.capturevideo.width; int height = cls.capturevideo.height; int n, d; unsigned int i; double aspect; + char vabuf[1024]; aspect = vid.width / (vid.height * vid_pixelheight.value); cls.capturevideo.format = CAPTUREVIDEOFORMAT_AVI_I420; - cls.capturevideo.videofile = FS_OpenRealFile(va("%s.avi", cls.capturevideo.basename), "wb", false); + cls.capturevideo.formatextension = "avi"; + cls.capturevideo.videofile = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "%s.%s", cls.capturevideo.basename, cls.capturevideo.formatextension), "wb", false); cls.capturevideo.endvideo = SCR_CaptureVideo_Avi_EndVideo; cls.capturevideo.videoframes = SCR_CaptureVideo_Avi_VideoFrames; cls.capturevideo.soundframe = SCR_CaptureVideo_Avi_SoundFrame; @@ -507,7 +522,7 @@ void SCR_CaptureVideo_Avi_BeginVideo() // AVI main header SCR_CaptureVideo_RIFF_Push("LIST", "hdrl", format->canseek ? -1 : 8+56+12+(12+52+8+40+8+68)+(cls.capturevideo.soundrate?(12+12+52+8+18):0)+12+(8+4)); SCR_CaptureVideo_RIFF_Push("avih", NULL, 56); - SCR_CaptureVideo_RIFF_Write32((int)(1000000.0 / cls.capturevideo.framerate)); // microseconds per frame + SCR_CaptureVideo_RIFF_Write32((int)(1000000.0 / (cls.capturevideo.framerate / cls.capturevideo.framestep))); // microseconds per frame SCR_CaptureVideo_RIFF_Write32(0); // max bytes per second SCR_CaptureVideo_RIFF_Write32(0); // padding granularity SCR_CaptureVideo_RIFF_Write32(0x910); // flags (AVIF_HASINDEX | AVIF_ISINTERLEAVED | AVIF_TRUSTCKTYPE) @@ -535,7 +550,7 @@ void SCR_CaptureVideo_Avi_BeginVideo() SCR_CaptureVideo_RIFF_Write16(0); // language SCR_CaptureVideo_RIFF_Write32(0); // initial frames // find an ideal divisor for the framerate - FindFraction(cls.capturevideo.framerate, &n, &d, 1000); + FindFraction(cls.capturevideo.framerate / cls.capturevideo.framestep, &n, &d, 1000); SCR_CaptureVideo_RIFF_Write32(d); // samples/second divisor SCR_CaptureVideo_RIFF_Write32(n); // samples/second multiplied by divisor SCR_CaptureVideo_RIFF_Write32(0); // start @@ -584,7 +599,7 @@ void SCR_CaptureVideo_Avi_BeginVideo() SCR_CaptureVideo_RIFF_Push("vprp", NULL, 68); SCR_CaptureVideo_RIFF_Write32(0); // VideoFormatToken SCR_CaptureVideo_RIFF_Write32(0); // VideoStandard - SCR_CaptureVideo_RIFF_Write32((int)cls.capturevideo.framerate); // dwVerticalRefreshRate (bogus) + SCR_CaptureVideo_RIFF_Write32((int)(cls.capturevideo.framerate / cls.capturevideo.framestep)); // dwVerticalRefreshRate (bogus) SCR_CaptureVideo_RIFF_Write32(width); // dwHTotalInT SCR_CaptureVideo_RIFF_Write32(height); // dwVTotalInLines FindFraction(aspect, &n, &d, 1000);