//====================================================================== // CameraCode.cpp // // This file contains routines that interface with the WebCam driver. // // Copyright (C) 2006 Douglas Boling // //====================================================================== #include "CameraCode.h" // Defines for this file #include "mjpeg2bmp.h" // Routines for converting MJPEG frames extern HANDLE SemBlob; DWORD WINAPI ReadFrameThread (PVOID pArg);//DWORD = typedef unsigned long #define NUMBUFFS 5 #define PREBUFFSIZE 512 typedef struct { BOOL fCont; HANDLE hCam; HANDLE hThread; BOOL fDraw; } CAMSTATE, *PCAMSTATE; typedef struct { PCAMSTATE pcs; WORD wFormat; WORD wFrame; DWORD dwInterval; RECT rect; HDC hdc; } THREADSTRUCT, *PTHREADSTRUCT; // Returns information on a given format int GetFormatInformation (PCAMSTATE, WORD wFormat, WORD wFrame, PFORMATPROPS pFmt); // Label for the standard features supported by the Video spec. The // order is important. LPTSTR szFeatureLbls[] = { TEXT("Unsupported"), // 0 TEXT("Scanning Mode"), // 1 TEXT("Auto-Exposure Mode"), // 2 TEXT("Auto-Exposure Priority"), // 3 TEXT("Exposure Time (Abs)"), // 4 TEXT("Exposure Time (Rel)"), // 5 TEXT("Focus (Abs)"), // 6 TEXT("Focus (Rel)"), // 7 TEXT("Iris (Abs)"), // 8 TEXT("Iris (Rel)"), // 9 TEXT("Zoom (Abs)"), // 10 TEXT("Zoom (Rel)"), // 11 TEXT("PanTilt (Abs)"), // 12 TEXT("PanTilt (Rel)"), // 13 TEXT("Roll (Abs)"), // 14 TEXT("Roll (Rel)"), // 15 TEXT("Focus, Auto"), // 16 TEXT("Privacy"), // 17 TEXT("Brightness"), // 18 TEXT("Contrast"), // 19 TEXT("Hue"), // 20 TEXT("Saturation"), // 21 TEXT("Sharpness"), // 22 TEXT("Gamma"), // 23 TEXT("White Balance Temp"), // 24 TEXT("White Balance Component"),// 25 TEXT("Backlight Compensation"), // 26 TEXT("Gain"), // 27 TEXT("Power Line Frequency"), // 28 TEXT("Hue-Auto"), // 29 TEXT("White Balance Temp-Auto"), // 30 TEXT("White Balance Component-Auto"),//31 TEXT("Digital Multiplier"), // 32 TEXT("Digital Multiplier Limit"),// 33 TEXT("Analog Video Standard"), // 34 TEXT("Analog Video Lock Status"), //35 }; //---------------------------------------------------------------------- // InitCamera - Opens the driver /** in: LPTSTR pszCamName out: DWORD pcs detail: create a variable pcs in the memory and initialise it. If no problem return (DWORD) pcs, else 0 */ DWORD InitCamera (LPTSTR pszCamName) { PCAMSTATE pcs = (PCAMSTATE)LocalAlloc (LPTR, sizeof (CAMSTATE)); if (pcs == 0) return 0; pcs->fCont = TRUE; pcs->hCam = INVALID_HANDLE_VALUE; pcs->fDraw = TRUE; pcs->hThread = 0; if (pcs->hCam == INVALID_HANDLE_VALUE) { // Open Driver pcs->hCam = CreateFile (pszCamName, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); if (pcs->hCam == INVALID_HANDLE_VALUE) { LocalFree ((PVOID)pcs); return 0; } } return (DWORD)pcs; } //---------------------------------------------------------------------- // ShutdownCamera - Stops streaming and closes the driver // /** in: DWORD dwContext out:int detail: stop streaming, close camera, free the memory , return 0 */ int ShutdownCamera (DWORD dwContext) { PCAMSTATE pcs = (PCAMSTATE)dwContext; if (pcs->fCont) StopStreaming (dwContext); if (pcs->hCam != INVALID_HANDLE_VALUE) { CloseHandle (pcs->hCam); } LocalFree ((PVOID)dwContext); return 0; } //---------------------------------------------------------------------- // SetDrawState - Sets or clears drawing state flag // /** in: DWORD dwContext, BOOL fDraw out:int detail:change the value of structure's camera's flag which is a bool :pcs->fDraw return 0 */ int SetDrawState (DWORD dwContext, BOOL fDraw) { PCAMSTATE pcs = (PCAMSTATE)dwContext; pcs->fDraw = fDraw; return 0; } //---------------------------------------------------------------------- // GetFeatureList // /** in:DWORD dwContext, PFEATUREPROPS pFeatures, DWORD *pdwSize out:int rc detail: PFEATUREPROPS: Structure used to return the array of features supported by the camera call the function DeviceIoControl:send a control code directly to a typical device driver if the result is false: rc = GetLastError else rc=0 return rc an integer */ int GetFeatureList (DWORD dwContext, PFEATUREPROPS pFeatures, DWORD *pdwSize) { int rc = 0; BOOL f; DWORD dwBytes; PCAMSTATE pcs = (PCAMSTATE)dwContext; if (pdwSize == 0) return ERROR_INVALID_PARAMETER; // See if they're asking for the number of supported features if (pFeatures == 0) { // // Get parameter list size // f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_QUERYPARAMETERARARY, 0, 0, 0, 0, pdwSize, NULL); if (!f) rc = GetLastError(); } else { // Get parameter list f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_QUERYPARAMETERARARY, 0, 0, pFeatures, *pdwSize, &dwBytes, NULL); if (!f) rc = GetLastError(); } return rc; } //---------------------------------------------------------------------- // GetFeatureText - Helper function that labels feature IDs // /** in:DWORD dwFeatureID out:LPCTSTR detail: typedef CONST WCHAR *LPCWSTR, *PCWSTR; typedef WCHAR *LPWSTR, *PWSTR; typedef LPWSTR PTSTR, LPTSTR; typedef LPCWSTR PCTSTR, LPCTSTR; init pstr and return pstr: camera structure ?????????????????????????????????????????????????????????????????? */ LPCTSTR GetFeatureText (DWORD dwFeatureID) { LPTSTR pstr = L""; if (dwFeatureID < dim (szFeatureLbls)) pstr = szFeatureLbls[dwFeatureID]; return pstr; } //---------------------------------------------------------------------- // GetFeatureSetting - Queries a setting from the camera // /** in: DWORD dwContext, DWORD dwFeature, DWORD *pVal out: int rc detail: call the function DeviceIoControl:send a control code directly to a typical device driver if the result is false: rc = GetLastError else rc=0 */ int GetFeatureSetting (DWORD dwContext, DWORD dwFeature, DWORD *pVal) { BOOL f; int rc = 0; DWORD dwBytes; PCAMSTATE pcs = (PCAMSTATE)dwContext; if (pVal == 0) return ERROR_INVALID_PARAMETER; f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_QUERYPARAMETER, &dwFeature, sizeof (DWORD), pVal, sizeof (DWORD), &dwBytes, NULL); if (!f) rc = GetLastError(); return rc; } //---------------------------------------------------------------------- // SetFeatureSetting - Sets a feature on the camera // /** in: DWORD dwContext, DWORD dwFeature, DWORD dwVal out: int rc detail: call the function DeviceIoControl:send a control code directly to a typical device driver if the result is false: rc = GetLastError else rc=0 */ int SetFeatureSetting (DWORD dwContext, DWORD dwFeature, DWORD dwVal) { BOOL f; int rc = 0; DWORD dwBytes; SETFEATURESTRUCT sfs;/// Structure used to set a parameter on the device PCAMSTATE pcs = (PCAMSTATE)dwContext; sfs.cbSize = sizeof (SETFEATURESTRUCT); sfs.dwFeatureID = dwFeature; sfs.dwVal = dwVal; f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_SETPARAMETER, &sfs, sizeof (SETFEATURESTRUCT), 0, 0, &dwBytes, NULL); if (!f) rc = GetLastError(); return rc; } //---------------------------------------------------------------------- // GetVideoFormats - Returns an array with the supported streaming // video formats // /** in:DWORD dwContext, PFORMATPROPS pFormats, int *pnCount out: int detail: return 0 */ int GetVideoFormats (DWORD dwContext, PFORMATPROPS pFormats, int *pnCount) { int i, rc, nCnt; PCAMSTATE pcs = (PCAMSTATE)dwContext; if (pnCount == 0) return 0; nCnt = *pnCount; *pnCount = 0; for (i = 0; i < nCnt; i++) { //void * memset(void *dest, int c, size_t count); memset (&pFormats[i], 0, sizeof (FORMATPROPS));//To set all the bytes in a block of memory to a particular value rc = GetFormatInformation (pcs, 1, i+1, &pFormats[i]); if (rc) break; (*pnCount)++; } return 0; } //---------------------------------------------------------------------- // GetStillFormats - Returns an array with the supported still // image formats // /** in:DWORD dwContext, PFORMATPROPS pFormats, int *pnCount out:int rc detail: call the function DeviceIoControl if the result is false: return rc = GetLastError else return rc=0 */ int GetStillFormats (DWORD dwContext, PFORMATPROPS pFormats, int *pnCount) { int rc = 0; DWORD dwBytes; BOOL f; PCAMSTATE pcs = (PCAMSTATE)dwContext; DWORD dwFormat = 1; DWORD dw = *pnCount * sizeof (FORMATPROPS); // // Get information about a given video format // f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_QUERYSTILLFORMATS, (LPVOID)&dwFormat, sizeof (DWORD), pFormats, dw, &dwBytes, NULL); if (!f) rc = GetLastError(); *pnCount = dwBytes / sizeof (FORMATPROPS); return rc; } //---------------------------------------------------------------------- // GetFormatInformation - Returns information about a specific streaming // video format // /** in: PCAMSTATE pcs, WORD wFormat, WORD wFrame, PFORMATPROPS pFmt out: int rc detail: */ int GetFormatInformation (PCAMSTATE pcs, WORD wFormat, WORD wFrame, PFORMATPROPS pFmt) { VIDFORMATSTRUCT vf;// Structure used to report video format currently streaming as well FORMATPROPS fmtData;// Structure to report the video formats available DWORD dwBytes; BOOL f; int rc; memset (&vf, 0, sizeof (vf)); vf.cbSize = sizeof (VIDFORMATSTRUCT); vf.wFormatIndex = wFormat; vf.wFrameIndex = wFrame; // // Get information about a given video format // f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_GETVIDEOFORMAT, (LPVOID)&vf, sizeof (VIDFORMATSTRUCT), &fmtData, sizeof (fmtData), &dwBytes, NULL); rc = GetLastError(); if (!f) { return rc; } if (dwBytes != sizeof (FORMATPROPS)) { return -1; } *pFmt = fmtData; return rc; } //---------------------------------------------------------------------- // GetFirstStreamFrame - Starts streaming video and returns the first // video frame. // /** in: DWORD dwContext, WORD wFormat, WORD wFrame, DWORD dwInterval, PBYTE *ppFrame, DWORD *pdwFrameSize, DWORD dwTimeout out:int rc detail: DeviceIoControl:send a control code directly to a typical device driver */ int GetFirstStreamFrame (DWORD dwContext, WORD wFormat, WORD wFrame, DWORD dwInterval, PBYTE *ppFrame, DWORD *pdwFrameSize, DWORD dwTimeout) { PCAMSTATE pcs = (PCAMSTATE)dwContext; STARTVIDSTRUCT svStruct;//Structure passed to driver when starting a video stream. DWORD dwBytes; BOOL f; int rc = 0; // Parameters needed to start a stream dwBytes = 0; svStruct.cbSize = sizeof (STARTVIDSTRUCT); svStruct.wFormatIndex = wFormat; svStruct.wFrameIndex = wFrame; svStruct.dwInterval = dwInterval; svStruct.dwNumBuffs = NUMBUFFS; svStruct.dwPreBuffSize = PREBUFFSIZE; svStruct.dwPostBuffSize = 0; // // Start the video stream // f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_STARTVIDEOSTREAM, (LPVOID)&svStruct, sizeof (STARTVIDSTRUCT), 0, 0, &dwBytes, NULL); if (f) { // Call the driver for a frame GETFRAMESTRUCT gfsIn; GETFRAMESTRUCTOUT gfsOut; memset (&gfsIn, 0, sizeof (GETFRAMESTRUCT)); gfsIn.cbSize = sizeof (GETFRAMESTRUCT); gfsIn.dwFlags = GETFRAMEFLAG_GET_LATESTFRAME; gfsIn.dwFlags |= GETFRAMEFLAG_TIMEOUT_VALID; gfsIn.dwTimeout = dwTimeout; memset (&gfsOut, 0, sizeof (GETFRAMESTRUCTOUT)); gfsOut.cbSize = sizeof (GETFRAMESTRUCTOUT); // Get the next frame of video f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_GETNEXTVIDEOFRAME, &gfsIn, sizeof (GETFRAMESTRUCT), &gfsOut, sizeof(GETFRAMESTRUCTOUT), &dwBytes, NULL); if (f) { *ppFrame = gfsOut.pFrameData; *pdwFrameSize = gfsOut.dwFrameSize; } } if (!f) rc = GetLastError(); return rc; } //---------------------------------------------------------------------- // GetNextStreamFrame - Returns the next available video frame. // int GetNextStreamFrame (DWORD dwContext, PBYTE *ppFrame, DWORD *pdwFrameSize, DWORD dwFlags, DWORD dwTimeout) { PCAMSTATE pcs = (PCAMSTATE)dwContext; GETFRAMESTRUCT gfsIn; GETFRAMESTRUCTOUT gfsOut; DWORD dwBytes; BOOL f; int rc = 0; gfsIn.cbSize = sizeof (GETFRAMESTRUCT); gfsIn.dwFlags = dwFlags; if (dwFlags & GETFRAMEFLAG_FREEBUFF_VALID) gfsIn.pFrameDataRet = *ppFrame; gfsIn.dwTimeout = dwTimeout; memset (&gfsOut, 0, sizeof (GETFRAMESTRUCTOUT)); gfsOut.cbSize = sizeof (GETFRAMESTRUCTOUT); // Call the driver f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_GETNEXTVIDEOFRAME, &gfsIn, sizeof (GETFRAMESTRUCT), &gfsOut, sizeof(GETFRAMESTRUCTOUT), &dwBytes, NULL); if (f) { *ppFrame = gfsOut.pFrameData; *pdwFrameSize = gfsOut.dwFrameSize; } if (!f) rc = GetLastError(); return rc; } //---------------------------------------------------------------------- // StreamFrameClose - Stops streaming of individual frames // int StreamFrameClose (DWORD dwContext) { PCAMSTATE pcs = (PCAMSTATE)dwContext; DWORD dwBytes; int rc = 0; // // Stop the stream // BOOL f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_STOPVIDEOSTREAM, 0, 0, 0, 0, &dwBytes, NULL); if (!f) rc = GetLastError(); return rc; } //---------------------------------------------------------------------- // StartStreaming - Starts streaming video to a device context at // the specified rectangle. // // If the .right and .bot fields of the rect structure are zero, the // image will be sized based on its original format. If the rect // structure is fully filled, the image will be sized to fit the rectangle // int StartStreaming (DWORD dwContext, HDC hdc, RECT * prect, WORD wFormat, WORD wFrame, DWORD dwInterval) { PCAMSTATE pcs; PTHREADSTRUCT pThd; pcs = (PCAMSTATE)dwContext; pThd = (PTHREADSTRUCT)LocalAlloc (LPTR, sizeof (THREADSTRUCT)); if (!pThd) return ERROR_NOT_ENOUGH_MEMORY; // Load parameter passing struct pThd->wFormat = wFormat; pThd->wFrame = wFrame; pThd->rect = *prect; pThd->dwInterval = dwInterval; pThd->hdc = hdc; pThd->pcs = pcs; if (pcs->hCam != INVALID_HANDLE_VALUE) { pcs->fCont = TRUE; pcs->hThread = CreateThread (NULL, 100000, ReadFrameThread, (PVOID)pThd, STACK_SIZE_PARAM_IS_A_RESERVATION , NULL); if (pcs->hThread) { Sleep (10); //Let the thread start... SetThreadPriority(pcs->hThread,THREAD_PRIORITY_ABOVE_IDLE); return 0; } else return GetLastError(); } return 0; } //---------------------------------------------------------------------- // Stops the video streaming // int StopStreaming (DWORD dwContext) { PCAMSTATE pcs = (PCAMSTATE)dwContext; pcs->fCont = FALSE; if (WaitForSingleObject (pcs->hThread, 5000) == WAIT_TIMEOUT) { DEBUGMSG (ZONE_ERROR, (TEXT("Can't shutdown ReadFrameThread\r\n"))); } CloseHandle (pcs->hThread); pcs->hThread = 0; return 0; } //====================================================================== // ReadFrameThread - Reads each frame of MJPEG video from the driver, // and displays it in a device context. This thread is started // by the StartStreaming function. // DWORD WINAPI ReadFrameThread (PVOID pArg) { int rc = 0; BOOL f; DWORD dwBytes; THREADSTRUCT Thd; FORMATPROPS fmtData; int nFrameCnt = 0; DWORD dwTick = 0; DWORD dwErr = 0; if (!pArg) return -1; // Copy over params Thd = *(PTHREADSTRUCT)pArg; PCAMSTATE pcs = (PCAMSTATE)Thd.pcs; LocalFree (pArg); // Get information about the format rc = GetFormatInformation (pcs, Thd.wFormat, Thd.wFrame, &fmtData); if (rc) return rc; RECT rect; SetRect (&rect, Thd.rect.left, Thd.rect.top, Thd.rect.left + fmtData.dwWidth, Thd.rect.top + fmtData.dwHeight); // Parameters needed to start a stream STARTVIDSTRUCT svStruct; dwBytes = 0; svStruct.cbSize = sizeof (STARTVIDSTRUCT); svStruct.wFormatIndex = Thd.wFormat; svStruct.wFrameIndex = Thd.wFrame; svStruct.dwInterval = Thd.dwInterval; svStruct.dwNumBuffs = NUMBUFFS; svStruct.dwPreBuffSize = PREBUFFSIZE; svStruct.dwPostBuffSize = 0; //SetWindowText(hMainText,_T("THREAD VIDEOSTREAM READY")); // // Start the video stream // f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_STARTVIDEOSTREAM, (LPVOID)&svStruct, sizeof (STARTVIDSTRUCT), 0, 0, &dwBytes, NULL); if (f) { //SetWindowText(hMainText,_T("START VIDEOSTREAM OK")); // Call the driver for a frame GETFRAMESTRUCT gfsIn; GETFRAMESTRUCTOUT gfsOut; memset (&gfsIn, 0, sizeof (GETFRAMESTRUCT)); gfsIn.cbSize = sizeof (GETFRAMESTRUCT); gfsIn.dwFlags = GETFRAMEFLAG_GET_LATESTFRAME; gfsIn.dwFlags |= GETFRAMEFLAG_TIMEOUT_VALID; gfsIn.dwTimeout = 10000; memset (&gfsOut, 0, sizeof (GETFRAMESTRUCTOUT)); gfsOut.cbSize = sizeof (GETFRAMESTRUCTOUT); // Get the next frame of video f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_GETNEXTVIDEOFRAME, &gfsIn, sizeof (GETFRAMESTRUCT), &gfsOut, sizeof(GETFRAMESTRUCTOUT), &dwBytes, NULL); pcs->fCont = f; Sleep(0); while (pcs->fCont) { nFrameCnt++; //////////////////////////////////////////////// // DOING HERE THE PROCESS TO CONVERT INTO BMP // //////////////////////////////////////////////// // This Semaphore Protect this Function for MultiAccess that can be dangerous for data integrity WaitForSingleObject(SemBlob,INFINITE); ProcessImage(gfsOut.pFrameData,gfsOut.dwFrameSize,Thd.hdc, &rect); ReleaseSemaphore(SemBlob, 1, NULL); dwTick = GetTickCount(); gfsIn.dwFlags = GETFRAMEFLAG_GET_LATESTFRAME | GETFRAMEFLAG_FREEBUFF_VALID; gfsIn.pFrameDataRet = gfsOut.pFrameData; gfsIn.dwFlags |= GETFRAMEFLAG_TIMEOUT_VALID; gfsIn.dwTimeout = 10000; // Call the driver f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_GETNEXTVIDEOFRAME, &gfsIn, sizeof (GETFRAMESTRUCT), &gfsOut, sizeof(GETFRAMESTRUCTOUT), &dwBytes, NULL); if (!f) pcs->fCont = FALSE; // Allow the other camera thread to take the microP else Sleep(0); } // // Stop the stream // f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_STOPVIDEOSTREAM, 0, 0, 0, 0, &dwBytes, NULL); } else { pcs->fCont = FALSE; } return 0; } //---------------------------------------------------------------------- // GetStillImage - Returns a still from the driver // int GetStillImage (DWORD dwContext, WORD wFormat, WORD wFrame, PBYTE *ppData, DWORD *pdwSize) { int rc = 0; VIDFORMATSTRUCT vf; DWORD dwBytes, dwBuff; BOOL f; PCAMSTATE pcs = (PCAMSTATE)dwContext; memset (&vf, 0, sizeof (vf)); vf.cbSize = sizeof (VIDFORMATSTRUCT); vf.wFormatIndex = wFormat; vf.wFrameIndex = wFrame; *pdwSize = 0; // See if we should allocate the buffer if (*ppData == 0) { // Call to get the size of the buffer f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_GETSTILLIMAGE, &vf, sizeof (VIDFORMATSTRUCT), 0, 0, &dwBytes, NULL); if (!f) { rc = GetLastError(); DEBUGMSG (ZONE_ERROR, (TEXT("failure calling IOCTL_CAMERA_DEVICE_GETSTILLIMAGE rc %d\r\n"), rc)); return rc; } // Allocate the buffer *ppData = (PBYTE) LocalAlloc (LPTR, dwBytes); if (*ppData == 0) return ERROR_NOT_ENOUGH_MEMORY; dwBuff = dwBytes; } // Call to get the image f = DeviceIoControl (pcs->hCam, IOCTL_CAMERA_DEVICE_GETSTILLIMAGE, &vf, sizeof (VIDFORMATSTRUCT), *ppData, dwBuff, &dwBytes, NULL); if (!f) { rc = GetLastError(); DEBUGMSG (ZONE_ERROR, (TEXT("failure calling IOCTL_CAMERA_DEVICE_GETSTILLIMAGE rc %d\r\n"), rc)); } else *pdwSize = dwBytes; return rc; } //------------------------------------------------------------------------- // Writes a MJPEG frame as a JPEG file // int WriteJPEG (LPTSTR lpszName, PBYTE pData, int nSize) { BYTE MJPGDHTSeg[0x1A4] = { /* JPEG DHT Segment for YCrCb omitted from MJPG data */ 0xFF,0xC4,0x01,0xA2, 0x00,0x00,0x01,0x05,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x01,0x00,0x03,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x08,0x09,0x0A,0x0B,0x10,0x00,0x02,0x01,0x03,0x03,0x02,0x04,0x03,0x05,0x05,0x04,0x04,0x00, 0x00,0x01,0x7D,0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61, 0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xA1,0x08,0x23,0x42,0xB1,0xC1,0x15,0x52,0xD1,0xF0,0x24, 0x33,0x62,0x72,0x82,0x09,0x0A,0x16,0x17,0x18,0x19,0x1A,0x25,0x26,0x27,0x28,0x29,0x2A,0x34, 0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56, 0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78, 0x79,0x7A,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99, 0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9, 0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9, 0xDA,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7, 0xF8,0xF9,0xFA,0x11,0x00,0x02,0x01,0x02,0x04,0x04,0x03,0x04,0x07,0x05,0x04,0x04,0x00,0x01, 0x02,0x77,0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71, 0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xA1,0xB1,0xC1,0x09,0x23,0x33,0x52,0xF0,0x15,0x62, 0x72,0xD1,0x0A,0x16,0x24,0x34,0xE1,0x25,0xF1,0x17,0x18,0x19,0x1A,0x26,0x27,0x28,0x29,0x2A, 0x35,0x36,0x37,0x38,0x39,0x3A,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x53,0x54,0x55,0x56, 0x57,0x58,0x59,0x5A,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x73,0x74,0x75,0x76,0x77,0x78, 0x79,0x7A,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x92,0x93,0x94,0x95,0x96,0x97,0x98, 0x99,0x9A,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8, 0xB9,0xBA,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8, 0xD9,0xDA,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8, 0xF9,0xFA }; int rc = 0; DWORD dwBytes; HANDLE hFile = CreateFile (lpszName, GENERIC_WRITE | GENERIC_READ, 0, NULL, CREATE_ALWAYS, 0, NULL); if (hFile != INVALID_HANDLE_VALUE) { BYTE bHdr[] = { 0xff,0xd8, // SOI 0xff,0xe0, // APP0 0x00,0x10, // APP0 Hdr size 0x4a,0x46,0x49,0x46,0x00, // ID string 0x01,0x01, // Version 0x00, // Bits per type 0x00, 0x00, // X density 0x00, 0x00, // Y density 0x00, // X Thumbnail size 0x00, // Y Thumbnail size }; WriteFile (hFile, bHdr, sizeof (bHdr), &dwBytes, NULL); // Write DHT color segment needed for stand-alone file WriteFile (hFile, MJPGDHTSeg, sizeof (MJPGDHTSeg), &dwBytes, NULL); // try removing AVI header from image #if 1 int n = *(pData+4); n = n << 8; n += *(pData+5)+4; PBYTE p2 = pData + n; WriteFile (hFile, p2, nSize-n, &dwBytes, NULL); #else WriteFile (hFile, pData, nSize, &dwBytes, NULL); #endif DEBUGMSG (1, (TEXT("Write %d bytes to image file.\r\n"), dwBytes)); CloseHandle (hFile); } else rc = GetLastError(); return rc; }