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