- //if (cl_capturevideo_)
- //{
- //}
- //else
- {
- cls.capturevideo.format = CAPTUREVIDEOFORMAT_AVI_I420;
- cls.capturevideo.videofile = FS_Open (va("%s.avi", cls.capturevideo.basename), "wb", false, true);
- SCR_CaptureVideo_RIFF_Start();
- // enclosing RIFF chunk (there can be multiple of these in >1GB files, the later ones are "AVIX" instead of "AVI " and have no header/stream info)
- SCR_CaptureVideo_RIFF_Push("RIFF", "AVI ");
- // AVI main header
- SCR_CaptureVideo_RIFF_Push("LIST", "hdrl");
- SCR_CaptureVideo_RIFF_Push("avih", NULL);
- SCR_CaptureVideo_RIFF_Write32((int)(1000000.0 / cls.capturevideo.framerate)); // 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)
- cls.capturevideo.videofile_firstchunkframes_offset = SCR_CaptureVideo_RIFF_GetPosition();
- SCR_CaptureVideo_RIFF_Write32(0); // total frames
- SCR_CaptureVideo_RIFF_Write32(0); // initial frames
- if (cls.capturevideo.soundrate)
- SCR_CaptureVideo_RIFF_Write32(2); // number of streams
- else
- SCR_CaptureVideo_RIFF_Write32(1); // number of streams
- SCR_CaptureVideo_RIFF_Write32(0); // suggested buffer size
- SCR_CaptureVideo_RIFF_Write32(width); // width
- SCR_CaptureVideo_RIFF_Write32(height); // height
- SCR_CaptureVideo_RIFF_Write32(0); // reserved[0]
- SCR_CaptureVideo_RIFF_Write32(0); // reserved[1]
- SCR_CaptureVideo_RIFF_Write32(0); // reserved[2]
- SCR_CaptureVideo_RIFF_Write32(0); // reserved[3]
- SCR_CaptureVideo_RIFF_Pop();
- // video stream info
- SCR_CaptureVideo_RIFF_Push("LIST", "strl");
- SCR_CaptureVideo_RIFF_Push("strh", "vids");
- SCR_CaptureVideo_RIFF_WriteFourCC("I420"); // stream fourcc (I420 colorspace, uncompressed)
- SCR_CaptureVideo_RIFF_Write32(0); // flags
- SCR_CaptureVideo_RIFF_Write16(0); // priority
- 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);
- SCR_CaptureVideo_RIFF_Write32(d); // samples/second divisor
- SCR_CaptureVideo_RIFF_Write32(n); // samples/second multiplied by divisor
- SCR_CaptureVideo_RIFF_Write32(0); // start
- cls.capturevideo.videofile_totalframes_offset1 = SCR_CaptureVideo_RIFF_GetPosition();
- SCR_CaptureVideo_RIFF_Write32(0); // length
- SCR_CaptureVideo_RIFF_Write32(width*height+(width/2)*(height/2)*2); // suggested buffer size
- SCR_CaptureVideo_RIFF_Write32(0); // quality
- SCR_CaptureVideo_RIFF_Write32(0); // sample size
- SCR_CaptureVideo_RIFF_Write16(0); // frame left
- SCR_CaptureVideo_RIFF_Write16(0); // frame top
- SCR_CaptureVideo_RIFF_Write16(width); // frame right
- SCR_CaptureVideo_RIFF_Write16(height); // frame bottom
- SCR_CaptureVideo_RIFF_Pop();
- // video stream format
- SCR_CaptureVideo_RIFF_Push("strf", NULL);
- SCR_CaptureVideo_RIFF_Write32(40); // BITMAPINFO struct size
- SCR_CaptureVideo_RIFF_Write32(width); // width
- SCR_CaptureVideo_RIFF_Write32(height); // height
- SCR_CaptureVideo_RIFF_Write16(3); // planes
- SCR_CaptureVideo_RIFF_Write16(12); // bitcount
- SCR_CaptureVideo_RIFF_WriteFourCC("I420"); // compression
- SCR_CaptureVideo_RIFF_Write32(width*height+(width/2)*(height/2)*2); // size of image
- SCR_CaptureVideo_RIFF_Write32(0); // x pixels per meter
- SCR_CaptureVideo_RIFF_Write32(0); // y pixels per meter
- SCR_CaptureVideo_RIFF_Write32(0); // color used
- SCR_CaptureVideo_RIFF_Write32(0); // color important
- SCR_CaptureVideo_RIFF_Pop();
- // master index
- SCR_CaptureVideo_RIFF_Push("indx", NULL);
- SCR_CaptureVideo_RIFF_Write16(4); // wLongsPerEntry
- SCR_CaptureVideo_RIFF_Write16(0); // bIndexSubType=0, bIndexType=0
- cls.capturevideo.videofile_ix_master_video_inuse_offset = SCR_CaptureVideo_RIFF_GetPosition();
- SCR_CaptureVideo_RIFF_Write32(0); // nEntriesInUse
- SCR_CaptureVideo_RIFF_WriteFourCC("00dc"); // dwChunkId
- SCR_CaptureVideo_RIFF_Write32(0); // dwReserved1
- SCR_CaptureVideo_RIFF_Write32(0); // dwReserved2
- SCR_CaptureVideo_RIFF_Write32(0); // dwReserved3
- cls.capturevideo.videofile_ix_master_video_start_offset = SCR_CaptureVideo_RIFF_GetPosition();
- for(i = 0; i < AVI_MASTER_INDEX_SIZE * 4; ++i)
- SCR_CaptureVideo_RIFF_Write32(0); // fill up later
- SCR_CaptureVideo_RIFF_Pop();
- // extended format (aspect!)
- SCR_CaptureVideo_RIFF_Push("vprp", NULL);
- 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(width); // dwHTotalInT
- SCR_CaptureVideo_RIFF_Write32(height); // dwVTotalInLines
- FindFraction(aspect, &n, &d, 1000);
- SCR_CaptureVideo_RIFF_Write32((n << 16) | d); // dwFrameAspectRatio // TODO a word
- SCR_CaptureVideo_RIFF_Write32(width); // dwFrameWidthInPixels
- SCR_CaptureVideo_RIFF_Write32(height); // dwFrameHeightInLines
- SCR_CaptureVideo_RIFF_Write32(1); // nFieldPerFrame
- SCR_CaptureVideo_RIFF_Write32(width); // CompressedBMWidth
- SCR_CaptureVideo_RIFF_Write32(height); // CompressedBMHeight
- SCR_CaptureVideo_RIFF_Write32(width); // ValidBMHeight
- SCR_CaptureVideo_RIFF_Write32(height); // ValidBMWidth
- SCR_CaptureVideo_RIFF_Write32(0); // ValidBMXOffset
- SCR_CaptureVideo_RIFF_Write32(0); // ValidBMYOffset
- SCR_CaptureVideo_RIFF_Write32(0); // ValidBMXOffsetInT
- SCR_CaptureVideo_RIFF_Write32(0); // ValidBMYValidStartLine
- SCR_CaptureVideo_RIFF_Pop();
- SCR_CaptureVideo_RIFF_Pop();
- if (cls.capturevideo.soundrate)
- {
- // audio stream info
- SCR_CaptureVideo_RIFF_Push("LIST", "strl");
- SCR_CaptureVideo_RIFF_Push("strh", "auds");
- SCR_CaptureVideo_RIFF_Write32(1); // stream fourcc (PCM audio, uncompressed)
- SCR_CaptureVideo_RIFF_Write32(0); // flags
- SCR_CaptureVideo_RIFF_Write16(0); // priority
- SCR_CaptureVideo_RIFF_Write16(0); // language
- SCR_CaptureVideo_RIFF_Write32(0); // initial frames
- SCR_CaptureVideo_RIFF_Write32(1); // samples/second divisor
- SCR_CaptureVideo_RIFF_Write32((int)(cls.capturevideo.soundrate)); // samples/second multiplied by divisor
- SCR_CaptureVideo_RIFF_Write32(0); // start
- cls.capturevideo.videofile_totalsampleframes_offset = SCR_CaptureVideo_RIFF_GetPosition();
- SCR_CaptureVideo_RIFF_Write32(0); // length
- SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.soundrate * 2); // suggested buffer size (this is a half second)
- SCR_CaptureVideo_RIFF_Write32(0); // quality
- SCR_CaptureVideo_RIFF_Write32(4); // sample size
- SCR_CaptureVideo_RIFF_Write16(0); // frame left
- SCR_CaptureVideo_RIFF_Write16(0); // frame top
- SCR_CaptureVideo_RIFF_Write16(0); // frame right
- SCR_CaptureVideo_RIFF_Write16(0); // frame bottom
- SCR_CaptureVideo_RIFF_Pop();
- // audio stream format
- SCR_CaptureVideo_RIFF_Push("strf", NULL);
- SCR_CaptureVideo_RIFF_Write16(1); // format (uncompressed PCM?)
- SCR_CaptureVideo_RIFF_Write16(2); // channels (stereo)
- SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.soundrate); // sampleframes per second
- SCR_CaptureVideo_RIFF_Write32(cls.capturevideo.soundrate * 4); // average bytes per second
- SCR_CaptureVideo_RIFF_Write16(4); // block align
- SCR_CaptureVideo_RIFF_Write16(16); // bits per sample
- SCR_CaptureVideo_RIFF_Write16(0); // size
- SCR_CaptureVideo_RIFF_Pop();
- // master index
- SCR_CaptureVideo_RIFF_Push("indx", NULL);
- SCR_CaptureVideo_RIFF_Write16(4); // wLongsPerEntry
- SCR_CaptureVideo_RIFF_Write16(0); // bIndexSubType=0, bIndexType=0
- cls.capturevideo.videofile_ix_master_audio_inuse_offset = SCR_CaptureVideo_RIFF_GetPosition();
- SCR_CaptureVideo_RIFF_Write32(0); // nEntriesInUse
- SCR_CaptureVideo_RIFF_WriteFourCC("01wb"); // dwChunkId
- SCR_CaptureVideo_RIFF_Write32(0); // dwReserved1
- SCR_CaptureVideo_RIFF_Write32(0); // dwReserved2
- SCR_CaptureVideo_RIFF_Write32(0); // dwReserved3
- cls.capturevideo.videofile_ix_master_audio_start_offset = SCR_CaptureVideo_RIFF_GetPosition();
- for(i = 0; i < AVI_MASTER_INDEX_SIZE * 4; ++i)
- SCR_CaptureVideo_RIFF_Write32(0); // fill up later
- SCR_CaptureVideo_RIFF_Pop();
- SCR_CaptureVideo_RIFF_Pop();
- }
-
- cls.capturevideo.videofile_ix_master_audio_inuse = cls.capturevideo.videofile_ix_master_video_inuse = 0;
-
- // extended header (for total #frames)
- SCR_CaptureVideo_RIFF_Push("LIST", "odml");
- SCR_CaptureVideo_RIFF_Push("dmlh", NULL);
- cls.capturevideo.videofile_totalframes_offset2 = SCR_CaptureVideo_RIFF_GetPosition();
- SCR_CaptureVideo_RIFF_Write32(0);
- SCR_CaptureVideo_RIFF_Pop();
- SCR_CaptureVideo_RIFF_Pop();
-
- // close the AVI header list
- SCR_CaptureVideo_RIFF_Pop();
- // software that produced this AVI video file
- SCR_CaptureVideo_RIFF_Push("LIST", "INFO");
- SCR_CaptureVideo_RIFF_Push("ISFT", NULL);
- SCR_CaptureVideo_RIFF_WriteTerminatedString(engineversion);
- SCR_CaptureVideo_RIFF_Pop();
- // enable this junk filler if you like the LIST movi to always begin at 4KB in the file (why?)
-#if 0
- SCR_CaptureVideo_RIFF_Push("JUNK", NULL);
- x = 4096 - SCR_CaptureVideo_RIFF_GetPosition();
- while (x > 0)