00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include "VFWCapture.h"
00047
00048 #include "Image/ByteImage.h"
00049 #include "Image/ImageProcessor.h"
00050 #include "Helpers/helpers.h"
00051
00052 #include <vfw.h>
00053 #include <wingdi.h>
00054
00055
00056
00057
00058
00059
00060
00061 #define BI_I420 0x30323449
00062 #define BI_YUY2 0x32595559
00063
00064
00065
00066
00067
00068
00069 CRITICAL_SECTION critical_section;
00070 static CByteImage *pCapturedImage = 0;
00071
00072
00073
00074
00075
00076
00077 #define myClip(x) (((x) > 255) ? 255 : ((x) < 0) ? 0 : (unsigned char) (x))
00078 static inline void yuv2rgb(unsigned char y, unsigned char u, unsigned char v, unsigned char *out)
00079 {
00080 int C = (int) y - 16;
00081 int D = (int) u - 128;
00082 int E = (int) v - 128;
00083
00084 int R = (( 298 * C + 409 * E + 128) >> 8);
00085 int G = (( 298 * C - 100 * D - 208 * E + 128) >> 8);
00086 int B = (( 298 * C + 516 * D + 128) >> 8);
00087
00088 out[0] = myClip(R);
00089 out[1] = myClip(G);
00090 out[2] = myClip(B);
00091 }
00092 #undef myClip
00093
00094 static LRESULT CALLBACK CallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr)
00095 {
00096 EnterCriticalSection(&critical_section);
00097
00098 if (!pCapturedImage)
00099 {
00100 LeaveCriticalSection(&critical_section);
00101 return (LRESULT) TRUE;
00102 }
00103
00104 pCapturedImage->pixels = (unsigned char *) lpVHdr->lpData;
00105
00106 LeaveCriticalSection(&critical_section);
00107
00108 return (LRESULT) TRUE;
00109 }
00110
00111
00112
00113
00114
00115
00116 CVFWCapture::CVFWCapture(int nDriverIndex)
00117 {
00118 pCapturedImage = 0;
00119 m_hCaptureWnd = 0;
00120
00121 m_nWidth = -1;
00122 m_nHeight = -1;
00123 m_nBitsPerPixel = 0;
00124 m_type = CByteImage::eGrayScale;
00125
00126 m_nDriverIndex = nDriverIndex;
00127 m_bFlipY = false;
00128
00129 m_bCameraOpened = false;
00130
00131 for (int i = 0; i < 1024; i++)
00132 m_clip[i] = i < 256 ? i : 255;
00133
00134 InitializeCriticalSection(&critical_section);
00135 }
00136
00137 CVFWCapture::~CVFWCapture()
00138 {
00139 CloseCamera();
00140
00141 if (m_hCaptureWnd)
00142 {
00143 DestroyWindow(m_hCaptureWnd);
00144 m_hCaptureWnd = 0;
00145 }
00146
00147 if (pCapturedImage)
00148 delete pCapturedImage;
00149
00150 DeleteCriticalSection(&critical_section);
00151 }
00152
00153
00154
00155
00156
00157
00158 bool CVFWCapture::OpenCamera()
00159 {
00160
00161 if (!m_hCaptureWnd)
00162 {
00163
00164 m_hCaptureWnd = capCreateCaptureWindow("Capture Window", 0, 0, 0, 640, 480, NULL, 0);
00165 if (!m_hCaptureWnd)
00166 return false;
00167
00168
00169 if (!capSetCallbackOnFrame(m_hCaptureWnd, CallbackProc))
00170 {
00171 DestroyWindow(m_hCaptureWnd);
00172 m_hCaptureWnd = 0;
00173 return false;
00174 }
00175 }
00176
00177
00178 if (!capDriverConnect(m_hCaptureWnd, m_nDriverIndex))
00179 {
00180 DestroyWindow(m_hCaptureWnd);
00181 m_hCaptureWnd = 0;
00182 return false;
00183 }
00184
00185 UpdateInformation();
00186
00187 capOverlay(m_hCaptureWnd, FALSE);
00188 capPreview(m_hCaptureWnd, FALSE);
00189
00190 CAPTUREPARMS s;
00191 s.dwRequestMicroSecPerFrame = 41667;
00192 s.fMakeUserHitOKToCapture = FALSE;
00193 s.wPercentDropForError = 10;
00194 s.fYield = TRUE;
00195 s.dwIndexSize = 34952;
00196 s.wChunkGranularity = 0;
00197 s.fUsingDOSMemory = FALSE;
00198 s.wNumVideoRequested = 10;
00199 s.fCaptureAudio = FALSE;
00200
00201 s.vKeyAbort = VK_ESCAPE;
00202 s.fAbortLeftMouse = FALSE;
00203 s.fAbortRightMouse = FALSE;
00204 s.fLimitEnabled = FALSE;
00205
00206 s.fMCIControl = FALSE;
00207
00208
00209
00210 s.fStepCaptureAt2x = FALSE;
00211 s.wStepCaptureAverageFrames = 1;
00212 s.dwAudioBufferSize = 0;
00213 s.fDisableWriteCache = FALSE;
00214 s.AVStreamMaster = AVSTREAMMASTER_NONE;
00215
00216 capCaptureSetSetup(m_hCaptureWnd, &s, sizeof(CAPTUREPARMS));
00217
00218
00219 m_bCameraOpened = true;
00220
00221 return true;
00222 }
00223
00224 void CVFWCapture::CloseCamera()
00225 {
00226 if (m_bCameraOpened)
00227 {
00228
00229
00230 capDriverDisconnect(m_hCaptureWnd);
00231
00232 m_nWidth = 0;
00233 m_nHeight = 0;
00234 m_nBitsPerPixel = 0;
00235
00236 m_bCameraOpened = false;
00237 }
00238 }
00239
00240 bool CVFWCapture::GetDriverName(int nDriverIndex, std::string &sName)
00241 {
00242 char szName[1000];
00243 char szVersion[1000];
00244
00245 if (!capGetDriverDescription(nDriverIndex, szName, sizeof(szName), szVersion, sizeof(szVersion)))
00246 return false;
00247
00248 sName = "";
00249 sName += szName;
00250
00251 return true;
00252 }
00253
00254 void CVFWCapture::ShowVideoFormatDialog()
00255 {
00256 EnterCriticalSection(&critical_section);
00257
00258 CAPDRIVERCAPS gCapDriverCaps;
00259
00260
00261 if (m_hCaptureWnd && capDriverGetCaps(m_hCaptureWnd, &gCapDriverCaps, sizeof(CAPDRIVERCAPS)))
00262 {
00263 if (gCapDriverCaps.fHasDlgVideoFormat)
00264 {
00265 capDlgVideoFormat(m_hCaptureWnd);
00266 UpdateInformation();
00267 }
00268 }
00269
00270 LeaveCriticalSection(&critical_section);
00271 }
00272
00273 void CVFWCapture::ShowVideoSourceDialog()
00274 {
00275 CAPDRIVERCAPS gCapDriverCaps;
00276
00277
00278 if (m_hCaptureWnd && capDriverGetCaps(m_hCaptureWnd, &gCapDriverCaps, sizeof(CAPDRIVERCAPS)))
00279 {
00280 if (gCapDriverCaps.fHasDlgVideoSource)
00281 {
00282 capDlgVideoSource(m_hCaptureWnd);
00283 UpdateInformation();
00284 }
00285 }
00286 }
00287
00288 void CVFWCapture::UpdateInformation()
00289 {
00290 EnterCriticalSection(&critical_section);
00291
00292 BITMAPINFO bitmapInfo;
00293
00294 if (m_hCaptureWnd && capGetVideoFormat(m_hCaptureWnd, &bitmapInfo, sizeof(BITMAPINFO)))
00295 {
00296 m_nWidth = bitmapInfo.bmiHeader.biWidth;
00297 m_nHeight = abs(bitmapInfo.bmiHeader.biHeight);
00298 m_nBitsPerPixel = bitmapInfo.bmiHeader.biBitCount;
00299 m_nCompression = bitmapInfo.bmiHeader.biCompression;
00300
00301 m_bFlipY = false;
00302
00303
00304
00305
00306
00307
00308
00309
00310 if (m_nCompression != BI_RGB && m_nCompression != BI_BITFIELDS)
00311 {
00312 printf("fourcc = %08x (%c%c%c%c)\n", m_nCompression, (m_nCompression >> 0) & 0xff, (m_nCompression >> 8) & 0xff, (m_nCompression >> 16) & 0xff, (m_nCompression >> 24) & 0xff);
00313 m_type = CByteImage::eRGB24;
00314 }
00315 else
00316 {
00317 m_type = m_nBitsPerPixel > 8 ? CByteImage::eRGB24 : CByteImage::eGrayScale;
00318
00319 if (bitmapInfo.bmiHeader.biHeight > 0)
00320 {
00321
00322 m_bFlipY = true;
00323 }
00324 }
00325
00326 if (pCapturedImage)
00327 delete pCapturedImage;
00328
00329 pCapturedImage = new CByteImage(m_nWidth, m_nHeight, m_type, true);
00330 }
00331
00332 LeaveCriticalSection(&critical_section);
00333 }
00334
00335 bool CVFWCapture::CaptureImage(CByteImage **ppImages)
00336 {
00337 capGrabFrameNoStop(m_hCaptureWnd);
00338
00339 EnterCriticalSection(&critical_section);
00340
00341
00342 if (!m_bCameraOpened || !m_hCaptureWnd || !ppImages || !ppImages[0] || m_nWidth != ppImages[0]->width || m_nHeight != ppImages[0]->height || m_type != ppImages[0]->type)
00343 {
00344 LeaveCriticalSection(&critical_section);
00345 return false;
00346 }
00347
00348 if (pCapturedImage && pCapturedImage->pixels)
00349 {
00350 if (pCapturedImage->type == CByteImage::eRGB24)
00351 {
00352 unsigned char *output = ppImages[0]->pixels;
00353
00354 if (m_nCompression == BI_RGB)
00355 {
00356 if (m_nBitsPerPixel == 24)
00357 {
00358 const int nBytes = m_nWidth * m_nHeight * 3;
00359 const unsigned char *input = pCapturedImage->pixels;
00360
00361 for (int i = 0; i < nBytes; i += 3)
00362 {
00363 output[i] = input[i + 2];
00364 output[i + 1] = input[i + 1];
00365 output[i + 2] = input[i];
00366 }
00367 }
00368 }
00369 else if (m_nCompression == BI_BITFIELDS)
00370 {
00371 printf("error: BI_BITFIELDS not yet implemented\n");
00372 }
00373 else
00374 {
00375
00376 if (m_nCompression == BI_I420)
00377 {
00378 const int nBytes = m_nWidth * m_nHeight;
00379 const unsigned char *inputY = pCapturedImage->pixels;
00380 const unsigned char *inputU = inputY + nBytes;
00381 const unsigned char *inputV = inputU + nBytes / 4;
00382
00383 int i = 0;
00384 for (int h = 0; h < m_nHeight; h += 1)
00385 {
00386 for (int w = 0; w < m_nWidth; w += 1)
00387 {
00388 int j = (h / 2) * (m_nWidth / 2) + (w / 2);
00389 yuv2rgb(inputY[i], inputU[j], inputV[j], &output[3 * i]);
00390 i += 1;
00391 }
00392 }
00393 }
00394 else if (m_nCompression == BI_YUY2)
00395 {
00396 const int nBytes = m_nWidth * m_nHeight * 2;
00397 const unsigned char *input = pCapturedImage->pixels;
00398
00399 for (int i = 0; i < nBytes; i += 4)
00400 {
00401 unsigned char y0 = *input++;
00402 unsigned char u = *input++;
00403 unsigned char y1 = *input++;
00404 unsigned char v = *input++;
00405
00406 yuv2rgb(y0, u, v, output);
00407 output += 3;
00408 yuv2rgb(y1, u, v, output);
00409 output += 3;
00410 }
00411 }
00412 }
00413 }
00414 else
00415 ImageProcessor::CopyImage(pCapturedImage, ppImages[0]);
00416 }
00417
00418 LeaveCriticalSection(&critical_section);
00419
00420 if (m_bFlipY)
00421 ImageProcessor::FlipY(ppImages[0], ppImages[0]);
00422
00423 return true;
00424 }
00425
00426 #undef BI_I420
00427 #undef BI_YUY2