Leaked source code of windows server 2003
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.

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