From 70a5e1ec8badd98cb0fce940f42e40688858dd99cbd783bcf8af0268663052e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Tue, 3 May 2022 17:42:13 +0000 Subject: [PATCH] Accepting request 973972 from home:StefanBruens:branches:science - Add upstream patches for FFmpeg 5.0 support, add * videoio_initial_FFmpeg_5_0_support.patch * videoio_ffmpeg_avoid_memory_leaks.patch - Restore memoryperjob constraint, avoid being scheduled on a 16 core system and use less than half of it. - Adjust %limit_build to 1800, to avoid recurrent build failures on aarch64. (People should not care for their pet architecture only, but also carefully check if they break others.) - Add missing libopencv_aruco dependency in devel package. OBS-URL: https://build.opensuse.org/request/show/973972 OBS-URL: https://build.opensuse.org/package/show/science/opencv?expand=0&rev=32 --- _constraints | 5 + opencv.changes | 17 + opencv.spec | 5 + videoio_ffmpeg_avoid_memory_leaks.patch | 69 ++ videoio_initial_FFmpeg_5_0_support.patch | 1001 ++++++++++++++++++++++ 5 files changed, 1097 insertions(+) create mode 100644 videoio_ffmpeg_avoid_memory_leaks.patch create mode 100644 videoio_initial_FFmpeg_5_0_support.patch diff --git a/_constraints b/_constraints index 0e5b9e6..83ff66d 100644 --- a/_constraints +++ b/_constraints @@ -7,5 +7,10 @@ 5700 + + + + 1200 + diff --git a/opencv.changes b/opencv.changes index ab6e78c..7a8ba65 100644 --- a/opencv.changes +++ b/opencv.changes @@ -1,3 +1,20 @@ +------------------------------------------------------------------- +Fri Apr 29 16:54:16 UTC 2022 - Stefan Brüns + +- Add upstream patches for FFmpeg 5.0 support, add + * videoio_initial_FFmpeg_5_0_support.patch + * videoio_ffmpeg_avoid_memory_leaks.patch + +------------------------------------------------------------------- +Sat Apr 9 17:42:50 UTC 2022 - Stefan Brüns + +- Restore memoryperjob constraint, avoid being scheduled on a 16 + core system and use less than half of it. +- Adjust %limit_build to 1800, to avoid recurrent build failures + on aarch64. (People should not care for their pet architecture + only, but also carefully check if they break others.) +- Add missing libopencv_aruco dependency in devel package. + ------------------------------------------------------------------- Mon Jan 10 11:08:32 UTC 2022 - Antonio Larrosa diff --git a/opencv.spec b/opencv.spec index 3a77b5f..dfddb5c 100644 --- a/opencv.spec +++ b/opencv.spec @@ -47,6 +47,10 @@ Source0: https://github.com/opencv/opencv/archive/%{version}.tar.gz#/%{na Source1: https://github.com/opencv/opencv_contrib/archive/%{version}.tar.gz#/opencv_contrib-%{version}.tar.gz # PATCH-FIX-UPSTREAM Patch0: 0001-highgui-Fix-unresolved-OpenGL-functions-for-Qt-backe.patch +# PATCH-FIX-UPSTREAM +Patch1: https://github.com/opencv/opencv/pull/21754.patch#/videoio_initial_FFmpeg_5_0_support.patch +# PATCH-FIX-UPSTREAM +Patch2: https://github.com/opencv/opencv/commit/271f7df3435c619ceba9261f88dcfbb0714b0b0d.patch#/videoio_ffmpeg_avoid_memory_leaks.patch BuildRequires: cmake BuildRequires: fdupes BuildRequires: libeigen3-devel @@ -213,6 +217,7 @@ Summary: Development files for using the OpenCV library License: BSD-3-Clause Group: Development/Libraries/C and C++ Requires: %{libname}%{soname} = %{version} +Requires: libopencv_aruco%{soname} = %{version} Requires: libopencv_face%{soname} = %{version} Requires: libopencv_highgui%{soname} = %{version} Requires: libopencv_imgcodecs%{soname} = %{version} diff --git a/videoio_ffmpeg_avoid_memory_leaks.patch b/videoio_ffmpeg_avoid_memory_leaks.patch new file mode 100644 index 0000000..f6ddbdf --- /dev/null +++ b/videoio_ffmpeg_avoid_memory_leaks.patch @@ -0,0 +1,69 @@ +From 271f7df3435c619ceba9261f88dcfbb0714b0b0d Mon Sep 17 00:00:00 2001 +From: Alexander Alekhin +Date: Fri, 1 Apr 2022 18:02:14 +0000 +Subject: [PATCH] videoio(ffmpeg): avoid memory leaks + +--- + modules/videoio/src/cap_ffmpeg_impl.hpp | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp +index 91a0f710aa63..b7fa0b745c1e 100644 +--- a/modules/videoio/src/cap_ffmpeg_impl.hpp ++++ b/modules/videoio/src/cap_ffmpeg_impl.hpp +@@ -2496,17 +2496,13 @@ double CvVideoWriter_FFMPEG::getProperty(int propId) const + /// 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 (picture && ok && oc) + { + #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(57, 0, 0) + if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) +@@ -2529,7 +2525,7 @@ void CvVideoWriter_FFMPEG::close() + } + + // free pictures +- if( context->pix_fmt != input_pix_fmt) ++ if (picture && context && context->pix_fmt != input_pix_fmt) + { + if(picture->data[0]) + free(picture->data[0]); +@@ -2540,8 +2536,14 @@ void CvVideoWriter_FFMPEG::close() + if (input_picture) + av_free(input_picture); + ++#ifdef CV_FFMPEG_CODECPAR ++ avcodec_free_context(&context); ++#else + /* close codec */ +- avcodec_close(context); ++ if (context) // fixed after https://github.com/FFmpeg/FFmpeg/commit/3e1f507f3e8f16b716aa115552d243b48ae809bd ++ avcodec_close(context); ++ context = NULL; ++#endif + + av_free(outbuf); + +@@ -2935,10 +2937,7 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + #endif + + #ifdef CV_FFMPEG_CODECPAR +- if (context) +- { +- avcodec_free_context(&context); +- } ++ avcodec_free_context(&context); + #endif + context = icv_configure_video_stream_FFMPEG(oc, video_st, codec, + width, height, (int) (bitrate + 0.5), diff --git a/videoio_initial_FFmpeg_5_0_support.patch b/videoio_initial_FFmpeg_5_0_support.patch new file mode 100644 index 0000000..91ccfaf --- /dev/null +++ b/videoio_initial_FFmpeg_5_0_support.patch @@ -0,0 +1,1001 @@ +From 5440fd6cb43ea65a056c46b691fcdab1a425e92d Mon Sep 17 00:00:00 2001 +From: Maksim Shabunin +Date: Sat, 19 Mar 2022 20:06:50 +0300 +Subject: [PATCH] videoio: initial FFmpeg 5.0 support + +--- + modules/videoio/src/cap_ffmpeg_impl.hpp | 442 ++++++++++++++++-------- + 1 file changed, 304 insertions(+), 138 deletions(-) + +diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp +index 43c555309b9d..91a0f710aa63 100644 +--- a/modules/videoio/src/cap_ffmpeg_impl.hpp ++++ b/modules/videoio/src/cap_ffmpeg_impl.hpp +@@ -41,6 +41,8 @@ + //M*/ + + #include "cap_ffmpeg_legacy_api.hpp" ++#include "opencv2/core/utils/logger.hpp" ++#include "cap_interface.hpp" + + using namespace cv; + +@@ -49,6 +51,7 @@ using namespace cv; + #endif + #include + #include ++#include + + #ifndef __OPENCV_BUILD + #define CV_FOURCC(c1, c2, c3, c4) (((c1) & 255) + (((c2) & 255) << 8) + (((c3) & 255) << 16) + (((c4) & 255) << 24)) +@@ -79,6 +82,7 @@ extern "C" { + + #include + #include ++#include + + #if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \ + ? CALC_FFMPEG_VERSION(51, 63, 100) : CALC_FFMPEG_VERSION(54, 6, 0)) +@@ -88,6 +92,62 @@ extern "C" { + #include + #include + ++// https://github.com/FFmpeg/FFmpeg/blob/b6af56c034759b81985f8ea094e41cbd5f7fecfb/doc/APIchanges#L602-L605 ++#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(58, 9, 100) ++# define CV_FFMPEG_REGISTER ++#endif ++ ++// https://github.com/FFmpeg/FFmpeg/blob/b6af56c034759b81985f8ea094e41cbd5f7fecfb/doc/APIchanges#L654-L657 ++#if LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(58, 9, 100) ++# define CV_FFMPEG_LOCKMGR ++#endif ++ ++// https://github.com/FFmpeg/FFmpeg/blob/b6af56c034759b81985f8ea094e41cbd5f7fecfb/doc/APIchanges#L390-L392 ++#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(58, 87, 100) ++#include ++#endif ++ ++// https://github.com/FFmpeg/FFmpeg/blob/b6af56c034759b81985f8ea094e41cbd5f7fecfb/doc/APIchanges#L208-L210 ++#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(59, 0, 100) ++# define CV_FFMPEG_FMT_CONST const ++#else ++# define CV_FFMPEG_FMT_CONST ++#endif ++ ++// https://github.com/FFmpeg/FFmpeg/blob/b6af56c034759b81985f8ea094e41cbd5f7fecfb/doc/APIchanges#L623-L624 ++#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(58, 7, 100) ++# define CV_FFMPEG_URL ++#endif ++ ++// AVStream.codec deprecated in favor of AVStream.codecpar ++// https://github.com/FFmpeg/FFmpeg/blob/b6af56c034759b81985f8ea094e41cbd5f7fecfb/doc/APIchanges#L1039-L1040 ++#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(59, 16, 100) ++//#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(57, 33, 100) ++# define CV_FFMPEG_CODECPAR ++# define CV_FFMPEG_CODEC_FIELD codecpar ++#else ++# define CV_FFMPEG_CODEC_FIELD codec ++#endif ++ ++#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(59, 16, 100) ++# define CV_FFMPEG_PTS_FIELD pts ++#else ++# define CV_FFMPEG_PTS_FIELD pkt_pts ++#endif ++ ++// https://github.com/FFmpeg/FFmpeg/blob/b6af56c034759b81985f8ea094e41cbd5f7fecfb/doc/APIchanges#L1757-L1758 ++#if LIBAVUTIL_BUILD < CALC_FFMPEG_VERSION(52, 63, 100) ++inline static AVRational av_make_q(int num, int den) ++{ ++ AVRational res; ++ res.num = num; ++ res.den = den; ++ return res; ++} ++#endif ++ ++ ++ + #ifdef __cplusplus + } + #endif +@@ -471,6 +531,15 @@ static AVRational _opencv_ffmpeg_get_sample_aspect_ratio(AVStream *stream) + #endif + } + ++inline static std::string _opencv_ffmpeg_get_error_string(int error_code) ++{ ++ char buf[255] = {0}; ++ const int err = av_strerror(error_code, buf, 254); ++ if (err == 0) ++ return std::string(buf); ++ else ++ return std::string("Unknown error"); ++} + + struct CvCapture_FFMPEG + { +@@ -502,6 +571,7 @@ struct CvCapture_FFMPEG + + AVFormatContext * ic; + AVCodec * avcodec; ++ AVCodecContext * context; + int video_stream; + AVStream * video_st; + AVFrame * picture; +@@ -565,6 +635,7 @@ void CvCapture_FFMPEG::init() + img_convert_ctx = 0; + + avcodec = 0; ++ context = 0; + frame_number = 0; + eps_zero = 0.000025; + +@@ -617,10 +688,19 @@ void CvCapture_FFMPEG::close() + + if( video_st ) + { +- avcodec_close( video_st->codec ); ++#ifdef CV_FFMPEG_CODECPAR ++ avcodec_close( context ); ++#endif + video_st = NULL; + } + ++ if (context) ++ { ++#ifdef CV_FFMPEG_CODECPAR ++ avcodec_free_context(&context); ++#endif ++ } ++ + if( ic ) + { + avformat_close_input(&ic); +@@ -798,8 +878,10 @@ class AutoLock + }; + #endif + ++ + static ImplMutex _mutex; + ++#ifdef CV_FFMPEG_LOCKMGR + static int LockCallBack(void **mutex, AVLockOp op) + { + ImplMutex* localMutex = reinterpret_cast(*mutex); +@@ -830,7 +912,7 @@ static int LockCallBack(void **mutex, AVLockOp op) + } + return 0; + } +- ++#endif + + static void ffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list vargs) + { +@@ -881,19 +963,59 @@ class InternalFFMpegRegister + { + avformat_network_init(); + ++#ifdef CV_FFMPEG_REGISTER + /* register all codecs, demux and protocols */ + av_register_all(); ++#endif + ++#ifdef CV_FFMPEG_LOCKMGR + /* register a callback function for synchronization */ + av_lockmgr_register(&LockCallBack); ++#endif + } + ~InternalFFMpegRegister() + { ++#ifdef CV_FFMPEG_LOCKMGR + av_lockmgr_register(NULL); ++#endif + av_log_set_callback(NULL); + } + }; + ++inline void fill_codec_context(AVCodecContext * enc, AVDictionary * dict) ++{ ++//#ifdef FF_API_THREAD_INIT ++// avcodec_thread_init(enc, get_number_of_cpus()); ++//#else ++ enc->thread_count = get_number_of_cpus(); ++//#endif ++ ++ AVDictionaryEntry* avdiscard_entry = av_dict_get(dict, "avdiscard", NULL, 0); ++ ++ if (avdiscard_entry) ++ { ++ if(strcmp(avdiscard_entry->value, "all") == 0) ++ enc->skip_frame = AVDISCARD_ALL; ++ else if (strcmp(avdiscard_entry->value, "bidir") == 0) ++ enc->skip_frame = AVDISCARD_BIDIR; ++ else if (strcmp(avdiscard_entry->value, "default") == 0) ++ enc->skip_frame = AVDISCARD_DEFAULT; ++ else if (strcmp(avdiscard_entry->value, "none") == 0) ++ enc->skip_frame = AVDISCARD_NONE; ++ // NONINTRA flag was introduced with version bump at revision: ++ // https://github.com/FFmpeg/FFmpeg/commit/b152152df3b778d0a86dcda5d4f5d065b4175a7b ++ // This key is supported only for FFMPEG version ++#if LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(55, 67, 100) ++ else if (strcmp(avdiscard_entry->value, "nonintra") == 0) ++ enc->skip_frame = AVDISCARD_NONINTRA; ++#endif ++ else if (strcmp(avdiscard_entry->value, "nonkey") == 0) ++ enc->skip_frame = AVDISCARD_NONKEY; ++ else if (strcmp(avdiscard_entry->value, "nonref") == 0) ++ enc->skip_frame = AVDISCARD_NONREF; ++ } ++} ++ + bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters& params) + { + InternalFFMpegRegister::init(); +@@ -997,7 +1119,7 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters& + #else + av_dict_set(&dict, "rtsp_transport", "tcp", 0); + #endif +- AVInputFormat* input_format = NULL; ++ CV_FFMPEG_FMT_CONST AVInputFormat* input_format = NULL; + AVDictionaryEntry* entry = av_dict_get(dict, "input_format", NULL, 0); + if (entry != 0) + { +@@ -1015,60 +1137,44 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters& + err = avformat_find_stream_info(ic, NULL); + if (err < 0) + { +- CV_WARN("Could not find codec parameters"); ++ CV_LOG_WARNING(NULL, "Unable to read codec parameters from stream (" << _opencv_ffmpeg_get_error_string(err) << ")"); + goto exit_func; + } + for(i = 0; i < ic->nb_streams; i++) + { +- AVCodecContext* enc = ic->streams[i]->codec; +- +-//#ifdef FF_API_THREAD_INIT +-// avcodec_thread_init(enc, get_number_of_cpus()); +-//#else +- enc->thread_count = get_number_of_cpus(); +-//#endif +- +- AVDictionaryEntry* avdiscard_entry = av_dict_get(dict, "avdiscard", NULL, 0); +- +- if (avdiscard_entry) { +- if(strcmp(avdiscard_entry->value, "all") == 0) +- enc->skip_frame = AVDISCARD_ALL; +- else if (strcmp(avdiscard_entry->value, "bidir") == 0) +- enc->skip_frame = AVDISCARD_BIDIR; +- else if (strcmp(avdiscard_entry->value, "default") == 0) +- enc->skip_frame = AVDISCARD_DEFAULT; +- else if (strcmp(avdiscard_entry->value, "none") == 0) +- enc->skip_frame = AVDISCARD_NONE; +- // NONINTRA flag was introduced with version bump at revision: +- // https://github.com/FFmpeg/FFmpeg/commit/b152152df3b778d0a86dcda5d4f5d065b4175a7b +- // This key is supported only for FFMPEG version +-#if LIBAVCODEC_VERSION_MICRO >= 100 && LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(55, 67, 100) +- else if (strcmp(avdiscard_entry->value, "nonintra") == 0) +- enc->skip_frame = AVDISCARD_NONINTRA; ++#ifndef CV_FFMPEG_CODECPAR ++ context = ic->streams[i]->codec; ++ AVCodecID codec_id = context->codec_id; ++ AVMediaType codec_type = context->codec_type; ++#else ++ AVCodecParameters* par = ic->streams[i]->codecpar; ++ AVCodecID codec_id = par->codec_id; ++ AVMediaType codec_type = par->codec_type; + #endif +- else if (strcmp(avdiscard_entry->value, "nonkey") == 0) +- enc->skip_frame = AVDISCARD_NONKEY; +- else if (strcmp(avdiscard_entry->value, "nonref") == 0) +- enc->skip_frame = AVDISCARD_NONREF; +- } + +- if( AVMEDIA_TYPE_VIDEO == enc->codec_type && video_stream < 0) ++ if( AVMEDIA_TYPE_VIDEO == codec_type && video_stream < 0) + { +- CV_LOG_DEBUG(NULL, "FFMPEG: stream[" << i << "] is video stream with codecID=" << (int)enc->codec_id +- << " width=" << enc->width +- << " height=" << enc->height ++ // backup encoder' width/height ++#ifndef CV_FFMPEG_CODECPAR ++ int enc_width = context->width; ++ int enc_height = context->height; ++#else ++ int enc_width = par->width; ++ int enc_height = par->height; ++#endif ++ ++ CV_LOG_DEBUG(NULL, "FFMPEG: stream[" << i << "] is video stream with codecID=" << (int)codec_id ++ << " width=" << enc_width ++ << " height=" << enc_height + ); + +- // backup encoder' width/height +- int enc_width = enc->width; +- int enc_height = enc->height; + + #if !USE_AV_HW_CODECS + va_type = VIDEO_ACCELERATION_NONE; + #endif + + // find and open decoder, try HW acceleration types specified in 'hw_acceleration' list (in order) +- AVCodec *codec = NULL; ++ const AVCodec *codec = NULL; + err = -1; + #if USE_AV_HW_CODECS + HWAccelIterator accel_iter(va_type, false/*isEncoder*/, dict); +@@ -1080,21 +1186,27 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters& + #if USE_AV_HW_CODECS + accel_iter.parse_next(); + AVHWDeviceType hw_type = accel_iter.hw_type(); +- enc->get_format = avcodec_default_get_format; +- if (enc->hw_device_ctx) { +- av_buffer_unref(&enc->hw_device_ctx); +- } + if (hw_type != AV_HWDEVICE_TYPE_NONE) + { + CV_LOG_DEBUG(NULL, "FFMPEG: trying to configure H/W acceleration: '" << accel_iter.hw_type_device_string() << "'"); + AVPixelFormat hw_pix_fmt = AV_PIX_FMT_NONE; +- codec = hw_find_codec(enc->codec_id, hw_type, av_codec_is_decoder, accel_iter.disabled_codecs().c_str(), &hw_pix_fmt); +- if (codec) { ++ codec = hw_find_codec(codec_id, hw_type, av_codec_is_decoder, accel_iter.disabled_codecs().c_str(), &hw_pix_fmt); ++ if (codec) ++ { ++#ifdef CV_FFMPEG_CODECPAR ++ context = avcodec_alloc_context3(codec); ++#endif ++ CV_Assert(context); ++ context->get_format = avcodec_default_get_format; ++ if (context->hw_device_ctx) { ++ av_buffer_unref(&context->hw_device_ctx); ++ } + if (hw_pix_fmt != AV_PIX_FMT_NONE) +- enc->get_format = hw_get_format_callback; // set callback to select HW pixel format, not SW format +- enc->hw_device_ctx = hw_create_device(hw_type, hw_device, accel_iter.device_subname(), use_opencl != 0); +- if (!enc->hw_device_ctx) ++ context->get_format = hw_get_format_callback; // set callback to select HW pixel format, not SW format ++ context->hw_device_ctx = hw_create_device(hw_type, hw_device, accel_iter.device_subname(), use_opencl != 0); ++ if (!context->hw_device_ctx) + { ++ context->get_format = avcodec_default_get_format; + CV_LOG_DEBUG(NULL, "FFMPEG: ... can't create H/W device: '" << accel_iter.hw_type_device_string() << "'"); + codec = NULL; + } +@@ -1106,10 +1218,10 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters& + AVDictionaryEntry* video_codec_param = av_dict_get(dict, "video_codec", NULL, 0); + if (video_codec_param == NULL) + { +- codec = avcodec_find_decoder(enc->codec_id); ++ codec = avcodec_find_decoder(codec_id); + if (!codec) + { +- CV_LOG_ERROR(NULL, "Could not find decoder for codec_id=" << (int)enc->codec_id); ++ CV_LOG_ERROR(NULL, "Could not find decoder for codec_id=" << (int)codec_id); + } + } + else +@@ -1121,10 +1233,26 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters& + CV_LOG_ERROR(NULL, "Could not find decoder '" << video_codec_param->value << "'"); + } + } ++ if (codec) ++ { ++#ifdef CV_FFMPEG_CODECPAR ++ context = avcodec_alloc_context3(codec); ++#endif ++ CV_Assert(context); ++ } + } + if (!codec) ++ { ++#ifdef CV_FFMPEG_CODECPAR ++ avcodec_free_context(&context); ++#endif + continue; +- err = avcodec_open2(enc, codec, NULL); ++ } ++ fill_codec_context(context, dict); ++#ifdef CV_FFMPEG_CODECPAR ++ avcodec_parameters_to_context(context, par); ++#endif ++ err = avcodec_open2(context, codec, NULL); + if (err >= 0) { + #if USE_AV_HW_CODECS + va_type = hw_type_to_va_type(hw_type); +@@ -1146,10 +1274,10 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters& + } + + // 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; ++ if (enc_width && (context->width != enc_width)) ++ context->width = enc_width; ++ if (enc_height && (context->height != enc_height)) ++ context->height = enc_height; + + video_stream = i; + video_st = ic->streams[i]; +@@ -1160,8 +1288,8 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters& + picture = avcodec_alloc_frame(); + #endif + +- frame.width = enc->width; +- frame.height = enc->height; ++ frame.width = context->width; ++ frame.height = context->height; + frame.cn = 3; + frame.step = 0; + frame.data = NULL; +@@ -1306,7 +1434,7 @@ bool CvCapture_FFMPEG::grabFrame() + int count_errs = 0; + const int max_number_of_attempts = 1 << 9; + +- if( !ic || !video_st ) return false; ++ if( !ic || !video_st || !context ) return false; + + if( ic->streams[video_stream]->nb_frames > 0 && + frame_number > ic->streams[video_stream]->nb_frames ) +@@ -1322,7 +1450,7 @@ bool CvCapture_FFMPEG::grabFrame() + + #if USE_AV_SEND_FRAME_API + // check if we can receive frame from previously decoded packet +- valid = avcodec_receive_frame(video_st->codec, picture) >= 0; ++ valid = avcodec_receive_frame(context, picture) >= 0; + #endif + + // get the next frame +@@ -1372,19 +1500,19 @@ bool CvCapture_FFMPEG::grabFrame() + + // Decode video frame + #if USE_AV_SEND_FRAME_API +- if (avcodec_send_packet(video_st->codec, &packet) < 0) { ++ if (avcodec_send_packet(context, &packet) < 0) { + break; + } +- ret = avcodec_receive_frame(video_st->codec, picture); ++ ret = avcodec_receive_frame(context, picture); + #else + int got_picture = 0; +- avcodec_decode_video2(video_st->codec, picture, &got_picture, &packet); ++ avcodec_decode_video2(context, picture, &got_picture, &packet); + ret = got_picture ? 0 : -1; + #endif + if (ret >= 0) { + //picture_pts = picture->best_effort_timestamp; + if( picture_pts == AV_NOPTS_VALUE_ ) +- picture_pts = picture->pkt_pts != AV_NOPTS_VALUE_ && picture->pkt_pts != 0 ? picture->pkt_pts : picture->pkt_dts; ++ picture_pts = picture->CV_FFMPEG_PTS_FIELD != AV_NOPTS_VALUE_ && picture->CV_FFMPEG_PTS_FIELD != 0 ? picture->CV_FFMPEG_PTS_FIELD : picture->pkt_dts; + + valid = true; + } else if (ret == AVERROR(EAGAIN)) { +@@ -1415,7 +1543,7 @@ bool CvCapture_FFMPEG::grabFrame() + + bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, int* width, int* height, int* cn) + { +- if (!video_st) ++ if (!video_st || !context) + return false; + + if (rawMode || flag == extraDataIdx) +@@ -1428,8 +1556,8 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, + ret = p.data != NULL; + } + else if (flag == extraDataIdx) { +- *data = ic->streams[video_stream]->codec->extradata; +- *step = ic->streams[video_stream]->codec->extradata_size; ++ *data = ic->streams[video_stream]->CV_FFMPEG_CODEC_FIELD->extradata; ++ *step = ic->streams[video_stream]->CV_FFMPEG_CODEC_FIELD->extradata_size; + } + *width = *step; + *height = 1; +@@ -1454,13 +1582,13 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, + return false; + + if( img_convert_ctx == NULL || +- frame.width != video_st->codec->width || +- frame.height != video_st->codec->height || ++ frame.width != video_st->CV_FFMPEG_CODEC_FIELD->width || ++ frame.height != video_st->CV_FFMPEG_CODEC_FIELD->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; ++ int buffer_width = context->coded_width, buffer_height = context->coded_height; + + img_convert_ctx = sws_getCachedContext( + img_convert_ctx, +@@ -1494,8 +1622,8 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, + _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.width = video_st->CV_FFMPEG_CODEC_FIELD->width; ++ frame.height = video_st->CV_FFMPEG_CODEC_FIELD->height; + frame.cn = 3; + frame.data = rgb_picture.data[0]; + frame.step = rgb_picture.linesize[0]; +@@ -1505,7 +1633,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int flag, unsigned char** data, int* step, + img_convert_ctx, + sw_picture->data, + sw_picture->linesize, +- 0, video_st->codec->coded_height, ++ 0, context->coded_height, + rgb_picture.data, + rgb_picture.linesize + ); +@@ -1529,12 +1657,12 @@ bool CvCapture_FFMPEG::retrieveHWFrame(cv::OutputArray output) + { + #if USE_AV_HW_CODECS + // check that we have HW frame in GPU memory +- if (!picture || !picture->hw_frames_ctx) { ++ if (!picture || !picture->hw_frames_ctx || !context) { + return false; + } + + // GPU color conversion NV12->BGRA, from GPU media buffer to GPU OpenCL buffer +- return hw_copy_frame_to_umat(video_st->codec->hw_device_ctx, picture, output); ++ return hw_copy_frame_to_umat(context->hw_device_ctx, picture, output); + #else + CV_UNUSED(output); + return false; +@@ -1543,7 +1671,7 @@ bool CvCapture_FFMPEG::retrieveHWFrame(cv::OutputArray output) + + double CvCapture_FFMPEG::getProperty( int property_id ) const + { +- if( !video_st ) return 0; ++ if( !video_st || !context ) return 0; + + double codec_tag = 0; + CV_CODEC_ID codec_id = AV_CODEC_ID_NONE; +@@ -1570,8 +1698,8 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const + case CAP_PROP_FPS: + return get_fps(); + case CAP_PROP_FOURCC: +- codec_id = video_st->codec->codec_id; +- codec_tag = (double) video_st->codec->codec_tag; ++ codec_id = video_st->CV_FFMPEG_CODEC_FIELD->codec_id; ++ codec_tag = (double) video_st->CV_FFMPEG_CODEC_FIELD->codec_tag; + + if(codec_tag || codec_id == AV_CODEC_ID_NONE) + { +@@ -1591,7 +1719,11 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const + return _opencv_ffmpeg_get_sample_aspect_ratio(ic->streams[video_stream]).den; + case CAP_PROP_CODEC_PIXEL_FORMAT: + { ++#ifdef CV_FFMPEG_CODECPAR ++ AVPixelFormat pix_fmt = (AVPixelFormat)video_st->codecpar->format; ++#else + AVPixelFormat pix_fmt = video_st->codec->pix_fmt; ++#endif + unsigned int fourcc_tag = avcodec_pix_fmt_to_codec_tag(pix_fmt); + return (fourcc_tag == 0) ? (double)-1 : (double)fourcc_tag; + } +@@ -1671,7 +1803,7 @@ double CvCapture_FFMPEG::get_fps() const + + if (fps < eps_zero) + { +- fps = 1.0 / r2d(ic->streams[video_stream]->codec->time_base); ++ fps = 1.0 / r2d(ic->streams[video_stream]->time_base); + } + #endif + return fps; +@@ -1703,7 +1835,16 @@ double CvCapture_FFMPEG::dts_to_sec(int64_t dts) const + void CvCapture_FFMPEG::get_rotation_angle() + { + rotation_angle = 0; +-#if LIBAVUTIL_BUILD >= CALC_FFMPEG_VERSION(52, 94, 100) ++#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(57, 68, 100) ++ const uint8_t *data = 0; ++ data = av_stream_get_side_data(video_st, AV_PKT_DATA_DISPLAYMATRIX, NULL); ++ if (data) ++ { ++ rotation_angle = cvRound(av_display_rotation_get((const int32_t*)data)); ++ if (rotation_angle < 0) ++ rotation_angle += 360; ++ } ++#elif LIBAVUTIL_BUILD >= CALC_FFMPEG_VERSION(52, 94, 100) + AVDictionaryEntry *rotate_tag = av_dict_get(video_st->metadata, "rotate", NULL, 0); + if (rotate_tag != NULL) + rotation_angle = atoi(rotate_tag->value); +@@ -1712,6 +1853,7 @@ void CvCapture_FFMPEG::get_rotation_angle() + + void CvCapture_FFMPEG::seek(int64_t _frame_number) + { ++ CV_Assert(context); + _frame_number = std::min(_frame_number, get_total_frames()); + int delta = 16; + +@@ -1728,7 +1870,7 @@ void CvCapture_FFMPEG::seek(int64_t _frame_number) + 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); ++ avcodec_flush_buffers(context); + if( _frame_number > 0 ) + { + grabFrame(); +@@ -1833,7 +1975,7 @@ struct CvVideoWriter_FFMPEG + + void init(); + +- AVOutputFormat * fmt; ++ CV_FFMPEG_FMT_CONST AVOutputFormat * fmt; + AVFormatContext * oc; + uint8_t * outbuf; + uint32_t outbuf_size; +@@ -1842,6 +1984,7 @@ struct CvVideoWriter_FFMPEG + AVFrame * input_picture; + uint8_t * picbuf; + AVStream * video_st; ++ AVCodecContext * context; + AVPixelFormat input_pix_fmt; + unsigned char * aligned_input; + size_t aligned_input_size; +@@ -1906,6 +2049,7 @@ void CvVideoWriter_FFMPEG::init() + input_picture = 0; + picbuf = 0; + video_st = 0; ++ context = 0; + input_pix_fmt = AV_PIX_FMT_NONE; + aligned_input = NULL; + aligned_input_size = 0; +@@ -1957,23 +2101,32 @@ static AVFrame * icv_alloc_picture_FFMPEG(int pix_fmt, int width, int height, bo + } + + /* configure video stream */ +-static bool icv_configure_video_stream_FFMPEG(AVFormatContext *oc, ++static AVCodecContext * icv_configure_video_stream_FFMPEG(AVFormatContext *oc, + AVStream *st, + const AVCodec* codec, + int w, int h, int bitrate, +- double fps, AVPixelFormat pixel_format) ++ double fps, AVPixelFormat pixel_format, int fourcc) + { ++#ifdef CV_FFMPEG_CODECPAR ++ AVCodecContext *c = avcodec_alloc_context3(codec); ++#else + AVCodecContext *c = st->codec; ++#endif ++ CV_Assert(c); ++ + int frame_rate, frame_rate_base; + + c->codec_id = codec->id; + c->codec_type = AVMEDIA_TYPE_VIDEO; ++ c->codec_tag = fourcc; + ++#ifndef CV_FFMPEG_CODECPAR + // Set per-codec defaults + CV_CODEC_ID 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; +@@ -2016,7 +2169,12 @@ static bool icv_configure_video_stream_FFMPEG(AVFormatContext *oc, + } + } + if (best == NULL) +- return false; ++ { ++#ifdef CV_FFMPEG_CODECPAR ++ avcodec_free_context(&c); ++#endif ++ return NULL; ++ } + c->time_base.den= best->num; + c->time_base.num= best->den; + } +@@ -2059,26 +2217,20 @@ static bool icv_configure_video_stream_FFMPEG(AVFormatContext *oc, + #endif + } + +-#if defined(_MSC_VER) +- AVRational avg_frame_rate = {frame_rate, frame_rate_base}; +- st->avg_frame_rate = avg_frame_rate; +-#else +- st->avg_frame_rate = (AVRational){frame_rate, frame_rate_base}; +-#endif ++ st->avg_frame_rate = av_make_q(frame_rate, frame_rate_base); + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(55, 20, 0) + st->time_base = c->time_base; + #endif + +- return true; ++ return c; + } + + static const int OPENCV_NO_FRAMES_WRITTEN_CODE = 1000; + +-static int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, ++static int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st, AVCodecContext * c, + uint8_t *, uint32_t, + AVFrame * picture, int frame_idx) + { +- AVCodecContext* c = video_st->codec; + int ret = OPENCV_NO_FRAMES_WRITTEN_CODE; + + #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(57, 0, 0) +@@ -2176,9 +2328,6 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int + width = frame_width; + height = frame_height; + +- // typecast from opaque data type to implemented struct +- AVCodecContext* c = video_st->codec; +- + // FFmpeg contains SIMD optimizations which can sometimes read data past + // the supplied input buffer. + // Related info: https://trac.ffmpeg.org/ticket/6763 +@@ -2215,10 +2364,10 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int + step = aligned_step; + } + +- AVPixelFormat sw_pix_fmt = c->pix_fmt; ++ AVPixelFormat sw_pix_fmt = context->pix_fmt; + #if USE_AV_HW_CODECS +- if (c->hw_frames_ctx) +- sw_pix_fmt = ((AVHWFramesContext*)c->hw_frames_ctx->data)->sw_format; ++ if (context->hw_frames_ctx) ++ sw_pix_fmt = ((AVHWFramesContext*)context->hw_frames_ctx->data)->sw_format; + #endif + if ( sw_pix_fmt != input_pix_fmt ) { + CV_Assert( input_picture ); +@@ -2232,8 +2381,8 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int + img_convert_ctx = sws_getContext(width, + height, + (AVPixelFormat)input_pix_fmt, +- c->width, +- c->height, ++ context->width, ++ context->height, + sw_pix_fmt, + SWS_BICUBIC, + NULL, NULL, NULL); +@@ -2255,14 +2404,14 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int + + bool ret; + #if USE_AV_HW_CODECS +- if (video_st->codec->hw_device_ctx) { ++ if (context->hw_device_ctx) { + // copy data to HW frame + AVFrame* hw_frame = av_frame_alloc(); + if (!hw_frame) { + CV_LOG_ERROR(NULL, "Error allocating AVFrame (av_frame_alloc)"); + return false; + } +- if (av_hwframe_get_buffer(video_st->codec->hw_frames_ctx, hw_frame, 0) < 0) { ++ if (av_hwframe_get_buffer(context->hw_frames_ctx, hw_frame, 0) < 0) { + CV_LOG_ERROR(NULL, "Error obtaining HW frame (av_hwframe_get_buffer)"); + av_frame_free(&hw_frame); + return false; +@@ -2273,14 +2422,14 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int + return false; + } + hw_frame->pts = frame_idx; +- int ret_write = icv_av_write_frame_FFMPEG(oc, video_st, outbuf, outbuf_size, hw_frame, frame_idx); ++ int ret_write = icv_av_write_frame_FFMPEG(oc, video_st, context, outbuf, outbuf_size, hw_frame, frame_idx); + ret = ret_write >= 0 ? true : false; + av_frame_free(&hw_frame); + } else + #endif + { + picture->pts = frame_idx; +- int ret_write = icv_av_write_frame_FFMPEG(oc, video_st, outbuf, outbuf_size, picture, frame_idx); ++ int ret_write = icv_av_write_frame_FFMPEG(oc, video_st, context, outbuf, outbuf_size, picture, frame_idx); + ret = ret_write >= 0 ? true : false; + } + +@@ -2291,7 +2440,7 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int + + bool CvVideoWriter_FFMPEG::writeHWFrame(cv::InputArray input) { + #if USE_AV_HW_CODECS +- if (!video_st->codec->hw_frames_ctx) ++ if (!video_st || !context || !context->hw_frames_ctx || !context->hw_device_ctx) + return false; + + // Get hardware frame from frame pool +@@ -2299,20 +2448,20 @@ bool CvVideoWriter_FFMPEG::writeHWFrame(cv::InputArray input) { + if (!hw_frame) { + return false; + } +- if (av_hwframe_get_buffer(video_st->codec->hw_frames_ctx, hw_frame, 0) < 0) { ++ if (av_hwframe_get_buffer(context->hw_frames_ctx, hw_frame, 0) < 0) { + av_frame_free(&hw_frame); + return false; + } + + // GPU to GPU copy +- if (!hw_copy_umat_to_frame(video_st->codec->hw_device_ctx, input, hw_frame)) { ++ if (!hw_copy_umat_to_frame(context->hw_device_ctx, input, hw_frame)) { + av_frame_free(&hw_frame); + return false; + } + + // encode + hw_frame->pts = frame_idx; +- icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, hw_frame, frame_idx); ++ icv_av_write_frame_FFMPEG( oc, video_st, context, outbuf, outbuf_size, hw_frame, frame_idx); + frame_idx++; + + av_frame_free(&hw_frame); +@@ -2365,7 +2514,7 @@ void CvVideoWriter_FFMPEG::close() + { + for(;;) + { +- int ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, NULL, frame_idx); ++ int ret = icv_av_write_frame_FFMPEG( oc, video_st, context, outbuf, outbuf_size, NULL, frame_idx); + if( ret == OPENCV_NO_FRAMES_WRITTEN_CODE || ret < 0 ) + break; + } +@@ -2380,7 +2529,7 @@ void CvVideoWriter_FFMPEG::close() + } + + // free pictures +- if( video_st->codec->pix_fmt != input_pix_fmt) ++ if( context->pix_fmt != input_pix_fmt) + { + if(picture->data[0]) + free(picture->data[0]); +@@ -2392,7 +2541,7 @@ void CvVideoWriter_FFMPEG::close() + av_free(input_picture); + + /* close codec */ +- avcodec_close(video_st->codec); ++ avcodec_close(context); + + av_free(outbuf); + +@@ -2599,8 +2748,15 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + + /* set file name */ + oc->oformat = fmt; ++#ifndef CV_FFMPEG_URL + snprintf(oc->filename, sizeof(oc->filename), "%s", filename); +- ++#else ++ size_t name_len = strlen(filename); ++ oc->url = (char*)av_malloc(name_len + 1); ++ CV_Assert(oc->url); ++ memcpy((void*)oc->url, filename, name_len + 1); ++ oc->url[name_len] = '\0'; ++#endif + /* set some options */ + oc->max_delay = (int)(0.7*AV_TIME_BASE); /* This reduces buffer underrun warnings with MPEG */ + +@@ -2715,7 +2871,7 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + double bitrate = std::min(bitrate_scale*fps*width*height, (double)INT_MAX/2); + + if (codec_id == AV_CODEC_ID_NONE) { +- codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO); ++ codec_id = av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_VIDEO); + } + + // Add video stream to output file +@@ -2733,11 +2889,9 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + } + #endif + +- AVCodecContext *c = video_st->codec; +- + // find and open encoder, try HW acceleration types specified in 'hw_acceleration' list (in order) + int err = -1; +- AVCodec* codec = NULL; ++ const AVCodec* codec = NULL; + #if USE_AV_HW_CODECS + AVBufferRef* hw_device_ctx = NULL; + HWAccelIterator accel_iter(va_type, true/*isEncoder*/, dict); +@@ -2780,9 +2934,17 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + AVPixelFormat format = codec_pix_fmt; + #endif + +- if (!icv_configure_video_stream_FFMPEG(oc, video_st, codec, +- width, height, (int) (bitrate + 0.5), +- fps, format)) { ++#ifdef CV_FFMPEG_CODECPAR ++ if (context) ++ { ++ avcodec_free_context(&context); ++ } ++#endif ++ context = icv_configure_video_stream_FFMPEG(oc, video_st, codec, ++ width, height, (int) (bitrate + 0.5), ++ fps, format, fourcc); ++ if (!context) ++ { + continue; + } + +@@ -2794,27 +2956,25 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + #endif + #endif + +- c->codec_tag = fourcc; +- + #if USE_AV_HW_CODECS + if (hw_device_ctx) { +- c->hw_device_ctx = av_buffer_ref(hw_device_ctx); ++ context->hw_device_ctx = av_buffer_ref(hw_device_ctx); + if (hw_format != AV_PIX_FMT_NONE) { +- c->hw_frames_ctx = hw_create_frames(NULL, hw_device_ctx, width, height, hw_format); +- if (!c->hw_frames_ctx) ++ context->hw_frames_ctx = hw_create_frames(NULL, hw_device_ctx, width, height, hw_format); ++ if (!context->hw_frames_ctx) + continue; + } + } + #endif + +- int64_t lbit_rate = (int64_t) c->bit_rate; ++ int64_t lbit_rate = (int64_t) context->bit_rate; + lbit_rate += (int64_t)(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; ++ context->bit_rate_tolerance = (int) lbit_rate; ++ context->bit_rate = (int) lbit_rate; + + /* open the codec */ +- err = avcodec_open2(c, codec, NULL); ++ err = avcodec_open2(context, codec, NULL); + if (err >= 0) { + #if USE_AV_HW_CODECS + va_type = hw_type_to_va_type(hw_type); +@@ -2823,7 +2983,7 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + #endif + break; + } else { +- CV_LOG_ERROR(NULL, "Could not open codec " << codec->name << ", error: " << icvFFMPEGErrStr(err)); ++ CV_LOG_ERROR(NULL, "Could not open codec " << codec->name << ", error: " << icvFFMPEGErrStr(err) << " (" << err << ")"); + } + #if USE_AV_HW_CODECS + } // while (accel_iter.good()) +@@ -2844,6 +3004,12 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + return false; + } + ++#ifdef CV_FFMPEG_CODECPAR ++ // Copy all to codecpar... ++ // !!! https://stackoverflow.com/questions/15897849/c-ffmpeg-not-writing-avcc-box-information ++ avcodec_parameters_from_context(video_st->codecpar, context); ++#endif ++ + outbuf = NULL; + + +@@ -2858,16 +3024,16 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + } + + bool need_color_convert; +- AVPixelFormat sw_pix_fmt = c->pix_fmt; ++ AVPixelFormat sw_pix_fmt = context->pix_fmt; + #if USE_AV_HW_CODECS +- if (c->hw_frames_ctx) +- sw_pix_fmt = ((AVHWFramesContext*)c->hw_frames_ctx->data)->sw_format; ++ if (context->hw_frames_ctx) ++ sw_pix_fmt = ((AVHWFramesContext*)context->hw_frames_ctx->data)->sw_format; + #endif + + need_color_convert = (sw_pix_fmt != input_pix_fmt); + + /* allocate the encoded raw picture */ +- picture = icv_alloc_picture_FFMPEG(sw_pix_fmt, c->width, c->height, need_color_convert); ++ picture = icv_alloc_picture_FFMPEG(sw_pix_fmt, context->width, context->height, need_color_convert); + if (!picture) { + return false; + } +@@ -2877,7 +3043,7 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc, + 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); ++ input_picture = icv_alloc_picture_FFMPEG(input_pix_fmt, context->width, context->height, false); + if (!input_picture) { + return false; + }