Added a first version of new ffmpeg wrapper
authorAlexander Reshetnikov <no@email>
Mon, 12 Mar 2012 17:07:54 +0000 (17:07 +0000)
committerAlexander Reshetnikov <no@email>
Mon, 12 Mar 2012 17:07:54 +0000 (17:07 +0000)
CMakeLists.txt
modules/highgui/CMakeLists.txt
modules/highgui/src/cap_ffmpeg_api.hpp
modules/highgui/src/cap_ffmpeg_impl_v2.hpp [new file with mode: 0755]
modules/highgui/src/cap_ffmpeg_v2.cpp [new file with mode: 0644]

index 96a48c4..3cb2898 100644 (file)
@@ -385,6 +385,7 @@ if(UNIX)
             set(HAVE_FFMPEG 1)
         endif()
       endif()
+
       # Find the bzip2 library because it is required on some systems
       FIND_LIBRARY(BZIP2_LIBRARIES NAMES bz2 bzip2)
       if(NOT BZIP2_LIBRARIES)
@@ -393,6 +394,10 @@ if(UNIX)
       endif()
     endif()
 
+    if(HAVE_FFMPEG)
+    CHECK_MODULE(libavformat>=53 NEW_FFMPEG)
+    endif()
+
     if(WITH_1394)
       CHECK_MODULE(libdc1394-2 HAVE_DC1394_2)
       if(NOT HAVE_DC1394_2)
index 59505a2..cb3028b 100644 (file)
@@ -53,6 +53,18 @@ set(grfmt_srcs src/bitstrm.cpp ${grfmt_srcs})
 source_group("Src\\grfmts" FILES ${grfmt_hdrs} ${grfmt_srcs})
 
 set(highgui_hdrs src/precomp.hpp src/utils.hpp)
+
+if(NEW_FFMPEG)
+set(highgui_srcs
+    src/cap.cpp
+    src/cap_images.cpp
+    src/cap_ffmpeg_v2.cpp
+    src/loadsave.cpp
+    src/precomp.cpp
+    src/utils.cpp
+    src/window.cpp
+    )
+else()
 set(highgui_srcs
     src/cap.cpp
     src/cap_images.cpp
@@ -62,6 +74,8 @@ set(highgui_srcs
     src/utils.cpp
     src/window.cpp
     )
+endif()
+
 file(GLOB highgui_ext_hdrs "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h")
 
 #YV
index 57d5f19..de9ad67 100644 (file)
@@ -26,16 +26,25 @@ enum
 
 
 OPENCV_FFMPEG_API struct CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG(const char* filename);
+OPENCV_FFMPEG_API struct CvCapture_FFMPEG_2* cvCreateFileCapture_FFMPEG_2(const char* filename);
 OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap,
                                                   int prop, double value);
+OPENCV_FFMPEG_API int cvSetCaptureProperty_FFMPEG_2(struct CvCapture_FFMPEG_2* cap,
+                                                    int prop, double value);
 OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG(struct CvCapture_FFMPEG* cap, int prop);
+OPENCV_FFMPEG_API double cvGetCaptureProperty_FFMPEG_2(struct CvCapture_FFMPEG_2* cap, int prop);
 OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG(struct CvCapture_FFMPEG* cap);
-OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(CvCapture_FFMPEG* capture, unsigned char** data,
+OPENCV_FFMPEG_API int cvGrabFrame_FFMPEG_2(struct CvCapture_FFMPEG_2* cap);
+OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG(struct CvCapture_FFMPEG* capture, unsigned char** data,
+                                             int* step, int* width, int* height, int* cn);
+OPENCV_FFMPEG_API int cvRetrieveFrame_FFMPEG_2(struct CvCapture_FFMPEG_2* capture, unsigned char** data,
                                              int* step, int* width, int* height, int* cn);
 OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG(struct CvCapture_FFMPEG** cap);
-
+OPENCV_FFMPEG_API void cvReleaseCapture_FFMPEG_2(struct CvCapture_FFMPEG_2** cap);
 OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG(const char* filename,
             int fourcc, double fps, int width, int height, int isColor );
+OPENCV_FFMPEG_API struct CvVideoWriter_FFMPEG_2* cvCreateVideoWriter_FFMPEG_2(const char* filename,
+            int fourcc, double fps, int width, int height, int isColor );
 
 OPENCV_FFMPEG_API int cvWriteFrame_FFMPEG(struct CvVideoWriter_FFMPEG* writer, const unsigned char* data,
                                           int step, int width, int height, int cn, int origin);
diff --git a/modules/highgui/src/cap_ffmpeg_impl_v2.hpp b/modules/highgui/src/cap_ffmpeg_impl_v2.hpp
new file mode 100755 (executable)
index 0000000..fa41502
--- /dev/null
@@ -0,0 +1,1470 @@
+/*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*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef  UINT64_C
+#define UINT64_C(val) val ## LL
+#include <libavformat/avformat.h>
+#include <libavcodec/avcodec.h>
+#include <libswscale/swscale.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "cap_ffmpeg_api.hpp"
+#include "assert.h"
+
+#define CALC_FFMPEG_VERSION(a,b,c) ( a<<16 | b<<8 | c )
+
+struct Image_FFMPEG
+{
+    unsigned char* data;
+    int step;
+    int width;
+    int height;
+    int cn;
+};
+
+struct CvCapture_FFMPEG_2
+{
+        CvCapture_FFMPEG_2(const char* filename);
+        CvCapture_FFMPEG_2(const CvCapture_FFMPEG_2& mf);
+        CvCapture_FFMPEG_2& operator=(const CvCapture_FFMPEG_2& mf);
+
+        ~CvCapture_FFMPEG_2();
+
+        bool open( const char* filename );
+        void close();
+        bool setProperty(int, double);
+        double getProperty(int);
+        bool grabFrame();
+        bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn);
+        void init();
+        bool reopen();
+
+        cv::Mat read();
+
+        void seek(int64_t frame_number);
+        void seek(double sec);
+
+        int64_t get_total_frames();
+        int64_t get_frame_number();
+
+ private:
+        AVFormatContext * ic;
+        AVCodecContext  * avcodec_context;
+        AVCodec         * avcodec;
+        AVFrame         * picture;
+        AVFrame         * rgb_picture;
+        AVStream        * video_st;
+        AVPacket          packet;
+        Image_FFMPEG      frame;
+
+        #if defined(HAVE_FFMPEG_SWSCALE)
+        struct SwsContext *img_convert_ctx;
+        #endif
+
+        char* filename;
+
+        int video_stream;
+        int64_t picture_pts;
+
+        size_t width, height;
+        int64_t frame_number;
+
+        double eps_zero;
+
+        double  get_duration_sec();
+        double  get_fps();
+        int     get_bitrate();
+
+        double r2d(AVRational r);
+        int64_t dts_to_frame_number(int64_t dts);
+        double  dts_to_sec(int64_t dts);
+};
+
+CvCapture_FFMPEG_2::CvCapture_FFMPEG_2(const char* filename) :
+ic(0), avcodec_context(0), avcodec(0),
+picture(0), rgb_picture(0), video_stream(-1),
+width(0), height(0), frame_number(0), eps_zero(0.000025)
+{
+ av_register_all();
+
+ avformat_network_init();
+
+ // Open video file
+ avformat_open_input(&ic, filename, NULL, NULL);
+
+ // Find the first video stream
+ for(int i = 0; i < static_cast<int>(ic->nb_streams); i++)
+ {
+        struct AVCodecContext * cc = ic->streams[i]->codec;
+        // set number of threads
+        cc->thread_count = 2;
+
+        if(cc->codec_type == AVMEDIA_TYPE_VIDEO && video_stream == -1)
+        {
+            AVCodec * codec = avcodec_find_decoder(cc->codec_id);
+
+            if (codec == NULL)
+                CV_Error(0, "Unsupported codec !!!");
+
+            avcodec_open2(cc, codec, NULL);
+            video_stream = i;
+            break;
+        }
+    }
+
+    if(video_stream == -1)
+        CV_Error(0, "Didn't find a video stream");
+
+    // Get a pointer to the codec context for the video stream
+    avcodec_context = ic->streams[video_stream]->codec;
+
+    // Allocate video frame
+    picture = avcodec_alloc_frame();
+}
+
+CvCapture_FFMPEG_2::CvCapture_FFMPEG_2(const CvCapture_FFMPEG_2& vr) :
+    ic(vr.ic),
+    avcodec_context (vr.avcodec_context),
+    avcodec(0),
+    picture(0),
+    rgb_picture(0),
+    video_stream(-1),
+    width(0), height(0),
+    frame_number(0),
+    eps_zero(0.000001) {}
+
+CvCapture_FFMPEG_2& CvCapture_FFMPEG_2::operator=(const CvCapture_FFMPEG_2& mf)
+{
+    ic = mf.ic;
+    avcodec_context  = mf.avcodec_context;
+    return *this;
+}
+
+bool CvCapture_FFMPEG_2::open(const char* filename)
+{
+    CvCapture_FFMPEG_2 cap(filename);
+    *this = cap;
+}
+
+void CvCapture_FFMPEG_2::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] )
+    {
+        free( rgb_picture->data[0] );
+        rgb_picture->data[0] = 0;
+    }
+
+    // free last packet if exist
+    if (packet.data) {
+        av_free_packet (&packet);
+    }
+
+    init();
+}
+
+bool CvCapture_FFMPEG_2::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) {
+        int ret = av_read_frame(ic, &packet);
+        if (ret == AVERROR(EAGAIN))
+            continue;
+        if (ret < 0)
+            break;
+
+        if( packet.stream_index != video_stream ) {
+                av_free_packet (&packet);
+                continue;
+            }
+
+        avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet);
+
+        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;
+}
+
+bool CvCapture_FFMPEG_2::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
+{
+    if( !video_st || !picture->data[0] )
+        return false;
+
+#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
+    *data = frame.data;
+    *step = frame.step;
+    *width = frame.width;
+    *height = frame.height;
+    *cn = frame.cn;
+
+    return true;
+}
+
+void CvCapture_FFMPEG_2::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
+}
+
+bool CvCapture_FFMPEG_2::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
+#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(52, 111, 0)
+    av_open_input_file(&ic, filename, NULL, 0, NULL);
+#else
+    avformat_open_input(&ic, filename, NULL, NULL);
+#endif
+
+    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
+
+#if FF_API_THREAD_INIT
+    avcodec_thread_init(enc, std::min(get_number_of_cpus(), 16));
+#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;
+}
+
+int64_t CvCapture_FFMPEG_2::get_frame_number()
+{
+    return frame_number;
+}
+
+cv::Mat CvCapture_FFMPEG_2::read()
+{
+    int frame_finished = 0;
+    AVPacket packet;
+
+    int count_errs = 0;
+    const int max_number_of_attempts = 32;
+
+    while(true)
+    {
+        av_read_frame(ic, &packet);
+
+        if(packet.stream_index == video_stream)
+        {
+            // Decode video frame
+            avcodec_decode_video2(avcodec_context, picture, &frame_finished, &packet);
+
+            // Did we get a video frame?
+            if(frame_finished)
+            {
+                rgb_picture = avcodec_alloc_frame();
+
+                cv::Mat img(static_cast<int>(avcodec_context->height), static_cast<int>(avcodec_context->width), CV_8UC3);
+
+                uint8_t * buffer = reinterpret_cast<uint8_t *>(img.ptr(0));
+
+                avpicture_fill(reinterpret_cast<AVPicture*>(rgb_picture), buffer, PIX_FMT_RGB24, avcodec_context->width, avcodec_context->height);
+
+                width  = picture->width;
+                height = picture->height;
+
+                struct SwsContext * img_convert_ctx = sws_getContext(
+                                                                     width, height,
+                                                                     avcodec_context->pix_fmt,
+                                                                     width, height,
+                                                                     PIX_FMT_BGR24,
+                                                                     SWS_BICUBIC,
+                                                                     NULL, NULL, NULL
+                                                                    );
+
+                            img_convert_ctx = sws_getCachedContext(
+                                                                     img_convert_ctx,
+                                                                     width, height,
+                                                                     avcodec_context->pix_fmt,
+                                                                     width, height,
+                                                                     PIX_FMT_BGR24,
+                                                                     SWS_BICUBIC,
+                                                                     NULL, NULL, NULL
+                                                                    );
+
+                if (img_convert_ctx == NULL)
+                    CV_Error(0, "Cannot initialize the conversion context!");
+
+                sws_scale(
+                            img_convert_ctx,
+                            picture->data,
+                            picture->linesize,
+                            0, height,
+                            rgb_picture->data,
+                            rgb_picture->linesize
+                         );
+
+                sws_freeContext(img_convert_ctx);
+
+                av_free(rgb_picture);
+
+                frame_number++;
+
+                //std::cout << "cur dts: " << ic->streams[video_stream]->cur_dts << std::endl;
+
+                return img;
+            }
+            else
+            {
+                count_errs ++;
+                if (count_errs > max_number_of_attempts)
+                        break;
+            }
+        }
+        else
+        {
+            count_errs ++;
+            if (count_errs > max_number_of_attempts)
+                    break;
+        }
+    }
+
+    // Free the packet that was allocated by av_read_frame
+    av_free_packet(&packet);
+
+    return cv::Mat();
+}
+
+double CvCapture_FFMPEG_2::r2d(AVRational r)
+{
+    if (r.num == 0 || r.den == 0)
+    {
+        return 0.0;
+    }
+    else
+    {
+        return static_cast<double>(r.num) / static_cast<double>(r.den);
+    }
+}
+
+double CvCapture_FFMPEG_2::get_duration_sec()
+{
+    double sec = static_cast<double>(ic->duration) / static_cast<double>(AV_TIME_BASE);
+
+    if (sec < eps_zero)
+    {
+        sec = static_cast<double>(ic->streams[video_stream]->duration) * r2d(ic->streams[video_stream]->time_base);
+    }
+
+    if (sec < eps_zero)
+    {
+        sec = static_cast<double>(static_cast<int64_t>(ic->streams[video_stream]->duration)) * r2d(ic->streams[video_stream]->time_base);
+    }
+    return sec;
+}
+
+int CvCapture_FFMPEG_2::get_bitrate()
+{
+    return ic->bit_rate;
+}
+
+double CvCapture_FFMPEG_2::get_fps()
+{
+    double fps = r2d(ic->streams[video_stream]->r_frame_rate);
+
+    if (fps < eps_zero)
+    {
+        fps = r2d(ic->streams[video_stream]->avg_frame_rate);
+    }
+
+    // may be this is wrong
+    if (fps < eps_zero)
+    {
+        fps = 1.0 / r2d(ic->streams[video_stream]->codec->time_base);
+    }
+
+    return fps;
+}
+
+int64_t CvCapture_FFMPEG_2::get_total_frames()
+{
+    int64_t nbf = ic->streams[video_stream]->nb_frames;
+
+    if (nbf == 0)
+    {
+        nbf = static_cast<int64_t>(get_duration_sec() * get_fps());
+    }
+    return nbf;
+}
+
+//#include <iostream>
+
+double round(double d)
+{
+    return std::floor(d + 0.5);
+}
+
+int64_t CvCapture_FFMPEG_2::dts_to_frame_number(int64_t dts)
+{
+    double sec = dts_to_sec(dts);
+    return static_cast<int64_t>(get_fps() * sec);
+}
+
+double  CvCapture_FFMPEG_2::dts_to_sec(int64_t dts)
+{
+    return static_cast<double>(dts - ic->streams[video_stream]->start_time) * r2d(ic->streams[video_stream]->time_base);
+}
+
+void CvCapture_FFMPEG_2::seek(int64_t frame_number)
+{
+    double sec = static_cast<double>(frame_number) / static_cast<double>(get_fps());
+    this->frame_number = std::min<int>(frame_number, get_total_frames());
+    seek(sec);
+    /* int64_t dts = dts_to_frame_number(ic->streams[video_stream]->cur_dts);
+
+    if (abs(dts - 2 - frame_number) > 16)
+    {
+        double sec = static_cast<double>(frame_number) / static_cast<double>(get_fps());
+        int64_t time_stamp = ic->streams[video_stream]->start_time;
+        double  time_base  = r2d(ic->streams[video_stream]->time_base);
+        time_stamp += static_cast<int64_t>(sec / time_base);
+        av_seek_frame(ic, video_stream, time_stamp, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD);
+    }
+
+    while(dts - 2 < frame_number)
+    {
+        cv::Mat i = read();
+        if (i.empty())
+            break;
+
+        dts = dts_to_frame_number(ic->streams[video_stream]->cur_dts);
+
+        //std::cout << "cur dts: " << ic->streams[video_stream]->cur_dts << " f: " << dts << std::endl;
+    } */
+}
+
+void CvCapture_FFMPEG_2::seek(double sec)
+{
+   // seek(static_cast<int64_t>(sec * get_fps()));
+
+   int64_t time_stamp = ic->streams[video_stream]->start_time;
+   double  time_base  = av_q2d(ic->streams[video_stream]->time_base);
+   time_stamp += static_cast<int64_t>(sec / time_base);
+   av_seek_frame(ic, video_stream, time_stamp, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD);
+}
+
+CvCapture_FFMPEG_2::~CvCapture_FFMPEG_2()
+{
+    avformat_close_input(&ic);
+}
+
+bool CvCapture_FFMPEG_2::setProperty( int property_id, double value )
+{
+    if (!video_stream) return false;
+
+    switch( property_id )
+    {
+    case CV_FFMPEG_CAP_PROP_POS_MSEC:
+    case CV_FFMPEG_CAP_PROP_POS_FRAMES:
+    case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
+        {
+
+            switch( property_id )
+            {
+            case CV_FFMPEG_CAP_PROP_POS_FRAMES:
+                seek(value/1000.0); break;
+                break;
+
+            case CV_FFMPEG_CAP_PROP_POS_MSEC:
+                seek(value);
+                break;
+
+            case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
+                seek(value*this->get_bitrate());
+                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 flags = AVSEEK_FLAG_ANY;
+                if (timestamp < ic->streams[video_stream]->cur_dts)
+                  flags |= AVSEEK_FLAG_BACKWARD;
+                int ret = av_seek_frame(ic, video_stream, timestamp, flags);
+                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;
+
+}
+
+#if defined(__APPLE__)
+#define AV_NOPTS_VALUE_ ((int64_t)0x8000000000000000LL)
+#else
+#define AV_NOPTS_VALUE_ ((int64_t)AV_NOPTS_VALUE)
+#endif
+
+double CvCapture_FFMPEG_2::getProperty( int property_id )
+{
+    // if( !capture || !video_st || !picture->data[0] ) return 0;
+    if( !video_stream ) return 0;
+
+    double frameScale = av_q2d (video_st->time_base) * av_q2d (video_st->r_frame_rate);
+    int64_t timestamp;
+    timestamp = picture_pts;
+
+    switch( property_id )
+    {
+    case CV_FFMPEG_CAP_PROP_POS_MSEC:
+        return 1000.0*static_cast<double>(dts_to_sec(frame_number));
+        break;
+
+    case CV_FFMPEG_CAP_PROP_POS_FRAMES:
+        return (double)static_cast<int>(get_frame_number());
+        break;
+
+    case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
+        return static_cast<double>(dts_to_frame_number(frame_number))/static_cast<double>(dts_to_sec(frame_number));
+        break;
+
+    case CV_FFMPEG_CAP_PROP_FRAME_COUNT:
+        return (double)static_cast<int>(get_total_frames());
+        break;
+
+    case CV_FFMPEG_CAP_PROP_FRAME_WIDTH:
+        return (double)static_cast<int>(width);
+    break;
+
+    case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT:
+        return (double)static_cast<int>(height);
+    break;
+
+    case CV_FFMPEG_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
+    break;
+    case CV_FFMPEG_CAP_PROP_FOURCC:
+#if LIBAVFORMAT_BUILD > 4628
+        return (double)video_st->codec->codec_tag;
+#else
+        return (double)video_st->codec.codec_tag;
+#endif
+    break;
+    }
+
+return 0;
+}
+
+///////////////// FFMPEG CvVideoWriter implementation //////////////////////////
+struct CvVideoWriter_FFMPEG
+{
+    bool open( const char* filename, int fourcc,
+        double fps, int width, int height, bool isColor );
+    void close();
+    bool writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin );
+
+    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;
+    Image_FFMPEG      temp_image;
+#if defined(HAVE_FFMPEG_SWSCALE)
+    struct SwsContext *img_convert_ctx;
+#endif
+};
+
+static const char * icvFFMPEGErrStr(int err)
+{
+#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
+    switch(err) {
+        case AVERROR_BSF_NOT_FOUND:
+            return "Bitstream filter not found";
+        case AVERROR_DECODER_NOT_FOUND:
+            return "Decoder not found";
+        case AVERROR_DEMUXER_NOT_FOUND:
+            return "Demuxer not found";
+        case AVERROR_ENCODER_NOT_FOUND:
+            return "Encoder not found";
+        case AVERROR_EOF:
+            return "End of file";
+        case AVERROR_EXIT:
+            return "Immediate exit was requested; the called function should not be restarted";
+        case AVERROR_FILTER_NOT_FOUND:
+            return "Filter not found";
+        case AVERROR_INVALIDDATA:
+            return "Invalid data found when processing input";
+        case AVERROR_MUXER_NOT_FOUND:
+            return "Muxer not found";
+        case AVERROR_OPTION_NOT_FOUND:
+            return "Option not found";
+        case AVERROR_PATCHWELCOME:
+            return "Not yet implemented in FFmpeg, patches welcome";
+        case AVERROR_PROTOCOL_NOT_FOUND:
+            return "Protocol not found";
+        case AVERROR_STREAM_NOT_FOUND:
+            return "Stream not found";
+        default:
+            break;
+    }
+#else
+    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;
+    }
+#endif
+
+    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;
+    memset(&temp_image, 0, sizeof(temp_image));
+#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 *) malloc(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, AVMEDIA_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 = AVMEDIA_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=(int)(fps+0.5);
+    frame_rate_base=1;
+    while (fabs((double)frame_rate/frame_rate_base) - fps > 0.001){
+        frame_rate_base*=10;
+        frame_rate=(int)(fps*frame_rate_base + 0.5);
+    }
+#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 )
+{
+
+#if LIBAVFORMAT_BUILD > 4628
+    AVCodecContext * c = video_st->codec;
+#else
+    AVCodecContext * c = &(video_st->codec);
+#endif
+    int out_size;
+    int ret;
+
+    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);
+
+        #ifndef PKT_FLAG_KEY
+            #define PKT_FLAG_KEY AV_PKT_FLAG_KEY
+        #endif
+
+        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) return -1;
+
+    return 0;
+}
+
+/// write a frame with FFMPEG
+bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin )
+{
+    bool ret = false;
+
+    // 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 && origin != 1 )
+    {
+        if( !temp_image.data )
+        {
+            temp_image.step = (width*cn + 3) & -4;
+            temp_image.width = width;
+            temp_image.height = height;
+            temp_image.cn = cn;
+            temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height);
+        }
+        for( int y = 0; y < height; y++ )
+            memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, width*cn);
+        data = temp_image.data;
+        step = temp_image.step;
+    }
+#else
+    if( width*cn != step )
+    {
+        if( !temp_image.data )
+        {
+            temp_image.step = width*cn;
+            temp_image.width = width;
+            temp_image.height = height;
+            temp_image.cn = cn;
+            temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height);
+        }
+        if (origin == 1)
+            for( int y = 0; y < height; y++ )
+                memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, temp_image.step);
+        else
+            for( int y = 0; y < height; y++ )
+                memcpy(temp_image.data + y*temp_image.step, data + y*step, temp_image.step);
+        data = temp_image.data;
+        step = temp_image.step;
+    }
+#endif
+
+    // check parameters
+    if (input_pix_fmt == PIX_FMT_BGR24) {
+        if (cn != 3) {
+            return false;
+        }
+    }
+    else if (input_pix_fmt == PIX_FMT_GRAY8) {
+        if (cn != 1) {
+            return false;
+        }
+    }
+    else {
+        assert(false);
+    }
+
+    // check if buffer sizes match, i.e. image has expected format (size, channels, bitdepth, alignment)
+/*#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(37<<8)+0)
+    assert (image->imageSize == avpicture_get_size( (PixelFormat)input_pix_fmt, image->width, image->height ));
+#else
+    assert (image->imageSize == avpicture_get_size( input_pix_fmt, image->width, image->height ));
+#endif*/
+
+    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 *) data,
+                (PixelFormat)input_pix_fmt, width, 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,
+                    width, height) < 0){
+            return false;
+        }
+#else
+        img_convert_ctx = sws_getContext(width,
+                     height,
+                     (PixelFormat)input_pix_fmt,
+                     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,
+                     height,
+                     picture->data, picture->linesize) < 0 )
+            {
+               return false;
+            }
+        sws_freeContext(img_convert_ctx);
+#endif
+    }
+    else{
+        avpicture_fill((AVPicture *)picture, (uint8_t *) data,
+                (PixelFormat)input_pix_fmt, width, height);
+    }
+
+    ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0;
+
+    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
+        if(picture->data[0])
+           free(picture->data[0]);
+        picture->data[0] = 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) && LIBAVCODEC_VERSION_INT <= ((54<<16)+(5<<8)+0)
+        url_fclose(oc->pb);
+    #else
+    #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
+        url_fclose(&oc->pb);
+#endif
+    #endif
+
+    }
+
+    /* free the stream */
+    av_free(oc);
+
+    if( temp_image.data )
+    {
+        free(temp_image.data);
+        temp_image.data = 0;
+    }
+
+    init();
+}
+
+/// Create a video writer object that uses FFMPEG
+bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
+        double fps, int width, int height, bool is_color )
+{
+    CodecID codec_id = CODEC_ID_NONE;
+    int err, codec_pix_fmt, bitrate_scale=64;
+
+    close();
+
+    // check arguments
+    assert (filename);
+    assert (fps > 0);
+    assert (width > 0  &&  height > 0);
+
+    // tell FFMPEG to register codecs
+    av_register_all ();
+
+    /* auto detect the output format from the name and fourcc code. */
+
+#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
+    fmt = av_guess_format(NULL, filename, NULL);
+#else
+    fmt = guess_format(NULL, filename, NULL);
+#endif
+
+    if (!fmt)
+        return false;
+
+    /* determine optimal pixel format */
+    if (is_color) {
+        input_pix_fmt = PIX_FMT_BGR24;
+    }
+    else {
+        input_pix_fmt = PIX_FMT_GRAY8;
+    }
+
+    /* 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 )
+        return false;
+#else
+   /*  const struct AVCodecTag * tags[] = { codec_bmp_tags, NULL};
+    if( (codec_id = av_codec_get_id(tags, fourcc)) == CODEC_ID_NONE )
+        return false; */
+#endif
+
+    // alloc memory for context
+#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
+    oc = avformat_alloc_context();
+#else
+    oc = av_alloc_format_context();
+#endif
+    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 */
+
+    // 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:
+      codec_pix_fmt = input_pix_fmt;
+      break;
+    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,
+            width, height, width*height*bitrate_scale,
+            fps, codec_pix_fmt);
+
+
+    /* set the output parameters (must be done even if no
+       parameters). */
+    #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
+
+    if (av_set_parameters(oc, NULL) < 0) {
+        return false;
+    }
+
+    #endif
+
+#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
+    av_dump_format(oc, 0, filename, 1);
+#else
+    dump_format(oc, 0, filename, 1);
+#endif
+
+    /* now that all the parameters are set, we can open the audio and
+       video codecs and allocate the necessary encode buffers */
+    if (!video_st){
+        return false;
+    }
+
+    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) {
+        return false;
+    }
+
+    c->bit_rate_tolerance = c->bit_rate;
+
+    /* 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));
+        return false;
+    }
+
+    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 = width*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) {
+        return false;
+    }
+
+    /* 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) {
+            return false;
+        }
+    }
+
+    /* open the output file, if needed */
+    #ifndef URL_RDONLY
+        #define URL_RDONLY 1
+    #endif
+    #ifndef URL_WRONLY
+       #define URL_WRONLY 2
+    #endif
+    #ifndef URL_RWONLY
+        #define URL_RWONLY (URL_RDONLY|URL_WRONLY)
+    #endif
+
+    if (!(fmt->flags & AVFMT_NOFILE))
+    {
+        #if LIBAVCODEC_VERSION_INT <= ((54<<16)+(5<<8)+0)
+        if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0)
+        {
+            return false;
+        }
+        #endif
+    }
+
+    /* write the stream header, if any */
+#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
+    avformat_write_header(oc, NULL);
+#else
+    av_write_header( oc );
+#endif
+    return true;
+}
+
+
+CvVideoWriter_FFMPEG* cvCreateVideoWriter_FFMPEG( const char* filename, int fourcc, double fps,
+                                                  int width, int height, int isColor )
+{
+    CvVideoWriter_FFMPEG* writer = (CvVideoWriter_FFMPEG*)malloc(sizeof(*writer));
+    writer->init();
+    if( writer->open( filename, fourcc, fps, width, height, isColor != 0 ))
+        return writer;
+    writer->close();
+    free(writer);
+    return 0;
+}
+
+
+void cvReleaseVideoWriter_FFMPEG( CvVideoWriter_FFMPEG** writer )
+{
+    if( writer && *writer )
+    {
+        (*writer)->close();
+        free(*writer);
+        *writer = 0;
+    }
+}
+
+
+int cvWriteFrame_FFMPEG( CvVideoWriter_FFMPEG* writer,
+                         const unsigned char* data, int step,
+                         int width, int height, int cn, int origin)
+{
+    return writer->writeFrame(data, step, width, height, cn, origin);
+}
+
+int cvSetCaptureProperty_FFMPEG_2(CvCapture_FFMPEG_2* capture, int prop_id, double value)
+{
+    return capture->setProperty(prop_id, value);
+}
+
+double cvGetCaptureProperty_FFMPEG_2(CvCapture_FFMPEG_2* capture, int prop_id)
+{
+    return capture->getProperty(prop_id);
+}
+
+int cvGrabFrame_FFMPEG_2(CvCapture_FFMPEG_2* capture)
+{
+    return capture->grabFrame();
+}
+
+int cvRetrieveFrame_FFMPEG_2(CvCapture_FFMPEG_2* capture, unsigned char** data, int* step, int* width, int* height, int* cn)
+{
+    return capture->retrieveFrame(0, data, step, width, height, cn);
+}
+
+CvCapture_FFMPEG_2* cvCreateFileCapture_FFMPEG_2( const char* filename )
+{
+    CvCapture_FFMPEG_2* capture = (CvCapture_FFMPEG_2*)malloc(sizeof(*capture));
+    capture->init();
+    if( capture->open( filename ))
+        return capture;
+    capture->close();
+    free(capture);
+    return 0;
+}
+
+void cvReleaseCapture_FFMPEG_2(CvCapture_FFMPEG_2** capture)
+{
+    if( capture && *capture )
+    {
+        (*capture)->close();
+        free(*capture);
+        *capture = 0;
+    }
+}
+
diff --git a/modules/highgui/src/cap_ffmpeg_v2.cpp b/modules/highgui/src/cap_ffmpeg_v2.cpp
new file mode 100644 (file)
index 0000000..2ae7bc8
--- /dev/null
@@ -0,0 +1,250 @@
+/*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 "precomp.hpp"
+
+#ifdef HAVE_FFMPEG
+#include "cap_ffmpeg_impl_v2.hpp"
+#else
+#include "cap_ffmpeg_api.hpp"
+#endif
+
+static CvCreateFileCapture_Plugin icvCreateFileCapture_FFMPEG_p = 0;
+static CvReleaseCapture_Plugin icvReleaseCapture_FFMPEG_p = 0;
+static CvGrabFrame_Plugin icvGrabFrame_FFMPEG_p = 0;
+static CvRetrieveFrame_Plugin icvRetrieveFrame_FFMPEG_p = 0;
+static CvSetCaptureProperty_Plugin icvSetCaptureProperty_FFMPEG_p = 0;
+static CvGetCaptureProperty_Plugin icvGetCaptureProperty_FFMPEG_p = 0;
+static CvCreateVideoWriter_Plugin icvCreateVideoWriter_FFMPEG_p = 0;
+static CvReleaseVideoWriter_Plugin icvReleaseVideoWriter_FFMPEG_p = 0;
+static CvWriteFrame_Plugin icvWriteFrame_FFMPEG_p = 0;
+
+static void
+icvInitFFMPEG(void)
+{
+    static int ffmpegInitialized = 0;
+    if( !ffmpegInitialized )
+    {
+    #if defined WIN32 || defined _WIN32
+        const char* module_name = "opencv_ffmpeg"
+        #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
+            "_64"
+        #endif
+            ".dll";
+
+        static HMODULE icvFFOpenCV = LoadLibrary( module_name );
+        if( icvFFOpenCV )
+        {
+            icvCreateFileCapture_FFMPEG_p =
+                (CvCreateFileCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateFileCapture_FFMPEG_2");
+            icvReleaseCapture_FFMPEG_p =
+                (CvReleaseCapture_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseCapture_FFMPEG_2");
+            icvGrabFrame_FFMPEG_p =
+                (CvGrabFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvGrabFrame_FFMPEG_2");
+            icvRetrieveFrame_FFMPEG_p =
+                (CvRetrieveFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvRetrieveFrame_FFMPEG_2");
+            icvSetCaptureProperty_FFMPEG_p =
+                (CvSetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvSetCaptureProperty_FFMPEG_2");
+            icvGetCaptureProperty_FFMPEG_p =
+                (CvGetCaptureProperty_Plugin)GetProcAddress(icvFFOpenCV, "cvGetCaptureProperty_FFMPEG_2");
+            icvCreateVideoWriter_FFMPEG_p =
+                (CvCreateVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvCreateVideoWriter_FFMPEG");
+            icvReleaseVideoWriter_FFMPEG_p =
+                (CvReleaseVideoWriter_Plugin)GetProcAddress(icvFFOpenCV, "cvReleaseVideoWriter_FFMPEG");
+            icvWriteFrame_FFMPEG_p =
+                (CvWriteFrame_Plugin)GetProcAddress(icvFFOpenCV, "cvWriteFrame_FFMPEG");
+
+#if 0
+            if( icvCreateFileCapture_FFMPEG_p != 0 &&
+                icvReleaseCapture_FFMPEG_p != 0 &&
+                icvGrabFrame_FFMPEG_p != 0 &&
+                icvRetrieveFrame_FFMPEG_p != 0 &&
+                icvSetCaptureProperty_FFMPEG_p != 0 &&
+                icvGetCaptureProperty_FFMPEG_p != 0 &&
+                icvCreateVideoWriter_FFMPEG_p != 0 &&
+                icvReleaseVideoWriter_FFMPEG_p != 0 &&
+                icvWriteFrame_FFMPEG_p != 0 )
+            {
+                printf("Successfully initialized ffmpeg plugin!\n");
+            }
+            else
+            {
+                printf("Failed to load FFMPEG plugin: module handle=%p\n", icvFFOpenCV);
+            }
+#endif
+        }
+    #elif defined HAVE_FFMPEG
+        icvCreateFileCapture_FFMPEG_p = (CvCreateFileCapture_Plugin)cvCreateFileCapture_FFMPEG_2;
+        icvReleaseCapture_FFMPEG_p = (CvReleaseCapture_Plugin)cvReleaseCapture_FFMPEG_2;
+        icvGrabFrame_FFMPEG_p = (CvGrabFrame_Plugin)cvGrabFrame_FFMPEG_2;
+        icvRetrieveFrame_FFMPEG_p = (CvRetrieveFrame_Plugin)cvRetrieveFrame_FFMPEG_2;
+        icvSetCaptureProperty_FFMPEG_p = (CvSetCaptureProperty_Plugin)cvSetCaptureProperty_FFMPEG_2;
+        icvGetCaptureProperty_FFMPEG_p = (CvGetCaptureProperty_Plugin)cvGetCaptureProperty_FFMPEG_2;
+        icvCreateVideoWriter_FFMPEG_p = (CvCreateVideoWriter_Plugin)cvCreateVideoWriter_FFMPEG;
+        icvReleaseVideoWriter_FFMPEG_p = (CvReleaseVideoWriter_Plugin)cvReleaseVideoWriter_FFMPEG;
+        icvWriteFrame_FFMPEG_p = (CvWriteFrame_Plugin)cvWriteFrame_FFMPEG;
+    #endif
+
+        ffmpegInitialized = 1;
+    }
+}
+
+
+class CvCapture_FFMPEG_proxy : public CvCapture
+{
+public:
+    CvCapture_FFMPEG_proxy() { ffmpegCapture = 0; }
+    virtual ~CvCapture_FFMPEG_proxy() { close(); }
+
+    virtual double getProperty(int propId)
+    {
+        return ffmpegCapture ? icvGetCaptureProperty_FFMPEG_p(ffmpegCapture, propId) : 0;
+    }
+    virtual bool setProperty(int propId, double value)
+    {
+        return ffmpegCapture ? icvSetCaptureProperty_FFMPEG_p(ffmpegCapture, propId, value)!=0 : false;
+    }
+    virtual bool grabFrame()
+    {
+        return ffmpegCapture ? icvGrabFrame_FFMPEG_p(ffmpegCapture)!=0 : false;
+    }
+    virtual IplImage* retrieveFrame(int)
+    {
+        unsigned char* data = 0;
+        int step=0, width=0, height=0, cn=0;
+
+        if(!ffmpegCapture ||
+           !icvRetrieveFrame_FFMPEG_p(ffmpegCapture, &data, &step, &width, &height, &cn))
+           return 0;
+        cvInitImageHeader(&frame, cvSize(width, height), 8, cn);
+        cvSetData(&frame, data, step);
+        return &frame;
+    }
+    virtual bool open( const char* filename )
+    {
+        close();
+
+        icvInitFFMPEG();
+        if( !icvCreateFileCapture_FFMPEG_p )
+            return false;
+        ffmpegCapture = icvCreateFileCapture_FFMPEG_p( filename );
+        return ffmpegCapture != 0;
+    }
+    virtual void close()
+    {
+        if( ffmpegCapture && icvReleaseCapture_FFMPEG_p )
+            icvReleaseCapture_FFMPEG_p( &ffmpegCapture );
+        assert( ffmpegCapture == 0 );
+        ffmpegCapture = 0;
+    }
+
+protected:
+    void* ffmpegCapture;
+    IplImage frame;
+};
+
+
+CvCapture* cvCreateFileCapture_FFMPEG_proxy(const char * filename)
+{
+    CvCapture_FFMPEG_proxy* result = new CvCapture_FFMPEG_proxy;
+    if( result->open( filename ))
+        return result;
+    delete result;
+#if defined WIN32 || defined _WIN32
+    return cvCreateFileCapture_VFW(filename);
+#else
+    return 0;
+#endif
+}
+
+
+class CvVideoWriter_FFMPEG_proxy : public CvVideoWriter
+{
+public:
+    CvVideoWriter_FFMPEG_proxy() { ffmpegWriter = 0; }
+    virtual ~CvVideoWriter_FFMPEG_proxy() { close(); }
+
+    virtual bool writeFrame( const IplImage* image )
+    {
+        if(!ffmpegWriter)
+            return false;
+        CV_Assert(image->depth == 8);
+
+        return icvWriteFrame_FFMPEG_p(ffmpegWriter, (const uchar*)image->imageData,
+             image->widthStep, image->width, image->height, image->nChannels, image->origin) !=0;
+    }
+    virtual bool open( const char* filename, int fourcc, double fps, CvSize frameSize, bool isColor )
+    {
+        close();
+        icvInitFFMPEG();
+        if( !icvCreateVideoWriter_FFMPEG_p )
+            return false;
+        ffmpegWriter = icvCreateVideoWriter_FFMPEG_p( filename, fourcc, fps, frameSize.width, frameSize.height, isColor );
+        return ffmpegWriter != 0;
+    }
+
+    virtual void close()
+    {
+        if( ffmpegWriter && icvReleaseVideoWriter_FFMPEG_p )
+            icvReleaseVideoWriter_FFMPEG_p( &ffmpegWriter );
+        assert( ffmpegWriter == 0 );
+        ffmpegWriter = 0;
+    }
+
+protected:
+    void* ffmpegWriter;
+};
+
+
+CvVideoWriter* cvCreateVideoWriter_FFMPEG_proxy( const char* filename, int fourcc,
+                                          double fps, CvSize frameSize, int isColor )
+{
+    CvVideoWriter_FFMPEG_proxy* result = new CvVideoWriter_FFMPEG_proxy;
+
+    if( result->open( filename, fourcc, fps, frameSize, isColor != 0 ))
+        return result;
+    delete result;
+#if defined WIN32 || defined _WIN32
+    return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, isColor);
+#else
+    return 0;
+#endif
+}