File 0002-videoio-initial-FFmpeg-5.0-support.patch of Package opencv3
From 40fb2701054ee3e5f76f1179e105da4fb7fea44b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
Date: Sun, 27 Nov 2022 00:54:26 +0100
Subject: [PATCH 2/2] videoio: initial FFmpeg 5.0 support
(cherry picked from commit 5440fd6cb43ea65a056c46b691fcdab1a425e92d)
videoio(ffmpeg): avoid memory leaks
(cherry picked from commit 271f7df3435c619ceba9261f88dcfbb0714b0b0d)
---
modules/videoio/src/cap_ffmpeg_impl.hpp | 327 +++++++++++++++++-------
1 file changed, 239 insertions(+), 88 deletions(-)
diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp
index 872f6f9c79..131e0d8e50 100644
--- a/modules/videoio/src/cap_ffmpeg_impl.hpp
+++ b/modules/videoio/src/cap_ffmpeg_impl.hpp
@@ -41,11 +41,17 @@
//M*/
#include "cap_ffmpeg_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 <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 +86,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,6 +96,62 @@ 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
@@ -446,6 +509,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,6 +547,7 @@ struct CvCapture_FFMPEG
AVFormatContext * ic;
AVCodec * avcodec;
+ AVCodecContext * context;
int video_stream;
AVStream * video_st;
AVFrame * picture;
@@ -534,6 +607,7 @@ void CvCapture_FFMPEG::init()
img_convert_ctx = 0;
avcodec = 0;
+ context = 0;
frame_number = 0;
eps_zero = 0.000025;
@@ -582,10 +656,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);
@@ -747,6 +830,7 @@ void ImplMutex::lock() { impl->lock(); }
void ImplMutex::unlock() { impl->unlock(); }
bool ImplMutex::trylock() { return impl->trylock(); }
+#ifdef CV_FFMPEG_LOCKMGR
static int LockCallBack(void **mutex, AVLockOp op)
{
ImplMutex* localMutex = reinterpret_cast<ImplMutex*>(*mutex);
@@ -794,6 +878,7 @@ private:
AutoLock(const AutoLock&); // disabled
AutoLock& operator = (const AutoLock&); // disabled
};
+#endif
static void ffmpeg_log_callback(void *ptr, int level, const char *fmt, va_list vargs)
{
@@ -855,11 +940,15 @@ 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
_initialized = true;
}
@@ -867,11 +956,47 @@ public:
~InternalFFMpegRegister()
{
_initialized = false;
+#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 )
{
InternalFFMpegRegister::init();
@@ -910,7 +1035,7 @@ bool CvCapture_FFMPEG::open( const char* _filename )
#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)
{
@@ -928,61 +1053,51 @@ bool CvCapture_FFMPEG::open( const char* _filename )
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)
{
// backup encoder' width/height
- int enc_width = enc->width;
- int enc_height = enc->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
AVCodec *codec;
- if(av_dict_get(dict, "video_codec", NULL, 0) == NULL) {
- codec = avcodec_find_decoder(enc->codec_id);
+ AVDictionaryEntry* video_codec_param = av_dict_get(dict, "video_codec", NULL, 0);
+ if (video_codec_param == NULL)
+ codec = avcodec_find_decoder(codec_id);
} else {
- codec = avcodec_find_decoder_by_name(av_dict_get(dict, "video_codec", NULL, 0)->value);
+ codec = avcodec_find_decoder_by_name(video_codec_param->value);
+ }
+ if (err < 0) {
+ CV_LOG_ERROR(NULL, "VIDEOIO/FFMPEG: Failed to initialize VideoCapture");
+ goto exit_func;
}
if (!codec || avcodec_open2(enc, codec, NULL) < 0)
goto exit_func;
// checking width/height (since decoder can sometimes alter it, eg. vp6f)
- if (enc_width && (enc->width != enc_width)) { enc->width = enc_width; }
- if (enc_height && (enc->height != enc_height)) { enc->height = enc_height; }
+ 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];
@@ -993,8 +1108,8 @@ bool CvCapture_FFMPEG::open( const char* _filename )
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;
@@ -1147,7 +1262,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 )
@@ -1214,7 +1329,7 @@ bool CvCapture_FFMPEG::grabFrame()
{
//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;
}
@@ -1243,7 +1358,7 @@ bool CvCapture_FFMPEG::grabFrame()
bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn)
{
- if (!video_st)
+ if (!video_st || !context)
return false;
if (rawMode)
@@ -1261,13 +1376,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,
@@ -1301,8 +1416,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];
@@ -1312,7 +1427,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
img_convert_ctx,
picture->data,
picture->linesize,
- 0, video_st->codec->coded_height,
+ 0, context->coded_height,
rgb_picture.data,
rgb_picture.linesize
);
@@ -1328,7 +1443,7 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
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;
@@ -1355,8 +1470,8 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
case CV_FFMPEG_CAP_PROP_FPS:
return get_fps();
case CV_FFMPEG_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)
{
@@ -1376,7 +1491,11 @@ double CvCapture_FFMPEG::getProperty( int property_id ) const
return _opencv_ffmpeg_get_sample_aspect_ratio(ic->streams[video_stream]).den;
case CV_FFMPEG_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;
}
@@ -1446,7 +1565,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;
@@ -1478,7 +1597,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);
@@ -1487,6 +1615,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;
@@ -1503,7 +1632,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();
@@ -1615,7 +1744,7 @@ struct CvVideoWriter_FFMPEG
void init();
- AVOutputFormat * fmt;
+ CV_FFMPEG_FMT_CONST AVOutputFormat * fmt;
AVFormatContext * oc;
uint8_t * outbuf;
uint32_t outbuf_size;
@@ -1625,6 +1754,7 @@ struct CvVideoWriter_FFMPEG
uint8_t * picbuf;
AVStream * video_st;
int input_pix_fmt;
+ AVCodecContext * context;
unsigned char * aligned_input;
size_t aligned_input_size;
int frame_width, frame_height;
@@ -1686,6 +1816,7 @@ void CvVideoWriter_FFMPEG::init()
picbuf = 0;
video_st = 0;
input_pix_fmt = 0;
+ context = 0;
aligned_input = NULL;
aligned_input_size = 0;
img_convert_ctx = 0;
@@ -1736,7 +1867,7 @@ static AVFrame * icv_alloc_picture_FFMPEG(int pix_fmt, int width, int height, bo
static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
CV_CODEC_ID codec_id,
int w, int h, int bitrate,
- double fps, int pixel_format)
+ double fps, int pixel_format, int fourcc)
{
AVCodecContext *c;
AVStream *st;
@@ -1750,6 +1881,7 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
return NULL;
}
+// XXX
c = st->codec;
c->codec_id = av_guess_codec(oc->oformat, NULL, oc->filename, NULL, AVMEDIA_TYPE_VIDEO);
@@ -1762,12 +1894,15 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
codec = avcodec_find_encoder(c->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;
@@ -1810,7 +1945,12 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
}
}
if (best == NULL)
+ {
+#ifdef CV_FFMPEG_CODECPAR
+ avcodec_free_context(&c);
+#endif
return NULL;
+ }
c->time_base.den= best->num;
c->time_base.num= best->den;
}
@@ -1853,26 +1993,20 @@ static AVStream *icv_add_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 st;
+ 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 )
{
- AVCodecContext* c = video_st->codec;
int ret = OPENCV_NO_FRAMES_WRITTEN_CODE;
#if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(57, 0, 0)
@@ -1942,9 +2076,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
@@ -1981,7 +2112,8 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
step = aligned_step;
}
- if ( c->pix_fmt != input_pix_fmt ) {
+ AVPixelFormat sw_pix_fmt = context->pix_fmt;
+ if ( sw_pix_fmt != input_pix_fmt ) {
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,
@@ -1993,9 +2125,9 @@ 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,
- c->pix_fmt,
+ context->width,
+ context->height,
+ sw_pix_fmt,
SWS_BICUBIC,
NULL, NULL, NULL);
if( !img_convert_ctx )
@@ -2015,12 +2147,14 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
}
picture->pts = frame_idx;
- bool ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0;
+ int ret_write = icv_av_write_frame_FFMPEG(oc, video_st, context, outbuf, outbuf_size, picture, frame_idx);
+ bool ret = ret_write >= 0 ? true : false;
frame_idx++;
return ret;
}
+
/// close video output stream and free associated memory
void CvVideoWriter_FFMPEG::close()
{
@@ -2038,7 +2172,7 @@ void CvVideoWriter_FFMPEG::close()
{
for(;;)
{
- int ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, NULL);
+ 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;
}
@@ -2053,7 +2187,7 @@ void CvVideoWriter_FFMPEG::close()
}
// free pictures
- if (picture && video_st && 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]);
@@ -2063,11 +2197,14 @@ void CvVideoWriter_FFMPEG::close()
av_freep(&input_picture);
- if (video_st && video_st->codec)
- {
- /* close codec */
- avcodec_close(video_st->codec);
- }
+#ifdef CV_FFMPEG_CODECPAR
+ avcodec_free_context(&context);
+#else
+ /* close codec */
+ if (context) // fixed after https://github.com/FFmpeg/FFmpeg/commit/3e1f507f3e8f16b716aa115552d243b48ae809bd
+ avcodec_close(context);
+ context = NULL;
+#endif
av_freep(&outbuf);
@@ -2227,8 +2364,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 */
@@ -2384,6 +2528,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;
@@ -2398,10 +2548,11 @@ bool CvVideoWriter_FFMPEG::open( const char * filename, int fourcc,
}
bool need_color_convert;
- need_color_convert = (c->pix_fmt != input_pix_fmt);
+ AVPixelFormat sw_pix_fmt = context->pix_fmt;
+ need_color_convert = (sw_pix_fmt != input_pix_fmt);
/* allocate the encoded raw picture */
- picture = icv_alloc_picture_FFMPEG(c->pix_fmt, c->width, c->height, need_color_convert);
+ picture = icv_alloc_picture_FFMPEG(sw_pix_fmt, context->width, context->height, need_color_convert);
if (!picture) {
return false;
}
@@ -2411,7 +2562,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;
}
--
2.38.1