Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

427 lines
13 KiB

4 years ago
  1. VOID WINAPI AVIPreloadFat (LPCAPSTREAM lpcs)
  2. {
  3. return;
  4. }
  5. // Add an index entry for an audio buffer
  6. // dwSize is the size of data ONLY, not including the chunk or junk
  7. // Returns: TRUE if index space is not exhausted
  8. //
  9. __inline STATICFN BOOL IndexAudio (LPCAPSTREAM lpcs, DWORD dwSize)
  10. {
  11. ++lpcs->dwWaveChunkCount;
  12. return TRUE;
  13. }
  14. // Add an index entry for a video frame
  15. // dwSize is the size of data ONLY, not including the chunk or junk
  16. // Returns: TRUE if index space is not exhausted
  17. //
  18. __inline STATICFN BOOL IndexVideo (LPCAPSTREAM lpcs, DWORD dwSize, BOOL bKeyFrame)
  19. {
  20. ++lpcs->dwVideoChunkCount;
  21. return TRUE;
  22. }
  23. STATICFN void AVIFileCleanup(LPCAPSTREAM lpcs)
  24. {
  25. if (lpcs->paudio)
  26. AVIStreamClose(lpcs->paudio), lpcs->paudio = NULL;
  27. if (lpcs->pvideo)
  28. AVIStreamClose(lpcs->pvideo), lpcs->pvideo = NULL;
  29. if (lpcs->pavifile)
  30. AVIFileClose(lpcs->pavifile), lpcs->pavifile = NULL;
  31. if (hmodKernel) {
  32. FreeLibrary(hmodKernel);
  33. pfnCreateIoCompletionPort = NULL;
  34. pfnGetQueuedCompletionStatus = NULL;
  35. hmodKernel = NULL;
  36. }
  37. }
  38. /*
  39. * CapFileInit
  40. *
  41. * Perform all initialization required to write a capture file.
  42. *
  43. * We take a slightly strange approach: We don't write
  44. * out the header until we're done capturing. For now,
  45. * we just seek 2K into the file, which is where all of
  46. * the real data will go.
  47. *
  48. * When we're done, we'll come back and write out the header,
  49. * because then we'll know all of the values we need.
  50. *
  51. * Also allocate and init the index.
  52. */
  53. BOOL CapFileInit (
  54. LPCAPSTREAM lpcs)
  55. {
  56. AVISTREAMINFOW si;
  57. LPBYTE ptr = NULL;
  58. UINT cksize;
  59. RGBQUAD FAR * prgb;
  60. PALETTEENTRY aPalEntry[256];
  61. LPBITMAPINFO lpBitsInfoOut; // Possibly compressed output format
  62. LONG lRet;
  63. UINT ii;
  64. // No special video format given -- use the default
  65. //
  66. lpBitsInfoOut = lpcs->CompVars.lpbiOut;
  67. if (lpcs->CompVars.hic == NULL)
  68. lpBitsInfoOut = lpcs->lpBitsInfo;
  69. // use avifile to access the data
  70. // create the avifile object, create a video and audio stream and
  71. // set the format for each stream.
  72. assert(lpcs->pavifile == NULL);
  73. /* if the capture file has not been set then error */
  74. if (!(*lpcs->achFile))
  75. goto error_exit;
  76. // !!! how to avoid truncating the file if already created ?
  77. lRet = AVIFileOpen(&lpcs->pavifile,
  78. lpcs->achFile,
  79. OF_WRITE | OF_CREATE,
  80. NULL);
  81. if (lRet || !lpcs->pavifile)
  82. goto error_exit;
  83. // create video stream
  84. ZeroMemory (&si, sizeof(si));
  85. si.fccType = streamtypeVIDEO;
  86. if (lpcs->CompVars.hic)
  87. si.fccHandler = lpcs->CompVars.fccHandler;
  88. else
  89. si.fccHandler = lpBitsInfoOut->bmiHeader.biCompression;
  90. // A bit of history...
  91. // In VFW 1.0, we set fccHandler to 0 for BI_RLE8 formats
  92. // as a kludge to make Mplayer and Videdit play the files.
  93. // Just prior to 1.1 release, we found this broke Premiere,
  94. // so now (after AVICAP beta is on Compuserve), we change the
  95. // fccHandler to "MRLE". Just ask Todd...
  96. // And now, at RC1, we change it again to "RLE ", Just ask Todd...
  97. if (si.fccHandler == BI_RLE8)
  98. si.fccHandler = mmioFOURCC('R', 'L', 'E', ' ');
  99. // !!!need to change this after capture
  100. si.dwScale = lpcs->sCapParms.dwRequestMicroSecPerFrame;
  101. si.dwRate = 1000000L;
  102. si.dwStart = 0L;
  103. si.dwQuality = (DWORD) -1L; /* !!! ICQUALITY_DEFAULT */
  104. si.dwSampleSize = 0L;
  105. lRet = AVIFileCreateStream(lpcs->pavifile, &lpcs->pvideo, &si);
  106. if (lRet || !lpcs->pvideo)
  107. goto error_exit;
  108. // set format of video stream
  109. // !!! dont write palette for full color?
  110. if (lpBitsInfoOut->bmiHeader.biBitCount > 8)
  111. lpBitsInfoOut->bmiHeader.biClrUsed = 0;
  112. // need to alloc a single block that we can fill with hdr + palette
  113. cksize = lpBitsInfoOut->bmiHeader.biSize
  114. + lpBitsInfoOut->bmiHeader.biClrUsed * sizeof(RGBQUAD);
  115. ptr = GlobalAllocPtr(GPTR, cksize);
  116. if (!ptr)
  117. goto error_exit;
  118. CopyMemory (ptr, (LPBYTE)&lpBitsInfoOut->bmiHeader,
  119. lpBitsInfoOut->bmiHeader.biSize);
  120. prgb = (RGBQUAD FAR *) &ptr[lpBitsInfoOut->bmiHeader.biSize];
  121. if (lpBitsInfoOut->bmiHeader.biClrUsed > 0) {
  122. // Get Palette info
  123. UINT nPalEntries = GetPaletteEntries(lpcs->hPalCurrent, 0,
  124. lpBitsInfoOut->bmiHeader.biClrUsed,
  125. aPalEntry);
  126. if (nPalEntries != lpBitsInfoOut->bmiHeader.biClrUsed)
  127. goto error_exit;
  128. for (ii = 0; ii < lpBitsInfoOut->bmiHeader.biClrUsed; ++ii) {
  129. prgb[ii].rgbRed = aPalEntry[ii].peRed;
  130. prgb[ii].rgbGreen = aPalEntry[ii].peGreen;
  131. prgb[ii].rgbBlue = aPalEntry[ii].peBlue;
  132. }
  133. }
  134. if (AVIStreamSetFormat(lpcs->pvideo, 0, ptr, cksize))
  135. goto error_exit;
  136. GlobalFreePtr(ptr), ptr = NULL;
  137. // create audio stream if sound capture enabled
  138. if (lpcs->sCapParms.fCaptureAudio) {
  139. ZeroMemory (&si, sizeof(si));
  140. si.fccType = streamtypeAUDIO;
  141. si.fccHandler = 0L;
  142. si.dwScale = lpcs->lpWaveFormat->nBlockAlign;
  143. si.dwRate = lpcs->lpWaveFormat->nAvgBytesPerSec;
  144. si.dwStart = 0L;
  145. si.dwLength = lpcs->dwWaveBytes / lpcs->lpWaveFormat->nBlockAlign;
  146. si.dwQuality = (DWORD)-1L; /* !!! ICQUALITY_DEFAULT */
  147. si.dwSampleSize = lpcs->lpWaveFormat->nBlockAlign;
  148. lRet = AVIFileCreateStream(lpcs->pavifile, &lpcs->paudio, &si);
  149. if (lRet || !lpcs->paudio)
  150. goto error_exit;
  151. // write wave stream format
  152. cksize = GetSizeOfWaveFormat (lpcs->lpWaveFormat);
  153. if (AVIStreamSetFormat(lpcs->paudio, 0, lpcs->lpWaveFormat, cksize))
  154. goto error_exit;
  155. }
  156. // start streaming
  157. //
  158. // parameters are random for now, and are not used at all by current impl.
  159. // probably covered by above call but you never know
  160. //
  161. AVIStreamBeginStreaming(lpcs->pvideo, 0, 32000, 1000);
  162. if (lpcs->sCapParms.fCaptureAudio)
  163. AVIStreamBeginStreaming(lpcs->paudio, 0, 32000, 1000);
  164. // this is used for timing calcs, not just indexing
  165. //
  166. lpcs->dwVideoChunkCount = 0;
  167. lpcs->dwWaveChunkCount = 0;
  168. // !!! write info chunks here
  169. return TRUE;
  170. error_exit:
  171. if (ptr) {
  172. GlobalFreePtr(ptr); ptr = NULL;
  173. }
  174. AVIFileCleanup (lpcs);
  175. return FALSE;
  176. }
  177. /*
  178. * AVIFileFini
  179. *
  180. * Write out the index, deallocate the index, and close the file.
  181. *
  182. */
  183. BOOL AVIFileFini (LPCAPSTREAM lpcs, BOOL fWroteJunkChunks, BOOL fAbort)
  184. {
  185. AVISTREAMINFOW si;
  186. DPF("AVICap32: Start of AVIFileFini\n");
  187. AVIStreamEndStreaming(lpcs->pvideo);
  188. if (lpcs->sCapParms.fCaptureAudio)
  189. AVIStreamEndStreaming(lpcs->paudio);
  190. // if we got a good file, allow editing of it
  191. lpcs->fFileCaptured = !fAbort;
  192. // -----------------------------------------------------------
  193. // adjust audio & video streams to be the same length
  194. // -----------------------------------------------------------
  195. #if 0 // old technique - match video to audio unconditionally
  196. // share the captured frames out evenly over the captured audio
  197. if (lpcs->sCapParms.fCaptureAudio && lpcs->dwVideoChunkCount &&
  198. (lpcs->dwWaveBytes > 0)) {
  199. /* HACK HACK */
  200. /* Set rate that was captured based on length of audio data */
  201. lpcs->dwActualMicroSecPerFrame = (DWORD)
  202. MulDiv((LONG)lpcs->dwWaveBytes,
  203. 1000000,
  204. (LONG)(lpcs->lpWaveFormat->nAvgBytesPerSec * lpcs->dwVideoChunkCount));
  205. } else {
  206. lpcs->dwActualMicroSecPerFrame = lpcs->sCapParms.dwRequestMicroSecPerFrame;
  207. }
  208. #else // new technique for stream length munging
  209. //
  210. // Init a value in case we're not capturing audio
  211. //
  212. lpcs->dwActualMicroSecPerFrame = lpcs->sCapParms.dwRequestMicroSecPerFrame;
  213. switch (lpcs->sCapParms.AVStreamMaster) {
  214. case AVSTREAMMASTER_NONE:
  215. lpcs->dwActualMicroSecPerFrame = lpcs->sCapParms.dwRequestMicroSecPerFrame;
  216. break;
  217. case AVSTREAMMASTER_AUDIO:
  218. default:
  219. // VFW 1.0 and 1.1 ALWAYS munged frame rate to match audio
  220. // duration.
  221. if (lpcs->sCapParms.fCaptureAudio && lpcs->dwVideoChunkCount) {
  222. // Modify the video framerate based on audio duration
  223. lpcs->dwActualMicroSecPerFrame = (DWORD)
  224. ((double)lpcs->dwWaveBytes * 1000000. /
  225. ((double)lpcs->lpWaveFormat->nAvgBytesPerSec *
  226. lpcs->dwVideoChunkCount + 0.5));
  227. }
  228. break;
  229. }
  230. #endif
  231. // ------------------------------------------------------------
  232. // write corrected stream timing back to the file
  233. // ------------------------------------------------------------
  234. #ifdef CHICAGO
  235. AVIStreamInfo (lpcs->pvideo, (LPAVISTREAMINFOA) &si, sizeof(si));
  236. #else
  237. AVIStreamInfo (lpcs->pvideo, &si, sizeof(si));
  238. #endif
  239. si.dwRate = 1000000L;
  240. si.dwScale = lpcs->dwActualMicroSecPerFrame;
  241. // no api for this- have to call the member directly!
  242. //
  243. lpcs->pvideo->lpVtbl->SetInfo(lpcs->pvideo, &si, sizeof(si));
  244. // Add the info chunks
  245. // This includes the capture card driver name, client app, date and time
  246. if (lpcs->lpInfoChunks) {
  247. LPBYTE lpInfo;
  248. DWORD cbData;
  249. lpInfo = lpcs->lpInfoChunks;
  250. while (lpInfo < (LPBYTE) lpcs->lpInfoChunks + lpcs->cbInfoChunks) {
  251. cbData = * (LPDWORD) (lpInfo + sizeof(DWORD));
  252. AVIFileWriteData (lpcs->pavifile,
  253. (DWORD) * (LPDWORD) lpInfo, // FOURCC
  254. lpInfo + sizeof (DWORD) * 2, // lpData
  255. cbData); // cbData
  256. lpInfo += cbData + sizeof (DWORD) * 2;
  257. }
  258. }
  259. AVIFileCleanup(lpcs);
  260. return lpcs->fFileCaptured;
  261. }
  262. //
  263. // Prepends dummy frame entries to the current valid video frame.
  264. // Bumps the index, but does not actually trigger a write operation.
  265. // nCount is a count of the number of frames to write
  266. // Returns: TRUE on a successful write
  267. BOOL WINAPI AVIWriteDummyFrames (
  268. LPCAPSTREAM lpcs,
  269. UINT nCount,
  270. LPUINT lpuError,
  271. LPBOOL lpbPending)
  272. {
  273. LONG lRet;
  274. lpcs->dwVideoChunkCount += nCount;
  275. lRet = AVIStreamWrite(lpcs->pvideo,
  276. -1, // current position
  277. nCount, // this many samples
  278. NULL, // no actual data
  279. 0, // no data
  280. 0, // not keyframe
  281. NULL, NULL); // no return of samples or bytes
  282. *lpbPending = FALSE;
  283. *lpuError = 0;
  284. if (lRet)
  285. *lpuError = IDS_CAP_FILE_WRITE_ERROR;
  286. return !(*lpuError);
  287. }
  288. // Writes compressed or uncompressed frames to the AVI file
  289. // returns TRUE if no error, FALSE if end of file.
  290. BOOL WINAPI AVIWriteVideoFrame (
  291. LPCAPSTREAM lpcs,
  292. LPBYTE lpData,
  293. DWORD dwBytesUsed,
  294. BOOL fKeyFrame,
  295. UINT uIndex,
  296. UINT nDropped,
  297. LPUINT lpuError,
  298. LPBOOL lpbPending)
  299. {
  300. LONG lRet;
  301. lRet = AVIStreamWrite(lpcs->pvideo, // write to video stream
  302. -1, // next sample
  303. 1, // 1 sample only
  304. lpData, // video buffer (no riff header)
  305. dwBytesUsed, // length of data
  306. fKeyFrame ? AVIIF_KEYFRAME : 0,
  307. NULL, NULL); // no return of sample or byte count
  308. *lpbPending = FALSE;
  309. *lpuError = 0;
  310. if (lRet)
  311. {
  312. dprintf("AVIStreamWrite returned 0x%x", lRet);
  313. *lpuError = IDS_CAP_FILE_WRITE_ERROR;
  314. }
  315. else
  316. {
  317. ++lpcs->dwVideoChunkCount;
  318. if (nDropped)
  319. AVIWriteDummyFrames (lpcs, nDropped, lpuError, lpbPending);
  320. }
  321. return !(*lpuError);
  322. }
  323. BOOL WINAPI AVIWriteAudio (
  324. LPCAPSTREAM lpcs,
  325. LPWAVEHDR lpWaveHdr,
  326. UINT uIndex,
  327. LPUINT lpuError,
  328. LPBOOL lpbPending)
  329. {
  330. LONG lRet;
  331. lRet = AVIStreamWrite(lpcs->paudio,
  332. -1, // next sample
  333. lpWaveHdr->dwBytesRecorded /
  334. lpcs->lpWaveFormat->nBlockAlign, // nr samples
  335. lpWaveHdr->lpData,
  336. lpWaveHdr->dwBytesRecorded,
  337. 0,
  338. NULL,
  339. NULL);
  340. *lpbPending = FALSE;
  341. *lpuError = 0;
  342. if (lRet)
  343. {
  344. dprintf("AVIStreamWrite returned 0x%x", lRet);
  345. *lpuError = IDS_CAP_FILE_WRITE_ERROR;
  346. }
  347. else
  348. ++lpcs->dwWaveChunkCount;
  349. return !(*lpuError);
  350. }