Merge branch '2.4' into master
authorAlexander Alekhin <alexander.alekhin@itseez.com>
Thu, 21 Apr 2016 17:10:51 +0000 (20:10 +0300)
committerAlexander Alekhin <alexander.alekhin@itseez.com>
Thu, 21 Apr 2016 17:15:08 +0000 (20:15 +0300)
Commits:
67fe57a add fixed video
db0ae2c Restore 2.4 source branch for bug fix 6317.
97ac59c Fix a memory leak indirectly caused by cvDestroyWindow
eb40afa Add a workaround for FFmpeg's color conversion accessing past the end of the buffer
421fcf9 Rearrange CvVideoWriter_FFMPEG::writeFrame for better readability
912592d Remove "INSTALL_NAME_DIR lib" target property
bb1c2d7 fix bug on border at pyrUp

1  2 
apps/annotation/CMakeLists.txt
apps/createsamples/CMakeLists.txt
apps/traincascade/CMakeLists.txt
cmake/OpenCVModule.cmake
modules/highgui/src/window_gtk.cpp
modules/imgcodecs/src/grfmt_png.cpp
modules/imgproc/src/pyramids.cpp
modules/java/CMakeLists.txt
modules/videoio/src/cap_ffmpeg_impl.hpp
samples/data/tree.avi

Simple merge
index 2450623,0000000..a285c69
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,38 @@@
-                       INSTALL_NAME_DIR lib
 +set(OPENCV_CREATESAMPLES_DEPS opencv_core opencv_imgproc opencv_objdetect opencv_imgcodecs opencv_highgui opencv_calib3d opencv_features2d opencv_videoio)
 +ocv_check_dependencies(${OPENCV_CREATESAMPLES_DEPS})
 +
 +if(NOT OCV_DEPENDENCIES_FOUND)
 +  return()
 +endif()
 +
 +project(createsamples)
 +set(the_target opencv_createsamples)
 +
 +ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv")
 +ocv_target_include_modules_recurse(${the_target} ${OPENCV_CREATESAMPLES_DEPS})
 +
 +file(GLOB SRCS *.cpp)
 +file(GLOB HDRS *.h*)
 +
 +set(createsamples_files ${SRCS} ${HDRS})
 +
 +ocv_add_executable(${the_target} ${createsamples_files})
 +ocv_target_link_libraries(${the_target} ${OPENCV_CREATESAMPLES_DEPS})
 +
 +set_target_properties(${the_target} PROPERTIES
 +                      DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
 +                      ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
 +                      RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
 +                      OUTPUT_NAME "opencv_createsamples")
 +
 +if(ENABLE_SOLUTION_FOLDERS)
 +  set_target_properties(${the_target} PROPERTIES FOLDER "applications")
 +endif()
 +
 +if(INSTALL_CREATE_DISTRIB)
 +  if(BUILD_SHARED_LIBS)
 +    install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev)
 +  endif()
 +else()
 +  install(TARGETS ${the_target} OPTIONAL RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev)
 +endif()
Simple merge
@@@ -827,13 -591,9 +827,12 @@@ macro(_ocv_create_module
    set_target_properties(${the_module} PROPERTIES
      OUTPUT_NAME "${the_module}${OPENCV_DLLVERSION}"
      DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
 +    COMPILE_PDB_NAME "${the_module}${OPENCV_DLLVERSION}"
 +    COMPILE_PDB_NAME_DEBUG "${the_module}${OPENCV_DLLVERSION}${OPENCV_DEBUG_POSTFIX}"
      ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
 +    COMPILE_PDB_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
      LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
      RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
-     INSTALL_NAME_DIR lib
    )
  
    # For dynamic link numbering convenions
Simple merge
index 2f4a62b,0000000..d5d175f
mode 100644,000000..100644
--- /dev/null
@@@ -1,449 -1,0 +1,447 @@@
-     uchar* data = img.ptr();
-     int step = (int)img.step;
 +/*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.
 +//
 +//
 +//                           License Agreement
 +//                For Open Source Computer Vision Library
 +//
 +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
 +// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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_PNG
 +
 +/****************************************************************************************\
 +    This part of the file implements PNG codec on base of libpng library,
 +    in particular, this code is based on example.c from libpng
 +    (see otherlibs/_graphics/readme.txt for copyright notice)
 +    and png2bmp sample from libpng distribution (Copyright (C) 1999-2001 MIYASAKA Masaru)
 +\****************************************************************************************/
 +
 +#ifndef _LFS64_LARGEFILE
 +#  define _LFS64_LARGEFILE 0
 +#endif
 +#ifndef _FILE_OFFSET_BITS
 +#  define _FILE_OFFSET_BITS 0
 +#endif
 +
 +#ifdef HAVE_LIBPNG_PNG_H
 +#include <libpng/png.h>
 +#else
 +#include <png.h>
 +#endif
 +#include <zlib.h>
 +
 +#include "grfmt_png.hpp"
 +
 +#if defined _MSC_VER && _MSC_VER >= 1200
 +    // interaction between '_setjmp' and C++ object destruction is non-portable
 +    #pragma warning( disable: 4611 )
 +#endif
 +
 +// the following defines are a hack to avoid multiple problems with frame ponter handling and setjmp
 +// see http://gcc.gnu.org/ml/gcc/2011-10/msg00324.html for some details
 +#define mingw_getsp(...) 0
 +#define __builtin_frame_address(...) 0
 +
 +namespace cv
 +{
 +
 +/////////////////////// PngDecoder ///////////////////
 +
 +PngDecoder::PngDecoder()
 +{
 +    m_signature = "\x89\x50\x4e\x47\xd\xa\x1a\xa";
 +    m_color_type = 0;
 +    m_png_ptr = 0;
 +    m_info_ptr = m_end_info = 0;
 +    m_f = 0;
 +    m_buf_supported = true;
 +    m_buf_pos = 0;
 +}
 +
 +
 +PngDecoder::~PngDecoder()
 +{
 +    close();
 +}
 +
 +ImageDecoder PngDecoder::newDecoder() const
 +{
 +    return makePtr<PngDecoder>();
 +}
 +
 +void  PngDecoder::close()
 +{
 +    if( m_f )
 +    {
 +        fclose( m_f );
 +        m_f = 0;
 +    }
 +
 +    if( m_png_ptr )
 +    {
 +        png_structp png_ptr = (png_structp)m_png_ptr;
 +        png_infop info_ptr = (png_infop)m_info_ptr;
 +        png_infop end_info = (png_infop)m_end_info;
 +        png_destroy_read_struct( &png_ptr, &info_ptr, &end_info );
 +        m_png_ptr = m_info_ptr = m_end_info = 0;
 +    }
 +}
 +
 +
 +void  PngDecoder::readDataFromBuf( void* _png_ptr, uchar* dst, size_t size )
 +{
 +    png_structp png_ptr = (png_structp)_png_ptr;
 +    PngDecoder* decoder = (PngDecoder*)(png_get_io_ptr(png_ptr));
 +    CV_Assert( decoder );
 +    const Mat& buf = decoder->m_buf;
 +    if( decoder->m_buf_pos + size > buf.cols*buf.rows*buf.elemSize() )
 +    {
 +        png_error(png_ptr, "PNG input buffer is incomplete");
 +        return;
 +    }
 +    memcpy( dst, decoder->m_buf.ptr() + decoder->m_buf_pos, size );
 +    decoder->m_buf_pos += size;
 +}
 +
 +bool  PngDecoder::readHeader()
 +{
 +    volatile bool result = false;
 +    close();
 +
 +    png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
 +
 +    if( png_ptr )
 +    {
 +        png_infop info_ptr = png_create_info_struct( png_ptr );
 +        png_infop end_info = png_create_info_struct( png_ptr );
 +
 +        m_png_ptr = png_ptr;
 +        m_info_ptr = info_ptr;
 +        m_end_info = end_info;
 +        m_buf_pos = 0;
 +
 +        if( info_ptr && end_info )
 +        {
 +            if( setjmp( png_jmpbuf( png_ptr ) ) == 0 )
 +            {
 +                if( !m_buf.empty() )
 +                    png_set_read_fn(png_ptr, this, (png_rw_ptr)readDataFromBuf );
 +                else
 +                {
 +                    m_f = fopen( m_filename.c_str(), "rb" );
 +                    if( m_f )
 +                        png_init_io( png_ptr, m_f );
 +                }
 +
 +                if( !m_buf.empty() || m_f )
 +                {
 +                    png_uint_32 wdth, hght;
 +                    int bit_depth, color_type, num_trans=0;
 +                    png_bytep trans;
 +                    png_color_16p trans_values;
 +
 +                    png_read_info( png_ptr, info_ptr );
 +
 +                    png_get_IHDR( png_ptr, info_ptr, &wdth, &hght,
 +                                  &bit_depth, &color_type, 0, 0, 0 );
 +
 +                    m_width = (int)wdth;
 +                    m_height = (int)hght;
 +                    m_color_type = color_type;
 +                    m_bit_depth = bit_depth;
 +
 +                    if( bit_depth <= 8 || bit_depth == 16 )
 +                    {
 +                        switch(color_type)
 +                        {
 +                            case PNG_COLOR_TYPE_RGB:
 +                                m_type = CV_8UC3;
 +                                break;
 +                            case PNG_COLOR_TYPE_PALETTE:
 +                                png_get_tRNS( png_ptr, info_ptr, &trans, &num_trans, &trans_values);
 +                                //Check if there is a transparency value in the palette
 +                                if ( num_trans > 0 )
 +                                    m_type = CV_8UC4;
 +                                else
 +                                    m_type = CV_8UC3;
 +                                break;
 +                            case PNG_COLOR_TYPE_RGB_ALPHA:
 +                                m_type = CV_8UC4;
 +                                break;
 +                            default:
 +                                m_type = CV_8UC1;
 +                        }
 +                        if( bit_depth == 16 )
 +                            m_type = CV_MAKETYPE(CV_16U, CV_MAT_CN(m_type));
 +                        result = true;
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    if( !result )
 +        close();
 +
 +    return result;
 +}
 +
 +
 +bool  PngDecoder::readData( Mat& img )
 +{
 +    volatile bool result = false;
 +    AutoBuffer<uchar*> _buffer(m_height);
 +    uchar** buffer = _buffer;
 +    int color = img.channels() > 1;
-                 buffer[y] = data + y*step;
 +
 +    if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
 +    {
 +        png_structp png_ptr = (png_structp)m_png_ptr;
 +        png_infop info_ptr = (png_infop)m_info_ptr;
 +        png_infop end_info = (png_infop)m_end_info;
 +
 +        if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
 +        {
 +            int y;
 +
 +            if( img.depth() == CV_8U && m_bit_depth == 16 )
 +                png_set_strip_16( png_ptr );
 +            else if( !isBigEndian() )
 +                png_set_swap( png_ptr );
 +
 +            if(img.channels() < 4)
 +            {
 +                /* observation: png_read_image() writes 400 bytes beyond
 +                 * end of data when reading a 400x118 color png
 +                 * "mpplus_sand.png".  OpenCV crashes even with demo
 +                 * programs.  Looking at the loaded image I'd say we get 4
 +                 * bytes per pixel instead of 3 bytes per pixel.  Test
 +                 * indicate that it is a good idea to always ask for
 +                 * stripping alpha..  18.11.2004 Axel Walthelm
 +                 */
 +                 png_set_strip_alpha( png_ptr );
 +            }
 +
 +            if( m_color_type == PNG_COLOR_TYPE_PALETTE )
 +                png_set_palette_to_rgb( png_ptr );
 +
 +            if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
 +#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \
 +    (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18)
 +                png_set_expand_gray_1_2_4_to_8( png_ptr );
 +#else
 +                png_set_gray_1_2_4_to_8( png_ptr );
 +#endif
 +
 +            if( CV_MAT_CN(m_type) > 1 && color )
 +                png_set_bgr( png_ptr ); // convert RGB to BGR
 +            else if( color )
 +                png_set_gray_to_rgb( png_ptr ); // Gray->RGB
 +            else
 +                png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray
 +
 +            png_set_interlace_handling( png_ptr );
 +            png_read_update_info( png_ptr, info_ptr );
 +
 +            for( y = 0; y < m_height; y++ )
++                buffer[y] = img.data + y*img.step;
 +
 +            png_read_image( png_ptr, buffer );
 +            png_read_end( png_ptr, end_info );
 +
 +            result = true;
 +        }
 +    }
 +
 +    close();
 +    return result;
 +}
 +
 +
 +/////////////////////// PngEncoder ///////////////////
 +
 +
 +PngEncoder::PngEncoder()
 +{
 +    m_description = "Portable Network Graphics files (*.png)";
 +    m_buf_supported = true;
 +}
 +
 +
 +PngEncoder::~PngEncoder()
 +{
 +}
 +
 +
 +bool  PngEncoder::isFormatSupported( int depth ) const
 +{
 +    return depth == CV_8U || depth == CV_16U;
 +}
 +
 +ImageEncoder PngEncoder::newEncoder() const
 +{
 +    return makePtr<PngEncoder>();
 +}
 +
 +
 +void PngEncoder::writeDataToBuf(void* _png_ptr, uchar* src, size_t size)
 +{
 +    if( size == 0 )
 +        return;
 +    png_structp png_ptr = (png_structp)_png_ptr;
 +    PngEncoder* encoder = (PngEncoder*)(png_get_io_ptr(png_ptr));
 +    CV_Assert( encoder && encoder->m_buf );
 +    size_t cursz = encoder->m_buf->size();
 +    encoder->m_buf->resize(cursz + size);
 +    memcpy( &(*encoder->m_buf)[cursz], src, size );
 +}
 +
 +
 +void PngEncoder::flushBuf(void*)
 +{
 +}
 +
 +bool  PngEncoder::write( const Mat& img, const std::vector<int>& params )
 +{
 +    png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 );
 +    png_infop info_ptr = 0;
 +    FILE * volatile f = 0;
 +    int y, width = img.cols, height = img.rows;
 +    int depth = img.depth(), channels = img.channels();
 +    volatile bool result = false;
 +    AutoBuffer<uchar*> buffer;
 +
 +    if( depth != CV_8U && depth != CV_16U )
 +        return false;
 +
 +    if( png_ptr )
 +    {
 +        info_ptr = png_create_info_struct( png_ptr );
 +
 +        if( info_ptr )
 +        {
 +            if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
 +            {
 +                if( m_buf )
 +                {
 +                    png_set_write_fn(png_ptr, this,
 +                        (png_rw_ptr)writeDataToBuf, (png_flush_ptr)flushBuf);
 +                }
 +                else
 +                {
 +                    f = fopen( m_filename.c_str(), "wb" );
 +                    if( f )
 +                        png_init_io( png_ptr, (png_FILE_p)f );
 +                }
 +
 +                int compression_level = -1; // Invalid value to allow setting 0-9 as valid
 +                int compression_strategy = Z_RLE; // Default strategy
 +                bool isBilevel = false;
 +
 +                for( size_t i = 0; i < params.size(); i += 2 )
 +                {
 +                    if( params[i] == CV_IMWRITE_PNG_COMPRESSION )
 +                    {
 +                        compression_level = params[i+1];
 +                        compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION);
 +                    }
 +                    if( params[i] == CV_IMWRITE_PNG_STRATEGY )
 +                    {
 +                        compression_strategy = params[i+1];
 +                        compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED);
 +                    }
 +                    if( params[i] == CV_IMWRITE_PNG_BILEVEL )
 +                    {
 +                        isBilevel = params[i+1] != 0;
 +                    }
 +                }
 +
 +                if( m_buf || f )
 +                {
 +                    if( compression_level >= 0 )
 +                    {
 +                        png_set_compression_level( png_ptr, compression_level );
 +                    }
 +                    else
 +                    {
 +                        // tune parameters for speed
 +                        // (see http://wiki.linuxquestions.org/wiki/Libpng)
 +                        png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_FILTER_SUB);
 +                        png_set_compression_level(png_ptr, Z_BEST_SPEED);
 +                    }
 +                    png_set_compression_strategy(png_ptr, compression_strategy);
 +
 +                    png_set_IHDR( png_ptr, info_ptr, width, height, depth == CV_8U ? isBilevel?1:8 : 16,
 +                        channels == 1 ? PNG_COLOR_TYPE_GRAY :
 +                        channels == 3 ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGBA,
 +                        PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
 +                        PNG_FILTER_TYPE_DEFAULT );
 +
 +                    png_write_info( png_ptr, info_ptr );
 +
 +                    if (isBilevel)
 +                        png_set_packing(png_ptr);
 +
 +                    png_set_bgr( png_ptr );
 +                    if( !isBigEndian() )
 +                        png_set_swap( png_ptr );
 +
 +                    buffer.allocate(height);
 +                    for( y = 0; y < height; y++ )
 +                        buffer[y] = img.data + y*img.step;
 +
 +                    png_write_image( png_ptr, buffer );
 +                    png_write_end( png_ptr, info_ptr );
 +
 +                    result = true;
 +                }
 +            }
 +        }
 +    }
 +
 +    png_destroy_write_struct( &png_ptr, &info_ptr );
 +    if(f) fclose( (FILE*)f );
 +
 +    return result;
 +}
 +
 +}
 +
 +#endif
 +
 +/* End of file. */
@@@ -1010,8 -349,8 +1010,8 @@@ pyrUp_( const Mat& _src, Mat& _dst, int
          for( ; sy <= y + 1; sy++ )
          {
              WT* row = buf + ((sy - sy0) % PU_SZ)*bufstep;
-             int _sy = borderInterpolate(sy*2, dsize.height, BORDER_REFLECT_101)/2;
+             int _sy = borderInterpolate(sy*2, ssize.height*2, BORDER_REFLECT_101)/2;
 -            const T* src = (const T*)(_src.data + _src.step*_sy);
 +            const T* src = _src.ptr<T>(_sy);
  
              if( ssize.width == cn )
              {
@@@ -370,29 -311,18 +370,28 @@@ if(BUILD_FAT_JAVA_LIB
    endif()
    if(APPLE)
      foreach(_dep ${__deps})
 -      target_link_libraries(${the_module} -Wl,-force_load "${_dep}")
 +      ocv_target_link_libraries(${the_module} -Wl,-force_load "${_dep}")
      endforeach()
    else()
 -    target_link_libraries(${the_module} -Wl,-whole-archive ${__deps} -Wl,-no-whole-archive)
 +    ocv_target_link_libraries(${the_module} -Wl,-whole-archive ${__deps} -Wl,-no-whole-archive)
    endif()
 -  target_link_libraries(${the_module} ${__extradeps} ${OPENCV_LINKER_LIBS})
 +  ocv_target_link_libraries(${the_module} ${__extradeps} ${OPENCV_LINKER_LIBS})
  else()
 -  target_link_libraries(${the_module} ${OPENCV_MODULE_${the_module}_DEPS} ${OPENCV_LINKER_LIBS})
 +  ocv_target_link_libraries(${the_module} ${OPENCV_MODULE_${the_module}_DEPS} ${OPENCV_LINKER_LIBS})
  endif()
  
-     INSTALL_NAME_DIR ${OPENCV_LIB_INSTALL_PATH}
 +# Additional target properties
 +set_target_properties(${the_module} PROPERTIES
 +    OUTPUT_NAME "${the_module}${LIB_NAME_SUFIX}"
 +    ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
 +    LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
 +    RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
 +    LINK_INTERFACE_LIBRARIES ""
 +    )
 +
  if(ANDROID)
 -  target_link_libraries(${the_module} jnigraphics) # for Mat <=> Bitmap converters
 +  ocv_target_link_libraries(${the_module} jnigraphics) # for Mat <=> Bitmap converters
 +  ocv_target_link_libraries(${the_module} LINK_INTERFACE_LIBRARIES ${OPENCV_LINKER_LIBS} jnigraphics)
  
    # force strip library after the build command
    # because samples and tests will make a copy of the library before install
index dbb7cf9,0000000..8ac33d7
mode 100644,000000..100644
--- /dev/null
@@@ -1,2786 -1,0 +1,2768 @@@
-     Image_FFMPEG      temp_image;
 +/*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.
 +//
 +//
 +//                          License Agreement
 +//                For Open Source Computer Vision Library
 +//
 +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
 +// Copyright (C) 2009, Willow Garage Inc., 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 the copyright holders 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 "cap_ffmpeg_api.hpp"
 +#if !(defined(WIN32) || defined(_WIN32) || defined(WINCE))
 +# include <pthread.h>
 +#endif
 +#include <assert.h>
 +#include <algorithm>
 +#include <limits>
 +
 +#define CALC_FFMPEG_VERSION(a,b,c) ( a<<16 | b<<8 | c )
 +
 +#if defined _MSC_VER && _MSC_VER >= 1200
 +#pragma warning( disable: 4244 4510 4512 4610 )
 +#endif
 +
 +#ifdef __GNUC__
 +#  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 +#endif
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#include "ffmpeg_codecs.hpp"
 +
 +#include <libavutil/mathematics.h>
 +
 +#if LIBAVUTIL_BUILD > CALC_FFMPEG_VERSION(51,11,0)
 +  #include <libavutil/opt.h>
 +#endif
 +
 +#if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(51, 63, 100) : CALC_FFMPEG_VERSION(54, 6, 0))
 +#include <libavutil/imgutils.h>
 +#endif
 +
 +#ifdef WIN32
 +  #define HAVE_FFMPEG_SWSCALE 1
 +  #include <libavcodec/avcodec.h>
 +  #include <libswscale/swscale.h>
 +#else
 +
 +#ifndef HAVE_FFMPEG_SWSCALE
 +    #error "libswscale is necessary to build the newer OpenCV ffmpeg wrapper"
 +#endif
 +
 +// 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
 +  #if defined(HAVE_FFMPEG_SWSCALE)
 +    #define HAVE_LIBSWSCALE_SWSCALE_H 1
 +  #endif
 +#elif defined HAVE_FFMPEG
 +  #define HAVE_FFMPEG_AVCODEC_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_SWSCALE_H)
 +  #include <ffmpeg/swscale.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
 +
 +#ifdef __cplusplus
 +}
 +#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
 +
 +#if defined WIN32 || defined _WIN32
 +    #include <windows.h>
 +    #if defined _MSC_VER && _MSC_VER < 1900
 +    struct timespec
 +    {
 +        time_t tv_sec;
 +        long   tv_nsec;
 +    };
 +  #endif
 +#elif defined __linux__ || defined __APPLE__
 +    #include <unistd.h>
 +    #include <stdio.h>
 +    #include <sys/types.h>
 +    #include <sys/time.h>
 +#if defined __APPLE__
 +    #include <sys/sysctl.h>
 +    #include <mach/clock.h>
 +    #include <mach/mach.h>
 +#endif
 +#endif
 +
 +#ifndef MIN
 +#define MIN(a, b) ((a) < (b) ? (a) : (b))
 +#endif
 +
 +#if defined(__APPLE__)
 +#define AV_NOPTS_VALUE_ ((int64_t)0x8000000000000000LL)
 +#else
 +#define AV_NOPTS_VALUE_ ((int64_t)AV_NOPTS_VALUE)
 +#endif
 +
 +#ifndef AVERROR_EOF
 +#define AVERROR_EOF (-MKTAG( 'E','O','F',' '))
 +#endif
 +
 +#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(54,25,0)
 +#  define CV_CODEC_ID AVCodecID
 +#  define CV_CODEC(name) AV_##name
 +#else
 +#  define CV_CODEC_ID CodecID
 +#  define CV_CODEC(name) name
 +#endif
 +
 +#if LIBAVUTIL_BUILD < (LIBAVUTIL_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(51, 74, 100) : CALC_FFMPEG_VERSION(51, 42, 0))
 +#define AVPixelFormat PixelFormat
 +#define AV_PIX_FMT_BGR24 PIX_FMT_BGR24
 +#define AV_PIX_FMT_RGB24 PIX_FMT_RGB24
 +#define AV_PIX_FMT_GRAY8 PIX_FMT_GRAY8
 +#define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
 +#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
 +#define AV_PIX_FMT_YUV444P PIX_FMT_YUV444P
 +#define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P
 +#define AV_PIX_FMT_GRAY16LE PIX_FMT_GRAY16LE
 +#define AV_PIX_FMT_GRAY16BE PIX_FMT_GRAY16BE
 +#endif
 +
 +#if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(52, 38, 100) : CALC_FFMPEG_VERSION(52, 13, 0))
 +#define USE_AV_FRAME_GET_BUFFER 1
 +#else
 +#define USE_AV_FRAME_GET_BUFFER 0
 +#ifndef AV_NUM_DATA_POINTERS // required for 0.7.x/0.8.x ffmpeg releases
 +#define AV_NUM_DATA_POINTERS 4
 +#endif
 +#endif
 +
 +
 +#ifndef USE_AV_INTERRUPT_CALLBACK
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 21, 0)
 +#define USE_AV_INTERRUPT_CALLBACK 1
 +#else
 +#define USE_AV_INTERRUPT_CALLBACK 0
 +#endif
 +#endif
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +#define LIBAVFORMAT_INTERRUPT_OPEN_TIMEOUT_MS 30000
 +#define LIBAVFORMAT_INTERRUPT_READ_TIMEOUT_MS 30000
 +
 +#ifdef WIN32
 +// http://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows
 +
 +static
 +inline LARGE_INTEGER get_filetime_offset()
 +{
 +    SYSTEMTIME s;
 +    FILETIME f;
 +    LARGE_INTEGER t;
 +
 +    s.wYear = 1970;
 +    s.wMonth = 1;
 +    s.wDay = 1;
 +    s.wHour = 0;
 +    s.wMinute = 0;
 +    s.wSecond = 0;
 +    s.wMilliseconds = 0;
 +    SystemTimeToFileTime(&s, &f);
 +    t.QuadPart = f.dwHighDateTime;
 +    t.QuadPart <<= 32;
 +    t.QuadPart |= f.dwLowDateTime;
 +    return t;
 +}
 +
 +static
 +inline void get_monotonic_time(timespec *tv)
 +{
 +    LARGE_INTEGER           t;
 +    FILETIME                          f;
 +    double                  microseconds;
 +    static LARGE_INTEGER    offset;
 +    static double           frequencyToMicroseconds;
 +    static int              initialized = 0;
 +    static BOOL             usePerformanceCounter = 0;
 +
 +    if (!initialized)
 +    {
 +        LARGE_INTEGER performanceFrequency;
 +        initialized = 1;
 +        usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
 +        if (usePerformanceCounter)
 +        {
 +            QueryPerformanceCounter(&offset);
 +            frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
 +        }
 +        else
 +        {
 +            offset = get_filetime_offset();
 +            frequencyToMicroseconds = 10.;
 +        }
 +    }
 +
 +    if (usePerformanceCounter)
 +    {
 +        QueryPerformanceCounter(&t);
 +    } else {
 +        GetSystemTimeAsFileTime(&f);
 +        t.QuadPart = f.dwHighDateTime;
 +        t.QuadPart <<= 32;
 +        t.QuadPart |= f.dwLowDateTime;
 +    }
 +
 +    t.QuadPart -= offset.QuadPart;
 +    microseconds = (double)t.QuadPart / frequencyToMicroseconds;
 +    t.QuadPart = microseconds;
 +    tv->tv_sec = t.QuadPart / 1000000;
 +    tv->tv_nsec = (t.QuadPart % 1000000) * 1000;
 +}
 +#else
 +static
 +inline void get_monotonic_time(timespec *time)
 +{
 +#if defined(__APPLE__) && defined(__MACH__)
 +    clock_serv_t cclock;
 +    mach_timespec_t mts;
 +    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
 +    clock_get_time(cclock, &mts);
 +    mach_port_deallocate(mach_task_self(), cclock);
 +    time->tv_sec = mts.tv_sec;
 +    time->tv_nsec = mts.tv_nsec;
 +#else
 +    clock_gettime(CLOCK_MONOTONIC, time);
 +#endif
 +}
 +#endif
 +
 +static
 +inline timespec get_monotonic_time_diff(timespec start, timespec end)
 +{
 +    timespec temp;
 +    if (end.tv_nsec - start.tv_nsec < 0)
 +    {
 +        temp.tv_sec = end.tv_sec - start.tv_sec - 1;
 +        temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
 +    }
 +    else
 +    {
 +        temp.tv_sec = end.tv_sec - start.tv_sec;
 +        temp.tv_nsec = end.tv_nsec - start.tv_nsec;
 +    }
 +    return temp;
 +}
 +
 +static
 +inline double get_monotonic_time_diff_ms(timespec time1, timespec time2)
 +{
 +    timespec delta = get_monotonic_time_diff(time1, time2);
 +    double milliseconds = delta.tv_sec * 1000 + (double)delta.tv_nsec / 1000000.0;
 +
 +    return milliseconds;
 +}
 +#endif // USE_AV_INTERRUPT_CALLBACK
 +
 +static int get_number_of_cpus(void)
 +{
 +#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(52, 111, 0)
 +    return 1;
 +#elif defined WIN32 || defined _WIN32
 +    SYSTEM_INFO sysinfo;
 +    GetSystemInfo( &sysinfo );
 +
 +    return (int)sysinfo.dwNumberOfProcessors;
 +#elif defined __linux__
 +    return (int)sysconf( _SC_NPROCESSORS_ONLN );
 +#elif defined __APPLE__
 +    int numCPU=0;
 +    int mib[4];
 +    size_t len = sizeof(numCPU);
 +
 +    // set the mib for hw.ncpu
 +    mib[0] = CTL_HW;
 +    mib[1] = HW_AVAILCPU;  // alternatively, try HW_NCPU;
 +
 +    // get the number of CPUs from the system
 +    sysctl(mib, 2, &numCPU, &len, NULL, 0);
 +
 +    if( numCPU < 1 )
 +    {
 +        mib[1] = HW_NCPU;
 +        sysctl( mib, 2, &numCPU, &len, NULL, 0 );
 +
 +        if( numCPU < 1 )
 +            numCPU = 1;
 +    }
 +
 +    return (int)numCPU;
 +#else
 +    return 1;
 +#endif
 +}
 +
 +
 +struct Image_FFMPEG
 +{
 +    unsigned char* data;
 +    int step;
 +    int width;
 +    int height;
 +    int cn;
 +};
 +
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +struct AVInterruptCallbackMetadata
 +{
 +    timespec value;
 +    unsigned int timeout_after_ms;
 +    int timeout;
 +};
 +
 +static
 +inline void _opencv_ffmpeg_free(void** ptr)
 +{
 +    if(*ptr) free(*ptr);
 +    *ptr = 0;
 +}
 +
 +static
 +inline int _opencv_ffmpeg_interrupt_callback(void *ptr)
 +{
 +    AVInterruptCallbackMetadata* metadata = (AVInterruptCallbackMetadata*)ptr;
 +    assert(metadata);
 +
 +    if (metadata->timeout_after_ms == 0)
 +    {
 +        return 0; // timeout is disabled
 +    }
 +
 +    timespec now;
 +    get_monotonic_time(&now);
 +
 +    metadata->timeout = get_monotonic_time_diff_ms(metadata->value, now) > metadata->timeout_after_ms;
 +
 +    return metadata->timeout ? -1 : 0;
 +}
 +#endif
 +
 +static
 +inline void _opencv_ffmpeg_av_packet_unref(AVPacket *pkt)
 +{
 +#if LIBAVCODEC_BUILD >= (LIBAVCODEC_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(55, 25, 100) : CALC_FFMPEG_VERSION(55, 16, 0))
 +    av_packet_unref(pkt);
 +#else
 +    av_free_packet(pkt);
 +#endif
 +};
 +
 +static
 +inline void _opencv_ffmpeg_av_image_fill_arrays(void *frame, uint8_t *ptr, enum AVPixelFormat pix_fmt, int width, int height)
 +{
 +#if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(51, 63, 100) : CALC_FFMPEG_VERSION(54, 6, 0))
 +    av_image_fill_arrays(((AVFrame*)frame)->data, ((AVFrame*)frame)->linesize, ptr, pix_fmt, width, height, 1);
 +#else
 +    avpicture_fill((AVPicture*)frame, ptr, pix_fmt, width, height);
 +#endif
 +};
 +
 +static
 +inline int _opencv_ffmpeg_av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height)
 +{
 +#if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(51, 63, 100) : CALC_FFMPEG_VERSION(54, 6, 0))
 +    return av_image_get_buffer_size(pix_fmt, width, height, 1);
 +#else
 +    return avpicture_get_size(pix_fmt, width, height);
 +#endif
 +};
 +
 +
 +struct CvCapture_FFMPEG
 +{
 +    bool open( const char* filename );
 +    void close();
 +
 +    double getProperty(int) const;
 +    bool setProperty(int, double);
 +    bool grabFrame();
 +    bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn);
 +
 +    void init();
 +
 +    void    seek(int64_t frame_number);
 +    void    seek(double sec);
 +    bool    slowSeek( int framenumber );
 +
 +    int64_t get_total_frames() const;
 +    double  get_duration_sec() const;
 +    double  get_fps() const;
 +    int     get_bitrate() const;
 +    AVRational get_sample_aspect_ratio(AVStream *stream) const;
 +
 +    double  r2d(AVRational r) const;
 +    int64_t dts_to_frame_number(int64_t dts);
 +    double  dts_to_sec(int64_t dts);
 +
 +    AVFormatContext * ic;
 +    AVCodec         * avcodec;
 +    int               video_stream;
 +    AVStream        * video_st;
 +    AVFrame         * picture;
 +    AVFrame           rgb_picture;
 +    int64_t           picture_pts;
 +
 +    AVPacket          packet;
 +    Image_FFMPEG      frame;
 +    struct SwsContext *img_convert_ctx;
 +
 +    int64_t frame_number, first_frame_number;
 +
 +    double eps_zero;
 +/*
 +   '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;
 +
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
 +    AVDictionary *dict;
 +#endif
 +#if USE_AV_INTERRUPT_CALLBACK
 +    AVInterruptCallbackMetadata interrupt_metadata;
 +#endif
 +};
 +
 +void CvCapture_FFMPEG::init()
 +{
 +    ic = 0;
 +    video_stream = -1;
 +    video_st = 0;
 +    picture = 0;
 +    picture_pts = AV_NOPTS_VALUE_;
 +    first_frame_number = -1;
 +    memset( &rgb_picture, 0, sizeof(rgb_picture) );
 +    memset( &frame, 0, sizeof(frame) );
 +    filename = 0;
 +    memset(&packet, 0, sizeof(packet));
 +    av_init_packet(&packet);
 +    img_convert_ctx = 0;
 +
 +    avcodec = 0;
 +    frame_number = 0;
 +    eps_zero = 0.000025;
 +
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
 +    dict = NULL;
 +#endif
 +}
 +
 +
 +void CvCapture_FFMPEG::close()
 +{
 +    if( img_convert_ctx )
 +    {
 +        sws_freeContext(img_convert_ctx);
 +        img_convert_ctx = 0;
 +    }
 +
 +    if( picture )
 +    {
 +#if LIBAVCODEC_BUILD >= (LIBAVCODEC_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(55, 45, 101) : CALC_FFMPEG_VERSION(55, 28, 1))
 +        av_frame_free(&picture);
 +#elif LIBAVCODEC_BUILD >= (LIBAVCODEC_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(54, 59, 100) : CALC_FFMPEG_VERSION(54, 28, 0))
 +        avcodec_free_frame(&picture);
 +#else
 +        av_free(picture);
 +#endif
 +    }
 +
 +    if( video_st )
 +    {
 +#if LIBAVFORMAT_BUILD > 4628
 +        avcodec_close( video_st->codec );
 +
 +#else
 +        avcodec_close( &(video_st->codec) );
 +
 +#endif
 +        video_st = NULL;
 +    }
 +
 +    if( ic )
 +    {
 +#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 24, 2)
 +        av_close_input_file(ic);
 +#else
 +        avformat_close_input(&ic);
 +#endif
 +
 +        ic = NULL;
 +    }
 +
 +#if USE_AV_FRAME_GET_BUFFER
 +    av_frame_unref(&rgb_picture);
 +#else
 +    if( rgb_picture.data[0] )
 +    {
 +        free( rgb_picture.data[0] );
 +        rgb_picture.data[0] = 0;
 +    }
 +#endif
 +
 +    // free last packet if exist
 +    if (packet.data) {
 +        _opencv_ffmpeg_av_packet_unref (&packet);
 +        packet.data = NULL;
 +    }
 +
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
 +    if (dict != NULL)
 +       av_dict_free(&dict);
 +#endif
 +
 +    init();
 +}
 +
 +
 +#ifndef AVSEEK_FLAG_FRAME
 +#define AVSEEK_FLAG_FRAME 0
 +#endif
 +#ifndef AVSEEK_FLAG_ANY
 +#define AVSEEK_FLAG_ANY 1
 +#endif
 +
 +class ImplMutex
 +{
 +public:
 +    ImplMutex() { init(); }
 +    ~ImplMutex() { destroy(); }
 +
 +    void init();
 +    void destroy();
 +
 +    void lock();
 +    bool trylock();
 +    void unlock();
 +
 +    struct Impl;
 +protected:
 +    Impl* impl;
 +
 +private:
 +    ImplMutex(const ImplMutex&);
 +    ImplMutex& operator = (const ImplMutex& m);
 +};
 +
 +#if defined WIN32 || defined _WIN32 || defined WINCE
 +
 +struct ImplMutex::Impl
 +{
 +    void init()
 +    {
 +#if (_WIN32_WINNT >= 0x0600)
 +        ::InitializeCriticalSectionEx(&cs, 1000, 0);
 +#else
 +        ::InitializeCriticalSection(&cs);
 +#endif
 +        refcount = 1;
 +    }
 +    void destroy() { DeleteCriticalSection(&cs); }
 +
 +    void lock() { EnterCriticalSection(&cs); }
 +    bool trylock() { return TryEnterCriticalSection(&cs) != 0; }
 +    void unlock() { LeaveCriticalSection(&cs); }
 +
 +    CRITICAL_SECTION cs;
 +    int refcount;
 +};
 +
 +#ifndef __GNUC__
 +static int _interlockedExchangeAdd(int* addr, int delta)
 +{
 +#if defined _MSC_VER && _MSC_VER >= 1500
 +    return (int)_InterlockedExchangeAdd((long volatile*)addr, delta);
 +#else
 +    return (int)InterlockedExchangeAdd((long volatile*)addr, delta);
 +#endif
 +}
 +#endif // __GNUC__
 +
 +#elif defined __APPLE__
 +
 +#include <libkern/OSAtomic.h>
 +
 +struct ImplMutex::Impl
 +{
 +    void init() { sl = OS_SPINLOCK_INIT; refcount = 1; }
 +    void destroy() { }
 +
 +    void lock() { OSSpinLockLock(&sl); }
 +    bool trylock() { return OSSpinLockTry(&sl); }
 +    void unlock() { OSSpinLockUnlock(&sl); }
 +
 +    OSSpinLock sl;
 +    int refcount;
 +};
 +
 +#elif defined __linux__ && !defined ANDROID
 +
 +struct ImplMutex::Impl
 +{
 +    void init() { pthread_spin_init(&sl, 0); refcount = 1; }
 +    void destroy() { pthread_spin_destroy(&sl); }
 +
 +    void lock() { pthread_spin_lock(&sl); }
 +    bool trylock() { return pthread_spin_trylock(&sl) == 0; }
 +    void unlock() { pthread_spin_unlock(&sl); }
 +
 +    pthread_spinlock_t sl;
 +    int refcount;
 +};
 +
 +#else
 +
 +struct ImplMutex::Impl
 +{
 +    void init() { pthread_mutex_init(&sl, 0); refcount = 1; }
 +    void destroy() { pthread_mutex_destroy(&sl); }
 +
 +    void lock() { pthread_mutex_lock(&sl); }
 +    bool trylock() { return pthread_mutex_trylock(&sl) == 0; }
 +    void unlock() { pthread_mutex_unlock(&sl); }
 +
 +    pthread_mutex_t sl;
 +    int refcount;
 +};
 +
 +#endif
 +
 +void ImplMutex::init()
 +{
 +    impl = (Impl*)malloc(sizeof(Impl));
 +    impl->init();
 +}
 +void ImplMutex::destroy()
 +{
 +    impl->destroy();
 +    free(impl);
 +    impl = NULL;
 +}
 +void ImplMutex::lock() { impl->lock(); }
 +void ImplMutex::unlock() { impl->unlock(); }
 +bool ImplMutex::trylock() { return impl->trylock(); }
 +
 +static int LockCallBack(void **mutex, AVLockOp op)
 +{
 +    ImplMutex* localMutex = reinterpret_cast<ImplMutex*>(*mutex);
 +    switch (op)
 +    {
 +        case AV_LOCK_CREATE:
 +            localMutex = reinterpret_cast<ImplMutex*>(malloc(sizeof(ImplMutex)));
 +            localMutex->init();
 +            *mutex = localMutex;
 +            if (!*mutex)
 +                return 1;
 +        break;
 +
 +        case AV_LOCK_OBTAIN:
 +            localMutex->lock();
 +        break;
 +
 +        case AV_LOCK_RELEASE:
 +            localMutex->unlock();
 +        break;
 +
 +        case AV_LOCK_DESTROY:
 +            localMutex->destroy();
 +            free(localMutex);
 +            localMutex = NULL;
 +            *mutex = NULL;
 +        break;
 +    }
 +    return 0;
 +}
 +
 +static ImplMutex _mutex;
 +static bool _initialized = false;
 +
 +class InternalFFMpegRegister
 +{
 +public:
 +    InternalFFMpegRegister()
 +    {
 +        _mutex.lock();
 +        if (!_initialized)
 +        {
 +    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0)
 +            avformat_network_init();
 +    #endif
 +
 +            /* register all codecs, demux and protocols */
 +            av_register_all();
 +
 +            /* register a callback function for synchronization */
 +            av_lockmgr_register(&LockCallBack);
 +
 +            av_log_set_level(AV_LOG_ERROR);
 +
 +            _initialized = true;
 +        }
 +        _mutex.unlock();
 +    }
 +
 +    ~InternalFFMpegRegister()
 +    {
 +        _initialized = false;
 +        av_lockmgr_register(NULL);
 +    }
 +};
 +
 +static InternalFFMpegRegister _init;
 +
 +bool CvCapture_FFMPEG::open( const char* _filename )
 +{
 +    unsigned i;
 +    bool valid = false;
 +
 +    close();
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +    /* interrupt callback */
 +    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_OPEN_TIMEOUT_MS;
 +    get_monotonic_time(&interrupt_metadata.value);
 +
 +    ic = avformat_alloc_context();
 +    ic->interrupt_callback.callback = _opencv_ffmpeg_interrupt_callback;
 +    ic->interrupt_callback.opaque = &interrupt_metadata;
 +#endif
 +
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
 +    av_dict_set(&dict, "rtsp_transport", "tcp", 0);
 +    int err = avformat_open_input(&ic, _filename, NULL, &dict);
 +#else
 +    int err = av_open_input_file(&ic, _filename, NULL, 0, NULL);
 +#endif
 +
 +    if (err < 0)
 +    {
 +        CV_WARN("Error opening file");
 +        CV_WARN(_filename);
 +        goto exit_func;
 +    }
 +    err =
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 6, 0)
 +    avformat_find_stream_info(ic, NULL);
 +#else
 +    av_find_stream_info(ic);
 +#endif
 +    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
 +
 +//#ifdef FF_API_THREAD_INIT
 +//        avcodec_thread_init(enc, get_number_of_cpus());
 +//#else
 +        enc->thread_count = get_number_of_cpus();
 +//#endif
 +
 +#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
 +#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
 +#endif
 +
 +        if( AVMEDIA_TYPE_VIDEO == enc->codec_type && video_stream < 0)
 +        {
 +            // backup encoder' width/height
 +            int enc_width = enc->width;
 +            int enc_height = enc->height;
 +
 +            AVCodec *codec = avcodec_find_decoder(enc->codec_id);
 +            if (!codec ||
 +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0)
 +                avcodec_open2(enc, codec, NULL)
 +#else
 +                avcodec_open(enc, codec)
 +#endif
 +                < 0)
 +                goto exit_func;
 +
 +            // checking width/height (since decoder can sometimes alter it, eg. vp6f)
 +            if (enc_width && (enc->width != enc_width)) { enc->width = enc_width; }
 +            if (enc_height && (enc->height != enc_height)) { enc->height = enc_height; }
 +
 +            video_stream = i;
 +            video_st = ic->streams[i];
 +#if LIBAVCODEC_BUILD >= (LIBAVCODEC_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(55, 45, 101) : CALC_FFMPEG_VERSION(55, 28, 1))
 +            picture = av_frame_alloc();
 +#else
 +            picture = avcodec_alloc_frame();
 +#endif
 +
 +            frame.width = enc->width;
 +            frame.height = enc->height;
 +            frame.cn = 3;
 +            frame.step = 0;
 +            frame.data = NULL;
 +            break;
 +        }
 +    }
 +
 +    if(video_stream >= 0) valid = true;
 +
 +exit_func:
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +    // deactivate interrupt callback
 +    interrupt_metadata.timeout_after_ms = 0;
 +#endif
 +
 +    if( !valid )
 +        close();
 +
 +    return valid;
 +}
 +
 +
 +bool CvCapture_FFMPEG::grabFrame()
 +{
 +    bool valid = false;
 +    int got_picture;
 +
 +    int count_errs = 0;
 +    const int max_number_of_attempts = 1 << 9;
 +
 +    if( !ic || !video_st )  return false;
 +
 +    if( ic->streams[video_stream]->nb_frames > 0 &&
 +        frame_number > ic->streams[video_stream]->nb_frames )
 +        return false;
 +
 +    picture_pts = AV_NOPTS_VALUE_;
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +    // activate interrupt callback
 +    get_monotonic_time(&interrupt_metadata.value);
 +    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_READ_TIMEOUT_MS;
 +#endif
 +
 +    // get the next frame
 +    while (!valid)
 +    {
 +
 +        _opencv_ffmpeg_av_packet_unref (&packet);
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +        if (interrupt_metadata.timeout)
 +        {
 +            valid = false;
 +            break;
 +        }
 +#endif
 +
 +        int ret = av_read_frame(ic, &packet);
 +        if (ret == AVERROR(EAGAIN)) continue;
 +
 +        /* else if (ret < 0) break; */
 +
 +        if( packet.stream_index != video_stream )
 +        {
 +            _opencv_ffmpeg_av_packet_unref (&packet);
 +            count_errs++;
 +            if (count_errs > max_number_of_attempts)
 +                break;
 +            continue;
 +        }
 +
 +        // Decode video frame
 +        #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
 +            avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet);
 +        #elif 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
 +
 +        // Did we get a video frame?
 +        if(got_picture)
 +        {
 +            //picture_pts = picture->best_effort_timestamp;
 +            if( picture_pts == AV_NOPTS_VALUE_ )
 +                picture_pts = packet.pts != AV_NOPTS_VALUE_ && packet.pts != 0 ? packet.pts : packet.dts;
 +            frame_number++;
 +            valid = true;
 +        }
 +        else
 +        {
 +            count_errs++;
 +            if (count_errs > max_number_of_attempts)
 +                break;
 +        }
 +    }
 +
 +    if( valid && first_frame_number < 0 )
 +        first_frame_number = dts_to_frame_number(picture_pts);
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +    // deactivate interrupt callback
 +    interrupt_metadata.timeout_after_ms = 0;
 +#endif
 +
 +    // return if we have a new picture or not
 +    return valid;
 +}
 +
 +
 +bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
 +{
 +    if( !video_st || !picture->data[0] )
 +        return false;
 +
 +    if( img_convert_ctx == NULL ||
 +        frame.width != video_st->codec->width ||
 +        frame.height != video_st->codec->height ||
 +        frame.data == NULL )
 +    {
 +        // Some sws_scale optimizations have some assumptions about alignment of data/step/width/height
 +        // Also we use coded_width/height to workaround problem with legacy ffmpeg versions (like n0.8)
 +        int buffer_width = video_st->codec->coded_width, buffer_height = video_st->codec->coded_height;
 +
 +        img_convert_ctx = sws_getCachedContext(
 +                img_convert_ctx,
 +                buffer_width, buffer_height,
 +                video_st->codec->pix_fmt,
 +                buffer_width, buffer_height,
 +                AV_PIX_FMT_BGR24,
 +                SWS_BICUBIC,
 +                NULL, NULL, NULL
 +                );
 +
 +        if (img_convert_ctx == NULL)
 +            return false;//CV_Error(0, "Cannot initialize the conversion context!");
 +
 +#if USE_AV_FRAME_GET_BUFFER
 +        av_frame_unref(&rgb_picture);
 +        rgb_picture.format = AV_PIX_FMT_BGR24;
 +        rgb_picture.width = buffer_width;
 +        rgb_picture.height = buffer_height;
 +        if (0 != av_frame_get_buffer(&rgb_picture, 32))
 +        {
 +            CV_WARN("OutOfMemory");
 +            return false;
 +        }
 +#else
 +        int aligns[AV_NUM_DATA_POINTERS];
 +        avcodec_align_dimensions2(video_st->codec, &buffer_width, &buffer_height, aligns);
 +        rgb_picture.data[0] = (uint8_t*)realloc(rgb_picture.data[0],
 +                _opencv_ffmpeg_av_image_get_buffer_size( AV_PIX_FMT_BGR24,
 +                                    buffer_width, buffer_height ));
 +        _opencv_ffmpeg_av_image_fill_arrays(&rgb_picture, rgb_picture.data[0],
 +                        AV_PIX_FMT_BGR24, buffer_width, buffer_height );
 +#endif
 +        frame.width = video_st->codec->width;
 +        frame.height = video_st->codec->height;
 +        frame.cn = 3;
 +        frame.data = rgb_picture.data[0];
 +        frame.step = rgb_picture.linesize[0];
 +    }
 +
 +    sws_scale(
 +            img_convert_ctx,
 +            picture->data,
 +            picture->linesize,
 +            0, video_st->codec->coded_height,
 +            rgb_picture.data,
 +            rgb_picture.linesize
 +            );
 +
 +    *data = frame.data;
 +    *step = frame.step;
 +    *width = frame.width;
 +    *height = frame.height;
 +    *cn = frame.cn;
 +
 +    return true;
 +}
 +
 +
 +double CvCapture_FFMPEG::getProperty( int property_id ) const
 +{
 +    if( !video_st ) return 0;
 +
 +    switch( property_id )
 +    {
 +    case CV_FFMPEG_CAP_PROP_POS_MSEC:
 +        return 1000.0*(double)frame_number/get_fps();
 +    case CV_FFMPEG_CAP_PROP_POS_FRAMES:
 +        return (double)frame_number;
 +    case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
 +        return r2d(ic->streams[video_stream]->time_base);
 +    case CV_FFMPEG_CAP_PROP_FRAME_COUNT:
 +        return (double)get_total_frames();
 +    case CV_FFMPEG_CAP_PROP_FRAME_WIDTH:
 +        return (double)frame.width;
 +    case CV_FFMPEG_CAP_PROP_FRAME_HEIGHT:
 +        return (double)frame.height;
 +    case CV_FFMPEG_CAP_PROP_FPS:
 +        return get_fps();
 +    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
 +    case CV_FFMPEG_CAP_PROP_SAR_NUM:
 +        return get_sample_aspect_ratio(ic->streams[video_stream]).num;
 +    case CV_FFMPEG_CAP_PROP_SAR_DEN:
 +        return get_sample_aspect_ratio(ic->streams[video_stream]).den;
 +    default:
 +        break;
 +    }
 +
 +    return 0;
 +}
 +
 +double CvCapture_FFMPEG::r2d(AVRational r) const
 +{
 +    return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;
 +}
 +
 +double CvCapture_FFMPEG::get_duration_sec() const
 +{
 +    double sec = (double)ic->duration / (double)AV_TIME_BASE;
 +
 +    if (sec < eps_zero)
 +    {
 +        sec = (double)ic->streams[video_stream]->duration * r2d(ic->streams[video_stream]->time_base);
 +    }
 +
 +    if (sec < eps_zero)
 +    {
 +        sec = (double)ic->streams[video_stream]->duration * r2d(ic->streams[video_stream]->time_base);
 +    }
 +
 +    return sec;
 +}
 +
 +int CvCapture_FFMPEG::get_bitrate() const
 +{
 +    return ic->bit_rate;
 +}
 +
 +double CvCapture_FFMPEG::get_fps() const
 +{
 +#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(54, 1, 0)
 +    double fps = r2d(ic->streams[video_stream]->avg_frame_rate);
 +#else
 +    double fps = r2d(ic->streams[video_stream]->r_frame_rate);
 +#endif
 +
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
 +    if (fps < eps_zero)
 +    {
 +        fps = r2d(ic->streams[video_stream]->avg_frame_rate);
 +    }
 +#endif
 +
 +    if (fps < eps_zero)
 +    {
 +        fps = 1.0 / r2d(ic->streams[video_stream]->codec->time_base);
 +    }
 +
 +    return fps;
 +}
 +
 +int64_t CvCapture_FFMPEG::get_total_frames() const
 +{
 +    int64_t nbf = ic->streams[video_stream]->nb_frames;
 +
 +    if (nbf == 0)
 +    {
 +        nbf = (int64_t)floor(get_duration_sec() * get_fps() + 0.5);
 +    }
 +    return nbf;
 +}
 +
 +int64_t CvCapture_FFMPEG::dts_to_frame_number(int64_t dts)
 +{
 +    double sec = dts_to_sec(dts);
 +    return (int64_t)(get_fps() * sec + 0.5);
 +}
 +
 +AVRational CvCapture_FFMPEG::get_sample_aspect_ratio(AVStream *stream) const
 +{
 +    AVRational undef = {0, 1};
 +    AVRational stream_sample_aspect_ratio = stream ? stream->sample_aspect_ratio : undef;
 +    AVRational frame_sample_aspect_ratio  = stream && stream->codec ? stream->codec->sample_aspect_ratio : undef;
 +
 +    av_reduce(&stream_sample_aspect_ratio.num, &stream_sample_aspect_ratio.den,
 +        stream_sample_aspect_ratio.num,  stream_sample_aspect_ratio.den, INT_MAX);
 +    if (stream_sample_aspect_ratio.num <= 0 || stream_sample_aspect_ratio.den <= 0)
 +        stream_sample_aspect_ratio = undef;
 +
 +    av_reduce(&frame_sample_aspect_ratio.num, &frame_sample_aspect_ratio.den,
 +        frame_sample_aspect_ratio.num,  frame_sample_aspect_ratio.den, INT_MAX);
 +    if (frame_sample_aspect_ratio.num <= 0 || frame_sample_aspect_ratio.den <= 0)
 +        frame_sample_aspect_ratio = undef;
 +
 +    if (stream_sample_aspect_ratio.num)
 +        return stream_sample_aspect_ratio;
 +    else
 +        return frame_sample_aspect_ratio;
 +}
 +
 +double CvCapture_FFMPEG::dts_to_sec(int64_t dts)
 +{
 +    return (double)(dts - ic->streams[video_stream]->start_time) *
 +        r2d(ic->streams[video_stream]->time_base);
 +}
 +
 +void CvCapture_FFMPEG::seek(int64_t _frame_number)
 +{
 +    _frame_number = std::min(_frame_number, get_total_frames());
 +    int delta = 16;
 +
 +    // if we have not grabbed a single frame before first seek, let's read the first frame
 +    // and get some valuable information during the process
 +    if( first_frame_number < 0 && get_total_frames() > 1 )
 +        grabFrame();
 +
 +    for(;;)
 +    {
 +        int64_t _frame_number_temp = std::max(_frame_number-delta, (int64_t)0);
 +        double sec = (double)_frame_number_temp / get_fps();
 +        int64_t time_stamp = ic->streams[video_stream]->start_time;
 +        double  time_base  = r2d(ic->streams[video_stream]->time_base);
 +        time_stamp += (int64_t)(sec / time_base + 0.5);
 +        if (get_total_frames() > 1) av_seek_frame(ic, video_stream, time_stamp, AVSEEK_FLAG_BACKWARD);
 +        avcodec_flush_buffers(ic->streams[video_stream]->codec);
 +        if( _frame_number > 0 )
 +        {
 +            grabFrame();
 +
 +            if( _frame_number > 1 )
 +            {
 +                frame_number = dts_to_frame_number(picture_pts) - first_frame_number;
 +                //printf("_frame_number = %d, frame_number = %d, delta = %d\n",
 +                //       (int)_frame_number, (int)frame_number, delta);
 +
 +                if( frame_number < 0 || frame_number > _frame_number-1 )
 +                {
 +                    if( _frame_number_temp == 0 || delta >= INT_MAX/4 )
 +                        break;
 +                    delta = delta < 16 ? delta*2 : delta*3/2;
 +                    continue;
 +                }
 +                while( frame_number < _frame_number-1 )
 +                {
 +                    if(!grabFrame())
 +                        break;
 +                }
 +                frame_number++;
 +                break;
 +            }
 +            else
 +            {
 +                frame_number = 1;
 +                break;
 +            }
 +        }
 +        else
 +        {
 +            frame_number = 0;
 +            break;
 +        }
 +    }
 +}
 +
 +void CvCapture_FFMPEG::seek(double sec)
 +{
 +    seek((int64_t)(sec * get_fps() + 0.5));
 +}
 +
 +bool CvCapture_FFMPEG::setProperty( int property_id, double value )
 +{
 +    if( !video_st ) 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((int64_t)value);
 +                break;
 +
 +            case CV_FFMPEG_CAP_PROP_POS_MSEC:
 +                seek(value/1000.0);
 +                break;
 +
 +            case CV_FFMPEG_CAP_PROP_POS_AVI_RATIO:
 +                seek((int64_t)(value*ic->duration));
 +                break;
 +            }
 +
 +            picture_pts=(int64_t)value;
 +        }
 +        break;
 +    default:
 +        return false;
 +    }
 +
 +    return true;
 +}
 +
 +
 +///////////////// 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;
-     memset(&temp_image, 0, sizeof(temp_image));
++    unsigned char   * aligned_input;
 +    int               frame_width, frame_height;
 +    int               frame_idx;
 +    bool              ok;
 +    struct SwsContext *img_convert_ctx;
 +};
 +
 +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 CV_CODEC_ID 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;
-     bool ret = false;
++    aligned_input = NULL;
 +    img_convert_ctx = 0;
 +    frame_width = frame_height = 0;
 +    frame_idx = 0;
 +    ok = false;
 +}
 +
 +/**
 + * 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;
 +
 +#if LIBAVCODEC_BUILD >= (LIBAVCODEC_VERSION_MICRO >= 100 \
 +    ? CALC_FFMPEG_VERSION(55, 45, 101) : CALC_FFMPEG_VERSION(55, 28, 1))
 +    picture = av_frame_alloc();
 +#else
 +    picture = avcodec_alloc_frame();
 +#endif
 +    if (!picture)
 +        return NULL;
 +
 +    picture->format = pix_fmt;
 +    picture->width = width;
 +    picture->height = height;
 +
 +    size = _opencv_ffmpeg_av_image_get_buffer_size( (AVPixelFormat) pix_fmt, width, height);
 +    if(alloc){
 +        picture_buf = (uint8_t *) malloc(size);
 +        if (!picture_buf)
 +        {
 +            av_free(picture);
 +            return NULL;
 +        }
 +        _opencv_ffmpeg_av_image_fill_arrays(picture, picture_buf,
 +                       (AVPixelFormat) pix_fmt, width, height);
 +    }
 +    else {
 +    }
 +    return picture;
 +}
 +
 +/* add a video output stream to the container */
 +static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
 +                                             CV_CODEC_ID 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;
 +
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0)
 +    st = avformat_new_stream(oc, 0);
 +#else
 +    st = av_new_stream(oc, 0);
 +#endif
 +
 +    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 != CV_CODEC(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;
 +
 +#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(54,25,0)
 +    // Set per-codec defaults
 +    AVCodecID c_id = c->codec_id;
 +    avcodec_get_context_defaults3(c, codec);
 +    // avcodec_get_context_defaults3 erases codec_id for some reason
 +    c->codec_id = c_id;
 +#endif
 +
 +    /* put sample parameters */
 +    int64_t lbit_rate = (int64_t)bitrate;
 +    lbit_rate += (bitrate / 2);
 +    lbit_rate = std::min(lbit_rate, (int64_t)INT_MAX);
 +    c->bit_rate = lbit_rate;
 +
 +    // took advice from
 +    // http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html
 +    c->qmin = 3;
 +
 +    /* 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 = (AVPixelFormat) pixel_format;
 +
 +    if (c->codec_id == CV_CODEC(CODEC_ID_MPEG2VIDEO)) {
 +        c->max_b_frames = 2;
 +    }
 +    if (c->codec_id == CV_CODEC(CODEC_ID_MPEG1VIDEO) || c->codec_id == CV_CODEC(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 LIBAVUTIL_BUILD > CALC_FFMPEG_VERSION(51,11,0)
 +    /* Some settings for libx264 encoding, restore dummy values for gop_size
 +     and qmin since they will be set to reasonable defaults by the libx264
 +     preset system. Also, use a crf encode with the default quality rating,
 +     this seems easier than finding an appropriate default bitrate. */
 +    if (c->codec_id == AV_CODEC_ID_H264) {
 +      c->gop_size = -1;
 +      c->qmin = -1;
 +      c->bit_rate = 0;
 +      if (c->priv_data)
 +          av_opt_set(c->priv_data,"crf","23", 0);
 +    }
 +#endif
 +
 +#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;
 +}
 +
 +static const int OPENCV_NO_FRAMES_WRITTEN_CODE = 1000;
 +
 +static int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st,
 +#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(54, 1, 0)
 +                                      uint8_t *, uint32_t,
 +#else
 +                                      uint8_t * outbuf, uint32_t outbuf_size,
 +#endif
 +                                      AVFrame * picture )
 +{
 +#if LIBAVFORMAT_BUILD > 4628
 +    AVCodecContext * c = video_st->codec;
 +#else
 +    AVCodecContext * c = &(video_st->codec);
 +#endif
 +    int ret = OPENCV_NO_FRAMES_WRITTEN_CODE;
 +
 +    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 */
 +        AVPacket pkt;
 +        av_init_packet(&pkt);
 +#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(54, 1, 0)
 +        int got_output = 0;
 +        pkt.data = NULL;
 +        pkt.size = 0;
 +        ret = avcodec_encode_video2(c, &pkt, picture, &got_output);
 +        if (ret < 0)
 +            ;
 +        else if (got_output) {
 +            if (pkt.pts != (int64_t)AV_NOPTS_VALUE)
 +                pkt.pts = av_rescale_q(pkt.pts, c->time_base, video_st->time_base);
 +            if (pkt.dts != (int64_t)AV_NOPTS_VALUE)
 +                pkt.dts = av_rescale_q(pkt.dts, c->time_base, video_st->time_base);
 +            if (pkt.duration)
 +                pkt.duration = av_rescale_q(pkt.duration, c->time_base, video_st->time_base);
 +            pkt.stream_index= video_st->index;
 +            ret = av_write_frame(oc, &pkt);
 +            _opencv_ffmpeg_av_packet_unref(&pkt);
 +        }
 +        else
 +            ret = OPENCV_NO_FRAMES_WRITTEN_CODE;
 +#else
 +        int out_size = avcodec_encode_video(c, outbuf, outbuf_size, picture);
 +        /* if zero size, it means the image was buffered */
 +        if (out_size > 0) {
 +#if LIBAVFORMAT_BUILD > 4752
 +            if(c->coded_frame->pts != (int64_t)AV_NOPTS_VALUE)
 +                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);
 +        }
 +#endif
 +    }
 +    return ret;
 +}
 +
 +/// write a frame with FFMPEG
 +bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin )
 +{
- #if LIBAVFORMAT_BUILD < 5231
-     // It is not needed in the latest versions of the ffmpeg
-     if( c->codec_id == CV_CODEC(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 )
++    // check parameters
++    if (input_pix_fmt == AV_PIX_FMT_BGR24) {
++        if (cn != 3) {
++            return false;
++        }
++    }
++    else if (input_pix_fmt == AV_PIX_FMT_GRAY8) {
++        if (cn != 1) {
++            return false;
++        }
++    }
++    else {
++        assert(false);
++    }
 +
 +    if( (width & -2) != frame_width || (height & -2) != frame_height || !data )
 +        return false;
 +    width = frame_width;
 +    height = frame_height;
 +
 +    // 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( !temp_image.data )
++    // FFmpeg contains SIMD optimizations which can sometimes read data past
++    // the supplied input buffer. To ensure that doesn't happen, we pad the
++    // step to a multiple of 32 (that's the minimal alignment for which Valgrind
++    // doesn't raise any warnings).
++    const int STEP_ALIGNMENT = 32;
++    if( step % STEP_ALIGNMENT != 0 )
 +    {
-             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);
++        int aligned_step = (step + STEP_ALIGNMENT - 1) & -STEP_ALIGNMENT;
++
++        if( !aligned_input )
 +        {
-                 memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, temp_image.step);
++            aligned_input = (unsigned char*)av_mallocz(aligned_step * height);
 +        }
++
 +        if (origin == 1)
 +            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
++                memcpy(aligned_input + y*aligned_step, data + (height-1-y)*step, step);
 +        else
 +            for( int y = 0; y < height; y++ )
-     // check parameters
-     if (input_pix_fmt == AV_PIX_FMT_BGR24) {
-         if (cn != 3) {
-             return false;
-         }
-     }
-     else if (input_pix_fmt == AV_PIX_FMT_GRAY8) {
-         if (cn != 1) {
-             return false;
-         }
-     }
-     else {
-         assert(false);
++                memcpy(aligned_input + y*aligned_step, data + y*step, step);
 +
-     ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0;
++        data = aligned_input;
++        step = aligned_step;
 +    }
 +
 +    if ( c->pix_fmt != input_pix_fmt ) {
 +        assert( input_picture );
 +        // let input_picture point to the raw data buffer of 'image'
 +        _opencv_ffmpeg_av_image_fill_arrays(input_picture, (uint8_t *) data,
 +                       (AVPixelFormat)input_pix_fmt, width, height);
++        input_picture->linesize[0] = step;
 +
 +        if( !img_convert_ctx )
 +        {
 +            img_convert_ctx = sws_getContext(width,
 +                                             height,
 +                                             (AVPixelFormat)input_pix_fmt,
 +                                             c->width,
 +                                             c->height,
 +                                             c->pix_fmt,
 +                                             SWS_BICUBIC,
 +                                             NULL, NULL, NULL);
 +            if( !img_convert_ctx )
 +                return false;
 +        }
 +
 +        if ( sws_scale(img_convert_ctx, input_picture->data,
 +                       input_picture->linesize, 0,
 +                       height,
 +                       picture->data, picture->linesize) < 0 )
 +            return false;
 +    }
 +    else{
 +        _opencv_ffmpeg_av_image_fill_arrays(picture, (uint8_t *) data,
 +                       (AVPixelFormat)input_pix_fmt, width, height);
++        picture->linesize[0] = step;
 +    }
 +
 +    picture->pts = frame_idx;
-     if( temp_image.data )
-     {
-         free(temp_image.data);
-         temp_image.data = 0;
-     }
++    bool ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0;
 +    frame_idx++;
 +
 +    return ret;
 +}
 +
 +/// close video output stream and free associated memory
 +void CvVideoWriter_FFMPEG::close()
 +{
 +    // 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 */
 +    if(ok && oc)
 +    {
 +        if( (oc->oformat->flags & AVFMT_RAWPICTURE) == 0 )
 +        {
 +            for(;;)
 +            {
 +                int ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, NULL);
 +                if( ret == OPENCV_NO_FRAMES_WRITTEN_CODE || ret < 0 )
 +                    break;
 +            }
 +        }
 +        av_write_trailer(oc);
 +    }
 +
 +    if( img_convert_ctx )
 +    {
 +        sws_freeContext(img_convert_ctx);
 +        img_convert_ctx = 0;
 +    }
 +
 +    // 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);
 +
 +    if (!(fmt->flags & AVFMT_NOFILE))
 +    {
 +        /* close the output file */
 +
 +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0)
 +#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0)
 +        url_fclose(oc->pb);
 +#else
 +        url_fclose(&oc->pb);
 +#endif
 +#else
 +        avio_close(oc->pb);
 +#endif
 +
 +    }
 +
 +    /* free the stream */
 +    avformat_free_context(oc);
 +
++    av_freep(&aligned_input);
 +
 +    init();
 +}
 +
 +#define CV_PRINTABLE_CHAR(ch) ((ch) < 32 ? '?' : (ch))
 +#define CV_TAG_TO_PRINTABLE_CHAR4(tag) CV_PRINTABLE_CHAR((tag) & 255), CV_PRINTABLE_CHAR(((tag) >> 8) & 255), CV_PRINTABLE_CHAR(((tag) >> 16) & 255), CV_PRINTABLE_CHAR(((tag) >> 24) & 255)
 +
 +static inline bool cv_ff_codec_tag_match(const AVCodecTag *tags, CV_CODEC_ID id, unsigned int tag)
 +{
 +    while (tags->id != AV_CODEC_ID_NONE)
 +    {
 +        if (tags->id == id && tags->tag == tag)
 +            return true;
 +        tags++;
 +    }
 +    return false;
 +}
 +static inline bool cv_ff_codec_tag_list_match(const AVCodecTag *const *tags, CV_CODEC_ID id, unsigned int tag)
 +{
 +    int i;
 +    for (i = 0; tags && tags[i]; i++) {
 +        bool res = cv_ff_codec_tag_match(tags[i], id, tag);
 +        if (res)
 +            return res;
 +    }
 +    return false;
 +}
 +
 +/// 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 )
 +{
 +    CV_CODEC_ID codec_id = CV_CODEC(CODEC_ID_NONE);
 +    int err, codec_pix_fmt;
 +    double bitrate_scale = 1;
 +
 +    close();
 +
 +    // check arguments
 +    if( !filename )
 +        return false;
 +    if(fps <= 0)
 +        return false;
 +
 +    // we allow frames of odd width or height, but in this case we truncate
 +    // the rightmost column/the bottom row. Probably, this should be handled more elegantly,
 +    // but some internal functions inside FFMPEG swscale require even width/height.
 +    width &= -2;
 +    height &= -2;
 +    if( width <= 0 || height <= 0 )
 +        return false;
 +
 +    /* 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 = AV_PIX_FMT_BGR24;
 +    }
 +    else {
 +        input_pix_fmt = AV_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 )) == CV_CODEC(CODEC_ID_NONE) )
 +        return false;
 +#else
 +    if( (codec_id = av_codec_get_id(fmt->codec_tag, fourcc)) == CV_CODEC(CODEC_ID_NONE) )
 +    {
 +        const struct AVCodecTag * fallback_tags[] = {
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(54, 1, 0)
 +// APIchanges:
 +// 2012-01-31 - dd6d3b0 - lavf 54.01.0
 +//   Add avformat_get_riff_video_tags() and avformat_get_riff_audio_tags().
 +                avformat_get_riff_video_tags(),
 +#endif
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(55, 25, 100) && defined LIBAVFORMAT_VERSION_MICRO && LIBAVFORMAT_VERSION_MICRO >= 100
 +// APIchanges: ffmpeg only
 +// 2014-01-19 - 1a193c4 - lavf 55.25.100 - avformat.h
 +//   Add avformat_get_mov_video_tags() and avformat_get_mov_audio_tags().
 +                avformat_get_mov_video_tags(),
 +#endif
 +                codec_bmp_tags, // fallback for avformat < 54.1
 +                NULL };
 +        if( (codec_id = av_codec_get_id(fallback_tags, fourcc)) == CV_CODEC(CODEC_ID_NONE) )
 +        {
 +            fflush(stdout);
 +            fprintf(stderr, "OpenCV: FFMPEG: tag 0x%08x/'%c%c%c%c' is not found (format '%s / %s')'\n",
 +                    fourcc, CV_TAG_TO_PRINTABLE_CHAR4(fourcc),
 +                    fmt->name, fmt->long_name);
 +            return false;
 +        }
 +    }
 +    // validate tag
 +    if (cv_ff_codec_tag_list_match(fmt->codec_tag, codec_id, fourcc) == false)
 +    {
 +        fflush(stdout);
 +        fprintf(stderr, "OpenCV: FFMPEG: tag 0x%08x/'%c%c%c%c' is not supported with codec id %d and format '%s / %s'\n",
 +                fourcc, CV_TAG_TO_PRINTABLE_CHAR4(fourcc),
 +                codec_id, fmt->name, fmt->long_name);
 +        int supported_tag;
 +        if( (supported_tag = av_codec_get_tag(fmt->codec_tag, codec_id)) != 0 )
 +        {
 +            fprintf(stderr, "OpenCV: FFMPEG: fallback to use tag 0x%08x/'%c%c%c%c'\n",
 +                    supported_tag, CV_TAG_TO_PRINTABLE_CHAR4(supported_tag));
 +            fourcc = supported_tag;
 +        }
 +    }
 +#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 CV_CODEC(CODEC_ID_JPEGLS):
 +        // BGR24 or GRAY8 depending on is_color...
 +        codec_pix_fmt = input_pix_fmt;
 +        break;
 +#endif
 +    case CV_CODEC(CODEC_ID_HUFFYUV):
 +        codec_pix_fmt = AV_PIX_FMT_YUV422P;
 +        break;
 +    case CV_CODEC(CODEC_ID_MJPEG):
 +    case CV_CODEC(CODEC_ID_LJPEG):
 +        codec_pix_fmt = AV_PIX_FMT_YUVJ420P;
 +        bitrate_scale = 3;
 +        break;
 +    case CV_CODEC(CODEC_ID_RAWVIDEO):
 +        codec_pix_fmt = input_pix_fmt == AV_PIX_FMT_GRAY8 ||
 +                        input_pix_fmt == AV_PIX_FMT_GRAY16LE ||
 +                        input_pix_fmt == AV_PIX_FMT_GRAY16BE ? input_pix_fmt : AV_PIX_FMT_YUV420P;
 +        break;
 +    default:
 +        // good for lossy formats, MPEG, etc.
 +        codec_pix_fmt = AV_PIX_FMT_YUV420P;
 +        break;
 +    }
 +
 +    double bitrate = MIN(bitrate_scale*fps*width*height, (double)INT_MAX/2);
 +
 +    // TODO -- safe to ignore output audio stream?
 +    video_st = icv_add_video_stream_FFMPEG(oc, codec_id,
 +                                           width, height, (int)(bitrate + 0.5),
 +                                           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 0
 +#if FF_API_DUMP_FORMAT
 +    dump_format(oc, 0, filename, 1);
 +#else
 +    av_dump_format(oc, 0, filename, 1);
 +#endif
 +#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) {
 +        fprintf(stderr, "Could not find encoder for codec id %d: %s\n", c->codec_id, icvFFMPEGErrStr(
 +        #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
 +                AVERROR_ENCODER_NOT_FOUND
 +        #else
 +                -1
 +        #endif
 +                ));
 +        return false;
 +    }
 +
 +    int64_t lbit_rate = (int64_t)c->bit_rate;
 +    lbit_rate += (bitrate / 2);
 +    lbit_rate = std::min(lbit_rate, (int64_t)INT_MAX);
 +    c->bit_rate_tolerance = (int)lbit_rate;
 +    c->bit_rate = (int)lbit_rate;
 +
 +    /* open the codec */
 +    if ((err=
 +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0)
 +         avcodec_open2(c, codec, NULL)
 +#else
 +         avcodec_open(c, codec)
 +#endif
 +         ) < 0) {
 +        fprintf(stderr, "Could not open codec '%s': %s\n", 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 */
 +    if (!(fmt->flags & AVFMT_NOFILE)) {
 +#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
 +        if (url_fopen(&oc->pb, filename, URL_WRONLY) < 0)
 +#else
 +            if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0)
 +#endif
 +            {
 +            return false;
 +        }
 +    }
 +
 +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
 +    /* write the stream header, if any */
 +    err=avformat_write_header(oc, NULL);
 +#else
 +    err=av_write_header( oc );
 +#endif
 +
 +    if(err < 0)
 +    {
 +        close();
 +        remove(filename);
 +        return false;
 +    }
 +    frame_width = width;
 +    frame_height = height;
 +    frame_idx = 0;
 +    ok = true;
 +
 +    return true;
 +}
 +
 +
 +
 +CvCapture_FFMPEG* cvCreateFileCapture_FFMPEG( const char* filename )
 +{
 +    CvCapture_FFMPEG* capture = (CvCapture_FFMPEG*)malloc(sizeof(*capture));
 +    capture->init();
 +    if( capture->open( filename ))
 +        return capture;
 +
 +    capture->close();
 +    free(capture);
 +    return 0;
 +}
 +
 +
 +void cvReleaseCapture_FFMPEG(CvCapture_FFMPEG** capture)
 +{
 +    if( capture && *capture )
 +    {
 +        (*capture)->close();
 +        free(*capture);
 +        *capture = 0;
 +    }
 +}
 +
 +int cvSetCaptureProperty_FFMPEG(CvCapture_FFMPEG* capture, int prop_id, double value)
 +{
 +    return capture->setProperty(prop_id, value);
 +}
 +
 +double cvGetCaptureProperty_FFMPEG(CvCapture_FFMPEG* capture, int prop_id)
 +{
 +    return capture->getProperty(prop_id);
 +}
 +
 +int cvGrabFrame_FFMPEG(CvCapture_FFMPEG* capture)
 +{
 +    return capture->grabFrame();
 +}
 +
 +int cvRetrieveFrame_FFMPEG(CvCapture_FFMPEG* capture, unsigned char** data, int* step, int* width, int* height, int* cn)
 +{
 +    return capture->retrieveFrame(0, data, step, width, height, cn);
 +}
 +
 +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);
 +}
 +
 +
 +
 +/*
 + * For CUDA encoder
 + */
 +
 +struct OutputMediaStream_FFMPEG
 +{
 +    bool open(const char* fileName, int width, int height, double fps);
 +    void close();
 +
 +    void write(unsigned char* data, int size, int keyFrame);
 +
 +    // add a video output stream to the container
 +    static AVStream* addVideoStream(AVFormatContext *oc, CV_CODEC_ID codec_id, int w, int h, int bitrate, double fps, AVPixelFormat pixel_format);
 +
 +    AVOutputFormat* fmt_;
 +    AVFormatContext* oc_;
 +    AVStream* video_st_;
 +};
 +
 +void OutputMediaStream_FFMPEG::close()
 +{
 +    // 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?
 +
 +    if (oc_)
 +    {
 +        // write the trailer, if any
 +        av_write_trailer(oc_);
 +
 +        // free the streams
 +        for (unsigned int i = 0; i < oc_->nb_streams; ++i)
 +        {
 +            av_freep(&oc_->streams[i]->codec);
 +            av_freep(&oc_->streams[i]);
 +        }
 +
 +        if (!(fmt_->flags & AVFMT_NOFILE) && oc_->pb)
 +        {
 +            // close the output file
 +
 +            #if LIBAVCODEC_VERSION_INT < ((52<<16)+(123<<8)+0)
 +                #if LIBAVCODEC_VERSION_INT >= ((51<<16)+(49<<8)+0)
 +                    url_fclose(oc_->pb);
 +                #else
 +                    url_fclose(&oc_->pb);
 +                #endif
 +            #else
 +                avio_close(oc_->pb);
 +            #endif
 +        }
 +
 +        // free the stream
 +        av_free(oc_);
 +    }
 +}
 +
 +AVStream* OutputMediaStream_FFMPEG::addVideoStream(AVFormatContext *oc, CV_CODEC_ID codec_id, int w, int h, int bitrate, double fps, AVPixelFormat pixel_format)
 +{
 +    AVCodec* codec = avcodec_find_encoder(codec_id);
 +    if (!codec)
 +    {
 +        fprintf(stderr, "Could not find encoder for codec id %d\n", codec_id);
 +        return NULL;
 +    }
 +
 +    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 10, 0)
 +        AVStream* st = avformat_new_stream(oc, 0);
 +    #else
 +        AVStream* st = av_new_stream(oc, 0);
 +    #endif
 +    if (!st)
 +        return 0;
 +
 +    #if LIBAVFORMAT_BUILD > 4628
 +        AVCodecContext* c = st->codec;
 +    #else
 +        AVCodecContext* c = &(st->codec);
 +    #endif
 +
 +    c->codec_id = codec_id;
 +    c->codec_type = AVMEDIA_TYPE_VIDEO;
 +
 +    // put sample parameters
 +    unsigned long long lbit_rate = static_cast<unsigned long long>(bitrate);
 +    lbit_rate += (bitrate / 4);
 +    lbit_rate = std::min(lbit_rate, static_cast<unsigned long long>(std::numeric_limits<int>::max()));
 +    c->bit_rate = bitrate;
 +
 +    // took advice from
 +    // http://ffmpeg-users.933282.n4.nabble.com/warning-clipping-1-dct-coefficients-to-127-127-td934297.html
 +    c->qmin = 3;
 +
 +    // 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
 +
 +    int frame_rate = static_cast<int>(fps+0.5);
 +    int frame_rate_base = 1;
 +    while (fabs(static_cast<double>(frame_rate)/frame_rate_base) - fps > 0.001)
 +    {
 +        frame_rate_base *= 10;
 +        frame_rate = static_cast<int>(fps*frame_rate_base + 0.5);
 +    }
 +    c->time_base.den = frame_rate;
 +    c->time_base.num = frame_rate_base;
 +
 +    #if LIBAVFORMAT_BUILD > 4752
 +        // adjust time base for supported framerates
 +        if (codec && codec->supported_framerates)
 +        {
 +            AVRational req = {frame_rate, frame_rate_base};
 +            const AVRational* best = NULL;
 +            AVRational best_error = {INT_MAX, 1};
 +
 +            for (const AVRational* p = codec->supported_framerates; 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;
 +        }
 +    #endif
 +
 +    c->gop_size = 12; // emit one intra frame every twelve frames at most
 +    c->pix_fmt = pixel_format;
 +
 +    if (c->codec_id == CV_CODEC(CODEC_ID_MPEG2VIDEO))
 +        c->max_b_frames = 2;
 +
 +    if (c->codec_id == CV_CODEC(CODEC_ID_MPEG1VIDEO) || c->codec_id == CV_CODEC(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;
 +}
 +
 +bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height, double fps)
 +{
 +    fmt_ = 0;
 +    oc_ = 0;
 +    video_st_ = 0;
 +
 +    // 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;
 +
 +    CV_CODEC_ID codec_id = CV_CODEC(CODEC_ID_H264);
 +
 +    // alloc memory for context
 +    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 2, 0)
 +        oc_ = avformat_alloc_context();
 +    #else
 +        oc_ = av_alloc_format_context();
 +    #endif
 +    if (!oc_)
 +        return false;
 +
 +    // set some options
 +    oc_->oformat = fmt_;
 +    snprintf(oc_->filename, sizeof(oc_->filename), "%s", fileName);
 +
 +    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..
 +    AVPixelFormat codec_pix_fmt = AV_PIX_FMT_YUV420P;
 +    int bitrate_scale = 64;
 +
 +    // TODO -- safe to ignore output audio stream?
 +    video_st_ = addVideoStream(oc_, codec_id, width, height, width * height * bitrate_scale, fps, codec_pix_fmt);
 +    if (!video_st_)
 +        return false;
 +
 +    // 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
 +
 +    // now that all the parameters are set, we can open the audio and
 +    // video codecs and allocate the necessary encode buffers
 +
 +    #if LIBAVFORMAT_BUILD > 4628
 +        AVCodecContext* c = (video_st_->codec);
 +    #else
 +        AVCodecContext* c = &(video_st_->codec);
 +    #endif
 +
 +    c->codec_tag = MKTAG('H', '2', '6', '4');
 +    c->bit_rate_tolerance = c->bit_rate;
 +
 +    // open the output file, if needed
 +    if (!(fmt_->flags & AVFMT_NOFILE))
 +    {
 +        #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
 +            int err = url_fopen(&oc_->pb, fileName, URL_WRONLY);
 +        #else
 +            int err = avio_open(&oc_->pb, fileName, AVIO_FLAG_WRITE);
 +        #endif
 +
 +        if (err != 0)
 +            return false;
 +    }
 +
 +    // write the stream header, if any
 +    #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
 +        av_write_header(oc_);
 +    #else
 +        avformat_write_header(oc_, NULL);
 +    #endif
 +
 +    return true;
 +}
 +
 +void OutputMediaStream_FFMPEG::write(unsigned char* data, int size, int keyFrame)
 +{
 +    // if zero size, it means the image was buffered
 +    if (size > 0)
 +    {
 +        AVPacket pkt;
 +        av_init_packet(&pkt);
 +
 +        if (keyFrame)
 +            pkt.flags |= PKT_FLAG_KEY;
 +
 +        pkt.stream_index = video_st_->index;
 +        pkt.data = data;
 +        pkt.size = size;
 +
 +        // write the compressed frame in the media file
 +        av_write_frame(oc_, &pkt);
 +    }
 +}
 +
 +struct OutputMediaStream_FFMPEG* create_OutputMediaStream_FFMPEG(const char* fileName, int width, int height, double fps)
 +{
 +    OutputMediaStream_FFMPEG* stream = (OutputMediaStream_FFMPEG*) malloc(sizeof(OutputMediaStream_FFMPEG));
 +
 +    if (stream->open(fileName, width, height, fps))
 +        return stream;
 +
 +    stream->close();
 +    free(stream);
 +
 +    return 0;
 +}
 +
 +void release_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream)
 +{
 +    stream->close();
 +    free(stream);
 +}
 +
 +void write_OutputMediaStream_FFMPEG(struct OutputMediaStream_FFMPEG* stream, unsigned char* data, int size, int keyFrame)
 +{
 +    stream->write(data, size, keyFrame);
 +}
 +
 +/*
 + * For CUDA decoder
 + */
 +
 +enum
 +{
 +    VideoCodec_MPEG1 = 0,
 +    VideoCodec_MPEG2,
 +    VideoCodec_MPEG4,
 +    VideoCodec_VC1,
 +    VideoCodec_H264,
 +    VideoCodec_JPEG,
 +    VideoCodec_H264_SVC,
 +    VideoCodec_H264_MVC,
 +
 +    // Uncompressed YUV
 +    VideoCodec_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')),   // Y,U,V (4:2:0)
 +    VideoCodec_YV12   = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')),   // Y,V,U (4:2:0)
 +    VideoCodec_NV12   = (('N'<<24)|('V'<<16)|('1'<<8)|('2')),   // Y,UV  (4:2:0)
 +    VideoCodec_YUYV   = (('Y'<<24)|('U'<<16)|('Y'<<8)|('V')),   // YUYV/YUY2 (4:2:2)
 +    VideoCodec_UYVY   = (('U'<<24)|('Y'<<16)|('V'<<8)|('Y'))    // UYVY (4:2:2)
 +};
 +
 +enum
 +{
 +    VideoChromaFormat_Monochrome = 0,
 +    VideoChromaFormat_YUV420,
 +    VideoChromaFormat_YUV422,
 +    VideoChromaFormat_YUV444
 +};
 +
 +struct InputMediaStream_FFMPEG
 +{
 +public:
 +    bool open(const char* fileName, int* codec, int* chroma_format, int* width, int* height);
 +    void close();
 +
 +    bool read(unsigned char** data, int* size, int* endOfFile);
 +
 +private:
 +    InputMediaStream_FFMPEG(const InputMediaStream_FFMPEG&);
 +    InputMediaStream_FFMPEG& operator =(const InputMediaStream_FFMPEG&);
 +
 +    AVFormatContext* ctx_;
 +    int video_stream_id_;
 +    AVPacket pkt_;
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +    AVInterruptCallbackMetadata interrupt_metadata;
 +#endif
 +};
 +
 +bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma_format, int* width, int* height)
 +{
 +    int err;
 +
 +    ctx_ = 0;
 +    video_stream_id_ = -1;
 +    memset(&pkt_, 0, sizeof(AVPacket));
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +    /* interrupt callback */
 +    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_OPEN_TIMEOUT_MS;
 +    get_monotonic_time(&interrupt_metadata.value);
 +
 +    ctx_ = avformat_alloc_context();
 +    ctx_->interrupt_callback.callback = _opencv_ffmpeg_interrupt_callback;
 +    ctx_->interrupt_callback.opaque = &interrupt_metadata;
 +#endif
 +
 +    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0)
 +        avformat_network_init();
 +    #endif
 +
 +    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 6, 0)
 +        err = avformat_open_input(&ctx_, fileName, 0, 0);
 +    #else
 +        err = av_open_input_file(&ctx_, fileName, 0, 0, 0);
 +    #endif
 +    if (err < 0)
 +        return false;
 +
 +    #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 6, 0)
 +        err = avformat_find_stream_info(ctx_, 0);
 +    #else
 +        err = av_find_stream_info(ctx_);
 +    #endif
 +    if (err < 0)
 +        return false;
 +
 +    for (unsigned int i = 0; i < ctx_->nb_streams; ++i)
 +    {
 +        #if LIBAVFORMAT_BUILD > 4628
 +            AVCodecContext *enc = ctx_->streams[i]->codec;
 +        #else
 +            AVCodecContext *enc = &ctx_->streams[i]->codec;
 +        #endif
 +
 +        if (enc->codec_type == AVMEDIA_TYPE_VIDEO)
 +        {
 +            video_stream_id_ = static_cast<int>(i);
 +
 +            switch (enc->codec_id)
 +            {
 +            case CV_CODEC(CODEC_ID_MPEG1VIDEO):
 +                *codec = ::VideoCodec_MPEG1;
 +                break;
 +
 +            case CV_CODEC(CODEC_ID_MPEG2VIDEO):
 +                *codec = ::VideoCodec_MPEG2;
 +                break;
 +
 +            case CV_CODEC(CODEC_ID_MPEG4):
 +                *codec = ::VideoCodec_MPEG4;
 +                break;
 +
 +            case CV_CODEC(CODEC_ID_VC1):
 +                *codec = ::VideoCodec_VC1;
 +                break;
 +
 +            case CV_CODEC(CODEC_ID_H264):
 +                *codec = ::VideoCodec_H264;
 +                break;
 +
 +            default:
 +                return false;
 +            };
 +
 +            switch (enc->pix_fmt)
 +            {
 +            case AV_PIX_FMT_YUV420P:
 +                *chroma_format = ::VideoChromaFormat_YUV420;
 +                break;
 +
 +            case AV_PIX_FMT_YUV422P:
 +                *chroma_format = ::VideoChromaFormat_YUV422;
 +                break;
 +
 +            case AV_PIX_FMT_YUV444P:
 +                *chroma_format = ::VideoChromaFormat_YUV444;
 +                break;
 +
 +            default:
 +                return false;
 +            }
 +
 +            *width = enc->coded_width;
 +            *height = enc->coded_height;
 +
 +            break;
 +        }
 +    }
 +
 +    if (video_stream_id_ < 0)
 +        return false;
 +
 +    av_init_packet(&pkt_);
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +    // deactivate interrupt callback
 +    interrupt_metadata.timeout_after_ms = 0;
 +#endif
 +
 +    return true;
 +}
 +
 +void InputMediaStream_FFMPEG::close()
 +{
 +    if (ctx_)
 +    {
 +        #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 24, 2)
 +            avformat_close_input(&ctx_);
 +        #else
 +            av_close_input_file(ctx_);
 +        #endif
 +    }
 +
 +    // free last packet if exist
 +    if (pkt_.data)
 +        _opencv_ffmpeg_av_packet_unref(&pkt_);
 +}
 +
 +bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFile)
 +{
 +    bool result = false;
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +    // activate interrupt callback
 +    get_monotonic_time(&interrupt_metadata.value);
 +    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_READ_TIMEOUT_MS;
 +#endif
 +
 +    // free last packet if exist
 +    if (pkt_.data)
 +        _opencv_ffmpeg_av_packet_unref(&pkt_);
 +
 +    // get the next frame
 +    for (;;)
 +    {
 +#if USE_AV_INTERRUPT_CALLBACK
 +        if(interrupt_metadata.timeout)
 +        {
 +            break;
 +        }
 +#endif
 +
 +        int ret = av_read_frame(ctx_, &pkt_);
 +
 +        if (ret == AVERROR(EAGAIN))
 +            continue;
 +
 +        if (ret < 0)
 +        {
 +            if (ret == (int)AVERROR_EOF)
 +                *endOfFile = true;
 +            break;
 +        }
 +
 +        if (pkt_.stream_index != video_stream_id_)
 +        {
 +            _opencv_ffmpeg_av_packet_unref(&pkt_);
 +            continue;
 +        }
 +
 +        result = true;
 +        break;
 +    }
 +
 +#if USE_AV_INTERRUPT_CALLBACK
 +    // deactivate interrupt callback
 +    interrupt_metadata.timeout_after_ms = 0;
 +#endif
 +
 +    if (result)
 +    {
 +        *data = pkt_.data;
 +        *size = pkt_.size;
 +        *endOfFile = false;
 +    }
 +
 +    return result;
 +}
 +
 +InputMediaStream_FFMPEG* create_InputMediaStream_FFMPEG(const char* fileName, int* codec, int* chroma_format, int* width, int* height)
 +{
 +    InputMediaStream_FFMPEG* stream = (InputMediaStream_FFMPEG*) malloc(sizeof(InputMediaStream_FFMPEG));
 +
 +    if (stream && stream->open(fileName, codec, chroma_format, width, height))
 +        return stream;
 +
 +    stream->close();
 +    free(stream);
 +
 +    return 0;
 +}
 +
 +void release_InputMediaStream_FFMPEG(InputMediaStream_FFMPEG* stream)
 +{
 +    stream->close();
 +    free(stream);
 +}
 +
 +int read_InputMediaStream_FFMPEG(InputMediaStream_FFMPEG* stream, unsigned char** data, int* size, int* endOfFile)
 +{
 +    return stream->read(data, size, endOfFile);
 +}
index 8c7ff14,ded3608..ded3608
Binary files differ