Apply maemo2 patch
[opencv] / otherlibs / highgui / cvcap_ffmpeg.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 #if defined _MSC_VER && _MSC_VER >= 1200
45 #pragma warning( disable: 4244 4510 4512 4610 )
46 #endif
47
48 extern "C" {
49 #ifndef WIN32
50 #define INT64_C
51 #define __STDC_CONSTANT_MACROS
52 #include <stdint.h>
53 #include <errno.h>
54 #endif
55
56 #include <ffmpeg/avformat.h>
57 #include <ffmpeg/avcodec.h>
58 }
59
60 #if defined _MSC_VER && _MSC_VER >= 1200
61 #pragma warning( default: 4244 4510 4512 4610 )
62 #endif
63
64 #ifdef NDEBUG
65 #define CV_WARN(message)
66 #else
67 #define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
68 #endif
69
70
71 #ifndef MKTAG
72 #define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
73 #endif
74
75
76
77
78 char * FOURCC2str( int fourcc )
79 {
80     char * mystr=(char*)malloc(5);
81     mystr[0]=(char)((fourcc    )&255);
82     mystr[1]=(char)((fourcc>> 8)&255);
83     mystr[2]=(char)((fourcc>>16)&255);
84     mystr[3]=(char)((fourcc>>24)&255);
85     mystr[4]=0;
86     return mystr;
87 }
88
89
90 // required to look up the correct codec ID depending on the FOURCC code,
91 // this is just a snipped from the file riff.c from ffmpeg/libavformat
92 typedef struct AVCodecTag {
93     int id;
94     unsigned int tag;
95 } AVCodecTag;
96
97 const AVCodecTag codec_bmp_tags[] = {
98     { CODEC_ID_H264, MKTAG('H', '2', '6', '4') },
99     { CODEC_ID_H264, MKTAG('h', '2', '6', '4') },
100     { CODEC_ID_H264, MKTAG('X', '2', '6', '4') },
101     { CODEC_ID_H264, MKTAG('x', '2', '6', '4') },
102     { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
103     { CODEC_ID_H264, MKTAG('V', 'S', 'S', 'H') },
104
105     { CODEC_ID_H263, MKTAG('H', '2', '6', '3') },
106     { CODEC_ID_H263P, MKTAG('H', '2', '6', '3') },
107     { CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
108     { CODEC_ID_H261, MKTAG('H', '2', '6', '1') },
109
110     /* added based on MPlayer */
111     { CODEC_ID_H263P, MKTAG('U', '2', '6', '3') },
112     { CODEC_ID_H263P, MKTAG('v', 'i', 'v', '1') },
113
114     { CODEC_ID_MPEG4, MKTAG('F', 'M', 'P', '4') },
115     { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') },
116     { CODEC_ID_MPEG4, MKTAG('D', 'X', '5', '0') },
117     { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') },
118     { CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
119     { CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
120     { CODEC_ID_MPEG4, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */
121
122     /* added based on MPlayer */
123     { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', '1') },
124     { CODEC_ID_MPEG4, MKTAG('B', 'L', 'Z', '0') },
125     { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
126     { CODEC_ID_MPEG4, MKTAG('U', 'M', 'P', '4') },
127     { CODEC_ID_MPEG4, MKTAG('W', 'V', '1', 'F') },
128     { CODEC_ID_MPEG4, MKTAG('S', 'E', 'D', 'G') },
129
130     { CODEC_ID_MPEG4, MKTAG('R', 'M', 'P', '4') },
131
132     { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3') }, /* default signature when using MSMPEG4 */
133     { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') },
134
135     /* added based on MPlayer */
136     { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', 'G', '3') },
137     { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '5') },
138     { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '6') },
139     { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '4') },
140     { CODEC_ID_MSMPEG4V3, MKTAG('A', 'P', '4', '1') },
141     { CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '1') },
142     { CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '0') },
143
144     { CODEC_ID_MSMPEG4V2, MKTAG('M', 'P', '4', '2') },
145
146     /* added based on MPlayer */
147     { CODEC_ID_MSMPEG4V2, MKTAG('D', 'I', 'V', '2') },
148
149     { CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', 'G', '4') },
150
151     { CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') },
152
153     /* added based on MPlayer */
154     { CODEC_ID_WMV2, MKTAG('W', 'M', 'V', '2') },
155     { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'd') },
156     { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'd') },
157     { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'l') },
158     { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '2', '5') },
159     { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '1') },
160     { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '2') },
161     { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', '2') },
162     { CODEC_ID_MPEG2VIDEO, MKTAG('M', 'P', 'E', 'G') },
163     { CODEC_ID_MPEG1VIDEO, MKTAG('P', 'I', 'M', '1') },
164     { CODEC_ID_MPEG1VIDEO, MKTAG('V', 'C', 'R', '2') },
165     { CODEC_ID_MPEG1VIDEO, 0x10000001 },
166     { CODEC_ID_MPEG2VIDEO, 0x10000002 },
167     { CODEC_ID_MPEG2VIDEO, MKTAG('D', 'V', 'R', ' ') },
168     { CODEC_ID_MPEG2VIDEO, MKTAG('M', 'M', 'E', 'S') },
169     { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
170     { CODEC_ID_MJPEG, MKTAG('L', 'J', 'P', 'G') },
171     { CODEC_ID_LJPEG, MKTAG('L', 'J', 'P', 'G') },
172     { CODEC_ID_MJPEG, MKTAG('J', 'P', 'G', 'L') }, /* Pegasus lossless JPEG */
173     { CODEC_ID_MJPEG, MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - decoder */
174     { CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') },
175     { CODEC_ID_MJPEG, MKTAG('I', 'J', 'P', 'G') },
176     { CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') },
177     { CODEC_ID_HUFFYUV, MKTAG('H', 'F', 'Y', 'U') },
178     { CODEC_ID_FFVHUFF, MKTAG('F', 'F', 'V', 'H') },
179     { CODEC_ID_CYUV, MKTAG('C', 'Y', 'U', 'V') },
180     { CODEC_ID_RAWVIDEO, 0 },
181     { CODEC_ID_RAWVIDEO, MKTAG('I', '4', '2', '0') },
182     { CODEC_ID_RAWVIDEO, MKTAG('Y', 'U', 'Y', '2') },
183     { CODEC_ID_RAWVIDEO, MKTAG('Y', '4', '2', '2') },
184     { CODEC_ID_RAWVIDEO, MKTAG('Y', 'V', '1', '2') },
185     { CODEC_ID_RAWVIDEO, MKTAG('U', 'Y', 'V', 'Y') },
186     { CODEC_ID_RAWVIDEO, MKTAG('I', 'Y', 'U', 'V') },
187     { CODEC_ID_RAWVIDEO, MKTAG('Y', '8', '0', '0') },
188     { CODEC_ID_RAWVIDEO, MKTAG('H', 'D', 'Y', 'C') },
189     { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '1') },
190     { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '2') },
191     { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') },
192     { CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') },
193     { CODEC_ID_ASV1, MKTAG('A', 'S', 'V', '1') },
194     { CODEC_ID_ASV2, MKTAG('A', 'S', 'V', '2') },
195     { CODEC_ID_VCR1, MKTAG('V', 'C', 'R', '1') },
196     { CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
197     { CODEC_ID_XAN_WC4, MKTAG('X', 'x', 'a', 'n') },
198     { CODEC_ID_MSRLE, MKTAG('m', 'r', 'l', 'e') },
199     { CODEC_ID_MSRLE, MKTAG(0x1, 0x0, 0x0, 0x0) },
200     { CODEC_ID_MSVIDEO1, MKTAG('M', 'S', 'V', 'C') },
201     { CODEC_ID_MSVIDEO1, MKTAG('m', 's', 'v', 'c') },
202     { CODEC_ID_MSVIDEO1, MKTAG('C', 'R', 'A', 'M') },
203     { CODEC_ID_MSVIDEO1, MKTAG('c', 'r', 'a', 'm') },
204     { CODEC_ID_MSVIDEO1, MKTAG('W', 'H', 'A', 'M') },
205     { CODEC_ID_MSVIDEO1, MKTAG('w', 'h', 'a', 'm') },
206     { CODEC_ID_CINEPAK, MKTAG('c', 'v', 'i', 'd') },
207     { CODEC_ID_TRUEMOTION1, MKTAG('D', 'U', 'C', 'K') },
208     { CODEC_ID_MSZH, MKTAG('M', 'S', 'Z', 'H') },
209     { CODEC_ID_ZLIB, MKTAG('Z', 'L', 'I', 'B') },
210     { CODEC_ID_SNOW, MKTAG('S', 'N', 'O', 'W') },
211     { CODEC_ID_4XM, MKTAG('4', 'X', 'M', 'V') },
212     { CODEC_ID_FLV1, MKTAG('F', 'L', 'V', '1') },
213     { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') },
214     { CODEC_ID_TSCC, MKTAG('t', 's', 'c', 'c') },
215     { CODEC_ID_ULTI, MKTAG('U', 'L', 'T', 'I') },
216     { CODEC_ID_VIXL, MKTAG('V', 'I', 'X', 'L') },
217     { CODEC_ID_QPEG, MKTAG('Q', 'P', 'E', 'G') },
218     { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '0') },
219     { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '1') },
220     { CODEC_ID_WMV3, MKTAG('W', 'M', 'V', '3') },
221     { CODEC_ID_LOCO, MKTAG('L', 'O', 'C', 'O') },
222     { CODEC_ID_THEORA, MKTAG('t', 'h', 'e', 'o') },
223 #if LIBAVCODEC_VERSION_INT>0x000409
224     { CODEC_ID_WNV1, MKTAG('W', 'N', 'V', '1') },
225     { CODEC_ID_AASC, MKTAG('A', 'A', 'S', 'C') },
226     { CODEC_ID_INDEO2, MKTAG('R', 'T', '2', '1') },
227     { CODEC_ID_FRAPS, MKTAG('F', 'P', 'S', '1') },
228     { CODEC_ID_TRUEMOTION2, MKTAG('T', 'M', '2', '0') },
229 #endif
230 #if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0)
231     { CODEC_ID_FLASHSV, MKTAG('F', 'S', 'V', '1') },
232     { CODEC_ID_JPEGLS,MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - encoder */
233     { CODEC_ID_VC1, MKTAG('W', 'V', 'C', '1') },
234     { CODEC_ID_VC1, MKTAG('W', 'M', 'V', 'A') },
235     { CODEC_ID_CSCD, MKTAG('C', 'S', 'C', 'D') },
236     { CODEC_ID_ZMBV, MKTAG('Z', 'M', 'B', 'V') },
237     { CODEC_ID_KMVC, MKTAG('K', 'M', 'V', 'C') },
238 #endif
239 #if LIBAVCODEC_VERSION_INT>((51<<16)+(11<<8)+0)
240     { CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') },
241     { CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') },
242     { CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') },
243     { CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') },
244     { CODEC_ID_VP6F, MKTAG('V', 'P', '6', 'F') },
245     { CODEC_ID_JPEG2000, MKTAG('M', 'J', '2', 'C') },
246     { CODEC_ID_VMNC, MKTAG('V', 'M', 'n', 'c') },
247 #endif
248 #if LIBAVCODEC_VERSION_INT>=((51<<16)+(49<<8)+0)
249 // this tag seems not to exist in older versions of FFMPEG
250     { CODEC_ID_TARGA, MKTAG('t', 'g', 'a', ' ') },
251 #endif
252     { CODEC_ID_NONE, 0 },
253 };
254
255
256 class CvCapture_FFMPEG : public CvCapture
257 {
258 public:
259     CvCapture_FFMPEG() { init(); }
260     virtual ~CvCapture_FFMPEG() { close(); }
261
262     virtual bool open( const char* filename );
263     virtual void close();
264     
265     virtual double getProperty(int);
266     virtual bool setProperty(int, double);
267     virtual bool grabFrame();
268     virtual IplImage* retrieveFrame();
269
270 protected:
271     void init();
272     bool reopen();
273     bool slowSeek( int framenumber );
274
275     AVFormatContext   * ic;
276     int                 video_stream;
277     AVStream          * video_st;
278     AVFrame           * picture;
279     int64_t             picture_pts;
280     AVFrame             rgb_picture;
281     IplImage            frame;
282 /*
283    'filename' contains the filename of the videosource,
284    'filename==NULL' indicates that ffmpeg's seek support works
285    for the particular file.
286    'filename!=NULL' indicates that the slow fallback function is used for seeking,
287    and so the filename is needed to reopen the file on backward seeking.
288 */
289     char              * filename;
290 };
291
292
293 void CvCapture_FFMPEG::init()
294 {
295     ic = 0;
296     video_stream = -1;
297     video_st = 0;
298     picture = 0;
299     picture_pts = 0;
300     memset( &rgb_picture, 0, sizeof(rgb_picture) );
301     memset( &frame, 0, sizeof(frame) );
302     filename = 0;
303 }
304
305
306 void CvCapture_FFMPEG::close()
307 {
308     if( picture )
309     av_free(picture);
310
311     if( video_st )
312     {
313 #if LIBAVFORMAT_BUILD > 4628
314         avcodec_close( video_st->codec );
315 #else
316         avcodec_close( &video_st->codec );
317 #endif
318         video_st = NULL;
319     }
320
321     if( ic )
322     {
323         av_close_input_file(ic);
324         ic = NULL;
325     }
326
327     if( rgb_picture.data[0] )
328         cvFree( &rgb_picture.data[0] );
329
330     init();
331 }
332
333
334 /*
335     Used to reopen a video if the slower fallback function for seeking is used.
336 */
337 bool CvCapture_FFMPEG::reopen()
338 {
339     if ( filename==NULL ) return false;
340
341 #if LIBAVFORMAT_BUILD > 4628
342     avcodec_close( video_st->codec );
343 #else
344     avcodec_close( &video_st->codec );
345 #endif
346     av_close_input_file(ic);
347
348     // reopen video
349     av_open_input_file(&ic, filename, NULL, 0, NULL);
350     av_find_stream_info(ic);
351 #if LIBAVFORMAT_BUILD > 4628
352     AVCodecContext *enc = ic->streams[video_stream]->codec;
353 #else
354     AVCodecContext *enc = &ic->streams[video_stream]->codec;
355 #endif
356     AVCodec *codec = avcodec_find_decoder(enc->codec_id);
357     avcodec_open(enc, codec);
358     video_st = ic->streams[video_stream];
359
360     // reset framenumber to zero
361     picture_pts=0;
362
363     return true;
364 }
365
366
367
368 bool CvCapture_FFMPEG::open( const char* _filename )
369 {
370     unsigned i;
371     bool valid = false;
372
373     close();
374
375     /* register all codecs, demux and protocols */
376     av_register_all();
377
378 #ifndef _DEBUG
379     // av_log_level = AV_LOG_QUIET;
380 #endif
381
382     int err = av_open_input_file(&ic, _filename, NULL, 0, NULL);
383     if (err < 0) {
384             CV_WARN("Error opening file");
385             goto exit_func;
386     }
387     err = av_find_stream_info(ic);
388     if (err < 0) {
389             CV_WARN("Could not find codec parameters");
390             goto exit_func;
391     }
392     for(i = 0; i < ic->nb_streams; i++) {
393 #if LIBAVFORMAT_BUILD > 4628
394         AVCodecContext *enc = ic->streams[i]->codec;
395 #else
396         AVCodecContext *enc = &ic->streams[i]->codec;
397 #endif
398         
399         if( CODEC_TYPE_VIDEO == enc->codec_type && video_stream < 0) {
400             AVCodec *codec = avcodec_find_decoder(enc->codec_id);
401             if (!codec ||
402             avcodec_open(enc, codec) < 0)
403             goto exit_func;
404             video_stream = i;
405             video_st = ic->streams[i];
406             picture = avcodec_alloc_frame();
407
408             rgb_picture.data[0] = (uint8_t*)cvAlloc(
409                                     avpicture_get_size( PIX_FMT_BGR24,
410                                     enc->width, enc->height ));
411             avpicture_fill( (AVPicture*)&rgb_picture, rgb_picture.data[0],
412                     PIX_FMT_BGR24, enc->width, enc->height );
413
414             cvInitImageHeader( &frame, cvSize( enc->width,
415                                        enc->height ), 8, 3, 0, 4 );
416             cvSetData( &frame, rgb_picture.data[0],
417                                rgb_picture.linesize[0] );
418             break;
419         }
420     }
421
422     if(video_stream >= 0) valid = true;
423
424     // perform check if source is seekable via ffmpeg's seek function av_seek_frame(...)
425     err = av_seek_frame(ic, video_stream, 10, 0);
426     if (err < 0)
427     {
428         filename=(char*)malloc(strlen(_filename)+1);
429         strcpy(filename, _filename);
430         // reopen videofile to 'seek' back to first frame
431         reopen();
432     }
433     else
434     {
435         // seek seems to work, so we don't need the filename,
436         // but we still need to seek back to filestart
437         filename=NULL;
438         av_seek_frame(ic, video_stream, 0, 0);
439     }
440 exit_func:
441
442     if( !valid )
443         close();
444
445     return valid;
446 }
447
448
449 bool CvCapture_FFMPEG::grabFrame()
450 {
451     bool valid = false;
452     static bool bFirstTime = true;
453     static AVPacket pkt;
454     int got_picture;
455
456     // First time we're called, set packet.data to NULL to indicate it
457     // doesn't have to be freed
458     if (bFirstTime) {
459         bFirstTime = false;
460         pkt.data = NULL;
461     }
462
463     if( !ic || !video_st )
464         return false;
465
466     // free last packet if exist
467     if (pkt.data != NULL) {
468         av_free_packet (&pkt);
469     }
470
471     // get the next frame
472     while (!valid && (av_read_frame(ic, &pkt) >= 0)) {
473                 if( pkt.stream_index != video_stream ) continue;
474 #if LIBAVFORMAT_BUILD > 4628
475         avcodec_decode_video(video_st->codec,
476                              picture, &got_picture,
477                              pkt.data, pkt.size);
478 #else
479         avcodec_decode_video(&video_st->codec,
480                              picture, &got_picture,
481                              pkt.data, pkt.size);
482 #endif
483
484         if (got_picture) {
485             // we have a new picture, so memorize it
486             picture_pts = pkt.pts;
487             valid = 1;
488         }
489     }
490
491     // return if we have a new picture or not
492     return valid;
493 }
494
495
496 IplImage* CvCapture_FFMPEG::retrieveFrame()
497 {
498     if( !video_st || !picture->data[0] )
499         return 0;
500
501
502 #if LIBAVFORMAT_BUILD > 4628
503     img_convert( (AVPicture*)&rgb_picture, PIX_FMT_BGR24,
504                  (AVPicture*)picture,
505                  video_st->codec->pix_fmt,
506                  video_st->codec->width,
507                  video_st->codec->height );
508 #else
509     img_convert( (AVPicture*)&rgb_picture, PIX_FMT_BGR24,
510                  (AVPicture*)picture,
511                  video_st->codec.pix_fmt,
512                  video_st->codec.width,
513                  video_st->codec.height );
514 #endif
515     return &frame;
516 }
517
518
519 double CvCapture_FFMPEG::getProperty( int property_id )
520 {
521     // if( !capture || !video_st || !picture->data[0] ) return 0;
522     if( !video_st ) return 0;
523
524
525     int64_t timestamp;
526     timestamp = picture_pts;
527
528     switch( property_id )
529     {
530     case CV_CAP_PROP_POS_MSEC:
531         // if(ic->start_time != static_cast<double>(AV_NOPTS_VALUE))
532         if(ic->start_time != AV_NOPTS_VALUE)
533         return (double)(timestamp - ic->start_time)*1000/(double)AV_TIME_BASE;
534         break;
535     case CV_CAP_PROP_POS_FRAMES:
536     //if(video_st->cur_dts != static_cast<double>(AV_NOPTS_VALUE))
537     if(video_st->cur_dts != AV_NOPTS_VALUE)
538         return (double)video_st->cur_dts-1;
539     break;
540     case CV_CAP_PROP_POS_AVI_RATIO:
541     //  if(ic->start_time != static_cast<double>(AV_NOPTS_VALUE) && ic->duration != static_cast<double>(AV_NOPTS_VALUE))
542     if(ic->start_time != AV_NOPTS_VALUE && ic->duration != AV_NOPTS_VALUE)
543         return (double)(timestamp-ic->start_time)/(double)ic->duration;
544     break;
545     case CV_CAP_PROP_FRAME_WIDTH:
546         return (double)frame.width;
547     break;
548     case CV_CAP_PROP_FRAME_HEIGHT:
549         return (double)frame.height;
550     break;
551     case CV_CAP_PROP_FPS:
552 #if LIBAVCODEC_BUILD > 4753
553         return av_q2d (video_st->r_frame_rate);
554 #else
555         return (double)video_st->codec.frame_rate
556             / (double)video_st->codec.frame_rate_base;
557 #endif
558     break;
559     case CV_CAP_PROP_FOURCC:
560 #if LIBAVFORMAT_BUILD > 4628
561         return (double)video_st->codec->codec_tag;
562 #else
563         return (double)video_st->codec.codec_tag;
564 #endif
565     break;
566     }
567     return 0;
568 }
569
570
571
572 // this is a VERY slow fallback function, ONLY used if ffmpeg's av_seek_frame delivers no correct result!
573 bool CvCapture_FFMPEG::slowSeek( int framenumber )
574 {
575     if ( framenumber>picture_pts )
576     {
577         while ( picture_pts<framenumber )
578             if ( !grabFrame() ) return false;
579     }
580     else if ( framenumber<picture_pts )
581     {
582         reopen();
583         while ( picture_pts<framenumber )
584             if ( !grabFrame() ) return false;
585     }
586     return true;
587 }
588
589
590 bool CvCapture_FFMPEG::setProperty( int property_id, double value )
591 {
592     if( !video_st ) return false;
593
594     switch( property_id )
595     {
596     case CV_CAP_PROP_POS_MSEC:
597     case CV_CAP_PROP_POS_FRAMES:
598     case CV_CAP_PROP_POS_AVI_RATIO:
599         {
600             int64_t timestamp = 0;
601             AVRational time_base;
602             switch( property_id )
603             {
604             case CV_CAP_PROP_POS_FRAMES:
605                 timestamp=(int64_t)value;
606                 if(ic->start_time != AV_NOPTS_VALUE)
607                     timestamp += ic->start_time;
608                 break;
609
610             case CV_CAP_PROP_POS_MSEC:
611                 time_base=ic->streams[video_stream]->time_base;
612                 timestamp=(int64_t)(value*(float(time_base.den)/float(time_base.num))/1000);
613                 if(ic->start_time != AV_NOPTS_VALUE)
614                     timestamp += ic->start_time;
615                 break;
616
617             case CV_CAP_PROP_POS_AVI_RATIO:
618                 timestamp=(int64_t)(value*ic->duration);
619                 if(ic->start_time != AV_NOPTS_VALUE && ic->duration != AV_NOPTS_VALUE)
620                     timestamp += ic->start_time;
621                 break;
622             }
623
624             if ( filename )
625             {
626                 // ffmpeg's seek doesn't work...
627                 if (!slowSeek((int)timestamp))
628                 {
629                     fprintf(stderr, "HIGHGUI ERROR: AVI: could not (slow) seek to position %0.3f\n",
630                         (double)timestamp / AV_TIME_BASE);
631                     return false;
632                 }
633             }
634             else
635             {
636                 int ret = av_seek_frame(ic, video_stream, timestamp, 0);
637                 if (ret < 0)
638                 {
639                     fprintf(stderr, "HIGHGUI ERROR: AVI: could not seek to position %0.3f\n",
640                             (double)timestamp / AV_TIME_BASE);
641                     return false;
642                 }
643             }
644             picture_pts=(int64_t)value;
645         }
646         break;
647
648     default:
649         return false;
650     }
651
652     return true;
653 }
654
655
656
657 CvCapture* cvCreateFileCapture_FFMPEG( const char* filename )
658 {
659     CvCapture_FFMPEG* capture = new CvCapture_FFMPEG;
660     if( capture->open( filename ))
661         return capture;
662     delete capture;
663     return 0;
664 }
665
666
667 ///////////////// FFMPEG CvVideoWriter implementation //////////////////////////
668 class CvVideoWriter_FFMPEG : public CvVideoWriter
669 {
670 public:
671     CvVideoWriter_FFMPEG() { init(); }
672     virtual ~CvVideoWriter_FFMPEG() { close(); }
673
674     virtual bool open( const char* filename, int fourcc,
675         double fps, CvSize frameSize, bool isColor );
676     virtual void close();
677     virtual bool writeFrame( const IplImage* image );
678
679 protected:
680     void init();
681
682     AVOutputFormat *fmt;
683     AVFormatContext *oc;
684     uint8_t         * outbuf;
685     uint32_t          outbuf_size;
686     FILE            * outfile;
687     AVFrame         * picture;
688     AVFrame         * input_picture;
689     uint8_t         * picbuf;
690     AVStream        * video_st;
691     int               input_pix_fmt;
692     IplImage        * temp_image;
693 };
694
695 static const char * icvFFMPEGErrStr(int err)
696 {
697     switch(err) {
698     case AVERROR_NUMEXPECTED:
699                 return "Incorrect filename syntax";
700     case AVERROR_INVALIDDATA:
701                 return "Invalid data in header";
702     case AVERROR_NOFMT:
703                 return "Unknown format";
704     case AVERROR_IO:
705                 return "I/O error occurred";
706     case AVERROR_NOMEM:
707                 return "Memory allocation error";
708     default:
709                 break;
710     }
711         return "Unspecified error";
712 }
713
714 /* function internal to FFMPEG (libavformat/riff.c) to lookup codec id by fourcc tag*/
715 extern "C" {
716         enum CodecID codec_get_bmp_id(unsigned int tag);
717 }
718
719 void CvVideoWriter_FFMPEG::init()
720 {
721     fmt = 0;
722     oc = 0;
723     outbuf = 0;
724     outbuf_size = 0;
725     outfile = 0;
726     picture = 0;
727     input_picture = 0;
728     picbuf = 0;
729     video_st = 0;
730     input_pix_fmt = 0;
731     temp_image = 0;
732 }
733
734 /**
735  * the following function is a modified version of code
736  * found in ffmpeg-0.4.9-pre1/output_example.c
737  */
738 static AVFrame * icv_alloc_picture_FFMPEG(int pix_fmt, int width, int height, bool alloc)
739 {
740         AVFrame * picture;
741         uint8_t * picture_buf;
742         int size;
743
744         picture = avcodec_alloc_frame();
745         if (!picture)
746                 return NULL;
747         size = avpicture_get_size(pix_fmt, width, height);
748         if(alloc){
749                 picture_buf = (uint8_t *) cvAlloc(size);
750                 if (!picture_buf)
751                 {
752                         av_free(picture);
753                         return NULL;
754                 }
755                 avpicture_fill((AVPicture *)picture, picture_buf,
756                                 pix_fmt, width, height);
757         }
758         else {
759         }
760         return picture;
761 }
762
763 /* add a video output stream to the container */
764 static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
765                                                      CodecID codec_id,
766                                                                                          int w, int h, int bitrate,
767                                                                                          double fps, int pixel_format)
768 {
769         AVCodecContext *c;
770         AVStream *st;
771         int frame_rate, frame_rate_base;
772         AVCodec *codec;
773
774
775         st = av_new_stream(oc, 0);
776         if (!st) {
777                 CV_WARN("Could not allocate stream");
778                 return NULL;
779         }
780
781 #if LIBAVFORMAT_BUILD > 4628
782         c = st->codec;
783 #else
784         c = &(st->codec);
785 #endif
786
787 #if LIBAVFORMAT_BUILD > 4621
788         c->codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, CODEC_TYPE_VIDEO);
789 #else
790         c->codec_id = oc->oformat->video_codec;
791 #endif
792
793         if(codec_id != CODEC_ID_NONE){
794                 c->codec_id = codec_id;
795         }
796
797     //if(codec_tag) c->codec_tag=codec_tag;
798         codec = avcodec_find_encoder(c->codec_id);
799
800         c->codec_type = CODEC_TYPE_VIDEO;
801
802         /* put sample parameters */
803         c->bit_rate = bitrate;
804
805         /* resolution must be a multiple of two */
806         c->width = w;
807         c->height = h;
808
809         /* time base: this is the fundamental unit of time (in seconds) in terms
810        of which frame timestamps are represented. for fixed-fps content,
811        timebase should be 1/framerate and timestamp increments should be
812        identically 1. */
813         frame_rate=cvRound(fps);
814         frame_rate_base=1;
815         while (fabs((double)frame_rate/frame_rate_base) - fps > 0.001){
816                 frame_rate_base*=10;
817                 frame_rate=cvRound(fps*frame_rate_base);
818         }
819 #if LIBAVFORMAT_BUILD > 4752
820     c->time_base.den = frame_rate;
821     c->time_base.num = frame_rate_base;
822         /* adjust time base for supported framerates */
823         if(codec && codec->supported_framerates){
824                 const AVRational *p= codec->supported_framerates;
825         AVRational req = {frame_rate, frame_rate_base};
826                 const AVRational *best=NULL;
827                 AVRational best_error= {INT_MAX, 1};
828                 for(; p->den!=0; p++){
829                         AVRational error= av_sub_q(req, *p);
830                         if(error.num <0) error.num *= -1;
831                         if(av_cmp_q(error, best_error) < 0){
832                                 best_error= error;
833                                 best= p;
834                         }
835                 }
836                 c->time_base.den= best->num;
837                 c->time_base.num= best->den;
838         }
839 #else
840         c->frame_rate = frame_rate;
841         c->frame_rate_base = frame_rate_base;
842 #endif
843
844         c->gop_size = 12; /* emit one intra frame every twelve frames at most */
845         c->pix_fmt = (PixelFormat) pixel_format;
846
847         if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
848         c->max_b_frames = 2;
849     }
850     if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3){
851         /* needed to avoid using macroblocks in which some coeffs overflow
852            this doesnt happen with normal video, it just happens here as the
853            motion of the chroma plane doesnt match the luma plane */
854                 /* avoid FFMPEG warning 'clipping 1 dct coefficients...' */
855         c->mb_decision=2;
856     }
857 #if LIBAVCODEC_VERSION_INT>0x000409
858     // some formats want stream headers to be seperate
859     if(oc->oformat->flags & AVFMT_GLOBALHEADER)
860     {
861         c->flags |= CODEC_FLAG_GLOBAL_HEADER;
862     }
863 #endif
864
865     return st;
866 }
867
868 int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, uint8_t * outbuf, uint32_t outbuf_size, AVFrame * picture ){
869         CV_FUNCNAME("icv_av_write_frame_FFMPEG");
870
871 #if LIBAVFORMAT_BUILD > 4628
872         AVCodecContext * c = video_st->codec;
873 #else
874         AVCodecContext * c = &(video_st->codec);
875 #endif
876         int out_size;
877         int ret;
878
879         __BEGIN__;
880
881     if (oc->oformat->flags & AVFMT_RAWPICTURE) {
882         /* raw video case. The API will change slightly in the near
883            futur for that */
884         AVPacket pkt;
885         av_init_packet(&pkt);
886
887         pkt.flags |= PKT_FLAG_KEY;
888         pkt.stream_index= video_st->index;
889         pkt.data= (uint8_t *)picture;
890         pkt.size= sizeof(AVPicture);
891
892         ret = av_write_frame(oc, &pkt);
893     } else {
894         /* encode the image */
895         out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);
896         /* if zero size, it means the image was buffered */
897         if (out_size > 0) {
898             AVPacket pkt;
899             av_init_packet(&pkt);
900
901 #if LIBAVFORMAT_BUILD > 4752
902             pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, video_st->time_base);
903 #else
904                         pkt.pts = c->coded_frame->pts;
905 #endif
906             if(c->coded_frame->key_frame)
907                 pkt.flags |= PKT_FLAG_KEY;
908             pkt.stream_index= video_st->index;
909             pkt.data= outbuf;
910             pkt.size= out_size;
911
912             /* write the compressed frame in the media file */
913             ret = av_write_frame(oc, &pkt);
914         } else {
915             ret = 0;
916         }
917     }
918     if (ret != 0) {
919                 CV_ERROR(CV_StsError, "Error while writing video frame");
920         }
921
922         __END__;
923         return CV_StsOk;
924 }
925
926 /// write a frame with FFMPEG
927 bool CvVideoWriter_FFMPEG::writeFrame( const IplImage * image )
928 {
929         bool ret = false;
930
931     CV_FUNCNAME("CvVideoWriter_FFMPEG::writerFrame");
932
933         __BEGIN__;
934
935         // typecast from opaque data type to implemented struct
936 #if LIBAVFORMAT_BUILD > 4628
937     AVCodecContext *c = video_st->codec;
938 #else
939         AVCodecContext *c = &(video_st->codec);
940 #endif
941
942     if( c->codec_id == CODEC_ID_RAWVIDEO && image->origin != IPL_ORIGIN_BL )
943     {
944         if( !temp_image )
945             temp_image = cvCreateImage( cvGetSize(image),
946                                     image->depth, image->nChannels );
947         cvFlip( image, temp_image, 0 );
948         image = temp_image;
949     }
950
951     // check parameters
952     if (input_pix_fmt == PIX_FMT_BGR24) {
953         if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U) {
954             CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 3.");
955         }
956     }
957         else if (input_pix_fmt == PIX_FMT_GRAY8) {
958         if (image->nChannels != 1 || image->depth != IPL_DEPTH_8U) {
959             CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 1.");
960         }
961     }
962         else {
963         assert(false);
964     }
965
966         // check if buffer sizes match, i.e. image has expected format (size, channels, bitdepth, alignment)
967         assert (image->imageSize == avpicture_get_size( input_pix_fmt, image->width, image->height ));
968
969         if ( c->pix_fmt != input_pix_fmt ) {
970                 assert( input_picture );
971                 // let input_picture point to the raw data buffer of 'image'
972                 avpicture_fill((AVPicture *)input_picture, (uint8_t *) image->imageData,
973                                 input_pix_fmt, image->width, image->height);
974
975                 // convert to the color format needed by the codec
976                 if( img_convert((AVPicture *)picture, c->pix_fmt,
977                                         (AVPicture *)input_picture, input_pix_fmt,
978                                         image->width, image->height) < 0){
979                         CV_ERROR(CV_StsUnsupportedFormat, "FFMPEG::img_convert pixel format conversion from BGR24 not handled");
980                 }
981         }
982         else{
983                 avpicture_fill((AVPicture *)picture, (uint8_t *) image->imageData,
984                                 input_pix_fmt, image->width, image->height);
985         }
986
987         ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0;
988
989         __END__;
990         return ret;
991 }
992
993 /// close video output stream and free associated memory
994 void CvVideoWriter_FFMPEG::close()
995 {
996         unsigned i;
997
998         // nothing to do if already released
999         if ( !picture )
1000                 return;
1001
1002         /* no more frame to compress. The codec has a latency of a few
1003            frames if using B frames, so we get the last frames by
1004            passing the same picture again */
1005         // TODO -- do we need to account for latency here?
1006
1007         /* write the trailer, if any */
1008         av_write_trailer(oc);
1009
1010         // free pictures
1011 #if LIBAVFORMAT_BUILD > 4628
1012         if( video_st->codec->pix_fmt != input_pix_fmt){
1013 #else
1014         if( video_st->codec.pix_fmt != input_pix_fmt){
1015 #endif
1016                 cvFree(&(picture->data[0]));
1017         }
1018         av_free(picture);
1019
1020     if (input_picture) {
1021         av_free(input_picture);
1022     }
1023
1024         /* close codec */
1025 #if LIBAVFORMAT_BUILD > 4628
1026         avcodec_close(video_st->codec);
1027 #else
1028         avcodec_close(&(video_st->codec));
1029 #endif
1030
1031         av_free(outbuf);
1032
1033         /* free the streams */
1034         for(i = 0; i < oc->nb_streams; i++) {
1035                 av_freep(&oc->streams[i]->codec);
1036                 av_freep(&oc->streams[i]);
1037         }
1038
1039         if (!(fmt->flags & AVFMT_NOFILE)) {
1040                 /* close the output file */
1041
1042
1043 #if LIBAVCODEC_VERSION_INT==((51<<16)+(49<<8)+0)
1044                 url_fclose(oc->pb);
1045 #else
1046                 url_fclose(&oc->pb);
1047 #endif
1048
1049         }
1050
1051         /* free the stream */
1052         av_free(oc);
1053
1054     cvReleaseImage( &temp_image );
1055
1056         init();
1057 }
1058
1059 /// Create a video writer object that uses FFMPEG
1060 bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
1061                 double fps, CvSize frameSize, bool is_color )
1062 {
1063     CV_FUNCNAME("CvVideoWriter_FFMPEG::open");
1064
1065         CodecID codec_id = CODEC_ID_NONE;
1066         int err;
1067
1068         __BEGIN__;
1069
1070     close();
1071
1072         // check arguments
1073         assert (filename);
1074         assert (fps > 0);
1075         assert (frameSize.width > 0  &&  frameSize.height > 0);
1076
1077         // tell FFMPEG to register codecs
1078         av_register_all ();
1079
1080         /* auto detect the output format from the name and fourcc code. */
1081         fmt = guess_format(NULL, filename, NULL);
1082         if (!fmt) {
1083                 CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG does not recognize the given file extension");
1084         }
1085
1086         /* determine optimal pixel format */
1087     if (is_color) {
1088         input_pix_fmt = PIX_FMT_BGR24;
1089     }
1090         else {
1091         input_pix_fmt = PIX_FMT_GRAY8;
1092     }
1093
1094         // alloc memory for context
1095         oc = av_alloc_format_context();
1096         assert (oc);
1097
1098         /* set file name */
1099         oc->oformat = fmt;
1100         snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
1101
1102         /* set some options */
1103         oc->max_delay = (int)(0.7*AV_TIME_BASE);  /* This reduces buffer underrun warnings with MPEG */
1104
1105         /* Lookup codec_id for given fourcc */
1106         if(fourcc!=CV_FOURCC_DEFAULT){
1107 #if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0)
1108         if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ){
1109                         CV_ERROR( CV_StsUnsupportedFormat,
1110                                 "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." );
1111                 }
1112         }
1113 #else
1114         if( (codec_id = av_codec_get_id((const AVCodecTag**)(&codec_bmp_tags), fourcc)) == CODEC_ID_NONE ){
1115                         CV_ERROR( CV_StsUnsupportedFormat,
1116                                 "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." );
1117                 }
1118         }
1119 #endif
1120
1121     // set a few optimal pixel formats for lossless codecs of interest..
1122     int codec_pix_fmt;
1123     switch (codec_id) {
1124 #if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0)
1125     case CODEC_ID_JPEGLS:
1126         // BGR24 or GRAY8 depending on is_color...
1127         codec_pix_fmt = input_pix_fmt;
1128         break;
1129 #endif
1130     case CODEC_ID_FFV1:
1131         // no choice... other supported formats are YUV only
1132         codec_pix_fmt = PIX_FMT_RGBA32;
1133         break;
1134         case CODEC_ID_MJPEG:
1135         case CODEC_ID_LJPEG:
1136                 codec_pix_fmt = PIX_FMT_YUVJ420P;
1137                 break;
1138     case CODEC_ID_RAWVIDEO:
1139     default:
1140         // good for lossy formats, MPEG, etc.
1141         codec_pix_fmt = PIX_FMT_YUV420P;
1142         break;
1143     }
1144
1145         // TODO -- safe to ignore output audio stream?
1146         video_st = icv_add_video_stream_FFMPEG(oc, codec_id,
1147                         frameSize.width, frameSize.height, frameSize.width*frameSize.height*64,
1148             fps, codec_pix_fmt);
1149
1150
1151         /* set the output parameters (must be done even if no
1152        parameters). */
1153     if (av_set_parameters(oc, NULL) < 0) {
1154                 CV_ERROR(CV_StsBadArg, "Invalid output format parameters");
1155     }
1156
1157     dump_format(oc, 0, filename, 1);
1158
1159     /* now that all the parameters are set, we can open the audio and
1160        video codecs and allocate the necessary encode buffers */
1161     if (!video_st){
1162                 CV_ERROR(CV_StsBadArg, "Couldn't open video stream");
1163         }
1164
1165     AVCodec *codec;
1166     AVCodecContext *c;
1167
1168 #if LIBAVFORMAT_BUILD > 4628
1169     c = (video_st->codec);
1170 #else
1171     c = &(video_st->codec);
1172 #endif
1173
1174     c->codec_tag = fourcc;
1175     /* find the video encoder */
1176     codec = avcodec_find_encoder(c->codec_id);
1177     if (!codec) {
1178                 CV_ERROR(CV_StsBadArg, "codec not found");
1179     }
1180
1181     /* open the codec */
1182     if ( (err=avcodec_open(c, codec)) < 0) {
1183                 char errtext[256];
1184                 sprintf(errtext, "Could not open codec '%s': %s", codec->name, icvFFMPEGErrStr(err));
1185                 CV_ERROR(CV_StsBadArg, errtext);
1186     }
1187
1188     outbuf = NULL;
1189
1190     if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
1191         /* allocate output buffer */
1192                 /* assume we will never get codec output with more than 4 bytes per pixel... */
1193                 outbuf_size = frameSize.width*frameSize.height*4;
1194         outbuf = (uint8_t *) av_malloc(outbuf_size);
1195     }
1196
1197         bool need_color_convert;
1198         need_color_convert = (c->pix_fmt != input_pix_fmt);
1199
1200     /* allocate the encoded raw picture */
1201     picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert);
1202     if (!picture) {
1203                 CV_ERROR(CV_StsNoMem, "Could not allocate picture");
1204     }
1205
1206     /* if the output format is not our input format, then a temporary
1207        picture of the input format is needed too. It is then converted
1208            to the required output format */
1209         input_picture = NULL;
1210     if ( need_color_convert ) {
1211         input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, c->width, c->height, false);
1212         if (!input_picture) {
1213                         CV_ERROR(CV_StsNoMem, "Could not allocate picture");
1214         }
1215     }
1216
1217         /* open the output file, if needed */
1218     if (!(fmt->flags & AVFMT_NOFILE)) {
1219         if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) {
1220                         CV_ERROR(CV_StsBadArg, "Couldn't open output file for writing");
1221         }
1222     }
1223
1224     /* write the stream header, if any */
1225     av_write_header( oc );
1226
1227
1228         __END__;
1229
1230         return true;
1231 }
1232
1233 CvVideoWriter* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,
1234                                            CvSize frameSize, int isColor )
1235 {
1236     CvVideoWriter_FFMPEG* writer = new CvVideoWriter_FFMPEG;
1237     if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 ))
1238         return writer;
1239     delete writer;
1240     return 0;
1241 }