windows-nt/Source/XPSP1/NT/multimedia/media/avi/avicap.io/capio.avf
2020-09-26 16:20:57 +08:00

428 lines
13 KiB
Plaintext

VOID WINAPI AVIPreloadFat (LPCAPSTREAM lpcs)
{
return;
}
// Add an index entry for an audio buffer
// dwSize is the size of data ONLY, not including the chunk or junk
// Returns: TRUE if index space is not exhausted
//
__inline STATICFN BOOL IndexAudio (LPCAPSTREAM lpcs, DWORD dwSize)
{
++lpcs->dwWaveChunkCount;
return TRUE;
}
// Add an index entry for a video frame
// dwSize is the size of data ONLY, not including the chunk or junk
// Returns: TRUE if index space is not exhausted
//
__inline STATICFN BOOL IndexVideo (LPCAPSTREAM lpcs, DWORD dwSize, BOOL bKeyFrame)
{
++lpcs->dwVideoChunkCount;
return TRUE;
}
STATICFN void AVIFileCleanup(LPCAPSTREAM lpcs)
{
if (lpcs->paudio)
AVIStreamClose(lpcs->paudio), lpcs->paudio = NULL;
if (lpcs->pvideo)
AVIStreamClose(lpcs->pvideo), lpcs->pvideo = NULL;
if (lpcs->pavifile)
AVIFileClose(lpcs->pavifile), lpcs->pavifile = NULL;
if (hmodKernel) {
FreeLibrary(hmodKernel);
pfnCreateIoCompletionPort = NULL;
pfnGetQueuedCompletionStatus = NULL;
hmodKernel = NULL;
}
}
/*
* CapFileInit
*
* Perform all initialization required to write a capture file.
*
* We take a slightly strange approach: We don't write
* out the header until we're done capturing. For now,
* we just seek 2K into the file, which is where all of
* the real data will go.
*
* When we're done, we'll come back and write out the header,
* because then we'll know all of the values we need.
*
* Also allocate and init the index.
*/
BOOL CapFileInit (
LPCAPSTREAM lpcs)
{
AVISTREAMINFOW si;
LPBYTE ptr = NULL;
UINT cksize;
RGBQUAD FAR * prgb;
PALETTEENTRY aPalEntry[256];
LPBITMAPINFO lpBitsInfoOut; // Possibly compressed output format
LONG lRet;
UINT ii;
// No special video format given -- use the default
//
lpBitsInfoOut = lpcs->CompVars.lpbiOut;
if (lpcs->CompVars.hic == NULL)
lpBitsInfoOut = lpcs->lpBitsInfo;
// use avifile to access the data
// create the avifile object, create a video and audio stream and
// set the format for each stream.
assert(lpcs->pavifile == NULL);
/* if the capture file has not been set then error */
if (!(*lpcs->achFile))
goto error_exit;
// !!! how to avoid truncating the file if already created ?
lRet = AVIFileOpen(&lpcs->pavifile,
lpcs->achFile,
OF_WRITE | OF_CREATE,
NULL);
if (lRet || !lpcs->pavifile)
goto error_exit;
// create video stream
ZeroMemory (&si, sizeof(si));
si.fccType = streamtypeVIDEO;
if (lpcs->CompVars.hic)
si.fccHandler = lpcs->CompVars.fccHandler;
else
si.fccHandler = lpBitsInfoOut->bmiHeader.biCompression;
// A bit of history...
// In VFW 1.0, we set fccHandler to 0 for BI_RLE8 formats
// as a kludge to make Mplayer and Videdit play the files.
// Just prior to 1.1 release, we found this broke Premiere,
// so now (after AVICAP beta is on Compuserve), we change the
// fccHandler to "MRLE". Just ask Todd...
// And now, at RC1, we change it again to "RLE ", Just ask Todd...
if (si.fccHandler == BI_RLE8)
si.fccHandler = mmioFOURCC('R', 'L', 'E', ' ');
// !!!need to change this after capture
si.dwScale = lpcs->sCapParms.dwRequestMicroSecPerFrame;
si.dwRate = 1000000L;
si.dwStart = 0L;
si.dwQuality = (DWORD) -1L; /* !!! ICQUALITY_DEFAULT */
si.dwSampleSize = 0L;
lRet = AVIFileCreateStream(lpcs->pavifile, &lpcs->pvideo, &si);
if (lRet || !lpcs->pvideo)
goto error_exit;
// set format of video stream
// !!! dont write palette for full color?
if (lpBitsInfoOut->bmiHeader.biBitCount > 8)
lpBitsInfoOut->bmiHeader.biClrUsed = 0;
// need to alloc a single block that we can fill with hdr + palette
cksize = lpBitsInfoOut->bmiHeader.biSize
+ lpBitsInfoOut->bmiHeader.biClrUsed * sizeof(RGBQUAD);
ptr = GlobalAllocPtr(GPTR, cksize);
if (!ptr)
goto error_exit;
CopyMemory (ptr, (LPBYTE)&lpBitsInfoOut->bmiHeader,
lpBitsInfoOut->bmiHeader.biSize);
prgb = (RGBQUAD FAR *) &ptr[lpBitsInfoOut->bmiHeader.biSize];
if (lpBitsInfoOut->bmiHeader.biClrUsed > 0) {
// Get Palette info
UINT nPalEntries = GetPaletteEntries(lpcs->hPalCurrent, 0,
lpBitsInfoOut->bmiHeader.biClrUsed,
aPalEntry);
if (nPalEntries != lpBitsInfoOut->bmiHeader.biClrUsed)
goto error_exit;
for (ii = 0; ii < lpBitsInfoOut->bmiHeader.biClrUsed; ++ii) {
prgb[ii].rgbRed = aPalEntry[ii].peRed;
prgb[ii].rgbGreen = aPalEntry[ii].peGreen;
prgb[ii].rgbBlue = aPalEntry[ii].peBlue;
}
}
if (AVIStreamSetFormat(lpcs->pvideo, 0, ptr, cksize))
goto error_exit;
GlobalFreePtr(ptr), ptr = NULL;
// create audio stream if sound capture enabled
if (lpcs->sCapParms.fCaptureAudio) {
ZeroMemory (&si, sizeof(si));
si.fccType = streamtypeAUDIO;
si.fccHandler = 0L;
si.dwScale = lpcs->lpWaveFormat->nBlockAlign;
si.dwRate = lpcs->lpWaveFormat->nAvgBytesPerSec;
si.dwStart = 0L;
si.dwLength = lpcs->dwWaveBytes / lpcs->lpWaveFormat->nBlockAlign;
si.dwQuality = (DWORD)-1L; /* !!! ICQUALITY_DEFAULT */
si.dwSampleSize = lpcs->lpWaveFormat->nBlockAlign;
lRet = AVIFileCreateStream(lpcs->pavifile, &lpcs->paudio, &si);
if (lRet || !lpcs->paudio)
goto error_exit;
// write wave stream format
cksize = GetSizeOfWaveFormat (lpcs->lpWaveFormat);
if (AVIStreamSetFormat(lpcs->paudio, 0, lpcs->lpWaveFormat, cksize))
goto error_exit;
}
// start streaming
//
// parameters are random for now, and are not used at all by current impl.
// probably covered by above call but you never know
//
AVIStreamBeginStreaming(lpcs->pvideo, 0, 32000, 1000);
if (lpcs->sCapParms.fCaptureAudio)
AVIStreamBeginStreaming(lpcs->paudio, 0, 32000, 1000);
// this is used for timing calcs, not just indexing
//
lpcs->dwVideoChunkCount = 0;
lpcs->dwWaveChunkCount = 0;
// !!! write info chunks here
return TRUE;
error_exit:
if (ptr) {
GlobalFreePtr(ptr); ptr = NULL;
}
AVIFileCleanup (lpcs);
return FALSE;
}
/*
* AVIFileFini
*
* Write out the index, deallocate the index, and close the file.
*
*/
BOOL AVIFileFini (LPCAPSTREAM lpcs, BOOL fWroteJunkChunks, BOOL fAbort)
{
AVISTREAMINFOW si;
DPF("AVICap32: Start of AVIFileFini\n");
AVIStreamEndStreaming(lpcs->pvideo);
if (lpcs->sCapParms.fCaptureAudio)
AVIStreamEndStreaming(lpcs->paudio);
// if we got a good file, allow editing of it
lpcs->fFileCaptured = !fAbort;
// -----------------------------------------------------------
// adjust audio & video streams to be the same length
// -----------------------------------------------------------
#if 0 // old technique - match video to audio unconditionally
// share the captured frames out evenly over the captured audio
if (lpcs->sCapParms.fCaptureAudio && lpcs->dwVideoChunkCount &&
(lpcs->dwWaveBytes > 0)) {
/* HACK HACK */
/* Set rate that was captured based on length of audio data */
lpcs->dwActualMicroSecPerFrame = (DWORD)
MulDiv((LONG)lpcs->dwWaveBytes,
1000000,
(LONG)(lpcs->lpWaveFormat->nAvgBytesPerSec * lpcs->dwVideoChunkCount));
} else {
lpcs->dwActualMicroSecPerFrame = lpcs->sCapParms.dwRequestMicroSecPerFrame;
}
#else // new technique for stream length munging
//
// Init a value in case we're not capturing audio
//
lpcs->dwActualMicroSecPerFrame = lpcs->sCapParms.dwRequestMicroSecPerFrame;
switch (lpcs->sCapParms.AVStreamMaster) {
case AVSTREAMMASTER_NONE:
lpcs->dwActualMicroSecPerFrame = lpcs->sCapParms.dwRequestMicroSecPerFrame;
break;
case AVSTREAMMASTER_AUDIO:
default:
// VFW 1.0 and 1.1 ALWAYS munged frame rate to match audio
// duration.
if (lpcs->sCapParms.fCaptureAudio && lpcs->dwVideoChunkCount) {
// Modify the video framerate based on audio duration
lpcs->dwActualMicroSecPerFrame = (DWORD)
((double)lpcs->dwWaveBytes * 1000000. /
((double)lpcs->lpWaveFormat->nAvgBytesPerSec *
lpcs->dwVideoChunkCount + 0.5));
}
break;
}
#endif
// ------------------------------------------------------------
// write corrected stream timing back to the file
// ------------------------------------------------------------
#ifdef CHICAGO
AVIStreamInfo (lpcs->pvideo, (LPAVISTREAMINFOA) &si, sizeof(si));
#else
AVIStreamInfo (lpcs->pvideo, &si, sizeof(si));
#endif
si.dwRate = 1000000L;
si.dwScale = lpcs->dwActualMicroSecPerFrame;
// no api for this- have to call the member directly!
//
lpcs->pvideo->lpVtbl->SetInfo(lpcs->pvideo, &si, sizeof(si));
// Add the info chunks
// This includes the capture card driver name, client app, date and time
if (lpcs->lpInfoChunks) {
LPBYTE lpInfo;
DWORD cbData;
lpInfo = lpcs->lpInfoChunks;
while (lpInfo < (LPBYTE) lpcs->lpInfoChunks + lpcs->cbInfoChunks) {
cbData = * (LPDWORD) (lpInfo + sizeof(DWORD));
AVIFileWriteData (lpcs->pavifile,
(DWORD) * (LPDWORD) lpInfo, // FOURCC
lpInfo + sizeof (DWORD) * 2, // lpData
cbData); // cbData
lpInfo += cbData + sizeof (DWORD) * 2;
}
}
AVIFileCleanup(lpcs);
return lpcs->fFileCaptured;
}
//
// Prepends dummy frame entries to the current valid video frame.
// Bumps the index, but does not actually trigger a write operation.
// nCount is a count of the number of frames to write
// Returns: TRUE on a successful write
BOOL WINAPI AVIWriteDummyFrames (
LPCAPSTREAM lpcs,
UINT nCount,
LPUINT lpuError,
LPBOOL lpbPending)
{
LONG lRet;
lpcs->dwVideoChunkCount += nCount;
lRet = AVIStreamWrite(lpcs->pvideo,
-1, // current position
nCount, // this many samples
NULL, // no actual data
0, // no data
0, // not keyframe
NULL, NULL); // no return of samples or bytes
*lpbPending = FALSE;
*lpuError = 0;
if (lRet)
*lpuError = IDS_CAP_FILE_WRITE_ERROR;
return !(*lpuError);
}
// Writes compressed or uncompressed frames to the AVI file
// returns TRUE if no error, FALSE if end of file.
BOOL WINAPI AVIWriteVideoFrame (
LPCAPSTREAM lpcs,
LPBYTE lpData,
DWORD dwBytesUsed,
BOOL fKeyFrame,
UINT uIndex,
UINT nDropped,
LPUINT lpuError,
LPBOOL lpbPending)
{
LONG lRet;
lRet = AVIStreamWrite(lpcs->pvideo, // write to video stream
-1, // next sample
1, // 1 sample only
lpData, // video buffer (no riff header)
dwBytesUsed, // length of data
fKeyFrame ? AVIIF_KEYFRAME : 0,
NULL, NULL); // no return of sample or byte count
*lpbPending = FALSE;
*lpuError = 0;
if (lRet)
{
dprintf("AVIStreamWrite returned 0x%x", lRet);
*lpuError = IDS_CAP_FILE_WRITE_ERROR;
}
else
{
++lpcs->dwVideoChunkCount;
if (nDropped)
AVIWriteDummyFrames (lpcs, nDropped, lpuError, lpbPending);
}
return !(*lpuError);
}
BOOL WINAPI AVIWriteAudio (
LPCAPSTREAM lpcs,
LPWAVEHDR lpWaveHdr,
UINT uIndex,
LPUINT lpuError,
LPBOOL lpbPending)
{
LONG lRet;
lRet = AVIStreamWrite(lpcs->paudio,
-1, // next sample
lpWaveHdr->dwBytesRecorded /
lpcs->lpWaveFormat->nBlockAlign, // nr samples
lpWaveHdr->lpData,
lpWaveHdr->dwBytesRecorded,
0,
NULL,
NULL);
*lpbPending = FALSE;
*lpuError = 0;
if (lRet)
{
dprintf("AVIStreamWrite returned 0x%x", lRet);
*lpuError = IDS_CAP_FILE_WRITE_ERROR;
}
else
++lpcs->dwWaveChunkCount;
return !(*lpuError);
}