Update to 2.0.0 tree from current Fremantle build
[opencv] / src / highgui / cvcap_ffmpeg.cpp
diff --git a/src/highgui/cvcap_ffmpeg.cpp b/src/highgui/cvcap_ffmpeg.cpp
new file mode 100644 (file)
index 0000000..63d4391
--- /dev/null
@@ -0,0 +1,1358 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "_highgui.h"
+
+#if defined _MSC_VER && _MSC_VER >= 1200
+#pragma warning( disable: 4244 4510 4512 4610 )
+#endif
+
+extern "C" {
+#if !defined(WIN32) || defined(__MINGW32__)
+// some versions of FFMPEG assume a C99 compiler, and don't define INT64_C
+#ifndef INT64_C
+#define INT64_C
+#define __STDC_CONSTANT_MACROS
+// force re-inclusion of stdint.h to get INT64_C macro
+#undef _STDINT_H
+#include <stdint.h>
+#endif
+#include <errno.h>
+#endif
+
+#ifdef WIN32
+  #include <ffmpeg_/avformat.h>
+  #include <ffmpeg_/avcodec.h>
+  #include <ffmpeg_/imgconvert.h>
+#else
+
+// if the header path is not specified explicitly, let's deduce it
+#if !defined HAVE_FFMPEG_AVCODEC_H && !defined HAVE_LIBAVCODEC_AVCODEC_H
+
+#if defined(HAVE_GENTOO_FFMPEG)
+  #define HAVE_LIBAVCODEC_AVCODEC_H 1
+  #define HAVE_LIBAVFORMAT_AVFORMAT_H 1
+  #if defined(HAVE_FFMPEG_SWSCALE)
+    #define HAVE_LIBSWSCALE_SWSCALE_H 1
+  #endif
+#elif defined HAVE_FFMPEG
+  #define HAVE_FFMPEG_AVCODEC_H 1
+  #define HAVE_FFMPEG_AVFORMAT_H 1
+  #if defined(HAVE_FFMPEG_SWSCALE)
+    #define HAVE_FFMPEG_SWSCALE_H 1
+  #endif
+#endif
+
+#endif
+
+#if defined(HAVE_FFMPEG_AVCODEC_H)
+  #include <ffmpeg/avcodec.h>
+#endif
+#if defined(HAVE_FFMPEG_AVFORMAT_H)
+  #include <ffmpeg/avformat.h>
+#endif
+#if defined(HAVE_FFMPEG_SWSCALE_H)
+  #include <ffmpeg/swscale.h>
+#endif
+
+#if defined(HAVE_LIBAVFORMAT_AVFORMAT_H)
+  #include <libavformat/avformat.h>
+#endif
+#if defined(HAVE_LIBAVCODEC_AVCODEC_H)
+  #include <libavcodec/avcodec.h>
+#endif
+#if defined(HAVE_LIBSWSCALE_SWSCALE_H)
+  #include <libswscale/swscale.h>
+#endif
+
+#endif
+
+}
+
+#if defined _MSC_VER && _MSC_VER >= 1200
+#pragma warning( default: 4244 4510 4512 4610 )
+#endif
+
+#ifdef NDEBUG
+#define CV_WARN(message)
+#else
+#define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
+#endif
+
+
+#ifndef MKTAG
+#define MKTAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))
+#endif
+
+/* PIX_FMT_RGBA32 macro changed in newer ffmpeg versions */
+#ifndef PIX_FMT_RGBA32
+#define PIX_FMT_RGBA32 PIX_FMT_RGB32
+#endif
+
+
+
+char * FOURCC2str( int fourcc )
+{
+    char * mystr=(char*)malloc(5);
+    mystr[0]=(char)((fourcc    )&255);
+    mystr[1]=(char)((fourcc>> 8)&255);
+    mystr[2]=(char)((fourcc>>16)&255);
+    mystr[3]=(char)((fourcc>>24)&255);
+    mystr[4]=0;
+    return mystr;
+}
+
+
+// required to look up the correct codec ID depending on the FOURCC code,
+// this is just a snipped from the file riff.c from ffmpeg/libavformat
+typedef struct AVCodecTag {
+    int id;
+    unsigned int tag;
+} AVCodecTag;
+
+const AVCodecTag codec_bmp_tags[] = {
+    { CODEC_ID_H264, MKTAG('H', '2', '6', '4') },
+    { CODEC_ID_H264, MKTAG('h', '2', '6', '4') },
+    { CODEC_ID_H264, MKTAG('X', '2', '6', '4') },
+    { CODEC_ID_H264, MKTAG('x', '2', '6', '4') },
+    { CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
+    { CODEC_ID_H264, MKTAG('V', 'S', 'S', 'H') },
+
+    { CODEC_ID_H263, MKTAG('H', '2', '6', '3') },
+    { CODEC_ID_H263P, MKTAG('H', '2', '6', '3') },
+    { CODEC_ID_H263I, MKTAG('I', '2', '6', '3') }, /* intel h263 */
+    { CODEC_ID_H261, MKTAG('H', '2', '6', '1') },
+
+    /* added based on MPlayer */
+    { CODEC_ID_H263P, MKTAG('U', '2', '6', '3') },
+    { CODEC_ID_H263P, MKTAG('v', 'i', 'v', '1') },
+
+    { CODEC_ID_MPEG4, MKTAG('F', 'M', 'P', '4') },
+    { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', 'X') },
+    { CODEC_ID_MPEG4, MKTAG('D', 'X', '5', '0') },
+    { CODEC_ID_MPEG4, MKTAG('X', 'V', 'I', 'D') },
+    { CODEC_ID_MPEG4, MKTAG('M', 'P', '4', 'S') },
+    { CODEC_ID_MPEG4, MKTAG('M', '4', 'S', '2') },
+    { CODEC_ID_MPEG4, MKTAG(0x04, 0, 0, 0) }, /* some broken avi use this */
+
+    /* added based on MPlayer */
+    { CODEC_ID_MPEG4, MKTAG('D', 'I', 'V', '1') },
+    { CODEC_ID_MPEG4, MKTAG('B', 'L', 'Z', '0') },
+    { CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
+    { CODEC_ID_MPEG4, MKTAG('U', 'M', 'P', '4') },
+    { CODEC_ID_MPEG4, MKTAG('W', 'V', '1', 'F') },
+    { CODEC_ID_MPEG4, MKTAG('S', 'E', 'D', 'G') },
+
+    { CODEC_ID_MPEG4, MKTAG('R', 'M', 'P', '4') },
+
+    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '3') }, /* default signature when using MSMPEG4 */
+    { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', '4', '3') },
+
+    /* added based on MPlayer */
+    { CODEC_ID_MSMPEG4V3, MKTAG('M', 'P', 'G', '3') },
+    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '5') },
+    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '6') },
+    { CODEC_ID_MSMPEG4V3, MKTAG('D', 'I', 'V', '4') },
+    { CODEC_ID_MSMPEG4V3, MKTAG('A', 'P', '4', '1') },
+    { CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '1') },
+    { CODEC_ID_MSMPEG4V3, MKTAG('C', 'O', 'L', '0') },
+
+    { CODEC_ID_MSMPEG4V2, MKTAG('M', 'P', '4', '2') },
+
+    /* added based on MPlayer */
+    { CODEC_ID_MSMPEG4V2, MKTAG('D', 'I', 'V', '2') },
+
+    { CODEC_ID_MSMPEG4V1, MKTAG('M', 'P', 'G', '4') },
+
+    { CODEC_ID_WMV1, MKTAG('W', 'M', 'V', '1') },
+
+    /* added based on MPlayer */
+    { CODEC_ID_WMV2, MKTAG('W', 'M', 'V', '2') },
+    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'd') },
+    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 'h', 'd') },
+    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', 's', 'l') },
+    { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '2', '5') },
+    { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '1') },
+    { CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', 'g', '2') },
+    { CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', 'g', '2') },
+    { CODEC_ID_MPEG2VIDEO, MKTAG('M', 'P', 'E', 'G') },
+    { CODEC_ID_MPEG1VIDEO, MKTAG('P', 'I', 'M', '1') },
+    { CODEC_ID_MPEG1VIDEO, MKTAG('V', 'C', 'R', '2') },
+    { CODEC_ID_MPEG1VIDEO, 0x10000001 },
+    { CODEC_ID_MPEG2VIDEO, 0x10000002 },
+    { CODEC_ID_MPEG2VIDEO, MKTAG('D', 'V', 'R', ' ') },
+    { CODEC_ID_MPEG2VIDEO, MKTAG('M', 'M', 'E', 'S') },
+    { CODEC_ID_MJPEG, MKTAG('M', 'J', 'P', 'G') },
+    { CODEC_ID_MJPEG, MKTAG('L', 'J', 'P', 'G') },
+    { CODEC_ID_LJPEG, MKTAG('L', 'J', 'P', 'G') },
+    { CODEC_ID_MJPEG, MKTAG('J', 'P', 'G', 'L') }, /* Pegasus lossless JPEG */
+    { CODEC_ID_MJPEG, MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - decoder */
+    { CODEC_ID_MJPEG, MKTAG('j', 'p', 'e', 'g') },
+    { CODEC_ID_MJPEG, MKTAG('I', 'J', 'P', 'G') },
+    { CODEC_ID_MJPEG, MKTAG('A', 'V', 'R', 'n') },
+    { CODEC_ID_HUFFYUV, MKTAG('H', 'F', 'Y', 'U') },
+    { CODEC_ID_FFVHUFF, MKTAG('F', 'F', 'V', 'H') },
+    { CODEC_ID_CYUV, MKTAG('C', 'Y', 'U', 'V') },
+    { CODEC_ID_RAWVIDEO, 0 },
+    { CODEC_ID_RAWVIDEO, MKTAG('I', '4', '2', '0') },
+    { CODEC_ID_RAWVIDEO, MKTAG('Y', 'U', 'Y', '2') },
+    { CODEC_ID_RAWVIDEO, MKTAG('Y', '4', '2', '2') },
+    { CODEC_ID_RAWVIDEO, MKTAG('Y', 'V', '1', '2') },
+    { CODEC_ID_RAWVIDEO, MKTAG('U', 'Y', 'V', 'Y') },
+    { CODEC_ID_RAWVIDEO, MKTAG('I', 'Y', 'U', 'V') },
+    { CODEC_ID_RAWVIDEO, MKTAG('Y', '8', '0', '0') },
+    { CODEC_ID_RAWVIDEO, MKTAG('H', 'D', 'Y', 'C') },
+    { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '1') },
+    { CODEC_ID_INDEO3, MKTAG('I', 'V', '3', '2') },
+    { CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') },
+    { CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') },
+    { CODEC_ID_ASV1, MKTAG('A', 'S', 'V', '1') },
+    { CODEC_ID_ASV2, MKTAG('A', 'S', 'V', '2') },
+    { CODEC_ID_VCR1, MKTAG('V', 'C', 'R', '1') },
+    { CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
+    { CODEC_ID_XAN_WC4, MKTAG('X', 'x', 'a', 'n') },
+    { CODEC_ID_MSRLE, MKTAG('m', 'r', 'l', 'e') },
+    { CODEC_ID_MSRLE, MKTAG(0x1, 0x0, 0x0, 0x0) },
+    { CODEC_ID_MSVIDEO1, MKTAG('M', 'S', 'V', 'C') },
+    { CODEC_ID_MSVIDEO1, MKTAG('m', 's', 'v', 'c') },
+    { CODEC_ID_MSVIDEO1, MKTAG('C', 'R', 'A', 'M') },
+    { CODEC_ID_MSVIDEO1, MKTAG('c', 'r', 'a', 'm') },
+    { CODEC_ID_MSVIDEO1, MKTAG('W', 'H', 'A', 'M') },
+    { CODEC_ID_MSVIDEO1, MKTAG('w', 'h', 'a', 'm') },
+    { CODEC_ID_CINEPAK, MKTAG('c', 'v', 'i', 'd') },
+    { CODEC_ID_TRUEMOTION1, MKTAG('D', 'U', 'C', 'K') },
+    { CODEC_ID_MSZH, MKTAG('M', 'S', 'Z', 'H') },
+    { CODEC_ID_ZLIB, MKTAG('Z', 'L', 'I', 'B') },
+    { CODEC_ID_SNOW, MKTAG('S', 'N', 'O', 'W') },
+    { CODEC_ID_4XM, MKTAG('4', 'X', 'M', 'V') },
+    { CODEC_ID_FLV1, MKTAG('F', 'L', 'V', '1') },
+    { CODEC_ID_SVQ1, MKTAG('s', 'v', 'q', '1') },
+    { CODEC_ID_TSCC, MKTAG('t', 's', 'c', 'c') },
+    { CODEC_ID_ULTI, MKTAG('U', 'L', 'T', 'I') },
+    { CODEC_ID_VIXL, MKTAG('V', 'I', 'X', 'L') },
+    { CODEC_ID_QPEG, MKTAG('Q', 'P', 'E', 'G') },
+    { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '0') },
+    { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '1') },
+    { CODEC_ID_WMV3, MKTAG('W', 'M', 'V', '3') },
+    { CODEC_ID_LOCO, MKTAG('L', 'O', 'C', 'O') },
+    { CODEC_ID_THEORA, MKTAG('t', 'h', 'e', 'o') },
+#if LIBAVCODEC_VERSION_INT>0x000409
+    { CODEC_ID_WNV1, MKTAG('W', 'N', 'V', '1') },
+    { CODEC_ID_AASC, MKTAG('A', 'A', 'S', 'C') },
+    { CODEC_ID_INDEO2, MKTAG('R', 'T', '2', '1') },
+    { CODEC_ID_FRAPS, MKTAG('F', 'P', 'S', '1') },
+    { CODEC_ID_TRUEMOTION2, MKTAG('T', 'M', '2', '0') },
+#endif
+#if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0)
+    { CODEC_ID_FLASHSV, MKTAG('F', 'S', 'V', '1') },
+    { CODEC_ID_JPEGLS,MKTAG('M', 'J', 'L', 'S') }, /* JPEG-LS custom FOURCC for avi - encoder */
+    { CODEC_ID_VC1, MKTAG('W', 'V', 'C', '1') },
+    { CODEC_ID_VC1, MKTAG('W', 'M', 'V', 'A') },
+    { CODEC_ID_CSCD, MKTAG('C', 'S', 'C', 'D') },
+    { CODEC_ID_ZMBV, MKTAG('Z', 'M', 'B', 'V') },
+    { CODEC_ID_KMVC, MKTAG('K', 'M', 'V', 'C') },
+#endif
+#if LIBAVCODEC_VERSION_INT>((51<<16)+(11<<8)+0)
+    { CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') },
+    { CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') },
+    { CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') },
+    { CODEC_ID_VP6, MKTAG('V', 'P', '6', '2') },
+    { CODEC_ID_VP6F, MKTAG('V', 'P', '6', 'F') },
+    { CODEC_ID_JPEG2000, MKTAG('M', 'J', '2', 'C') },
+    { CODEC_ID_VMNC, MKTAG('V', 'M', 'n', 'c') },
+#endif
+#if LIBAVCODEC_VERSION_INT>=((51<<16)+(49<<8)+0)
+// this tag seems not to exist in older versions of FFMPEG
+    { CODEC_ID_TARGA, MKTAG('t', 'g', 'a', ' ') },
+#endif
+    { CODEC_ID_NONE, 0 },
+};
+
+
+class CvCapture_FFMPEG : public CvCapture
+{
+public:
+    CvCapture_FFMPEG() { init(); }
+    virtual ~CvCapture_FFMPEG() { close(); }
+
+    virtual bool open( const char* filename );
+    virtual void close();
+
+    virtual double getProperty(int);
+    virtual bool setProperty(int, double);
+    virtual bool grabFrame();
+    virtual IplImage* retrieveFrame(int);
+
+protected:
+    void init();
+    bool reopen();
+    bool slowSeek( int framenumber );
+
+    AVFormatContext   * ic;
+    int                 video_stream;
+    AVStream          * video_st;
+    AVFrame           * picture;
+    int64_t             picture_pts;
+    AVFrame             rgb_picture;
+    AVPacket            packet;
+    IplImage            frame;
+#if defined(HAVE_FFMPEG_SWSCALE)
+    struct SwsContext *img_convert_ctx;
+#endif
+/*
+   'filename' contains the filename of the videosource,
+   'filename==NULL' indicates that ffmpeg's seek support works
+   for the particular file.
+   'filename!=NULL' indicates that the slow fallback function is used for seeking,
+   and so the filename is needed to reopen the file on backward seeking.
+*/
+    char              * filename;
+};
+
+
+void CvCapture_FFMPEG::init()
+{
+    ic = 0;
+    video_stream = -1;
+    video_st = 0;
+    picture = 0;
+    picture_pts = 0;
+    memset( &rgb_picture, 0, sizeof(rgb_picture) );
+    memset( &frame, 0, sizeof(frame) );
+    filename = 0;
+    packet.data = NULL;
+#if defined(HAVE_FFMPEG_SWSCALE)
+    img_convert_ctx = 0;
+#endif    
+}
+
+
+void CvCapture_FFMPEG::close()
+{
+    if( picture )
+    av_free(picture);
+
+    if( video_st )
+    {
+#if LIBAVFORMAT_BUILD > 4628
+        avcodec_close( video_st->codec );
+#else
+        avcodec_close( &video_st->codec );
+#endif
+        video_st = NULL;
+    }
+
+    if( ic )
+    {
+        av_close_input_file(ic);
+        ic = NULL;
+    }
+
+    if( rgb_picture.data[0] )
+        cvFree( &rgb_picture.data[0] );
+
+    // free last packet if exist
+    if (packet.data) {
+        av_free_packet (&packet);
+    }
+
+
+    init();
+}
+
+
+/*
+    Used to reopen a video if the slower fallback function for seeking is used.
+*/
+bool CvCapture_FFMPEG::reopen()
+{
+    if ( filename==NULL ) return false;
+
+#if LIBAVFORMAT_BUILD > 4628
+    avcodec_close( video_st->codec );
+#else
+    avcodec_close( &video_st->codec );
+#endif
+    av_close_input_file(ic);
+
+    // reopen video
+    av_open_input_file(&ic, filename, NULL, 0, NULL);
+    av_find_stream_info(ic);
+#if LIBAVFORMAT_BUILD > 4628
+    AVCodecContext *enc = ic->streams[video_stream]->codec;
+#else
+    AVCodecContext *enc = &ic->streams[video_stream]->codec;
+#endif
+    AVCodec *codec = avcodec_find_decoder(enc->codec_id);
+    avcodec_open(enc, codec);
+    video_st = ic->streams[video_stream];
+
+    // reset framenumber to zero
+    picture_pts=0;
+
+    return true;
+}
+
+
+
+bool CvCapture_FFMPEG::open( const char* _filename )
+{
+    unsigned i;
+    bool valid = false;
+
+    close();
+
+    /* register all codecs, demux and protocols */
+    av_register_all();
+
+#ifndef _DEBUG
+    // av_log_level = AV_LOG_QUIET;
+#endif
+
+    int err = av_open_input_file(&ic, _filename, NULL, 0, NULL);
+    if (err < 0) {
+           CV_WARN("Error opening file");
+           goto exit_func;
+    }
+    err = av_find_stream_info(ic);
+    if (err < 0) {
+           CV_WARN("Could not find codec parameters");
+           goto exit_func;
+    }
+    for(i = 0; i < ic->nb_streams; i++) {
+#if LIBAVFORMAT_BUILD > 4628
+        AVCodecContext *enc = ic->streams[i]->codec;
+#else
+        AVCodecContext *enc = &ic->streams[i]->codec;
+#endif
+
+        if( CODEC_TYPE_VIDEO == enc->codec_type && video_stream < 0) {
+            AVCodec *codec = avcodec_find_decoder(enc->codec_id);
+            if (!codec ||
+            avcodec_open(enc, codec) < 0)
+            goto exit_func;
+            video_stream = i;
+            video_st = ic->streams[i];
+            picture = avcodec_alloc_frame();
+
+            rgb_picture.data[0] = (uint8_t*)cvAlloc(
+                                    avpicture_get_size( PIX_FMT_BGR24,
+                                    enc->width, enc->height ));
+            avpicture_fill( (AVPicture*)&rgb_picture, rgb_picture.data[0],
+                    PIX_FMT_BGR24, enc->width, enc->height );
+
+            cvInitImageHeader( &frame, cvSize( enc->width,
+                                       enc->height ), 8, 3, 0, 4 );
+            cvSetData( &frame, rgb_picture.data[0],
+                               rgb_picture.linesize[0] );
+            break;
+        }
+    }
+
+    if(video_stream >= 0) valid = true;
+
+    // perform check if source is seekable via ffmpeg's seek function av_seek_frame(...)
+    err = av_seek_frame(ic, video_stream, 10, 0);
+    if (err < 0)
+    {
+        filename=(char*)malloc(strlen(_filename)+1);
+        strcpy(filename, _filename);
+        // reopen videofile to 'seek' back to first frame
+        reopen();
+    }
+    else
+    {
+        // seek seems to work, so we don't need the filename,
+        // but we still need to seek back to filestart
+        filename=NULL;
+        av_seek_frame(ic, video_stream, 0, 0);
+    }
+exit_func:
+
+    if( !valid )
+        close();
+
+    return valid;
+}
+
+
+bool CvCapture_FFMPEG::grabFrame()
+{
+    bool valid = false;
+    static bool bFirstTime = true;
+    int got_picture;
+
+    // First time we're called, set packet.data to NULL to indicate it
+    // doesn't have to be freed
+    if (bFirstTime) {
+        bFirstTime = false;
+        packet.data = NULL;
+    }
+
+    if( !ic || !video_st )
+        return false;
+
+    // free last packet if exist
+    if (packet.data != NULL) {
+        av_free_packet (&packet);
+    }
+
+    // get the next frame
+    while (!valid && (av_read_frame(ic, &packet) >= 0)) {
+               if( packet.stream_index != video_stream ) {
+                       av_free_packet (&packet);
+                       continue;
+               }
+
+#if LIBAVFORMAT_BUILD > 4628
+        avcodec_decode_video(video_st->codec,
+                             picture, &got_picture,
+                             packet.data, packet.size);
+#else
+        avcodec_decode_video(&video_st->codec,
+                             picture, &got_picture,
+                             packet.data, packet.size);
+#endif
+
+        if (got_picture) {
+            // we have a new picture, so memorize it
+            picture_pts = packet.pts;
+            valid = 1;
+        }
+    }
+
+    // return if we have a new picture or not
+    return valid;
+}
+
+
+IplImage* CvCapture_FFMPEG::retrieveFrame(int)
+{
+    if( !video_st || !picture->data[0] )
+        return 0;
+
+#if !defined(HAVE_FFMPEG_SWSCALE)
+#if LIBAVFORMAT_BUILD > 4628
+    img_convert( (AVPicture*)&rgb_picture, PIX_FMT_BGR24,
+                 (AVPicture*)picture,
+                 video_st->codec->pix_fmt,
+                 video_st->codec->width,
+                 video_st->codec->height );
+#else
+    img_convert( (AVPicture*)&rgb_picture, PIX_FMT_BGR24,
+                 (AVPicture*)picture,
+                 video_st->codec.pix_fmt,
+                 video_st->codec.width,
+                 video_st->codec.height );
+#endif
+#else
+    img_convert_ctx = sws_getContext(video_st->codec->width,
+                  video_st->codec->height,
+                  video_st->codec->pix_fmt,
+                  video_st->codec->width,
+                  video_st->codec->height,
+                  PIX_FMT_BGR24,
+                  SWS_BICUBIC,
+                  NULL, NULL, NULL);
+
+         sws_scale(img_convert_ctx, picture->data,
+             picture->linesize, 0,
+             video_st->codec->height,
+             rgb_picture.data, rgb_picture.linesize);
+    sws_freeContext(img_convert_ctx);
+#endif
+    return &frame;
+}
+
+#if defined(__APPLE__)
+#define AV_NOPTS_VALUE_ ((int64_t)0x8000000000000000LL)
+#else
+#define AV_NOPTS_VALUE_ ((int64_t)AV_NOPTS_VALUE)
+#endif
+
+double CvCapture_FFMPEG::getProperty( int property_id )
+{
+    // if( !capture || !video_st || !picture->data[0] ) return 0;
+    if( !video_st ) return 0;
+
+
+    int64_t timestamp;
+    timestamp = picture_pts;
+
+    switch( property_id )
+    {
+    case CV_CAP_PROP_POS_MSEC:
+        if(video_st->cur_dts != AV_NOPTS_VALUE_)
+            return (((double)video_st->cur_dts-1) *1000) / av_q2d (video_st->r_frame_rate);
+        break;
+    case CV_CAP_PROP_POS_FRAMES:
+        if(video_st->cur_dts != AV_NOPTS_VALUE_)
+            return (double)video_st->cur_dts-1;
+        break;
+    case CV_CAP_PROP_POS_AVI_RATIO:
+        if(video_st->cur_dts != AV_NOPTS_VALUE_ && video_st->duration != AV_NOPTS_VALUE_)
+            return (double)(video_st->cur_dts-1)/(double)video_st->duration;
+        break;
+       case CV_CAP_PROP_FRAME_COUNT:
+           if(video_st->duration != AV_NOPTS_VALUE_)
+                   return (double)video_st->duration;
+           break;
+    case CV_CAP_PROP_FRAME_WIDTH:
+        return (double)frame.width;
+    case CV_CAP_PROP_FRAME_HEIGHT:
+        return (double)frame.height;
+    case CV_CAP_PROP_FPS:
+#if LIBAVCODEC_BUILD > 4753
+        return av_q2d (video_st->r_frame_rate);
+#else
+        return (double)video_st->codec.frame_rate
+            / (double)video_st->codec.frame_rate_base;
+#endif
+    case CV_CAP_PROP_FOURCC:
+#if LIBAVFORMAT_BUILD > 4628
+        return (double)video_st->codec->codec_tag;
+#else
+        return (double)video_st->codec.codec_tag;
+#endif
+    }
+    return 0;
+}
+
+
+
+// this is a VERY slow fallback function, ONLY used if ffmpeg's av_seek_frame delivers no correct result!
+bool CvCapture_FFMPEG::slowSeek( int framenumber )
+{
+    if ( framenumber>picture_pts )
+    {
+        while ( picture_pts<framenumber )
+            if ( !grabFrame() ) return false;
+    }
+    else if ( framenumber<picture_pts )
+    {
+        reopen();
+        while ( picture_pts<framenumber )
+            if ( !grabFrame() ) return false;
+    }
+    return true;
+}
+
+
+bool CvCapture_FFMPEG::setProperty( int property_id, double value )
+{
+    if( !video_st ) return false;
+
+    switch( property_id )
+    {
+    case CV_CAP_PROP_POS_MSEC:
+    case CV_CAP_PROP_POS_FRAMES:
+    case CV_CAP_PROP_POS_AVI_RATIO:
+        {
+            int64_t timestamp = 0;
+            AVRational time_base;
+            switch( property_id )
+            {
+            case CV_CAP_PROP_POS_FRAMES:
+                timestamp=(int64_t)value;
+                if(ic->start_time != AV_NOPTS_VALUE_)
+                    timestamp += ic->start_time;
+                break;
+
+            case CV_CAP_PROP_POS_MSEC:
+                time_base=ic->streams[video_stream]->time_base;
+                timestamp=(int64_t)(value*(float(time_base.den)/float(time_base.num))/1000);
+                if(ic->start_time != AV_NOPTS_VALUE_)
+                    timestamp += ic->start_time;
+                break;
+
+            case CV_CAP_PROP_POS_AVI_RATIO:
+                timestamp=(int64_t)(value*ic->duration);
+                if(ic->start_time != AV_NOPTS_VALUE_ && ic->duration != AV_NOPTS_VALUE_)
+                    timestamp += ic->start_time;
+                break;
+            }
+
+            if ( filename )
+            {
+                // ffmpeg's seek doesn't work...
+                if (!slowSeek((int)timestamp))
+                {
+                    fprintf(stderr, "HIGHGUI ERROR: AVI: could not (slow) seek to position %0.3f\n",
+                        (double)timestamp / AV_TIME_BASE);
+                    return false;
+                }
+            }
+            else
+            {
+                int ret = av_seek_frame(ic, video_stream, timestamp, 0);
+                if (ret < 0)
+                {
+                    fprintf(stderr, "HIGHGUI ERROR: AVI: could not seek to position %0.3f\n",
+                            (double)timestamp / AV_TIME_BASE);
+                    return false;
+                }
+            }
+            picture_pts=(int64_t)value;
+        }
+        break;
+
+    default:
+        return false;
+    }
+
+    return true;
+}
+
+
+
+CvCapture* cvCreateFileCapture_FFMPEG( const char* filename )
+{
+    CvCapture_FFMPEG* capture = new CvCapture_FFMPEG;
+    if( capture->open( filename ))
+        return capture;
+    delete capture;
+    return 0;
+}
+
+
+///////////////// FFMPEG CvVideoWriter implementation //////////////////////////
+class CvVideoWriter_FFMPEG : public CvVideoWriter
+{
+public:
+    CvVideoWriter_FFMPEG() { init(); }
+    virtual ~CvVideoWriter_FFMPEG() { close(); }
+
+    virtual bool open( const char* filename, int fourcc,
+        double fps, CvSize frameSize, bool isColor );
+    virtual void close();
+    virtual bool writeFrame( const IplImage* image );
+
+protected:
+    void init();
+
+    AVOutputFormat *fmt;
+    AVFormatContext *oc;
+    uint8_t         * outbuf;
+    uint32_t          outbuf_size;
+    FILE            * outfile;
+    AVFrame         * picture;
+    AVFrame         * input_picture;
+    uint8_t         * picbuf;
+    AVStream        * video_st;
+    int               input_pix_fmt;
+    IplImage        * temp_image;
+#if defined(HAVE_FFMPEG_SWSCALE)
+    struct SwsContext *img_convert_ctx;
+#endif
+};
+
+static const char * icvFFMPEGErrStr(int err)
+{
+    switch(err) {
+    case AVERROR_NUMEXPECTED:
+               return "Incorrect filename syntax";
+    case AVERROR_INVALIDDATA:
+               return "Invalid data in header";
+    case AVERROR_NOFMT:
+               return "Unknown format";
+    case AVERROR_IO:
+               return "I/O error occurred";
+    case AVERROR_NOMEM:
+               return "Memory allocation error";
+    default:
+               break;
+    }
+       return "Unspecified error";
+}
+
+/* function internal to FFMPEG (libavformat/riff.c) to lookup codec id by fourcc tag*/
+extern "C" {
+       enum CodecID codec_get_bmp_id(unsigned int tag);
+}
+
+void CvVideoWriter_FFMPEG::init()
+{
+    fmt = 0;
+    oc = 0;
+    outbuf = 0;
+    outbuf_size = 0;
+    outfile = 0;
+    picture = 0;
+    input_picture = 0;
+    picbuf = 0;
+    video_st = 0;
+    input_pix_fmt = 0;
+    temp_image = 0;
+#if defined(HAVE_FFMPEG_SWSCALE)
+    img_convert_ctx = 0;
+#endif    
+}
+
+/**
+ * the following function is a modified version of code
+ * found in ffmpeg-0.4.9-pre1/output_example.c
+ */
+static AVFrame * icv_alloc_picture_FFMPEG(int pix_fmt, int width, int height, bool alloc)
+{
+       AVFrame * picture;
+       uint8_t * picture_buf;
+       int size;
+
+       picture = avcodec_alloc_frame();
+       if (!picture)
+               return NULL;
+       size = avpicture_get_size( (PixelFormat) pix_fmt, width, height);
+       if(alloc){
+               picture_buf = (uint8_t *) cvAlloc(size);
+               if (!picture_buf)
+               {
+                       av_free(picture);
+                       return NULL;
+               }
+               avpicture_fill((AVPicture *)picture, picture_buf,
+                               (PixelFormat) pix_fmt, width, height);
+       }
+       else {
+       }
+       return picture;
+}
+
+/* add a video output stream to the container */
+static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
+                                                    CodecID codec_id,
+                                                                                        int w, int h, int bitrate,
+                                                                                        double fps, int pixel_format)
+{
+       AVCodecContext *c;
+       AVStream *st;
+       int frame_rate, frame_rate_base;
+       AVCodec *codec;
+
+
+       st = av_new_stream(oc, 0);
+       if (!st) {
+               CV_WARN("Could not allocate stream");
+               return NULL;
+       }
+
+#if LIBAVFORMAT_BUILD > 4628
+       c = st->codec;
+#else
+       c = &(st->codec);
+#endif
+
+#if LIBAVFORMAT_BUILD > 4621
+       c->codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, CODEC_TYPE_VIDEO);
+#else
+       c->codec_id = oc->oformat->video_codec;
+#endif
+
+       if(codec_id != CODEC_ID_NONE){
+               c->codec_id = codec_id;
+       }
+
+    //if(codec_tag) c->codec_tag=codec_tag;
+       codec = avcodec_find_encoder(c->codec_id);
+
+       c->codec_type = CODEC_TYPE_VIDEO;
+
+       /* put sample parameters */
+       c->bit_rate = bitrate;
+
+       /* resolution must be a multiple of two */
+       c->width = w;
+       c->height = h;
+
+       /* time base: this is the fundamental unit of time (in seconds) in terms
+       of which frame timestamps are represented. for fixed-fps content,
+       timebase should be 1/framerate and timestamp increments should be
+       identically 1. */
+       frame_rate=cvRound(fps);
+       frame_rate_base=1;
+       while (fabs((double)frame_rate/frame_rate_base) - fps > 0.001){
+               frame_rate_base*=10;
+               frame_rate=cvRound(fps*frame_rate_base);
+       }
+#if LIBAVFORMAT_BUILD > 4752
+    c->time_base.den = frame_rate;
+    c->time_base.num = frame_rate_base;
+       /* adjust time base for supported framerates */
+       if(codec && codec->supported_framerates){
+               const AVRational *p= codec->supported_framerates;
+        AVRational req = {frame_rate, frame_rate_base};
+               const AVRational *best=NULL;
+               AVRational best_error= {INT_MAX, 1};
+               for(; p->den!=0; p++){
+                       AVRational error= av_sub_q(req, *p);
+                       if(error.num <0) error.num *= -1;
+                       if(av_cmp_q(error, best_error) < 0){
+                               best_error= error;
+                               best= p;
+                       }
+               }
+               c->time_base.den= best->num;
+               c->time_base.num= best->den;
+       }
+#else
+       c->frame_rate = frame_rate;
+       c->frame_rate_base = frame_rate_base;
+#endif
+
+       c->gop_size = 12; /* emit one intra frame every twelve frames at most */
+       c->pix_fmt = (PixelFormat) pixel_format;
+
+       if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
+        c->max_b_frames = 2;
+    }
+    if (c->codec_id == CODEC_ID_MPEG1VIDEO || c->codec_id == CODEC_ID_MSMPEG4V3){
+        /* needed to avoid using macroblocks in which some coeffs overflow
+           this doesnt happen with normal video, it just happens here as the
+           motion of the chroma plane doesnt match the luma plane */
+               /* avoid FFMPEG warning 'clipping 1 dct coefficients...' */
+        c->mb_decision=2;
+    }
+#if LIBAVCODEC_VERSION_INT>0x000409
+    // some formats want stream headers to be seperate
+    if(oc->oformat->flags & AVFMT_GLOBALHEADER)
+    {
+        c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+    }
+#endif
+
+    return st;
+}
+
+int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, uint8_t * outbuf, uint32_t outbuf_size, AVFrame * picture ){
+       CV_FUNCNAME("icv_av_write_frame_FFMPEG");
+
+#if LIBAVFORMAT_BUILD > 4628
+       AVCodecContext * c = video_st->codec;
+#else
+       AVCodecContext * c = &(video_st->codec);
+#endif
+       int out_size;
+       int ret;
+
+       __BEGIN__;
+
+    if (oc->oformat->flags & AVFMT_RAWPICTURE) {
+        /* raw video case. The API will change slightly in the near
+           futur for that */
+        AVPacket pkt;
+        av_init_packet(&pkt);
+
+        pkt.flags |= PKT_FLAG_KEY;
+        pkt.stream_index= video_st->index;
+        pkt.data= (uint8_t *)picture;
+        pkt.size= sizeof(AVPicture);
+
+        ret = av_write_frame(oc, &pkt);
+    } else {
+        /* encode the image */
+        out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);
+        /* if zero size, it means the image was buffered */
+        if (out_size > 0) {
+            AVPacket pkt;
+            av_init_packet(&pkt);
+
+#if LIBAVFORMAT_BUILD > 4752
+            pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, video_st->time_base);
+#else
+                       pkt.pts = c->coded_frame->pts;
+#endif
+            if(c->coded_frame->key_frame)
+                pkt.flags |= PKT_FLAG_KEY;
+            pkt.stream_index= video_st->index;
+            pkt.data= outbuf;
+            pkt.size= out_size;
+
+            /* write the compressed frame in the media file */
+            ret = av_write_frame(oc, &pkt);
+        } else {
+            ret = 0;
+        }
+    }
+    if (ret != 0) {
+               CV_ERROR(CV_StsError, "Error while writing video frame");
+       }
+
+       __END__;
+       return CV_StsOk;
+}
+
+/// write a frame with FFMPEG
+bool CvVideoWriter_FFMPEG::writeFrame( const IplImage * image )
+{
+       bool ret = false;
+
+    CV_FUNCNAME("CvVideoWriter_FFMPEG::writerFrame");
+
+       __BEGIN__;
+
+       // typecast from opaque data type to implemented struct
+#if LIBAVFORMAT_BUILD > 4628
+    AVCodecContext *c = video_st->codec;
+#else
+       AVCodecContext *c = &(video_st->codec);
+#endif
+
+#if LIBAVFORMAT_BUILD < 5231
+    // It is not needed in the latest versions of the ffmpeg
+    if( c->codec_id == CODEC_ID_RAWVIDEO && image->origin != IPL_ORIGIN_BL )
+    {
+        if( !temp_image )
+            temp_image = cvCreateImage( cvGetSize(image),
+                                    image->depth, image->nChannels );
+        cvFlip( image, temp_image, 0 );
+        image = temp_image;
+    }
+#endif
+
+    // check parameters
+    if (input_pix_fmt == PIX_FMT_BGR24) {
+        if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U) {
+            CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 3.");
+        }
+    }
+       else if (input_pix_fmt == PIX_FMT_GRAY8) {
+        if (image->nChannels != 1 || image->depth != IPL_DEPTH_8U) {
+            CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 1.");
+        }
+    }
+       else {
+        assert(false);
+    }
+
+       // check if buffer sizes match, i.e. image has expected format (size, channels, bitdepth, alignment)
+       assert (image->imageSize == avpicture_get_size( input_pix_fmt, image->width, image->height ));
+
+       if ( c->pix_fmt != input_pix_fmt ) {
+               assert( input_picture );
+               // let input_picture point to the raw data buffer of 'image'
+               avpicture_fill((AVPicture *)input_picture, (uint8_t *) image->imageData,
+                               (PixelFormat)input_pix_fmt, image->width, image->height);
+
+#if !defined(HAVE_FFMPEG_SWSCALE)
+               // convert to the color format needed by the codec
+               if( img_convert((AVPicture *)picture, c->pix_fmt,
+                                       (AVPicture *)input_picture, (PixelFormat)input_pix_fmt,
+                                       image->width, image->height) < 0){
+                       CV_ERROR(CV_StsUnsupportedFormat, "FFMPEG::img_convert pixel format conversion from BGR24 not handled");
+               }
+#else
+               img_convert_ctx = sws_getContext(image->width,
+                            image->height,
+                            PIX_FMT_BGR24,
+                            c->width,
+                            c->height,
+                            c->pix_fmt,
+                            SWS_BICUBIC,
+                            NULL, NULL, NULL);
+
+                   if ( sws_scale(img_convert_ctx, input_picture->data,
+                            input_picture->linesize, 0,
+                            image->height,
+                            picture->data, picture->linesize) < 0 )
+                   {
+                     CV_ERROR(CV_StsUnsupportedFormat, "FFMPEG::img_convert pixel format conversion from BGR24 not handled");
+                   }
+               sws_freeContext(img_convert_ctx);
+#endif
+       }
+       else{
+               avpicture_fill((AVPicture *)picture, (uint8_t *) image->imageData,
+                               (PixelFormat)input_pix_fmt, image->width, image->height);
+       }
+
+       ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0;
+
+       __END__;
+       return ret;
+}
+
+/// close video output stream and free associated memory
+void CvVideoWriter_FFMPEG::close()
+{
+       unsigned i;
+
+       // nothing to do if already released
+       if ( !picture )
+               return;
+
+       /* no more frame to compress. The codec has a latency of a few
+          frames if using B frames, so we get the last frames by
+          passing the same picture again */
+       // TODO -- do we need to account for latency here?
+
+       /* write the trailer, if any */
+       av_write_trailer(oc);
+
+       // free pictures
+#if LIBAVFORMAT_BUILD > 4628
+       if( video_st->codec->pix_fmt != input_pix_fmt){
+#else
+       if( video_st->codec.pix_fmt != input_pix_fmt){
+#endif
+               cvFree(&(picture->data[0]));
+       }
+       av_free(picture);
+
+    if (input_picture) {
+        av_free(input_picture);
+    }
+
+       /* close codec */
+#if LIBAVFORMAT_BUILD > 4628
+       avcodec_close(video_st->codec);
+#else
+       avcodec_close(&(video_st->codec));
+#endif
+
+       av_free(outbuf);
+
+       /* free the streams */
+       for(i = 0; i < oc->nb_streams; i++) {
+               av_freep(&oc->streams[i]->codec);
+               av_freep(&oc->streams[i]);
+       }
+
+       if (!(fmt->flags & AVFMT_NOFILE)) {
+               /* close the output file */
+
+
+#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0)
+               url_fclose(oc->pb);
+#else
+               url_fclose(&oc->pb);
+#endif
+
+       }
+
+       /* free the stream */
+       av_free(oc);
+
+    cvReleaseImage( &temp_image );
+
+       init();
+}
+
+/// Create a video writer object that uses FFMPEG
+bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
+               double fps, CvSize frameSize, bool is_color )
+{
+    CV_FUNCNAME("CvVideoWriter_FFMPEG::open");
+
+       CodecID codec_id = CODEC_ID_NONE;
+       int err, codec_pix_fmt, bitrate_scale=64;
+
+       __BEGIN__;
+
+    close();
+
+       // check arguments
+       assert (filename);
+       assert (fps > 0);
+       assert (frameSize.width > 0  &&  frameSize.height > 0);
+
+       // tell FFMPEG to register codecs
+       av_register_all ();
+
+       /* auto detect the output format from the name and fourcc code. */
+       fmt = guess_format(NULL, filename, NULL);
+       if (!fmt) {
+               CV_ERROR( CV_StsUnsupportedFormat, "FFMPEG does not recognize the given file extension");
+       }
+
+       /* determine optimal pixel format */
+    if (is_color) {
+        input_pix_fmt = PIX_FMT_BGR24;
+    }
+       else {
+        input_pix_fmt = PIX_FMT_GRAY8;
+    }
+
+       // alloc memory for context
+       oc = av_alloc_format_context();
+       assert (oc);
+
+       /* set file name */
+       oc->oformat = fmt;
+       snprintf(oc->filename, sizeof(oc->filename), "%s", filename);
+
+       /* set some options */
+       oc->max_delay = (int)(0.7*AV_TIME_BASE);  /* This reduces buffer underrun warnings with MPEG */
+
+       /* Lookup codec_id for given fourcc */
+#if LIBAVCODEC_VERSION_INT<((51<<16)+(49<<8)+0)
+        if( (codec_id = codec_get_bmp_id( fourcc )) == CODEC_ID_NONE ){
+                       CV_ERROR( CV_StsUnsupportedFormat,
+                               "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." );
+               }
+#else
+       {
+       const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL};
+        if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE ){
+                       CV_ERROR( CV_StsUnsupportedFormat,
+                               "FFMPEG could not find a codec matching the given FOURCC code. Use fourcc=CV_FOURCC_DEFAULT for auto selection." );
+               }
+       }
+#endif
+
+    // set a few optimal pixel formats for lossless codecs of interest..
+    switch (codec_id) {
+#if LIBAVCODEC_VERSION_INT>((50<<16)+(1<<8)+0)
+    case CODEC_ID_JPEGLS:
+        // BGR24 or GRAY8 depending on is_color...
+        codec_pix_fmt = input_pix_fmt;
+        break;
+#endif
+    case CODEC_ID_HUFFYUV:
+        codec_pix_fmt = PIX_FMT_YUV422P;
+        break;
+    case CODEC_ID_MJPEG:
+    case CODEC_ID_LJPEG:
+      codec_pix_fmt = PIX_FMT_YUVJ420P;
+      bitrate_scale = 128;
+      break;
+    case CODEC_ID_RAWVIDEO:
+    default:
+        // good for lossy formats, MPEG, etc.
+        codec_pix_fmt = PIX_FMT_YUV420P;
+        break;
+    }
+
+       // TODO -- safe to ignore output audio stream?
+       video_st = icv_add_video_stream_FFMPEG(oc, codec_id,
+                       frameSize.width, frameSize.height, frameSize.width*frameSize.height*bitrate_scale,
+            fps, codec_pix_fmt);
+
+
+       /* set the output parameters (must be done even if no
+       parameters). */
+    if (av_set_parameters(oc, NULL) < 0) {
+               CV_ERROR(CV_StsBadArg, "Invalid output format parameters");
+    }
+
+    dump_format(oc, 0, filename, 1);
+
+    /* now that all the parameters are set, we can open the audio and
+       video codecs and allocate the necessary encode buffers */
+    if (!video_st){
+               CV_ERROR(CV_StsBadArg, "Couldn't open video stream");
+       }
+
+    AVCodec *codec;
+    AVCodecContext *c;
+
+#if LIBAVFORMAT_BUILD > 4628
+    c = (video_st->codec);
+#else
+    c = &(video_st->codec);
+#endif
+
+    c->codec_tag = fourcc;
+    /* find the video encoder */
+    codec = avcodec_find_encoder(c->codec_id);
+    if (!codec) {
+               CV_ERROR(CV_StsBadArg, "codec not found");
+    }
+
+    /* open the codec */
+    if ( (err=avcodec_open(c, codec)) < 0) {
+               char errtext[256];
+               sprintf(errtext, "Could not open codec '%s': %s", codec->name, icvFFMPEGErrStr(err));
+               CV_ERROR(CV_StsBadArg, errtext);
+    }
+
+    outbuf = NULL;
+
+    if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
+        /* allocate output buffer */
+               /* assume we will never get codec output with more than 4 bytes per pixel... */
+               outbuf_size = frameSize.width*frameSize.height*4;
+        outbuf = (uint8_t *) av_malloc(outbuf_size);
+    }
+
+       bool need_color_convert;
+       need_color_convert = (c->pix_fmt != input_pix_fmt);
+
+    /* allocate the encoded raw picture */
+    picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert);
+    if (!picture) {
+               CV_ERROR(CV_StsNoMem, "Could not allocate picture");
+    }
+
+    /* if the output format is not our input format, then a temporary
+       picture of the input format is needed too. It is then converted
+          to the required output format */
+       input_picture = NULL;
+    if ( need_color_convert ) {
+        input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, c->width, c->height, false);
+        if (!input_picture) {
+                       CV_ERROR(CV_StsNoMem, "Could not allocate picture");
+        }
+    }
+
+       /* open the output file, if needed */
+    if (!(fmt->flags & AVFMT_NOFILE)) {
+        if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0) {
+                       CV_ERROR(CV_StsBadArg, "Couldn't open output file for writing");
+        }
+    }
+
+    /* write the stream header, if any */
+    av_write_header( oc );
+
+
+       __END__;
+
+       return true;
+}
+
+CvVideoWriter* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,
+                                           CvSize frameSize, int isColor )
+{
+    CvVideoWriter_FFMPEG* writer = new CvVideoWriter_FFMPEG;
+    if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 ))
+        return writer;
+    delete writer;
+    return 0;
+}