X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fhighgui%2Fcvcap_vfw.cpp;fp=src%2Fhighgui%2Fcvcap_vfw.cpp;h=7eec58544ed2fa34b1911c389c655ea545188134;hb=e4c14cdbdf2fe805e79cd96ded236f57e7b89060;hp=0000000000000000000000000000000000000000;hpb=454138ff8a20f6edb9b65a910101403d8b520643;p=opencv diff --git a/src/highgui/cvcap_vfw.cpp b/src/highgui/cvcap_vfw.cpp new file mode 100644 index 0000000..7eec585 --- /dev/null +++ b/src/highgui/cvcap_vfw.cpp @@ -0,0 +1,704 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "_highgui.h" + +#include + +#if _MSC_VER >= 1200 +#pragma warning( disable: 4711 ) +#endif + +#ifdef __GNUC__ +#define WM_CAP_FIRSTA (WM_USER) +#define capSendMessage(hwnd,m,w,l) (IsWindow(hwnd)?SendMessage(hwnd,m,w,l):0) +#endif + +#if (defined WIN64 || defined _WIN64) && defined _MSC_VER && !defined __ICL +#pragma optimize("",off) +#endif + +/********************* Capturing video from AVI via VFW ************************/ + +static BITMAPINFOHEADER icvBitmapHeader( int width, int height, int bpp, int compression = BI_RGB ) +{ + BITMAPINFOHEADER bmih; + memset( &bmih, 0, sizeof(bmih)); + bmih.biSize = sizeof(bmih); + bmih.biWidth = width; + bmih.biHeight = height; + bmih.biBitCount = (WORD)bpp; + bmih.biCompression = compression; + bmih.biPlanes = 1; + + return bmih; +} + + +static void icvInitCapture_VFW() +{ + static int isInitialized = 0; + if( !isInitialized ) + { + AVIFileInit(); + isInitialized = 1; + } +} + + +class CvCaptureAVI_VFW : public CvCapture +{ +public: + CvCaptureAVI_VFW() + { + CoInitialize(NULL); + init(); + } + + virtual ~CvCaptureAVI_VFW() + { + close(); + CoUninitialize(); + } + + virtual bool open( const char* filename ); + virtual void close(); + + virtual double getProperty(int); + 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... + +protected: + void init(); + + PAVIFILE avifile; + PAVISTREAM avistream; + PGETFRAME getframe; + AVISTREAMINFO aviinfo; + BITMAPINFOHEADER * bmih; + CvSlice film_range; + double fps; + int pos; + IplImage* frame; + CvSize size; +}; + + +void CvCaptureAVI_VFW::init() +{ + avifile = 0; + avistream = 0; + getframe = 0; + memset( &aviinfo, 0, sizeof(aviinfo) ); + bmih = 0; + film_range = cvSlice(0,0); + fps = 0; + pos = 0; + frame = 0; + size = cvSize(0,0); +} + + +void CvCaptureAVI_VFW::close() +{ + if( getframe ) + AVIStreamGetFrameClose( getframe ); + + if( avistream ) + AVIStreamRelease( avistream ); + + if( avifile ) + AVIFileRelease( avifile ); + + if (frame) + cvReleaseImage( &frame ); + + init(); +} + + +bool CvCaptureAVI_VFW::open( const char* filename ) +{ + close(); + icvInitCapture_VFW(); + + if( !filename ) + return false; + + HRESULT hr = AVIFileOpen( &avifile, filename, OF_READ, NULL ); + if( SUCCEEDED(hr)) + { + hr = AVIFileGetStream( avifile, &avistream, streamtypeVIDEO, 0 ); + if( SUCCEEDED(hr)) + { + hr = AVIStreamInfo( avistream, &aviinfo, sizeof(aviinfo)); + if( SUCCEEDED(hr)) + { + size.width = aviinfo.rcFrame.right - aviinfo.rcFrame.left; + size.height = aviinfo.rcFrame.bottom - aviinfo.rcFrame.top; + BITMAPINFOHEADER bmih = icvBitmapHeader( size.width, size.height, 24 ); + + film_range.start_index = (int)aviinfo.dwStart; + film_range.end_index = film_range.start_index + (int)aviinfo.dwLength; + fps = (double)aviinfo.dwRate/aviinfo.dwScale; + pos = film_range.start_index; + getframe = AVIStreamGetFrameOpen( avistream, &bmih ); + if( getframe != 0 ) + return true; + } + } + } + + close(); + return false; +} + +bool CvCaptureAVI_VFW::grabFrame() +{ + if( avistream ) + bmih = (BITMAPINFOHEADER*)AVIStreamGetFrame( getframe, pos++ ); + return bmih != 0; +} + +IplImage* CvCaptureAVI_VFW::retrieveFrame(int) +{ + if( avistream && bmih ) + { + IplImage src; + cvInitImageHeader( &src, cvSize( bmih->biWidth, bmih->biHeight ), + IPL_DEPTH_8U, 3, IPL_ORIGIN_BL, 4 ); + cvSetData( &src, (char*)(bmih + 1), src.widthStep ); + if( !frame || frame->width != src.width || frame->height != src.height ) + { + cvReleaseImage( &frame ); + frame = cvCreateImage( cvGetSize(&src), 8, 3 ); + } + + cvFlip( &src, frame, 0 ); + return frame; + } + + return 0; +} + +double CvCaptureAVI_VFW::getProperty( int property_id ) +{ + switch( property_id ) + { + case CV_CAP_PROP_POS_MSEC: + return cvRound(pos*1000./fps); + case CV_CAP_PROP_POS_FRAMES: + return pos; + case CV_CAP_PROP_POS_AVI_RATIO: + return (pos - film_range.start_index)/ + (film_range.end_index - film_range.start_index + 1e-10); + case CV_CAP_PROP_FRAME_WIDTH: + return size.width; + case CV_CAP_PROP_FRAME_HEIGHT: + return size.height; + case CV_CAP_PROP_FPS: + return fps; + case CV_CAP_PROP_FOURCC: + return aviinfo.fccHandler; + case CV_CAP_PROP_FRAME_COUNT: + return film_range.end_index - film_range.start_index; + } + return 0; +} + +bool CvCaptureAVI_VFW::setProperty( int property_id, double value ) +{ + switch( property_id ) + { + case CV_CAP_PROP_POS_MSEC: + case CV_CAP_PROP_POS_FRAMES: + case CV_CAP_PROP_POS_AVI_RATIO: + { + switch( property_id ) + { + case CV_CAP_PROP_POS_MSEC: + pos = cvRound(value*fps*0.001); + break; + case CV_CAP_PROP_POS_AVI_RATIO: + pos = cvRound(value*(film_range.end_index - + film_range.start_index) + + film_range.start_index); + break; + default: + pos = cvRound(value); + } + if( pos < film_range.start_index ) + pos = film_range.start_index; + if( pos > film_range.end_index ) + pos = film_range.end_index; + } + break; + default: + return false; + } + + return true; +} + +CvCapture* cvCreateFileCapture_VFW (const char* filename) +{ + CvCaptureAVI_VFW* capture = new CvCaptureAVI_VFW; + if( capture->open(filename) ) + return capture; + delete capture; + return 0; +} + + +/********************* Capturing video from camera via VFW *********************/ + +class CvCaptureCAM_VFW : public CvCapture +{ +public: + CvCaptureCAM_VFW() { init(); } + virtual ~CvCaptureCAM_VFW() { close(); } + + virtual bool open( int index ); + virtual void close(); + virtual double getProperty(int); + virtual bool setProperty(int, double) { return false; } + 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... + +protected: + void init(); + void closeHIC(); + static LRESULT PASCAL frameCallback( HWND hWnd, VIDEOHDR* hdr ); + + CAPDRIVERCAPS caps; + HWND capWnd; + VIDEOHDR* hdr; + DWORD fourcc; + HIC hic; + IplImage* frame; +}; + + +void CvCaptureCAM_VFW::init() +{ + memset( &caps, 0, sizeof(caps) ); + capWnd = 0; + hdr = 0; + fourcc = 0; + hic = 0; + frame = 0; +} + +void CvCaptureCAM_VFW::closeHIC() +{ + if( hic ) + { + ICDecompressEnd( hic ); + ICClose( hic ); + hic = 0; + } +} + + +LRESULT PASCAL CvCaptureCAM_VFW::frameCallback( HWND hWnd, VIDEOHDR* hdr ) +{ + CvCaptureCAM_VFW* capture = 0; + + if (!hWnd) return FALSE; + + capture = (CvCaptureCAM_VFW*)capGetUserData(hWnd); + capture->hdr = hdr; + + return (LRESULT)TRUE; +} + + +// Initialize camera input +bool CvCaptureCAM_VFW::open( int wIndex ) +{ + char szDeviceName[80]; + char szDeviceVersion[80]; + HWND hWndC = 0; + + close(); + + if( (unsigned)wIndex >= 10 ) + wIndex = 0; + + for( ; wIndex < 10; wIndex++ ) + { + if( capGetDriverDescription( wIndex, szDeviceName, + sizeof (szDeviceName), szDeviceVersion, + sizeof (szDeviceVersion))) + { + hWndC = capCreateCaptureWindow ( "My Own Capture Window", + WS_POPUP | WS_CHILD, 0, 0, 320, 240, 0, 0); + if( capDriverConnect (hWndC, wIndex)) + break; + DestroyWindow( hWndC ); + hWndC = 0; + } + } + + if( hWndC ) + { + capWnd = hWndC; + hdr = 0; + hic = 0; + fourcc = (DWORD)-1; + + memset( &caps, 0, sizeof(caps)); + capDriverGetCaps( hWndC, &caps, sizeof(&caps)); + ::MoveWindow( hWndC, 0, 0, 320, 240, TRUE ); + capSetUserData( hWndC, (size_t)this ); + capSetCallbackOnFrame( hWndC, frameCallback ); + CAPTUREPARMS p; + capCaptureGetSetup(hWndC,&p,sizeof(CAPTUREPARMS)); + p.dwRequestMicroSecPerFrame = 66667/2; + capCaptureSetSetup(hWndC,&p,sizeof(CAPTUREPARMS)); + //capPreview( hWndC, 1 ); + capPreviewScale(hWndC,FALSE); + capPreviewRate(hWndC,1); + } + return capWnd != 0; +} + + +void CvCaptureCAM_VFW::close() +{ + if( capWnd ) + { + capSetCallbackOnFrame( capWnd, NULL ); + capDriverDisconnect( capWnd ); + DestroyWindow( capWnd ); + closeHIC(); + } + cvReleaseImage( &frame ); + init(); +} + + +bool CvCaptureCAM_VFW::grabFrame() +{ + if( capWnd ) + { + SendMessage( capWnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0 ); + return true; + } + return false; +} + + +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; + + if( !hdr || hdr->lpData == 0 || sz == 0 ) + return 0; + + if( !frame || frame->width != vfmt0.biWidth || frame->height != vfmt0.biHeight ) + { + cvReleaseImage( &frame ); + frame = cvCreateImage( cvSize( vfmt0.biWidth, vfmt0.biHeight ), 8, 3 ); + } + + if( vfmt.bmiHeader.biCompression != BI_RGB || + vfmt.bmiHeader.biBitCount != 24 ) + { + BITMAPINFOHEADER vfmt1 = icvBitmapHeader( vfmt0.biWidth, vfmt0.biHeight, 24 ); + + if( hic == 0 || fourcc != vfmt0.biCompression || + prevWidth != vfmt0.biWidth || prevHeight != vfmt0.biHeight ) + { + closeHIC(); + hic = ICOpen( MAKEFOURCC('V','I','D','C'), + vfmt0.biCompression, ICMODE_DECOMPRESS ); + if( hic ) + { + if( ICDecompressBegin( hic, &vfmt0, &vfmt1 ) != ICERR_OK ) + { + closeHIC(); + return 0; + } + } + } + + if( !hic || ICDecompress( hic, 0, &vfmt0, hdr->lpData, + &vfmt1, frame->imageData ) != ICERR_OK ) + { + closeHIC(); + return 0; + } + + cvFlip( frame, frame, 0 ); + } + else + { + IplImage src; + cvInitImageHeader( &src, cvSize(vfmt0.biWidth, vfmt0.biHeight), + IPL_DEPTH_8U, 3, IPL_ORIGIN_BL, 4 ); + cvSetData( &src, hdr->lpData, src.widthStep ); + cvFlip( &src, frame, 0 ); + } + + return frame; +} + + +double CvCaptureCAM_VFW::getProperty( int property_id ) +{ + switch( property_id ) + { + case CV_CAP_PROP_FRAME_WIDTH: + return frame ? frame->width : 0; + case CV_CAP_PROP_FRAME_HEIGHT: + return frame ? frame->height : 0; + case CV_CAP_PROP_FOURCC: + return fourcc; + } + return 0; +} + + +CvCapture* cvCreateCameraCapture_VFW( int index ) +{ + CvCaptureCAM_VFW* capture = new CvCaptureCAM_VFW; + + if( capture->open( index )) + return capture; + + delete capture; + return 0; +} + + +/*************************** writing AVIs ******************************/ + +class CvVideoWriter_VFW : public CvVideoWriter +{ +public: + CvVideoWriter_VFW() { init(); } + virtual ~CvVideoWriter_VFW() { close(); } + + virtual bool open( const char* filename, int fourcc, + double fps, CvSize frameSize, bool isColor ); + virtual void close(); + virtual bool writeFrame( const IplImage* ); + +protected: + void init(); + bool createStreams( CvSize frameSize, bool isColor ); + + PAVIFILE avifile; + PAVISTREAM compressed; + PAVISTREAM uncompressed; + double fps; + IplImage* tempFrame; + long pos; + int fourcc; +}; + + +void CvVideoWriter_VFW::init() +{ + avifile = 0; + compressed = uncompressed = 0; + fps = 0; + tempFrame = 0; + pos = 0; + fourcc = 0; +} + +void CvVideoWriter_VFW::close() +{ + if( uncompressed ) + AVIStreamRelease( uncompressed ); + if( compressed ) + AVIStreamRelease( compressed ); + if( avifile ) + AVIFileRelease( avifile ); + cvReleaseImage( &tempFrame ); + init(); +} + + +// philipg. Made this code capable of writing 8bpp gray scale bitmaps +struct BITMAPINFO_8Bit +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; +}; + + +bool CvVideoWriter_VFW::open( const char* filename, int _fourcc, double _fps, CvSize frameSize, bool isColor ) +{ + close(); + + icvInitCapture_VFW(); + if( AVIFileOpen( &avifile, filename, OF_CREATE | OF_WRITE, 0 ) == AVIERR_OK ) + { + fourcc = _fourcc; + fps = _fps; + if( frameSize.width > 0 && frameSize.height > 0 && + !createStreams( frameSize, isColor ) ) + { + close(); + return false; + } + } + return true; +} + + +bool CvVideoWriter_VFW::createStreams( CvSize frameSize, bool isColor ) +{ + if( !avifile ) + return false; + AVISTREAMINFO aviinfo; + + BITMAPINFO_8Bit bmih; + bmih.bmiHeader = icvBitmapHeader( frameSize.width, frameSize.height, isColor ? 24 : 8 ); + for( int i = 0; i < 256; i++ ) + { + bmih.bmiColors[i].rgbBlue = (BYTE)i; + bmih.bmiColors[i].rgbGreen = (BYTE)i; + bmih.bmiColors[i].rgbRed = (BYTE)i; + bmih.bmiColors[i].rgbReserved = 0; + } + + memset( &aviinfo, 0, sizeof(aviinfo)); + aviinfo.fccType = streamtypeVIDEO; + aviinfo.fccHandler = 0; + // use highest possible accuracy for dwRate/dwScale + aviinfo.dwScale = (DWORD)((double)0x7FFFFFFF / fps); + aviinfo.dwRate = cvRound(fps * aviinfo.dwScale); + aviinfo.rcFrame.top = aviinfo.rcFrame.left = 0; + aviinfo.rcFrame.right = frameSize.width; + aviinfo.rcFrame.bottom = frameSize.height; + + if( AVIFileCreateStream( avifile, &uncompressed, &aviinfo ) == AVIERR_OK ) + { + AVICOMPRESSOPTIONS copts, *pcopts = &copts; + copts.fccType = streamtypeVIDEO; + copts.fccHandler = fourcc != -1 ? fourcc : 0; + copts.dwKeyFrameEvery = 1; + copts.dwQuality = 10000; + copts.dwBytesPerSecond = 0; + copts.dwFlags = AVICOMPRESSF_VALID; + copts.lpFormat = &bmih; + copts.cbFormat = (isColor ? sizeof(BITMAPINFOHEADER) : sizeof(bmih)); + copts.lpParms = 0; + copts.cbParms = 0; + copts.dwInterleaveEvery = 0; + + if( fourcc != -1 || AVISaveOptions( 0, 0, 1, &uncompressed, &pcopts ) == TRUE ) + { + if( AVIMakeCompressedStream( &compressed, uncompressed, pcopts, 0 ) == AVIERR_OK && + AVIStreamSetFormat( compressed, 0, &bmih, sizeof(bmih)) == AVIERR_OK ) + { + fps = fps; + fourcc = (int)copts.fccHandler; + frameSize = frameSize; + tempFrame = cvCreateImage( frameSize, 8, (isColor ? 3 : 1) ); + return true; + } + } + } + return false; +} + + +bool CvVideoWriter_VFW::writeFrame( const IplImage* image ) +{ + bool result = false; + CV_FUNCNAME( "CvVideoWriter_VFW::writeFrame" ); + + __BEGIN__; + + if( !image ) + EXIT; + + if( !compressed && !createStreams( cvGetSize(image), image->nChannels > 1 )) + EXIT; + + if( image->width != tempFrame->width || image->height != tempFrame->height ) + CV_ERROR( CV_StsUnmatchedSizes, + "image size is different from the currently set frame size" ); + + if( image->nChannels != tempFrame->nChannels || + image->depth != tempFrame->depth || + image->origin == 0 || + image->widthStep != cvAlign(image->width*image->nChannels*((image->depth & 255)/8), 4)) + { + cvConvertImage( image, tempFrame, image->origin == 0 ? CV_CVTIMG_FLIP : 0 ); + image = (const IplImage*)tempFrame; + } + + result = AVIStreamWrite( compressed, pos++, 1, image->imageData, + image->imageSize, AVIIF_KEYFRAME, 0, 0 ) == AVIERR_OK; + + __END__; + + return result; +} + +CvVideoWriter* cvCreateVideoWriter_VFW( const char* filename, int fourcc, + double fps, CvSize frameSize, int isColor ) +{ + CvVideoWriter_VFW* writer = new CvVideoWriter_VFW; + if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 )) + return writer; + delete writer; + return 0; +}