Fix build error due to upgrade to ffmpeg 5.1.2 46/285546/2 accepted/tizen/unified/20221221.165303
authorhj kim <backto.kim@samsung.com>
Wed, 14 Dec 2022 09:32:39 +0000 (18:32 +0900)
committerhj kim <backto.kim@samsung.com>
Thu, 15 Dec 2022 01:18:47 +0000 (10:18 +0900)
[Version] 4.5.3-5
[Issue type] Build error fix

videoio.hpp, cap_ffmpeg_impl.hpp : Get all code from opencv 4.6.0(official release, https://opencv.org/releases/)

Change-Id: Ib6338e21017ae7404cf82e2b6b707a736ffa43a7

modules/videoio/include/opencv2/videoio.hpp
modules/videoio/src/cap_ffmpeg_impl.hpp
modules/videoio/src/ffmpeg_codecs.hpp
packaging/opencv.spec

index 348448bda7a89a8018e3329c2c6a505ee46b5728..93ea8cdddcf5fc5876f6af848aba8105a70e7536 100644 (file)
@@ -186,6 +186,22 @@ enum VideoCaptureProperties {
        CAP_PROP_HW_ACCELERATION=50, //!< (**open-only**) Hardware acceleration type (see #VideoAccelerationType). Setting supported only via `params` parameter in cv::VideoCapture constructor / .open() method. Default value is backend-specific.
        CAP_PROP_HW_DEVICE      =51, //!< (**open-only**) Hardware device index (select GPU if multiple available). Device enumeration is acceleration type specific.
        CAP_PROP_HW_ACCELERATION_USE_OPENCL=52, //!< (**open-only**) If non-zero, create new OpenCL context and bind it to current thread. The OpenCL context created with Video Acceleration context attached it (if not attached yet) for optimized GPU data copy between HW accelerated decoder and cv::UMat.
+       CAP_PROP_OPEN_TIMEOUT_MSEC=53, //!< (**open-only**) timeout in milliseconds for opening a video capture (applicable for FFmpeg back-end only)
+       CAP_PROP_READ_TIMEOUT_MSEC=54, //!< (**open-only**) timeout in milliseconds for reading from a video capture (applicable for FFmpeg back-end only)
+       CAP_PROP_STREAM_OPEN_TIME_USEC =55, //<! (read-only) time in microseconds since Jan 1 1970 when stream was opened. Applicable for FFmpeg backend only. Useful for RTSP and other live streams
+       CAP_PROP_VIDEO_TOTAL_CHANNELS = 56, //!< (read-only) Number of video channels
+       CAP_PROP_VIDEO_STREAM = 57, //!< (**open-only**) Specify video stream, 0-based index. Use -1 to disable video stream from file or IP cameras. Default value is 0.
+       CAP_PROP_AUDIO_STREAM = 58, //!< (**open-only**) Specify stream in multi-language media files, -1 - disable audio processing or microphone. Default value is -1.
+       CAP_PROP_AUDIO_POS = 59, //!< (read-only) Audio position is measured in samples. Accurate audio sample timestamp of previous grabbed fragment. See CAP_PROP_AUDIO_SAMPLES_PER_SECOND and CAP_PROP_AUDIO_SHIFT_NSEC.
+       CAP_PROP_AUDIO_SHIFT_NSEC = 60, //!< (read only) Contains the time difference between the start of the audio stream and the video stream in nanoseconds. Positive value means that audio is started after the first video frame. Negative value means that audio is started before the first video frame.
+       CAP_PROP_AUDIO_DATA_DEPTH = 61, //!< (open, read) Alternative definition to bits-per-sample, but with clear handling of 32F / 32S
+       CAP_PROP_AUDIO_SAMPLES_PER_SECOND = 62, //!< (open, read) determined from file/codec input. If not specified, then selected audio sample rate is 44100
+       CAP_PROP_AUDIO_BASE_INDEX = 63, //!< (read-only) Index of the first audio channel for .retrieve() calls. That audio channel number continues enumeration after video channels.
+       CAP_PROP_AUDIO_TOTAL_CHANNELS = 64, //!< (read-only) Number of audio channels in the selected audio stream (mono, stereo, etc)
+       CAP_PROP_AUDIO_TOTAL_STREAMS = 65, //!< (read-only) Number of audio streams.
+       CAP_PROP_AUDIO_SYNCHRONIZE = 66, //!< (open, read) Enables audio synchronization.
+       CAP_PROP_LRF_HAS_KEY_FRAME = 67, //!< FFmpeg back-end only - Indicates whether the Last Raw Frame (LRF), output from VideoCapture::read() when VideoCapture is initialized with VideoCapture::open(CAP_FFMPEG, {CAP_PROP_FORMAT, -1}) or VideoCapture::set(CAP_PROP_FORMAT,-1) is called before the first call to VideoCapture::read(), contains encoded data for a key frame.
+       CAP_PROP_CODEC_EXTRADATA_INDEX = 68, //!< Positive index indicates that returning extra data is supported by the video back end.  This can be retrieved as cap.retrieve(data, <returned index>).  E.g. When reading from a h264 encoded RTSP stream, the FFmpeg backend could return the SPS and/or PPS if available (if sent in reply to a DESCRIBE request), from calls to cap.retrieve(data, <returned index>).
 #ifndef CV_DOXYGEN
        CV__CAP_PROP_LATEST
 #endif
index 1e73cb8fc8811939cf1b5d77bc09b5353f9473af..b7fa0b745c1e13e26cbd053804373da02e8de551 100644 (file)
 //M*/
 
 #include "cap_ffmpeg_legacy_api.hpp"
+#include "opencv2/core/utils/logger.hpp"
+#include "cap_interface.hpp"
 
 using namespace cv;
 
 #if !(defined(_WIN32) || defined(WINCE))
 # include <pthread.h>
 #endif
-#include <assert.h>
 #include <algorithm>
 #include <limits>
+#include <string.h>
 
 #ifndef __OPENCV_BUILD
 #define CV_FOURCC(c1, c2, c3, c4) (((c1) & 255) + (((c2) & 255) << 8) + (((c3) & 255) << 16) + (((c4) & 255) << 24))
@@ -80,6 +82,7 @@ extern "C" {
 
 #include <libavutil/mathematics.h>
 #include <libavutil/opt.h>
+#include <libavutil/display.h>
 
 #if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \
     ? CALC_FFMPEG_VERSION(51, 63, 100) : CALC_FFMPEG_VERSION(54, 6, 0))
@@ -89,10 +92,72 @@ extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libswscale/swscale.h>
 
+// 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 <libavcodec/bsf.h>
+#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
 
+// GCC 4.x compilation bug. Details: https://github.com/opencv/opencv/issues/20292
+#if (defined(__GNUC__) && __GNUC__ < 5) && !defined(__clang__)
+#undef USE_AV_HW_CODECS
+#define USE_AV_HW_CODECS 0
+#endif
+
 //#define USE_AV_HW_CODECS 0
 #ifndef USE_AV_HW_CODECS
 #if LIBAVUTIL_VERSION_MAJOR >= 56 // FFMPEG 4.0+
@@ -183,8 +248,8 @@ extern "C" {
 #endif
 
 #if USE_AV_INTERRUPT_CALLBACK
-#define LIBAVFORMAT_INTERRUPT_OPEN_TIMEOUT_MS 30000
-#define LIBAVFORMAT_INTERRUPT_READ_TIMEOUT_MS 30000
+#define LIBAVFORMAT_INTERRUPT_OPEN_DEFAULT_TIMEOUT_MS 30000
+#define LIBAVFORMAT_INTERRUPT_READ_DEFAULT_TIMEOUT_MS 30000
 
 #ifdef _WIN32
 // http://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows
@@ -394,7 +459,7 @@ static
 inline int _opencv_ffmpeg_interrupt_callback(void *ptr)
 {
     AVInterruptCallbackMetadata* metadata = (AVInterruptCallbackMetadata*)ptr;
-    assert(metadata);
+    CV_Assert(metadata);
 
     if (metadata->timeout_after_ms == 0)
     {
@@ -466,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
 {
@@ -475,7 +549,7 @@ struct CvCapture_FFMPEG
     double getProperty(int) const;
     bool setProperty(int, double);
     bool grabFrame();
-    bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn);
+    bool retrieveFrame(int flag, unsigned char** data, int* step, int* width, int* height, int* cn);
     bool retrieveHWFrame(cv::OutputArray output);
     void rotateFrame(cv::Mat &mat) const;
 
@@ -497,6 +571,7 @@ struct CvCapture_FFMPEG
 
     AVFormatContext * ic;
     AVCodec         * avcodec;
+    AVCodecContext  * context;
     int               video_stream;
     AVStream        * video_st;
     AVFrame         * picture;
@@ -523,6 +598,8 @@ struct CvCapture_FFMPEG
 
     AVDictionary *dict;
 #if USE_AV_INTERRUPT_CALLBACK
+    int open_timeout;
+    int read_timeout;
     AVInterruptCallbackMetadata interrupt_metadata;
 #endif
 
@@ -539,6 +616,7 @@ struct CvCapture_FFMPEG
     VideoAccelerationType va_type;
     int hw_device;
     int use_opencl;
+    int extraDataIdx;
 };
 
 void CvCapture_FFMPEG::init()
@@ -557,6 +635,7 @@ void CvCapture_FFMPEG::init()
     img_convert_ctx = 0;
 
     avcodec = 0;
+    context = 0;
     frame_number = 0;
     eps_zero = 0.000025;
 
@@ -569,6 +648,11 @@ void CvCapture_FFMPEG::init()
 #endif
     dict = NULL;
 
+#if USE_AV_INTERRUPT_CALLBACK
+    open_timeout = LIBAVFORMAT_INTERRUPT_OPEN_DEFAULT_TIMEOUT_MS;
+    read_timeout = LIBAVFORMAT_INTERRUPT_READ_DEFAULT_TIMEOUT_MS;
+#endif
+
     rawMode = false;
     rawModeInitialized = false;
     memset(&packet_filtered, 0, sizeof(packet_filtered));
@@ -577,6 +661,7 @@ void CvCapture_FFMPEG::init()
     va_type = cv::VIDEO_ACCELERATION_NONE;  // TODO OpenCV 5.0: change to _ANY?
     hw_device = -1;
     use_opencl = 0;
+    extraDataIdx = 1;
 }
 
 
@@ -603,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);
@@ -784,8 +878,10 @@ private:
 };
 #endif
 
+
 static ImplMutex _mutex;
 
+#ifdef CV_FFMPEG_LOCKMGR
 static int LockCallBack(void **mutex, AVLockOp op)
 {
     ImplMutex* localMutex = reinterpret_cast<ImplMutex*>(*mutex);
@@ -816,13 +912,14 @@ 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)
 {
     static bool skip_header = false;
     static int prev_level = -1;
     CV_UNUSED(ptr);
+    if (level>av_log_get_level()) return;
     if (!skip_header || level != prev_level) printf("[OPENCV:FFMPEG:%02d] ", level);
     vprintf(fmt, vargs);
     size_t fmt_len = strlen(fmt);
@@ -843,9 +940,15 @@ public:
     {
 #ifndef NO_GETENV
         char* debug_option = getenv("OPENCV_FFMPEG_DEBUG");
-        if (debug_option != NULL)
+        char* level_option = getenv("OPENCV_FFMPEG_LOGLEVEL");
+        int level = AV_LOG_VERBOSE;
+        if (level_option != NULL)
+        {
+            level = atoi(level_option);
+        }
+        if ( (debug_option != NULL) || (level_option != NULL) )
         {
-            av_log_set_level(AV_LOG_VERBOSE);
+            av_log_set_level(level);
             av_log_set_callback(ffmpeg_log_callback);
         }
         else
@@ -860,19 +963,59 @@ public:
     {
         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();
@@ -928,6 +1071,16 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters&
         if (params.has(CAP_PROP_HW_ACCELERATION_USE_OPENCL)) {
             use_opencl = params.get<int>(CAP_PROP_HW_ACCELERATION_USE_OPENCL);
         }
+#if USE_AV_INTERRUPT_CALLBACK
+        if (params.has(CAP_PROP_OPEN_TIMEOUT_MSEC))
+        {
+            open_timeout = params.get<int>(CAP_PROP_OPEN_TIMEOUT_MSEC);
+        }
+        if (params.has(CAP_PROP_READ_TIMEOUT_MSEC))
+        {
+            read_timeout = params.get<int>(CAP_PROP_READ_TIMEOUT_MSEC);
+        }
+#endif
         if (params.warnUnusedParameters())
         {
             CV_LOG_ERROR(NULL, "VIDEOIO/FFMPEG: unsupported parameters in .open(), see logger INFO channel for details. Bailout");
@@ -937,7 +1090,7 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters&
 
 #if USE_AV_INTERRUPT_CALLBACK
     /* interrupt callback */
-    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_OPEN_TIMEOUT_MS;
+    interrupt_metadata.timeout_after_ms = open_timeout;
     get_monotonic_time(&interrupt_metadata.value);
 
     ic = avformat_alloc_context();
@@ -949,7 +1102,11 @@ bool CvCapture_FFMPEG::open(const char* _filename, const VideoCaptureParameters&
     char* options = getenv("OPENCV_FFMPEG_CAPTURE_OPTIONS");
     if(options == NULL)
     {
+#if LIBAVFORMAT_VERSION_MICRO >= 100  && LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(55, 48, 100)
+        av_dict_set(&dict, "rtsp_flags", "prefer_tcp", 0);
+#else
         av_dict_set(&dict, "rtsp_transport", "tcp", 0);
+#endif
     }
     else
     {
@@ -962,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)
     {
@@ -980,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);
@@ -1045,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;
                         }
@@ -1071,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
@@ -1086,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);
@@ -1111,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];
@@ -1125,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;
@@ -1271,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 )
@@ -1282,12 +1445,12 @@ bool CvCapture_FFMPEG::grabFrame()
 #if USE_AV_INTERRUPT_CALLBACK
     // activate interrupt callback
     get_monotonic_time(&interrupt_metadata.value);
-    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_READ_TIMEOUT_MS;
+    interrupt_metadata.timeout_after_ms = read_timeout;
 #endif
 
 #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
@@ -1337,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)) {
@@ -1378,20 +1541,28 @@ bool CvCapture_FFMPEG::grabFrame()
     return valid;
 }
 
-bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
+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)
+    if (rawMode || flag == extraDataIdx)
     {
-        AVPacket& p = bsfc ? packet_filtered : packet;
-        *data = p.data;
-        *step = p.size;
-        *width = p.size;
+        bool ret = true;
+        if (flag == 0) {
+            AVPacket& p = bsfc ? packet_filtered : packet;
+            *data = p.data;
+            *step = p.size;
+            ret = p.data != NULL;
+        }
+        else if (flag == extraDataIdx) {
+            *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;
         *cn = 1;
-        return p.data != NULL;
+        return  ret;
     }
 
     AVFrame* sw_picture = picture;
@@ -1411,13 +1582,13 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
         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,
@@ -1451,8 +1622,8 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
         _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];
@@ -1462,7 +1633,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
             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
             );
@@ -1476,7 +1647,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
 #if USE_AV_HW_CODECS
     if (sw_picture != picture)
     {
-        av_frame_unref(sw_picture);
+        av_frame_free(&sw_picture);
     }
 #endif
     return true;
@@ -1486,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;
@@ -1500,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;
@@ -1527,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)
         {
@@ -1548,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;
     }
@@ -1556,6 +1731,12 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
         if (rawMode)
             return -1;
         break;
+    case CAP_PROP_LRF_HAS_KEY_FRAME: {
+        const AVPacket& p = bsfc ? packet_filtered : packet;
+        return ((p.flags & AV_PKT_FLAG_KEY) != 0) ? 1 : 0;
+    }
+    case CAP_PROP_CODEC_EXTRADATA_INDEX:
+            return extraDataIdx;
     case CAP_PROP_BITRATE:
         return static_cast<double>(get_bitrate());
     case CAP_PROP_ORIENTATION_META:
@@ -1574,6 +1755,9 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
     case CAP_PROP_HW_ACCELERATION_USE_OPENCL:
         return static_cast<double>(use_opencl);
 #endif  // USE_AV_HW_CODECS
+    case CAP_PROP_STREAM_OPEN_TIME_USEC:
+        //ic->start_time_realtime is in microseconds
+        return ((double)ic->start_time_realtime);
     default:
         break;
     }
@@ -1619,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;
@@ -1651,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);
@@ -1660,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;
 
@@ -1676,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();
@@ -1781,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;
@@ -1790,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;
@@ -1854,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;
@@ -1905,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;
@@ -1964,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;
     }
@@ -2007,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)
@@ -2116,7 +2320,7 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
         }
     }
     else {
-        assert(false);
+        CV_Assert(false);
     }
 
     if( (width & -2) != frame_width || (height & -2) != frame_height || !data )
@@ -2124,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
@@ -2163,13 +2364,13 @@ 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 ) {
-        assert( input_picture );
+        CV_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);
@@ -2180,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);
@@ -2203,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;
@@ -2221,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;
     }
 
@@ -2239,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
@@ -2247,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);
@@ -2295,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))
@@ -2313,7 +2510,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;
             }
@@ -2328,7 +2525,7 @@ void CvVideoWriter_FFMPEG::close()
     }
 
     // free pictures
-    if( video_st->codec->pix_fmt != input_pix_fmt)
+    if (picture && context && context->pix_fmt != input_pix_fmt)
     {
         if(picture->data[0])
             free(picture->data[0]);
@@ -2339,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(video_st->codec);
+    if (context)  // fixed after https://github.com/FFmpeg/FFmpeg/commit/3e1f507f3e8f16b716aa115552d243b48ae809bd
+        avcodec_close(context);
+    context = NULL;
+#endif
 
     av_free(outbuf);
 
@@ -2543,12 +2746,19 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
 
     // alloc memory for context
     oc = avformat_alloc_context();
-    assert (oc);
+    CV_Assert(oc);
 
     /* 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 */
 
@@ -2663,7 +2873,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
@@ -2681,11 +2891,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);
@@ -2728,9 +2936,14 @@ 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
+        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;
         }
 
@@ -2742,27 +2955,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);
@@ -2771,7 +2982,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())
@@ -2792,6 +3003,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;
 
 
@@ -2806,16 +3023,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;
     }
@@ -2825,7 +3042,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;
         }
index 61788e0345a6ac940ef09393a420adbcdd201696..994a1dbf1b241a84d44c5a51ab5c23c518709b28 100644 (file)
@@ -61,6 +61,7 @@ extern "C" {
 #endif
 
 #include <libavformat/avformat.h>
+#include <libavcodec/version.h>
 
 #ifdef __cplusplus
 }
index e5a22f3d99b49ec5c90c8cfdac4ac15779515fd6..1e4689fd8d4fa0112515b1afa98603322f11ef56 100644 (file)
@@ -7,7 +7,7 @@
 Name: opencv
 Summary: OpenCV library
 Version: 4.5.3
-Release: 4
+Release: 5
 Group: Development/Libraries
 License: Apache-2.0 and BSD-3-Clause
 Source0: %{name}-%{version}.tar.gz