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