www.pudn.com > CamTest2.rar > CameraCode.cpp, change:2009-03-31,size:20885b


//====================================================================== 
// CameraCode.cpp  
// 
// This file contains routines that interface with the WebCam driver. 
// 
// Copyright (C) 2005 Douglas Boling 
// 
//====================================================================== 
#include <windows.h>				// For all that Windows stuff 
#include <winioctl.h>				// Needed for CTLCODE macro 
 
#include "WebCamSDK.h"				// WebCam IOCTLs and structures 
 
#include "CameraCode.h"				// Defines for this file 
 
#include "mjpeg2bmp.h"				// Routines for converting MJPEG frames 
 
#include "camtest2.h"				// THis is only needed for debug zones 
 
#define DEBUG 1						// Print debug info 
 
typedef struct { 
	HANDLE h; 
	PBYTE p; 
} MMOBJSTRUCT, *PMMOBJSTRUCT; 
     
int WriteJPEG (LPTSTR lpszName, PBYTE pData, int nSize); 
int AllocMMObject (int nSize, PMMOBJSTRUCT obj); 
int FreeMMObject (PMMOBJSTRUCT obj); 
DWORD WINAPI ReadFrameThread (PVOID pArg); 
 
BOOL fCont = TRUE; 
HANDLE hCam = INVALID_HANDLE_VALUE; 
HANDLE hThread; 
 
extern BOOL fDraw; 
 
 
#define NUMBUFFS       6 
#define PREBUFFSIZE  512  
 
typedef struct { 
	WORD wFormat; 
	WORD wFrame; 
	DWORD dwInterval; 
	RECT rect; 
	HDC hdc; 
} THREADSTRUCT, *PTHREADSTRUCT; 
 
// 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 
// 
int InitCamera () 
{ 
	int rc = 0; 
	if (hCam == INVALID_HANDLE_VALUE) 
	{ 
		// Open Driver 
		hCam = CreateFile (TEXT("CAM1:"), GENERIC_WRITE | GENERIC_READ,  
							   0, NULL, OPEN_EXISTING, 0, NULL); 
		if (hCam == INVALID_HANDLE_VALUE) 
		{ 
			rc = GetLastError(); 
			RETAILMSG(1, (TEXT("***LGCAM: can't open file rc = %d\r\n"), rc));			 
		} 
	} 
	return rc; 
} 
//---------------------------------------------------------------------- 
// ShutdownCamera - Stops streaming and closes the driver 
// 
int ShutdownCamera () 
{ 
	if (fCont) 
		StopStreaming (); 
 
	if (hCam != INVALID_HANDLE_VALUE) 
	{ 
		CloseHandle (hCam); 
	} 
	hCam = INVALID_HANDLE_VALUE; 
 
	return 0; 
} 
 
//---------------------------------------------------------------------- 
// GetFeatureList 
// 
int GetFeatureList (PFEATUREPROPS pFeatures, DWORD *pdwSize) 
{ 
	int rc = 0; 
	BOOL f; 
	DWORD dwBytes; 
 
	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 (hCam, IOCTL_CAMERA_DEVICE_QUERYPARAMETERARARY,  
							 0, 0, 0, 0, pdwSize, NULL); 
		if (!f) 
			rc = GetLastError(); 
		RETAILMSG(1, (TEXT("***LGCAM: DeviceIoControl returned %d %d\r\n"), f, rc));		 
	} 
	else 
	{ 
		// Get parameter list  
		f = DeviceIoControl (hCam, IOCTL_CAMERA_DEVICE_QUERYPARAMETERARARY, 0, 0,  
		                     pFeatures, *pdwSize, &dwBytes, NULL); 
		if (!f) 
			rc = GetLastError(); 
		RETAILMSG(1, (TEXT("***LGCAM: DeviceIoControl IOCTL_CAMERA_DEVICE_QUERYPARAMETERARARY returned %d %d\r\n"), f, rc)); 
		 
	} 
	return rc; 
} 
 
//---------------------------------------------------------------------- 
// GetFeatureText - Helper function that labels feature IDs 
// 
LPCTSTR GetFeatureText (DWORD dwFeatureID) 
{ 
	LPTSTR pstr = L""; 
 
	if (dwFeatureID < dim (szFeatureLbls)) 
		pstr = szFeatureLbls[dwFeatureID]; 
 
	return pstr; 
} 
//---------------------------------------------------------------------- 
// GetFeatureSetting - Queries a setting from the camera 
// 
int GetFeatureSetting (DWORD dwFeature, DWORD *pVal) 
{ 
	BOOL f; 
	int rc = 0; 
	DWORD dwBytes; 
 
	if (pVal == 0) 
		return ERROR_INVALID_PARAMETER; 
 
	f = DeviceIoControl (hCam, IOCTL_CAMERA_DEVICE_QUERYPARAMETER,  
		                 &dwFeature, sizeof (DWORD),  
		                 pVal, sizeof (DWORD), &dwBytes, NULL); 
	if (!f) 
		rc = GetLastError(); 
	RETAILMSG(1, (TEXT("***LGCAM: DeviceIoControl IOCTL_CAMERA_DEVICE_QUERYPARAMETER returned %d %d\r\n"), f, rc)); 
	return rc; 
} 
//---------------------------------------------------------------------- 
// SetFeatureSetting - Sets a feature on the camera 
// 
int SetFeatureSetting (DWORD dwFeature, DWORD dwVal) 
{ 
	BOOL f; 
	int rc = 0; 
	DWORD dwBytes; 
	SETFEATURESTRUCT sfs; 
 
	sfs.cbSize = sizeof (SETFEATURESTRUCT); 
	sfs.dwFeatureID = dwFeature; 
	sfs.dwVal = dwVal; 
 
	f = DeviceIoControl (hCam, IOCTL_CAMERA_DEVICE_SETPARAMETER,  
		                 &sfs, sizeof (SETFEATURESTRUCT), 0, 0, 
		                 &dwBytes, NULL); 
	if (!f) 
		rc = GetLastError(); 
	RETAILMSG(1, (TEXT("***LGCAM: DeviceIoControl IOCTL_CAMERA_DEVICE_SETPARAMETER returned %d %d\r\n"), f, rc)); 
	 
	return rc; 
} 
//---------------------------------------------------------------------- 
// GetVideoFormats - Returns an array with the supported streaming 
// video formats 
// 
int GetVideoFormats (PFORMATPROPS pFormats, int *pnCount) 
{ 
	int i, rc, nCnt; 
 
	if (pnCount == 0) 
		return 0; 
 
	nCnt = *pnCount; 
	*pnCount = 0; 
	for (i = 0; i < nCnt; i++) 
	{ 
		memset (&pFormats[i], 0, sizeof (FORMATPROPS)); 
		rc = GetFormatInformation (1, i+1, &pFormats[i]); 
		if (rc) break; 
		(*pnCount)++; 
	} 
 return 0; 
} 
//---------------------------------------------------------------------- 
// GetStillFormats - Returns an array with the supported still 
// image formats 
// 
int GetStillFormats (PFORMATPROPS pFormats, int *pnCount) 
{ 
	int rc = 0; 
	DWORD dwBytes; 
	BOOL f; 
 
	DWORD dwFormat = 1; 
	DWORD dw = *pnCount * sizeof (FORMATPROPS); 
	// 
	// Get information about a given video format 
	// 
	f = DeviceIoControl (hCam, IOCTL_CAMERA_DEVICE_QUERYSTILLFORMATS,  
	                     (LPVOID)&dwFormat, sizeof (DWORD),  
						 pFormats, dw, &dwBytes, NULL); 
	rc = GetLastError(); 
	RETAILMSG(1, (TEXT("***LGCAM: DeviceIoControl IOCTL_CAMERA_DEVICE_QUERYSTILLFORMATS returned %d %d\r\n"), f, rc)); 
	if (!f)  
	{ 
		RETAILMSG(1, (TEXT("***LGCAM: Failure to get format data rc = %d\r\n"),rc));		 
		return rc; 
	} 
	*pnCount = dwBytes / sizeof (FORMATPROPS); 
	return rc; 
} 
 
//---------------------------------------------------------------------- 
// GetFormatInformation - Returns information about a specific streaming 
// video format 
// 
int GetFormatInformation (WORD wFormat, WORD wFrame, PFORMATPROPS pFmt) 
{ 
	VIDFORMATSTRUCT vf; 
	FORMATPROPS fmtData; 
	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 (hCam, IOCTL_CAMERA_DEVICE_GETVIDEOFORMAT,  
	                     (LPVOID)&vf, sizeof (VIDFORMATSTRUCT),  
						 &fmtData, sizeof (fmtData), &dwBytes, NULL); 
	rc = GetLastError(); 
	RETAILMSG(1, (TEXT("***LGCAM: DeviceIoControl IOCTL_CAMERA_DEVICE_GETVIDEOFORMAT returned %d %d\r\n"), f, rc)); 
	 
	if (!f)  
	{ 
		RETAILMSG(1, (TEXT("***LGCAM: Failure to get format data rc = %d\r\n"),rc));		 
		return rc; 
	} 
	if (dwBytes != sizeof (FORMATPROPS)) 
	{ 
		RETAILMSG(1, (TEXT("***LGCAM: Unexpected size for return data\r\n")));			 
		return -1; 
	} 
	*pFmt = fmtData; 
	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 (HDC hdc, RECT *prect, WORD wFormat, WORD wFrame, DWORD dwInterval) 
{ 
 
	PTHREADSTRUCT 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; 
		 
	if (hCam != INVALID_HANDLE_VALUE) 
	{ 
		fCont = TRUE; 
		hThread = CreateThread (NULL, 0, ReadFrameThread, (PVOID)pThd, 0, NULL); 
		if (hThread) 
		{ 
			Sleep (0);  //Let the thread start... 
			return 0; 
		} 
		else 
			return GetLastError(); 
	} 
	return 0; 
} 
//---------------------------------------------------------------------- 
// Stops the video streaming 
// 
int StopStreaming () 
{ 
	fCont = FALSE; 
	if (WaitForSingleObject (hThread, 5000) == WAIT_TIMEOUT) 
	{ 
		DEBUGMSG (ZONE_ERROR, (DTAG TEXT("Can't shutdown ReadFrameThread\r\n"))); 
	} 
	CloseHandle (hThread); 
	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; 
 
	RETAILMSG(1, (TEXT("***LGCAM: ReadFrameThread++\r\n"))); 
	 
	if (!pArg) 
		return -1; 
 
	// Copy over params 
	Thd = *(PTHREADSTRUCT)pArg; 
	LocalFree (pArg); 
	 
	// Get information about the format 
	rc = GetFormatInformation (Thd.wFormat, Thd.wFrame, &fmtData); 
 
	if (rc)  
	{ 
		RETAILMSG(1, (TEXT("***LGCAM: Failure to get format data rc = %d\r\n"),rc));		 
		return rc; 
	} 
	RETAILMSG(1, (TEXT("***LGCAM: Format       %d\r\n"),fmtData.wFormatType)); 
	RETAILMSG(1, (TEXT("***LGCAM: dwWidth      %d\r\n"),fmtData.dwWidth)); 
	RETAILMSG(1, (TEXT("***LGCAM: dwHeight     %d\r\n"),fmtData.dwHeight)); 
	RETAILMSG(1, (TEXT("***LGCAM: dwMaxBuff    %d\r\n"),fmtData.dwMaxBuff)); 
	RETAILMSG(1, (TEXT("***LGCAM: nNumInterval %d\r\n"),fmtData.nNumInterval)); 
	 
	// Initialize the conversion library 
	rc = InitDisplayFrame (NULL); 
 
	RECT rect; 
	// See if the caller wants to just specify position and not size 
	if ((Thd.rect.right == 0) && (Thd.rect.bottom == 0)) 
	{ 
// If debugging, make room for framerate 
#ifdef DEBUG 
		SetRect (&rect, Thd.rect.left, Thd.rect.top + 30,  
		         Thd.rect.left + fmtData.dwWidth, Thd.rect.top + 30 + fmtData.dwHeight); 
#else 
		SetRect (&rect, Thd.rect.left, Thd.rect.top,  
		         Thd.rect.left + fmtData.dwWidth, Thd.rect.top + fmtData.dwHeight); 
#endif 
	} 
	else 
		rect = Thd.rect; 
 
	// 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; 
	// 
	// Start the video stream 
	// 
	f = DeviceIoControl (hCam, IOCTL_CAMERA_DEVICE_STARTVIDEOSTREAM,  
				         (LPVOID)&svStruct, sizeof (STARTVIDSTRUCT),  
						 0, 0, &dwBytes, NULL); 
 
	RETAILMSG(1, (TEXT("***LGCAM: deviceioctl IOCTL_CAMERA_DEVICE_STARTVIDEOSTREAM returned %d.  dwBytes:%d\r\n"), f, dwBytes)); 
	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 = 10000; 
		 
		memset (&gfsOut, 0, sizeof (GETFRAMESTRUCTOUT)); 
		gfsOut.cbSize = sizeof (GETFRAMESTRUCTOUT); 
 
		// Get the next frame of video 
		f = DeviceIoControl (hCam, IOCTL_CAMERA_DEVICE_GETNEXTVIDEOFRAME,  
					         &gfsIn, sizeof (GETFRAMESTRUCT),  
							 &gfsOut, sizeof(GETFRAMESTRUCTOUT), &dwBytes, NULL); 
		RETAILMSG(1, (TEXT("***LGCAM: deviceioctl IOCTL_CAMERA_DEVICE_GETNEXTVIDEOFRAME returned %d.  dwBytes:%d\r\n"), f, dwBytes)); 
	 
		fCont = f; 
		while (fCont) 
		{ 
			nFrameCnt++; 
			if (fDraw) 
			{ 
				// Draw frame in HDC 
				rc = DisplayFrame (gfsOut.pFrameData, PREBUFFSIZE, gfsOut.dwFrameSize, Thd.hdc, &rect); 
				if (rc) dwErr++; 
				RETAILMSG(1, (TEXT("***LGCAM: DisplayFrame-- %d mS to draw\r\n"),GetTickCount() - dwTick));				 
			} 
#ifdef DEBUG 
			{ 
				TCHAR sz[128]; 
				DWORD dwElapsed = GetTickCount() - dwTick; 
				if (dwElapsed == 0) dwElapsed++; 
				wsprintf (sz, TEXT("%3d x %3d  Frame rate  %4d fps   Missed Frames %2d  Errors %3d%%                "),  
				          fmtData.dwWidth, fmtData.dwHeight, 1000/dwElapsed, gfsOut.dwMissedFrames-1,  
						  (dwErr*100)/nFrameCnt); 
 
				ExtTextOut (Thd.hdc, Thd.rect.left+5, Thd.rect.top + 2, ETO_OPAQUE, NULL, sz, lstrlen (sz), 0); 
			} 
#endif 
			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 (hCam, IOCTL_CAMERA_DEVICE_GETNEXTVIDEOFRAME,  
						         &gfsIn, sizeof (GETFRAMESTRUCT),  
								 &gfsOut, sizeof(GETFRAMESTRUCTOUT), &dwBytes, NULL); 
			if (!f) 
			{ 
				RETAILMSG(1, (TEXT("***LGCAM: deviceioctl IOCTL_CAMERA_DEVICE_GETNEXTVIDEOFRAME returned %d.  dwBytes:%d\r\n"), f, dwBytes));				 
				fCont = FALSE; 
			} 
		} 
		// 
		// Stop the stream 
		// 
		f = DeviceIoControl (hCam, IOCTL_CAMERA_DEVICE_STOPVIDEOSTREAM,  
					         0, 0, 0, 0, &dwBytes, NULL); 
	} 
	else 
	{ 
		RETAILMSG(1, (TEXT("***LGCAM: failure calling IOCTL_CAMERA_DEVICE_STARTVIDEOSTREAM rc %d\r\n"),GetLastError()));				 
		 
		fCont = FALSE; 
	} 
	// Clean up translation code 
	ReleaseDisplayFrame (); 
 
	RETAILMSG(1, (TEXT("***LGCAM: ReadFrameThread--\r\n"))); 
	 
	return 0; 
} 
 
//---------------------------------------------------------------------- 
// GetStillImage - Returns a still from the driver 
// 
int GetStillImage (WORD wFormat, WORD wFrame, PFORMATPROPS pFmt, PBYTE *ppData, DWORD *pdwSize) 
{ 
	int rc = 0; 
 
	VIDFORMATSTRUCT vf; 
	DWORD dwBytes, dwBuff; 
	BOOL f; 
 
	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 (hCam, IOCTL_CAMERA_DEVICE_GETSTILLIMAGE,  
							 &vf, sizeof (VIDFORMATSTRUCT), 0, 0, &dwBytes, NULL); 
		if (!f) 
		{ 
			rc = GetLastError(); 
			RETAILMSG(1, (TEXT("***LGCAM: 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 (hCam, IOCTL_CAMERA_DEVICE_GETSTILLIMAGE,  
						 &vf, sizeof (VIDFORMATSTRUCT), *ppData, dwBuff, &dwBytes, NULL); 
	if (!f) 
	{ 
		rc = GetLastError(); 
		RETAILMSG(1, (TEXT("***LGCAM: failure calling IOCTL_CAMERA_DEVICE_GETSTILLIMAGE rc %d\r\n"),rc)); 
		 
	} else 
		*pdwSize = dwBytes; 
 
	RETAILMSG(1, (TEXT("***LGCAM: deviceioctl IOCTL_CAMERA_DEVICE_GETNEXTVIDEOFRAME returned %d.  dwBytes:%d\r\n"), f, dwBytes)); 
 
	return rc; 
} 
//---------------------------------------------------------------------- 
// 
// 
int AllocMMObject (int nSize, PMMOBJSTRUCT obj) 
{ 
	if ((obj == 0) || (nSize == 0)) 
		return ERROR_INVALID_PARAMETER; 
 
	obj->h = CreateFileMapping ((HANDLE)-1, NULL, PAGE_READWRITE | SEC_COMMIT, 
	                            0, nSize, NULL); 
	if (obj->h == 0) 
		return GetLastError(); 
	obj->p = (PBYTE)MapViewOfFile (obj->h, FILE_MAP_WRITE, 0, 0, 0); 
	if (obj->h == 0) 
	{ 
		CloseHandle (obj->h); 
		return GetLastError(); 
	} 
	return 0; 
} 
//---------------------------------------------------------------------- 
// 
// 
int FreeMMObject (PMMOBJSTRUCT obj) 
{ 
	if (obj == 0) 
		return ERROR_INVALID_PARAMETER; 
 
	UnmapViewOfFile (obj->p); 
	CloseHandle (obj->h); 
	return 0; 
} 
//------------------------------------------------------------------------- 
// 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; 
}