diff --git a/modules/highgui/src/cap_vfw.cpp b/modules/highgui/src/cap_vfw.cpp index d845953f8e..46e070a13b 100644 --- a/modules/highgui/src/cap_vfw.cpp +++ b/modules/highgui/src/cap_vfw.cpp @@ -318,7 +318,7 @@ public: virtual bool open( int index ); virtual void close(); virtual double getProperty(int); - virtual bool setProperty(int, double) { return false; } + virtual bool setProperty(int, double); virtual bool grabFrame(); virtual IplImage* retrieveFrame(int); virtual int getCaptureDomain() { return CV_CAP_VFW; } // Return the type of the capture object: CV_CAP_VFW, etc... @@ -332,6 +332,8 @@ protected: HWND capWnd; VIDEOHDR* hdr; DWORD fourcc; + int width, height; + int widthSet, heightSet; HIC hic; IplImage* frame; }; @@ -345,6 +347,8 @@ void CvCaptureCAM_VFW::init() fourcc = 0; hic = 0; frame = 0; + width = height = -1; + widthSet = heightSet = 0; } void CvCaptureCAM_VFW::closeHIC() @@ -407,16 +411,43 @@ bool CvCaptureCAM_VFW::open( int wIndex ) memset( &caps, 0, sizeof(caps)); capDriverGetCaps( hWndC, &caps, sizeof(caps)); - ::MoveWindow( hWndC, 0, 0, 320, 240, TRUE ); + CAPSTATUS status = {}; + capGetStatus(hWndC, &status, sizeof(status)); + ::SetWindowPos(hWndC, NULL, 0, 0, status.uiImageWidth, status.uiImageHeight, SWP_NOZORDER|SWP_NOMOVE); capSetUserData( hWndC, (size_t)this ); capSetCallbackOnFrame( hWndC, frameCallback ); CAPTUREPARMS p; capCaptureGetSetup(hWndC,&p,sizeof(CAPTUREPARMS)); - p.dwRequestMicroSecPerFrame = 66667/2; + p.dwRequestMicroSecPerFrame = 66667/2; // 30 FPS capCaptureSetSetup(hWndC,&p,sizeof(CAPTUREPARMS)); //capPreview( hWndC, 1 ); capPreviewScale(hWndC,FALSE); capPreviewRate(hWndC,1); + + // Get frame initial parameters. + const DWORD size = capGetVideoFormatSize(capWnd); + if( size > 0 ) + { + unsigned char *pbi = new unsigned char[size]; + if( pbi ) + { + if( capGetVideoFormat(capWnd, pbi, size) == size ) + { + BITMAPINFOHEADER& vfmt = ((BITMAPINFO*)pbi)->bmiHeader; + widthSet = vfmt.biWidth; + heightSet = vfmt.biHeight; + fourcc = vfmt.biCompression; + } + delete []pbi; + } + } + // And alternative way in case of failure. + if( widthSet == 0 || heightSet == 0 ) + { + widthSet = status.uiImageWidth; + heightSet = status.uiImageHeight; + } + } return capWnd != 0; } @@ -439,10 +470,8 @@ void CvCaptureCAM_VFW::close() bool CvCaptureCAM_VFW::grabFrame() { if( capWnd ) - { - SendMessage( capWnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0 ); - return true; - } + return capGrabFrameNoStop(capWnd) == TRUE; + return false; } @@ -452,14 +481,13 @@ IplImage* CvCaptureCAM_VFW::retrieveFrame(int) BITMAPINFO vfmt; memset( &vfmt, 0, sizeof(vfmt)); BITMAPINFOHEADER& vfmt0 = vfmt.bmiHeader; - int sz, prevWidth, prevHeight; if( !capWnd ) return 0; - sz = capGetVideoFormat( capWnd, &vfmt, sizeof(vfmt)); - prevWidth = frame ? frame->width : 0; - prevHeight = frame ? frame->height : 0; + const DWORD sz = capGetVideoFormat( capWnd, &vfmt, sizeof(vfmt)); + const int prevWidth = frame ? frame->width : 0; + const int prevHeight = frame ? frame->height : 0; if( !hdr || hdr->lpData == 0 || sz == 0 ) return 0; @@ -470,8 +498,8 @@ IplImage* CvCaptureCAM_VFW::retrieveFrame(int) frame = cvCreateImage( cvSize( vfmt0.biWidth, vfmt0.biHeight ), 8, 3 ); } - if( vfmt.bmiHeader.biCompression != BI_RGB || - vfmt.bmiHeader.biBitCount != 24 ) + if( vfmt0.biCompression != BI_RGB || + vfmt0.biBitCount != 24 ) { BITMAPINFOHEADER vfmt1 = icvBitmapHeader( vfmt0.biWidth, vfmt0.biHeight, 24 ); @@ -518,15 +546,106 @@ double CvCaptureCAM_VFW::getProperty( int property_id ) switch( property_id ) { case CV_CAP_PROP_FRAME_WIDTH: - return frame ? frame->width : 0; + return widthSet; case CV_CAP_PROP_FRAME_HEIGHT: - return frame ? frame->height : 0; + return heightSet; case CV_CAP_PROP_FOURCC: return fourcc; + case CV_CAP_PROP_FPS: + { + CAPTUREPARMS params = {}; + if( capCaptureGetSetup(capWnd, ¶ms, sizeof(params)) ) + return 1e6 / params.dwRequestMicroSecPerFrame; + } + break; + default: + break; } return 0; } +bool CvCaptureCAM_VFW::setProperty(int property_id, double value) +{ + bool handledSize = false; + + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + width = cvRound(value); + handledSize = true; + break; + case CV_CAP_PROP_FRAME_HEIGHT: + height = cvRound(value); + handledSize = true; + break; + case CV_CAP_PROP_FOURCC: + break; + case CV_CAP_PROP_FPS: + if( value > 0 ) + { + CAPTUREPARMS params; + if( capCaptureGetSetup(capWnd, ¶ms, sizeof(params)) ) + { + params.dwRequestMicroSecPerFrame = cvRound(1e6/value); + return capCaptureSetSetup(capWnd, ¶ms, sizeof(params)) == TRUE; + } + } + break; + default: + break; + } + + if ( handledSize ) + { + // If both width and height are set then change frame size. + if( width > 0 && height > 0 ) + { + const DWORD size = capGetVideoFormatSize(capWnd); + if( size == 0 ) + return false; + + unsigned char *pbi = new unsigned char[size]; + if( !pbi ) + return false; + + if( capGetVideoFormat(capWnd, pbi, size) != size ) + { + delete []pbi; + return false; + } + + BITMAPINFOHEADER& vfmt = ((BITMAPINFO*)pbi)->bmiHeader; + bool success = true; + if( width != vfmt.biWidth || height != vfmt.biHeight ) + { + // Change frame size. + vfmt.biWidth = width; + vfmt.biHeight = height; + vfmt.biSizeImage = height * ((width * vfmt.biBitCount + 31) / 32) * 4; + vfmt.biCompression = BI_RGB; + success = capSetVideoFormat(capWnd, pbi, size) == TRUE; + } + if( success ) + { + // Adjust capture window size. + CAPSTATUS status = {}; + capGetStatus(capWnd, &status, sizeof(status)); + ::SetWindowPos(capWnd, NULL, 0, 0, status.uiImageWidth, status.uiImageHeight, SWP_NOZORDER|SWP_NOMOVE); + // Store frame size. + widthSet = width; + heightSet = height; + } + delete []pbi; + width = height = -1; + + return success; + } + + return true; + } + + return false; +} CvCapture* cvCreateCameraCapture_VFW( int index ) {