Source code of Windows XP (NT5)
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.

5617 lines
219 KiB

  1. #include "precomp.h"
  2. // #define LOG_COMPRESSION_PARAMS 1
  3. // #define LOGPAYLOAD_ON 1
  4. #ifdef LOGPAYLOAD_ON
  5. HANDLE g_DebugFile = (HANDLE)NULL;
  6. HANDLE g_TDebugFile = (HANDLE)NULL;
  7. #endif
  8. // #define VALIDATE_SBIT_EBIT 1
  9. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  10. DWORD g_dwPreviousEBIT = 0;
  11. #endif // } VALIDATE_SBIT_EBIT
  12. #define BUFFER_SIZE 50
  13. #define NUM_FPS_ENTRIES 1
  14. #define NUM_BITDEPTH_ENTRIES 9
  15. #define NUM_RGB_BITDEPTH_ENTRIES 4
  16. #define VIDEO_FORMAT_NUM_RESOLUTIONS 6
  17. #define MAX_NUM_REGISTERED_SIZES 3
  18. #define MAX_VERSION 80 // Needs to be in sync with the MAX_VERSION in dcap\inc\idcap.h
  19. // String resources
  20. #define IDS_FORMAT_1 TEXT("%4.4hs.%4.4hs, %02dbit, %02dfps, %03dx%03d")
  21. #define IDS_FORMAT_2 TEXT("%4.4hs.%04d, %02dbit, %02dfps, %03dx%03d")
  22. #define szRegDeviceKey TEXT("SOFTWARE\\Microsoft\\Conferencing\\CaptureDevices")
  23. #define szRegCaptureDefaultKey TEXT("SOFTWARE\\Microsoft\\Conferencing\\CaptureDefaultFormats")
  24. #define szRegConferencingKey TEXT("SOFTWARE\\Microsoft\\Conferencing")
  25. #define szTotalRegDeviceKey TEXT("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Conferencing\\CaptureDevices")
  26. #define szRegCaptureKey TEXT("CaptureDevices")
  27. #define szRegdwImageSizeKey TEXT("dwImageSize")
  28. #define szRegImageSizesKey TEXT("aImageSizes")
  29. #define szRegNumImageSizesKey TEXT("nNumSizes")
  30. #define szRegdwNumColorsKey TEXT("dwNumColors")
  31. #define szRegdwStreamingModeKey TEXT("dwStreamingMode")
  32. #define szRegdwDialogsKey TEXT("dwDialogs")
  33. #define szRegbmi4bitColorsKey TEXT("bmi4bitColors")
  34. #define szRegbmi8bitColorsKey TEXT("bmi8bitColors")
  35. #define szRegDefaultFormatKey TEXT("DefaultFormat")
  36. EXTERN_C HINSTANCE g_hInst; // Our module handle. defined in nac.cpp
  37. //External function (in msiacaps.cpp) to read reg info in one shot
  38. extern ULONG ReadRegistryFormats (LPCSTR lpszKeyName,CHAR ***pppName,BYTE ***pppData,PUINT pnFormats,DWORD dwDebugSize);
  39. PVCM_APP_ICINFO g_aVCMAppInfo;
  40. int g_nNumVCMAppInfoEntries;
  41. int g_nNumFrameSizesEntries;
  42. BOOL g_fNewCodecsInstalled;
  43. #ifdef LOGFILE_ON
  44. DWORD g_CompressTime;
  45. DWORD g_DecompressTime;
  46. HANDLE g_CompressLogFile;
  47. HANDLE g_DecompressLogFile;
  48. DWORD g_dwCompressBytesWritten;
  49. DWORD g_dwDecompressBytesWritten;
  50. char g_szCompressBuffer[256];
  51. char g_szDecompressBuffer[256];
  52. DWORD g_OrigCompressTime;
  53. DWORD g_OrigDecompressTime;
  54. DWORD g_AvgCompressTime;
  55. DWORD g_AvgDecompressTime;
  56. DWORD g_aCompressTime[4096];
  57. DWORD g_aDecompressTime[4096];
  58. SYSTEMTIME g_SystemTime;
  59. #endif
  60. typedef struct tagDejaVu
  61. {
  62. VIDEOFORMATEX vfx;
  63. DWORD dwFlags;
  64. } DEJAVU, *PDEJAVU;
  65. #if 1
  66. // Array of known ITU sizes
  67. MYFRAMESIZE g_ITUSizes[8] =
  68. {
  69. { 0, 0 },
  70. { 128, 96 },
  71. { 176, 144 },
  72. { 352, 288 },
  73. #if !defined(_ALPHA_) && defined(USE_BILINEAR_MSH26X)
  74. { 80, 64 },
  75. #else
  76. { 704, 576 },
  77. #endif
  78. { 1408,1152 },
  79. { 0, 0 },
  80. { 0, 0 }
  81. };
  82. // For now, the size of the VIDEOFORMATEX being 1118 even if
  83. // there is no palette, do not enumerate all of the possible
  84. // formats. As soon as you have replaced the BITMAPINFOHEADER
  85. // + Palette by pointers to such structure, enable all the
  86. // sizes.
  87. NCAP_APP_INFO g_awResolutions[VIDEO_FORMAT_NUM_RESOLUTIONS] =
  88. {
  89. // VIDEO_FORMAT_IMAGE_SIZE_40_30,
  90. // VIDEO_FORMAT_IMAGE_SIZE_64_48,
  91. // VIDEO_FORMAT_IMAGE_SIZE_80_60,
  92. // VIDEO_FORMAT_IMAGE_SIZE_96_64,
  93. // VIDEO_FORMAT_IMAGE_SIZE_112_80,
  94. // VIDEO_FORMAT_IMAGE_SIZE_120_90,
  95. { VIDEO_FORMAT_IMAGE_SIZE_128_96, 128, 96 },
  96. // VIDEO_FORMAT_IMAGE_SIZE_144_112,
  97. { VIDEO_FORMAT_IMAGE_SIZE_160_120, 160, 120 },
  98. // VIDEO_FORMAT_IMAGE_SIZE_160_128,
  99. { VIDEO_FORMAT_IMAGE_SIZE_176_144, 176, 144 },
  100. // VIDEO_FORMAT_IMAGE_SIZE_192_160,
  101. // VIDEO_FORMAT_IMAGE_SIZE_200_150,
  102. // VIDEO_FORMAT_IMAGE_SIZE_208_176,
  103. // VIDEO_FORMAT_IMAGE_SIZE_224_192,
  104. { VIDEO_FORMAT_IMAGE_SIZE_240_180, 240, 180 },
  105. // VIDEO_FORMAT_IMAGE_SIZE_240_208,
  106. // VIDEO_FORMAT_IMAGE_SIZE_256_224,
  107. // VIDEO_FORMAT_IMAGE_SIZE_272_240,
  108. // VIDEO_FORMAT_IMAGE_SIZE_280_210,
  109. // VIDEO_FORMAT_IMAGE_SIZE_288_256,
  110. // VIDEO_FORMAT_IMAGE_SIZE_304_272,
  111. { VIDEO_FORMAT_IMAGE_SIZE_320_240, 320, 240 },
  112. // VIDEO_FORMAT_IMAGE_SIZE_320_288,
  113. // VIDEO_FORMAT_IMAGE_SIZE_336_288,
  114. { VIDEO_FORMAT_IMAGE_SIZE_352_288, 352, 288 },
  115. // VIDEO_FORMAT_IMAGE_SIZE_640_480,
  116. };
  117. #else
  118. // For now, the size of the VIDEOFORMATEX being 1118 even if
  119. // there is no palette, do not enumerate all of the possible
  120. // formats. As soon as you have replaced the BITMAPINFOHEADER
  121. // + Palette by pointers to such structure, enable all the
  122. // sizes.
  123. DWORD g_awResolutions[VIDEO_FORMAT_NUM_RESOLUTIONS] =
  124. {
  125. // VIDEO_FORMAT_IMAGE_SIZE_40_30,
  126. // VIDEO_FORMAT_IMAGE_SIZE_64_48,
  127. // VIDEO_FORMAT_IMAGE_SIZE_80_60,
  128. // VIDEO_FORMAT_IMAGE_SIZE_96_64,
  129. // VIDEO_FORMAT_IMAGE_SIZE_112_80,
  130. // VIDEO_FORMAT_IMAGE_SIZE_120_90,
  131. VIDEO_FORMAT_IMAGE_SIZE_160_120,
  132. // VIDEO_FORMAT_IMAGE_SIZE_144_112,
  133. VIDEO_FORMAT_IMAGE_SIZE_128_96,
  134. // VIDEO_FORMAT_IMAGE_SIZE_160_128,
  135. VIDEO_FORMAT_IMAGE_SIZE_240_180,
  136. // VIDEO_FORMAT_IMAGE_SIZE_192_160,
  137. // VIDEO_FORMAT_IMAGE_SIZE_200_150,
  138. // VIDEO_FORMAT_IMAGE_SIZE_208_176,
  139. // VIDEO_FORMAT_IMAGE_SIZE_224_192,
  140. VIDEO_FORMAT_IMAGE_SIZE_176_144,
  141. // VIDEO_FORMAT_IMAGE_SIZE_240_208,
  142. // VIDEO_FORMAT_IMAGE_SIZE_256_224,
  143. // VIDEO_FORMAT_IMAGE_SIZE_272_240,
  144. // VIDEO_FORMAT_IMAGE_SIZE_280_210,
  145. // VIDEO_FORMAT_IMAGE_SIZE_288_256,
  146. // VIDEO_FORMAT_IMAGE_SIZE_304_272,
  147. VIDEO_FORMAT_IMAGE_SIZE_320_240,
  148. // VIDEO_FORMAT_IMAGE_SIZE_320_288,
  149. // VIDEO_FORMAT_IMAGE_SIZE_336_288,
  150. VIDEO_FORMAT_IMAGE_SIZE_352_288,
  151. // VIDEO_FORMAT_IMAGE_SIZE_640_480,
  152. };
  153. #endif
  154. //int g_aiFps[NUM_FPS_ENTRIES] = {3, 7, 15};
  155. int g_aiFps[NUM_FPS_ENTRIES] = {30};
  156. // The order of the bit depths matches what I think is the
  157. // preferred format if more than one is supported.
  158. // For color, 16bit is almost as good as 24 but uses less memory
  159. // and is faster for color QuickCam.
  160. // For greyscale, 16 greyscale levels is Ok, not as good as 64,
  161. // but Greyscale QuickCam is too slow at 64 levels.
  162. int g_aiBitDepth[NUM_BITDEPTH_ENTRIES] = {9, 12, 12, 16, 16, 16, 24, 4, 8};
  163. int g_aiNumColors[NUM_BITDEPTH_ENTRIES] = {VIDEO_FORMAT_NUM_COLORS_YVU9, VIDEO_FORMAT_NUM_COLORS_I420, VIDEO_FORMAT_NUM_COLORS_IYUV, VIDEO_FORMAT_NUM_COLORS_YUY2, VIDEO_FORMAT_NUM_COLORS_UYVY, VIDEO_FORMAT_NUM_COLORS_65536, VIDEO_FORMAT_NUM_COLORS_16777216, VIDEO_FORMAT_NUM_COLORS_16, VIDEO_FORMAT_NUM_COLORS_256};
  164. int g_aiFourCCCode[NUM_BITDEPTH_ENTRIES] = {VIDEO_FORMAT_YVU9, VIDEO_FORMAT_I420, VIDEO_FORMAT_IYUV, VIDEO_FORMAT_YUY2, VIDEO_FORMAT_UYVY, VIDEO_FORMAT_BI_RGB, VIDEO_FORMAT_BI_RGB, VIDEO_FORMAT_BI_RGB, VIDEO_FORMAT_BI_RGB};
  165. int g_aiClrUsed[NUM_BITDEPTH_ENTRIES] = {0, 0, 0, 0, 0, 0, 0, 16, 256};
  166. PVCMSTREAMHEADER DeQueVCMHeader(PVCMSTREAM pvs);
  167. MMRESULT VCMAPI vcmDefaultFormatWriteToReg(LPSTR szDeviceName, LPSTR szDeviceVersion, LPBITMAPINFOHEADER lpbmih);
  168. #define IsVCMHeaderPrepared(pvh) ((pvh)->fdwStatus & VCMSTREAMHEADER_STATUSF_PREPARED)
  169. #define MarkVCMHeaderPrepared(pvh) ((pvh)->fdwStatus |= VCMSTREAMHEADER_STATUSF_PREPARED)
  170. #define MarkVCMHeaderUnprepared(pvh) ((pvh)->fdwStatus &=~VCMSTREAMHEADER_STATUSF_PREPARED)
  171. #define IsVCMHeaderInQueue(pvh) ((pvh)->fdwStatus & VCMSTREAMHEADER_STATUSF_INQUEUE)
  172. #define MarkVCMHeaderInQueue(pvh) ((pvh)->fdwStatus |= VCMSTREAMHEADER_STATUSF_INQUEUE)
  173. #define MarkVCMHeaderUnQueued(pvh) ((pvh)->fdwStatus &=~VCMSTREAMHEADER_STATUSF_INQUEUE)
  174. #define IsVCMHeaderDone(pvh) ((pvh)->fdwStatus & VCMSTREAMHEADER_STATUSF_DONE)
  175. #define MarkVCMHeaderDone(pvh) ((pvh)->fdwStatus |= VCMSTREAMHEADER_STATUSF_DONE)
  176. #define MarkVCMHeaderNotDone(pvh) ((pvh)->fdwStatus &=~VCMSTREAMHEADER_STATUSF_DONE)
  177. /****************************************************************************
  178. * @doc EXTERNAL COMPFUNC
  179. *
  180. * @func MMRESULT | vcmMetrics | This function returns various metrics for the Video
  181. * Compression Manager (VCM) or related VCM objects.
  182. *
  183. * @parm HVCMOBJ | hvo | Specifies the VCM object to query for the metric
  184. * specified in <p uMetric>. This argument may be NULL for some
  185. * queries.
  186. *
  187. * @parm UINT | uMetric | Specifies the metric index to be returned in
  188. * <p pMetric>.
  189. *
  190. * @flag VCM_METRIC_COUNT_COMPRESSORS | Specifies that the returned value is
  191. * the number of global VCM compressors in
  192. * the system. The <p hvo> argument must be NULL for this metric index.
  193. * The <p pMetric> argument must point to a buffer of a size equal to a
  194. * DWORD.
  195. *
  196. * @flag VCM_METRIC_COUNT_DECOMPRESSORS | Specifies that the returned value is
  197. * the number of global VCM decompressors in
  198. * the system. The <p hvo> argument must be NULL for this metric index.
  199. * The <p pMetric> argument must point to a buffer of a size equal to a
  200. * DWORD.
  201. *
  202. * @flag VCM_METRIC_MAX_SIZE_FORMAT | Specifies that the returned value
  203. * is the size of the largest <t VIDEOFORMATEX> structure. If <p hvo>
  204. * is NULL, then the return value is the largest <t VIDEOFORMATEX>
  205. * structure in the system. If <p hvo> identifies an open instance
  206. * of an VCM driver (<t HVCMDRIVER>) or a VCM driver identifier
  207. * (<t HVCMDRIVERID>), then the largest <t VIDEOFORMATEX>
  208. * structure for that driver is returned. The <p pMetric> argument must
  209. * point to a buffer of a size equal to a DWORD. This metric is not allowed
  210. * for a VCM stream handle (<t HVCMSTREAM>).
  211. *
  212. * @parm LPVOID | pMetric | Specifies a pointer to the buffer that will
  213. * receive the metric details. The exact definition depends on the
  214. * <p uMetric> index.
  215. *
  216. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  217. * a non-zero error number. Possible error returns are:
  218. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  219. * @flag MMSYSERR_INVALPARAM | The <p pMetric> parameter is invalid.
  220. * @flag MMSYSERR_NOTSUPPORTED | The <p uMetric> index is not supported.
  221. * @flag VCMERR_NOTPOSSIBLE | The <p uMetric> index cannot be returned
  222. * for the specified <p hvo>.
  223. *
  224. ***************************************************************************/
  225. MMRESULT VCMAPI vcmMetrics(HVCMOBJ hao, UINT uMetric, LPVOID pMetric)
  226. {
  227. MMRESULT mmr;
  228. ICINFO ICinfo;
  229. if (!pMetric)
  230. {
  231. ERRORMESSAGE(("vcmMetrics: Specified pointer is invalid, pMetric=NULL\r\n"));
  232. return ((MMRESULT)MMSYSERR_INVALPARAM);
  233. }
  234. switch (uMetric)
  235. {
  236. case VCM_METRIC_MAX_SIZE_FORMAT:
  237. // For now, assume all VIDEOFORMATEX structures have identical sizes
  238. *(LPDWORD)pMetric = (DWORD)sizeof(VIDEOFORMATEX);
  239. mmr = (MMRESULT)MMSYSERR_NOERROR;
  240. break;
  241. case VCM_METRIC_MAX_SIZE_BITMAPINFOHEADER:
  242. // For now, assume all BITMAPINFOHEADER structures have identical sizes
  243. *(LPDWORD)pMetric = (DWORD)sizeof(BITMAPINFOHEADER);
  244. mmr = (MMRESULT)MMSYSERR_NOERROR;
  245. break;
  246. case VCM_METRIC_COUNT_DRIVERS:
  247. case VCM_METRIC_COUNT_COMPRESSORS:
  248. for (*(LPDWORD)pMetric = 0; ICInfo(ICTYPE_VIDEO, *(LPDWORD)pMetric, &ICinfo); (*(LPDWORD)pMetric)++)
  249. ;
  250. mmr = (MMRESULT)MMSYSERR_NOERROR;
  251. break;
  252. default:
  253. ERRORMESSAGE(("vcmMetrics: Specified index is invalid, uMetric=%ld\r\n", uMetric));
  254. mmr = (MMRESULT)MMSYSERR_NOTSUPPORTED;
  255. break;
  256. }
  257. return (mmr);
  258. }
  259. /****************************************************************************
  260. * @doc EXTERNAL COMPFUNC
  261. *
  262. * @func MMRESULT | vcmDriverDetails | This function queries a specified
  263. * Video Compression Manager (VCM) driver to determine its driver details.
  264. *
  265. * @parm PVCMDRIVERDETAILS | pvdd | Pointer to a <t VCMDRIVERDETAILS>
  266. * structure that will receive the driver details. The
  267. * <e VCMDRIVERDETAILS.cbStruct> member must be initialized to the
  268. * size, in bytes, of the structure. The <e VCMDRIVERDETAILS.fccType> member
  269. * must be initialized to the four-character code indicating the type of
  270. * stream being compressed or decompressed. Specify VCMDRIVERDETAILS_FCCTYPE_VIDEOCODEC
  271. * for video streams. The <e VCMDRIVERDETAILS.fccHandler> member must be initialized
  272. * to the four-character code identifying the compressor.
  273. *
  274. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  275. * a non-zero error number. Possible error returns are:
  276. * @flag MMSYSERR_NODRIVER | No matching codec is present.
  277. * @flag MMSYSERR_INVALPARAM | One or more arguments passed is invalid.
  278. *
  279. * @xref <f vcmDriverEnum>
  280. ***************************************************************************/
  281. MMRESULT VCMAPI vcmDriverDetails(PVCMDRIVERDETAILS pvdd)
  282. {
  283. DWORD fccHandler;
  284. ICINFO ICinfo;
  285. HIC hIC;
  286. // Check input params
  287. if (!pvdd)
  288. {
  289. ERRORMESSAGE(("vcmDriverDetails: Specified pointer is invalid, pvdd=NULL\r\n"));
  290. return ((MMRESULT)MMSYSERR_INVALPARAM);
  291. }
  292. // Make fccHandler uppercase and back it up
  293. fccHandler = pvdd->fccHandler;
  294. if (fccHandler > 256)
  295. CharUpperBuff((LPTSTR)&fccHandler, sizeof(DWORD));
  296. // Try to open the codec
  297. if (hIC = ICOpen(ICTYPE_VIDEO, fccHandler, ICMODE_QUERY))
  298. {
  299. // Get the details
  300. ICGetInfo(hIC, &ICinfo, sizeof(ICINFO));
  301. // Restore fccHandler
  302. ICinfo.fccHandler = fccHandler;
  303. // VCMDRIVERDETAILS and ICINFO are identical structures
  304. CopyMemory(pvdd, &ICinfo, sizeof(VCMDRIVERDETAILS));
  305. // Close the codec
  306. ICClose(hIC);
  307. }
  308. else
  309. return ((MMRESULT)MMSYSERR_NODRIVER);
  310. return ((MMRESULT)MMSYSERR_NOERROR);
  311. }
  312. /****************************************************************************
  313. * @doc EXTERNAL COMPFUNC
  314. *
  315. * @func MMRESULT | vcmFormatDetails | This function queries the Video Compression
  316. * Manager (VCM) for details on format for a specific video format.
  317. *
  318. * @parm PVCMFORMATDETAILS | pvfd | Specifies a pointer to the
  319. * <t VCMFORMATDETAILS> structure that is to receive the format
  320. * details for the given embedded pointer to a <t VIDEOFORMATEX> structure.
  321. *
  322. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  323. * a non-zero error number. Possible error returns are:
  324. * @flag MMSYSERR_NODRIVER | No matching codec is present.
  325. * @flag MMSYSERR_INVALPARAM | One or more arguments passed is invalid.
  326. *
  327. * @xref <f vcmDriverDetails>
  328. ***************************************************************************/
  329. MMRESULT VCMAPI vcmFormatDetails(PVCMFORMATDETAILS pvfd)
  330. {
  331. MMRESULT mmr = (MMRESULT)MMSYSERR_NOERROR;
  332. DWORD fccHandler;
  333. DWORD fccType;
  334. HIC hIC;
  335. char szBuffer[BUFFER_SIZE]; // Could be smaller.
  336. int iLen;
  337. // Check input params
  338. if (!pvfd)
  339. {
  340. ERRORMESSAGE(("vcmDriverDetails: Specified pointer is invalid, pvdd=NULL\r\n"));
  341. return ((MMRESULT)MMSYSERR_INVALPARAM);
  342. }
  343. if (!pvfd->pvfx)
  344. {
  345. ERRORMESSAGE(("vcmDriverDetails: Specified pointer is invalid, pvdd->pvfx=NULL\r\n"));
  346. return ((MMRESULT)MMSYSERR_INVALPARAM);
  347. }
  348. // Make fccHandler uppercase and back it up
  349. fccHandler = pvfd->pvfx->dwFormatTag;
  350. fccType = ICTYPE_VIDEO;
  351. if (fccHandler > 256)
  352. CharUpperBuff((LPTSTR)&fccHandler, sizeof(DWORD));
  353. // Try to open the codec
  354. if (hIC = ICOpen(fccType, pvfd->pvfx->dwFormatTag, ICMODE_QUERY))
  355. {
  356. // Check if the codec supports the format
  357. if (ICDecompressQuery(hIC, &pvfd->pvfx->bih, (LPBITMAPINFOHEADER)NULL) == ICERR_OK)
  358. {
  359. #if 0
  360. if (ICCompressQuery(hIC, (LPBITMAPINFOHEADER)NULL, &pvfd->pvfx->bih) == ICERR_OK)
  361. {
  362. #endif
  363. // Now complete the format details info, overwrite some of the fields of
  364. // the VIDEOFORMATEX structure too, just in case we were passed bogus values...
  365. pvfd->pvfx->nSamplesPerSec = g_aiFps[0];
  366. if (pvfd->pvfx->dwFormatTag > 256)
  367. wsprintf(szBuffer, IDS_FORMAT_1, (LPSTR)&fccType, (LPSTR)&fccHandler,
  368. pvfd->pvfx->bih.biBitCount, pvfd->pvfx->nSamplesPerSec,
  369. pvfd->pvfx->bih.biWidth, pvfd->pvfx->bih.biHeight);
  370. else
  371. wsprintf(szBuffer, IDS_FORMAT_2, (LPSTR)&fccType, fccHandler,
  372. pvfd->pvfx->bih.biBitCount, pvfd->pvfx->nSamplesPerSec,
  373. pvfd->pvfx->bih.biWidth, pvfd->pvfx->bih.biHeight);
  374. iLen = MultiByteToWideChar(GetACP(), 0, szBuffer, -1, pvfd->szFormat, 0);
  375. MultiByteToWideChar(GetACP(), 0, szBuffer, -1, pvfd->szFormat, iLen);
  376. #if 0
  377. }
  378. else
  379. mmr = (MMRESULT)MMSYSERR_NODRIVER;
  380. #endif
  381. }
  382. else
  383. mmr = (MMRESULT)MMSYSERR_NODRIVER;
  384. // Close the codec
  385. ICClose(hIC);
  386. }
  387. else
  388. mmr = (MMRESULT)MMSYSERR_NODRIVER;
  389. return (mmr);
  390. }
  391. /*****************************************************************************
  392. * @doc EXTERNAL DEVCAPSFUNC
  393. *
  394. * @func MMRESULT | vcmGetDevCaps | This function queries a specified
  395. * video capture input device to determine its capabilities.
  396. *
  397. * @parm UINT | uDevice | Specifies the video capture input device ID.
  398. *
  399. * @parm PVIDEOINCAPS | pvc | Specifies a pointer to a <t VIDEOINCAPS>
  400. * structure. This structure is filled with information about the
  401. * capabilities of the device.
  402. *
  403. * @parm UINT | cbvc | Specifies the size of the <t VIDEOINCAPS> structure.
  404. *
  405. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  406. * an error number. Possible error values include the following:
  407. * @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
  408. * @flag MMSYSERR_BADDEVICEID | Specified device device ID is invalid.
  409. * @flag MMSYSERR_INVALPARAM | Specified pointer to structure is invalid.
  410. * @flag MMSYSERR_NODRIVER | No capture device driver or device is present.
  411. * @flag VCMERR_NONSPECIFIC | The capture driver failed to provide description information.
  412. *
  413. * @comm Only <p cbwc> bytes (or less) of information is copied to the location
  414. * pointed to by <p pvc>. If <p cbwc> is zero, nothing is copied, and
  415. * the function returns zero.
  416. *
  417. * If the ID of the capture device passed is VIDEO_MAPPER, the first device in the list
  418. * of installed capture devices is considered.
  419. *
  420. * @devnote You never return MMSYSERR_NODRIVER. Is there a way to make a difference
  421. * between a call failing because there is no device, or because of a device failure?
  422. *
  423. * @xref <f videoDevCapsProfile> <f videoDevCapsReadFromReg> <f videoDevCapsWriteToReg>
  424. ****************************************************************************/
  425. MMRESULT VCMAPI vcmGetDevCaps(UINT uDevice, PVIDEOINCAPS pvc, UINT cbvc)
  426. {
  427. MMRESULT mmr;
  428. FINDCAPTUREDEVICE fcd;
  429. // Check input params
  430. if ((uDevice >= MAXVIDEODRIVERS) && (uDevice != VIDEO_MAPPER))
  431. {
  432. ERRORMESSAGE(("vcmGetDevCaps: Specified capture device ID is invalid, uDevice=%ld (expected values are 0x%lX or between 0 and %ld)\r\n", uDevice, VIDEO_MAPPER, MAXVIDEODRIVERS-1));
  433. return ((MMRESULT)MMSYSERR_BADDEVICEID);
  434. }
  435. if (!pvc)
  436. {
  437. ERRORMESSAGE(("vcmGetDevCaps: Specified pointer is invalid, pvc=NULL\r\n"));
  438. return ((MMRESULT)MMSYSERR_INVALPARAM);
  439. }
  440. if (!cbvc)
  441. {
  442. ERRORMESSAGE(("vcmGetDevCaps: Specified structure size is invalid, cbvc=%ld\r\n", cbvc));
  443. return ((MMRESULT)MMSYSERR_NOERROR);
  444. }
  445. // Get the driver name and version number
  446. fcd.dwSize = sizeof (FINDCAPTUREDEVICE);
  447. if (uDevice == VIDEO_MAPPER)
  448. {
  449. if (!FindFirstCaptureDevice(&fcd, NULL))
  450. {
  451. ERRORMESSAGE(("vcmGetDevCaps: FindFirstCaptureDevice() failed\r\n"));
  452. return ((MMRESULT)VCMERR_NONSPECIFIC);
  453. }
  454. }
  455. else
  456. {
  457. if (!FindFirstCaptureDeviceByIndex(&fcd, uDevice))
  458. {
  459. ERRORMESSAGE(("vcmGetDevCaps: FindFirstCaptureDevice() failed\r\n"));
  460. return ((MMRESULT)VCMERR_NONSPECIFIC);
  461. }
  462. }
  463. // Set default values
  464. pvc->dwImageSize = pvc->dwNumColors = (DWORD)NULL;
  465. pvc->dwStreamingMode = STREAMING_PREFER_FRAME_GRAB;
  466. pvc->dwDialogs = FORMAT_DLG_OFF | SOURCE_DLG_ON;
  467. //Look for a specific version of the driver first....
  468. lstrcpy(pvc->szDeviceName, fcd.szDeviceDescription);
  469. lstrcpy(pvc->szDeviceVersion, fcd.szDeviceVersion);
  470. // Based on the name and version number of the driver, set capabilities.
  471. // We first try to look them up from the registry. If this is a very popular
  472. // board/camera, chances are that we have set the key at install time already.
  473. // If we can't find the key, we profile the hardware and save the results
  474. // to the registry.
  475. if (vcmDevCapsReadFromReg(pvc->szDeviceName, pvc->szDeviceVersion,pvc, cbvc) != MMSYSERR_NOERROR)
  476. {
  477. //Didn't find the specific version, try it again, with NULL version info
  478. pvc->szDeviceVersion[0]= (char) NULL;
  479. if (vcmDevCapsReadFromReg(pvc->szDeviceName, NULL,pvc, cbvc) != MMSYSERR_NOERROR)
  480. {
  481. DEBUGMSG (ZONE_VCM, ("vcmGetDevCaps: Unknown capture hardware found. Profiling...\r\n"));
  482. lstrcpy(pvc->szDeviceVersion, fcd.szDeviceVersion);
  483. if ((mmr = vcmDevCapsProfile(uDevice, pvc, cbvc)) == MMSYSERR_NOERROR)
  484. {
  485. // record this default in the registry
  486. if (pvc->szDeviceName[0] != '\0')
  487. {
  488. vcmDevCapsWriteToReg(pvc->szDeviceName, pvc->szDeviceVersion, pvc, cbvc);
  489. }
  490. else
  491. {
  492. //fcd.szDeviceName is the Driver Name
  493. vcmDevCapsWriteToReg(fcd.szDeviceName, pvc->szDeviceVersion, pvc, cbvc);
  494. }
  495. }
  496. else
  497. {
  498. ERRORMESSAGE(("vcmGetDevCaps: vcmDevCapsProfile() failed\r\n"));
  499. return (mmr);
  500. }
  501. }
  502. }
  503. return ((MMRESULT)MMSYSERR_NOERROR);
  504. }
  505. /****************************************************************************
  506. * @doc INTERNAL COMPFUNC
  507. *
  508. * @func MMRESULT | AppICInfo | The <f AppICInfo> function
  509. * will either call the standard ICInfo function
  510. * function continues enumerating until there are no more suitable
  511. * formats for the format tag or the callback function returns FALSE.
  512. *
  513. ***************************************************************************/
  514. /*
  515. * NOTE:
  516. *
  517. * ICInfo returns TRUE on success and FALSE on failure. The documentation suggests
  518. * otherwise and is wrong. AppICInfo returns the same.
  519. */
  520. BOOL VFWAPI AppICInfo(DWORD fccType, DWORD fccHandler, ICINFO FAR * lpicinfo, DWORD fdwEnum)
  521. {
  522. if ((fdwEnum & VCM_FORMATENUMF_ALLMASK) == VCM_FORMATENUMF_ALL)
  523. {
  524. // enumerating all formats, just do the standard ICInfo
  525. return ICInfo(fccType, fccHandler, lpicinfo);
  526. }
  527. else
  528. {
  529. // only enumerating specific formats
  530. // are we done ?
  531. if (fccHandler >= (DWORD)g_nNumVCMAppInfoEntries)
  532. {
  533. // we're done enumerating app-specific formats
  534. return FALSE;
  535. }
  536. lpicinfo->fccType = g_aVCMAppInfo[fccHandler].fccType;
  537. lpicinfo->fccHandler = g_aVCMAppInfo[fccHandler].fccHandler;
  538. return TRUE;
  539. }
  540. }
  541. BOOL vcmBuildDefaultEntries (void)
  542. {
  543. //Yikes! Reg. problem (or first boot) instantiate only the minimum...
  544. #if !defined(_ALPHA_) && defined(USE_BILINEAR_MSH26X)
  545. g_nNumVCMAppInfoEntries=3;
  546. #else
  547. g_nNumVCMAppInfoEntries=2;
  548. #endif
  549. g_nNumFrameSizesEntries=MAX_NUM_REGISTERED_SIZES;
  550. g_fNewCodecsInstalled=FALSE;
  551. //Allocate space for the VCM_APP_ICINFO structure (zero init'd)
  552. if (!(g_aVCMAppInfo = (VCM_APP_ICINFO *)MemAlloc (g_nNumVCMAppInfoEntries*sizeof (VCM_APP_ICINFO)))) {
  553. //Aiiie!
  554. ERRORMESSAGE (("vcmBDE: Memory Allocation Failed!\r\n"));
  555. return FALSE;
  556. }
  557. //H.263
  558. g_aVCMAppInfo[0].fccType=ICTYPE_VIDEO;
  559. #ifndef _ALPHA_
  560. g_aVCMAppInfo[0].fccHandler=VIDEO_FORMAT_MSH263;
  561. #else
  562. g_aVCMAppInfo[0].fccHandler=VIDEO_FORMAT_DECH263;
  563. #endif
  564. g_aVCMAppInfo[0].framesize[0].biWidth=128;
  565. g_aVCMAppInfo[0].framesize[0].biHeight=96;
  566. g_aVCMAppInfo[0].framesize[1].biWidth=176;
  567. g_aVCMAppInfo[0].framesize[1].biHeight=144;
  568. g_aVCMAppInfo[0].framesize[2].biWidth=352;
  569. g_aVCMAppInfo[0].framesize[2].biHeight=288;
  570. //H.261
  571. g_aVCMAppInfo[1].fccType=ICTYPE_VIDEO;
  572. #ifndef _ALPHA_
  573. g_aVCMAppInfo[1].fccHandler=VIDEO_FORMAT_MSH261;
  574. #else
  575. g_aVCMAppInfo[1].fccHandler=VIDEO_FORMAT_DECH261;
  576. #endif
  577. g_aVCMAppInfo[1].framesize[0].biWidth=0;
  578. g_aVCMAppInfo[1].framesize[0].biHeight=0;
  579. g_aVCMAppInfo[1].framesize[1].biWidth=176;
  580. g_aVCMAppInfo[1].framesize[1].biHeight=144;
  581. g_aVCMAppInfo[1].framesize[2].biWidth=352;
  582. g_aVCMAppInfo[1].framesize[2].biHeight=288;
  583. #if !defined(_ALPHA_) && defined(USE_BILINEAR_MSH26X)
  584. //H.26X
  585. g_aVCMAppInfo[2].fccType=ICTYPE_VIDEO;
  586. g_aVCMAppInfo[2].fccHandler=VIDEO_FORMAT_MSH26X;
  587. g_aVCMAppInfo[2].framesize[0].biWidth=80;
  588. g_aVCMAppInfo[2].framesize[0].biHeight=64;
  589. g_aVCMAppInfo[2].framesize[1].biWidth=128;
  590. g_aVCMAppInfo[2].framesize[1].biHeight=96;
  591. g_aVCMAppInfo[2].framesize[2].biWidth=176;
  592. g_aVCMAppInfo[2].framesize[2].biHeight=144;
  593. #endif
  594. return TRUE;
  595. }
  596. BOOL vcmFillGlobalsFromRegistry (void)
  597. {
  598. int i,j,k,iFormats,iOffset;
  599. DWORD *pTmp;
  600. BOOL bKnown;
  601. MYFRAMESIZE *pTmpFrame;
  602. char **pVCMNames;
  603. VIDCAP_DETAILS **pVCMData;
  604. UINT nFormats;
  605. //Read the registry for all the keys that we care about
  606. //We're loading the values of HKLM\Software\Microsoft\Internet Audio\VCMEncodings
  607. if (ReadRegistryFormats(szRegInternetPhone TEXT("\\") szRegInternetPhoneVCMEncodings,
  608. &pVCMNames,(BYTE ***)&pVCMData,&nFormats,sizeof (VIDCAP_DETAILS)) != ERROR_SUCCESS) {
  609. ERRORMESSAGE (("vcmFillGlobalsFromRegistry, couldn't build formats from registry\r\n"));
  610. return (vcmBuildDefaultEntries());
  611. }
  612. //Minimum number of frame and format sizes;
  613. g_nNumFrameSizesEntries=MAX_NUM_REGISTERED_SIZES;
  614. g_nNumVCMAppInfoEntries=0;
  615. g_fNewCodecsInstalled=FALSE;
  616. //Allocate a temp buffer of size of nFormats, use this to track various things
  617. if (!(pTmp = (DWORD *)MemAlloc (nFormats * sizeof (DWORD)))) {
  618. ERRORMESSAGE (("vcmFillGlobalsFromRegistry: Memory Allocation Failed!\r\n"));
  619. return FALSE;
  620. }
  621. //Find the number of formats,
  622. for (i=0;i< (int )nFormats;i++) {
  623. bKnown=FALSE;
  624. for (j=0;j<g_nNumVCMAppInfoEntries;j++) {
  625. if (pVCMData[i]->dwFormatTag == pTmp[j]) {
  626. bKnown=TRUE;
  627. break;
  628. }
  629. }
  630. if (!bKnown) {
  631. //something new
  632. pTmp[g_nNumVCMAppInfoEntries++]=pVCMData[i]->dwFormatTag;
  633. g_fNewCodecsInstalled=TRUE;
  634. }
  635. }
  636. //Allocate space for the VCM_APP_ICINFO structure (zero init'd)
  637. if (g_aVCMAppInfo != NULL)
  638. {
  639. MemFree(g_aVCMAppInfo);
  640. }
  641. if (!(g_aVCMAppInfo = (VCM_APP_ICINFO *)MemAlloc (g_nNumVCMAppInfoEntries*sizeof (VCM_APP_ICINFO))))
  642. {
  643. //Aiiie!
  644. MemFree (pTmp);
  645. ERRORMESSAGE (("vcmFillGlobalsFromRegistry: Memory Allocation Failed!\r\n"));
  646. return FALSE;
  647. }
  648. //Fill out the basic information.
  649. //All elements have a certain commonality
  650. for (j=0;j<g_nNumVCMAppInfoEntries;j++) {
  651. g_aVCMAppInfo[j].fccType=ICTYPE_VIDEO;
  652. g_aVCMAppInfo[j].fccHandler=pTmp[j];
  653. //Known local formats
  654. iFormats=0;
  655. for (i=0;i<(int )nFormats;i++) {
  656. if (pTmp[j] == pVCMData[i]->dwFormatTag) {
  657. //Ok, add the registry size, if we don't have it listed
  658. bKnown=FALSE;
  659. for (k=0;k<iFormats;k++) {
  660. if (g_aVCMAppInfo[j].framesize[k].biWidth == pVCMData[i]->video_params.biWidth &&
  661. g_aVCMAppInfo[j].framesize[k].biHeight == pVCMData[i]->video_params.biHeight ) {
  662. bKnown=TRUE;
  663. break;
  664. }
  665. }
  666. if (!bKnown) {
  667. iOffset=pVCMData[i]->video_params.enumVideoSize;
  668. g_aVCMAppInfo[j].framesize[iOffset].biWidth = (WORD)pVCMData[i]->video_params.biWidth;
  669. g_aVCMAppInfo[j].framesize[iOffset].biHeight = (WORD)pVCMData[i]->video_params.biHeight;
  670. iFormats++;
  671. }
  672. }
  673. }
  674. }
  675. //Now, build the DCAP_APP_INFO ptr
  676. //Max * is #entries * MAX_NUM_REGISTERED_SIZES
  677. if (!(pTmpFrame = (MYFRAMESIZE *)MemAlloc ((g_nNumVCMAppInfoEntries*MAX_NUM_REGISTERED_SIZES)*sizeof (DWORD)))) {
  678. //Aiiie!
  679. MemFree (pTmp);
  680. ERRORMESSAGE (("vcmFillGlobalsFromRegistry: Memory Allocation Failed!\r\n"));
  681. return FALSE;
  682. }
  683. iFormats=0;
  684. for (j=0;j<g_nNumVCMAppInfoEntries;j++) {
  685. //Magic # of frame sizes per format
  686. for (k=0;k < MAX_NUM_REGISTERED_SIZES;k++) {
  687. bKnown=FALSE;
  688. for (i=0;i<iFormats;i++) {
  689. if ( (g_aVCMAppInfo[j].framesize[k].biWidth == pTmpFrame[i].biWidth &&
  690. g_aVCMAppInfo[j].framesize[k].biHeight == pTmpFrame[i].biHeight)
  691. || (!g_aVCMAppInfo[j].framesize[k].biWidth && !g_aVCMAppInfo[j].framesize[k].biHeight) ){
  692. bKnown=TRUE;
  693. break;
  694. }
  695. }
  696. if (!bKnown) {
  697. pTmpFrame[iFormats].biWidth = g_aVCMAppInfo[j].framesize[k].biWidth;
  698. pTmpFrame[iFormats++].biHeight = g_aVCMAppInfo[j].framesize[k].biHeight;
  699. }
  700. }
  701. }
  702. g_nNumFrameSizesEntries=iFormats;
  703. //Free up the ReadRegistryEntries memory...
  704. for (i=0;i<(int) nFormats; i++) {
  705. MemFree (pVCMNames[i]);
  706. MemFree (pVCMData[i]);
  707. }
  708. MemFree (pVCMNames);
  709. MemFree (pVCMData);
  710. MemFree (pTmp);
  711. MemFree (pTmpFrame);
  712. return TRUE;
  713. }
  714. /****************************************************************************
  715. * @doc EXTERNAL COMPFUNC
  716. *
  717. * @func MMRESULT | vcmFormatEnum | The <f vcmFormatEnum> function
  718. * enumerates video formats available. The <f vcmFormatEnum>
  719. * function continues enumerating until there are no more suitable
  720. * formats for the format tag or the callback function returns FALSE.
  721. *
  722. * @parm UINT | uDevice | Specifies the capture device ID.
  723. *
  724. * @parm VCMFORMATENUMCB | fnCallback | Specifies the procedure-instance
  725. * address of the application-defined callback function.
  726. *
  727. * @parm PVCMDRIVERDETAILS | pvdd | Specifies a pointer to the
  728. * <t VCMDRIVERDETAILS> structure that is to receive the driver details
  729. * passed to the <p fnCallback> function.
  730. *
  731. * @parm PVCMFORMATDETAILS | pvfd | Specifies a pointer to the
  732. * <t VCMFORMATDETAILS> structure that is to receive the format details
  733. * passed to the <p fnCallback> function. This structure must have the
  734. * <e VCMFORMATDETAILS.cbStruct>, <e VCMFORMATDETAILS.pvfx>, and
  735. * <e VCMFORMATDETAILS.cbvfx> members of the <t VCMFORMATDETAILS>
  736. * structure initialized. The <e VCMFORMATDETAILS.dwFormatTag> member
  737. * must also be initialized to either VIDEO_FORMAT_UNKNOWN or a
  738. * valid format tag.
  739. *
  740. * @parm DWORD | dwInstance | Specifies a 32-bit, application-defined value
  741. * that is passed to the callback function along with VCM format details.
  742. *
  743. * @parm DWORD | fdwEnum | Specifies flags for enumerating formats that can be
  744. * generated, or formats that can be decompressed.
  745. *
  746. * @flag VCM_FORMATENUMF_INPUT | Specifies that the format enumeration should only
  747. * return the video formats that can be transmitted.
  748. *
  749. * @flag VCM_FORMATENUMF_OUTPUT | Specifies that the format enumeration should only
  750. * return the video formats that can be received.
  751. *
  752. * @flag VCM_FORMATENUMF_BOTH | Specifies that the format enumeration should
  753. * return the video formats that can be received and transmitted.
  754. *
  755. * @flag VCM_FORMATENUMF_APP | Specifies that the format enumeration should
  756. * enumerate only video formats known to the application
  757. *
  758. * @flag VCM_FORMATENUMF_ALL | Specifies that the format enumeration should
  759. * enumerate all video formats known to VCM
  760. *
  761. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  762. * a non-zero error number. Possible error returns are:
  763. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  764. * @flag MMSYSERR_INVALFLAG | One or more flags are invalid.
  765. * @flag MMSYSERR_INVALPARAM | One or more arguments passed are invalid.
  766. * @flag MMSYSERR_NOMEM | A memory allocation failed.
  767. * @flag MMSYSERR_BADDEVICEID | Specified device device ID is invalid.
  768. * @flag VCMERR_NOTPOSSIBLE | The details for the format cannot be
  769. * returned.
  770. *
  771. * @comm The <f vcmFormatEnum> function will return MMSYSERR_NOERROR
  772. * (zero) if no suitable VCM drivers are installed. Moreover, the
  773. * callback function will not be called.
  774. *
  775. * @xref <f vcmFormatEnumCallback>
  776. ***************************************************************************/
  777. MMRESULT VCMAPI vcmFormatEnum( UINT uDevice, VCMFORMATENUMCB fnCallback, PVCMDRIVERDETAILS pvdd,
  778. PVCMFORMATDETAILS pvfd, DWORD_PTR dwInstance, DWORD fdwEnum)
  779. {
  780. int i, j, k, l, m;
  781. HIC hIC;
  782. ICINFO ICinfo;
  783. BITMAPINFO bmi;
  784. DWORD dw;
  785. char szBuffer[BUFFER_SIZE]; // Could be smaller.
  786. int iLen;
  787. VIDEOINCAPS vic;
  788. PDEJAVU pdvDejaVuCurr, pdvDejaVu;
  789. BOOL bDejaVu, fUnsupportedInputSize, fUnsupportedBitDepth;
  790. DWORD fccHandler;
  791. int iNumCaps = 0; // Num of valid caps into the advDejaVu matrix
  792. // Check input params
  793. if (!pvdd)
  794. {
  795. ERRORMESSAGE(("vcmFormatEnum: Specified pointer is invalid, pvdd=NULL\r\n"));
  796. return ((MMRESULT)MMSYSERR_INVALPARAM);
  797. }
  798. if (!pvfd)
  799. {
  800. ERRORMESSAGE(("vcmFormatEnum: Specified pointer is invalid, pvfd=NULL\r\n"));
  801. return ((MMRESULT)MMSYSERR_INVALPARAM);
  802. }
  803. if (!(VCM_FORMATENUMF_TYPEMASK & fdwEnum))
  804. {
  805. ERRORMESSAGE(("vcmFormatEnum: Specified mask is invalid, fdwEnum=0x%lX\r\n", fdwEnum));
  806. return ((MMRESULT)MMSYSERR_INVALFLAG);
  807. }
  808. if ((uDevice >= MAXVIDEODRIVERS) && (uDevice != VIDEO_MAPPER))
  809. {
  810. ERRORMESSAGE(("vcmFormatEnum: Specified capture device ID is invalid, uDevice=%ld (expected values are 0x%lX or between 0 and %ld)\r\n", uDevice, VIDEO_MAPPER, MAXVIDEODRIVERS-1));
  811. return ((MMRESULT)MMSYSERR_BADDEVICEID);
  812. }
  813. //Build the system VCM globals
  814. if (!vcmFillGlobalsFromRegistry ())
  815. {
  816. ERRORMESSAGE (("vcmFormatEnum, couldn't build formats from registry\r\n"));
  817. return (VCMERR_NOTPOSSIBLE);
  818. }
  819. // We need to remember what we have already enumerated
  820. // The formats already enumerated are stored in the following matrix
  821. if (!(pdvDejaVu = (PDEJAVU)MemAlloc(g_nNumFrameSizesEntries *
  822. NUM_BITDEPTH_ENTRIES *
  823. NUM_FPS_ENTRIES * sizeof(DEJAVU))))
  824. {
  825. ERRORMESSAGE(("vcmFormatEnum: A memory allocation failed\r\n"));
  826. return ((MMRESULT)MMSYSERR_NOMEM);
  827. }
  828. // If we enumerate formats we can generate, they need to be in sync with what
  829. // the capture hardware can actually produce, that is RGB4, RGB8, RGB16, RGB24, YUY2, UYVY, YVU9, I420 or IYUV.
  830. if ((fdwEnum & VCM_FORMATENUMF_INPUT) || (fdwEnum & VCM_FORMATENUMF_BOTH))
  831. {
  832. if (vcmGetDevCaps(uDevice, &vic, sizeof(VIDEOINCAPS)) != MMSYSERR_NOERROR)
  833. {
  834. if (fdwEnum & VCM_FORMATENUMF_INPUT)
  835. return ((MMRESULT)MMSYSERR_NOERROR);
  836. else
  837. fdwEnum = VCM_FORMATENUMF_OUTPUT;
  838. }
  839. }
  840. // We're asked to enumerate all the formats that this machine can render or transmit.
  841. // We can send or render all the RGB formats, in which case they will not be
  842. // compressed/decompressed, but directly transmitted/rendered by the UI. But still, someone needs
  843. // to enumerate these. This is done here.
  844. // We, of course, also enumerate the formats that we can decompress and the ones we can generate.
  845. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  846. bmi.bmiHeader.biPlanes = 1;
  847. bmi.bmiHeader.biCompression = BI_RGB;
  848. bmi.bmiHeader.biXPelsPerMeter = 0;
  849. bmi.bmiHeader.biYPelsPerMeter = 0;
  850. bmi.bmiHeader.biClrUsed = 0;
  851. bmi.bmiHeader.biClrImportant = 0;
  852. // Now enumerate real compressors
  853. // for (i=0; ICInfo(ICTYPE_VIDEO, i, &ICinfo); i++) == NO GOOD:
  854. // We need to enumerate everything and then filter on
  855. // the value of fccHandler, because some codecs will fail to
  856. // enum entirely if the fccType parameter to ICInfo is non null.
  857. // SOMEONE should be shot...
  858. for (i=0; AppICInfo(0, i, &ICinfo, fdwEnum); i++, iNumCaps = 0)
  859. {
  860. // Get the details of the ICINFO structure
  861. if ((ICinfo.fccType == ICTYPE_VIDEO) && (ICInfo(ICinfo.fccType, ICinfo.fccHandler, &ICinfo)))
  862. {
  863. // Make fccHandler uppercase and back it up
  864. if (ICinfo.fccHandler > 256)
  865. CharUpperBuff((LPTSTR)&ICinfo.fccHandler, sizeof(DWORD));
  866. fccHandler = ICinfo.fccHandler;
  867. // If the client returns FALSE we need to terminate the enumeration process
  868. if (hIC = ICOpen(ICinfo.fccType, ICinfo.fccHandler, ICMODE_QUERY))
  869. {
  870. // Enable H.26x codecs
  871. #ifndef _ALPHA_
  872. #ifdef USE_BILINEAR_MSH26X
  873. if ((ICinfo.fccHandler == VIDEO_FORMAT_MSH263) || (ICinfo.fccHandler == VIDEO_FORMAT_MSH261) || (ICinfo.fccHandler == VIDEO_FORMAT_MSH26X))
  874. #else
  875. if ((ICinfo.fccHandler == VIDEO_FORMAT_MSH263) || (ICinfo.fccHandler == VIDEO_FORMAT_MSH261))
  876. #endif
  877. #else
  878. if ((ICinfo.fccHandler == VIDEO_FORMAT_DECH263) || (ICinfo.fccHandler == VIDEO_FORMAT_DECH261))
  879. #endif
  880. ICSendMessage(hIC, CUSTOM_ENABLE_CODEC, G723MAGICWORD1, G723MAGICWORD2);
  881. ICGetInfo(hIC, &ICinfo, sizeof(ICINFO));
  882. // The VDEC codec sets the fccType to the same
  883. // value than the fccHandler! Correct that hereticism:
  884. if ((ICinfo.fccType == VIDEO_FORMAT_VDEC) && (ICinfo.fccHandler == VIDEO_FORMAT_VDEC))
  885. ICinfo.fccType = ICTYPE_VIDEO;
  886. // Restore fccHandler
  887. ICinfo.fccHandler = fccHandler;
  888. // VCMDRIVERDETAILS and ICINFO are identical structures
  889. CopyMemory(pvdd, &ICinfo, sizeof(VCMDRIVERDETAILS));
  890. // For all the built-in sizes we support
  891. for (l=0; l<MAX_NUM_REGISTERED_SIZES; l++)
  892. {
  893. if ((g_aVCMAppInfo[i].framesize[l].biWidth != 0) && (g_aVCMAppInfo[i].framesize[l].biHeight != 0))
  894. {
  895. fUnsupportedInputSize = FALSE;
  896. #ifndef NO_LARGE_SIZE_EXCLUSION_HACK
  897. // HACK for version 2
  898. // Since we didn't get general scaling code into version 2, we want to disable the largest size
  899. // if the capture device doesn't support it. Otherwise we'll put a smaller size into the middle
  900. // of a large black field which looks ugly. For version 3, we should be able to add the general
  901. // scaling code and remove this hack.
  902. if (l == MAX_NUM_REGISTERED_SIZES-1) {
  903. // find largest size supported by capture device
  904. // NOTE: we assume that the bit definitions for sizes are sorted
  905. for (k = VIDEO_FORMAT_NUM_RESOLUTIONS-1; k >= 0 && !(g_awResolutions[k].dwRes & vic.dwImageSize); k--)
  906. {}
  907. // if we don't find a size, or the size is not greater than half the current size
  908. // then mark the size as not supported
  909. if ((k < 0) ||
  910. (g_awResolutions[k].framesize.biWidth <= (LONG)g_aVCMAppInfo[i].framesize[l].biWidth/2) ||
  911. (g_awResolutions[k].framesize.biHeight <= (LONG)g_aVCMAppInfo[i].framesize[l].biHeight/2)) {
  912. // capture doesn't support this size
  913. if (fdwEnum & VCM_FORMATENUMF_INPUT)
  914. continue; // we're done
  915. else if (fdwEnum & VCM_FORMATENUMF_BOTH)
  916. fUnsupportedInputSize = TRUE;
  917. }
  918. }
  919. #endif
  920. // The new capture stuff can generate data at any size
  921. bmi.bmiHeader.biWidth = (LONG)g_aVCMAppInfo[i].framesize[l].biWidth;
  922. bmi.bmiHeader.biHeight = (LONG)g_aVCMAppInfo[i].framesize[l].biHeight;
  923. // For all the bit depths we support
  924. for (k=0; k<NUM_BITDEPTH_ENTRIES; k++)
  925. {
  926. // Try the non-RGB formats only if no RGB format
  927. fUnsupportedBitDepth = FALSE;
  928. if (((fdwEnum & VCM_FORMATENUMF_INPUT) || (fdwEnum & VCM_FORMATENUMF_BOTH)) && !((g_aiNumColors[k] & vic.dwNumColors)))
  929. fUnsupportedBitDepth = TRUE;
  930. if ((fdwEnum & VCM_FORMATENUMF_INPUT) && fUnsupportedBitDepth)
  931. goto NextCompressedBitDepth;
  932. // Set the direction flag appropriately
  933. if (fdwEnum & VCM_FORMATENUMF_OUTPUT)
  934. pvfd->dwFlags = VCM_FORMATENUMF_OUTPUT;
  935. else if (fdwEnum & VCM_FORMATENUMF_INPUT)
  936. pvfd->dwFlags = VCM_FORMATENUMF_INPUT;
  937. else if (fdwEnum & VCM_FORMATENUMF_BOTH)
  938. {
  939. if (fUnsupportedInputSize || fUnsupportedBitDepth)
  940. pvfd->dwFlags = VCM_FORMATENUMF_OUTPUT;
  941. else
  942. pvfd->dwFlags = VCM_FORMATENUMF_BOTH;
  943. }
  944. bmi.bmiHeader.biBitCount = (WORD)g_aiBitDepth[k];
  945. bmi.bmiHeader.biCompression = g_aiFourCCCode[k];
  946. bmi.bmiHeader.biSizeImage = (DWORD)WIDTHBYTES(bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount) * bmi.bmiHeader.biHeight;
  947. // Check if the compressor supports the format
  948. if (ICCompressQuery(hIC, &bmi, (LPBITMAPINFOHEADER)NULL) == ICERR_OK)
  949. {
  950. // Now get the size required to hold the format
  951. dw = ICCompressGetFormatSize(hIC, &bmi);
  952. // PHILF's BUGBUG: pvfd->cbvfx is the size of the whole structure, not the bitmap info header
  953. if ((dw >= sizeof(BITMAPINFOHEADER)) && (dw <= pvfd->cbvfx))
  954. {
  955. if (ICCompressGetFormat(hIC, &bmi, &pvfd->pvfx->bih) == ICERR_OK)
  956. {
  957. // Check if it has alreay been enumerated
  958. for (m=0, bDejaVu=FALSE, pdvDejaVuCurr = pdvDejaVu; m<iNumCaps; m++, pdvDejaVuCurr++)
  959. {
  960. bDejaVu = (!((pdvDejaVuCurr->vfx.bih.biWidth != pvfd->pvfx->bih.biWidth)
  961. || (pdvDejaVuCurr->vfx.bih.biHeight != pvfd->pvfx->bih.biHeight)
  962. || (pdvDejaVuCurr->vfx.bih.biBitCount != pvfd->pvfx->bih.biBitCount)
  963. || (pdvDejaVuCurr->vfx.bih.biCompression != pvfd->pvfx->bih.biCompression)));
  964. if (bDejaVu)
  965. {
  966. // Only remember the maximum compressed size
  967. if (pdvDejaVuCurr->vfx.bih.biSizeImage < pvfd->pvfx->bih.biSizeImage)
  968. pdvDejaVuCurr->vfx.bih.biSizeImage = pvfd->pvfx->bih.biSizeImage;
  969. break;
  970. }
  971. }
  972. if (!bDejaVu)
  973. {
  974. // Add new format to the list of DejaVus
  975. CopyMemory(&(pdvDejaVu + iNumCaps)->vfx, pvfd->pvfx, sizeof(VIDEOFORMATEX));
  976. (pdvDejaVu + iNumCaps)->dwFlags = pvfd->dwFlags;
  977. // Update count of caps
  978. iNumCaps++;
  979. }
  980. else
  981. if ((pvfd->dwFlags == VCM_FORMATENUMF_BOTH) && ((pdvDejaVu + m)->dwFlags != VCM_FORMATENUMF_BOTH))
  982. (pdvDejaVu + m)->dwFlags = VCM_FORMATENUMF_BOTH;
  983. }
  984. }
  985. }
  986. NextCompressedBitDepth:;
  987. }
  988. }
  989. }
  990. ICClose(hIC);
  991. // For all the caps we have found
  992. for (m=0; m<iNumCaps; m++)
  993. {
  994. // For all the frame rates we support
  995. for (j=0; j<NUM_FPS_ENTRIES; j++)
  996. {
  997. // Copy the cap and flags
  998. CopyMemory(pvfd->pvfx, &(pdvDejaVu + m)->vfx, sizeof(VIDEOFORMATEX));
  999. pvfd->dwFlags = (pdvDejaVu + m)->dwFlags;
  1000. // Update rest of the fields
  1001. pvfd->pvfx->nSamplesPerSec = g_aiFps[j];
  1002. pvfd->pvfx->wBitsPerSample = pvfd->pvfx->bih.biBitCount;
  1003. #if 0
  1004. if (pvfd->pvfx->bih.biCompression > 256)
  1005. {
  1006. CharUpperBuff((LPTSTR)&pvfd->pvfx->bih.biCompression, sizeof(DWORD));
  1007. pvdd->fccHandler = pvfd->dwFormatTag = pvfd->pvfx->dwFormatTag = pvfd->pvfx->bih.biCompression;
  1008. }
  1009. else
  1010. #endif
  1011. pvfd->pvfx->dwFormatTag = pvfd->dwFormatTag = pvdd->fccHandler;
  1012. pvfd->pvfx->nAvgBytesPerSec = pvfd->pvfx->nMinBytesPerSec = pvfd->pvfx->nMaxBytesPerSec = pvfd->pvfx->nSamplesPerSec * pvfd->pvfx->bih.biSizeImage;
  1013. pvfd->pvfx->nBlockAlign = pvfd->pvfx->bih.biSizeImage;
  1014. // The following fields should probably not be modified...
  1015. pvfd->pvfx->dwRequestMicroSecPerFrame = 1000000L / g_aiFps[j];
  1016. pvfd->pvfx->dwPercentDropForError = 10UL;
  1017. // pvfd->pvfx->dwNumVideoRequested = 2UL;
  1018. pvfd->pvfx->dwNumVideoRequested = g_aiFps[j];
  1019. pvfd->pvfx->dwSupportTSTradeOff = 1UL;
  1020. pvfd->pvfx->bLive = TRUE;
  1021. pvfd->pvfx->dwFormatSize = sizeof(VIDEOFORMATEX);
  1022. // Copy the palette if there is one
  1023. if (pvfd->pvfx->wBitsPerSample == 4)
  1024. {
  1025. pvfd->pvfx->bih.biClrUsed = 0;
  1026. if (vic.dwFlags & VICF_4BIT_TABLE) {
  1027. // Copy the 16 color palette
  1028. CopyMemory(&pvfd->pvfx->bihSLOP[0], &vic.bmi4bitColors[0], NUM_4BIT_ENTRIES * sizeof(RGBQUAD));
  1029. pvfd->pvfx->bih.biClrUsed = 16;
  1030. }
  1031. }
  1032. else if (pvfd->pvfx->wBitsPerSample == 8)
  1033. {
  1034. pvfd->pvfx->bih.biClrUsed = 0;
  1035. if (vic.dwFlags & VICF_8BIT_TABLE) {
  1036. // Copy the 256 color palette
  1037. CopyMemory(&pvfd->pvfx->bihSLOP[0], &vic.bmi8bitColors[0], NUM_8BIT_ENTRIES * sizeof(RGBQUAD));
  1038. pvfd->pvfx->bih.biClrUsed = 256;
  1039. }
  1040. }
  1041. if (pvdd->fccHandler > 256)
  1042. wsprintf(szBuffer, IDS_FORMAT_1, (LPSTR)&pvdd->fccType, (LPSTR)&pvdd->fccHandler,
  1043. pvfd->pvfx->bih.biBitCount, pvfd->pvfx->nSamplesPerSec,
  1044. pvfd->pvfx->bih.biWidth, pvfd->pvfx->bih.biHeight);
  1045. else
  1046. wsprintf(szBuffer, IDS_FORMAT_2, (LPSTR)&pvdd->fccType, pvdd->fccHandler,
  1047. pvfd->pvfx->bih.biBitCount, pvfd->pvfx->nSamplesPerSec,
  1048. pvfd->pvfx->bih.biWidth, pvfd->pvfx->bih.biHeight);
  1049. iLen = MultiByteToWideChar(GetACP(), 0, szBuffer, -1, pvfd->szFormat, 0);
  1050. MultiByteToWideChar(GetACP(), 0, szBuffer, -1, pvfd->szFormat, iLen);
  1051. if (!((* fnCallback)((HVCMDRIVERID)hIC, pvdd, pvfd, dwInstance)))
  1052. break;
  1053. }
  1054. }
  1055. }
  1056. }
  1057. }
  1058. // Free table of capabilities
  1059. if (pdvDejaVu)
  1060. MemFree((HANDLE)pdvDejaVu);
  1061. return ((MMRESULT)MMSYSERR_NOERROR);
  1062. }
  1063. /****************************************************************************
  1064. * @doc EXTERNAL COMPFUNC
  1065. *
  1066. * @func MMRESULT | vcmFormatSuggest | This function asks the Video Compression Manager
  1067. * (VCM) or a specified VCM driver to suggest a destination format for
  1068. * the supplied source format, or the recommended source format for a supplied destination
  1069. * format. For example, an application can use this function to determine one or more
  1070. * valid RGB formats to which a compressed format can be decompressed.
  1071. *
  1072. * @parm UINT | uDevice | Identifies the capture device ID.
  1073. *
  1074. * @parm HVCMDRIVER | hvd | Identifies an optional open instance of a
  1075. * driver to query for a suggested destination format. If this
  1076. * argument is NULL, the VCM attempts to find the best driver to suggest
  1077. * a destination format or a source format.
  1078. *
  1079. * @parm PVIDEOFORMATEX | pvfxSrc | Specifies a pointer to a <t VIDEOFORMATEX>
  1080. * structure that identifies the source format to suggest a destination
  1081. * format to be used for a conversion, or that will receive the suggested
  1082. * source format for the <p pvfxDst> format. Note
  1083. * that based on the <p fdwSuggest> argument, some members of the structure
  1084. * pointed to by <p pvfxSrc> may require initialization.
  1085. *
  1086. * @parm PVIDEOFORMATEX | pvfxDst | Specifies a pointer to a <t VIDEOFORMATEX>
  1087. * data structure that will receive the suggested destination format
  1088. * for the <p pvfxSrc> format, or that identifies the destination format to
  1089. * suggest a recommended source format to be used for a conversion. Note
  1090. * that based on the <p fdwSuggest> argument, some members of the structure
  1091. * pointed to by <p pvfxDst> may require initialization.
  1092. *
  1093. * @parm DWORD | cbvfxDst | Specifies the size in bytes available for
  1094. * the destination, or the source format. The <f vcmMetrics>
  1095. * functions can be used to determine the maximum size required for any
  1096. * format available for the specified driver (or for all installed VCM
  1097. * drivers).
  1098. *
  1099. * @parm DWORD | fdwSuggest | Specifies flags for matching the desired
  1100. * destination format, or source format.
  1101. *
  1102. * @flag VCM_FORMATSUGGESTF_DST_WFORMATTAG | Specifies that the
  1103. * <e VIDEOFORMATEX.dwFormatTag> member of the <p pvfxDst> structure is
  1104. * valid. The VCM will query acceptable installed drivers that can
  1105. * use the <p pvfxSrc> structure as their source format and output a
  1106. * destination format matching the <e VIDEOFORMATEX.dwFormatTag>
  1107. * member, or fail. The <p pvfxDst> structure is updated with the complete
  1108. * destination format.
  1109. *
  1110. * @flag VCM_FORMATSUGGESTF_DST_NSAMPLESPERSEC | Specifies that the
  1111. * <e VIDEOFORMATEX.nSamplesPerSec> member of the <p pvfxDst> structure
  1112. * is valid. The VCM will query acceptable installed drivers that can
  1113. * use the <p pvfxSrc> structure as their source format and output a
  1114. * destination format matching the <e VIDEOFORMATEX.nSamplesPerSec>
  1115. * member, or fail. The <p pvfxDst> structure is updated with the complete
  1116. * destination format.
  1117. *
  1118. * @flag VCM_FORMATSUGGESTF_DST_WBITSPERSAMPLE | Specifies that the
  1119. * <e VIDEOFORMATEX.wBitsPerSample> member of the <p pvfxDst> structure
  1120. * is valid. The VCM will query acceptable installed drivers that can
  1121. * use the <p pvfxSrc> structure as their source format and output a
  1122. * destination format matching the <e VIDEOFORMATEX.wBitsPerSample>
  1123. * member, or fail. The <p pvfxDst> structure is updated with the complete
  1124. * destination format.
  1125. *
  1126. * @flag VCM_FORMATSUGGESTF_SRC_WFORMATTAG | Specifies that the
  1127. * <e VIDEOFORMATEX.dwFormatTag> member of the <p pvfxSrc> structure is
  1128. * valid. The VCM will query acceptable installed drivers that can
  1129. * use the <p pvfxDst> structure as their destination format and accept a
  1130. * source format matching the <e VIDEOFORMATEX.dwFormatTag>
  1131. * member, or fail. The <p pvfxSrc> structure is updated with the complete
  1132. * source format.
  1133. *
  1134. * @flag VCM_FORMATSUGGESTF_SRC_NSAMPLESPERSEC | Specifies that the
  1135. * <e VIDEOFORMATEX.nSamplesPerSec> member of the <p pvfxSrc> structure
  1136. * is valid. The VCM will query acceptable installed drivers that can
  1137. * use the <p pvfxDst> structure as their destination format and accept a
  1138. * source format matching the <e VIDEOFORMATEX.nSamplesPerSec>
  1139. * member or fail. The <p pvfxSrc> structure is updated with the complete
  1140. * source format.
  1141. *
  1142. * @flag VCM_FORMATSUGGESTF_SRC_WBITSPERSAMPLE | Specifies that the
  1143. * <e VIDEOFORMATEX.wBitsPerSample> member of the <p pvfxSrc> structure
  1144. * is valid. The VCM will query acceptable installed drivers that can
  1145. * use the <p pvfxDst> structure as their destination format and accept a
  1146. * source format matching the <e VIDEOFORMATEX.wBitsPerSample>
  1147. * member, or fail. The <p pvfxSrc> structure is updated with the complete
  1148. * source format.
  1149. *
  1150. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1151. * a non-zero error number. Possible error returns are:
  1152. *
  1153. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  1154. *
  1155. * @flag MMSYSERR_INVALFLAG | One or more flags are invalid.
  1156. *
  1157. * @flag MMSYSERR_INVALPARAM | One or more arguments passed are invalid.
  1158. *
  1159. * @flag MMSYSERR_NOTSUPPORTED | One or more of the restriction bits is not supported.
  1160. *
  1161. * @flag MMSYSERR_NODRIVER | No capture device driver or device is present.
  1162. *
  1163. * @devnote PhilF: For now, only the VCM_FORMATSUGGESTF_DST_WFORMATTAG and VCM_FORMATSUGGESTF_SRC_WFORMATTAG
  1164. * are supported. The other flags are just ignored. Add real support for other flags
  1165. * if they would really make a difference. But for the two current Data Pump calls,
  1166. * they don't influence the outcome of the call.
  1167. *
  1168. * The cbvfxDst is never used. Should we still pass it? How can I make a good use of it?
  1169. *
  1170. * Should there also be cbvfxSrc parameter?
  1171. *
  1172. * This function is used to determine what should the (source) capture format of the capture
  1173. * device be in order to generate a specific compressed destination format.
  1174. * Now, there are two possibilities. Either we can directly capture at a frame size
  1175. * identical to the one in the <p pvfxDst> structure, or we can't, but still, once compressed
  1176. * the output frame has the same size than the one in the <p pvfxDst> structure.
  1177. * Typical example: Greyscale QuickCam. If the output format were set to 128x96 (SQCIF)
  1178. * and we were to try capturing directly at this size, this would fail, since 128x96
  1179. * is not supported by the hardware. On the other hand, if we capture at 160x120,
  1180. * the codec will truncate to 128x96. Now, how can we figure this out programmatically?
  1181. * For now, the next largest size is ASSUMED to be truncatable by the codec to the right size.
  1182. * This needs to be actually run through the codec for validation. Fix that.
  1183. *
  1184. * If the capture driver capture with a format that is not RGB, this call will fail to suggest
  1185. * a valid source format and will return MMSYSERR_NODRIVER. Fix that.
  1186. *
  1187. * @xref <f vcmMetrics> <f vcmFormatEnum>
  1188. ***************************************************************************/
  1189. MMRESULT VCMAPI vcmFormatSuggest(UINT uDevice, HVCMDRIVER hvd, PVIDEOFORMATEX pvfxSrc, PVIDEOFORMATEX pvfxDst, DWORD cbvfxDst, DWORD fdwSuggest)
  1190. {
  1191. DWORD dwSize;
  1192. MMRESULT mmr;
  1193. WORD wFlags;
  1194. HIC hIC;
  1195. DWORD fdwSuggestL;
  1196. DWORD dwFormatTag;
  1197. VIDEOINCAPS vic;
  1198. int i, delta, best, tmp;
  1199. #define VCM_FORMAT_SUGGEST_SUPPORT VCM_FORMATSUGGESTF_TYPEMASK
  1200. // Check input params
  1201. if (!pvfxSrc)
  1202. {
  1203. ERRORMESSAGE(("vcmFormatSuggest: Specified pointer is invalid, pvfxSrc=NULL\r\n"));
  1204. return ((MMRESULT)MMSYSERR_INVALPARAM);
  1205. }
  1206. if (!pvfxDst)
  1207. {
  1208. ERRORMESSAGE(("vcmFormatSuggest: Specified pointer is invalid, pvfxSrc=NULL\r\n"));
  1209. return ((MMRESULT)MMSYSERR_INVALPARAM);
  1210. }
  1211. if ((uDevice >= MAXVIDEODRIVERS) && (uDevice != VIDEO_MAPPER))
  1212. {
  1213. ERRORMESSAGE(("vcmFormatSuggest: Specified capture device ID is invalid, uDevice=%ld (expected values are 0x%lX or between 0 and %ld)\r\n", uDevice, VIDEO_MAPPER, MAXVIDEODRIVERS-1));
  1214. return ((MMRESULT)MMSYSERR_BADDEVICEID);
  1215. }
  1216. // Grab the suggestion restriction bits and verify that we support
  1217. // the ones that are specified
  1218. fdwSuggestL = (VCM_FORMATSUGGESTF_TYPEMASK & fdwSuggest);
  1219. if (~VCM_FORMAT_SUGGEST_SUPPORT & fdwSuggestL)
  1220. {
  1221. ERRORMESSAGE(("vcmFormatSuggest: Specified mask is invalid, fdwSuggest=0x%lX\r\n", fdwSuggest));
  1222. return ((MMRESULT)MMSYSERR_NOTSUPPORTED);
  1223. }
  1224. // Get the size of the largest bitmap info header
  1225. if (((mmr = vcmMetrics((HVCMOBJ)NULL, VCM_METRIC_MAX_SIZE_BITMAPINFOHEADER, &dwSize)) == MMSYSERR_NOERROR) && (dwSize >= sizeof(BITMAPINFOHEADER)))
  1226. {
  1227. if (fdwSuggest & VCM_FORMATSUGGESTF_DST_WFORMATTAG)
  1228. {
  1229. if (pvfxSrc->bih.biCompression == BI_RGB)
  1230. {
  1231. if (pvfxDst->bih.biCompression == BI_RGB)
  1232. {
  1233. // Input and output format are uncompressed
  1234. CopyMemory(pvfxDst, pvfxSrc, pvfxSrc->dwFormatSize);
  1235. return ((MMRESULT)MMSYSERR_NOERROR);
  1236. }
  1237. else
  1238. {
  1239. wFlags = ICMODE_COMPRESS;
  1240. dwFormatTag = pvfxDst->dwFormatTag;
  1241. }
  1242. }
  1243. else
  1244. {
  1245. wFlags = ICMODE_DECOMPRESS;
  1246. dwFormatTag = pvfxSrc->dwFormatTag;
  1247. }
  1248. #ifndef _ALPHA_
  1249. #ifdef USE_BILINEAR_MSH26X
  1250. if ((dwFormatTag == VIDEO_FORMAT_MSH263) || (dwFormatTag == VIDEO_FORMAT_MSH261) || (dwFormatTag == VIDEO_FORMAT_MSH26X))
  1251. #else
  1252. if ((dwFormatTag == VIDEO_FORMAT_MSH263) || (dwFormatTag == VIDEO_FORMAT_MSH261))
  1253. #endif
  1254. #else
  1255. if ((dwFormatTag == VIDEO_FORMAT_DECH263) || (dwFormatTag == VIDEO_FORMAT_DECH261))
  1256. #endif
  1257. {
  1258. hIC = ICOpen(VCMDRIVERDETAILS_FCCTYPE_VIDEOCODEC, dwFormatTag, wFlags);
  1259. if (hIC && (wFlags == ICMODE_COMPRESS))
  1260. ICSendMessage(hIC, CUSTOM_ENABLE_CODEC, G723MAGICWORD1, G723MAGICWORD2);
  1261. }
  1262. else
  1263. hIC = ICLocate(VCMDRIVERDETAILS_FCCTYPE_VIDEOCODEC, dwFormatTag, (LPBITMAPINFOHEADER)&pvfxSrc->bih, (LPBITMAPINFOHEADER)NULL, wFlags);
  1264. if (hIC)
  1265. {
  1266. if (wFlags == ICMODE_COMPRESS)
  1267. {
  1268. // Now get the size required to hold the format
  1269. dwSize = ICCompressGetFormatSize(hIC, &pvfxSrc->bih);
  1270. if ((dwSize >= sizeof(BITMAPINFOHEADER)) && (dwSize <= cbvfxDst))
  1271. {
  1272. if (ICCompressGetFormat(hIC, &pvfxSrc->bih, &pvfxDst->bih) == ICERR_OK)
  1273. {
  1274. pvfxDst->nSamplesPerSec = pvfxSrc->nSamplesPerSec;
  1275. pvfxDst->wBitsPerSample = pvfxDst->bih.biBitCount;
  1276. pvfxDst->dwFormatTag = pvfxDst->bih.biCompression;
  1277. pvfxDst->nAvgBytesPerSec = pvfxDst->nMinBytesPerSec = pvfxDst->nMaxBytesPerSec = pvfxDst->nSamplesPerSec * pvfxDst->bih.biSizeImage;
  1278. pvfxDst->nBlockAlign = pvfxDst->bih.biSizeImage;
  1279. // The following fields should probably not be modified...
  1280. pvfxDst->dwRequestMicroSecPerFrame = pvfxSrc->dwRequestMicroSecPerFrame;
  1281. pvfxDst->dwPercentDropForError = pvfxSrc->dwPercentDropForError;
  1282. pvfxDst->dwNumVideoRequested = pvfxSrc->dwNumVideoRequested;
  1283. pvfxDst->dwSupportTSTradeOff = pvfxSrc->dwSupportTSTradeOff;
  1284. pvfxDst->bLive = pvfxSrc->bLive;
  1285. pvfxDst->dwFormatSize = sizeof(VIDEOFORMATEX);
  1286. }
  1287. }
  1288. }
  1289. else
  1290. {
  1291. // Now get the size required to hold the format
  1292. dwSize = ICDecompressGetFormatSize(hIC, &pvfxSrc->bih);
  1293. if ((dwSize >= sizeof(BITMAPINFOHEADER)) && (dwSize <= cbvfxDst))
  1294. {
  1295. if (ICDecompressGetFormat(hIC, &pvfxSrc->bih, &pvfxDst->bih) == ICERR_OK)
  1296. {
  1297. pvfxDst->nSamplesPerSec = pvfxSrc->nSamplesPerSec;
  1298. pvfxDst->wBitsPerSample = pvfxDst->bih.biBitCount;
  1299. pvfxDst->dwFormatTag = pvfxDst->bih.biCompression;
  1300. pvfxDst->nAvgBytesPerSec = pvfxDst->nMinBytesPerSec = pvfxDst->nMaxBytesPerSec = pvfxDst->nSamplesPerSec * pvfxDst->bih.biSizeImage;
  1301. pvfxDst->nBlockAlign = pvfxDst->bih.biSizeImage;
  1302. pvfxDst->dwRequestMicroSecPerFrame = pvfxSrc->dwRequestMicroSecPerFrame;
  1303. // The following fields should probably not be modified...
  1304. pvfxDst->dwRequestMicroSecPerFrame = pvfxSrc->dwRequestMicroSecPerFrame;
  1305. pvfxDst->dwPercentDropForError = pvfxSrc->dwPercentDropForError;
  1306. pvfxDst->dwNumVideoRequested = pvfxSrc->dwNumVideoRequested;
  1307. pvfxDst->dwSupportTSTradeOff = pvfxSrc->dwSupportTSTradeOff;
  1308. pvfxDst->bLive = pvfxSrc->bLive;
  1309. pvfxDst->dwFormatSize = sizeof(VIDEOFORMATEX);
  1310. }
  1311. }
  1312. }
  1313. ICClose(hIC);
  1314. }
  1315. }
  1316. else if (fdwSuggest & VCM_FORMATSUGGESTF_SRC_WFORMATTAG)
  1317. {
  1318. // In case only the format tag was initialized, copy it to the biCompression field
  1319. pvfxSrc->bih.biCompression = pvfxSrc->dwFormatTag;
  1320. if (pvfxSrc->bih.biCompression == BI_RGB)
  1321. {
  1322. if (pvfxDst->bih.biCompression == BI_RGB)
  1323. {
  1324. // Input and output format are uncompressed
  1325. CopyMemory(pvfxSrc, pvfxDst, pvfxDst->dwFormatSize);
  1326. return ((MMRESULT)MMSYSERR_NOERROR);
  1327. }
  1328. else
  1329. {
  1330. wFlags = ICMODE_COMPRESS;
  1331. dwFormatTag = pvfxDst->dwFormatTag;
  1332. }
  1333. }
  1334. else
  1335. {
  1336. if (pvfxDst->bih.biCompression == BI_RGB)
  1337. {
  1338. wFlags = ICMODE_DECOMPRESS;
  1339. dwFormatTag = pvfxSrc->dwFormatTag;
  1340. }
  1341. else
  1342. {
  1343. wFlags = ICMODE_COMPRESS;
  1344. dwFormatTag = pvfxDst->dwFormatTag;
  1345. }
  1346. }
  1347. if (wFlags == ICMODE_COMPRESS)
  1348. {
  1349. // Now, there are two possibilities. Either we can directly capture at a frame size
  1350. // identical to the one in the pvfxDst structure, or we can't, but once compressed
  1351. // the output frame has the same size than the one in the pvfxDst structure.
  1352. // Typical example, Greyscale QuickCam. If the output format were set to 128x96 (SQCIF)
  1353. // and we were to try capturing directly at this size, this would fail, since 128x96
  1354. // is not supported by the hardware. On the other hand, if we capture at 160x120,
  1355. // the codec will truncate to 128x96. Now, how can we figure this out programmatically?
  1356. // The color and greyscale capability field will let us know what bit depth to use.
  1357. // We should probably have a field that also says which bit depth is preferred in the
  1358. // case more than one are supported. For now, assume the priority order is: 16, 24, 4, 8
  1359. if ((mmr = vcmGetDevCaps(uDevice, &vic, sizeof(VIDEOINCAPS))) != MMSYSERR_NOERROR)
  1360. return (mmr);
  1361. if (vic.dwImageSize & VIDEO_FORMAT_IMAGE_SIZE_USE_DEFAULT) {
  1362. ERRORMESSAGE(("vcmFormatSuggest: suggest using default\r\n"));
  1363. return ((MMRESULT)MMSYSERR_NOTSUPPORTED);
  1364. }
  1365. CopyMemory(&pvfxSrc->bih, &pvfxDst->bih, sizeof(BITMAPINFOHEADER));
  1366. // Assume the next resolution will be correctly truncated to the output size
  1367. best = -1;
  1368. delta = 999999;
  1369. for (i=0; i<VIDEO_FORMAT_NUM_RESOLUTIONS; i++) {
  1370. if (g_awResolutions[i].dwRes & vic.dwImageSize) {
  1371. tmp = g_awResolutions[i].framesize.biWidth - pvfxDst->bih.biWidth;
  1372. if (tmp < 0) tmp = -tmp;
  1373. if (tmp < delta) {
  1374. delta = tmp;
  1375. best = i;
  1376. }
  1377. tmp = g_awResolutions[i].framesize.biHeight - pvfxDst->bih.biHeight;
  1378. if (tmp < 0) tmp = -tmp;
  1379. if (tmp < delta) {
  1380. delta = tmp;
  1381. best = i;
  1382. }
  1383. }
  1384. }
  1385. if (best < 0) {
  1386. ERRORMESSAGE(("vcmFormatSuggest: no available formats\r\n"));
  1387. return ((MMRESULT)MMSYSERR_NOTSUPPORTED);
  1388. }
  1389. // Actually, you don't have to assume it will work. You can directly ask the codec
  1390. // is this would work...
  1391. pvfxSrc->bih.biWidth = g_awResolutions[best].framesize.biWidth;
  1392. pvfxSrc->bih.biHeight = g_awResolutions[best].framesize.biHeight;
  1393. // Now, we assume that the captured format is an RGB format. Once in place, you should
  1394. // verify this from the capability set of the capture device.
  1395. if (pvfxSrc->bih.biSize != sizeof(BITMAPINFOHEADER))
  1396. pvfxSrc->bih.biSize = sizeof(BITMAPINFOHEADER);
  1397. // If the capture hardware does not support RGB, we need to use its compressed format
  1398. for (i=0; i<NUM_BITDEPTH_ENTRIES; i++)
  1399. {
  1400. if (vic.dwNumColors & g_aiNumColors[i])
  1401. {
  1402. pvfxSrc->bih.biBitCount = (WORD)g_aiBitDepth[i];
  1403. pvfxSrc->bih.biCompression = g_aiFourCCCode[i];
  1404. break;
  1405. }
  1406. }
  1407. // Copy the palette if there is one
  1408. if (pvfxSrc->bih.biBitCount == 4)
  1409. {
  1410. pvfxSrc->bih.biClrUsed = 0;
  1411. if (vic.dwFlags & VICF_4BIT_TABLE) {
  1412. // Copy the 16 color palette
  1413. CopyMemory(&pvfxSrc->bihSLOP[0], &vic.bmi4bitColors[0], NUM_4BIT_ENTRIES * sizeof(RGBQUAD));
  1414. pvfxSrc->bih.biClrUsed = 16;
  1415. }
  1416. }
  1417. else if (pvfxSrc->bih.biBitCount == 8)
  1418. {
  1419. pvfxSrc->bih.biClrUsed = 0;
  1420. if (vic.dwFlags & VICF_8BIT_TABLE) {
  1421. // Copy the 256 color palette
  1422. CopyMemory(&pvfxSrc->bihSLOP[0], &vic.bmi8bitColors[0], NUM_8BIT_ENTRIES * sizeof(RGBQUAD));
  1423. pvfxSrc->bih.biClrUsed = 256;
  1424. }
  1425. }
  1426. pvfxSrc->bih.biSizeImage = WIDTHBYTES(pvfxSrc->bih.biWidth * pvfxSrc->bih.biBitCount) * pvfxSrc->bih.biHeight;
  1427. }
  1428. else
  1429. {
  1430. #ifndef _ALPHA_
  1431. #ifdef USE_BILINEAR_MSH26X
  1432. if ((dwFormatTag == VIDEO_FORMAT_MSH263) || (dwFormatTag == VIDEO_FORMAT_MSH261) || (dwFormatTag == VIDEO_FORMAT_MSH26X))
  1433. #else
  1434. if ((dwFormatTag == VIDEO_FORMAT_MSH263) || (dwFormatTag == VIDEO_FORMAT_MSH261))
  1435. #endif
  1436. #else
  1437. if ((dwFormatTag == VIDEO_FORMAT_DECH263) || (dwFormatTag == VIDEO_FORMAT_DECH261))
  1438. #endif
  1439. hIC = ICOpen(VCMDRIVERDETAILS_FCCTYPE_VIDEOCODEC, dwFormatTag, wFlags);
  1440. else
  1441. hIC = ICLocate(VCMDRIVERDETAILS_FCCTYPE_VIDEOCODEC, dwFormatTag, (LPBITMAPINFOHEADER)&pvfxSrc->bih, (LPBITMAPINFOHEADER)NULL, wFlags);
  1442. if (hIC)
  1443. {
  1444. // Now get the size required to hold the format
  1445. dwSize = ICDecompressGetFormatSize(hIC, &pvfxSrc->bih);
  1446. if ((dwSize >= sizeof(BITMAPINFOHEADER)) && (dwSize <= cbvfxDst))
  1447. {
  1448. if (ICDecompressGetFormat(hIC, &pvfxSrc->bih, &pvfxDst->bih) == ICERR_OK)
  1449. {
  1450. pvfxSrc->nSamplesPerSec = pvfxSrc->nSamplesPerSec;
  1451. pvfxSrc->wBitsPerSample = pvfxDst->bih.biBitCount;
  1452. pvfxSrc->dwFormatTag = pvfxDst->bih.biCompression;
  1453. pvfxDst->nAvgBytesPerSec = pvfxDst->nMinBytesPerSec = pvfxDst->nMaxBytesPerSec = pvfxDst->nSamplesPerSec * pvfxDst->bih.biSizeImage;
  1454. pvfxDst->nBlockAlign = pvfxDst->bih.biSizeImage;
  1455. pvfxDst->dwRequestMicroSecPerFrame = pvfxSrc->dwRequestMicroSecPerFrame;
  1456. // The following fields should probably not be modified...
  1457. pvfxDst->dwRequestMicroSecPerFrame = pvfxSrc->dwRequestMicroSecPerFrame;
  1458. pvfxDst->dwPercentDropForError = pvfxSrc->dwPercentDropForError;
  1459. pvfxDst->dwNumVideoRequested = pvfxSrc->dwNumVideoRequested;
  1460. pvfxDst->dwSupportTSTradeOff = pvfxSrc->dwSupportTSTradeOff;
  1461. pvfxDst->bLive = pvfxSrc->bLive;
  1462. pvfxDst->dwFormatSize = sizeof(VIDEOFORMATEX);
  1463. }
  1464. }
  1465. ICClose(hIC);
  1466. }
  1467. }
  1468. }
  1469. }
  1470. return (mmr);
  1471. }
  1472. /****************************************************************************
  1473. * @doc EXTERNAL COMPFUNC
  1474. *
  1475. * @func MMRESULT | vcmStreamOpen | The vcmStreamOpen function opens a Video Compression
  1476. * Manager (VCM) conversion stream. Conversion streams are used to convert data from
  1477. * one specified video format to another.
  1478. *
  1479. * @parm PHVCMSTREAM | phvs | Specifies a pointer to a <t HVCMSTREAM>
  1480. * handle that will receive the new stream handle that can be used to
  1481. * perform conversions. Use this handle to identify the stream
  1482. * when calling other VCM stream conversion functions. This parameter
  1483. * should be NULL if the VCM_STREAMOPENF_QUERY flag is specified.
  1484. *
  1485. * @parm HVCMDRIVER | hvd | Specifies an optional handle to a VCM driver.
  1486. * If specified, this handle identifies a specific driver to be used
  1487. * for a conversion stream. If this argument is NULL, then all suitable
  1488. * installed VCM drivers are queried until a match is found.
  1489. *
  1490. * @parm PVIDEOFORMATEX | pvfxSrc | Specifies a pointer to a <t VIDEOFORMATEX>
  1491. * structure that identifies the desired source format for the
  1492. * conversion.
  1493. *
  1494. * @parm PVIDEOFORMATEX | pvfxDst | Specifies a pointer to a <t VIDEOFORMATEX>
  1495. * structure that identifies the desired destination format for the
  1496. * conversion.
  1497. *
  1498. * @parm DWORD | dwImageQuality | Specifies an image quality value (between 0
  1499. * and 31. The lower number indicates a high spatial quality at a low frame
  1500. * rate, the larger number indiocates a low spatial quality at a high frame
  1501. * rate.
  1502. *
  1503. * @parm DWORD | dwCallback | Specifies the address of a callback function
  1504. * or a handle to a window called after each buffer is converted. A
  1505. * callback will only be called if the conversion stream is opened with
  1506. * the VCM_STREAMOPENF_ASYNC flag. If the conversion stream is opened
  1507. * without the CCM_STREAMOPENF_ASYNC flag, then this parameter should
  1508. * be set to zero.
  1509. *
  1510. * @parm DWORD | dwInstance | Specifies user-instance data passed on to the
  1511. * callback specified by <p dwCallback>. This argument is not used with
  1512. * window callbacks. If the conversion stream is opened without the
  1513. * VCM_STREAMOPENF_ASYNC flag, then this parameter should be set to zero.
  1514. *
  1515. * @parm DWORD | fdwOpen | Specifies flags for opening the conversion stream.
  1516. *
  1517. * @flag VCM_STREAMOPENF_QUERY | Specifies that the VCM will be queried
  1518. * to determine whether it supports the given conversion. A conversion
  1519. * stream will not be opened and no <t HVCMSTREAM> handle will be
  1520. * returned.
  1521. *
  1522. * @flag VCM_STREAMOPENF_NONREALTIME | Specifies that the VCM will not
  1523. * consider time constraints when converting the data. By default, the
  1524. * driver will attempt to convert the data in real time. Note that for
  1525. * some formats, specifying this flag might improve the video quality
  1526. * or other characteristics.
  1527. *
  1528. * @flag VCM_STREAMOPENF_ASYNC | Specifies that conversion of the stream should
  1529. * be performed asynchronously. If this flag is specified, the application
  1530. * can use a callback to be notified on open and close of the conversion
  1531. * stream, and after each buffer is converted. In addition to using a
  1532. * callback, an application can examine the <e VCMSTREAMHEADER.fdwStatus>
  1533. * of the <t VCMSTREAMHEADER> structure for the VCMSTREAMHEADER_STATUSF_DONE
  1534. * flag.
  1535. *
  1536. * @flag CALLBACK_WINDOW | Specifies that <p dwCallback> is assumed to
  1537. * be a window handle.
  1538. *
  1539. * @flag CALLBACK_FUNCTION | Specifies that <p dwCallback> is assumed to
  1540. * be a callback procedure address. The function prototype must conform
  1541. * to the <f vcmStreamConvertCallback> convention.
  1542. *
  1543. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1544. * a non-zero error number. Possible error returns are:
  1545. *
  1546. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  1547. *
  1548. * @flag MMSYSERR_INVALFLAG | One or more flags are invalid.
  1549. *
  1550. * @flag MMSYSERR_INVALPARAM | One or more arguments passed are invalid.
  1551. *
  1552. * @flag MMSYSERR_NOMEM | Unable to allocate resources.
  1553. *
  1554. * @flag VCMERR_NOTPOSSIBLE | The requested operation cannot be performed.
  1555. *
  1556. * @comm Note that if a VCM driver cannot perform real-time conversions,
  1557. * and the VCM_STREAMOPENF_NONREALTIME flag is not specified for
  1558. * the <p fdwOpen> argument, the open will fail returning an
  1559. * VCMERR_NOTPOSSIBLE error code. An application can use the
  1560. * VCM_STREAMOPENF_QUERY flag to determine if real-time conversions
  1561. * are supported for the input arguments.
  1562. *
  1563. * If a window is chosen to receive callback information, the
  1564. * following messages are sent to the window procedure function to
  1565. * indicate the progress of the conversion stream: <m MM_VCM_OPEN>,
  1566. * <m MM_VCM_CLOSE>, and <m MM_VCM_DONE>. The <p wParam> parameter identifies
  1567. * the <t HVCMSTREAM> handle. The <p lParam> parameter identifies the
  1568. * <t VCMSTREAMHEADER> structure for <m MM_VCM_DONE>, but is not used
  1569. * for <m MM_VCM_OPEN> and <m MM_VCM_CLOSE>.
  1570. *
  1571. * If a function is chosen to receive callback information, the
  1572. * following messages are sent to the function to indicate the progress
  1573. * of output: <m MM_VCM_OPEN>, <m MM_VCM_CLOSE>, and
  1574. * <m MM_VCM_DONE>. The callback function must reside in a DLL. You do
  1575. * not need to use <f MakeProcInstance> to get a procedure-instance
  1576. * address for the callback function.
  1577. *
  1578. * @xref <f vcmStreamClose> <f vcmStreamConvert>
  1579. * <f vcmFormatSuggest> <f vcmStreamConvertCallback>
  1580. ***************************************************************************/
  1581. MMRESULT VCMAPI vcmStreamOpen(PHVCMSTREAM phvs, HVCMDRIVER hvd, PVIDEOFORMATEX pvfxSrc, PVIDEOFORMATEX pvfxDst, DWORD dwImageQuality, DWORD dwPacketSize, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
  1582. {
  1583. MMRESULT mmr;
  1584. DWORD dwFlags;
  1585. DWORD fccHandler;
  1586. HIC hIC;
  1587. VIDEOFORMATEX *pvfxS;
  1588. VIDEOFORMATEX *pvfxD;
  1589. BITMAPINFOHEADER *pbmiPrev; // Pointer to reconstructed frame bitmap info header (for now assume it is the same than the input format...)
  1590. ICINFO icInfo;
  1591. PVOID pvState; // Pointer to codec configuration information
  1592. DWORD dw; // Size of codec configuration information or destination BITAMPINFO
  1593. ICCOMPRESSFRAMES iccf = {0}; // Structure used to set compression parameters
  1594. PMSH26XCOMPINSTINFO pciMSH26XInfo; // Pointer to MS H26X configuration information
  1595. #ifdef USE_MPEG4_SCRUNCH
  1596. PMPEG4COMPINSTINFO pciMPEG4Info; // Pointer to MPEG4 Scrunch configuration information
  1597. #endif
  1598. // Check input params
  1599. if (!pvfxSrc)
  1600. {
  1601. ERRORMESSAGE(("vcmStreamOpen: Specified pointer is invalid, pvfxSrc=NULL\r\n"));
  1602. return ((MMRESULT)MMSYSERR_INVALPARAM);
  1603. }
  1604. if (!pvfxDst)
  1605. {
  1606. ERRORMESSAGE(("vcmStreamOpen: Specified pointer is invalid, pvfxSrc=NULL\r\n"));
  1607. return ((MMRESULT)MMSYSERR_INVALPARAM);
  1608. }
  1609. if (!pvfxSrc->dwFormatSize)
  1610. {
  1611. ERRORMESSAGE(("vcmStreamOpen: Specified format size is invalid, pvfxSrc->dwFormatSize=%ld\r\n", pvfxSrc->dwFormatSize));
  1612. return ((MMRESULT)MMSYSERR_INVALPARAM);
  1613. }
  1614. if (!pvfxDst->dwFormatSize)
  1615. {
  1616. ERRORMESSAGE(("vcmStreamOpen: Specified format size is invalid, pvfxDst->dwFormatSize=%ld\r\n", pvfxDst->dwFormatSize));
  1617. return ((MMRESULT)MMSYSERR_INVALPARAM);
  1618. }
  1619. if ((dwImageQuality < VCM_MIN_IMAGE_QUALITY) || (dwImageQuality > VCM_MAX_IMAGE_QUALITY))
  1620. dwImageQuality = VCM_DEFAULT_IMAGE_QUALITY;
  1621. // Set default values
  1622. *phvs = (HVCMSTREAM)NULL;
  1623. // Are we compressing of decompressing?
  1624. if (pvfxSrc->bih.biCompression == BI_RGB)
  1625. {
  1626. dwFlags = ICMODE_COMPRESS;
  1627. fccHandler = (DWORD)pvfxDst->bih.biCompression;
  1628. }
  1629. else
  1630. {
  1631. if (pvfxDst->bih.biCompression == BI_RGB)
  1632. {
  1633. dwFlags = ICMODE_DECOMPRESS;
  1634. fccHandler = (DWORD)pvfxSrc->bih.biCompression;
  1635. }
  1636. else
  1637. {
  1638. dwFlags = ICMODE_COMPRESS;
  1639. fccHandler = (DWORD)pvfxDst->bih.biCompression;
  1640. }
  1641. }
  1642. // Get a handle to the compressor/decompressor
  1643. #ifndef _ALPHA_
  1644. #ifdef USE_BILINEAR_MSH26X
  1645. if ((fccHandler == VIDEO_FORMAT_MSH263) || (fccHandler == VIDEO_FORMAT_MSH261) || (fccHandler == VIDEO_FORMAT_MSH26X))
  1646. #else
  1647. if ((fccHandler == VIDEO_FORMAT_MSH263) || (fccHandler == VIDEO_FORMAT_MSH261))
  1648. #endif
  1649. #else
  1650. if ((fccHandler == VIDEO_FORMAT_DECH263) || (fccHandler == VIDEO_FORMAT_DECH261))
  1651. #endif
  1652. {
  1653. hIC = ICOpen(VCMDRIVERDETAILS_FCCTYPE_VIDEOCODEC, fccHandler, (WORD)dwFlags);
  1654. if (hIC && (dwFlags == ICMODE_COMPRESS))
  1655. ICSendMessage(hIC, CUSTOM_ENABLE_CODEC, G723MAGICWORD1, G723MAGICWORD2);
  1656. }
  1657. else
  1658. hIC = ICLocate(VCMDRIVERDETAILS_FCCTYPE_VIDEOCODEC, fccHandler, (LPBITMAPINFOHEADER)&pvfxSrc->bih, (LPBITMAPINFOHEADER)&pvfxDst->bih, (WORD)dwFlags);
  1659. if (hIC)
  1660. {
  1661. // Get info about this compressor
  1662. ICGetInfo(hIC, &icInfo, sizeof(ICINFO));
  1663. // Allocate VCM stream structure
  1664. if (!(*phvs = (HVCMSTREAM)MemAlloc(sizeof(VCMSTREAM))))
  1665. {
  1666. ERRORMESSAGE(("vcmStreamOpen: Memory allocation of a VCM stream structure failed\r\n"));
  1667. mmr = (MMRESULT)MMSYSERR_NOMEM;
  1668. goto MyExit0;
  1669. }
  1670. else
  1671. {
  1672. ((PVCMSTREAM)(*phvs))->hIC = (HVCMDRIVER)hIC;
  1673. ((PVCMSTREAM)(*phvs))->dwICInfoFlags = icInfo.dwFlags;
  1674. ((PVCMSTREAM)(*phvs))->dwQuality = dwImageQuality;
  1675. ((PVCMSTREAM)(*phvs))->dwMaxPacketSize = dwPacketSize;
  1676. ((PVCMSTREAM)(*phvs))->dwFrame = 0L;
  1677. // For now, issue a key frame every 15 seconds
  1678. ((PVCMSTREAM)(*phvs))->dwLastIFrameTime = GetTickCount();
  1679. ((PVCMSTREAM)(*phvs))->fPeriodicIFrames = TRUE;
  1680. ((PVCMSTREAM)(*phvs))->dwCallback = dwCallback;
  1681. ((PVCMSTREAM)(*phvs))->dwCallbackInstance = dwInstance;
  1682. ((PVCMSTREAM)(*phvs))->fdwOpen = fdwOpen;
  1683. ((PVCMSTREAM)(*phvs))->fdwStream = dwFlags;
  1684. ((PVCMSTREAM)(*phvs))->dwLastTimestamp = ULONG_MAX;
  1685. // We need the following crs to make sure we don't miss any of the I-Frame requests
  1686. // emittted by the UI. Problematic scenario: pvs->dwFrame is at 123 for instance.
  1687. // The UI thread requests an I-Frame by setting pvs->dwFrame. If the capture/compression
  1688. // thread was in ICCompress() (which is very probable since it takes quite some time
  1689. // to compress a frame), pvs->dwFrame will be incremented by one when ICCompress()
  1690. // returns. We failed to handle the I-Frame request correctly, since the next time
  1691. // ICCompress() gets called pvs->dwFrame will be equal to 1, for which we do not
  1692. // generate an I-Frame.
  1693. if ((dwFlags == ICMODE_COMPRESS) || (dwFlags == ICMODE_FASTCOMPRESS)) // Hmmm... where could you have set the second mode?
  1694. InitializeCriticalSection(&(((PVCMSTREAM)(*phvs))->crsFrameNumber));
  1695. // Allocate the video formats
  1696. if (!(pvfxS = (VIDEOFORMATEX *)MemAlloc(pvfxSrc->dwFormatSize)))
  1697. {
  1698. ERRORMESSAGE(("vcmStreamOpen: Memory allocation of source video format failed\r\n"));
  1699. mmr = (MMRESULT)MMSYSERR_NOMEM;
  1700. goto MyExit1;
  1701. }
  1702. else
  1703. {
  1704. if (!(pvfxD = (VIDEOFORMATEX *)MemAlloc(pvfxDst->dwFormatSize)))
  1705. {
  1706. ERRORMESSAGE(("vcmStreamOpen: Memory allocation of destination video format failed\r\n"));
  1707. mmr = (MMRESULT)MMSYSERR_NOMEM;
  1708. goto MyExit2;
  1709. }
  1710. else
  1711. { // This is naive. You need to query the codec for its decompressed format size and data
  1712. if (!(pbmiPrev = (BITMAPINFOHEADER *)MemAlloc(sizeof(BITMAPINFOHEADER))))
  1713. {
  1714. ERRORMESSAGE(("vcmStreamOpen: Memory allocation of previous video frame failed\r\n"));
  1715. mmr = (MMRESULT)MMSYSERR_NOMEM;
  1716. goto MyExit3;
  1717. }
  1718. else
  1719. {
  1720. CopyMemory(((PVCMSTREAM)(*phvs))->pvfxSrc = pvfxS, pvfxSrc, pvfxSrc->dwFormatSize);
  1721. CopyMemory(((PVCMSTREAM)(*phvs))->pvfxDst = pvfxD, pvfxDst, pvfxDst->dwFormatSize);
  1722. CopyMemory(((PVCMSTREAM)(*phvs))->pbmiPrev = pbmiPrev, &pvfxSrc->bih, sizeof(BITMAPINFOHEADER));
  1723. }
  1724. }
  1725. }
  1726. if ((dwFlags == ICMODE_COMPRESS) || (dwFlags == ICMODE_FASTCOMPRESS)) // Hmmm... where could you have set the second mode?
  1727. {
  1728. // Get the state of the compressor
  1729. if (dw = ICGetStateSize(hIC))
  1730. {
  1731. if (!(pvState = (PVOID)MemAlloc(dw)))
  1732. {
  1733. ERRORMESSAGE(("vcmStreamOpen: Memory allocation of codec configuration information structure failed\r\n"));
  1734. mmr = (MMRESULT)MMSYSERR_NOMEM;
  1735. goto MyExit4;
  1736. }
  1737. if (((DWORD) ICGetState(hIC, pvState, dw)) != dw)
  1738. {
  1739. ERRORMESSAGE(("vcmStreamOpen: ICGetState() failed\r\n"));
  1740. mmr = (MMRESULT)VCMERR_FAILED;
  1741. goto MyExit5;
  1742. }
  1743. }
  1744. // Do any of the stuff that is MS H.263 or MS H.261 specific right here
  1745. #ifndef _ALPHA_
  1746. #ifdef USE_BILINEAR_MSH26X
  1747. if ((pvfxDst->bih.biCompression == VIDEO_FORMAT_MSH263) || (pvfxDst->bih.biCompression == VIDEO_FORMAT_MSH261) || (pvfxDst->bih.biCompression == VIDEO_FORMAT_MSH26X))
  1748. #else
  1749. if ((pvfxDst->bih.biCompression == VIDEO_FORMAT_MSH263) || (pvfxDst->bih.biCompression == VIDEO_FORMAT_MSH261))
  1750. #endif
  1751. #else
  1752. if ((pvfxDst->bih.biCompression == VIDEO_FORMAT_DECH263) || (pvfxDst->bih.biCompression == VIDEO_FORMAT_DECH261))
  1753. #endif
  1754. {
  1755. pciMSH26XInfo = (PMSH26XCOMPINSTINFO)pvState;
  1756. // Really configure the codec for compression
  1757. pciMSH26XInfo->Configuration.bRTPHeader = TRUE;
  1758. pciMSH26XInfo->Configuration.unPacketSize = ((PVCMSTREAM)(*phvs))->dwMaxPacketSize;
  1759. pciMSH26XInfo->Configuration.bEncoderResiliency = FALSE;
  1760. pciMSH26XInfo->Configuration.unPacketLoss = 0;
  1761. // PhilF-: Make this work on the alpha
  1762. #ifndef _ALPHA_
  1763. pciMSH26XInfo->Configuration.bBitRateState = TRUE;
  1764. #else
  1765. pciMSH26XInfo->Configuration.bBitRateState = FALSE;
  1766. #endif
  1767. pciMSH26XInfo->Configuration.unBytesPerSecond = 1664;
  1768. if (((DWORD) ICSetState(hIC, (PVOID)pciMSH26XInfo, dw)) != dw)
  1769. {
  1770. ERRORMESSAGE(("vcmStreamOpen: ICSetState() failed\r\n"));
  1771. mmr = (MMRESULT)VCMERR_FAILED;
  1772. goto MyExit5;
  1773. }
  1774. // Get rid of the state structure
  1775. MemFree((HANDLE)pvState);
  1776. }
  1777. #ifdef USE_MPEG4_SCRUNCH
  1778. else if ((pvfxDst->bih.biCompression == VIDEO_FORMAT_MPEG4_SCRUNCH))
  1779. {
  1780. pciMPEG4Info = (PMPEG4COMPINSTINFO)pvState;
  1781. // Configure the codec for compression
  1782. pciMPEG4Info->lMagic = MPG4_STATE_MAGIC;
  1783. pciMPEG4Info->dDataRate = 20;
  1784. pciMPEG4Info->lCrisp = CRISP_DEF;
  1785. pciMPEG4Info->lKeydist = 30;
  1786. pciMPEG4Info->lPScale = MPG4_PSEUDO_SCALE;
  1787. pciMPEG4Info->lTotalWindowMs = MPG4_TOTAL_WINDOW_DEFAULT;
  1788. pciMPEG4Info->lVideoWindowMs = MPG4_VIDEO_WINDOW_DEFAULT;
  1789. pciMPEG4Info->lFramesInfoValid = FALSE;
  1790. pciMPEG4Info->lBFrameOn = MPG4_B_FRAME_ON;
  1791. pciMPEG4Info->lLiveEncode = MPG4_LIVE_ENCODE;
  1792. if (((DWORD) ICSetState(hIC, (PVOID)pciMPEG4Info, dw)) != dw)
  1793. {
  1794. ERRORMESSAGE(("vcmStreamOpen: ICSetState() failed\r\n"));
  1795. mmr = (MMRESULT)VCMERR_FAILED;
  1796. goto MyExit5;
  1797. }
  1798. // Get rid of the state structure
  1799. MemFree((HANDLE)pvState);
  1800. }
  1801. #endif
  1802. // Initialize ICCOMPRESSFRAMES structure
  1803. iccf.dwFlags = icInfo.dwFlags;
  1804. ((PVCMSTREAM)(*phvs))->dwQuality = dwImageQuality;
  1805. iccf.lQuality = 10000UL - (dwImageQuality * 322UL);
  1806. iccf.lDataRate = 1664; // Look into this...
  1807. iccf.lKeyRate = LONG_MAX;
  1808. iccf.dwRate = 1000UL;
  1809. #ifdef USE_MPEG4_SCRUNCH
  1810. iccf.dwScale = 142857;
  1811. #else
  1812. iccf.dwScale = pvfxDst->dwRequestMicroSecPerFrame / 1000UL;
  1813. #endif
  1814. ((PVCMSTREAM)(*phvs))->dwTargetFrameRate = iccf.dwScale;
  1815. ((PVCMSTREAM)(*phvs))->dwTargetByterate = iccf.lDataRate;
  1816. // Send this guy to the compressor
  1817. if ((mmr = ICSendMessage(hIC, ICM_COMPRESS_FRAMES_INFO, (DWORD_PTR)&iccf, sizeof(iccf)) != ICERR_OK))
  1818. {
  1819. ERRORMESSAGE(("vcmStreamOpen: Codec failed to handle ICM_COMPRESS_FRAMES_INFO message correctly\r\n"));
  1820. mmr = (MMRESULT)VCMERR_FAILED;
  1821. goto MyExit4;
  1822. }
  1823. // Start the compressor/decompressor with the right format
  1824. if ((dw = ICCompressGetFormatSize(hIC, &pvfxSrc->bih) < sizeof(BITMAPINFOHEADER)))
  1825. {
  1826. ERRORMESSAGE(("vcmStreamOpen: Codec failed to answer request for compressed format size\r\n"));
  1827. mmr = (MMRESULT)VCMERR_FAILED;
  1828. goto MyExit4;
  1829. }
  1830. // BUG_BUG: Where has pvfxDst been re-allocated ???
  1831. if ((dw = (DWORD)ICCompressGetFormat(hIC, &pvfxSrc->bih, &pvfxD->bih)) != ICERR_OK)
  1832. {
  1833. ERRORMESSAGE(("vcmStreamOpen: Codec failed to answer request for compressed format\r\n"));
  1834. mmr = (MMRESULT)VCMERR_FAILED;
  1835. goto MyExit4;
  1836. }
  1837. if ((mmr = (MMRESULT)ICCompressBegin(hIC, &pvfxSrc->bih, &pvfxD->bih)) != MMSYSERR_NOERROR)
  1838. {
  1839. ERRORMESSAGE(("vcmStreamOpen: Codec failed to start\r\n"));
  1840. mmr = (MMRESULT)VCMERR_FAILED;
  1841. goto MyExit4;
  1842. }
  1843. DEBUGMSG (1, ("vcmStreamOpen: Opening %.4s compression stream\r\n", (LPSTR)&pvfxDst->bih.biCompression));
  1844. // Update the passed destination video format. The caller really needs to use
  1845. // that information to allocate the buffer sizes appropriately.
  1846. CopyMemory(pvfxDst, pvfxD, sizeof(VIDEOFORMATEX));
  1847. // Here, you can probably get the size of the compressed frames and update the destination format
  1848. // with the real size of the compressed video buffer so that the DP can allocate the right set
  1849. // of video buffers.
  1850. }
  1851. else if ((dwFlags == ICMODE_DECOMPRESS) || (dwFlags == ICMODE_FASTDECOMPRESS))
  1852. {
  1853. if (mmr = ICDecompressBegin(hIC, &pvfxSrc->bih, &pvfxDst->bih) != MMSYSERR_NOERROR)
  1854. {
  1855. ERRORMESSAGE(("vcmStreamOpen: Codec failed to start\r\n"));
  1856. mmr = (MMRESULT)VCMERR_FAILED;
  1857. goto MyExit4;
  1858. }
  1859. DEBUGMSG (1, ("vcmStreamOpen: Opening %.4s decompression stream\r\n", (LPSTR)&pvfxSrc->bih.biCompression));
  1860. #ifndef _ALPHA_
  1861. #ifdef USE_BILINEAR_MSH26X
  1862. if ((pvfxSrc->bih.biCompression == VIDEO_FORMAT_MSH263) || (pvfxSrc->bih.biCompression == VIDEO_FORMAT_MSH261) || (pvfxSrc->bih.biCompression == VIDEO_FORMAT_MSH26X))
  1863. #else
  1864. if ((pvfxSrc->bih.biCompression == VIDEO_FORMAT_MSH263) || (pvfxSrc->bih.biCompression == VIDEO_FORMAT_MSH261))
  1865. #endif
  1866. #else
  1867. if ((pvfxSrc->bih.biCompression == VIDEO_FORMAT_DECH263) || (pvfxSrc->bih.biCompression == VIDEO_FORMAT_DECH261))
  1868. #endif
  1869. vcmStreamMessage(*phvs, CUSTOM_ENABLE_CODEC, G723MAGICWORD1, G723MAGICWORD2);
  1870. }
  1871. }
  1872. #ifdef LOGFILE_ON
  1873. if ((dwFlags == ICMODE_COMPRESS) || (dwFlags == ICMODE_FASTCOMPRESS))
  1874. {
  1875. if ((g_CompressLogFile = CreateFile("C:\\VCMCLog.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) != INVALID_HANDLE_VALUE)
  1876. {
  1877. GetLocalTime(&g_SystemTime);
  1878. wsprintf(g_szCompressBuffer, "Date %hu/%hu/%hu, Time %hu:%hu\r\n", g_SystemTime.wMonth, g_SystemTime.wDay, g_SystemTime.wYear, g_SystemTime.wHour, g_SystemTime.wMinute);
  1879. WriteFile(g_CompressLogFile, g_szCompressBuffer, strlen(g_szCompressBuffer), &g_dwCompressBytesWritten, NULL);
  1880. wsprintf(g_szCompressBuffer, "Frame#\t\tSize\t\tArrival Time\t\tCompression Time\r\n");
  1881. WriteFile(g_CompressLogFile, g_szCompressBuffer, strlen(g_szCompressBuffer), &g_dwCompressBytesWritten, NULL);
  1882. CloseHandle(g_CompressLogFile);
  1883. }
  1884. }
  1885. else if ((dwFlags == ICMODE_DECOMPRESS) || (dwFlags == ICMODE_FASTDECOMPRESS))
  1886. {
  1887. if ((g_DecompressLogFile = CreateFile("C:\\VCMDLog.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) != INVALID_HANDLE_VALUE)
  1888. {
  1889. GetLocalTime(&g_SystemTime);
  1890. wsprintf(g_szDecompressBuffer, "Date %hu/%hu/%hu, Time %hu:%hu\r\n", g_SystemTime.wMonth, g_SystemTime.wDay, g_SystemTime.wYear, g_SystemTime.wHour, g_SystemTime.wMinute);
  1891. WriteFile(g_DecompressLogFile, g_szDecompressBuffer, strlen(g_szDecompressBuffer), &g_dwDecompressBytesWritten, NULL);
  1892. wsprintf(g_szDecompressBuffer, "Frame#\t\tSize\t\tArrival Time\t\tDecompression Time\r\n");
  1893. WriteFile(g_DecompressLogFile, g_szDecompressBuffer, strlen(g_szDecompressBuffer), &g_dwDecompressBytesWritten, NULL);
  1894. CloseHandle(g_DecompressLogFile);
  1895. }
  1896. }
  1897. #endif
  1898. return ((MMRESULT)MMSYSERR_NOERROR);
  1899. }
  1900. else
  1901. return ((MMRESULT)VCMERR_NOTPOSSIBLE);
  1902. MyExit5:
  1903. if (pvState)
  1904. MemFree(pvState);
  1905. MyExit4:
  1906. if (pbmiPrev)
  1907. MemFree(pbmiPrev);
  1908. MyExit3:
  1909. if (pvfxD)
  1910. MemFree(pvfxD);
  1911. MyExit2:
  1912. if (pvfxS)
  1913. MemFree(pvfxS);
  1914. MyExit1:
  1915. if ((dwFlags == ICMODE_COMPRESS) || (dwFlags == ICMODE_FASTCOMPRESS)) // Hmmm... where could you have set the second mode?
  1916. DeleteCriticalSection(&(((PVCMSTREAM)(*phvs))->crsFrameNumber));
  1917. if (*phvs)
  1918. MemFree(*phvs);
  1919. *phvs = (HVCMSTREAM)(PVCMSTREAM)NULL;
  1920. MyExit0:
  1921. return (mmr);
  1922. }
  1923. /****************************************************************************
  1924. * @doc EXTERNAL COMPFUNC
  1925. *
  1926. * @func MMRESULT | vcmStreamClose | The vcmStreamClose function closes a previously
  1927. * opened Video Compression Manager (VCM) conversion stream. If the function is
  1928. * successful, the handle is invalidated.
  1929. *
  1930. * @parm HVCMSTREAM | hvs | Identifies the open conversion stream to be closed.
  1931. *
  1932. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  1933. * a non-zero error number. Possible error returns are:
  1934. *
  1935. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  1936. *
  1937. * @flag VCMERR_BUSY | The conversion stream cannot be closed because
  1938. * an asynchronous conversion is still in progress.
  1939. *
  1940. * @xref <f vcmStreamOpen> <f vcmStreamReset>
  1941. ***************************************************************************/
  1942. MMRESULT VCMAPI vcmStreamClose(HVCMSTREAM hvs)
  1943. {
  1944. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  1945. #ifdef LOGFILE_ON
  1946. DWORD i;
  1947. #endif
  1948. // Check input params
  1949. if (!hvs)
  1950. {
  1951. ERRORMESSAGE(("vcmStreamClose: Specified HVCMSTREAM handle is invalid, hvs=NULL\r\n"));
  1952. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  1953. }
  1954. // Stop the compressor/decompressor
  1955. if ((pvs->fdwStream == ICMODE_COMPRESS) || (pvs->fdwStream == ICMODE_FASTCOMPRESS))
  1956. {
  1957. #ifdef LOGFILE_ON
  1958. g_OrigCompressTime = GetTickCount() - g_OrigCompressTime;
  1959. if (pvs->dwFrame)
  1960. {
  1961. for (i=0, g_AvgCompressTime=0; i<pvs->dwFrame && i<4096; i++)
  1962. g_AvgCompressTime += g_aCompressTime[i];
  1963. g_AvgCompressTime /= i;
  1964. }
  1965. if ((g_CompressLogFile = CreateFile("C:\\VCMCLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) != INVALID_HANDLE_VALUE)
  1966. {
  1967. SetFilePointer(g_CompressLogFile, 0, NULL, FILE_END);
  1968. if (pvs->dwFrame)
  1969. {
  1970. wsprintf(g_szCompressBuffer, "Frames/s\tAvg. Comp. Time\r\n");
  1971. WriteFile(g_CompressLogFile, g_szCompressBuffer, strlen(g_szCompressBuffer), &g_dwCompressBytesWritten, NULL);
  1972. wsprintf(g_szCompressBuffer, "%04d\t\t%03d\r\n", pvs->dwFrame * 1000 / g_OrigCompressTime, g_AvgCompressTime);
  1973. WriteFile(g_CompressLogFile, g_szCompressBuffer, strlen(g_szCompressBuffer), &g_dwCompressBytesWritten, NULL);
  1974. }
  1975. else
  1976. {
  1977. wsprintf(g_szCompressBuffer, "No frames were compressed!");
  1978. WriteFile(g_CompressLogFile, g_szCompressBuffer, strlen(g_szCompressBuffer), &g_dwCompressBytesWritten, NULL);
  1979. }
  1980. CloseHandle(g_CompressLogFile);
  1981. }
  1982. #endif
  1983. if (ICCompressEnd((HIC)pvs->hIC) != MMSYSERR_NOERROR)
  1984. {
  1985. ERRORMESSAGE(("vcmStreamClose: Codec failed to stop\r\n"));
  1986. return ((MMRESULT)VCMERR_FAILED);
  1987. }
  1988. }
  1989. else if ((pvs->fdwStream == ICMODE_DECOMPRESS) || (pvs->fdwStream == ICMODE_FASTDECOMPRESS))
  1990. {
  1991. #ifdef LOGFILE_ON
  1992. g_OrigDecompressTime = GetTickCount() - g_OrigDecompressTime;
  1993. if (pvs->dwFrame)
  1994. {
  1995. for (i=0, g_AvgDecompressTime=0; i<pvs->dwFrame && i<4096; i++)
  1996. g_AvgDecompressTime += g_aDecompressTime[i];
  1997. g_AvgDecompressTime /= i;
  1998. }
  1999. if ((g_DecompressLogFile = CreateFile("C:\\VCMDLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) != INVALID_HANDLE_VALUE)
  2000. {
  2001. SetFilePointer(g_DecompressLogFile, 0, NULL, FILE_END);
  2002. if (pvs->dwFrame)
  2003. {
  2004. wsprintf(g_szDecompressBuffer, "Frames/s\tAvg. Decomp. Time\r\n");
  2005. WriteFile(g_DecompressLogFile, g_szDecompressBuffer, strlen(g_szDecompressBuffer), &g_dwDecompressBytesWritten, NULL);
  2006. wsprintf(g_szDecompressBuffer, "%04d\t\t%03d\r\n", pvs->dwFrame * 1000 / g_OrigDecompressTime, g_AvgDecompressTime);
  2007. WriteFile(g_DecompressLogFile, g_szDecompressBuffer, strlen(g_szDecompressBuffer), &g_dwDecompressBytesWritten, NULL);
  2008. }
  2009. else
  2010. {
  2011. wsprintf(g_szDecompressBuffer, "No frames were decompressed!");
  2012. WriteFile(g_DecompressLogFile, g_szDecompressBuffer, strlen(g_szDecompressBuffer), &g_dwDecompressBytesWritten, NULL);
  2013. }
  2014. CloseHandle(g_DecompressLogFile);
  2015. }
  2016. #endif
  2017. if (ICDecompressEnd((HIC)pvs->hIC) != MMSYSERR_NOERROR)
  2018. {
  2019. ERRORMESSAGE(("vcmStreamClose: Codec failed to stop\r\n"));
  2020. return ((MMRESULT)VCMERR_FAILED);
  2021. }
  2022. }
  2023. // Close compressor/decompressor
  2024. if (pvs->hIC)
  2025. ICClose((HIC)pvs->hIC);
  2026. // Nuke critical section
  2027. if ((pvs->fdwStream == ICMODE_COMPRESS) || (pvs->fdwStream == ICMODE_FASTCOMPRESS))
  2028. DeleteCriticalSection(&pvs->crsFrameNumber);
  2029. // Free video format buffers
  2030. if (pvs->pvfxSrc)
  2031. MemFree(pvs->pvfxSrc);
  2032. if (pvs->pvfxDst)
  2033. MemFree(pvs->pvfxDst);
  2034. if (pvs->pbmiPrev)
  2035. MemFree(pvs->pbmiPrev);
  2036. // Free main VCM structure
  2037. MemFree(pvs);
  2038. return ((MMRESULT)MMSYSERR_NOERROR);
  2039. }
  2040. /****************************************************************************
  2041. * @doc EXTERNAL COMPFUNC
  2042. *
  2043. * @func MMRESULT | vcmStreamSize | The vcmStreamSize function returns a recommended size for a
  2044. * source or destination buffer on an Video Compression Manager (VCM)
  2045. * stream.
  2046. *
  2047. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  2048. *
  2049. * @parm DWORD | cbInput | Specifies the size in bytes of either the source
  2050. * or destination buffer. The <p fdwSize> flags specify what the
  2051. * input argument defines. This argument must be non-zero.
  2052. *
  2053. * @parm LPDWORD | pdwOutputBytes | Specifies a pointer to a <t DWORD>
  2054. * that contains the size in bytes of the source or destination buffer.
  2055. * The <p fdwSize> flags specify what the output argument defines.
  2056. * If the <f vcmStreamSize> function succeeds, this location will
  2057. * always be filled with a non-zero value.
  2058. *
  2059. * @parm DWORD | fdwSize | Specifies flags for the stream-size query.
  2060. *
  2061. * @flag VCM_STREAMSIZEF_SOURCE | Indicates that <p cbInput> contains
  2062. * the size of the source buffer. The <p pdwOutputBytes> argument will
  2063. * receive the recommended destination buffer size in bytes.
  2064. *
  2065. * @flag VCM_STREAMSIZEF_DESTINATION | Indicates that <p cbInput>
  2066. * contains the size of the destination buffer. The <p pdwOutputBytes>
  2067. * argument will receive the recommended source buffer size in bytes.
  2068. *
  2069. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2070. * a non-zero error number. Possible error returns are:
  2071. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  2072. * @flag MMSYSERR_INVALFLAG | One or more flags are invalid.
  2073. * @flag MMSYSERR_INVALPARAM | One or more arguments passed are invalid.
  2074. * @flag VCMERR_NOTPOSSIBLE | The requested operation cannot be performed.
  2075. *
  2076. * @comm An application can use the <f vcmStreamSize> function to determine
  2077. * suggested buffer sizes for either source or destination buffers.
  2078. * The buffer sizes returned might be only an estimation of the
  2079. * actual sizes required for conversion. Because actual conversion
  2080. * sizes cannot always be determined without performing the conversion,
  2081. * the sizes returned will usually be overestimated.
  2082. *
  2083. * In the event of an error, the location pointed to by
  2084. * <p pdwOutputBytes> will receive zero. This assumes that the pointer
  2085. * specified by <p pdwOutputBytes> is valid.
  2086. *
  2087. * @xref <f vcmStreamPrepareHeader> <f vcmStreamConvert>
  2088. ***************************************************************************/
  2089. MMRESULT VCMAPI vcmStreamSize(HVCMSTREAM hvs, DWORD cbInput, PDWORD pdwOutputBytes, DWORD fdwSize)
  2090. {
  2091. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  2092. DWORD dwNumFrames;
  2093. // Check input params
  2094. if (!hvs)
  2095. {
  2096. ERRORMESSAGE(("vcmStreamSize: Specified HVCMSTREAM handle is invalid, hvs=NULL\r\n"));
  2097. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  2098. }
  2099. // Do the math
  2100. switch (VCM_STREAMSIZEF_QUERYMASK & fdwSize)
  2101. {
  2102. case VCM_STREAMSIZEF_SOURCE:
  2103. if (pvs->pvfxSrc->dwFormatTag != VIDEO_FORMAT_BI_RGB)
  2104. {
  2105. // How many destination RGB bytes are needed to hold the decoded source
  2106. // buffer of cbInput compressed bytes
  2107. if (!(dwNumFrames = cbInput / pvs->pvfxSrc->nBlockAlign))
  2108. {
  2109. ERRORMESSAGE(("vcmStreamSize: The requested operation cannot be performed\r\n"));
  2110. return ((MMRESULT)VCMERR_NOTPOSSIBLE);
  2111. }
  2112. else
  2113. *pdwOutputBytes = dwNumFrames * pvs->pvfxDst->nBlockAlign;
  2114. }
  2115. else
  2116. {
  2117. // How many destination compressed bytes are needed to hold the encoded source
  2118. // buffer of cbInput RGB bytes
  2119. if (!(dwNumFrames = cbInput / pvs->pvfxSrc->nBlockAlign))
  2120. {
  2121. ERRORMESSAGE(("vcmStreamSize: The requested operation cannot be performed\r\n"));
  2122. return ((MMRESULT)VCMERR_NOTPOSSIBLE);
  2123. }
  2124. else
  2125. {
  2126. if (cbInput % pvs->pvfxSrc->nBlockAlign)
  2127. dwNumFrames++;
  2128. *pdwOutputBytes = dwNumFrames * pvs->pvfxDst->nBlockAlign;
  2129. }
  2130. }
  2131. return ((MMRESULT)MMSYSERR_NOERROR);
  2132. case VCM_STREAMSIZEF_DESTINATION:
  2133. if (pvs->pvfxDst->dwFormatTag != VIDEO_FORMAT_BI_RGB)
  2134. {
  2135. // How many source RGB bytes can be encoded into a destination buffer
  2136. // of cbInput bytes
  2137. if (!(dwNumFrames = cbInput / pvs->pvfxDst->nBlockAlign))
  2138. {
  2139. ERRORMESSAGE(("vcmStreamSize: The requested operation cannot be performed\r\n"));
  2140. return ((MMRESULT)VCMERR_NOTPOSSIBLE);
  2141. }
  2142. else
  2143. *pdwOutputBytes = dwNumFrames * pvs->pvfxSrc->nBlockAlign;
  2144. }
  2145. else
  2146. {
  2147. // How many source encoded bytes can be decoded into a destination buffer
  2148. // of cbInput RGB bytes
  2149. if (!(dwNumFrames = cbInput / pvs->pvfxDst->nBlockAlign))
  2150. {
  2151. ERRORMESSAGE(("vcmStreamSize: The requested operation cannot be performed\r\n"));
  2152. return ((MMRESULT)VCMERR_NOTPOSSIBLE);
  2153. }
  2154. else
  2155. *pdwOutputBytes = dwNumFrames * pvs->pvfxSrc->nBlockAlign;
  2156. }
  2157. return ((MMRESULT)MMSYSERR_NOERROR);
  2158. default:
  2159. ERRORMESSAGE(("vcmStreamSize: One or more flags are invalid\r\n"));
  2160. return ((MMRESULT)MMSYSERR_NOTSUPPORTED);
  2161. }
  2162. }
  2163. /****************************************************************************
  2164. * @doc EXTERNAL COMPFUNC
  2165. *
  2166. * @func MMRESULT | vcmStreamReset | The vcmStreamReset function stops conversions
  2167. * for a given Video Compression Manager (VCM) stream. All pending
  2168. * buffers are marked as done and returned to the application.
  2169. *
  2170. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  2171. *
  2172. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2173. * a non-zero error number. Possible error returns are:
  2174. *
  2175. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  2176. *
  2177. * @flag MMSYSERR_INVALFLAG | One or more flags are invalid.
  2178. *
  2179. * @comm Resetting a VCM conversion stream is only necessary to reset
  2180. * asynchronous conversion streams. However, resetting a synchronous
  2181. * conversion stream will succeed, but no action will be taken.
  2182. *
  2183. * @xref <f vcmStreamConvert> <f vcmStreamClose>
  2184. ***************************************************************************/
  2185. MMRESULT VCMAPI vcmStreamReset(HVCMSTREAM hvs)
  2186. {
  2187. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  2188. PVCMSTREAMHEADER pvsh;
  2189. // Check input params
  2190. if (!hvs)
  2191. {
  2192. ERRORMESSAGE(("vcmSreamReset: Specified HVCMSTREAM handle is invalid, hvs=NULL\r\n"));
  2193. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  2194. }
  2195. while (pvsh = DeQueVCMHeader(pvs))
  2196. {
  2197. MarkVCMHeaderDone(pvsh);
  2198. // Look into how this would be best handled
  2199. // What if the capture driver sends us those exact same
  2200. // messages for its own buffers?
  2201. // Test for the validity of the callback before doing this...
  2202. switch (pvs->fdwOpen)
  2203. {
  2204. case CALLBACK_FUNCTION:
  2205. (*(VCMSTREAMPROC)pvs->dwCallback)(hvs, VCM_DONE, pvs->dwCallbackInstance, (DWORD_PTR)pvsh, 0);
  2206. break;
  2207. case CALLBACK_EVENT:
  2208. SetEvent((HANDLE)pvs->dwCallback);
  2209. break;
  2210. case CALLBACK_WINDOW:
  2211. PostMessage((HWND)pvs->dwCallback, MM_VCM_DONE, (WPARAM)hvs, (LPARAM)pvsh);
  2212. break;
  2213. case CALLBACK_THREAD:
  2214. PostThreadMessage((DWORD)pvs->dwCallback, MM_VCM_DONE, (WPARAM)hvs, (LPARAM)pvsh);
  2215. break;
  2216. case CALLBACK_NULL:
  2217. break;
  2218. default:
  2219. break;
  2220. }
  2221. }
  2222. pvs->pvhFirst = NULL;
  2223. pvs->pvhLast = NULL;
  2224. return ((MMRESULT)MMSYSERR_NOERROR);
  2225. }
  2226. /****************************************************************************
  2227. * @doc EXTERNAL COMPFUNC
  2228. *
  2229. * @func MMRESULT | vcmStreamMessage | This function sends a user-defined
  2230. * message to a given Video Compression Manager (VCM) stream instance.
  2231. *
  2232. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  2233. *
  2234. * @parm UINT | uMsg | Specifies the message that the VCM stream must
  2235. * process. This message must be in the <m VCMDM_USER> message range
  2236. * (above or equal to <m VCMDM_USER> and less than
  2237. * <m VCMDM_RESERVED_LOW>). The exception to this restriction is
  2238. * the <m VCMDM_STREAM_UPDATE> message.
  2239. *
  2240. * @parm LPARAM | lParam1 | Specifies the first message parameter.
  2241. *
  2242. * @parm LPARAM | lParam2 | Specifies the second message parameter.
  2243. *
  2244. * @rdesc The return value is specific to the user-defined VCM driver
  2245. * message <p uMsg> sent. However, the following return values are
  2246. * possible:
  2247. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  2248. * @flag MMSYSERR_INVALPARAM | <p uMsg> is not in the VCMDM_USER range.
  2249. * @flag MMSYSERR_NOTSUPPORTED | The VCM driver did not process the message.
  2250. ***************************************************************************/
  2251. MMRESULT VCMAPI vcmStreamMessage(HVCMSTREAM hvs, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
  2252. {
  2253. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  2254. // Check input params
  2255. if (!hvs)
  2256. {
  2257. ERRORMESSAGE(("vcmStreamMessage: Specified HVCMSTREAM handle is invalid, hvs=NULL\r\n"));
  2258. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  2259. }
  2260. // Check input params
  2261. if ((uMsg > VCMDM_RESERVED_HIGH) || (uMsg < VCMDM_RESERVED_LOW))
  2262. {
  2263. ERRORMESSAGE(("vcmStreamMessage: Specified message is out of range, uMsg=0x%lX (expected value is between 0x%lX and 0x%lX)\r\n", uMsg, VCMDM_RESERVED_LOW, VCMDM_RESERVED_HIGH));
  2264. return ((MMRESULT)MMSYSERR_INVALPARAM);
  2265. }
  2266. // Send the message to the codec.
  2267. if (pvs->hIC)
  2268. if (ICSendMessage((HIC)(HVCMDRIVERID)pvs->hIC, uMsg, lParam1, lParam2) != ICERR_OK)
  2269. {
  2270. ERRORMESSAGE(("vcmStreamMessage: Codec failed to handle user-defined message correctly\r\n"));
  2271. return ((MMRESULT)MMSYSERR_NOTSUPPORTED);
  2272. }
  2273. return ((MMRESULT)MMSYSERR_NOERROR);
  2274. }
  2275. /****************************************************************************
  2276. * @doc EXTERNAL COMPFUNC
  2277. *
  2278. * @func MMRESULT | vcmStreamConvert | The vcmStreamConvert function requests the Video
  2279. * Compression Manager (VCM) to perform a conversion on the specified conversion stream. A
  2280. * conversion may be synchronous or asynchronous depending on how the
  2281. * stream was opened.
  2282. *
  2283. * @parm HVCMSTREAM | has | Identifies the open conversion stream.
  2284. *
  2285. * @parm PVCMSTREAMHEADER | pash | Specifies a pointer to a stream header
  2286. * that describes source and destination buffers for a conversion. This
  2287. * header must have been prepared previously using the
  2288. * <f vcmStreamPrepareHeader> function.
  2289. *
  2290. * @parm DWORD | fdwConvert | Specifies flags for doing the conversion.
  2291. *
  2292. * @flag VCM_STREAMCONVERTF_BLOCKALIGN | Specifies that only integral
  2293. * numbers of blocks will be converted. Converted data will end on
  2294. * block aligned boundaries. An application should use this flag for
  2295. * all conversions on a stream until there is not enough source data
  2296. * to convert to a block-aligned destination. In this case, the last
  2297. * conversion should be specified without this flag.
  2298. *
  2299. * @flag VCM_STREAMCONVERTF_START | Specifies that the VCM conversion
  2300. * stream should reinitialize its instance data. For example, if a
  2301. * conversion stream holds instance data, such as delta or predictor
  2302. * information, this flag will restore the stream to starting defaults.
  2303. * Note that this flag can be specified with the VCM_STREAMCONVERTF_END
  2304. * flag.
  2305. *
  2306. * @flag VCM_STREAMCONVERTF_END | Specifies that the VCM conversion
  2307. * stream should begin returning pending instance data. For example, if
  2308. * a conversion stream holds instance data, such as the tail end of an
  2309. * echo filter operation, this flag will cause the stream to start
  2310. * returning this remaining data with optional source data. Note that
  2311. * this flag can be specified with the VCM_STREAMCONVERTF_START flag.
  2312. *
  2313. * @flag VCM_STREAMCONVERTF_FORCE_KEYFRAME | Specifies that the VCM conversion
  2314. * stream should compress the current frame as a key frame.
  2315. *
  2316. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2317. * a non-zero error number. Possible error returns are:
  2318. *
  2319. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  2320. *
  2321. * @flag MMSYSERR_INVALFLAG | One or more flags are invalid.
  2322. *
  2323. * @flag MMSYSERR_INVALPARAM | One or more arguments passed are invalid.
  2324. *
  2325. * @flag VCMERR_BUSY | The stream header <p pash> is currently in use
  2326. * and cannot be reused.
  2327. *
  2328. * @flag VCMERR_UNPREPARED | The stream header <p pash> is currently
  2329. * not prepared by the <f vcmStreamPrepareHeader> function.
  2330. *
  2331. * @comm The source and destination data buffers must be prepared with
  2332. * <f vcmStreamPrepareHeader> before they are passed to <f vcmStreamConvert>.
  2333. *
  2334. * If an asynchronous conversion request is successfully queued by
  2335. * the VCM or driver, and later the conversion is determined to
  2336. * be impossible, then the <t VCMSTREAMHEADER> will be posted back to
  2337. * the application's callback with the <e VCMSTREAMHEADER.cbDstLengthUsed>
  2338. * member set to zero.
  2339. *
  2340. * @xref <f vcmStreamOpen> <f vcmStreamReset> <f vcmStreamPrepareHeader>
  2341. * <f vcmStreamUnprepareHeader>
  2342. ***************************************************************************/
  2343. MMRESULT VCMAPI vcmStreamConvert(HVCMSTREAM hvs, PVCMSTREAMHEADER pvsh, DWORD fdwConvert)
  2344. {
  2345. MMRESULT mmr;
  2346. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  2347. BOOL fKeyFrame;
  2348. BOOL fTemporalCompress;
  2349. BOOL fFastTemporal;
  2350. DWORD dwMaxSizeThisFrame = 0xffffff;
  2351. DWORD ckid = 0UL;
  2352. DWORD dwFlags;
  2353. DWORD dwTimestamp;
  2354. #ifdef LOGFILE_ON
  2355. if ((pvs->fdwStream == ICMODE_COMPRESS) || (pvs->fdwStream == ICMODE_FASTCOMPRESS))
  2356. g_CompressTime = GetTickCount();
  2357. else if ((pvs->fdwStream == ICMODE_DECOMPRESS) || (pvs->fdwStream == ICMODE_FASTDECOMPRESS))
  2358. g_DecompressTime = GetTickCount();
  2359. #endif
  2360. // Check input params
  2361. if (!hvs)
  2362. {
  2363. ERRORMESSAGE(("vcmStreamConvert: Specified HVCMSTREAM handle is invalid, hvs=NULL\r\n"));
  2364. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  2365. }
  2366. if (!pvsh)
  2367. {
  2368. ERRORMESSAGE(("vcmStreamConvert: Specified PVCMSTREAMHEADER pointer is invalid, pvsh=NULL\r\n"));
  2369. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  2370. }
  2371. if (pvsh->cbStruct < sizeof(VCMSTREAMHEADER))
  2372. {
  2373. ERRORMESSAGE(("vcmStreamConvert: The size of the VCM stream header is invalid, pvsh->cbStruct=%ld (expected value is %ld)\r\n", pvsh->cbStruct, sizeof(VCMSTREAMHEADER)));
  2374. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  2375. }
  2376. // Return if buffer is already being converted
  2377. if (IsVCMHeaderInQueue(pvsh))
  2378. {
  2379. ERRORMESSAGE(("vcmStreamConvert: Buffer is already being converted\r\n"));
  2380. return ((MMRESULT)VCMERR_BUSY);
  2381. }
  2382. // Return if buffer has not been prepared
  2383. if (!IsVCMHeaderPrepared(pvsh))
  2384. {
  2385. ERRORMESSAGE(("vcmStreamConvert: Buffer has not been prepared\r\n"));
  2386. return ((MMRESULT)VCMERR_UNPREPARED);
  2387. }
  2388. // Set flags
  2389. MarkVCMHeaderNotDone(pvsh);
  2390. pvsh->cbSrcLengthUsed = pvsh->cbSrcLength;
  2391. pvsh->cbDstLengthUsed = pvsh->cbDstLength;
  2392. pvsh->cbPrevLengthUsed = pvsh->cbPrevLength;
  2393. MarkVCMHeaderInQueue(pvsh);
  2394. // Queue buffer
  2395. pvsh->pNext = NULL;
  2396. if (pvs->pvhLast)
  2397. pvs->pvhLast->pNext = pvsh;
  2398. else
  2399. pvs->pvhFirst = pvsh;
  2400. pvs->pvhLast = pvsh;
  2401. if ((pvs->fdwStream == ICMODE_COMPRESS) || (pvs->fdwStream == ICMODE_FASTCOMPRESS))
  2402. {
  2403. // Save the current time
  2404. dwTimestamp = GetTickCount();
  2405. // We need the following crs to make sure we don't miss any of the I-Frame requests
  2406. // emittted by the UI. Problematic scenario: pvs->dwFrame is at 123 for instance.
  2407. // The UI thread requests an I-Frame by setting pvs->dwFrame to 0. If the capture/compression
  2408. // thread was in ICCompress() (which is very probable since it takes quite some time
  2409. // to compress a frame), pvs->dwFrame will be incremented by one when ICCompress()
  2410. // returns. We failed to handle the I-Frame request correctly, since the next time
  2411. // ICCompress() gets called pvs->dwFrame will be equal to 1, for which we do not
  2412. // generate an I-Frame.
  2413. EnterCriticalSection(&pvs->crsFrameNumber);
  2414. // Compress
  2415. fTemporalCompress = pvs->dwICInfoFlags & VIDCF_TEMPORAL;
  2416. fFastTemporal = pvs->dwICInfoFlags & VIDCF_FASTTEMPORALC;
  2417. fKeyFrame = !fTemporalCompress || (fTemporalCompress && !fFastTemporal && ((pvsh->pbPrev == (PBYTE)NULL) || (pvsh->cbPrevLength == (DWORD)NULL))) ||
  2418. (pvs->fPeriodicIFrames && (((dwTimestamp > pvs->dwLastIFrameTime) && ((dwTimestamp - pvs->dwLastIFrameTime) > MIN_IFRAME_REQUEST_INTERVAL)))) || (pvs->dwFrame == 0) || (fdwConvert & VCM_STREAMCONVERTF_FORCE_KEYFRAME);
  2419. dwFlags = fKeyFrame ? AVIIF_KEYFRAME : 0;
  2420. #if 0
  2421. dwMaxSizeThisFrame = fKeyFrame ? 0xffffff : pvs->dwTargetFrameRate ? pvs->dwTargetByterate * pvs->dwTargetFrameRate / 1000UL : 0;
  2422. #else
  2423. dwMaxSizeThisFrame = pvs->dwTargetFrameRate ? pvs->dwTargetByterate * 100UL / pvs->dwTargetFrameRate : 0;
  2424. #endif
  2425. // We need to modify the frame number so that the codec can generate
  2426. // a valid TR. TRs use MPIs as their units. So we need to generate a
  2427. // frame number assuming a 29.97Hz capture rate, even though we will be
  2428. // capturing at some other rate.
  2429. if (pvs->dwLastTimestamp == ULONG_MAX)
  2430. {
  2431. // This is the first frame
  2432. pvs->dwFrame = 0UL;
  2433. // Save the current time
  2434. pvs->dwLastTimestamp = dwTimestamp;
  2435. // DEBUGMSG (ZONE_VCM, ("vcmStreamConvert: Last Timestamp = ULONG_MAX => Frame # = 0\r\n"));
  2436. }
  2437. else
  2438. {
  2439. // Compare the current timestamp to the last one we saved. The difference
  2440. // will let us normalize the frame count to 29.97Hz.
  2441. if (fKeyFrame)
  2442. {
  2443. pvs->dwFrame = 0UL;
  2444. pvs->dwLastTimestamp = dwTimestamp;
  2445. }
  2446. else
  2447. pvs->dwFrame = (dwTimestamp - pvs->dwLastTimestamp) * 2997 / 100000UL;
  2448. // DEBUGMSG (ZONE_VCM, ("vcmStreamConvert: Last Timestamp = %ld => Frame # = %ld\r\n", pvs->dwLastTimestamp, pvs->dwFrame));
  2449. }
  2450. if (fKeyFrame)
  2451. {
  2452. pvs->dwLastIFrameTime = dwTimestamp;
  2453. DEBUGMSG (ZONE_VCM, ("vcmStreamConvert: Generating an I-Frame...\r\n"));
  2454. }
  2455. mmr = ICCompress((HIC)pvs->hIC, fKeyFrame ? ICCOMPRESS_KEYFRAME : 0, (LPBITMAPINFOHEADER)&pvs->pvfxDst->bih, pvsh->pbDst, (LPBITMAPINFOHEADER)&pvs->pvfxSrc->bih, pvsh->pbSrc, &ckid, &dwFlags,
  2456. pvs->dwFrame++, dwMaxSizeThisFrame, 10000UL - (pvs->dwQuality * 322UL), fKeyFrame | fFastTemporal ? NULL : (LPBITMAPINFOHEADER)&pvs->pbmiPrev, fKeyFrame | fFastTemporal ? NULL : pvsh->pbPrev);
  2457. // Allow the UI to modify the frame number on its own thread
  2458. LeaveCriticalSection(&pvs->crsFrameNumber);
  2459. if (mmr != MMSYSERR_NOERROR)
  2460. {
  2461. #ifdef LOGFILE_ON
  2462. if (pvs->dwFrame < 4096)
  2463. {
  2464. if (pvs->dwFrame ==1)
  2465. g_OrigCompressTime = g_CompressTime;
  2466. g_aCompressTime[pvs->dwFrame-1] = g_CompressTime = GetTickCount() - g_CompressTime;
  2467. if ((g_CompressLogFile = CreateFile("C:\\VCMCLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) != INVALID_HANDLE_VALUE)
  2468. {
  2469. SetFilePointer(g_CompressLogFile, 0, NULL, FILE_END);
  2470. wsprintf(g_szCompressBuffer, "%04d\t\t%08d\t\t.o0Failed!0o.\r\n", pvs->dwFrame-1, g_OrigCompressTime);
  2471. WriteFile(g_CompressLogFile, g_szCompressBuffer, strlen(g_szCompressBuffer), &g_dwCompressBytesWritten, NULL);
  2472. CloseHandle(g_CompressLogFile);
  2473. }
  2474. }
  2475. #endif
  2476. ERRORMESSAGE(("vcmStreamConvert: ICCompress() failed, mmr=%ld\r\n", mmr));
  2477. // Get the handle to the video device associated to the capture window
  2478. pvsh = DeQueVCMHeader(pvs);
  2479. MarkVCMHeaderDone(pvsh);
  2480. return ((MMRESULT)VCMERR_FAILED);
  2481. }
  2482. pvsh->cbDstLengthUsed = pvs->pvfxDst->bih.biSizeImage;
  2483. if ((fTemporalCompress) && (!fFastTemporal))
  2484. {
  2485. if (!pvsh->pbPrev)
  2486. pvsh->pbPrev = (PBYTE)MemAlloc(pvs->pvfxSrc->bih.biSizeImage);
  2487. if (pvsh->pbPrev)
  2488. {
  2489. // What about fast temporal?
  2490. if (mmr = ICDecompress((HIC)pvs->hIC, 0, (LPBITMAPINFOHEADER)&pvs->pvfxDst->bih, pvsh->pbDst, (LPBITMAPINFOHEADER)&pvs->pvfxSrc->bih, pvsh->pbPrev) != MMSYSERR_NOERROR)
  2491. {
  2492. ERRORMESSAGE(("vcmStreamConvert: ICCompress() failed, mmr=%ld\r\n", mmr));
  2493. // Get the handle to the video device associated to the capture window
  2494. pvsh = DeQueVCMHeader(pvs);
  2495. MarkVCMHeaderDone(pvsh);
  2496. return ((MMRESULT)VCMERR_FAILED); // Do we really want to quit?
  2497. }
  2498. }
  2499. }
  2500. }
  2501. else if ((pvs->fdwStream == ICMODE_DECOMPRESS) || (pvs->fdwStream == ICMODE_FASTDECOMPRESS))
  2502. {
  2503. // Decompress
  2504. pvs->dwFrame++;
  2505. pvs->pvfxSrc->bih.biSizeImage = pvsh->cbSrcLength;
  2506. if (mmr = ICDecompress((HIC)pvs->hIC, 0, (LPBITMAPINFOHEADER)&pvs->pvfxSrc->bih, pvsh->pbSrc, (LPBITMAPINFOHEADER)&pvs->pvfxDst->bih, pvsh->pbDst) != MMSYSERR_NOERROR)
  2507. {
  2508. #ifdef LOGFILE_ON
  2509. if (pvs->dwFrame < 4096)
  2510. {
  2511. if (pvs->dwFrame ==1)
  2512. g_OrigDecompressTime = g_DecompressTime;
  2513. g_aDecompressTime[pvs->dwFrame-1] = g_DecompressTime = GetTickCount() - g_DecompressTime;
  2514. if ((g_DecompressLogFile = CreateFile("C:\\VCMDLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) != INVALID_HANDLE_VALUE)
  2515. {
  2516. SetFilePointer(g_DecompressLogFile, 0, NULL, FILE_END);
  2517. wsprintf(g_szDecompressBuffer, "%04d\t\t%08d\t\t.o0Failed!0o.\r\n", pvs->dwFrame-1, g_OrigDecompressTime);
  2518. WriteFile(g_DecompressLogFile, g_szDecompressBuffer, strlen(g_szDecompressBuffer), &g_dwDecompressBytesWritten, NULL);
  2519. CloseHandle(g_DecompressLogFile);
  2520. }
  2521. }
  2522. #endif
  2523. ERRORMESSAGE(("vcmStreamConvert: ICDecompress() failed, mmr=%ld\r\n", mmr));
  2524. // Get the handle to the video device associated to the capture window
  2525. pvsh = DeQueVCMHeader(pvs);
  2526. MarkVCMHeaderDone(pvsh);
  2527. return ((MMRESULT)VCMERR_FAILED);
  2528. }
  2529. }
  2530. #ifdef LOGFILE_ON
  2531. if (pvs->dwFrame < 4096)
  2532. {
  2533. if ((pvs->fdwStream == ICMODE_COMPRESS) || (pvs->fdwStream == ICMODE_FASTCOMPRESS))
  2534. {
  2535. if (pvs->dwFrame == 1)
  2536. g_OrigCompressTime = g_CompressTime;
  2537. g_aCompressTime[pvs->dwFrame-1] = g_CompressTime = GetTickCount() - g_CompressTime;
  2538. if ((g_CompressLogFile = CreateFile("C:\\VCMCLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) != INVALID_HANDLE_VALUE)
  2539. {
  2540. SetFilePointer(g_CompressLogFile, 0, NULL, FILE_END);
  2541. wsprintf(g_szCompressBuffer, "%04d\t\t%08d\t\t%05d\t\t%03d\r\n", pvs->dwFrame-1, g_OrigCompressTime, pvs->pvfxDst->bih.biSizeImage, g_CompressTime);
  2542. WriteFile(g_CompressLogFile, g_szCompressBuffer, strlen(g_szCompressBuffer), &g_dwCompressBytesWritten, NULL);
  2543. CloseHandle(g_CompressLogFile);
  2544. }
  2545. }
  2546. else if ((pvs->fdwStream == ICMODE_DECOMPRESS) || (pvs->fdwStream == ICMODE_FASTDECOMPRESS))
  2547. {
  2548. if (pvs->dwFrame == 1)
  2549. g_OrigDecompressTime = g_DecompressTime;
  2550. g_aDecompressTime[pvs->dwFrame-1] = g_DecompressTime = GetTickCount() - g_DecompressTime;
  2551. if ((g_DecompressLogFile = CreateFile("C:\\VCMDLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL)) != INVALID_HANDLE_VALUE)
  2552. {
  2553. SetFilePointer(g_DecompressLogFile, 0, NULL, FILE_END);
  2554. wsprintf(g_szDecompressBuffer, "%04d\t\t%08d\t\t%05d\t\t%03d\r\n", pvs->dwFrame-1, g_OrigDecompressTime, pvs->pvfxDst->bih.biSizeImage, g_DecompressTime);
  2555. WriteFile(g_DecompressLogFile, g_szDecompressBuffer, strlen(g_szDecompressBuffer), &g_dwDecompressBytesWritten, NULL);
  2556. CloseHandle(g_DecompressLogFile);
  2557. }
  2558. }
  2559. }
  2560. #endif
  2561. // Get the handle to the video device associated to the capture window
  2562. pvsh = DeQueVCMHeader(pvs);
  2563. MarkVCMHeaderDone(pvsh);
  2564. // Test for the validity of the callback before doing this...
  2565. switch (pvs->fdwOpen)
  2566. {
  2567. case CALLBACK_FUNCTION:
  2568. (*(VCMSTREAMPROC)pvs->dwCallback)(hvs, VCM_DONE, pvs->dwCallbackInstance, (DWORD_PTR)pvsh, 0);
  2569. break;
  2570. case CALLBACK_EVENT:
  2571. SetEvent((HANDLE)pvs->dwCallback);
  2572. break;
  2573. case CALLBACK_WINDOW:
  2574. PostMessage((HWND)pvs->dwCallback, MM_VCM_DONE, (WPARAM)hvs, (LPARAM)pvsh);
  2575. break;
  2576. case CALLBACK_THREAD:
  2577. PostThreadMessage((DWORD)pvs->dwCallback, MM_VCM_DONE, (WPARAM)hvs, (LPARAM)pvsh);
  2578. break;
  2579. case CALLBACK_NULL:
  2580. default:
  2581. break;
  2582. }
  2583. return ((MMRESULT)MMSYSERR_NOERROR);
  2584. }
  2585. /****************************************************************************
  2586. * @doc EXTERNAL COMPFUNC
  2587. *
  2588. * @func MMRESULT | vcmStreamPrepareHeader | The vcmStreamPrepareHeader
  2589. * function prepares an <t VCMSTREAMHEADER> for an Video Compression
  2590. * Manager (VCM) stream conversion. This function must be called for
  2591. * every stream header before it can be used in a conversion stream. An
  2592. * application only needs to prepare a stream header once for the life of
  2593. * a given stream; the stream header can be reused as long as the same
  2594. * source and destiniation buffers are used, and the size of the source
  2595. * and destination buffers do not exceed the sizes used when the stream
  2596. * header was originally prepared.
  2597. *
  2598. * @parm HVCMSTREAM | has | Specifies a handle to the conversion steam.
  2599. *
  2600. * @parm PVCMSTREAMHEADER | pash | Specifies a pointer to an <t VCMSTREAMHEADER>
  2601. * structure that identifies the source and destination data buffers to
  2602. * be prepared.
  2603. *
  2604. * @parm DWORD | fdwPrepare | This argument is not used and must be set to
  2605. * zero.
  2606. *
  2607. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2608. * a non-zero error number. Possible error returns are:
  2609. *
  2610. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  2611. *
  2612. * @flag MMSYSERR_INVALPARAM | One or more arguments passed are invalid.
  2613. *
  2614. * @flag MMSYSERR_INVALFLAG | One or more flags are invalid.
  2615. *
  2616. * @flag MMSYSERR_NOMEM | Unable to allocate resources.
  2617. *
  2618. * @comm Preparing a stream header that has already been prepared has no
  2619. * effect, and the function returns zero. However, an application should
  2620. * take care to structure code so multiple prepares do not occur.
  2621. *
  2622. * @xref <f vcmStreamUnprepareHeader> <f vcmStreamOpen>
  2623. ***************************************************************************/
  2624. MMRESULT VCMAPI vcmStreamPrepareHeader(HVCMSTREAM hvs, PVCMSTREAMHEADER pvsh, DWORD fdwPrepare)
  2625. {
  2626. MMRESULT mmr = (MMRESULT)MMSYSERR_NOERROR;
  2627. // Check input params
  2628. if (!hvs)
  2629. {
  2630. ERRORMESSAGE(("vcmStreamPrepareHeader: Specified handle is invalid, hvs=NULL\r\n"));
  2631. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  2632. }
  2633. if (!pvsh)
  2634. {
  2635. ERRORMESSAGE(("vcmStreamPrepareHeader: Specified pointer is invalid, pvsh=NULL\r\n"));
  2636. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  2637. }
  2638. // Return if buffer has already been prepared
  2639. if (IsVCMHeaderPrepared(pvsh))
  2640. {
  2641. ERRORMESSAGE(("vcmStreamPrepareHeader: Buffer has already been prepared\r\n"));
  2642. return (mmr);
  2643. }
  2644. #ifdef REALLY_LOCK
  2645. // Lock the buffers
  2646. if (!VirtualLock(pvsh, (DWORD)sizeof(VCMSTREAMHEADER)))
  2647. {
  2648. ERRORMESSAGE(("vcmStreamPrepareHeader: VirtualLock() failed\r\n"));
  2649. mmr = (MMRESULT)MMSYSERR_NOMEM;
  2650. }
  2651. else
  2652. {
  2653. if (!VirtualLock(pvsh->pbSrc, pvsh->cbSrcLength))
  2654. {
  2655. ERRORMESSAGE(("vcmStreamPrepareHeader: VirtualLock() failed\r\n"));
  2656. VirtualUnlock(pvsh, (DWORD)sizeof(VCMSTREAMHEADER));
  2657. mmr = (MMRESULT)MMSYSERR_NOMEM;
  2658. }
  2659. else
  2660. {
  2661. if (!VirtualLock(pvsh->pbDst, pvsh->cbDstLength))
  2662. {
  2663. ERRORMESSAGE(("vcmStreamPrepareHeader: VirtualLock() failed\r\n"));
  2664. VirtualUnlock(pvsh->pbSrc, pvsh->cbSrcLength);
  2665. VirtualUnlock(pvsh, (DWORD)sizeof(VCMSTREAMHEADER));
  2666. mmr = (MMRESULT)MMSYSERR_NOMEM;
  2667. }
  2668. }
  2669. }
  2670. #endif
  2671. // Update flag
  2672. if (mmr == MMSYSERR_NOERROR)
  2673. MarkVCMHeaderPrepared(pvsh);
  2674. return (mmr);
  2675. }
  2676. /****************************************************************************
  2677. * @doc EXTERNAL COMPFUNC
  2678. *
  2679. * @func MMRESULT | vcmStreamUnprepareHeader | The vcmStreamUnprepareHeader function
  2680. * cleans up the preparation performed by the <f vcmStreamPrepareHeader>
  2681. * function for an Video Compression Manager (VCM) stream. This function must
  2682. * be called after the VCM is finished with the given buffers. An
  2683. * application must call this function before freeing the source and
  2684. * destination buffers.
  2685. *
  2686. * @parm HVCMSTREAM | has | Specifies a handle to the conversion steam.
  2687. *
  2688. * @parm PVCMSTREAMHEADER | pash | Specifies a pointer to an <t VCMSTREAMHEADER>
  2689. * structure that identifies the source and destination data buffers to
  2690. * be unprepared.
  2691. *
  2692. * @parm DWORD | fdwUnprepare | This argument is not used and must be set to
  2693. * zero.
  2694. *
  2695. * @rdesc Returns zero if the function was successful. Otherwise, it returns
  2696. * a non-zero error number. Possible error returns are:
  2697. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  2698. * @flag MMSYSERR_INVALPARAM | One or more arguments passed are invalid.
  2699. * @flag MMSYSERR_INVALFLAG | One or more flags are invalid.
  2700. * @flag VCMERR_BUSY | The stream header <p pash> is currently in use
  2701. * and cannot be unprepared.
  2702. * @flag VCMERR_UNPREPARED | The stream header <p pash> was
  2703. * not prepared by the <f vcmStreamPrepareHeader> function.
  2704. *
  2705. * @comm Unpreparing a stream header that has already been unprepared is
  2706. * an error. An application must specify the source and destination
  2707. * buffer lengths (<e VCMSTREAMHEADER.cbSrcLength> and
  2708. * <e VCMSTREAMHEADER.cbDstLength> respectively) that were used
  2709. * during the corresponding <f vcmStreamPrepareHeader> call. Failing
  2710. * to reset these member values will cause <f vcmStreamUnprepareHeader>
  2711. * to fail with MMSYSERR_INVALPARAM.
  2712. *
  2713. * Note that there are some errors that the VCM can recover from. The
  2714. * VCM will return a non-zero error, yet the stream header will be
  2715. * properly unprepared. To determine whether the stream header was
  2716. * actually unprepared an application can examine the
  2717. * VCMSTREAMHEADER_STATUSF_PREPARED flag. The header will always be
  2718. * unprepared if <f vcmStreamUnprepareHeader> returns success.
  2719. *
  2720. * @xref <f vcmStreamPrepareHeader> <f vcmStreamClose>
  2721. ***************************************************************************/
  2722. MMRESULT VCMAPI vcmStreamUnprepareHeader(HVCMSTREAM hvs, PVCMSTREAMHEADER pvsh, DWORD fdwUnprepare)
  2723. {
  2724. MMRESULT mmr = (MMRESULT)MMSYSERR_NOERROR;
  2725. // Check input params
  2726. if (!hvs)
  2727. {
  2728. ERRORMESSAGE(("vcmStreamUnprepareHeader: Specified handle is invalid, hvs=NULL\r\n"));
  2729. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  2730. }
  2731. if (!pvsh)
  2732. {
  2733. ERRORMESSAGE(("vcmStreamUnprepareHeader: Specified pointer is invalid, pvsh=NULL\r\n"));
  2734. return ((MMRESULT)MMSYSERR_INVALPARAM);
  2735. }
  2736. // Return if buffer is currently in use
  2737. if (IsVCMHeaderInQueue(pvsh))
  2738. {
  2739. ERRORMESSAGE(("vcmStreamUnprepareHeader: Buffer is currently in use\r\n"));
  2740. return ((MMRESULT)VCMERR_BUSY);
  2741. }
  2742. // Return if buffer has not been prepared
  2743. if (!IsVCMHeaderPrepared(pvsh))
  2744. {
  2745. ERRORMESSAGE(("vcmStreamUnprepareHeader: Buffer has not been prepared\r\n"));
  2746. return ((MMRESULT)VCMERR_UNPREPARED);
  2747. }
  2748. #ifdef REALLY_LOCK
  2749. // Unlock the buffers
  2750. VirtualUnlock(pvsh->pbSrc, pvsh->cbSrcLength);
  2751. VirtualUnlock(pvsh->pbDst, pvsh->cbDstLength);
  2752. VirtualUnlock(pvsh, (DWORD)sizeof(VCMSTREAMHEADER));
  2753. #endif
  2754. // Update flag
  2755. MarkVCMHeaderUnprepared(pvsh);
  2756. return ((MMRESULT)MMSYSERR_NOERROR);
  2757. }
  2758. PVCMSTREAMHEADER DeQueVCMHeader(PVCMSTREAM pvs)
  2759. {
  2760. PVCMSTREAMHEADER pvsh;
  2761. if (pvsh = pvs->pvhFirst)
  2762. {
  2763. MarkVCMHeaderUnQueued(pvsh);
  2764. pvs->pvhFirst = pvsh->pNext;
  2765. if (pvs->pvhFirst == NULL)
  2766. pvs->pvhLast = NULL;
  2767. }
  2768. return (pvsh);
  2769. }
  2770. /*****************************************************************************
  2771. * @doc INTERNAL DEVCAPSFUNC
  2772. *
  2773. * @func MMRESULT | vcmDevCapsReadFromReg | This function looks up the
  2774. * capabilities of a specified video capture input device from the registry.
  2775. *
  2776. * @parm UINT | szDeviceName | Specifies the video capture input device driver name.
  2777. *
  2778. * @parm UINT | szDeviceVersion | Specifies the video capture input device driver version.
  2779. * May be NULL.
  2780. *
  2781. * @parm PVIDEOINCAPS | pvc | Specifies a pointer to a <t VIDEOINCAPS>
  2782. * structure. This structure is filled with information about the
  2783. * capabilities of the device.
  2784. *
  2785. * @parm UINT | cbvc | Specifies the size of the <t VIDEOINCAPS> structure.
  2786. *
  2787. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  2788. * an error number. Possible error values include the following:
  2789. * @flag MMSYSERR_INVALPARAM | Specified pointer is invalid, or its content is invalid.
  2790. * @flag VCMERR_NOREGENTRY | No registry entry for specified capture device driver was found.
  2791. *
  2792. * @comm Only <p cbwc> bytes (or less) of information is copied to the location
  2793. * pointed to by <p pvc>. If <p cbwc> is zero, nothing is copied, and
  2794. * the function returns zero.
  2795. *
  2796. * @xref <f vcmGetDevCaps> <f vcmDevCapsProfile> <f vcmDevCapsWriteToReg>
  2797. ****************************************************************************/
  2798. MMRESULT VCMAPI vcmDevCapsReadFromReg(LPSTR szDeviceName, LPSTR szDeviceVersion,PVIDEOINCAPS pvc, UINT cbvc)
  2799. {
  2800. MMRESULT mmr = (MMRESULT)MMSYSERR_NOERROR;
  2801. HKEY hDeviceKey, hKey;
  2802. DWORD dwSize, dwType;
  2803. char szKey[MAX_PATH + MAX_VERSION + 2];
  2804. LONG lRet;
  2805. // Check input params
  2806. if (!szDeviceName)
  2807. {
  2808. ERRORMESSAGE(("vcmDevCapsReadFromReg: Specified pointer is invalid, szDeviceName=NULL\r\n"));
  2809. return ((MMRESULT)MMSYSERR_INVALPARAM);
  2810. }
  2811. if (szDeviceName[0] == '\0')
  2812. {
  2813. ERRORMESSAGE(("vcmDevCapsReadFromReg: Video capture input device driver name is empty\r\n"));
  2814. return ((MMRESULT)MMSYSERR_INVALPARAM);
  2815. }
  2816. if (!pvc)
  2817. {
  2818. ERRORMESSAGE(("vcmDevCapsReadFromReg: Specified pointer is invalid, pvc=NULL\r\n"));
  2819. return ((MMRESULT)MMSYSERR_INVALPARAM);
  2820. }
  2821. if (!cbvc)
  2822. {
  2823. ERRORMESSAGE(("vcmDevCapsReadFromReg: Specified structure size is invalid, cbvc=0\r\n"));
  2824. return ((MMRESULT)MMSYSERR_NOERROR);
  2825. }
  2826. // Check if the main capture devices key is there
  2827. if (RegOpenKey(HKEY_LOCAL_MACHINE, szRegDeviceKey, &hDeviceKey) != ERROR_SUCCESS)
  2828. return ((MMRESULT)VCMERR_NOREGENTRY);
  2829. //If we have version info use that to build the key name
  2830. if (szDeviceVersion) {
  2831. wsprintf(szKey, "%s, %s", szDeviceName, szDeviceVersion);
  2832. } else {
  2833. wsprintf(szKey, "%s", szDeviceName);
  2834. }
  2835. // Check if there already is a key for the current device
  2836. if (RegOpenKey(hDeviceKey, szKey, &hKey) != ERROR_SUCCESS)
  2837. {
  2838. mmr = (MMRESULT)VCMERR_NOREGENTRY;
  2839. goto MyExit0;
  2840. }
  2841. // Get the values stored in the key
  2842. dwSize = sizeof(DWORD);
  2843. RegQueryValueEx(hKey, (LPTSTR)szRegdwImageSizeKey, NULL, &dwType, (LPBYTE)&pvc->dwImageSize, &dwSize);
  2844. dwSize = sizeof(DWORD);
  2845. RegQueryValueEx(hKey, (LPTSTR)szRegdwNumColorsKey, NULL, &dwType, (LPBYTE)&pvc->dwNumColors, &dwSize);
  2846. dwSize = sizeof(DWORD);
  2847. pvc->dwStreamingMode = STREAMING_PREFER_FRAME_GRAB;
  2848. RegQueryValueEx(hKey, (LPTSTR)szRegdwStreamingModeKey, NULL, &dwType, (LPBYTE)&pvc->dwStreamingMode, &dwSize);
  2849. dwSize = sizeof(DWORD);
  2850. pvc->dwDialogs = FORMAT_DLG_OFF | SOURCE_DLG_ON;
  2851. RegQueryValueEx(hKey, (LPTSTR)szRegdwDialogsKey, NULL, &dwType, (LPBYTE)&pvc->dwDialogs, &dwSize);
  2852. // Check dwNumColors to figure out if we need to read the palettes too
  2853. if (pvc->dwNumColors & VIDEO_FORMAT_NUM_COLORS_16)
  2854. {
  2855. dwSize = NUM_4BIT_ENTRIES * sizeof(RGBQUAD);
  2856. if (RegQueryValueEx(hKey, (LPTSTR)szRegbmi4bitColorsKey, NULL, &dwType,
  2857. (LPBYTE)&pvc->bmi4bitColors[0], &dwSize) == ERROR_SUCCESS) {
  2858. pvc->dwFlags |= VICF_4BIT_TABLE;
  2859. }
  2860. else
  2861. FillMemory ((LPBYTE)&pvc->bmi4bitColors[0], NUM_4BIT_ENTRIES * sizeof(RGBQUAD), 0);
  2862. }
  2863. if (pvc->dwNumColors & VIDEO_FORMAT_NUM_COLORS_256)
  2864. {
  2865. dwSize = NUM_8BIT_ENTRIES * sizeof(RGBQUAD);
  2866. if (RegQueryValueEx(hKey, (LPTSTR)szRegbmi8bitColorsKey, NULL, &dwType,
  2867. (LPBYTE)&pvc->bmi8bitColors[0], &dwSize) == ERROR_SUCCESS) {
  2868. pvc->dwFlags |= VICF_8BIT_TABLE;
  2869. }
  2870. else
  2871. FillMemory ((LPBYTE)&pvc->bmi8bitColors[0], NUM_8BIT_ENTRIES * sizeof(RGBQUAD), 0);
  2872. }
  2873. // Close the registry keys
  2874. RegCloseKey(hKey);
  2875. MyExit0:
  2876. RegCloseKey(hDeviceKey);
  2877. return (mmr);
  2878. }
  2879. /*****************************************************************************
  2880. * @doc INTERNAL DEVCAPSFUNC
  2881. *
  2882. * @func MMRESULT | vcmDevCapsProfile | This function profiles the video capture
  2883. * input device to figure out its capabilities.
  2884. *
  2885. * @parm PVIDEOINCAPS | pvc | Specifies a pointer to a <t VIDEOINCAPS>
  2886. * structure. This structure is filled with information about the
  2887. * capabilities of the device.
  2888. *
  2889. * @parm UINT | cbvc | Specifies the size of the <t VIDEOINCAPS> structure.
  2890. *
  2891. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  2892. * an error number. Possible error values include the following:
  2893. * @flag MMSYSERR_INVALPARAM | Specified pointer is invalid, or its content is invalid.
  2894. * @flag MMSYSERR_NOMEM | A memory allocation failed.
  2895. * @flag MMSYSERR_NODRIVER | No capture device driver or device is present.
  2896. * @flag VCMERR_NONSPECIFIC | The capture driver failed to provide description information.
  2897. *
  2898. * @comm Only <p cbwc> bytes (or less) of information is copied to the location
  2899. * pointed to by <p pvc>. If <p cbwc> is zero, nothing is copied, and
  2900. * the function returns zero.
  2901. *
  2902. * @xref <f vcmGetDevCaps> <f videoDevCapsReadFromReg> <f videoDevCapsWriteToReg>
  2903. ****************************************************************************/
  2904. MMRESULT VCMAPI vcmDevCapsProfile(UINT uDevice, PVIDEOINCAPS pvc, UINT cbvc)
  2905. {
  2906. MMRESULT mmr = (MMRESULT)MMSYSERR_NOERROR;
  2907. FINDCAPTUREDEVICE fcd;
  2908. LPBITMAPINFO lpbmi;
  2909. HCAPDEV hCapDev = (HCAPDEV)NULL;
  2910. int k,l;
  2911. BOOL b4bitPalInitialized = FALSE;
  2912. BOOL b8bitPalInitialized = FALSE;
  2913. BOOL bRet;
  2914. // Check input params
  2915. if (!pvc)
  2916. {
  2917. ERRORMESSAGE(("vcmDevCapsProfile: Specified pointer is invalid, pvc=NULL\r\n"));
  2918. return ((MMRESULT)MMSYSERR_INVALPARAM);
  2919. }
  2920. if (!cbvc)
  2921. {
  2922. ERRORMESSAGE(("vcmDevCapsProfile: Specified structure size is invalid, cbvc=0\r\n"));
  2923. return ((MMRESULT)MMSYSERR_NOERROR);
  2924. }
  2925. // Check input params
  2926. if ((uDevice >= MAXVIDEODRIVERS) && (uDevice != VIDEO_MAPPER))
  2927. {
  2928. ERRORMESSAGE(("vcmGetDevCaps: Specified capture device ID is invalid, uDevice=%ld (expected values are 0x%lX or between 0 and %ld)\r\n", uDevice, VIDEO_MAPPER, MAXVIDEODRIVERS-1));
  2929. return ((MMRESULT)MMSYSERR_BADDEVICEID);
  2930. }
  2931. // Allocate space for BMIH and palette
  2932. if ((lpbmi = (LPBITMAPINFO)MemAlloc(sizeof(BITMAPINFOHEADER) + NUM_8BIT_ENTRIES * sizeof(RGBQUAD))) == NULL)
  2933. {
  2934. ERRORMESSAGE(("vcmDevCapsProfile: BMIH and palette allocation failed\r\n"));
  2935. return ((MMRESULT)MMSYSERR_NOMEM);
  2936. }
  2937. // For now, always set the preferred streaming mode to STREAMING_PREFER_FRAME_GRAB
  2938. // But in the future, do some real profiling...
  2939. pvc->dwStreamingMode = STREAMING_PREFER_FRAME_GRAB;
  2940. pvc->dwDialogs = FORMAT_DLG_OFF | SOURCE_DLG_OFF;
  2941. lpbmi->bmiHeader.biPlanes = 1;
  2942. // if VIDEO_MAPPER: use first capture device
  2943. fcd.dwSize = sizeof (FINDCAPTUREDEVICE);
  2944. if (uDevice == VIDEO_MAPPER)
  2945. {
  2946. bRet = FindFirstCaptureDevice(&fcd, NULL);
  2947. }
  2948. else
  2949. bRet = FindFirstCaptureDeviceByIndex(&fcd, uDevice);
  2950. if (bRet)
  2951. hCapDev = OpenCaptureDevice(fcd.nDeviceIndex);
  2952. if (hCapDev != NULL)
  2953. {
  2954. // If the driver exposes a source dialog, there is no need to go further:
  2955. // we advertise this dialog and that's it. On the other hand, if there isn't
  2956. // a source dialog per se, it may be hidden in the format dialog, in which case
  2957. // we advertise the format dialog.
  2958. if (CaptureDeviceDialog(hCapDev, (HWND)NULL, CAPDEV_DIALOG_SOURCE | CAPDEV_DIALOG_QUERY, NULL))
  2959. pvc->dwDialogs |= SOURCE_DLG_ON;
  2960. else
  2961. if (CaptureDeviceDialog(hCapDev, (HWND)NULL, CAPDEV_DIALOG_IMAGE | CAPDEV_DIALOG_QUERY, NULL))
  2962. pvc->dwDialogs |= FORMAT_DLG_ON;
  2963. // since we don't know anything about this adapter, we just use its default format
  2964. // and report that we can get any size, which we will do through conversion
  2965. // we will report the correct color depth only if the default size matches one of
  2966. // our sizes, we'll always report 24bit color
  2967. pvc->dwImageSize |= VIDEO_FORMAT_IMAGE_SIZE_USE_DEFAULT;
  2968. // get the device's default format
  2969. lpbmi->bmiHeader.biSize = GetCaptureDeviceFormatHeaderSize(hCapDev);
  2970. GetCaptureDeviceFormat(hCapDev, (LPBITMAPINFOHEADER)lpbmi);
  2971. // record this default in the registry
  2972. if (pvc->szDeviceName[0] != '\0') {
  2973. vcmDefaultFormatWriteToReg(pvc->szDeviceName, pvc->szDeviceVersion, (LPBITMAPINFOHEADER)lpbmi);
  2974. } else {
  2975. //Fall back and use driver name as the key
  2976. vcmDefaultFormatWriteToReg(fcd.szDeviceName, pvc->szDeviceVersion, (LPBITMAPINFOHEADER)lpbmi);
  2977. }
  2978. if ((lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_BI_RGB) ||
  2979. (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_YVU9) ||
  2980. (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_YUY2) ||
  2981. (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_UYVY) ||
  2982. (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_I420) ||
  2983. (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_IYUV)) {
  2984. if (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_YVU9)
  2985. k = VIDEO_FORMAT_NUM_COLORS_YVU9;
  2986. else if (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_YUY2)
  2987. k = VIDEO_FORMAT_NUM_COLORS_YUY2;
  2988. else if (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_UYVY)
  2989. k = VIDEO_FORMAT_NUM_COLORS_UYVY;
  2990. else if (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_I420)
  2991. k = VIDEO_FORMAT_NUM_COLORS_I420;
  2992. else if (lpbmi->bmiHeader.biCompression == VIDEO_FORMAT_IYUV)
  2993. k = VIDEO_FORMAT_NUM_COLORS_IYUV;
  2994. else {
  2995. for (k = 0; k < NUM_BITDEPTH_ENTRIES; k++) {
  2996. if (lpbmi->bmiHeader.biBitCount == g_aiBitDepth[k])
  2997. break;
  2998. }
  2999. if (k < NUM_BITDEPTH_ENTRIES)
  3000. k = g_aiNumColors[k];
  3001. else
  3002. k = 0;
  3003. }
  3004. }
  3005. // converted sizes will probably get to RGB24, so always say that we support it
  3006. pvc->dwNumColors |= VIDEO_FORMAT_NUM_COLORS_16777216;
  3007. // always say that we support these 2 standard formats
  3008. pvc->dwImageSize |= VIDEO_FORMAT_IMAGE_SIZE_176_144 | VIDEO_FORMAT_IMAGE_SIZE_128_96;
  3009. for (l=0; l<VIDEO_FORMAT_NUM_RESOLUTIONS; l++) {
  3010. if ((lpbmi->bmiHeader.biWidth == (LONG)g_awResolutions[l].framesize.biWidth) &&
  3011. (lpbmi->bmiHeader.biHeight == (LONG)g_awResolutions[l].framesize.biHeight)) {
  3012. pvc->dwImageSize |= g_awResolutions[l].dwRes;
  3013. pvc->dwNumColors |= k;
  3014. break;
  3015. }
  3016. }
  3017. }
  3018. else
  3019. mmr = (MMRESULT)MMSYSERR_NODRIVER;
  3020. // Close capture device
  3021. if (hCapDev)
  3022. CloseCaptureDevice(hCapDev);
  3023. // Free BMIH + palette space
  3024. if (lpbmi)
  3025. MemFree(lpbmi);
  3026. return (mmr);
  3027. }
  3028. /*****************************************************************************
  3029. * @doc EXTERNAL DEVCAPSFUNC
  3030. *
  3031. * @func MMRESULT | vcmDevCapsWriteToReg | This function writes the
  3032. * capabilities of a specified video capture input device into the registry.
  3033. *
  3034. * @parm UINT | szDeviceName | Specifies the video capture input device driver name.
  3035. *
  3036. * @parm UINT | szDeviceVersion | Specifies the video capture input device driver version.
  3037. * May be NULL.
  3038. *
  3039. * @parm PVIDEOINCAPS | pvc | Specifies a pointer to a <t VIDEOINCAPS>
  3040. * structure. This structure is filled with information about the
  3041. * capabilities of the device.
  3042. *
  3043. * @parm UINT | cbvc | Specifies the size of the <t VIDEOINCAPS> structure.
  3044. *
  3045. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3046. * an error number. Possible error values include the following:
  3047. * @flag MMSYSERR_INVALPARAM | Specified pointer is invalid, or its content is invalid.
  3048. * @flag VCMERR_NOREGENTRY | No registry entry could be created for the specified capture device driver.
  3049. *
  3050. * @comm Only <p cbwc> bytes (or less) of information is copied to the location
  3051. * pointed to by <p pvc>. If <p cbwc> is zero, nothing is copied, and
  3052. * the function returns zero.
  3053. *
  3054. * @xref <f vcmGetDevCaps> <f videoDevCapsProfile> <f videoDevCapsWriteToReg>
  3055. ****************************************************************************/
  3056. MMRESULT VCMAPI vcmDevCapsWriteToReg(LPSTR szDeviceName, LPSTR szDeviceVersion, PVIDEOINCAPS pvc, UINT cbvc)
  3057. {
  3058. HKEY hDeviceKey;
  3059. HKEY hKey;
  3060. DWORD dwDisposition;
  3061. DWORD dwSize;
  3062. char szKey[MAX_PATH + MAX_VERSION + 2];
  3063. // Check input params
  3064. if (!szDeviceName)
  3065. {
  3066. ERRORMESSAGE(("vcmDevCapsWriteToReg: Specified pointer is invalid, szDeviceName=NULL\r\n"));
  3067. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3068. }
  3069. if (szDeviceName[0] == '\0')
  3070. {
  3071. ERRORMESSAGE(("vcmDevCapsWriteToReg: Video capture input device driver name is empty\r\n"));
  3072. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3073. }
  3074. if (!pvc)
  3075. {
  3076. ERRORMESSAGE(("vcmDevCapsWriteToReg: Specified pointer is invalid, pvc=NULL\r\n"));
  3077. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3078. }
  3079. if (!cbvc)
  3080. {
  3081. ERRORMESSAGE(("vcmDevCapsWriteToReg: Specified structure size is invalid, cbvc=0\r\n"));
  3082. return ((MMRESULT)MMSYSERR_NOERROR);
  3083. }
  3084. // Open the main capture devices key, or create it if it doesn't exist
  3085. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegDeviceKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hDeviceKey, &dwDisposition) != ERROR_SUCCESS)
  3086. return ((MMRESULT)VCMERR_NOREGENTRY);
  3087. //If we have version info use that to build the key name
  3088. if (szDeviceVersion && szDeviceVersion[0] != '\0') {
  3089. wsprintf(szKey, "%s, %s", szDeviceName, szDeviceVersion);
  3090. } else {
  3091. wsprintf(szKey, "%s", szDeviceName);
  3092. }
  3093. // Check if there already is a key for the current device
  3094. // Open the key for the current device, or create the key if it doesn't exist
  3095. if (RegCreateKeyEx(hDeviceKey, szKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS)
  3096. return ((MMRESULT)VCMERR_NOREGENTRY);
  3097. // Set the values in the key
  3098. dwSize = sizeof(DWORD);
  3099. RegSetValueEx(hKey, (LPTSTR)szRegdwImageSizeKey, (DWORD)NULL, REG_DWORD, (LPBYTE)&pvc->dwImageSize, dwSize);
  3100. dwSize = sizeof(DWORD);
  3101. RegSetValueEx(hKey, (LPTSTR)szRegdwNumColorsKey, (DWORD)NULL, REG_DWORD, (LPBYTE)&pvc->dwNumColors, dwSize);
  3102. dwSize = sizeof(DWORD);
  3103. RegSetValueEx(hKey, (LPTSTR)szRegdwStreamingModeKey, (DWORD)NULL, REG_DWORD, (LPBYTE)&pvc->dwStreamingMode, dwSize);
  3104. dwSize = sizeof(DWORD);
  3105. RegSetValueEx(hKey, (LPTSTR)szRegdwDialogsKey, (DWORD)NULL, REG_DWORD, (LPBYTE)&pvc->dwDialogs, dwSize);
  3106. // Check dwNumColors to figure out if we need to set the palettes too
  3107. if (pvc->dwNumColors & VIDEO_FORMAT_NUM_COLORS_16)
  3108. {
  3109. dwSize = NUM_4BIT_ENTRIES * sizeof(RGBQUAD);
  3110. RegSetValueEx(hKey, (LPTSTR)szRegbmi4bitColorsKey, (DWORD)NULL, REG_BINARY, (LPBYTE)&pvc->bmi4bitColors[0], dwSize);
  3111. }
  3112. if (pvc->dwNumColors & VIDEO_FORMAT_NUM_COLORS_256)
  3113. {
  3114. dwSize = NUM_8BIT_ENTRIES * sizeof(RGBQUAD);
  3115. RegSetValueEx(hKey, (LPTSTR)szRegbmi8bitColorsKey, (DWORD)NULL, REG_BINARY, (LPBYTE)&pvc->bmi8bitColors[0], dwSize);
  3116. }
  3117. // Close the keys
  3118. RegCloseKey(hKey);
  3119. RegCloseKey(hDeviceKey);
  3120. return ((MMRESULT)MMSYSERR_NOERROR);
  3121. }
  3122. MMRESULT VCMAPI vcmDefaultFormatWriteToReg(LPSTR szDeviceName, LPSTR szDeviceVersion, LPBITMAPINFOHEADER lpbmih)
  3123. {
  3124. HKEY hDeviceKey;
  3125. HKEY hKey;
  3126. DWORD dwDisposition;
  3127. DWORD dwSize;
  3128. char szKey[MAX_PATH + MAX_VERSION + 2];
  3129. char szFOURCC[5];
  3130. // Check input params
  3131. if (!szDeviceName)
  3132. {
  3133. ERRORMESSAGE(("vcmDefaultFormatWriteToReg: Specified pointer is invalid, szDeviceName=NULL\r\n"));
  3134. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3135. }
  3136. if (szDeviceName[0] == '\0')
  3137. {
  3138. ERRORMESSAGE(("vcmDefaultFormatWriteToReg: Video capture input device driver name is empty\r\n"));
  3139. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3140. }
  3141. if (!lpbmih)
  3142. {
  3143. ERRORMESSAGE(("vcmDefaultFormatWriteToReg: Specified pointer is invalid, lpbmih=NULL\r\n"));
  3144. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3145. }
  3146. // Open the main capture devices key, or create it if it doesn't exist
  3147. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRegCaptureDefaultKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hDeviceKey, &dwDisposition) != ERROR_SUCCESS)
  3148. return ((MMRESULT)VCMERR_NOREGENTRY);
  3149. //If we have version info use that to build the key name
  3150. if (szDeviceVersion && szDeviceVersion[0] != '\0') {
  3151. wsprintf(szKey, "%s, %s", szDeviceName, szDeviceVersion);
  3152. } else {
  3153. wsprintf(szKey, "%s", szDeviceName);
  3154. }
  3155. // Check if there already is a key for the current device
  3156. // Open the key for the current device, or create the key if it doesn't exist
  3157. if (RegCreateKeyEx(hDeviceKey, szKey, 0, 0, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS)
  3158. return ((MMRESULT)VCMERR_NOREGENTRY);
  3159. if (lpbmih->biCompression == BI_RGB)
  3160. wsprintf(szFOURCC, "RGB");
  3161. else {
  3162. *((DWORD*)&szFOURCC) = lpbmih->biCompression;
  3163. szFOURCC[4] = '\0';
  3164. }
  3165. dwSize = wsprintf(szKey, "%s, %dx%dx%d", szFOURCC, lpbmih->biWidth, lpbmih->biHeight, lpbmih->biBitCount);
  3166. RegSetValueEx(hKey, (LPTSTR)szRegDefaultFormatKey, (DWORD)NULL, REG_SZ, (CONST BYTE *)szKey, dwSize+1);
  3167. // Close the keys
  3168. RegCloseKey(hKey);
  3169. RegCloseKey(hDeviceKey);
  3170. return ((MMRESULT)MMSYSERR_NOERROR);
  3171. }
  3172. /*****************************************************************************
  3173. * @doc EXTERNAL DEVCAPSFUNC
  3174. *
  3175. * @func MMRESULT | vcmGetDevCapsPreferredFormatTag | This function queries a specified
  3176. * video capture input device to determine the format tag it will be effectively
  3177. * capturing at.
  3178. *
  3179. * @parm UINT | uDevice | Specifies the video capture input device ID.
  3180. *
  3181. * @parm PINT | pbiWidth | Specifies a pointer to the actual width
  3182. * the capture will be performed at.
  3183. *
  3184. * @parm PINT | pbiHeight | Specifies a pointer to the actual height
  3185. * the capture will be performed at.
  3186. *
  3187. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3188. * an error number. Possible error values include the following:
  3189. * @flag MMSYSERR_INVALPARAM | Specified pointer to structure is invalid.
  3190. * @flag MMSYSERR_BADDEVICEID | Specified device device ID is invalid.
  3191. * @flag VCMERR_NONSPECIFIC | The capture driver failed to provide valid information.
  3192. *
  3193. * @xref <f vcmGetDevCaps>
  3194. ****************************************************************************/
  3195. MMRESULT VCMAPI vcmGetDevCapsPreferredFormatTag(UINT uDevice, PDWORD pdwFormatTag)
  3196. {
  3197. MMRESULT mmr = (MMRESULT)MMSYSERR_NOERROR;
  3198. VIDEOINCAPS vic;
  3199. int i;
  3200. // Check input params
  3201. if (!pdwFormatTag)
  3202. {
  3203. ERRORMESSAGE(("vcmGetDevCapsPreferredFormatTag: Specified pointer is invalid, pdwFormatTag=NULL\r\n"));
  3204. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3205. }
  3206. if ((uDevice >= MAXVIDEODRIVERS) && (uDevice != VIDEO_MAPPER))
  3207. {
  3208. ERRORMESSAGE(("vcmGetDevCapsPreferredFormatTag: Specified capture device ID is invalid, uDevice=%ld (expected values are 0x%lX or between 0 and %ld)\r\n", uDevice, VIDEO_MAPPER, MAXVIDEODRIVERS-1));
  3209. return ((MMRESULT)MMSYSERR_BADDEVICEID);
  3210. }
  3211. // Get the capabilities of the capture hardware
  3212. if ((mmr = vcmGetDevCaps(uDevice, &vic, sizeof(VIDEOINCAPS))) != MMSYSERR_NOERROR)
  3213. return (mmr);
  3214. // WE prefer to use I420 or IYUV, YVU9, YUY2, UYVY, RGB16, RGB24, RGB4, RGB8 in that order.
  3215. for (i=0; i<NUM_BITDEPTH_ENTRIES; i++)
  3216. if (g_aiNumColors[i] & vic.dwNumColors)
  3217. break;
  3218. if (i == NUM_BITDEPTH_ENTRIES)
  3219. return ((MMRESULT)VCMERR_NONSPECIFIC);
  3220. else
  3221. *pdwFormatTag = g_aiFourCCCode[i];
  3222. return ((MMRESULT)MMSYSERR_NOERROR);
  3223. }
  3224. /*****************************************************************************
  3225. * @doc EXTERNAL DEVCAPSFUNC
  3226. *
  3227. * @func MMRESULT | vcmGetDevCapsStreamingMode | This function queries a specified
  3228. * video capture input device to determine its preferred streaming mode.
  3229. *
  3230. * @parm UINT | uDevice | Specifies the video capture input device ID.
  3231. *
  3232. * @parm PDWORD | pdwStreamingMode | Specifies a pointer to the preferred streaming mode.
  3233. *
  3234. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3235. * an error number. Possible error values include the following:
  3236. * @flag MMSYSERR_INVALPARAM | Specified pointer to structure is invalid.
  3237. * @flag MMSYSERR_BADDEVICEID | Specified device device ID is invalid.
  3238. * @flag VCMERR_NONSPECIFIC | The capture driver failed to provide valid information.
  3239. *
  3240. * @xref <f vcmGetDevCaps>
  3241. ****************************************************************************/
  3242. MMRESULT VCMAPI vcmGetDevCapsStreamingMode(UINT uDevice, PDWORD pdwStreamingMode)
  3243. {
  3244. MMRESULT mmr = (MMRESULT)MMSYSERR_NOERROR;
  3245. VIDEOINCAPS vic;
  3246. // Check input params
  3247. if (!pdwStreamingMode)
  3248. {
  3249. ERRORMESSAGE(("vcmGetDevCapsStreamingMode: Specified pointer is invalid, pdwStreamingMode=NULL\r\n"));
  3250. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3251. }
  3252. if ((uDevice >= MAXVIDEODRIVERS) && (uDevice != VIDEO_MAPPER))
  3253. {
  3254. ERRORMESSAGE(("vcmGetDevCapsStreamingMode: Specified capture device ID is invalid, uDevice=%ld (expected values are 0x%lX or between 0 and %ld)\r\n", uDevice, VIDEO_MAPPER, MAXVIDEODRIVERS-1));
  3255. return ((MMRESULT)MMSYSERR_BADDEVICEID);
  3256. }
  3257. // Get the capabilities of the capture hardware
  3258. if ((mmr = vcmGetDevCaps(uDevice, &vic, sizeof(VIDEOINCAPS))) != MMSYSERR_NOERROR)
  3259. return (mmr);
  3260. // Get the streaming mode.
  3261. *pdwStreamingMode = vic.dwStreamingMode;
  3262. return ((MMRESULT)MMSYSERR_NOERROR);
  3263. }
  3264. /*****************************************************************************
  3265. * @doc EXTERNAL DEVCAPSFUNC
  3266. *
  3267. * @func MMRESULT | vcmGetDevCapsDialogs | This function queries a specified
  3268. * video capture input device to determine if its dialog and source format
  3269. * its should be exposed.
  3270. *
  3271. * @parm UINT | uDevice | Specifies the video capture input device ID.
  3272. *
  3273. * @parm PDWORD | pdwDialogs | Specifies a pointer to the dialogs to be exposed.
  3274. *
  3275. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3276. * an error number. Possible error values include the following:
  3277. * @flag MMSYSERR_INVALPARAM | Specified pointer to structure is invalid.
  3278. * @flag MMSYSERR_BADDEVICEID | Specified device device ID is invalid.
  3279. * @flag VCMERR_NONSPECIFIC | The capture driver failed to provide valid information.
  3280. *
  3281. * @xref <f vcmGetDevCaps>
  3282. ****************************************************************************/
  3283. MMRESULT VCMAPI vcmGetDevCapsDialogs(UINT uDevice, PDWORD pdwDialogs)
  3284. {
  3285. MMRESULT mmr = (MMRESULT)MMSYSERR_NOERROR;
  3286. VIDEOINCAPS vic;
  3287. // Check input params
  3288. if (!pdwDialogs)
  3289. {
  3290. ERRORMESSAGE(("vcmGetDevCapsDialogs: Specified pointer is invalid, pdwDialogs=NULL\r\n"));
  3291. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3292. }
  3293. if ((uDevice >= MAXVIDEODRIVERS) && (uDevice != VIDEO_MAPPER))
  3294. {
  3295. ERRORMESSAGE(("vcmGetDevCapsDialogs: Specified capture device ID is invalid, uDevice=%ld (expected values are 0x%lX or between 0 and %ld)\r\n", uDevice, VIDEO_MAPPER, MAXVIDEODRIVERS-1));
  3296. return ((MMRESULT)MMSYSERR_BADDEVICEID);
  3297. }
  3298. // Get the capabilities of the capture hardware
  3299. if ((mmr = vcmGetDevCaps(uDevice, &vic, sizeof(VIDEOINCAPS))) != MMSYSERR_NOERROR)
  3300. return (mmr);
  3301. // Get the streaming mode.
  3302. *pdwDialogs = vic.dwDialogs;
  3303. return ((MMRESULT)MMSYSERR_NOERROR);
  3304. }
  3305. /****************************************************************************
  3306. * @doc EXTERNAL COMPFUNC
  3307. *
  3308. * @func MMRESULT | vcmStreamSetBrightness | This function sends a user-defined
  3309. * message to a given Video Compression Manager (VCM) stream instance to set
  3310. * the brightness of the decompressed images. The brightness is a value defined
  3311. * between 0 and 255. The brightness can also be reset by passing a value equal
  3312. * to VCM_RESET_BRIGHTNESS.
  3313. *
  3314. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  3315. *
  3316. * @parm DWORD | dwBrightness | Specifies the value of the brightness requested.
  3317. *
  3318. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3319. * an error number. Possible error values include the following:
  3320. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  3321. * @flag MMSYSERR_INVALPARAM | Specified brightness value is invalid.
  3322. * @flag MMSYSERR_NOTSUPPORTED | The VCM driver cannot set the brightness.
  3323. *
  3324. * @xref <f vcmStreamMessage>
  3325. ***************************************************************************/
  3326. MMRESULT VCMAPI vcmStreamSetBrightness(HVCMSTREAM hvs, DWORD dwBrightness)
  3327. {
  3328. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  3329. // Check input params
  3330. if (!hvs)
  3331. {
  3332. ERRORMESSAGE(("vcmStreamSetBrightness: Specified HVCMSTREAM handle is invalid, hvs=NULL\r\n"));
  3333. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  3334. }
  3335. if ((dwBrightness != VCM_RESET_BRIGHTNESS) && ((dwBrightness > VCM_MAX_BRIGHTNESS) || (dwBrightness < VCM_MIN_BRIGHTNESS)))
  3336. {
  3337. ERRORMESSAGE(("vcmStreamSetBrightness: Specified brightness value is invalid, dwBrightness=%ld (expected value is between %ld and %ld)\r\n", dwBrightness, VCM_MIN_BRIGHTNESS, VCM_MAX_BRIGHTNESS));
  3338. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3339. }
  3340. // Only our (intel h.263) codec supports this. If the codec used is different,
  3341. // that's Ok: no need to return an error.
  3342. #if !defined(_ALPHA_) && defined(USE_BILINEAR_MSH26X)
  3343. if (pvs->pvfxSrc && ((pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH263) || (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH26X)))
  3344. #else
  3345. if (pvs->pvfxSrc && (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH263))
  3346. #endif
  3347. vcmStreamMessage(hvs, PLAYBACK_CUSTOM_CHANGE_BRIGHTNESS, (dwBrightness != VCM_RESET_BRIGHTNESS) ? (LPARAM)dwBrightness : (LPARAM)VCM_DEFAULT_BRIGHTNESS, (LPARAM)0);
  3348. return ((MMRESULT)MMSYSERR_NOERROR);
  3349. }
  3350. /****************************************************************************
  3351. * @doc EXTERNAL COMPFUNC
  3352. *
  3353. * @func MMRESULT | vcmStreamSetContrast | This function sends a user-defined
  3354. * message to a given Video Compression Manager (VCM) stream instance to set
  3355. * the contrast of the decompressed images. The contrast is a value defined
  3356. * between 0 and 255. The contrast can also be reset by passing a value equal
  3357. * to VCM_RESET_CONTRAST.
  3358. *
  3359. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  3360. *
  3361. * @parm DWORD | dwContrast | Specifies the value of the contrast requested.
  3362. *
  3363. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3364. * an error number. Possible error values include the following:
  3365. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  3366. * @flag MMSYSERR_INVALPARAM | Specified contrast value is invalid.
  3367. * @flag MMSYSERR_NOTSUPPORTED | The VCM driver cannot set the contrast.
  3368. *
  3369. * @xref <f vcmStreamMessage>
  3370. ***************************************************************************/
  3371. MMRESULT VCMAPI vcmStreamSetContrast(HVCMSTREAM hvs, DWORD dwContrast)
  3372. {
  3373. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  3374. // Check input params
  3375. if (!hvs)
  3376. {
  3377. ERRORMESSAGE(("vcmStreamSetContrast: Specified handle is invalid, hvs=NULL\r\n"));
  3378. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  3379. }
  3380. if ((dwContrast != VCM_RESET_CONTRAST) && ((dwContrast > VCM_MAX_CONTRAST) || (dwContrast < VCM_MIN_CONTRAST)))
  3381. {
  3382. ERRORMESSAGE(("vcmStreamSetContrast: Specified contrast value is invalid, dwContrast=%ld (expected value is between %ld and %ld)\r\n", dwContrast, VCM_MIN_CONTRAST, VCM_MAX_CONTRAST));
  3383. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3384. }
  3385. // Only our (intel ) codec supports this. If the codec used is different,
  3386. // that's Ok: no need to return an error.
  3387. #if !defined(_ALPHA_) && defined(USE_BILINEAR_MSH26X)
  3388. if (pvs->pvfxSrc && ((pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH263) || (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH26X)))
  3389. #else
  3390. if (pvs->pvfxSrc && (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH263))
  3391. #endif
  3392. vcmStreamMessage(hvs, PLAYBACK_CUSTOM_CHANGE_CONTRAST, (dwContrast != VCM_RESET_CONTRAST) ? (LPARAM)dwContrast : (LPARAM)VCM_DEFAULT_CONTRAST, (LPARAM)0);
  3393. return ((MMRESULT)MMSYSERR_NOERROR);
  3394. }
  3395. /****************************************************************************
  3396. * @doc EXTERNAL COMPFUNC
  3397. *
  3398. * @func MMRESULT | vcmStreamSetSaturation | This function sends a user-defined
  3399. * message to a given Video Compression Manager (VCM) stream instance to set
  3400. * the saturation of the decompressed images. The saturation is a value defined
  3401. * between 0 and 255. The saturation can also be reset by passing a value equal
  3402. * to VCM_RESET_SATURATION.
  3403. *
  3404. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  3405. *
  3406. * @parm DWORD | dwSaturation | Specifies the value of the saturation requested.
  3407. *
  3408. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3409. * an error number. Possible error values include the following:
  3410. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  3411. * @flag MMSYSERR_INVALPARAM | Specified saturation value is invalid.
  3412. * @flag MMSYSERR_NOTSUPPORTED | The VCM driver cannot set the saturation.
  3413. *
  3414. * @xref <f vcmStreamMessage>
  3415. ***************************************************************************/
  3416. MMRESULT VCMAPI vcmStreamSetSaturation(HVCMSTREAM hvs, DWORD dwSaturation)
  3417. {
  3418. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  3419. // Check input params
  3420. if (!hvs)
  3421. {
  3422. ERRORMESSAGE(("vcmStreamSetSaturation: Specified handle is invalid, hvs=NULL\r\n"));
  3423. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  3424. }
  3425. if ((dwSaturation != VCM_RESET_SATURATION) && ((dwSaturation > VCM_MAX_SATURATION) || (dwSaturation < VCM_MIN_SATURATION)))
  3426. {
  3427. ERRORMESSAGE(("vcmStreamSetSaturation: Specified saturation value is invalid, dwSaturation=%ld (expected value is between %ld and %ld)\r\n", dwSaturation, VCM_MIN_SATURATION, VCM_MAX_SATURATION));
  3428. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3429. }
  3430. // Only our (H.263 intel) codec supports this. If the codec used is different,
  3431. // that's Ok: no need to return an error.
  3432. #if !defined(_ALPHA_) && defined(USE_BILINEAR_MSH26X)
  3433. if (pvs->pvfxSrc && ((pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH263) || (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH26X)))
  3434. #else
  3435. if (pvs->pvfxSrc && (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH263))
  3436. #endif
  3437. vcmStreamMessage(hvs, PLAYBACK_CUSTOM_CHANGE_SATURATION, (dwSaturation != VCM_RESET_SATURATION) ? (LPARAM)dwSaturation : (LPARAM)VCM_DEFAULT_SATURATION, (LPARAM)0);
  3438. return ((MMRESULT)MMSYSERR_NOERROR);
  3439. }
  3440. /****************************************************************************
  3441. * @doc EXTERNAL COMPFUNC
  3442. *
  3443. * @func MMRESULT | vcmStreamIsPostProcessingSupported | This function is used to find
  3444. * out if the decompressor can post-process the decompressed image to, for
  3445. * instance, modify its brightness, contrast or saturation.
  3446. *
  3447. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  3448. *
  3449. * @rdesc The return value is TRUE if the decompressor supports post-processing. Otherwise, it returns FALSE.
  3450. *
  3451. * @xref <f vcmStreamMessage>
  3452. ***************************************************************************/
  3453. BOOL VCMAPI vcmStreamIsPostProcessingSupported(HVCMSTREAM hvs)
  3454. {
  3455. // Check input params
  3456. if (!hvs)
  3457. return (FALSE);
  3458. // Put the code that checks this property right here!!!
  3459. return (FALSE);
  3460. }
  3461. /****************************************************************************
  3462. * @doc EXTERNAL COMPFUNC
  3463. *
  3464. * @func MMRESULT | vcmStreamSetImageQuality | This function sends the image
  3465. * quality compression parameter.
  3466. *
  3467. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  3468. *
  3469. * @parm DWORD | dwImageQuality | Specifies an image quality value (between 0
  3470. * and 31. The lower number indicates a high spatial quality at a low frame
  3471. * rate, the larger number indiocates a low spatial quality at a high frame
  3472. * rate.
  3473. *
  3474. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3475. * an error number. Possible error values include the following:
  3476. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  3477. * @flag MMSYSERR_INVALPARAM | Specified image quality value is invalid.
  3478. * @flag MMSYSERR_NOTSUPPORTED | The VCM driver cannot set the compression ratio.
  3479. *
  3480. * @xref <f vcmStreamMessage>
  3481. ***************************************************************************/
  3482. MMRESULT VCMAPI vcmStreamSetImageQuality(HVCMSTREAM hvs, DWORD dwImageQuality)
  3483. {
  3484. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  3485. #ifdef USE_MPEG4_SCRUNCH
  3486. PVOID pvState;
  3487. DWORD dw;
  3488. PMPEG4COMPINSTINFO pciMPEG4Info;
  3489. #endif
  3490. #ifdef LOG_COMPRESSION_PARAMS
  3491. char szDebug[100];
  3492. #endif
  3493. // Check input param
  3494. if (!hvs)
  3495. {
  3496. ERRORMESSAGE(("vcmStreamSetImageQuality: Specified handle is invalid, hvs=NULL\r\n"));
  3497. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  3498. }
  3499. // Set to default value if out or range
  3500. if ((dwImageQuality > VCM_MIN_IMAGE_QUALITY))
  3501. {
  3502. pvs->dwQuality = VCM_DEFAULT_IMAGE_QUALITY;
  3503. ERRORMESSAGE(("vcmStreamSetImageQuality: Specified image quality value is invalid, dwImageQuality=%ld (expected value is between %ld and %ld)\r\n", dwImageQuality, VCM_MAX_IMAGE_QUALITY, VCM_MIN_IMAGE_QUALITY));
  3504. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3505. }
  3506. // Put the code that sets this property right here!!!
  3507. pvs->dwQuality = dwImageQuality;
  3508. #ifdef USE_MPEG4_SCRUNCH
  3509. // Get the state of the compressor
  3510. if (dw = ICGetStateSize((HIC)pvs->hIC))
  3511. {
  3512. if (pvState = (PVOID)MemAlloc(dw))
  3513. {
  3514. if (((DWORD) ICGetState((HIC)pvs->hIC, pvState, dw)) == dw)
  3515. {
  3516. pciMPEG4Info = (PMPEG4COMPINSTINFO)pvState;
  3517. // Configure the codec for compression
  3518. pciMPEG4Info->lMagic = MPG4_STATE_MAGIC;
  3519. pciMPEG4Info->dDataRate = 20;
  3520. pciMPEG4Info->lCrisp = dwImageQuality * 3;
  3521. pciMPEG4Info->lKeydist = 30;
  3522. pciMPEG4Info->lPScale = MPG4_PSEUDO_SCALE;
  3523. pciMPEG4Info->lTotalWindowMs = MPG4_TOTAL_WINDOW_DEFAULT;
  3524. pciMPEG4Info->lVideoWindowMs = MPG4_VIDEO_WINDOW_DEFAULT;
  3525. pciMPEG4Info->lFramesInfoValid = FALSE;
  3526. pciMPEG4Info->lBFrameOn = MPG4_B_FRAME_ON;
  3527. pciMPEG4Info->lLiveEncode = MPG4_LIVE_ENCODE;
  3528. ICSetState((HIC)pvs->hIC, (PVOID)pciMPEG4Info, dw);
  3529. // Get rid of the state structure
  3530. MemFree((HANDLE)pvState);
  3531. }
  3532. }
  3533. }
  3534. #endif
  3535. #ifdef LOG_COMPRESSION_PARAMS
  3536. wsprintf(szDebug, "New image quality: %ld\r\n", dwImageQuality);
  3537. OutputDebugString(szDebug);
  3538. #endif
  3539. return ((MMRESULT)MMSYSERR_NOERROR);
  3540. }
  3541. /****************************************************************************
  3542. * @doc EXTERNAL COMPFUNC
  3543. *
  3544. * @func MMRESULT | vcmStreamSetMaxPacketSize | This function sets the maximum
  3545. * video packet size.
  3546. *
  3547. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  3548. *
  3549. * @parm DWORD | dwMaxPacketSize | Specifies the maximum packet size.
  3550. *
  3551. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3552. * an error number. Possible error values include the following:
  3553. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  3554. * @flag MMSYSERR_INVALPARAM | Specified image quality value is invalid.
  3555. * @flag MMSYSERR_NOTSUPPORTED | The VCM driver cannot set the size.
  3556. *
  3557. * @xref <f vcmStreamMessage>
  3558. ***************************************************************************/
  3559. MMRESULT VCMAPI vcmStreamSetMaxPacketSize(HVCMSTREAM hvs, DWORD dwMaxPacketSize)
  3560. {
  3561. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  3562. // Check input params
  3563. if (!hvs)
  3564. {
  3565. ERRORMESSAGE(("vcmStreamSetMaxPacketSize: Specified handle is invalid, hvs=NULL\r\n"));
  3566. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  3567. }
  3568. if ((dwMaxPacketSize != VCM_RESET_PACKET_SIZE) && ((dwMaxPacketSize > VCM_MAX_PACKET_SIZE) || (dwMaxPacketSize < VCM_MIN_PACKET_SIZE)))
  3569. {
  3570. ERRORMESSAGE(("vcmStreamSetMaxPacketSize: Specified max packet size value is invalid, dwMaxPacketSize=%ld (expected value is between %ld and %ld)\r\n", dwMaxPacketSize, VCM_MIN_PACKET_SIZE, VCM_MAX_PACKET_SIZE));
  3571. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3572. }
  3573. // Only our (H.26x intel) codecs supports this. If the codec used is different,
  3574. // just return an 'unsupported' error.
  3575. #if !defined(_ALPHA_) && defined(USE_BILINEAR_MSH26X)
  3576. if (pvs->pvfxDst && ((pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH263) || (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH261) || (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH26X)))
  3577. #else
  3578. if (pvs->pvfxDst && ((pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH263) || (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH261)))
  3579. #endif
  3580. {
  3581. if (dwMaxPacketSize != VCM_RESET_PACKET_SIZE)
  3582. pvs->dwMaxPacketSize = dwMaxPacketSize;
  3583. else
  3584. pvs->dwMaxPacketSize = VCM_DEFAULT_PACKET_SIZE;
  3585. vcmStreamMessage(hvs, CODEC_CUSTOM_ENCODER_CONTROL, MAKELONG(EC_PACKET_SIZE,EC_SET_CURRENT), (LPARAM)pvs->dwMaxPacketSize);
  3586. }
  3587. else
  3588. return ((MMRESULT)MMSYSERR_NOTSUPPORTED);
  3589. return ((MMRESULT)MMSYSERR_NOERROR);
  3590. }
  3591. /****************************************************************************
  3592. * @doc EXTERNAL COMPFUNC
  3593. *
  3594. * @func MMRESULT | vcmStreamSetTargetRates | This function sets the target
  3595. * bitrate and frame rate to be used in the estimation of the target frame
  3596. * size at compression time.
  3597. *
  3598. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  3599. *
  3600. * @parm DWORD | dwTargetFrameRate | Specifies a target frame rate value.
  3601. *
  3602. * @parm DWORD | dwTargetByterate | Specifies a target byterate value.
  3603. *
  3604. * @rdesc The return value is zero if the function is successful. Otherwise,
  3605. * it returns an error number. Possible error values include the following:
  3606. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  3607. * @flag MMSYSERR_INVALPARAM | Specified target frame rate value is
  3608. * invalid.
  3609. * @flag MMSYSERR_NOTSUPPORTED | The VCM driver cannot set the compression
  3610. * ratio.
  3611. *
  3612. * @xref <f vcmStreamMessage>
  3613. ***************************************************************************/
  3614. MMRESULT VCMAPI vcmStreamSetTargetRates(HVCMSTREAM hvs, DWORD dwTargetFrameRate, DWORD dwTargetByterate)
  3615. {
  3616. FX_ENTRY("vcmStreamSetTargetRates");
  3617. // IP + UDP + RTP + payload mode C header - worst case
  3618. #define TRANSPORT_HEADER_SIZE (20 + 8 + 12 + 12)
  3619. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  3620. ICCOMPRESSFRAMES iccf = {0};
  3621. ASSERT(hvs && ((dwTargetFrameRate == VCM_RESET_FRAME_RATE) || ((dwTargetFrameRate <= VCM_MAX_FRAME_RATE) && (dwTargetFrameRate >= VCM_MIN_FRAME_RATE))) && ((dwTargetByterate == VCM_RESET_BYTE_RATE) || ((dwTargetByterate <= VCM_MAX_BYTE_RATE) && (dwTargetByterate >= VCM_MIN_BYTE_RATE))));
  3622. // Check input params
  3623. if (!hvs)
  3624. {
  3625. ERRORMESSAGE(("%s: Specified handle is invalid, hvs=NULL\r\n", _fx_));
  3626. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  3627. }
  3628. if ((dwTargetFrameRate != VCM_RESET_FRAME_RATE) && (dwTargetFrameRate > VCM_MAX_FRAME_RATE) && (dwTargetFrameRate < VCM_MIN_FRAME_RATE))
  3629. {
  3630. ERRORMESSAGE(("%s: Specified target frame rate value is invalid, dwTargetFrameRate=%ld (expected value is between %ld and %ld)\r\n", _fx_, dwTargetFrameRate, VCM_MIN_FRAME_RATE, VCM_MAX_FRAME_RATE));
  3631. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3632. }
  3633. if ((dwTargetByterate != VCM_RESET_BYTE_RATE) && (dwTargetByterate > VCM_MAX_BYTE_RATE) && (dwTargetByterate < VCM_MIN_BYTE_RATE))
  3634. {
  3635. ERRORMESSAGE(("%s: Specified target bitrate value is invalid, dwTargetBitrate=%ld bps (expected value is between %ld and %ld bps)\r\n", _fx_, dwTargetByterate << 3, VCM_MIN_BYTE_RATE << 3, VCM_MAX_BYTE_RATE << 3));
  3636. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3637. }
  3638. // Don't change the state of the codec while it's compressing a frame
  3639. EnterCriticalSection(&pvs->crsFrameNumber);
  3640. // Set the new rates on the codec
  3641. iccf.lQuality = 10000UL - (pvs->dwQuality * 322UL);
  3642. if (pvs->dwMaxPacketSize)
  3643. iccf.lDataRate = pvs->dwTargetByterate = dwTargetByterate - (dwTargetByterate / pvs->dwMaxPacketSize + 1) * TRANSPORT_HEADER_SIZE;
  3644. else
  3645. iccf.lDataRate = pvs->dwTargetByterate = dwTargetByterate;
  3646. iccf.lKeyRate = LONG_MAX;
  3647. iccf.dwRate = 1000UL;
  3648. pvs->dwTargetFrameRate = dwTargetFrameRate;
  3649. iccf.dwScale = iccf.dwRate * 100UL / dwTargetFrameRate;
  3650. if (ICSendMessage((HIC)(HVCMDRIVERID)pvs->hIC, ICM_COMPRESS_FRAMES_INFO, (DWORD_PTR)&iccf, sizeof(iccf)) != ICERR_OK)
  3651. {
  3652. LeaveCriticalSection(&pvs->crsFrameNumber);
  3653. ERRORMESSAGE(("%s: Codec failed to handle ICM_COMPRESS_FRAMES_INFO message correctly\r\n", _fx_));
  3654. return ((MMRESULT)VCMERR_FAILED);
  3655. }
  3656. LeaveCriticalSection(&pvs->crsFrameNumber);
  3657. DEBUGMSG(ZONE_VCM, ("%s: New targets:\r\n Frame rate: %ld.%ld fps\r\n Bitrate (minus network overhead): %ld bps\r\n Frame size: %ld bits\r\n", _fx_, pvs->dwTargetFrameRate / 100UL, (DWORD)(pvs->dwTargetFrameRate - (DWORD)(pvs->dwTargetFrameRate / 100UL) * 100UL), pvs->dwTargetByterate << 3, (pvs->dwTargetByterate << 3) * 100UL / pvs->dwTargetFrameRate));
  3658. return ((MMRESULT)MMSYSERR_NOERROR);
  3659. }
  3660. /****************************************************************************
  3661. * @doc EXTERNAL COMPFUNC
  3662. *
  3663. * @func MMRESULT | vcmStreamRestorePayload | This function takes a list of video
  3664. * packets and recreates the video payload of a complete frame from these.
  3665. *
  3666. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  3667. *
  3668. * @parm WSABUF* | ppDataPkt | Specifies a pointer to the list of video packets.
  3669. *
  3670. * @parm DWORD | dwPktCount | Specifies the number of packets in the list.
  3671. *
  3672. * @parm PBYTE | pbyFrame | Specifies a pointer to the reconstructed video data.
  3673. *
  3674. * @parm DWORD* | pdwFrameSize | Specifies a pointer to the size of reconstructed video data.
  3675. *
  3676. * @parm BOOL* | pfReceivedKeyframe | Specifies a pointer to receive the type (I or P) of a frame.
  3677. *
  3678. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  3679. * an error number. Possible error values include the following:
  3680. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  3681. * @flag MMSYSERR_INVALPARAM | Specified data pointer is invalid.
  3682. *
  3683. * @comm The <p pdwFrameSize> parameter should be initialized to the maximum frame
  3684. * size, before calling the <f vcmStreamRestorePayload> function.
  3685. *
  3686. * @xref <f vcmStreamFormatPayload>
  3687. ***************************************************************************/
  3688. MMRESULT VCMAPI vcmStreamRestorePayload(HVCMSTREAM hvs, WSABUF *ppDataPkt, DWORD dwPktCount, PBYTE pbyFrame, PDWORD pdwFrameSize, BOOL *pfReceivedKeyframe)
  3689. {
  3690. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  3691. DWORD dwHeaderSize = 0UL;
  3692. DWORD dwPSCBytes = 0UL;
  3693. DWORD dwMaxFrameSize;
  3694. #ifdef DEBUG
  3695. char szTDebug[256];
  3696. #endif
  3697. #ifdef LOGPAYLOAD_ON
  3698. PBYTE p = pbyFrame;
  3699. HANDLE g_TDebugFile;
  3700. DWORD d, GOBn;
  3701. long j = (long)(BYTE)ppDataPkt->buf[3];
  3702. #endif
  3703. // Check input params
  3704. if (!hvs)
  3705. {
  3706. ERRORMESSAGE(("vcmStreamRestorePayload: Specified handle is invalid, hvs=NULL\r\n"));
  3707. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  3708. }
  3709. if (!ppDataPkt)
  3710. {
  3711. ERRORMESSAGE(("vcmStreamRestorePayload: Specified pointer is invalid, hvs=NULL\r\n"));
  3712. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3713. }
  3714. if (!dwPktCount)
  3715. {
  3716. ERRORMESSAGE(("vcmStreamRestorePayload: Specified packet count is invalid, dwPktCount=0\r\n"));
  3717. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3718. }
  3719. if (!pbyFrame)
  3720. {
  3721. ERRORMESSAGE(("vcmStreamRestorePayload: Specified pointer is invalid, pbyFrame=NULL\r\n"));
  3722. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3723. }
  3724. if (!pdwFrameSize)
  3725. {
  3726. ERRORMESSAGE(("vcmStreamRestorePayload: Specified pointer is invalid, pdwFrameSize=NULL\r\n"));
  3727. return ((MMRESULT)MMSYSERR_INVALPARAM);
  3728. }
  3729. // Save maximum payload size
  3730. dwMaxFrameSize = *pdwFrameSize;
  3731. // Initialize payload size
  3732. *pdwFrameSize = 0;
  3733. // Initialize default frame type
  3734. *pfReceivedKeyframe = FALSE;
  3735. // What is the type of this payload
  3736. #ifndef _ALPHA_
  3737. #ifdef USE_BILINEAR_MSH26X
  3738. if ((pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH263) || (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH26X))
  3739. #else
  3740. if (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH263)
  3741. #endif
  3742. #else
  3743. if (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_DECH263)
  3744. #endif
  3745. {
  3746. // Strip the header of each packet and copy the payload in the video buffer
  3747. while (dwPktCount--)
  3748. {
  3749. // Look for the first two bits to figure out what's the mode used.
  3750. // This will dictate the size of the header to be removed.
  3751. // Mode A is 4 bytes: first bit is set to 1,
  3752. // Mode B is 8 bytes: first bit is set to 0, second bit is set to 0,
  3753. // Mode C is 12 bytes: first bit is set to 0, second bit is set to 1.
  3754. dwHeaderSize = ((ppDataPkt->buf[0] & 0x80) ? ((ppDataPkt->buf[0] & 0x40) ? 12 : 8) : 4);
  3755. // Look at the payload header to figure out if the frame is a keyframe
  3756. *pfReceivedKeyframe |= (BOOL)(ppDataPkt->buf[2] & 0x80);
  3757. #ifdef LOGPAYLOAD_ON
  3758. // Output some debug stuff
  3759. if (dwHeaderSize == 4)
  3760. {
  3761. GOBn = (DWORD)((BYTE)ppDataPkt->buf[4]) << 24 | (DWORD)((BYTE)ppDataPkt->buf[5]) << 16 | (DWORD)((BYTE)ppDataPkt->buf[6]) << 8 | (DWORD)((BYTE)ppDataPkt->buf[7]);
  3762. GOBn >>= (DWORD)(10 - (DWORD)((ppDataPkt->buf[0] & 0x38) >> 3));
  3763. GOBn &= 0x0000001F;
  3764. wsprintf(szTDebug, "Header content: Frame %3ld, GOB %0ld\r\n", (DWORD)(ppDataPkt->buf[3]), GOBn);
  3765. OutputDebugString(szTDebug);
  3766. wsprintf(szTDebug, (ppDataPkt->buf[0] & 0x80) ? " F: '1' => Mode B or C\r\n" : " F: '0' => Mode A\r\n");
  3767. OutputDebugString(szTDebug);
  3768. wsprintf(szTDebug, (ppDataPkt->buf[0] & 0x40) ? " P: '1' => PB-frame\r\n" : " P: '0' => I or P frame\r\n");
  3769. OutputDebugString(szTDebug);
  3770. wsprintf(szTDebug, " SBIT: %01ld\r\n", (DWORD)((ppDataPkt->buf[0] & 0x38) >> 3));
  3771. OutputDebugString(szTDebug);
  3772. wsprintf(szTDebug, " EBIT: %01ld\r\n", (DWORD)(ppDataPkt->buf[0] & 0x07));
  3773. OutputDebugString(szTDebug);
  3774. switch ((DWORD)(ppDataPkt->buf[1] >> 5))
  3775. {
  3776. case 0:
  3777. wsprintf(szTDebug, " SRC: '000' => Source format forbidden!\r\n");
  3778. break;
  3779. case 1:
  3780. wsprintf(szTDebug, " SRC: '001' => Source format sub-QCIF\r\n");
  3781. break;
  3782. case 2:
  3783. wsprintf(szTDebug, " SRC: '010' => Source format QCIF\r\n");
  3784. break;
  3785. case 3:
  3786. wsprintf(szTDebug, " SRC: '011' => Source format CIF\r\n");
  3787. break;
  3788. case 4:
  3789. wsprintf(szTDebug, " SRC: '100' => Source format 4CIF\r\n");
  3790. break;
  3791. case 5:
  3792. wsprintf(szTDebug, " SRC: '101' => Source format 16CIF\r\n");
  3793. break;
  3794. case 6:
  3795. wsprintf(szTDebug, " SRC: '110' => Source format reserved\r\n");
  3796. break;
  3797. case 7:
  3798. wsprintf(szTDebug, " SRC: '111' => Source format reserved\r\n");
  3799. break;
  3800. default:
  3801. wsprintf(szTDebug, " SRC: %ld => Source format unknown!\r\n", (DWORD)(ppDataPkt->buf[1] >> 5));
  3802. break;
  3803. }
  3804. OutputDebugString(szTDebug);
  3805. wsprintf(szTDebug, " R: %02ld => Reserved, must be 0\r\n", (DWORD)((ppDataPkt->buf[1] & 0x1F) >> 5));
  3806. OutputDebugString(szTDebug);
  3807. wsprintf(szTDebug, (ppDataPkt->buf[2] & 0x80) ? " I: '1' => Intra-coded\r\n" : " I: '0' => Not Intra-coded\r\n");
  3808. OutputDebugString(szTDebug);
  3809. wsprintf(szTDebug, (ppDataPkt->buf[2] & 0x40) ? " A: '1' => Optional Advanced Prediction mode ON\r\n" : " A: '0' => Optional Advanced Prediction mode OFF\r\n");
  3810. OutputDebugString(szTDebug);
  3811. wsprintf(szTDebug, (ppDataPkt->buf[2] & 0x20) ? " S: '1' => Optional Syntax-based Arithmetic Code mode ON\r\n" : " S: '0' => Optional Syntax-based Arithmetic Code mode OFF\r\n");
  3812. OutputDebugString(szTDebug);
  3813. wsprintf(szTDebug, " DBQ: %01ld => Should be 0\r\n", (DWORD)((ppDataPkt->buf[2] & 0x18) >> 3));
  3814. OutputDebugString(szTDebug);
  3815. wsprintf(szTDebug, " TRB: %01ld => Should be 0\r\n", (DWORD)(ppDataPkt->buf[2] & 0x07));
  3816. OutputDebugString(szTDebug);
  3817. wsprintf(szTDebug, " TR: %03ld\r\n", (DWORD)(ppDataPkt->buf[3]));
  3818. OutputDebugString(szTDebug);
  3819. wsprintf(szTDebug, "Header: %02lX %02lX %02lX %02lX\r\n", (BYTE)ppDataPkt->buf[0], (BYTE)ppDataPkt->buf[1], (BYTE)ppDataPkt->buf[2], (BYTE)ppDataPkt->buf[3]);
  3820. OutputDebugString(szTDebug);
  3821. wsprintf(szTDebug, "dword1: %02lX %02lX %02lX %02lX\r\n", (BYTE)ppDataPkt->buf[4], (BYTE)ppDataPkt->buf[5], (BYTE)ppDataPkt->buf[6], (BYTE)ppDataPkt->buf[7]);
  3822. OutputDebugString(szTDebug);
  3823. wsprintf(szTDebug, "dword2: %02lX %02lX %02lX %02lX\r\n", (BYTE)ppDataPkt->buf[8], (BYTE)ppDataPkt->buf[9], (BYTE)ppDataPkt->buf[10], (BYTE)ppDataPkt->buf[11]);
  3824. OutputDebugString(szTDebug);
  3825. }
  3826. else if (dwHeaderSize == 8)
  3827. {
  3828. wsprintf(szTDebug, "Header content:\r\n");
  3829. OutputDebugString(szTDebug);
  3830. wsprintf(szTDebug, (ppDataPkt->buf[0] & 0x80) ? " F: '1' => Mode B or C\r\n" : " F: '0' => Mode A\r\n");
  3831. OutputDebugString(szTDebug);
  3832. wsprintf(szTDebug, (ppDataPkt->buf[0] & 0x40) ? " P: '1' => PB-frame\r\n" : " P: '0' => I or P frame\r\n");
  3833. OutputDebugString(szTDebug);
  3834. wsprintf(szTDebug, " SBIT: %01ld\r\n", (DWORD)((ppDataPkt->buf[0] & 0x38) >> 3));
  3835. OutputDebugString(szTDebug);
  3836. wsprintf(szTDebug, " EBIT: %01ld\r\n", (DWORD)(ppDataPkt->buf[0] & 0x07));
  3837. OutputDebugString(szTDebug);
  3838. switch ((DWORD)(ppDataPkt->buf[1] >> 5))
  3839. {
  3840. case 0:
  3841. wsprintf(szTDebug, " SRC: '000' => Source format forbidden!\r\n");
  3842. break;
  3843. case 1:
  3844. wsprintf(szTDebug, " SRC: '001' => Source format sub-QCIF\r\n");
  3845. break;
  3846. case 2:
  3847. wsprintf(szTDebug, " SRC: '010' => Source format QCIF\r\n");
  3848. break;
  3849. case 3:
  3850. wsprintf(szTDebug, " SRC: '011' => Source format CIF\r\n");
  3851. break;
  3852. case 4:
  3853. wsprintf(szTDebug, " SRC: '100' => Source format 4CIF\r\n");
  3854. break;
  3855. case 5:
  3856. wsprintf(szTDebug, " SRC: '101' => Source format 16CIF\r\n");
  3857. break;
  3858. case 6:
  3859. wsprintf(szTDebug, " SRC: '110' => Source format reserved\r\n");
  3860. break;
  3861. case 7:
  3862. wsprintf(szTDebug, " SRC: '111' => Source format reserved\r\n");
  3863. break;
  3864. default:
  3865. wsprintf(szTDebug, " SRC: %ld => Source format unknown!\r\n", (DWORD)(ppDataPkt->buf[1] >> 5));
  3866. break;
  3867. }
  3868. OutputDebugString(szTDebug);
  3869. wsprintf(szTDebug, " QUANT: %02ld\r\n", (DWORD)((ppDataPkt->buf[1] & 0x1F) >> 5));
  3870. OutputDebugString(szTDebug);
  3871. wsprintf(szTDebug, (ppDataPkt->buf[2] & 0x80) ? " I: '1' => Intra-coded\r\n" : " I: '0' => Not Intra-coded\r\n");
  3872. OutputDebugString(szTDebug);
  3873. wsprintf(szTDebug, (ppDataPkt->buf[2] & 0x40) ? " A: '1' => Optional Advanced Prediction mode ON\r\n" : " A: '0' => Optional Advanced Prediction mode OFF\r\n");
  3874. OutputDebugString(szTDebug);
  3875. wsprintf(szTDebug, (ppDataPkt->buf[2] & 0x20) ? " S: '1' => Optional Syntax-based Arithmetic Code mode ON\r\n" : " S: '0' => Optional Syntax-based Arithmetic Code mode OFF\r\n");
  3876. OutputDebugString(szTDebug);
  3877. wsprintf(szTDebug, " GOBN: %03ld\r\n", (DWORD)(ppDataPkt->buf[2] & 0x1F));
  3878. OutputDebugString(szTDebug);
  3879. wsprintf(szTDebug, " MBA: %03ld\r\n", (DWORD)(ppDataPkt->buf[3]));
  3880. OutputDebugString(szTDebug);
  3881. wsprintf(szTDebug, " HMV1: %03ld\r\n", (DWORD)(ppDataPkt->buf[7]));
  3882. OutputDebugString(szTDebug);
  3883. wsprintf(szTDebug, " VMV1: %03ld\r\n", (DWORD)(ppDataPkt->buf[6]));
  3884. OutputDebugString(szTDebug);
  3885. wsprintf(szTDebug, " HMV2: %03ld\r\n", (DWORD)(ppDataPkt->buf[5]));
  3886. OutputDebugString(szTDebug);
  3887. wsprintf(szTDebug, " VMV2: %03ld\r\n", (DWORD)(ppDataPkt->buf[4]));
  3888. OutputDebugString(szTDebug);
  3889. wsprintf(szTDebug, "Header: %02lX %02lX %02lX %02lX %02lX %02lX %02lX %02lX\r\n", (BYTE)ppDataPkt->buf[0], (BYTE)ppDataPkt->buf[1], (BYTE)ppDataPkt->buf[2], (BYTE)ppDataPkt->buf[3], (BYTE)ppDataPkt->buf[4], (BYTE)ppDataPkt->buf[5], (BYTE)ppDataPkt->buf[6], (BYTE)ppDataPkt->buf[7]);
  3890. OutputDebugString(szTDebug);
  3891. wsprintf(szTDebug, "dword1: %02lX %02lX %02lX %02lX\r\n", (BYTE)ppDataPkt->buf[8], (BYTE)ppDataPkt->buf[9], (BYTE)ppDataPkt->buf[10], (BYTE)ppDataPkt->buf[11]);
  3892. OutputDebugString(szTDebug);
  3893. }
  3894. #endif
  3895. // The purpose of this code is to look for the presence of the
  3896. // Picture Start Code at the beginning of the frame. If it is
  3897. // not present, we should break in debug mode.
  3898. // Only look for PSC at the beginning of the frame
  3899. if (!*pdwFrameSize)
  3900. {
  3901. // The start of the frame may not be at a byte boundary. The SBIT field
  3902. // of the header ((BYTE)ppDataPkt->buf[0] & 0xE0) will tell us exactly where
  3903. // our frame starts. We then look for the PSC (0000 0000 0000 0000 1000 00 bits)
  3904. *((BYTE *)&dwPSCBytes + 3) = *(BYTE *)&(ppDataPkt->buf[dwHeaderSize]);
  3905. *((BYTE *)&dwPSCBytes + 2) = *(BYTE *)&(ppDataPkt->buf[dwHeaderSize + 1]);
  3906. *((BYTE *)&dwPSCBytes + 1) = *(BYTE *)&(ppDataPkt->buf[dwHeaderSize + 2]);
  3907. *((BYTE *)&dwPSCBytes + 0) = *(BYTE *)&(ppDataPkt->buf[dwHeaderSize + 3]);
  3908. dwPSCBytes <<= ((DWORD)((BYTE)ppDataPkt->buf[0] & 0x38) >> 3);
  3909. if ((dwPSCBytes & 0xFFFFFC00) != 0x00008000)
  3910. {
  3911. #ifdef DEBUG
  3912. wsprintf(szTDebug, "VCMSTRM: The first packet to reassemble is missing a PSC!\r\n");
  3913. OutputDebugString(szTDebug);
  3914. // DebugBreak();
  3915. #endif
  3916. return ((MMRESULT)VCMERR_PSCMISSING);
  3917. }
  3918. }
  3919. // The end of a buffer and the start of the next buffer could belong to the
  3920. // same byte. If this is the case, the first byte of the next buffer was already
  3921. // copied in the video data buffer, with the previous packet. It should not be copied
  3922. // twice. The SBIT field of the payload header allows us to figure out if this is the case.
  3923. if (*pdwFrameSize && (ppDataPkt->buf[0] & 0x38))
  3924. dwHeaderSize++;
  3925. #if 0
  3926. //
  3927. // THIS IS FOR EXPERIMENTATION ONLY !!!
  3928. //
  3929. // For I frames, ditch their middle GOB
  3930. if (((dwHeaderSize == 4) || (dwHeaderSize == 5)) && (GOBn == 8) && (ppDataPkt->buf[2] & 0x80))
  3931. {
  3932. wsprintf(szTDebug, "Ditched GOB %2ld of I frame %3ld!\r\n", GOBn, (DWORD)(ppDataPkt->buf[3]));
  3933. OutputDebugString(szTDebug);
  3934. ppDataPkt++;
  3935. }
  3936. else if (((dwHeaderSize == 4) || (dwHeaderSize == 5)) && GOBn && !(ppDataPkt->buf[2] & 0x80))
  3937. {
  3938. wsprintf(szTDebug, "Ditched all GOBs after GOB %2ld of P frame %3ld!\r\n", GOBn, (DWORD)(ppDataPkt->buf[3]));
  3939. OutputDebugString(szTDebug);
  3940. ppDataPkt++;
  3941. }
  3942. else
  3943. #endif
  3944. // Verify that the source format has the same video resolution than the conversion stream
  3945. // Test for invalid packets that have a length below the size of the payload header
  3946. if ( (g_ITUSizes[(DWORD)(((BYTE)ppDataPkt->buf[1]) >> 5)].biWidth == pvs->pvfxSrc->bih.biWidth)
  3947. && (g_ITUSizes[(DWORD)(((BYTE)ppDataPkt->buf[1]) >> 5)].biHeight == pvs->pvfxSrc->bih.biHeight)
  3948. && (ppDataPkt->len >= dwHeaderSize)
  3949. && ((*pdwFrameSize + ppDataPkt->len - dwHeaderSize) <= dwMaxFrameSize) )
  3950. {
  3951. // Copy the payload
  3952. CopyMemory(pbyFrame + *pdwFrameSize, ppDataPkt->buf + dwHeaderSize, ppDataPkt->len - dwHeaderSize);
  3953. // Update the payload size and pointer to the input video packets
  3954. *pdwFrameSize += ppDataPkt->len - dwHeaderSize;
  3955. }
  3956. else
  3957. {
  3958. // The total size of the reassembled packet would be larger than the maximum allowed!!!
  3959. // Or the packet has a length less than the payload header size
  3960. // Dump the frame
  3961. #ifdef DEBUG
  3962. wsprintf(szTDebug, (ppDataPkt->len >= dwHeaderSize) ? "VCMSTRM: Cumulative size of the reassembled packets is too large: discarding frame!\r\n" : "VCMSTRM: Packet length is smaller than payload header size: discarding frame!\r\n");
  3963. OutputDebugString(szTDebug);
  3964. #endif
  3965. return ((MMRESULT)VCMERR_NONSPECIFIC);
  3966. }
  3967. ppDataPkt++;
  3968. }
  3969. #ifdef LOGPAYLOAD_ON
  3970. g_TDebugFile = CreateFile("C:\\RecvLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  3971. SetFilePointer(g_TDebugFile, 0, NULL, FILE_END);
  3972. wsprintf(szTDebug, "Frame #%03ld\r\n", (DWORD)j);
  3973. WriteFile(g_TDebugFile, szTDebug, strlen(szTDebug), &d, NULL);
  3974. for (j=*pdwFrameSize; j>0; j-=4, p+=4)
  3975. {
  3976. wsprintf(szTDebug, "%02lX %02lX %02lX %02lX\r\n", *((BYTE *)p), *((BYTE *)p+1), *((BYTE *)p+2), *((BYTE *)p+3));
  3977. WriteFile(g_TDebugFile, szTDebug, strlen(szTDebug), &d, NULL);
  3978. }
  3979. CloseHandle(g_TDebugFile);
  3980. #endif
  3981. }
  3982. #ifndef _ALPHA_
  3983. else if (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_MSH261)
  3984. #else
  3985. else if (pvs->pvfxSrc->dwFormatTag == VIDEO_FORMAT_DECH261)
  3986. #endif
  3987. {
  3988. // Strip the header of each packet and copy the payload in the video buffer
  3989. while (dwPktCount--)
  3990. {
  3991. #ifdef LOGPAYLOAD_ON
  3992. // wsprintf(szDebug, "Header: %02lX %02lX %02lX %02lX\r\ndword1: %02lX %02lX %02lX %02lX\r\ndword2: %02lX %02lX %02lX %02lX\r\n", ppDataPkt->buf[0], ppDataPkt->buf[1], ppDataPkt->buf[2], ppDataPkt->buf[3], ppDataPkt->buf[4], ppDataPkt->buf[5], ppDataPkt->buf[6], ppDataPkt->buf[7], ppDataPkt->buf[8], ppDataPkt->buf[9], ppDataPkt->buf[10], ppDataPkt->buf[11]);
  3993. wsprintf(szTDebug, "Header: %02lX %02lX %02lX %02lX\r\n", (BYTE)ppDataPkt->buf[0], (BYTE)ppDataPkt->buf[1], (BYTE)ppDataPkt->buf[2], (BYTE)ppDataPkt->buf[3]);
  3994. OutputDebugString(szTDebug);
  3995. wsprintf(szTDebug, "dword1: %02lX %02lX %02lX %02lX\r\n", (BYTE)ppDataPkt->buf[4], (BYTE)ppDataPkt->buf[5], (BYTE)ppDataPkt->buf[6], (BYTE)ppDataPkt->buf[7]);
  3996. OutputDebugString(szTDebug);
  3997. wsprintf(szTDebug, "dword2: %02lX %02lX %02lX %02lX\r\n", (BYTE)ppDataPkt->buf[8], (BYTE)ppDataPkt->buf[9], (BYTE)ppDataPkt->buf[10], (BYTE)ppDataPkt->buf[11]);
  3998. OutputDebugString(szTDebug);
  3999. #endif
  4000. // The H.261 payload header size is always 4 bytes long
  4001. dwHeaderSize = 4;
  4002. // Look at the payload header to figure out if the frame is a keyframe
  4003. *pfReceivedKeyframe |= (BOOL)(ppDataPkt->buf[0] & 0x02);
  4004. // The purpose of this code is to look for the presence of the
  4005. // Picture Start Code at the beginning of the frame. If it is
  4006. // not present, we should break in debug mode.
  4007. // Only look for PSC at the beginning of the frame
  4008. if (!*pdwFrameSize)
  4009. {
  4010. // The start of the frame may not be at a byte boundary. The SBIT field
  4011. // of the header ((BYTE)ppDataPkt->buf[0] & 0xE0) will tell us exactly where
  4012. // our frame starts. We then look for the PSC (0000 0000 0000 0001 0000 bits)
  4013. *((BYTE *)&dwPSCBytes + 3) = *(BYTE *)&(ppDataPkt->buf[dwHeaderSize]);
  4014. *((BYTE *)&dwPSCBytes + 2) = *(BYTE *)&(ppDataPkt->buf[dwHeaderSize + 1]);
  4015. *((BYTE *)&dwPSCBytes + 1) = *(BYTE *)&(ppDataPkt->buf[dwHeaderSize + 2]);
  4016. *((BYTE *)&dwPSCBytes + 0) = *(BYTE *)&(ppDataPkt->buf[dwHeaderSize + 3]);
  4017. dwPSCBytes <<= ((DWORD)((BYTE)ppDataPkt->buf[0] & 0xE0) >> 5);
  4018. if ((dwPSCBytes & 0xFFFFF000) != 0x00010000)
  4019. {
  4020. #ifdef DEBUG
  4021. wsprintf(szTDebug, "VCMSTRM: The first packet to reassemble is missing a PSC!\r\n");
  4022. OutputDebugString(szTDebug);
  4023. // DebugBreak();
  4024. #endif
  4025. return ((MMRESULT)VCMERR_PSCMISSING);
  4026. }
  4027. }
  4028. // The end of a buffer and the start of the next buffer could belong to the
  4029. // same byte. If this is the case, the first byte of the next buffer was already
  4030. // copied in the video data buffer, with the previous packet. It should not be copied
  4031. // twice. The SBIT field of the payload header allows us to figure out if this is the case.
  4032. if (*pdwFrameSize && (ppDataPkt->buf[0] & 0xE0))
  4033. dwHeaderSize++;
  4034. // Copy the payload
  4035. // Test for invalid packets that have a length below the size of the payload header
  4036. if ( (ppDataPkt->len >= dwHeaderSize) && ((*pdwFrameSize + ppDataPkt->len - dwHeaderSize) <= dwMaxFrameSize) )
  4037. {
  4038. // Copy the payload
  4039. CopyMemory(pbyFrame + *pdwFrameSize, ppDataPkt->buf + dwHeaderSize, ppDataPkt->len - dwHeaderSize);
  4040. // Update the payload size and pointer to the input video packets
  4041. *pdwFrameSize += ppDataPkt->len - dwHeaderSize;
  4042. ppDataPkt++;
  4043. }
  4044. else
  4045. {
  4046. // The total size of the reassembled packet would be larger than the maximum allowed!!!
  4047. // Or the packet has a length less than the payload header size
  4048. // Dump the frame
  4049. #ifdef DEBUG
  4050. wsprintf(szTDebug, (ppDataPkt->len >= dwHeaderSize) ? "VCMSTRM: Cumulative size of the reassembled packets is too large: discarding frame!\r\n" : "VCMSTRM: Packet length is smaller than payload header size: discarding frame!\r\n");
  4051. OutputDebugString(szTDebug);
  4052. // DebugBreak();
  4053. #endif
  4054. return ((MMRESULT)VCMERR_NONSPECIFIC);
  4055. }
  4056. }
  4057. #ifdef LOGPAYLOAD_ON
  4058. g_TDebugFile = CreateFile("C:\\RecvLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  4059. SetFilePointer(g_TDebugFile, 0, NULL, FILE_END);
  4060. wsprintf(szTDebug, "Frame #%03ld\r\n", (DWORD)j);
  4061. WriteFile(g_TDebugFile, szTDebug, strlen(szTDebug), &d, NULL);
  4062. for (j=*pdwFrameSize; j>0; j-=4, p+=4)
  4063. {
  4064. wsprintf(szTDebug, "%02lX %02lX %02lX %02lX\r\n", *((BYTE *)p), *((BYTE *)p+1), *((BYTE *)p+2), *((BYTE *)p+3));
  4065. WriteFile(g_TDebugFile, szTDebug, strlen(szTDebug), &d, NULL);
  4066. }
  4067. CloseHandle(g_TDebugFile);
  4068. #endif
  4069. }
  4070. else
  4071. {
  4072. // Strip the header of each packet and copy the payload in the video buffer
  4073. while (dwPktCount--)
  4074. {
  4075. // Copy the payload
  4076. // Test for invalid packets that have a length below the size of the payload header
  4077. if ( (ppDataPkt->len >= dwHeaderSize) && ((*pdwFrameSize + ppDataPkt->len - dwHeaderSize) <= dwMaxFrameSize))
  4078. {
  4079. // Copy the payload
  4080. CopyMemory(pbyFrame + *pdwFrameSize, ppDataPkt->buf + dwHeaderSize, ppDataPkt->len - dwHeaderSize);
  4081. // Update the payload size and pointer to the input video packets
  4082. *pdwFrameSize += ppDataPkt->len - dwHeaderSize;
  4083. ppDataPkt++;
  4084. }
  4085. else
  4086. {
  4087. // The total size of the reassembled packet would be larger than the maximum allowed!!!
  4088. // Or the packet has a length less than the payload header size
  4089. // Dump the frame
  4090. #ifdef DEBUG
  4091. wsprintf(szTDebug, (ppDataPkt->len >= dwHeaderSize) ? "VCMSTRM: Cumulative size of the reassembled packets is too large: discarding frame!\r\n" : "VCMSTRM: Packet length is smaller than payload header size: discarding frame!\r\n");
  4092. OutputDebugString(szTDebug);
  4093. // DebugBreak();
  4094. #endif
  4095. return ((MMRESULT)VCMERR_NONSPECIFIC);
  4096. }
  4097. }
  4098. }
  4099. return ((MMRESULT)MMSYSERR_NOERROR);
  4100. }
  4101. /****************************************************************************
  4102. * @doc EXTERNAL COMPFUNC
  4103. *
  4104. * @func MMRESULT | vcmStreamFormatPayload | This function returns compressed data
  4105. * spread into data packets with a payload header for the specific format of the
  4106. * compressed data.
  4107. *
  4108. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  4109. *
  4110. * @parm PBYTE | pDataSrc | Specifies a pointer to the whole compressed data.
  4111. *
  4112. * @parm DWORD | dwDataSize | Specifies the size of the input data in bytes.
  4113. *
  4114. * @parm PBYTE* | ppDataPkt | Specifies a pointer to a pointer to a packet.
  4115. *
  4116. * @parm DWORD* | pdwPktSize | Specifies a pointer to the size of the packet.
  4117. *
  4118. * @parm DWORD | dwPktCount | Specifies what packet to return (0 first packet, 1 second packet, ...)
  4119. *
  4120. * @parm DWORD | dwMaxFragSize | Specifies the maximum packet size
  4121. *
  4122. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  4123. * an error number. Possible error values include the following:
  4124. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  4125. * @flag MMSYSERR_INVALPARAM | Specified data pointer is invalid.
  4126. * @flag VCMERR_NOMOREPACKETS | There is no more data for the requested packet number, or there isn't any handler for this payload.
  4127. * @flag VCMERR_NONSPECIFIC | We were asked to put a header we do not know how to generate.
  4128. ***************************************************************************/
  4129. MMRESULT VCMAPI vcmStreamFormatPayload( HVCMSTREAM hvs,
  4130. PBYTE pDataSrc,
  4131. DWORD dwDataSize,
  4132. PBYTE *ppDataPkt,
  4133. PDWORD pdwPktSize,
  4134. PDWORD pdwPktCount,
  4135. UINT *pfMark,
  4136. PBYTE *pHdrInfo,
  4137. PDWORD pdwHdrSize)
  4138. {
  4139. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  4140. PH26X_RTP_BSINFO_TRAILER pbsiT;
  4141. PRTP_H263_BSINFO pbsi263;
  4142. PRTP_H261_BSINFO pbsi261;
  4143. PBYTE pb;
  4144. DWORD dwHeaderHigh = 0UL; // most significant
  4145. DWORD dwHeaderMiddle = 0UL;
  4146. DWORD dwHeaderLow = 0UL; // least significant
  4147. BOOL bOneFrameOnePacket;
  4148. #ifdef DEBUG
  4149. char szDebug[256];
  4150. #endif
  4151. long i;
  4152. #ifdef LOGPAYLOAD_ON
  4153. PBYTE p;
  4154. DWORD d;
  4155. DWORD dwLastChunk;
  4156. DWORD wPrevOffset;
  4157. #endif
  4158. // Check input params
  4159. if (!hvs)
  4160. {
  4161. ERRORMESSAGE(("vcmStreamFormatPayload: Specified handle is invalid, hvs=NULL\r\n"));
  4162. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  4163. }
  4164. if (!pDataSrc)
  4165. {
  4166. ERRORMESSAGE(("vcmStreamFormatPayload: Specified pointer is invalid, pDataSrc=NULL\r\n"));
  4167. return ((MMRESULT)MMSYSERR_INVALPARAM);
  4168. }
  4169. // Initialize packet pointer
  4170. *ppDataPkt = pDataSrc;
  4171. *pdwPktSize = dwDataSize;
  4172. *pfMark = 1;
  4173. bOneFrameOnePacket = FALSE;
  4174. // Put the code that builds the packets right here!!!
  4175. #ifndef _ALPHA_
  4176. #ifdef USE_BILINEAR_MSH26X
  4177. if ((pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH263) || (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH26X))
  4178. #else
  4179. if (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH263)
  4180. #endif
  4181. #else
  4182. if (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_DECH263)
  4183. #endif
  4184. {
  4185. // Look for the bitstream info trailer
  4186. pbsiT = (PH26X_RTP_BSINFO_TRAILER)(pDataSrc + dwDataSize - sizeof(H26X_RTP_BSINFO_TRAILER));
  4187. // If the whole frame can fit in pvs->dwMaxPacketSize, send it non fragmented
  4188. if ((pbsiT->dwCompressedSize + 4) < pvs->dwMaxPacketSize)
  4189. bOneFrameOnePacket = TRUE;
  4190. // Look for the packet to receive a H.263 payload header
  4191. if ((*pdwPktCount < pbsiT->dwNumOfPackets) && !(bOneFrameOnePacket && *pdwPktCount))
  4192. {
  4193. #ifdef _ALPHA_
  4194. // Verify that the content of the bistream info structures is correct
  4195. // If not, do not parse the frame, and fail the call
  4196. // This is to solve problems with the data returned by the DEC codecs
  4197. if (!*pdwPktCount)
  4198. {
  4199. pbsi263 = (PRTP_H263_BSINFO)((PBYTE)pbsiT - pbsiT->dwNumOfPackets * sizeof(RTP_H263_BSINFO));
  4200. for (i=1; i<(long)pbsiT->dwNumOfPackets; i++, pbsi263++)
  4201. {
  4202. if ((pbsi263->dwBitOffset >= (pbsi263+1)->dwBitOffset) || ((pbsiT->dwCompressedSize*8) <= pbsi263->dwBitOffset))
  4203. {
  4204. #ifdef DEBUG
  4205. OutputDebugString("VCMSTRM: The content of the extended bitstream info structures is invalid!\r\n");
  4206. #endif
  4207. // return ((MMRESULT)VCMERR_NONSPECIFIC);
  4208. bOneFrameOnePacket = TRUE;
  4209. }
  4210. }
  4211. // Test last info strucure
  4212. if ( !bOneFrameOnePacket && ((pbsiT->dwCompressedSize*8) <= pbsi263->dwBitOffset))
  4213. {
  4214. #ifdef DEBUG
  4215. OutputDebugString("VCMSTRM: The content of the extended bitstream info structures is invalid!\r\n");
  4216. #endif
  4217. // return ((MMRESULT)VCMERR_NONSPECIFIC);
  4218. bOneFrameOnePacket = TRUE;
  4219. }
  4220. }
  4221. #endif
  4222. #ifdef LOGPAYLOAD_ON
  4223. // Dump the whole frame in the debug window for comparison with receive side
  4224. if (!*pdwPktCount)
  4225. {
  4226. g_DebugFile = CreateFile("C:\\SendLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  4227. SetFilePointer(g_DebugFile, 0, NULL, FILE_END);
  4228. wsprintf(szDebug, "Frame #%03ld\r\n", (DWORD)pbsiT->byTR);
  4229. WriteFile(g_DebugFile, szDebug, strlen(szDebug), &d, NULL);
  4230. wsprintf(szDebug, "Frame #%03ld has %1ld packets of size ", (DWORD)pbsiT->byTR, (DWORD)pbsiT->dwNumOfPackets);
  4231. OutputDebugString(szDebug);
  4232. pbsi263 = (PRTP_H263_BSINFO)((PBYTE)pbsiT - pbsiT->dwNumOfPackets * sizeof(RTP_H263_BSINFO));
  4233. for (i=1; i<(long)pbsiT->dwNumOfPackets; i++)
  4234. {
  4235. wPrevOffset = pbsi263->dwBitOffset;
  4236. pbsi263++;
  4237. wsprintf(szDebug, "%04ld, ", (DWORD)(pbsi263->dwBitOffset - wPrevOffset) >> 3);
  4238. OutputDebugString(szDebug);
  4239. }
  4240. wsprintf(szDebug, "%04ld\r\n", (DWORD)(pbsiT->dwCompressedSize * 8 - pbsi263->dwBitOffset) >> 3);
  4241. OutputDebugString(szDebug);
  4242. for (i=pbsiT->dwCompressedSize, p=pDataSrc; i>0; i-=4, p+=4)
  4243. {
  4244. wsprintf(szDebug, "%02lX %02lX %02lX %02lX\r\n", *((BYTE *)p), *((BYTE *)p+1), *((BYTE *)p+2), *((BYTE *)p+3));
  4245. WriteFile(g_DebugFile, szDebug, strlen(szDebug), &d, NULL);
  4246. }
  4247. CloseHandle(g_DebugFile);
  4248. }
  4249. #endif
  4250. // Look for the bitstream info structure
  4251. pbsi263 = (PRTP_H263_BSINFO)((PBYTE)pbsiT - (pbsiT->dwNumOfPackets - *pdwPktCount) * sizeof(RTP_H263_BSINFO));
  4252. // Set the marker bit: as long as this is not the last packet of the frame
  4253. // this bit needs to be set to 0
  4254. if (!bOneFrameOnePacket)
  4255. {
  4256. // Count the number of GOBS that could fit in pvs->dwMaxPacketSize
  4257. for (i=1; (i<(long)(pbsiT->dwNumOfPackets - *pdwPktCount)) && (pbsi263->byMode != RTP_H263_MODE_B); i++)
  4258. {
  4259. // Don't try to add a Mode B packet to the end of another Mode A or Mode B packet
  4260. if (((pbsi263+i)->dwBitOffset - pbsi263->dwBitOffset > (pvs->dwMaxPacketSize * 8)) || ((pbsi263+i)->byMode == RTP_H263_MODE_B))
  4261. break;
  4262. }
  4263. if (i < (long)(pbsiT->dwNumOfPackets - *pdwPktCount))
  4264. {
  4265. *pfMark = 0;
  4266. if (i>1)
  4267. i--;
  4268. }
  4269. else
  4270. {
  4271. // Hey! You 're forgetting the last GOB! It could make the total
  4272. // size of the last packet larger than pvs->dwMaxPacketSize... Imbecile!
  4273. if ((pbsiT->dwCompressedSize * 8 - pbsi263->dwBitOffset > (pvs->dwMaxPacketSize * 8)) && (i>1))
  4274. {
  4275. *pfMark = 0;
  4276. i--;
  4277. }
  4278. }
  4279. #if 0
  4280. //
  4281. // THIS IS FOR EXPERIMENTATION ONLY !!!
  4282. //
  4283. // Ditch the last GOB
  4284. if ((*pfMark == 1) && (i == 1))
  4285. return ((MMRESULT)VCMERR_NOMOREPACKETS);
  4286. #endif
  4287. }
  4288. // Go to the beginning of the data
  4289. pb = pDataSrc + pbsi263->dwBitOffset / 8;
  4290. #if 0
  4291. //
  4292. // THIS IS FOR EXPERIMENTATION ONLY !!!
  4293. //
  4294. // Trash the PSC once in a while to see how the other end reacts
  4295. if (!*pdwPktCount && (((*pb == 0) && (*(pb+1) == 0) && ((*(pb+2) & 0xFC) == 0x80))))
  4296. {
  4297. // The previous test guarantees that it is in fact a PSC that we trash...
  4298. if ((DWORD)(RAND_MAX - rand()) < (DWORD)(RAND_MAX / 10))
  4299. *pb = 0xFF;
  4300. }
  4301. #endif
  4302. #ifdef DEBUG
  4303. if (!*pdwPktCount && (((*pb != 0) || (*(pb+1) != 0) || ((*(pb+2) & 0xFC) != 0x80))))
  4304. {
  4305. wsprintf(szDebug, "VCMSTRM: This compressed frame is missing a PSC!\r\n");
  4306. OutputDebugString(szDebug);
  4307. // DebugBreak();
  4308. }
  4309. #endif
  4310. // Look for the kind of header to be built
  4311. if (pbsi263->byMode == RTP_H263_MODE_A)
  4312. {
  4313. // Build a header in mode A
  4314. // 0 1 2 3
  4315. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  4316. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4317. //|F|P|SBIT |EBIT | SRC | R |I|A|S|DBQ| TRB | TR |
  4318. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4319. // But that's the network byte order...
  4320. // F bit already set to 0
  4321. // Set the SRC bits
  4322. dwHeaderHigh |= ((DWORD)(pbsiT->bySrc)) << 21;
  4323. // R bits already set to 0
  4324. // Set the P bit
  4325. dwHeaderHigh |= (pbsiT->dwFlags & RTP_H263_PB) << 29;
  4326. // Set the I bit
  4327. dwHeaderHigh |= (pbsiT->dwFlags & RTP_H26X_INTRA_CODED) << 15;
  4328. // Set the A bit
  4329. dwHeaderHigh |= (pbsiT->dwFlags & RTP_H263_AP) << 12;
  4330. // Set the S bit
  4331. dwHeaderHigh |= (pbsiT->dwFlags & RTP_H263_SAC) << 10;
  4332. // Set the DBQ bits
  4333. dwHeaderHigh |= ((DWORD)(pbsiT->byDBQ)) << 11;
  4334. // Set the TRB bits
  4335. dwHeaderHigh |= ((DWORD)(pbsiT->byTRB)) << 8;
  4336. // Set the TR bits
  4337. dwHeaderHigh |= ((DWORD)(pbsiT->byTR));
  4338. // Special case: 1 frame = 1 packet
  4339. if (bOneFrameOnePacket)
  4340. {
  4341. // SBIT is already set to 0
  4342. // EBIT is already set to 0
  4343. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  4344. ERRORMESSAGE(("vcmFormatPayload: (1F1P) Previous EBIT=%ld, current SBIT=%ld, current EBIT=%ld (New frame)\r\n", g_dwPreviousEBIT, (DWORD)(dwHeaderHigh & 0x38000000) >> 27, (DWORD)(dwHeaderHigh & 0x07000000) >> 24));
  4345. #endif // } VALIDATE_SBIT_EBIT
  4346. // Update the packet size
  4347. *pdwPktSize = pbsiT->dwCompressedSize + 4;
  4348. // Update the packet count
  4349. *pdwPktCount = pbsiT->dwNumOfPackets;
  4350. }
  4351. else
  4352. {
  4353. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  4354. DWORD dwCurrentSBIT;
  4355. #endif // } VALIDATE_SBIT_EBIT
  4356. // Set the SBIT bits
  4357. dwHeaderHigh |= (pbsi263->dwBitOffset % 8) << 27;
  4358. // Set the EBIT bits
  4359. if ((pbsiT->dwNumOfPackets - *pdwPktCount - i) >= 1)
  4360. dwHeaderHigh |= (DWORD)((8UL - ((pbsi263+i)->dwBitOffset % 8)) & 0x00000007) << 24;
  4361. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  4362. // Compare this to the previous EBIT. If the sum of the two
  4363. // is not equal to 8 or 0, something's broken
  4364. if (*pdwPktCount)
  4365. ERRORMESSAGE(("vcmFormatPayload: Previous EBIT=%ld, current SBIT=%ld, current EBIT=%ld\r\n", g_dwPreviousEBIT, (DWORD)(dwHeaderHigh & 0x38000000) >> 27, (DWORD)(dwHeaderHigh & 0x07000000) >> 24));
  4366. else
  4367. ERRORMESSAGE(("vcmFormatPayload: Previous EBIT=%ld, current SBIT=%ld, current EBIT=%ld (New frame)\r\n", g_dwPreviousEBIT, (DWORD)(dwHeaderHigh & 0x38000000) >> 27, (DWORD)(dwHeaderHigh & 0x07000000) >> 24));
  4368. // Only test this if this is the first packet
  4369. dwCurrentSBIT = (DWORD)(dwHeaderHigh & 0x38000000) >> 27;
  4370. if ((*pdwPktCount) && (((dwCurrentSBIT + g_dwPreviousEBIT) != 8) && (((dwCurrentSBIT + g_dwPreviousEBIT) != 0))))
  4371. DebugBreak();
  4372. g_dwPreviousEBIT = (dwHeaderHigh & 0x07000000) >> 24;
  4373. #endif // } VALIDATE_SBIT_EBIT
  4374. // Update the packet size
  4375. if ((pbsiT->dwNumOfPackets - *pdwPktCount - i) >= 1)
  4376. *pdwPktSize = (((pbsi263+i)->dwBitOffset - 1) / 8) - (pbsi263->dwBitOffset / 8) + 1 + 4;
  4377. else
  4378. *pdwPktSize = pbsiT->dwCompressedSize - pbsi263->dwBitOffset / 8 + 4;
  4379. // Update the packet count
  4380. *pdwPktCount += i;
  4381. }
  4382. #if 0
  4383. // Save the header right before the data chunk
  4384. *ppDataPkt = pDataSrc + (pbsi263->dwBitOffset / 8) - 4;
  4385. // Convert to network byte order
  4386. *((BYTE *)*ppDataPkt+3) = (BYTE)(dwHeaderHigh & 0x000000FF);
  4387. *((BYTE *)*ppDataPkt+2) = (BYTE)((dwHeaderHigh >> 8) & 0x000000FF);
  4388. *((BYTE *)*ppDataPkt+1) = (BYTE)((dwHeaderHigh >> 16) & 0x000000FF);
  4389. *((BYTE *)*ppDataPkt) = (BYTE)((dwHeaderHigh >> 24) & 0x000000FF);
  4390. #else
  4391. // Save the header right before the data chunk
  4392. *ppDataPkt = pDataSrc + (pbsi263->dwBitOffset / 8) - 4;
  4393. *pdwHdrSize=4;
  4394. // Convert to network byte order
  4395. *((BYTE *)*pHdrInfo+3) = (BYTE)(dwHeaderHigh & 0x000000FF);
  4396. *((BYTE *)*pHdrInfo+2) = (BYTE)((dwHeaderHigh >> 8) & 0x000000FF);
  4397. *((BYTE *)*pHdrInfo+1) = (BYTE)((dwHeaderHigh >> 16) & 0x000000FF);
  4398. *((BYTE *)*pHdrInfo) = (BYTE)((dwHeaderHigh >> 24) & 0x000000FF);
  4399. #endif
  4400. #ifdef LOGPAYLOAD_ON
  4401. // Output some debug stuff
  4402. wsprintf(szDebug, "Header content:\r\n");
  4403. OutputDebugString(szDebug);
  4404. wsprintf(szDebug, (*(BYTE *)*ppDataPkt & 0x80) ? " F: '1' => Mode B or C\r\n" : " F: '0' => Mode A\r\n");
  4405. OutputDebugString(szDebug);
  4406. wsprintf(szDebug, (*(BYTE *)*ppDataPkt & 0x40) ? " P: '1' => PB-frame\r\n" : " P: '0' => I or P frame\r\n");
  4407. OutputDebugString(szDebug);
  4408. wsprintf(szDebug, " SBIT: %01ld\r\n", (DWORD)((*(BYTE *)*ppDataPkt & 0x38) >> 3));
  4409. OutputDebugString(szDebug);
  4410. wsprintf(szDebug, " EBIT: %01ld\r\n", (DWORD)(*(BYTE *)*ppDataPkt & 0x07));
  4411. OutputDebugString(szDebug);
  4412. switch ((DWORD)(*((BYTE *)*ppDataPkt+1) >> 5))
  4413. {
  4414. case 0:
  4415. wsprintf(szDebug, " SRC: '000' => Source format forbidden!\r\n");
  4416. break;
  4417. case 1:
  4418. wsprintf(szDebug, " SRC: '001' => Source format sub-QCIF\r\n");
  4419. break;
  4420. case 2:
  4421. wsprintf(szDebug, " SRC: '010' => Source format QCIF\r\n");
  4422. break;
  4423. case 3:
  4424. wsprintf(szDebug, " SRC: '011' => Source format CIF\r\n");
  4425. break;
  4426. case 4:
  4427. wsprintf(szDebug, " SRC: '100' => Source format 4CIF\r\n");
  4428. break;
  4429. case 5:
  4430. wsprintf(szDebug, " SRC: '101' => Source format 16CIF\r\n");
  4431. break;
  4432. case 6:
  4433. wsprintf(szDebug, " SRC: '110' => Source format reserved\r\n");
  4434. break;
  4435. case 7:
  4436. wsprintf(szDebug, " SRC: '111' => Source format reserved\r\n");
  4437. break;
  4438. default:
  4439. wsprintf(szDebug, " SRC: %ld => Source format unknown!\r\n", (DWORD)(*((BYTE *)*ppDataPkt+1) >> 5));
  4440. break;
  4441. }
  4442. OutputDebugString(szDebug);
  4443. wsprintf(szDebug, " R: %02ld => Reserved, must be 0\r\n", (DWORD)((*((BYTE *)*ppDataPkt+1) & 0x1F) >> 5));
  4444. OutputDebugString(szDebug);
  4445. wsprintf(szDebug, (*((BYTE *)*ppDataPkt+2) & 0x80) ? " I: '1' => Intra-coded\r\n" : " I: '0' => Not Intra-coded\r\n");
  4446. OutputDebugString(szDebug);
  4447. wsprintf(szDebug, (*((BYTE *)*ppDataPkt+2) & 0x40) ? " A: '1' => Optional Advanced Prediction mode ON\r\n" : " A: '0' => Optional Advanced Prediction mode OFF\r\n");
  4448. OutputDebugString(szDebug);
  4449. wsprintf(szDebug, (*((BYTE *)*ppDataPkt+2) & 0x20) ? " S: '1' => Optional Syntax-based Arithmetic Code mode ON\r\n" : " S: '0' => Optional Syntax-based Arithmetic Code mode OFF\r\n");
  4450. OutputDebugString(szDebug);
  4451. wsprintf(szDebug, " DBQ: %01ld => Should be 0\r\n", (DWORD)((*((BYTE *)*ppDataPkt+2) & 0x18) >> 3));
  4452. OutputDebugString(szDebug);
  4453. wsprintf(szDebug, " TRB: %01ld => Should be 0\r\n", (DWORD)(*((BYTE *)*ppDataPkt+2) & 0x07));
  4454. OutputDebugString(szDebug);
  4455. wsprintf(szDebug, " TR: %03ld\r\n", (DWORD)(*((BYTE *)*ppDataPkt+3)));
  4456. OutputDebugString(szDebug);
  4457. wsprintf(szDebug, "Packet: %02lX\r\n Header: %02lX %02lX %02lX %02lX\r\n dword1: %02lX %02lX %02lX %02lX\r\n dword2: %02lX %02lX %02lX %02lX\r\n", *pdwPktCount, *((BYTE *)*ppDataPkt), *((BYTE *)*ppDataPkt+1), *((BYTE *)*ppDataPkt+2), *((BYTE *)*ppDataPkt+3), *((BYTE *)*ppDataPkt+4), *((BYTE *)*ppDataPkt+5), *((BYTE *)*ppDataPkt+6), *((BYTE *)*ppDataPkt+7), *((BYTE *)*ppDataPkt+8), *((BYTE *)*ppDataPkt+9), *((BYTE *)*ppDataPkt+10), *((BYTE *)*ppDataPkt+11));
  4458. OutputDebugString(szDebug);
  4459. if (*pdwPktCount == pbsiT->dwNumOfPackets)
  4460. wsprintf(szDebug, " Tail : %02lX %02lX XX XX\r\n", *((BYTE *)*ppDataPkt+*pdwPktSize-2), *((BYTE *)*ppDataPkt+*pdwPktSize-1));
  4461. else
  4462. wsprintf(szDebug, " Tail : %02lX %02lX %02lX %02lX\r\n", *((BYTE *)*ppDataPkt+*pdwPktSize-2), *((BYTE *)*ppDataPkt+*pdwPktSize-1), *((BYTE *)*ppDataPkt+*pdwPktSize), *((BYTE *)*ppDataPkt+*pdwPktSize+1));
  4463. OutputDebugString(szDebug);
  4464. if (*pfMark == 1)
  4465. wsprintf(szDebug, " Marker: ON\r\n");
  4466. else
  4467. wsprintf(szDebug, " Marker: OFF\r\n");
  4468. OutputDebugString(szDebug);
  4469. wsprintf(szDebug, "Frame #%03ld, Packet of size %04ld\r\n", (DWORD)pbsiT->byTR, *pdwPktSize);
  4470. OutputDebugString(szDebug);
  4471. #endif
  4472. }
  4473. else if (pbsi263->byMode == RTP_H263_MODE_B)
  4474. {
  4475. // Build a header in mode B
  4476. // 0 1 2 3
  4477. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  4478. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4479. //|F|P|SBIT |EBIT | SRC | QUANT |I|A|S| GOBN | MBA |
  4480. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4481. //| HMV1 | VMV1 | HMV2 | VMV2 |
  4482. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4483. // But that's the network byte order...
  4484. // Set the F bit to 1
  4485. dwHeaderHigh = 0x80000000;
  4486. // Set the SRC bits
  4487. dwHeaderHigh |= ((DWORD)(pbsiT->bySrc)) << 21;
  4488. // Set the QUANT bits
  4489. dwHeaderHigh |= ((DWORD)(pbsi263->byQuant)) << 16;
  4490. // Set the P bit
  4491. dwHeaderHigh |= (pbsiT->dwFlags & RTP_H263_PB) << 29;
  4492. // Set the I bit
  4493. dwHeaderHigh |= (pbsiT->dwFlags & RTP_H26X_INTRA_CODED) << 15;
  4494. // Set the A bit
  4495. dwHeaderHigh |= (pbsiT->dwFlags & RTP_H263_AP) << 12;
  4496. // Set the S bit
  4497. dwHeaderHigh |= (pbsiT->dwFlags & RTP_H263_SAC) << 10;
  4498. // Set the GOBN bits
  4499. dwHeaderHigh |= ((DWORD)(pbsi263->byGOBN)) << 8;
  4500. // Set the TR bits
  4501. dwHeaderHigh |= ((DWORD)(pbsi263->byMBA));
  4502. // Set the HMV1 bits
  4503. dwHeaderLow |= ((DWORD)(BYTE)(pbsi263->cHMV1)) << 24;
  4504. // Set the VMV1 bits
  4505. dwHeaderLow |= ((DWORD)(BYTE)(pbsi263->cVMV1)) << 16;
  4506. // Set the HMV2 bits
  4507. dwHeaderLow |= ((DWORD)(BYTE)(pbsi263->cHMV2)) << 8;
  4508. // Set the VMV2 bits
  4509. dwHeaderLow |= ((DWORD)(BYTE)(pbsi263->cVMV2));
  4510. // Special case: 1 frame = 1 packet
  4511. if (bOneFrameOnePacket)
  4512. {
  4513. // SBIT is already set to 0
  4514. // EBIT is already set to 0
  4515. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  4516. ERRORMESSAGE(("vcmFormatPayload: (1F1P) Previous EBIT=%ld, current SBIT=%ld, current EBIT=%ld (New frame)\r\n", g_dwPreviousEBIT, (DWORD)(dwHeaderHigh & 0x38000000) >> 27, (DWORD)(dwHeaderHigh & 0x07000000) >> 24));
  4517. #endif // } VALIDATE_SBIT_EBIT
  4518. // Update the packet size
  4519. *pdwPktSize = pbsiT->dwCompressedSize + 8;
  4520. // Update the packet count
  4521. *pdwPktCount = pbsiT->dwNumOfPackets;
  4522. }
  4523. else
  4524. {
  4525. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  4526. DWORD dwCurrentSBIT;
  4527. #endif // } VALIDATE_SBIT_EBIT
  4528. // Set the SBIT bits
  4529. dwHeaderHigh |= (pbsi263->dwBitOffset % 8) << 27;
  4530. // Set the EBIT bits
  4531. if ((pbsiT->dwNumOfPackets - *pdwPktCount - i) >= 1)
  4532. dwHeaderHigh |= (DWORD)((8UL - ((pbsi263+i)->dwBitOffset % 8)) & 0x00000007) << 24;
  4533. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  4534. // Compare this to the previous EBIT. If the sum of the two
  4535. // is not equal to 8 or 0, something's broken
  4536. if (*pdwPktCount)
  4537. ERRORMESSAGE(("vcmFormatPayload: Previous EBIT=%ld, current SBIT=%ld, current EBIT=%ld\r\n", g_dwPreviousEBIT, (DWORD)(dwHeaderHigh & 0x38000000) >> 27, (DWORD)(dwHeaderHigh & 0x07000000) >> 24));
  4538. else
  4539. ERRORMESSAGE(("vcmFormatPayload: Previous EBIT=%ld, current SBIT=%ld, current EBIT=%ld (New frame)\r\n", g_dwPreviousEBIT, (DWORD)(dwHeaderHigh & 0x38000000) >> 27, (DWORD)(dwHeaderHigh & 0x07000000) >> 24));
  4540. // Only test this if this is the first packet
  4541. dwCurrentSBIT = (DWORD)(dwHeaderHigh & 0x38000000) >> 27;
  4542. if ((*pdwPktCount) && (((dwCurrentSBIT + g_dwPreviousEBIT) != 8) && (((dwCurrentSBIT + g_dwPreviousEBIT) != 0))))
  4543. DebugBreak();
  4544. g_dwPreviousEBIT = (dwHeaderHigh & 0x07000000) >> 24;
  4545. #endif // } VALIDATE_SBIT_EBIT
  4546. // Update the packet size
  4547. if ((pbsiT->dwNumOfPackets - *pdwPktCount - i) >= 1)
  4548. *pdwPktSize = (((pbsi263+i)->dwBitOffset - 1) / 8) - (pbsi263->dwBitOffset / 8) + 1 + 8;
  4549. else
  4550. *pdwPktSize = pbsiT->dwCompressedSize - pbsi263->dwBitOffset / 8 + 8;
  4551. // Update the packet count
  4552. *pdwPktCount += i;
  4553. }
  4554. #if 0
  4555. // Save the header right before the data chunk
  4556. *ppDataPkt = pDataSrc + (pbsi263->dwBitOffset / 8) - 8;
  4557. // Convert to network byte order
  4558. *((BYTE *)*ppDataPkt+3) = (BYTE)(dwHeaderHigh & 0x000000FF);
  4559. *((BYTE *)*ppDataPkt+2) = (BYTE)((dwHeaderHigh >> 8) & 0x000000FF);
  4560. *((BYTE *)*ppDataPkt+1) = (BYTE)((dwHeaderHigh >> 16) & 0x000000FF);
  4561. *((BYTE *)*ppDataPkt) = (BYTE)((dwHeaderHigh >> 24) & 0x000000FF);
  4562. *((BYTE *)*ppDataPkt+7) = (BYTE)(dwHeaderLow & 0x000000FF);
  4563. *((BYTE *)*ppDataPkt+6) = (BYTE)((dwHeaderLow >> 8) & 0x000000FF);
  4564. *((BYTE *)*ppDataPkt+5) = (BYTE)((dwHeaderLow >> 16) & 0x000000FF);
  4565. *((BYTE *)*ppDataPkt+4) = (BYTE)((dwHeaderLow >> 24) & 0x000000FF);
  4566. #else
  4567. // Save the header right before the data chunk
  4568. *ppDataPkt = pDataSrc + (pbsi263->dwBitOffset / 8) - 8;
  4569. *pdwHdrSize=8;
  4570. // Convert to network byte order
  4571. *((BYTE *)*pHdrInfo+3) = (BYTE)(dwHeaderHigh & 0x000000FF);
  4572. *((BYTE *)*pHdrInfo+2) = (BYTE)((dwHeaderHigh >> 8) & 0x000000FF);
  4573. *((BYTE *)*pHdrInfo+1) = (BYTE)((dwHeaderHigh >> 16) & 0x000000FF);
  4574. *((BYTE *)*pHdrInfo) = (BYTE)((dwHeaderHigh >> 24) & 0x000000FF);
  4575. *((BYTE *)*pHdrInfo+7) = (BYTE)(dwHeaderLow & 0x000000FF);
  4576. *((BYTE *)*pHdrInfo+6) = (BYTE)((dwHeaderLow >> 8) & 0x000000FF);
  4577. *((BYTE *)*pHdrInfo+5) = (BYTE)((dwHeaderLow >> 16) & 0x000000FF);
  4578. *((BYTE *)*pHdrInfo+4) = (BYTE)((dwHeaderLow >> 24) & 0x000000FF);
  4579. #endif
  4580. #ifdef LOGPAYLOAD_ON
  4581. // Output some info
  4582. wsprintf(szDebug, "Header content:\r\n");
  4583. OutputDebugString(szDebug);
  4584. wsprintf(szDebug, (*(BYTE *)*ppDataPkt & 0x80) ? " F: '1' => Mode B or C\r\n" : " F: '0' => Mode A\r\n");
  4585. OutputDebugString(szDebug);
  4586. wsprintf(szDebug, (*(BYTE *)*ppDataPkt & 0x40) ? " P: '1' => PB-frame\r\n" : " P: '0' => I or P frame\r\n");
  4587. OutputDebugString(szDebug);
  4588. wsprintf(szDebug, " SBIT: %01ld\r\n", (DWORD)((*(BYTE *)*ppDataPkt & 0x38) >> 3));
  4589. OutputDebugString(szDebug);
  4590. wsprintf(szDebug, " EBIT: %01ld\r\n", (DWORD)(*(BYTE *)*ppDataPkt & 0x07));
  4591. OutputDebugString(szDebug);
  4592. switch ((DWORD)(*((BYTE *)*ppDataPkt+1) >> 5))
  4593. {
  4594. case 0:
  4595. wsprintf(szDebug, " SRC: '000' => Source format forbidden!\r\n");
  4596. break;
  4597. case 1:
  4598. wsprintf(szDebug, " SRC: '001' => Source format sub-QCIF\r\n");
  4599. break;
  4600. case 2:
  4601. wsprintf(szDebug, " SRC: '010' => Source format QCIF\r\n");
  4602. break;
  4603. case 3:
  4604. wsprintf(szDebug, " SRC: '011' => Source format CIF\r\n");
  4605. break;
  4606. case 4:
  4607. wsprintf(szDebug, " SRC: '100' => Source format 4CIF\r\n");
  4608. break;
  4609. case 5:
  4610. wsprintf(szDebug, " SRC: '101' => Source format 16CIF\r\n");
  4611. break;
  4612. case 6:
  4613. wsprintf(szDebug, " SRC: '110' => Source format reserved\r\n");
  4614. break;
  4615. case 7:
  4616. wsprintf(szDebug, " SRC: '111' => Source format reserved\r\n");
  4617. break;
  4618. default:
  4619. wsprintf(szDebug, " SRC: %ld => Source format unknown!\r\n", (DWORD)(*((BYTE *)*ppDataPkt+1) >> 5));
  4620. break;
  4621. }
  4622. OutputDebugString(szDebug);
  4623. wsprintf(szDebug, " QUANT: %02ld\r\n", (DWORD)((*((BYTE *)*ppDataPkt+1) & 0x1F) >> 5));
  4624. OutputDebugString(szDebug);
  4625. wsprintf(szDebug, (*((BYTE *)*ppDataPkt+2) & 0x80) ? " I: '1' => Intra-coded\r\n" : " I: '0' => Not Intra-coded\r\n");
  4626. OutputDebugString(szDebug);
  4627. wsprintf(szDebug, (*((BYTE *)*ppDataPkt+2) & 0x40) ? " A: '1' => Optional Advanced Prediction mode ON\r\n" : " A: '0' => Optional Advanced Prediction mode OFF\r\n");
  4628. OutputDebugString(szDebug);
  4629. wsprintf(szDebug, (*((BYTE *)*ppDataPkt+2) & 0x20) ? " S: '1' => Optional Syntax-based Arithmetic Code mode ON\r\n" : " S: '0' => Optional Syntax-based Arithmetic Code mode OFF\r\n");
  4630. OutputDebugString(szDebug);
  4631. wsprintf(szDebug, " GOBN: %03ld\r\n", (DWORD)(*((BYTE *)*ppDataPkt+2) & 0x1F));
  4632. OutputDebugString(szDebug);
  4633. wsprintf(szDebug, " MBA: %03ld\r\n", (DWORD)(*((BYTE *)*ppDataPkt+3)));
  4634. OutputDebugString(szDebug);
  4635. wsprintf(szDebug, " HMV1: %03ld\r\n", (DWORD)(*((BYTE *)*ppDataPkt+7)));
  4636. OutputDebugString(szDebug);
  4637. wsprintf(szDebug, " VMV1: %03ld\r\n", (DWORD)(*((BYTE *)*ppDataPkt+6)));
  4638. OutputDebugString(szDebug);
  4639. wsprintf(szDebug, " HMV2: %03ld\r\n", (DWORD)(*((BYTE *)*ppDataPkt+5)));
  4640. OutputDebugString(szDebug);
  4641. wsprintf(szDebug, " VMV2: %03ld\r\n", (DWORD)(*((BYTE *)*ppDataPkt+4)));
  4642. OutputDebugString(szDebug);
  4643. wsprintf(szDebug, "Packet: %02lX\r\n Header: %02lX %02lX %02lX %02lX %02lX %02lX %02lX %02lX\r\n dword1: %02lX %02lX %02lX %02lX\r\n", *pdwPktCount, *((BYTE *)*ppDataPkt), *((BYTE *)*ppDataPkt+1), *((BYTE *)*ppDataPkt+2), *((BYTE *)*ppDataPkt+3), *((BYTE *)*ppDataPkt+4), *((BYTE *)*ppDataPkt+5), *((BYTE *)*ppDataPkt+6), *((BYTE *)*ppDataPkt+7), *((BYTE *)*ppDataPkt+8), *((BYTE *)*ppDataPkt+9), *((BYTE *)*ppDataPkt+10), *((BYTE *)*ppDataPkt+11));
  4644. OutputDebugString(szDebug);
  4645. if (*pdwPktCount == pbsiT->dwNumOfPackets)
  4646. wsprintf(szDebug, " Tail : %02lX %02lX XX XX\r\n", *((BYTE *)*ppDataPkt+*pdwPktSize-2), *((BYTE *)*ppDataPkt+*pdwPktSize-1));
  4647. else
  4648. wsprintf(szDebug, " Tail : %02lX %02lX %02lX %02lX\r\n", *((BYTE *)*ppDataPkt+*pdwPktSize-2), *((BYTE *)*ppDataPkt+*pdwPktSize-1), *((BYTE *)*ppDataPkt+*pdwPktSize), *((BYTE *)*ppDataPkt+*pdwPktSize+1));
  4649. OutputDebugString(szDebug);
  4650. if (*pfMark == 1)
  4651. wsprintf(szDebug, " Marker: ON\r\n");
  4652. else
  4653. wsprintf(szDebug, " Marker: OFF\r\n");
  4654. OutputDebugString(szDebug);
  4655. wsprintf(szDebug, "Frame #%03ld, Packet of size %04ld\r\n", (DWORD)pbsiT->byTR, *pdwPktSize);
  4656. OutputDebugString(szDebug);
  4657. #endif
  4658. }
  4659. else if (pbsi263->byMode == RTP_H263_MODE_C)
  4660. {
  4661. // Build a header in mode C
  4662. #ifdef DEBUG
  4663. wsprintf(szDebug, "VCMSTRM: We were asked to generate a MODE C H.263 payload header!");
  4664. OutputDebugString(szDebug);
  4665. // DebugBreak();
  4666. #endif
  4667. return ((MMRESULT)VCMERR_NONSPECIFIC);
  4668. }
  4669. }
  4670. else
  4671. return ((MMRESULT)VCMERR_NOMOREPACKETS);
  4672. }
  4673. #ifndef _ALPHA_
  4674. else if (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH261)
  4675. #else
  4676. else if (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_DECH261)
  4677. #endif
  4678. {
  4679. // Look for the bitstream info trailer
  4680. pbsiT = (PH26X_RTP_BSINFO_TRAILER)(pDataSrc + dwDataSize - sizeof(H26X_RTP_BSINFO_TRAILER));
  4681. // If the whole frame can fit in dwMaxFragSize, send it non fragmented
  4682. if ((pbsiT->dwCompressedSize + 4) < pvs->dwMaxPacketSize)
  4683. bOneFrameOnePacket = TRUE;
  4684. // Look for the packet to receive a H.261 payload header
  4685. if ((*pdwPktCount < pbsiT->dwNumOfPackets) && !(bOneFrameOnePacket && *pdwPktCount))
  4686. {
  4687. #ifdef _ALPHA_
  4688. // Verify that the content of the bistream info structures is correct
  4689. // If not, do not parse the frame, and fail the call
  4690. // This is to solve problems with the data returned by the DEC codecs
  4691. if (!*pdwPktCount)
  4692. {
  4693. pbsi261 = (PRTP_H261_BSINFO)((PBYTE)pbsiT - pbsiT->dwNumOfPackets * sizeof(RTP_H261_BSINFO));
  4694. for (i=1; i<(long)pbsiT->dwNumOfPackets; i++, pbsi261++)
  4695. {
  4696. if ((pbsi261->dwBitOffset >= (pbsi261+1)->dwBitOffset) || ((pbsiT->dwCompressedSize*8) <= pbsi261->dwBitOffset))
  4697. {
  4698. #ifdef DEBUG
  4699. OutputDebugString("VCMSTRM: The content of the extended bitstream info structures is invalid!\r\n");
  4700. #endif
  4701. // return ((MMRESULT)VCMERR_NONSPECIFIC);
  4702. bOneFrameOnePacket = TRUE;
  4703. }
  4704. }
  4705. // Test last info strucure
  4706. if ( !bOneFrameOnePacket && ((pbsiT->dwCompressedSize*8) <= pbsi261->dwBitOffset))
  4707. {
  4708. #ifdef DEBUG
  4709. OutputDebugString("VCMSTRM: The content of the extended bitstream info structures is invalid!\r\n");
  4710. #endif
  4711. // return ((MMRESULT)VCMERR_NONSPECIFIC);
  4712. bOneFrameOnePacket = TRUE;
  4713. }
  4714. }
  4715. #endif
  4716. #ifdef LOGPAYLOAD_ON
  4717. // Dump the whole frame in the debug window for comparison with receive side
  4718. if (!*pdwPktCount)
  4719. {
  4720. g_DebugFile = CreateFile("C:\\SendLog.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  4721. SetFilePointer(g_DebugFile, 0, NULL, FILE_END);
  4722. wsprintf(szDebug, "Frame #%03ld\r\n", (DWORD)pbsiT->byTR);
  4723. WriteFile(g_DebugFile, szDebug, strlen(szDebug), &d, NULL);
  4724. wsprintf(szDebug, "Frame #%03ld has %1ld GOBs of size ", (DWORD)pbsiT->byTR, (DWORD)pbsiT->dwNumOfPackets);
  4725. OutputDebugString(szDebug);
  4726. pbsi261 = (PRTP_H261_BSINFO)((PBYTE)pbsiT - pbsiT->dwNumOfPackets * sizeof(RTP_H261_BSINFO));
  4727. for (i=1; i<(long)pbsiT->dwNumOfPackets; i++)
  4728. {
  4729. wPrevOffset = pbsi261->dwBitOffset;
  4730. pbsi261++;
  4731. wsprintf(szDebug, "%04ld, ", (DWORD)(pbsi261->dwBitOffset - wPrevOffset) >> 3);
  4732. OutputDebugString(szDebug);
  4733. }
  4734. wsprintf(szDebug, "%04ld\r\n", (DWORD)(pbsiT->dwCompressedSize * 8 - pbsi261->dwBitOffset) >> 3);
  4735. OutputDebugString(szDebug);
  4736. for (i=pbsiT->dwCompressedSize, p=pDataSrc; i>0; i-=4, p+=4)
  4737. {
  4738. wsprintf(szDebug, "%02lX %02lX %02lX %02lX\r\n", *((BYTE *)p), *((BYTE *)p+1), *((BYTE *)p+2), *((BYTE *)p+3));
  4739. WriteFile(g_DebugFile, szDebug, strlen(szDebug), &d, NULL);
  4740. }
  4741. CloseHandle(g_DebugFile);
  4742. }
  4743. #endif
  4744. // Look for the bitstream info structure
  4745. pbsi261 = (PRTP_H261_BSINFO)((PBYTE)pbsiT - (pbsiT->dwNumOfPackets - *pdwPktCount) * sizeof(RTP_H261_BSINFO));
  4746. // Set the marker bit: as long as this is not the last packet of the frame
  4747. // this bit needs to be set to 0
  4748. if (!bOneFrameOnePacket)
  4749. {
  4750. // Count the number of GOBS that could fit in dwMaxFragSize
  4751. for (i=1; i<(long)(pbsiT->dwNumOfPackets - *pdwPktCount); i++)
  4752. {
  4753. if ((pbsi261+i)->dwBitOffset - pbsi261->dwBitOffset > (pvs->dwMaxPacketSize * 8))
  4754. break;
  4755. }
  4756. if (i < (long)(pbsiT->dwNumOfPackets - *pdwPktCount))
  4757. {
  4758. *pfMark = 0;
  4759. if (i>1)
  4760. i--;
  4761. }
  4762. else
  4763. {
  4764. // Hey! You 're forgetting the last GOB! It could make the total
  4765. // size of the last packet larger than dwMaxFragSize... Imbecile!
  4766. if ((pbsiT->dwCompressedSize * 8 - pbsi261->dwBitOffset > (pvs->dwMaxPacketSize * 8)) && (i>1))
  4767. {
  4768. *pfMark = 0;
  4769. i--;
  4770. }
  4771. }
  4772. }
  4773. // Go to the beginning of the data
  4774. pb = pDataSrc + pbsi261->dwBitOffset / 8;
  4775. #ifdef DEBUG
  4776. if (!*pdwPktCount && ((*pb != 0) || (*(pb+1) != 1)))
  4777. {
  4778. wsprintf(szDebug, "VCMSTRM: This GOB is missing a GOB Start!");
  4779. OutputDebugString(szDebug);
  4780. // DebugBreak();
  4781. }
  4782. #endif
  4783. // Build a header to this thing!
  4784. // 0 1 2 3
  4785. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  4786. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4787. //|SBIT |EBIT |I|V| GOBN | MBAP | QUANT | HMVD | VMVD |
  4788. //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4789. // But that's the network byte order...
  4790. // Set the V bit to 1
  4791. dwHeaderHigh |= 0x01000000;
  4792. // Set the I bit
  4793. dwHeaderHigh |= (pbsiT->dwFlags & RTP_H26X_INTRA_CODED) << 25;
  4794. // Set the GOBn bits
  4795. dwHeaderHigh |= ((DWORD)(pbsi261->byGOBN)) << 20;
  4796. // Set the MBAP bits
  4797. dwHeaderHigh |= ((DWORD)(pbsi261->byMBA)) << 15;
  4798. // Set the QUANT bits
  4799. dwHeaderHigh |= ((DWORD)(pbsi261->byQuant)) << 10;
  4800. // Set the HMVD bits
  4801. dwHeaderHigh |= ((DWORD)(BYTE)(pbsi261->cHMV)) << 5;
  4802. // Set the VMVD bits
  4803. dwHeaderHigh |= ((DWORD)(BYTE)(pbsi261->cVMV));
  4804. // Special case: 1 frame = 1 packet
  4805. if (bOneFrameOnePacket)
  4806. {
  4807. // SBIT is already set to 0
  4808. // EBIT is already set to 0
  4809. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  4810. ERRORMESSAGE(("vcmFormatPayload: (1F1P) Previous EBIT=%ld, current SBIT=%ld, current EBIT=%ld (New frame)\r\n", g_dwPreviousEBIT, (DWORD)(dwHeaderHigh & 0xE0000000) >> 29, (DWORD)(dwHeaderHigh & 0x1C000000) >> 26));
  4811. #endif // } VALIDATE_SBIT_EBIT
  4812. // Update the packet size
  4813. *pdwPktSize = pbsiT->dwCompressedSize + 4;
  4814. // Update the packet count
  4815. *pdwPktCount = pbsiT->dwNumOfPackets;
  4816. }
  4817. else
  4818. {
  4819. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  4820. DWORD dwCurrentSBIT;
  4821. #endif // } VALIDATE_SBIT_EBIT
  4822. // Set the SBIT bits
  4823. dwHeaderHigh |= (pbsi261->dwBitOffset % 8) << 29;
  4824. // Set the EBIT bits
  4825. if ((pbsiT->dwNumOfPackets - *pdwPktCount - i) >= 1)
  4826. dwHeaderHigh |= (DWORD)((8UL - ((pbsi261+i)->dwBitOffset % 8)) & 0x00000007) << 26;
  4827. #ifdef VALIDATE_SBIT_EBIT // { VALIDATE_SBIT_EBIT
  4828. // Compare this to the previous EBIT. If the sum of the two
  4829. // is not equal to 8, something's broken
  4830. if (*pdwPktCount)
  4831. ERRORMESSAGE(("vcmFormatPayload: Previous EBIT=%ld, current SBIT=%ld, current EBIT=%ld\r\n", g_dwPreviousEBIT, (DWORD)(dwHeaderHigh & 0xE0000000) >> 29, (DWORD)(dwHeaderHigh & 0x1C000000) >> 26));
  4832. else
  4833. ERRORMESSAGE(("vcmFormatPayload: Previous EBIT=%ld, current SBIT=%ld, current EBIT=%ld (New frame)\r\n", g_dwPreviousEBIT, (DWORD)(dwHeaderHigh & 0xE0000000) >> 29, (DWORD)(dwHeaderHigh & 0x1C000000) >> 26));
  4834. // Only test this if this is the first packet
  4835. dwCurrentSBIT = (DWORD)(dwHeaderHigh & 0xE0000000) >> 29;
  4836. if ((*pdwPktCount) && (((dwCurrentSBIT + g_dwPreviousEBIT) != 8) && (((dwCurrentSBIT + g_dwPreviousEBIT) != 0))))
  4837. DebugBreak();
  4838. g_dwPreviousEBIT = (dwHeaderHigh & 0x1C000000) >> 26;
  4839. #endif // } VALIDATE_SBIT_EBIT
  4840. // Update the packet size
  4841. if ((pbsiT->dwNumOfPackets - *pdwPktCount - i) >= 1)
  4842. *pdwPktSize = (((pbsi261+i)->dwBitOffset - 1) / 8) - (pbsi261->dwBitOffset / 8) + 1 + 4;
  4843. else
  4844. *pdwPktSize = pbsiT->dwCompressedSize - pbsi261->dwBitOffset / 8 + 4;
  4845. // Update the packet count
  4846. *pdwPktCount += i;
  4847. }
  4848. #if 0
  4849. // Save the header right before the data chunk
  4850. *ppDataPkt = pDataSrc + (pbsi261->dwBitOffset / 8) - 4;
  4851. // Convert to network byte order
  4852. *((BYTE *)*ppDataPkt+3) = (BYTE)(dwHeaderHigh & 0x000000FF);
  4853. *((BYTE *)*ppDataPkt+2) = (BYTE)((dwHeaderHigh >> 8) & 0x000000FF);
  4854. *((BYTE *)*ppDataPkt+1) = (BYTE)((dwHeaderHigh >> 16) & 0x000000FF);
  4855. *((BYTE *)*ppDataPkt) = (BYTE)((dwHeaderHigh >> 24) & 0x000000FF);
  4856. #else
  4857. // Save the header right before the data chunk
  4858. *ppDataPkt = pDataSrc + (pbsi261->dwBitOffset / 8) - 4;
  4859. *pdwHdrSize=4;
  4860. // Convert to network byte order
  4861. *((BYTE *)*pHdrInfo+3) = (BYTE)(dwHeaderHigh & 0x000000FF);
  4862. *((BYTE *)*pHdrInfo+2) = (BYTE)((dwHeaderHigh >> 8) & 0x000000FF);
  4863. *((BYTE *)*pHdrInfo+1) = (BYTE)((dwHeaderHigh >> 16) & 0x000000FF);
  4864. *((BYTE *)*pHdrInfo) = (BYTE)((dwHeaderHigh >> 24) & 0x000000FF);
  4865. #endif
  4866. #ifdef LOGPAYLOAD_ON
  4867. // Output some debug stuff
  4868. wsprintf(szDebug, "Packet: %02lX\r\n Header: %02lX %02lX %02lX %02lX\r\n dword1: %02lX %02lX %02lX %02lX\r\n dword2: %02lX %02lX %02lX %02lX\r\n", *pdwPktCount, *((BYTE *)*ppDataPkt), *((BYTE *)*ppDataPkt+1), *((BYTE *)*ppDataPkt+2), *((BYTE *)*ppDataPkt+3), *((BYTE *)*ppDataPkt+4), *((BYTE *)*ppDataPkt+5), *((BYTE *)*ppDataPkt+6), *((BYTE *)*ppDataPkt+7), *((BYTE *)*ppDataPkt+8), *((BYTE *)*ppDataPkt+9), *((BYTE *)*ppDataPkt+10), *((BYTE *)*ppDataPkt+11));
  4869. OutputDebugString(szDebug);
  4870. if (*pdwPktCount == pbsiT->dwNumOfPackets)
  4871. wsprintf(szDebug, " Tail : %02lX %02lX XX XX\r\n", *((BYTE *)*ppDataPkt+*pdwPktSize-2), *((BYTE *)*ppDataPkt+*pdwPktSize-1));
  4872. else
  4873. wsprintf(szDebug, " Tail : %02lX %02lX %02lX %02lX\r\n", *((BYTE *)*ppDataPkt+*pdwPktSize-2), *((BYTE *)*ppDataPkt+*pdwPktSize-1), *((BYTE *)*ppDataPkt+*pdwPktSize), *((BYTE *)*ppDataPkt+*pdwPktSize+1));
  4874. OutputDebugString(szDebug);
  4875. if (*pfMark == 1)
  4876. wsprintf(szDebug, " Marker: ON\r\n");
  4877. else
  4878. wsprintf(szDebug, " Marker: OFF\r\n");
  4879. OutputDebugString(szDebug);
  4880. wsprintf(szDebug, "Frame #%03ld, Packet of size %04ld\r\n", (DWORD)pbsiT->byTR, *pdwPktSize);
  4881. OutputDebugString(szDebug);
  4882. #endif
  4883. }
  4884. else
  4885. return ((MMRESULT)VCMERR_NOMOREPACKETS);
  4886. }
  4887. else
  4888. {
  4889. if (!*pdwPktCount)
  4890. {
  4891. *pdwPktCount = 1;
  4892. *pdwHdrSize = 0;
  4893. }
  4894. else
  4895. return ((MMRESULT)VCMERR_NOMOREPACKETS);
  4896. }
  4897. return ((MMRESULT)MMSYSERR_NOERROR);
  4898. }
  4899. /****************************************************************************
  4900. * @doc EXTERNAL COMPFUNC
  4901. *
  4902. * @func MMRESULT | vcmStreamGetPayloadHeaderSize | This function gets the size
  4903. * of the RTP payload header associated to a video codec.
  4904. *
  4905. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  4906. *
  4907. * @parm PDWORD | pdwPayloadHeaderSize | Specifies a pointer to the payload header size.
  4908. *
  4909. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  4910. * an error number. Possible error values include the following:
  4911. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  4912. * @flag MMSYSERR_INVALPARAM | Specified saturation value is invalid.
  4913. *
  4914. * @xref <f vcmStreamFormatPayload>
  4915. ***************************************************************************/
  4916. MMRESULT VCMAPI vcmStreamGetPayloadHeaderSize(HVCMSTREAM hvs, PDWORD pdwPayloadHeaderSize)
  4917. {
  4918. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  4919. // Check input params
  4920. if (!hvs)
  4921. {
  4922. ERRORMESSAGE(("vcmStreamGetPayloadHeaderSize: Specified handle is invalid, hvs=NULL\r\n"));
  4923. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  4924. }
  4925. if (!pdwPayloadHeaderSize)
  4926. {
  4927. ERRORMESSAGE(("vcmStreamGetPayloadHeaderSize: Specified pointer is invalid, pdwPayloadHeaderSize=NULL\r\n"));
  4928. return ((MMRESULT)MMSYSERR_INVALPARAM);
  4929. }
  4930. // Set default payload header size to 0
  4931. *pdwPayloadHeaderSize = 0;
  4932. // The name of the codec will tell us how to get to the payload header size info
  4933. #ifndef _ALPHA_
  4934. #ifdef USE_BILINEAR_MSH26X
  4935. if ((pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH263) || (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH26X))
  4936. #else
  4937. if (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH263)
  4938. #endif
  4939. #else
  4940. if (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_DECH263)
  4941. #endif
  4942. {
  4943. // H.263 has a max payload header size of 12 bytes
  4944. *pdwPayloadHeaderSize = 12;
  4945. }
  4946. #ifndef _ALPHA_
  4947. else if (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_MSH261)
  4948. #else
  4949. else if (pvs->pvfxDst->dwFormatTag == VIDEO_FORMAT_DECH261)
  4950. #endif
  4951. {
  4952. // H.261 has a unique payload header size of 4 bytes
  4953. *pdwPayloadHeaderSize = 4;
  4954. }
  4955. return ((MMRESULT)MMSYSERR_NOERROR);
  4956. }
  4957. /****************************************************************************
  4958. * @doc EXTERNAL COMPFUNC
  4959. *
  4960. * @func MMRESULT | vcmStreamRequestIFrame | This function forces the
  4961. * codec to generate an I-Frame.
  4962. *
  4963. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  4964. *
  4965. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  4966. * an error number. Possible error values include the following:
  4967. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  4968. *
  4969. ***************************************************************************/
  4970. MMRESULT VCMAPI vcmStreamRequestIFrame(HVCMSTREAM hvs)
  4971. {
  4972. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  4973. // Check input params
  4974. if (!hvs)
  4975. {
  4976. ERRORMESSAGE(("vcmStreamRequestIFrame: Specified handle is invalid, hvs=NULL\r\n"));
  4977. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  4978. }
  4979. DEBUGMSG (ZONE_VCM, ("vcmStreamRequestIFrame: Requesting an I-Frame...\r\n"));
  4980. // We need the following crs to make sure we don't miss any of the I-Frame requests
  4981. // emitted by the UI. Problematic scenario: pvs->dwFrame is at 123 for instance.
  4982. // The UI thread requests an I-Frame by setting pvs->dwFrame to 0. If the capture/compression
  4983. // thread was in ICCompress() (which is very probable since it takes quite some time
  4984. // to compress a frame), pvs->dwFrame will be incremented by one when ICCompress()
  4985. // returns. We fail to handle the I-Frame request correctly, since the next time
  4986. // ICCompress() gets called pvs->dwFrame will be equal to 1, for which we do not
  4987. // generate an I-Frame.
  4988. EnterCriticalSection(&pvs->crsFrameNumber);
  4989. // Set the frame number to 0. This will force the codec to generate an I-Frame
  4990. pvs->dwFrame = 0;
  4991. // Allow the capture/compression thread to proceed.
  4992. LeaveCriticalSection(&pvs->crsFrameNumber);
  4993. return ((MMRESULT)MMSYSERR_NOERROR);
  4994. }
  4995. /****************************************************************************
  4996. * @doc EXTERNAL COMPFUNC
  4997. *
  4998. * @func MMRESULT | vcmStreamPeriodicIFrames | This function enables or
  4999. * disables generation of I-Frames periodically.
  5000. *
  5001. * @parm HVCMSTREAM | hvs | Specifies the conversion stream.
  5002. *
  5003. * @parm BOOL | fPeriodicIFrames | Set to TRUE to generate I-Frames
  5004. * periodically, FALSE otherwise.
  5005. *
  5006. * @rdesc The return value is zero if the function is successful. Otherwise, it returns
  5007. * an error number. Possible error values include the following:
  5008. * @flag MMSYSERR_INVALHANDLE | Specified handle is invalid.
  5009. *
  5010. ***************************************************************************/
  5011. MMRESULT VCMAPI vcmStreamPeriodicIFrames(HVCMSTREAM hvs, BOOL fPeriodicIFrames)
  5012. {
  5013. PVCMSTREAM pvs = (PVCMSTREAM)hvs;
  5014. // Check input params
  5015. if (!hvs)
  5016. {
  5017. ERRORMESSAGE(("vcmStreamDisablePeriodicIFrames: Specified handle is invalid, hvs=NULL\r\n"));
  5018. return ((MMRESULT)MMSYSERR_INVALHANDLE);
  5019. }
  5020. DEBUGMSG (ZONE_VCM, ("vcmStreamDisablePeriodicIFrames: Disabling periodic generation of I-Frames...\r\n"));
  5021. // No more periodic I-Frames
  5022. pvs->fPeriodicIFrames = fPeriodicIFrames;
  5023. return ((MMRESULT)MMSYSERR_NOERROR);
  5024. }
  5025. // frees memory prior to shutdown
  5026. MMRESULT VCMAPI vcmReleaseResources()
  5027. {
  5028. if (g_aVCMAppInfo)
  5029. {
  5030. MemFree(g_aVCMAppInfo);
  5031. g_aVCMAppInfo = NULL;
  5032. }
  5033. return MMSYSERR_NOERROR;
  5034. }