b7ccfcd99bb77a88d24e29592e744b8afb7291a8
[opencv] / otherlibs / highgui / cvcap_vfw.cpp
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 "_highgui.h"
43
44 #include <vfw.h>
45 #if _MSC_VER >= 1200
46 #pragma warning( disable: 4711 )
47 #endif
48
49 #if defined WIN64 && defined EM64T && defined _MSC_VER && !defined __ICL
50 #pragma optimize("",off)
51 #endif
52
53
54 CvCapture* cvCaptureFromFile_VFW (const char* filename);
55 CvCapture* cvCaptureFromCAM_VFW  (int index);
56
57 /********************* Capturing video from AVI via VFW ************************/
58
59 static BITMAPINFOHEADER icvBitmapHeader( int width, int height, int bpp, int compression = BI_RGB )
60 {
61     BITMAPINFOHEADER bmih;
62     memset( &bmih, 0, sizeof(bmih));
63     bmih.biSize = sizeof(bmih);
64     bmih.biWidth = width;
65     bmih.biHeight = height;
66     bmih.biBitCount = (WORD)bpp;
67     bmih.biCompression = compression;
68     bmih.biPlanes = 1;
69
70     return bmih;
71 }
72
73 static void icvInitCapture_VFW()
74 {
75     static int isInitialized = 0;
76     if( !isInitialized )
77     {
78         AVIFileInit();
79         isInitialized = 1;
80     }
81 }
82
83
84 typedef struct CvCaptureAVI_VFW
85 {
86     CvCaptureVTable   * vtable;
87     PAVIFILE            avifile;
88     PAVISTREAM          avistream;
89     PGETFRAME           getframe;
90     AVISTREAMINFO       aviinfo;
91     BITMAPINFOHEADER  * bmih;
92     CvSlice             film_range;
93     double              fps;
94     int                 pos;
95     int                 data_offset;
96     IplImage            frame;
97     CvSize              size;
98 }
99 CvCaptureAVI_VFW;
100
101
102 static void icvCloseAVI_VFW( CvCaptureAVI_VFW* capture )
103 {
104     if( capture->getframe )
105     {
106         AVIStreamGetFrameClose( capture->getframe );
107         capture->getframe = 0;
108     }
109     if( capture->avistream )
110     {
111         AVIStreamRelease( capture->avistream );
112         capture->avistream = 0;
113     }
114     if( capture->avifile )
115     {
116         AVIFileRelease( capture->avifile );
117         capture->avifile = 0;
118     }
119     capture->bmih = 0;
120     capture->pos = 0;
121     capture->film_range.start_index = capture->film_range.end_index = 0;
122     memset( &capture->frame, 0, sizeof(capture->frame));
123 }
124
125 static int icvOpenAVI_VFW( CvCaptureAVI_VFW* capture, const char* filename )
126 {
127     HRESULT hr;
128
129     icvInitCapture_VFW();
130
131     if( !capture )
132         return 0;
133
134     hr = AVIFileOpen( &capture->avifile, filename, OF_READ, NULL );
135     if( SUCCEEDED(hr))
136     {
137         hr = AVIFileGetStream( capture->avifile, &capture->avistream, streamtypeVIDEO, 0 );
138         if( SUCCEEDED(hr))
139         {
140             hr = AVIStreamInfo( capture->avistream, &capture->aviinfo,
141                                     sizeof(capture->aviinfo));
142             if( SUCCEEDED(hr))
143             {
144                 //int fcc = capture->aviinfo.fccHandler;
145                 capture->data_offset = 0;
146                 capture->size.width = capture->aviinfo.rcFrame.right -
147                                       capture->aviinfo.rcFrame.left;
148                 capture->size.height = capture->aviinfo.rcFrame.bottom -
149                                       capture->aviinfo.rcFrame.top;
150                 BITMAPINFOHEADER bmih = icvBitmapHeader(
151                     capture->size.width, capture->size.height, 24 );
152                 
153                 capture->film_range.start_index = (int)capture->aviinfo.dwStart;
154                 capture->film_range.end_index = capture->film_range.start_index +
155                                                 (int)capture->aviinfo.dwLength;
156                 capture->fps = ((double)capture->aviinfo.dwRate)/capture->aviinfo.dwScale;
157                 capture->pos = capture->film_range.start_index;
158                 capture->getframe = AVIStreamGetFrameOpen( capture->avistream, &bmih );
159                 if( capture->getframe != 0 )
160                     return 1;
161             }
162         }
163     }
164
165     icvCloseAVI_VFW( capture );
166     return 0;
167 }
168
169 static int icvGrabFrameAVI_VFW( CvCaptureAVI_VFW* capture )
170 {
171     if( capture->avistream )
172     {
173         capture->bmih = (BITMAPINFOHEADER*)
174             AVIStreamGetFrame( capture->getframe, capture->pos++ );
175     }
176
177     return capture->bmih != 0;
178 }
179
180 static const IplImage* icvRetrieveFrameAVI_VFW( CvCaptureAVI_VFW* capture )
181 {
182     if( capture->avistream && capture->bmih )
183     {
184         cvInitImageHeader( &capture->frame,
185                            cvSize( capture->bmih->biWidth,
186                                    capture->bmih->biHeight ),
187                            IPL_DEPTH_8U, 3, IPL_ORIGIN_BL, 4 );
188         capture->frame.imageData = capture->frame.imageDataOrigin =
189             (char*)(capture->bmih + 1) + capture->data_offset;
190         return &capture->frame;
191     }
192
193     return 0;
194 }
195
196 static double icvGetPropertyAVI_VFW( CvCaptureAVI_VFW* capture, int property_id )
197 {
198     switch( property_id )
199     {
200     case CV_CAP_PROP_POS_MSEC:
201         return cvRound(capture->pos*1000./capture->fps);
202     case CV_CAP_PROP_POS_FRAMES:
203         return capture->pos;
204     case CV_CAP_PROP_POS_AVI_RATIO:
205         return (capture->pos - capture->film_range.start_index)/
206                (capture->film_range.end_index - capture->film_range.start_index + 1e-10);
207     case CV_CAP_PROP_FRAME_WIDTH:
208         return capture->size.width;
209     case CV_CAP_PROP_FRAME_HEIGHT:
210         return capture->size.height;
211     case CV_CAP_PROP_FPS:
212         return capture->fps;
213     case CV_CAP_PROP_FOURCC:
214         return capture->aviinfo.fccHandler;
215     case CV_CAP_PROP_FRAME_COUNT:
216         return capture->film_range.end_index - capture->film_range.start_index;
217     }
218     return 0;
219 }
220
221
222 static int icvSetPropertyAVI_VFW( CvCaptureAVI_VFW* capture,
223                                   int property_id, double value )
224 {
225     switch( property_id )
226     {
227     case CV_CAP_PROP_POS_MSEC:
228     case CV_CAP_PROP_POS_FRAMES:
229     case CV_CAP_PROP_POS_AVI_RATIO:
230         {
231             int pos;
232             switch( property_id )
233             {
234             case CV_CAP_PROP_POS_MSEC:
235                 pos = cvRound(value*capture->fps*0.001);
236                 break;
237             case CV_CAP_PROP_POS_AVI_RATIO:
238                 pos = cvRound(value*(capture->film_range.end_index - 
239                                      capture->film_range.start_index) +
240                               capture->film_range.start_index);
241                 break;
242             default:
243                 pos = cvRound(value);
244             }
245             if( pos < capture->film_range.start_index )
246                 pos = capture->film_range.start_index;
247             if( pos > capture->film_range.end_index )
248                 pos = capture->film_range.end_index;
249             capture->pos = pos;
250         }
251         break;
252     default:
253         return 0;
254     }
255
256     return 1;
257 }
258
259 static CvCaptureVTable captureAVI_VFW_vtable = 
260 {
261     6, 
262     (CvCaptureCloseFunc)          icvCloseAVI_VFW,
263     (CvCaptureGrabFrameFunc)      icvGrabFrameAVI_VFW,
264     (CvCaptureRetrieveFrameFunc)  icvRetrieveFrameAVI_VFW,
265     (CvCaptureGetPropertyFunc)    icvGetPropertyAVI_VFW,
266     (CvCaptureSetPropertyFunc)    icvSetPropertyAVI_VFW,
267     (CvCaptureGetDescriptionFunc) 0
268 };
269
270
271 CvCapture* cvCaptureFromFile_VFW (const char* filename)
272 {
273     CvCaptureAVI_VFW* capture = 0;
274
275     if( filename )
276     {
277         capture = (CvCaptureAVI_VFW*)cvAlloc( sizeof(*capture));
278         memset( capture, 0, sizeof(*capture));
279
280         capture->vtable = &captureAVI_VFW_vtable;
281
282         if( !icvOpenAVI_VFW( capture, filename ))
283             cvReleaseCapture( (CvCapture**)&capture );
284     }
285
286     return (CvCapture*)capture;
287 }
288
289 /********************* Capturing video from camera via VFW *********************/
290
291 typedef struct CvCaptureCAM_VFW
292 {
293     CvCaptureVTable* vtable;
294     CAPDRIVERCAPS caps;
295     HWND   capWnd;
296     VIDEOHDR* hdr;
297     DWORD  fourcc;
298     HIC    hic;
299     IplImage* rgb_frame;
300     IplImage frame;
301 }
302 CvCaptureCAM_VFW;
303
304
305 static LRESULT PASCAL FrameCallbackProc( HWND hWnd, VIDEOHDR* hdr ) 
306
307     CvCaptureCAM_VFW* capture = 0;
308
309     if (!hWnd) return FALSE;
310
311     capture = (CvCaptureCAM_VFW*)capGetUserData(hWnd);
312     capture->hdr = hdr;
313
314     return (LRESULT)TRUE; 
315
316
317
318 // Initialize camera input
319 static int icvOpenCAM_VFW( CvCaptureCAM_VFW* capture, int wIndex )
320 {
321     char szDeviceName[80];
322     char szDeviceVersion[80];
323     HWND hWndC = 0;
324     
325     if( (unsigned)wIndex >= 10 )
326         wIndex = 0;
327
328     for( ; wIndex < 10; wIndex++ ) 
329     {
330         if( capGetDriverDescription( wIndex, szDeviceName, 
331             sizeof (szDeviceName), szDeviceVersion, 
332             sizeof (szDeviceVersion))) 
333         {
334             hWndC = capCreateCaptureWindow ( "My Own Capture Window", 
335                 WS_POPUP | WS_CHILD, 0, 0, 320, 240, 0, 0);
336             if( capDriverConnect (hWndC, wIndex))
337                 break;
338             DestroyWindow( hWndC );
339             hWndC = 0;
340         }
341     }
342     
343     if( hWndC )
344     {
345         capture->capWnd = hWndC;
346         capture->hdr = 0;
347         capture->hic = 0;
348         capture->fourcc = (DWORD)-1;
349         capture->rgb_frame = 0;
350         
351         memset( &capture->caps, 0, sizeof(capture->caps));
352         capDriverGetCaps( hWndC, &capture->caps, sizeof(&capture->caps));
353         ::MoveWindow( hWndC, 0, 0, 320, 240, TRUE );
354         capSetUserData( hWndC, (size_t)capture );
355         capSetCallbackOnFrame( hWndC, FrameCallbackProc ); 
356         CAPTUREPARMS p;
357         capCaptureGetSetup(hWndC,&p,sizeof(CAPTUREPARMS));
358         p.dwRequestMicroSecPerFrame = 66667/2;
359         capCaptureSetSetup(hWndC,&p,sizeof(CAPTUREPARMS));
360         //capPreview( hWndC, 1 );
361         capPreviewScale(hWndC,FALSE);
362         capPreviewRate(hWndC,1);
363     }
364     return capture->capWnd != 0;
365 }
366
367 static  void icvCloseCAM_VFW( CvCaptureCAM_VFW* capture )
368 {
369     if( capture && capture->capWnd )
370     {
371         capSetCallbackOnFrame( capture->capWnd, NULL ); 
372         capDriverDisconnect( capture->capWnd );
373         DestroyWindow( capture->capWnd );
374         cvReleaseImage( &capture->rgb_frame );
375         if( capture->hic )
376         {
377             ICDecompressEnd( capture->hic );
378             ICClose( capture->hic );
379         }
380
381         capture->capWnd = 0;
382         capture->hic = 0;
383         capture->hdr = 0;
384         capture->fourcc = 0;
385         capture->rgb_frame = 0;
386         memset( &capture->frame, 0, sizeof(capture->frame));
387     }
388 }
389
390
391 static int icvGrabFrameCAM_VFW( CvCaptureCAM_VFW* capture )
392 {
393     if( capture->capWnd )
394     {
395         SendMessage( capture->capWnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0 );
396         return 1;
397     }
398     return 0;
399 }
400
401
402 static IplImage* icvRetrieveFrameCAM_VFW( CvCaptureCAM_VFW* capture )
403 {
404     if( capture->capWnd )
405     {
406         BITMAPINFO vfmt;
407         memset( &vfmt, 0, sizeof(vfmt));
408         int sz = capGetVideoFormat( capture->capWnd, &vfmt, sizeof(vfmt));
409
410         if( capture->hdr && capture->hdr->lpData && sz != 0 )
411         {
412             long code = ICERR_OK;
413             char* frame_data = (char*)capture->hdr->lpData;
414
415             if( vfmt.bmiHeader.biCompression != BI_RGB ||
416                 vfmt.bmiHeader.biBitCount != 24 )
417             {
418                 BITMAPINFOHEADER& vfmt0 = vfmt.bmiHeader;
419                 BITMAPINFOHEADER vfmt1 = icvBitmapHeader( vfmt0.biWidth, vfmt0.biHeight, 24 );
420                 code = ICERR_ERROR;
421
422                 if( capture->hic == 0 ||
423                     capture->fourcc != vfmt0.biCompression ||
424                     capture->rgb_frame == 0 ||
425                     vfmt0.biWidth != capture->rgb_frame->width ||
426                     vfmt0.biHeight != capture->rgb_frame->height )
427                 {
428                     if( capture->hic )
429                     {
430                         ICDecompressEnd( capture->hic );
431                         ICClose( capture->hic );
432                     }
433                     capture->hic = ICOpen( MAKEFOURCC('V','I','D','C'),
434                                             vfmt0.biCompression, ICMODE_DECOMPRESS );
435                     if( capture->hic &&
436                         ICDecompressBegin( capture->hic, &vfmt0, &vfmt1 ) == ICERR_OK )
437                     {
438                         cvReleaseImage( &capture->rgb_frame );
439                         capture->rgb_frame = cvCreateImage(
440                             cvSize( vfmt0.biWidth, vfmt0.biHeight ), IPL_DEPTH_8U, 3 );
441                         capture->rgb_frame->origin = IPL_ORIGIN_BL;
442
443                         code = ICDecompress( capture->hic, 0,
444                                              &vfmt0, capture->hdr->lpData,
445                                              &vfmt1, capture->rgb_frame->imageData );
446                         frame_data = capture->rgb_frame->imageData;
447                     }
448                 }
449             }
450         
451             if( code == ICERR_OK )
452             {
453                 cvInitImageHeader( &capture->frame,
454                                    cvSize(vfmt.bmiHeader.biWidth,
455                                           vfmt.bmiHeader.biHeight),
456                                    IPL_DEPTH_8U, 3, IPL_ORIGIN_BL, 4 );
457                 capture->frame.imageData = capture->frame.imageDataOrigin = frame_data;
458                 return &capture->frame;
459             }
460         }
461     }
462
463     return 0;
464 }
465
466
467 static double icvGetPropertyCAM_VFW( CvCaptureCAM_VFW* capture, int property_id )
468 {
469     switch( property_id )
470     {
471     case CV_CAP_PROP_FRAME_WIDTH:
472         return capture->frame.width;
473     case CV_CAP_PROP_FRAME_HEIGHT:
474         return capture->frame.height;
475     case CV_CAP_PROP_FOURCC:
476         return capture->fourcc;
477     }
478     return 0;
479 }
480
481
482
483 static CvCaptureVTable captureCAM_VFW_vtable = 
484 {
485     6,
486     (CvCaptureCloseFunc)icvCloseCAM_VFW,
487     (CvCaptureGrabFrameFunc)icvGrabFrameCAM_VFW,
488     (CvCaptureRetrieveFrameFunc)icvRetrieveFrameCAM_VFW,
489     (CvCaptureGetPropertyFunc)icvGetPropertyCAM_VFW,
490     (CvCaptureSetPropertyFunc)0,
491     (CvCaptureGetDescriptionFunc)0
492 };
493
494
495 CvCapture* cvCaptureFromCAM_VFW( int index )
496 {
497         CvCaptureCAM_VFW * capture = (CvCaptureCAM_VFW*)cvAlloc( sizeof(*capture));
498         memset( capture, 0, sizeof(*capture));
499         capture->vtable = &captureCAM_VFW_vtable;
500         
501         if( icvOpenCAM_VFW( capture, index ))
502                 return (CvCapture*)capture;
503         
504         cvReleaseCapture( (CvCapture**)&capture );
505         return 0;
506 }
507
508
509 /*************************** writing AVIs ******************************/
510
511 typedef struct CvAVI_VFW_Writer
512 {
513     PAVIFILE      avifile;
514     PAVISTREAM    compressed;
515     PAVISTREAM    uncompressed;
516     double        fps;
517     CvSize        frameSize;
518     IplImage    * tempFrame;
519     long          pos;
520     int           fourcc;
521 } CvAVI_VFW_Writer;
522
523
524 static void icvCloseAVIWriter( CvAVI_VFW_Writer* writer )
525 {
526     if( writer )
527     {
528         if( writer->uncompressed )
529             AVIStreamRelease( writer->uncompressed );
530         if( writer->compressed )
531             AVIStreamRelease( writer->compressed );
532         if( writer->avifile )
533             AVIFileRelease( writer->avifile );
534         cvReleaseImage( &writer->tempFrame );
535         memset( writer, 0, sizeof(*writer));
536     }
537 }
538
539
540 // philipg.  Made this code capable of writing 8bpp gray scale bitmaps
541 typedef struct tagBITMAPINFO_8Bit 
542 {
543     BITMAPINFOHEADER bmiHeader;
544     RGBQUAD          bmiColors[256];
545 } BITMAPINFOHEADER_8BIT;
546
547 static int icvInitAVIWriter( CvAVI_VFW_Writer* writer, int fourcc,
548                              double fps, CvSize frameSize, int is_color )
549 {
550     if( writer && writer->avifile )
551     {
552         AVICOMPRESSOPTIONS copts, *pcopts = &copts;
553         AVISTREAMINFO aviinfo;
554                 
555         assert( frameSize.width > 0 && frameSize.height > 0 );
556                 
557         BITMAPINFOHEADER_8BIT bmih;
558         int i;
559                 
560         bmih.bmiHeader = icvBitmapHeader( frameSize.width, frameSize.height, is_color ? 24 : 8 );
561         for( i = 0; i < 256; i++ )
562         {
563             bmih.bmiColors[i].rgbBlue = (BYTE)i;
564             bmih.bmiColors[i].rgbGreen = (BYTE)i;
565             bmih.bmiColors[i].rgbRed = (BYTE)i;
566             bmih.bmiColors[i].rgbReserved = 0;
567         }
568                 
569         memset( &aviinfo, 0, sizeof(aviinfo));
570         aviinfo.fccType = streamtypeVIDEO;
571         aviinfo.fccHandler = 0;
572         // use highest possible accuracy for dwRate/dwScale
573         aviinfo.dwScale = (DWORD)((double)0x7FFFFFFF / fps);
574         aviinfo.dwRate = cvRound(fps * aviinfo.dwScale);
575         aviinfo.rcFrame.top = aviinfo.rcFrame.left = 0;
576         aviinfo.rcFrame.right = frameSize.width;
577         aviinfo.rcFrame.bottom = frameSize.height;
578                 
579         if( AVIFileCreateStream( writer->avifile,
580                                                                  &writer->uncompressed, &aviinfo ) == AVIERR_OK )
581         {
582             copts.fccType = streamtypeVIDEO;
583             copts.fccHandler = fourcc != -1 ? fourcc : 0; 
584             copts.dwKeyFrameEvery = 1; 
585             copts.dwQuality = (DWORD)-1; 
586             copts.dwBytesPerSecond = 0; 
587             copts.dwFlags = AVICOMPRESSF_VALID; 
588             copts.lpFormat = &bmih; 
589             copts.cbFormat = (is_color ? sizeof(BITMAPINFOHEADER) : sizeof(bmih));
590             copts.lpParms = 0; 
591             copts.cbParms = 0; 
592             copts.dwInterleaveEvery = 0;
593                         
594             if( fourcc != -1 ||
595                 AVISaveOptions( 0, 0, 1, &writer->uncompressed, &pcopts ) == TRUE )
596             {
597                 if( AVIMakeCompressedStream( &writer->compressed,
598                                                                                          writer->uncompressed, pcopts, 0 ) == AVIERR_OK &&
599                     // check that the resolution was not changed
600                     bmih.bmiHeader.biWidth == frameSize.width &&
601                     bmih.bmiHeader.biHeight == frameSize.height &&
602                     AVIStreamSetFormat( writer->compressed, 0, &bmih, sizeof(bmih)) == AVIERR_OK )
603                                 {
604                                         writer->fps = fps;
605                                         writer->fourcc = (int)copts.fccHandler;
606                                         writer->frameSize = frameSize;
607                                         writer->tempFrame = cvCreateImage( frameSize, 8, (is_color ? 3 : 1) );
608                                         return 1;
609                                 }
610             }
611         }
612     }
613     icvCloseAVIWriter( writer );
614     return 0;
615 }
616
617 CvVideoWriter* cvCreateVideoWriter_VFW( const char* filename, int fourcc,
618                                         double fps, CvSize frameSize, int is_color )
619 {
620     CvAVI_VFW_Writer* writer = (CvAVI_VFW_Writer*)cvAlloc( sizeof(CvAVI_VFW_Writer));
621     memset( writer, 0, sizeof(*writer));
622         
623     icvInitCapture_VFW();
624     
625     if( AVIFileOpen( &writer->avifile, filename, OF_CREATE | OF_WRITE, 0 ) == AVIERR_OK )
626     {
627         if( frameSize.width > 0 && frameSize.height > 0 )
628         {
629             if( !icvInitAVIWriter( writer, fourcc, fps, frameSize, is_color ))
630                 cvReleaseVideoWriter( (CvVideoWriter**)&writer );
631         }
632         else if( fourcc == -1 )
633         {
634             icvCloseAVIWriter( writer );
635         }
636         else
637         {
638             /* postpone initialization until the first frame is written */
639             writer->fourcc = fourcc;
640             writer->fps = fps;
641             writer->frameSize = frameSize;
642         }
643     }
644     
645     return (CvVideoWriter*)writer;
646 }
647
648 int cvWriteFrame_VFW( CvVideoWriter* _writer, const IplImage* image )
649 {
650     CvAVI_VFW_Writer* writer = (CvAVI_VFW_Writer*)_writer;
651         
652     if( writer && (writer->compressed ||
653                                    icvInitAVIWriter( writer, writer->fourcc, writer->fps,
654                                                                          writer->frameSize, image->nChannels > 1 )))
655     {
656         if (image->nChannels != writer->tempFrame->nChannels)
657         {
658             cvConvertImage( image, writer->tempFrame,
659                                                         image->origin == 0 ? CV_CVTIMG_FLIP : 0 );
660             image = (const IplImage*)writer->tempFrame;
661         }
662         // If only flipping is needed, do not call cvConvertImage because when source and destination are single channel, cvConvertImage fails.
663         else if (image->origin == 0)
664         {
665             cvFlip( image, writer->tempFrame, 0 );
666             image = (const IplImage*)writer->tempFrame;
667         }
668         if( AVIStreamWrite( writer->compressed, writer->pos++, 1, image->imageData,
669                             image->imageSize, AVIIF_KEYFRAME, 0, 0 ) == AVIERR_OK )
670         {
671             return 1;
672         }
673     }
674     return 0;
675 }
676
677 void cvReleaseVideoWriter_VFW( CvVideoWriter** writer )
678 {
679     if( writer && *writer )
680     {
681         icvCloseAVIWriter( (CvAVI_VFW_Writer*)*writer );
682         cvFree( writer );
683     }
684 }
685
686