1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5//  By downloading, copying, installing or using the software you agree to this license.
6//  If you do not agree to this license, do not download, install,
7//  copy or use the software.
8//
9//
10//                        Intel License Agreement
11//                For Open Source Computer Vision Library
12//
13// Copyright (C) 2000, Intel Corporation, all rights reserved.
14// Third party copyrights are property of their respective owners.
15//
16// Redistribution and use in source and binary forms, with or without modification,
17// are permitted provided that the following conditions are met:
18//
19//   * Redistribution's of source code must retain the above copyright notice,
20//     this list of conditions and the following disclaimer.
21//
22//   * Redistribution's in binary form must reproduce the above copyright notice,
23//     this list of conditions and the following disclaimer in the documentation
24//     and/or other materials provided with the distribution.
25//
26//   * The name of Intel Corporation may not be used to endorse or promote products
27//     derived from this software without specific prior written permission.
28//
29// This software is provided by the copyright holders and contributors "as is" and
30// any express or implied warranties, including, but not limited to, the implied
31// warranties of merchantability and fitness for a particular purpose are disclaimed.
32// In no event shall the Intel Corporation or contributors be liable for any direct,
33// indirect, incidental, special, exemplary, or consequential damages
34// (including, but not limited to, procurement of substitute goods or services;
35// loss of use, data, or profits; or business interruption) however caused
36// and on any theory of liability, whether in contract, strict liability,
37// or tort (including negligence or otherwise) arising in any way out of
38// the use of this software, even if advised of the possibility of such damage.
39//
40//M*/
41
42#include "precomp.hpp"
43
44#include <vfw.h>
45
46#ifdef __GNUC__
47#define WM_CAP_FIRSTA              (WM_USER)
48#define capSendMessage(hwnd,m,w,l) (IsWindow(hwnd)?SendMessage(hwnd,m,w,l):0)
49#endif
50
51#if defined _M_X64 && defined _MSC_VER
52#pragma optimize("",off)
53#pragma warning(disable: 4748)
54#endif
55
56/********************* Capturing video from AVI via VFW ************************/
57
58static BITMAPINFOHEADER icvBitmapHeader( int width, int height, int bpp, int compression = BI_RGB )
59{
60    BITMAPINFOHEADER bmih;
61    memset( &bmih, 0, sizeof(bmih));
62    bmih.biSize = sizeof(bmih);
63    bmih.biWidth = width;
64    bmih.biHeight = height;
65    bmih.biBitCount = (WORD)bpp;
66    bmih.biCompression = compression;
67    bmih.biPlanes = 1;
68
69    return bmih;
70}
71
72
73static void icvInitCapture_VFW()
74{
75    static int isInitialized = 0;
76    if( !isInitialized )
77    {
78        AVIFileInit();
79        isInitialized = 1;
80    }
81}
82
83
84class CvCaptureAVI_VFW : public CvCapture
85{
86public:
87    CvCaptureAVI_VFW()
88    {
89      CoInitialize(NULL);
90      init();
91    }
92
93    virtual ~CvCaptureAVI_VFW()
94    {
95        close();
96        CoUninitialize();
97    }
98
99    virtual bool open( const char* filename );
100    virtual void close();
101
102    virtual double getProperty(int) const;
103    virtual bool setProperty(int, double);
104    virtual bool grabFrame();
105    virtual IplImage* retrieveFrame(int);
106    virtual int getCaptureDomain() { return CV_CAP_VFW; } // Return the type of the capture object: CV_CAP_VFW, etc...
107
108protected:
109    void init();
110
111    PAVIFILE            avifile;
112    PAVISTREAM          avistream;
113    PGETFRAME           getframe;
114    AVISTREAMINFO       aviinfo;
115    BITMAPINFOHEADER  * bmih;
116    CvSlice             film_range;
117    double              fps;
118    int                 pos;
119    IplImage*           frame;
120    CvSize              size;
121};
122
123
124void CvCaptureAVI_VFW::init()
125{
126    avifile = 0;
127    avistream = 0;
128    getframe = 0;
129    memset( &aviinfo, 0, sizeof(aviinfo) );
130    bmih = 0;
131    film_range = cvSlice(0,0);
132    fps = 0;
133    pos = 0;
134    frame = 0;
135    size = cvSize(0,0);
136}
137
138
139void CvCaptureAVI_VFW::close()
140{
141    if( getframe )
142        AVIStreamGetFrameClose( getframe );
143
144    if( avistream )
145        AVIStreamRelease( avistream );
146
147    if( avifile )
148        AVIFileRelease( avifile );
149
150    if (frame)
151        cvReleaseImage( &frame );
152
153    init();
154}
155
156
157bool CvCaptureAVI_VFW::open( const char* filename )
158{
159    close();
160    icvInitCapture_VFW();
161
162    if( !filename )
163        return false;
164
165    HRESULT hr = AVIFileOpen( &avifile, filename, OF_READ, NULL );
166    if( SUCCEEDED(hr))
167    {
168        hr = AVIFileGetStream( avifile, &avistream, streamtypeVIDEO, 0 );
169        if( SUCCEEDED(hr))
170        {
171            hr = AVIStreamInfo( avistream, &aviinfo, sizeof(aviinfo));
172            if( SUCCEEDED(hr))
173            {
174                size.width = aviinfo.rcFrame.right - aviinfo.rcFrame.left;
175                size.height = aviinfo.rcFrame.bottom - aviinfo.rcFrame.top;
176                BITMAPINFOHEADER bmihdr = icvBitmapHeader( size.width, size.height, 24 );
177
178                film_range.start_index = (int)aviinfo.dwStart;
179                film_range.end_index = film_range.start_index + (int)aviinfo.dwLength;
180                fps = (double)aviinfo.dwRate/aviinfo.dwScale;
181                pos = film_range.start_index;
182                getframe = AVIStreamGetFrameOpen( avistream, &bmihdr );
183                if( getframe != 0 )
184                    return true;
185
186                // Attempt to open as 8-bit AVI.
187                bmihdr = icvBitmapHeader( size.width, size.height, 8);
188                getframe = AVIStreamGetFrameOpen( avistream, &bmihdr );
189                if( getframe != 0 )
190                    return true;
191            }
192        }
193    }
194
195    close();
196    return false;
197}
198
199bool CvCaptureAVI_VFW::grabFrame()
200{
201    if( avistream )
202        bmih = (BITMAPINFOHEADER*)AVIStreamGetFrame( getframe, pos++ );
203    return bmih != 0;
204}
205
206IplImage* CvCaptureAVI_VFW::retrieveFrame(int)
207{
208    if( avistream && bmih )
209    {
210        bool isColor = bmih->biBitCount == 24;
211        int nChannels = (isColor) ? 3 : 1;
212        IplImage src;
213        cvInitImageHeader( &src, cvSize( bmih->biWidth, bmih->biHeight ),
214                           IPL_DEPTH_8U, nChannels, IPL_ORIGIN_BL, 4 );
215
216        char* dataPtr = (char*)(bmih + 1);
217
218        // Only account for the color map size if we are an 8-bit image and the color map is used
219        if (!isColor)
220        {
221            static int RGBQUAD_SIZE_PER_BYTE = sizeof(RGBQUAD)/sizeof(BYTE);
222            int offsetFromColormapToData = (int)bmih->biClrUsed*RGBQUAD_SIZE_PER_BYTE;
223            dataPtr += offsetFromColormapToData;
224        }
225
226        cvSetData( &src, dataPtr, src.widthStep );
227
228        if( !frame || frame->width != src.width || frame->height != src.height )
229        {
230            cvReleaseImage( &frame );
231            frame = cvCreateImage( cvGetSize(&src), 8, nChannels );
232        }
233
234        cvFlip( &src, frame, 0 );
235        return frame;
236    }
237
238    return 0;
239}
240
241double CvCaptureAVI_VFW::getProperty( int property_id ) const
242{
243    switch( property_id )
244    {
245    case CV_CAP_PROP_POS_MSEC:
246        return cvRound(pos*1000./fps);
247    case CV_CAP_PROP_POS_FRAMES:
248        return pos;
249    case CV_CAP_PROP_POS_AVI_RATIO:
250        return (pos - film_range.start_index)/
251               (film_range.end_index - film_range.start_index + 1e-10);
252    case CV_CAP_PROP_FRAME_WIDTH:
253        return size.width;
254    case CV_CAP_PROP_FRAME_HEIGHT:
255        return size.height;
256    case CV_CAP_PROP_FPS:
257        return fps;
258    case CV_CAP_PROP_FOURCC:
259        return aviinfo.fccHandler;
260    case CV_CAP_PROP_FRAME_COUNT:
261        return film_range.end_index - film_range.start_index;
262    }
263    return 0;
264}
265
266bool CvCaptureAVI_VFW::setProperty( int property_id, double value )
267{
268    switch( property_id )
269    {
270    case CV_CAP_PROP_POS_MSEC:
271    case CV_CAP_PROP_POS_FRAMES:
272    case CV_CAP_PROP_POS_AVI_RATIO:
273        {
274            switch( property_id )
275            {
276            case CV_CAP_PROP_POS_MSEC:
277                pos = cvRound(value*fps*0.001);
278                break;
279            case CV_CAP_PROP_POS_AVI_RATIO:
280                pos = cvRound(value*(film_range.end_index -
281                                     film_range.start_index) +
282                              film_range.start_index);
283                break;
284            default:
285                pos = cvRound(value);
286            }
287            if( pos < film_range.start_index )
288                pos = film_range.start_index;
289            if( pos > film_range.end_index )
290                pos = film_range.end_index;
291        }
292        break;
293    default:
294        return false;
295    }
296
297    return true;
298}
299
300CvCapture* cvCreateFileCapture_VFW (const char* filename)
301{
302    CvCaptureAVI_VFW* capture = new CvCaptureAVI_VFW;
303    if( capture->open(filename) )
304        return capture;
305    delete capture;
306    return 0;
307}
308
309
310/********************* Capturing video from camera via VFW *********************/
311
312class CvCaptureCAM_VFW : public CvCapture
313{
314public:
315    CvCaptureCAM_VFW() { init(); }
316    virtual ~CvCaptureCAM_VFW() { close(); }
317
318    virtual bool open( int index );
319    virtual void close();
320    virtual double getProperty(int) const;
321    virtual bool setProperty(int, double);
322    virtual bool grabFrame();
323    virtual IplImage* retrieveFrame(int);
324    virtual int getCaptureDomain() { return CV_CAP_VFW; } // Return the type of the capture object: CV_CAP_VFW, etc...
325
326protected:
327    void init();
328    void closeHIC();
329    static LRESULT PASCAL frameCallback( HWND hWnd, VIDEOHDR* hdr );
330
331    CAPDRIVERCAPS caps;
332    HWND   capWnd;
333    VIDEOHDR* hdr;
334    DWORD  fourcc;
335    int width, height;
336    int widthSet, heightSet;
337    HIC    hic;
338    IplImage* frame;
339};
340
341
342void CvCaptureCAM_VFW::init()
343{
344    memset( &caps, 0, sizeof(caps) );
345    capWnd = 0;
346    hdr = 0;
347    fourcc = 0;
348    hic = 0;
349    frame = 0;
350    width = height = -1;
351    widthSet = heightSet = 0;
352}
353
354void CvCaptureCAM_VFW::closeHIC()
355{
356    if( hic )
357    {
358        ICDecompressEnd( hic );
359        ICClose( hic );
360        hic = 0;
361    }
362}
363
364
365LRESULT PASCAL CvCaptureCAM_VFW::frameCallback( HWND hWnd, VIDEOHDR* hdr )
366{
367    CvCaptureCAM_VFW* capture = 0;
368
369    if (!hWnd) return FALSE;
370
371    capture = (CvCaptureCAM_VFW*)capGetUserData(hWnd);
372    capture->hdr = hdr;
373
374    return (LRESULT)TRUE;
375}
376
377
378// Initialize camera input
379bool CvCaptureCAM_VFW::open( int wIndex )
380{
381    char szDeviceName[80];
382    char szDeviceVersion[80];
383    HWND hWndC = 0;
384
385    close();
386
387    if( (unsigned)wIndex >= 10 )
388        wIndex = 0;
389
390    for( ; wIndex < 10; wIndex++ )
391    {
392        if( capGetDriverDescription( wIndex, szDeviceName,
393            sizeof (szDeviceName), szDeviceVersion,
394            sizeof (szDeviceVersion)))
395        {
396            hWndC = capCreateCaptureWindow ( "My Own Capture Window",
397                WS_POPUP | WS_CHILD, 0, 0, 320, 240, 0, 0);
398            if( capDriverConnect (hWndC, wIndex))
399                break;
400            DestroyWindow( hWndC );
401            hWndC = 0;
402        }
403    }
404
405    if( hWndC )
406    {
407        capWnd = hWndC;
408        hdr = 0;
409        hic = 0;
410        fourcc = (DWORD)-1;
411
412        memset( &caps, 0, sizeof(caps));
413        capDriverGetCaps( hWndC, &caps, sizeof(caps));
414        CAPSTATUS status = {};
415        capGetStatus(hWndC, &status, sizeof(status));
416        ::SetWindowPos(hWndC, NULL, 0, 0, status.uiImageWidth, status.uiImageHeight, SWP_NOZORDER|SWP_NOMOVE);
417        capSetUserData( hWndC, (size_t)this );
418        capSetCallbackOnFrame( hWndC, frameCallback );
419        CAPTUREPARMS p;
420        capCaptureGetSetup(hWndC,&p,sizeof(CAPTUREPARMS));
421        p.dwRequestMicroSecPerFrame = 66667/2; // 30 FPS
422        capCaptureSetSetup(hWndC,&p,sizeof(CAPTUREPARMS));
423        //capPreview( hWndC, 1 );
424        capPreviewScale(hWndC,FALSE);
425        capPreviewRate(hWndC,1);
426
427        // Get frame initial parameters.
428        const DWORD size = capGetVideoFormatSize(capWnd);
429        if( size > 0 )
430        {
431            unsigned char *pbi = new unsigned char[size];
432            if( pbi )
433            {
434                if( capGetVideoFormat(capWnd, pbi, size) == size )
435                {
436                    BITMAPINFOHEADER& vfmt = ((BITMAPINFO*)pbi)->bmiHeader;
437                    widthSet = vfmt.biWidth;
438                    heightSet = vfmt.biHeight;
439                    fourcc = vfmt.biCompression;
440                }
441                delete []pbi;
442            }
443        }
444        // And alternative way in case of failure.
445        if( widthSet == 0 || heightSet == 0 )
446        {
447            widthSet = status.uiImageWidth;
448            heightSet = status.uiImageHeight;
449        }
450
451    }
452    return capWnd != 0;
453}
454
455
456void CvCaptureCAM_VFW::close()
457{
458    if( capWnd )
459    {
460        capSetCallbackOnFrame( capWnd, NULL );
461        capDriverDisconnect( capWnd );
462        DestroyWindow( capWnd );
463        closeHIC();
464    }
465    cvReleaseImage( &frame );
466    init();
467}
468
469
470bool CvCaptureCAM_VFW::grabFrame()
471{
472    if( capWnd )
473        return capGrabFrameNoStop(capWnd) == TRUE;
474
475    return false;
476}
477
478
479IplImage* CvCaptureCAM_VFW::retrieveFrame(int)
480{
481    BITMAPINFO vfmt;
482    memset( &vfmt, 0, sizeof(vfmt));
483    BITMAPINFOHEADER& vfmt0 = vfmt.bmiHeader;
484
485    if( !capWnd )
486        return 0;
487
488    const DWORD sz = capGetVideoFormat( capWnd, &vfmt, sizeof(vfmt));
489    const int prevWidth = frame ? frame->width : 0;
490    const int prevHeight = frame ? frame->height : 0;
491
492    if( !hdr || hdr->lpData == 0 || sz == 0 )
493        return 0;
494
495    if( !frame || frame->width != vfmt0.biWidth || frame->height != vfmt0.biHeight )
496    {
497        cvReleaseImage( &frame );
498        frame = cvCreateImage( cvSize( vfmt0.biWidth, vfmt0.biHeight ), 8, 3 );
499    }
500
501    if( vfmt0.biCompression != BI_RGB ||
502        vfmt0.biBitCount != 24 )
503    {
504        BITMAPINFOHEADER vfmt1 = icvBitmapHeader( vfmt0.biWidth, vfmt0.biHeight, 24 );
505
506        if( hic == 0 || fourcc != vfmt0.biCompression ||
507            prevWidth != vfmt0.biWidth || prevHeight != vfmt0.biHeight )
508        {
509            closeHIC();
510            hic = ICOpen( MAKEFOURCC('V','I','D','C'),
511                          vfmt0.biCompression, ICMODE_DECOMPRESS );
512            if( hic )
513            {
514                if( ICDecompressBegin( hic, &vfmt0, &vfmt1 ) != ICERR_OK )
515                {
516                    closeHIC();
517                    return 0;
518                }
519            }
520        }
521
522        if( !hic || ICDecompress( hic, 0, &vfmt0, hdr->lpData,
523            &vfmt1, frame->imageData ) != ICERR_OK )
524        {
525            closeHIC();
526            return 0;
527        }
528
529        cvFlip( frame, frame, 0 );
530    }
531    else
532    {
533        IplImage src;
534        cvInitImageHeader( &src, cvSize(vfmt0.biWidth, vfmt0.biHeight),
535            IPL_DEPTH_8U, 3, IPL_ORIGIN_BL, 4 );
536        cvSetData( &src, hdr->lpData, src.widthStep );
537        cvFlip( &src, frame, 0 );
538    }
539
540    return frame;
541}
542
543
544double CvCaptureCAM_VFW::getProperty( int property_id ) const
545{
546    switch( property_id )
547    {
548    case CV_CAP_PROP_FRAME_WIDTH:
549        return widthSet;
550    case CV_CAP_PROP_FRAME_HEIGHT:
551        return heightSet;
552    case CV_CAP_PROP_FOURCC:
553        return fourcc;
554    case CV_CAP_PROP_FPS:
555        {
556            CAPTUREPARMS params = {};
557            if( capCaptureGetSetup(capWnd, &params, sizeof(params)) )
558                return 1e6 / params.dwRequestMicroSecPerFrame;
559        }
560        break;
561    default:
562        break;
563    }
564    return 0;
565}
566
567bool CvCaptureCAM_VFW::setProperty(int property_id, double value)
568{
569    bool handledSize = false;
570
571    switch( property_id )
572    {
573    case CV_CAP_PROP_FRAME_WIDTH:
574        width = cvRound(value);
575        handledSize = true;
576        break;
577    case CV_CAP_PROP_FRAME_HEIGHT:
578        height = cvRound(value);
579        handledSize = true;
580        break;
581    case CV_CAP_PROP_FOURCC:
582        break;
583    case CV_CAP_PROP_FPS:
584        if( value > 0 )
585        {
586            CAPTUREPARMS params;
587            if( capCaptureGetSetup(capWnd, &params, sizeof(params)) )
588            {
589                params.dwRequestMicroSecPerFrame = cvRound(1e6/value);
590                return capCaptureSetSetup(capWnd, &params, sizeof(params)) == TRUE;
591            }
592        }
593        break;
594    default:
595        break;
596    }
597
598    if ( handledSize )
599    {
600        // If both width and height are set then change frame size.
601        if( width > 0 && height > 0 )
602        {
603            const DWORD size = capGetVideoFormatSize(capWnd);
604            if( size == 0 )
605                return false;
606
607            unsigned char *pbi = new unsigned char[size];
608            if( !pbi )
609                return false;
610
611            if( capGetVideoFormat(capWnd, pbi, size) != size )
612            {
613                delete []pbi;
614                return false;
615            }
616
617            BITMAPINFOHEADER& vfmt = ((BITMAPINFO*)pbi)->bmiHeader;
618            bool success = true;
619            if( width != vfmt.biWidth || height != vfmt.biHeight )
620            {
621                // Change frame size.
622                vfmt.biWidth = width;
623                vfmt.biHeight = height;
624                vfmt.biSizeImage = height * ((width * vfmt.biBitCount + 31) / 32) * 4;
625                vfmt.biCompression = BI_RGB;
626                success = capSetVideoFormat(capWnd, pbi, size) == TRUE;
627            }
628            if( success )
629            {
630                // Adjust capture window size.
631                CAPSTATUS status = {};
632                capGetStatus(capWnd, &status, sizeof(status));
633                ::SetWindowPos(capWnd, NULL, 0, 0, status.uiImageWidth, status.uiImageHeight, SWP_NOZORDER|SWP_NOMOVE);
634                // Store frame size.
635                widthSet = width;
636                heightSet = height;
637            }
638            delete []pbi;
639            width = height = -1;
640
641            return success;
642        }
643
644        return true;
645    }
646
647    return false;
648}
649
650CvCapture* cvCreateCameraCapture_VFW( int index )
651{
652    CvCaptureCAM_VFW* capture = new CvCaptureCAM_VFW;
653
654    if( capture->open( index ))
655        return capture;
656
657    delete capture;
658    return 0;
659}
660
661
662/*************************** writing AVIs ******************************/
663
664class CvVideoWriter_VFW : public CvVideoWriter
665{
666public:
667    CvVideoWriter_VFW() { init(); }
668    virtual ~CvVideoWriter_VFW() { close(); }
669
670    virtual bool open( const char* filename, int fourcc,
671                       double fps, CvSize frameSize, bool isColor );
672    virtual void close();
673    virtual bool writeFrame( const IplImage* );
674
675protected:
676    void init();
677    bool createStreams( CvSize frameSize, bool isColor );
678
679    PAVIFILE      avifile;
680    PAVISTREAM    compressed;
681    PAVISTREAM    uncompressed;
682    double        fps;
683    IplImage*     tempFrame;
684    long          pos;
685    int           fourcc;
686};
687
688
689void CvVideoWriter_VFW::init()
690{
691    avifile = 0;
692    compressed = uncompressed = 0;
693    fps = 0;
694    tempFrame = 0;
695    pos = 0;
696    fourcc = 0;
697}
698
699void CvVideoWriter_VFW::close()
700{
701    if( uncompressed )
702        AVIStreamRelease( uncompressed );
703    if( compressed )
704        AVIStreamRelease( compressed );
705    if( avifile )
706        AVIFileRelease( avifile );
707    cvReleaseImage( &tempFrame );
708    init();
709}
710
711
712// philipg.  Made this code capable of writing 8bpp gray scale bitmaps
713struct BITMAPINFO_8Bit
714{
715    BITMAPINFOHEADER bmiHeader;
716    RGBQUAD          bmiColors[256];
717};
718
719
720bool CvVideoWriter_VFW::open( const char* filename, int _fourcc, double _fps, CvSize frameSize, bool isColor )
721{
722    close();
723
724    icvInitCapture_VFW();
725    if( AVIFileOpen( &avifile, filename, OF_CREATE | OF_WRITE, 0 ) == AVIERR_OK )
726    {
727        fourcc = _fourcc;
728        fps = _fps;
729        if( frameSize.width > 0 && frameSize.height > 0 &&
730            !createStreams( frameSize, isColor ) )
731        {
732            close();
733            return false;
734        }
735        return true;
736    }
737    else
738        return false;
739}
740
741
742bool CvVideoWriter_VFW::createStreams( CvSize frameSize, bool isColor )
743{
744    if( !avifile )
745        return false;
746    AVISTREAMINFO aviinfo;
747
748    BITMAPINFO_8Bit bmih;
749    bmih.bmiHeader = icvBitmapHeader( frameSize.width, frameSize.height, isColor ? 24 : 8 );
750    for( int i = 0; i < 256; i++ )
751    {
752        bmih.bmiColors[i].rgbBlue = (BYTE)i;
753        bmih.bmiColors[i].rgbGreen = (BYTE)i;
754        bmih.bmiColors[i].rgbRed = (BYTE)i;
755        bmih.bmiColors[i].rgbReserved = 0;
756    }
757
758    memset( &aviinfo, 0, sizeof(aviinfo));
759    aviinfo.fccType = streamtypeVIDEO;
760    aviinfo.fccHandler = 0;
761    // use highest possible accuracy for dwRate/dwScale
762    aviinfo.dwScale = (DWORD)((double)0x7FFFFFFF / fps);
763    aviinfo.dwRate = cvRound(fps * aviinfo.dwScale);
764    aviinfo.rcFrame.top = aviinfo.rcFrame.left = 0;
765    aviinfo.rcFrame.right = frameSize.width;
766    aviinfo.rcFrame.bottom = frameSize.height;
767
768    if( AVIFileCreateStream( avifile, &uncompressed, &aviinfo ) == AVIERR_OK )
769    {
770        AVICOMPRESSOPTIONS copts, *pcopts = &copts;
771        copts.fccType = streamtypeVIDEO;
772        copts.fccHandler = fourcc != -1 ? fourcc : 0;
773        copts.dwKeyFrameEvery = 1;
774        copts.dwQuality = 10000;
775        copts.dwBytesPerSecond = 0;
776        copts.dwFlags = AVICOMPRESSF_VALID;
777        copts.lpFormat = &bmih;
778        copts.cbFormat = (isColor ? sizeof(BITMAPINFOHEADER) : sizeof(bmih));
779        copts.lpParms = 0;
780        copts.cbParms = 0;
781        copts.dwInterleaveEvery = 0;
782
783        if( fourcc != -1 || AVISaveOptions( 0, 0, 1, &uncompressed, &pcopts ) == TRUE )
784        {
785            if( AVIMakeCompressedStream( &compressed, uncompressed, pcopts, 0 ) == AVIERR_OK &&
786                AVIStreamSetFormat( compressed, 0, &bmih, sizeof(bmih)) == AVIERR_OK )
787            {
788                fps = fps;
789                fourcc = (int)copts.fccHandler;
790                frameSize = frameSize;
791                tempFrame = cvCreateImage( frameSize, 8, (isColor ? 3 : 1) );
792                return true;
793            }
794        }
795    }
796    return false;
797}
798
799
800bool CvVideoWriter_VFW::writeFrame( const IplImage* image )
801{
802    bool result = false;
803    CV_FUNCNAME( "CvVideoWriter_VFW::writeFrame" );
804
805    __BEGIN__;
806
807    if( !image )
808        EXIT;
809
810    if( !compressed && !createStreams( cvGetSize(image), image->nChannels > 1 ))
811        EXIT;
812
813    if( image->width != tempFrame->width || image->height != tempFrame->height )
814        CV_ERROR( CV_StsUnmatchedSizes,
815            "image size is different from the currently set frame size" );
816
817    if( image->nChannels != tempFrame->nChannels ||
818        image->depth != tempFrame->depth ||
819        image->origin == 0 ||
820        image->widthStep != cvAlign(image->width*image->nChannels*((image->depth & 255)/8), 4))
821    {
822        cvConvertImage( image, tempFrame, image->origin == 0 ? CV_CVTIMG_FLIP : 0 );
823        image = (const IplImage*)tempFrame;
824    }
825
826    result = AVIStreamWrite( compressed, pos++, 1, image->imageData,
827                             image->imageSize, AVIIF_KEYFRAME, 0, 0 ) == AVIERR_OK;
828
829    __END__;
830
831    return result;
832}
833
834CvVideoWriter* cvCreateVideoWriter_VFW( const char* filename, int fourcc,
835                                        double fps, CvSize frameSize, int isColor )
836{
837    CvVideoWriter_VFW* writer = new CvVideoWriter_VFW;
838    if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 ))
839        return writer;
840    delete writer;
841    return 0;
842}
843