File mlt-ffmpeg-8.patch of Package libmlt
From 80af88840f9edb2aaec093a9e16c4a889688623d Mon Sep 17 00:00:00 2001
From: Dan Dennedy <dan@dennedy.org>
Date: Tue, 26 Aug 2025 11:19:13 -0700
Subject: [PATCH] Support FFmpeg 8 (#1142)
* Support FFmpeg 8
* Fix support for FFmpeg 6 & 7
---
src/modules/avformat/common.c | 12 +++-
src/modules/avformat/consumer_avformat.c | 23 ++++---
src/modules/avformat/filter_avfilter.c | 11 ++++
src/modules/avformat/filter_swscale.c | 7 +++
src/modules/avformat/link_avfilter.c | 13 +++-
src/modules/avformat/producer_avformat.c | 79 +++++++++++++++++++++---
6 files changed, 126 insertions(+), 19 deletions(-)
diff --git a/src/modules/avformat/common.c b/src/modules/avformat/common.c
index e337651..eca4a04 100644
--- a/src/modules/avformat/common.c
+++ b/src/modules/avformat/common.c
@@ -367,10 +367,20 @@ void mlt_image_to_avframe(mlt_image image, mlt_frame mltframe, AVFrame *avframe)
avframe->height = image->height;
avframe->format = mlt_to_av_image_format(image->format);
avframe->sample_aspect_ratio = av_d2q(mlt_frame_get_aspect_ratio(mltframe), 1024);
- ;
avframe->pts = mlt_frame_get_position(mltframe);
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ if (!mlt_properties_get_int(frame_properties, "progressive"))
+ avframe->flags |= AV_FRAME_FLAG_INTERLACED;
+ else
+ avframe->flags &= ~AV_FRAME_FLAG_INTERLACED;
+ if (mlt_properties_get_int(frame_properties, "top_field_first"))
+ avframe->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
+ else
+ avframe->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
+#else
avframe->interlaced_frame = !mlt_properties_get_int(frame_properties, "progressive");
avframe->top_field_first = mlt_properties_get_int(frame_properties, "top_field_first");
+#endif
avframe->color_primaries = mlt_properties_get_int(frame_properties, "color_primaries");
avframe->color_trc = mlt_properties_get_int(frame_properties, "color_trc");
avframe->color_range = mlt_properties_get_int(frame_properties, "full_range")
diff --git a/src/modules/avformat/consumer_avformat.c b/src/modules/avformat/consumer_avformat.c
index 22a90dc..d44d555 100644
--- a/src/modules/avformat/consumer_avformat.c
+++ b/src/modules/avformat/consumer_avformat.c
@@ -1923,18 +1923,27 @@ static int encode_video(encode_ctx_t *enc_ctx,
avframe->pts = enc_ctx->frame_count;
// Set frame interlace hints
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ if (!mlt_properties_get_int(frame_properties, "progressive"))
+ avframe->flags |= AV_FRAME_FLAG_INTERLACED;
+ else
+ avframe->flags &= ~AV_FRAME_FLAG_INTERLACED;
+ const int tff = mlt_properties_get_int(frame_properties, "top_field_first");
+ if (tff)
+ avframe->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
+ else
+ avframe->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
+#else
avframe->interlaced_frame = !mlt_properties_get_int(frame_properties, "progressive");
- avframe->top_field_first = mlt_properties_get_int(frame_properties, "top_field_first");
+ const int tff = avframe->top_field_first = mlt_properties_get_int(frame_properties,
+ "top_field_first");
+#endif
if (mlt_properties_get_int(frame_properties, "progressive"))
c->field_order = AV_FIELD_PROGRESSIVE;
else if (c->codec_id == AV_CODEC_ID_MJPEG)
- c->field_order = (mlt_properties_get_int(frame_properties, "top_field_first"))
- ? AV_FIELD_TT
- : AV_FIELD_BB;
+ c->field_order = tff ? AV_FIELD_TT : AV_FIELD_BB;
else
- c->field_order = (mlt_properties_get_int(frame_properties, "top_field_first"))
- ? AV_FIELD_TB
- : AV_FIELD_BT;
+ c->field_order = tff ? AV_FIELD_TB : AV_FIELD_BT;
// Encode the image
ret = avcodec_send_frame(c, avframe);
diff --git a/src/modules/avformat/filter_avfilter.c b/src/modules/avformat/filter_avfilter.c
index 32736c1..8e7ff68 100644
--- a/src/modules/avformat/filter_avfilter.c
+++ b/src/modules/avformat/filter_avfilter.c
@@ -802,10 +802,21 @@ static int filter_get_image(mlt_frame frame,
pdata->avinframe->sample_aspect_ratio = (AVRational){profile->sample_aspect_num,
profile->sample_aspect_den};
pdata->avinframe->pts = pos;
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ if (!mlt_properties_get_int(frame_properties, "progressive"))
+ pdata->avinframe->flags |= AV_FRAME_FLAG_INTERLACED;
+ else
+ pdata->avinframe->flags &= ~AV_FRAME_FLAG_INTERLACED;
+ if (mlt_properties_get_int(frame_properties, "top_field_first"))
+ pdata->avinframe->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
+ else
+ pdata->avinframe->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
+#else
pdata->avinframe->interlaced_frame = !mlt_properties_get_int(frame_properties,
"progressive");
pdata->avinframe->top_field_first = mlt_properties_get_int(frame_properties,
"top_field_first");
+#endif
pdata->avinframe->color_primaries = mlt_properties_get_int(frame_properties,
"color_primaries");
pdata->avinframe->color_trc = mlt_properties_get_int(frame_properties, "color_trc");
diff --git a/src/modules/avformat/filter_swscale.c b/src/modules/avformat/filter_swscale.c
index 938d074..5b56e22 100644
--- a/src/modules/avformat/filter_swscale.c
+++ b/src/modules/avformat/filter_swscale.c
@@ -170,8 +170,15 @@ static int filter_scale(mlt_frame frame,
avinframe->height = iheight;
avinframe->format = avformat;
avinframe->sample_aspect_ratio = av_d2q(mlt_frame_get_aspect_ratio(frame), 1024);
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ if (!mlt_properties_get_int(properties, "progressive"))
+ avinframe->flags |= AV_FRAME_FLAG_INTERLACED;
+ if (mlt_properties_get_int(properties, "top_field_first"))
+ avinframe->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
+#else
avinframe->interlaced_frame = !mlt_properties_get_int(properties, "progressive");
avinframe->top_field_first = mlt_properties_get_int(properties, "top_field_first");
+#endif
av_image_fill_arrays(avinframe->data,
avinframe->linesize,
*image,
diff --git a/src/modules/avformat/link_avfilter.c b/src/modules/avformat/link_avfilter.c
index 8efda84..f041c67 100644
--- a/src/modules/avformat/link_avfilter.c
+++ b/src/modules/avformat/link_avfilter.c
@@ -1,6 +1,6 @@
/*
* link_avfilter.c -- provide various links based on libavfilter
- * Copyright (C) 2023-2024 Meltytech, LLC
+ * Copyright (C) 2023-2025 Meltytech, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -917,10 +917,21 @@ static int link_get_image(mlt_frame frame,
pdata->avinframe->sample_aspect_ratio = (AVRational){profile->sample_aspect_num,
profile->sample_aspect_den};
pdata->avinframe->pts = pos;
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ if (!mlt_properties_get_int(frame_properties, "progressive"))
+ pdata->avinframe->flags |= AV_FRAME_FLAG_INTERLACED;
+ else
+ pdata->avinframe->flags &= ~AV_FRAME_FLAG_INTERLACED;
+ if (mlt_properties_get_int(frame_properties, "top_field_first"))
+ pdata->avinframe->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
+ else
+ pdata->avinframe->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
+#else
pdata->avinframe->interlaced_frame = !mlt_properties_get_int(frame_properties,
"progressive");
pdata->avinframe->top_field_first = mlt_properties_get_int(frame_properties,
"top_field_first");
+#endif
pdata->avinframe->color_primaries = mlt_properties_get_int(frame_properties,
"color_primaries");
pdata->avinframe->color_trc = mlt_properties_get_int(frame_properties, "color_trc");
diff --git a/src/modules/avformat/producer_avformat.c b/src/modules/avformat/producer_avformat.c
index 1ce59ef..895b68a 100644
--- a/src/modules/avformat/producer_avformat.c
+++ b/src/modules/avformat/producer_avformat.c
@@ -335,11 +335,20 @@ static int first_video_index(producer_avformat self)
static const char *get_projection(AVStream *st)
{
+#if LIBAVCODEC_VERSION_INT >= ((60 << 16) + (29 << 8) + 100)
+ const AVPacketSideData *psd = av_packet_side_data_get(st->codecpar->coded_side_data,
+ st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_SPHERICAL);
+ if (psd) {
+ const AVSphericalMapping *spherical = (const AVSphericalMapping *) psd->data;
+#else
const AVSphericalMapping *spherical
= (const AVSphericalMapping *) av_stream_get_side_data(st, AV_PKT_DATA_SPHERICAL, NULL);
- if (spherical)
+ if (spherical) {
+#endif
return av_spherical_projection_name(spherical->projection);
+ }
return NULL;
}
@@ -349,7 +358,16 @@ static double get_rotation(mlt_properties properties, AVStream *st)
{
AVDictionaryEntry *rotate_tag = av_dict_get(st->metadata, "rotate", NULL, 0);
int has_rotate_metadata = rotate_tag && *rotate_tag->value && strcmp(rotate_tag->value, "0");
+#if LIBAVCODEC_VERSION_INT >= ((60 << 16) + (29 << 8) + 100)
+ int32_t *displaymatrix = NULL;
+ const AVPacketSideData *psd = av_packet_side_data_get(st->codecpar->coded_side_data,
+ st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_DISPLAYMATRIX);
+ if (psd)
+ displaymatrix = (int32_t *) psd->data;
+#else
uint8_t *displaymatrix = av_stream_get_side_data(st, AV_PKT_DATA_DISPLAYMATRIX, NULL);
+#endif
double theta = mlt_properties_get_double(properties, "rotate");
int has_mlt_rotate = !!mlt_properties_get(properties, "rotate");
@@ -418,13 +436,6 @@ static AVRational guess_frame_rate(producer_avformat self, AVStream *stream)
frame_rate = av_d2q(av_q2d(stream->avg_frame_rate), 1024);
fps = av_q2d(frame_rate);
}
- // XXX frame rates less than 1 fps are not considered sane
- if (isnan(fps) || isinf(fps) || fps < 1.0) {
- // Get the frame rate from the codec.
- frame_rate.num = self->video_codec->time_base.den;
- frame_rate.den = self->video_codec->time_base.num * self->video_codec->ticks_per_frame;
- fps = av_q2d(frame_rate);
- }
if (isnan(fps) || isinf(fps) || fps < 1.0) {
// Use the profile frame rate if all else fails.
mlt_profile profile = mlt_service_profile(MLT_PRODUCER_SERVICE(self->parent));
@@ -1580,7 +1591,7 @@ static void get_audio_streams_info(producer_avformat self)
#endif
if (codec_params->sample_rate > self->max_frequency)
self->max_frequency = codec_params->sample_rate;
- avcodec_close(codec_context);
+ avcodec_free_context(&codec_context);
}
pthread_mutex_unlock(&self->open_mutex);
}
@@ -1716,7 +1727,11 @@ static int sliced_h_pix_fmt_conv_proc(int id, int idx, int jobs, void *cookie)
struct SwsContext *sws;
struct sliced_pix_fmt_conv_t *ctx = (struct sliced_pix_fmt_conv_t *) cookie;
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ interlaced = ctx->frame->flags & AV_FRAME_FLAG_INTERLACED;
+#else
interlaced = ctx->frame->interlaced_frame;
+#endif
field = (interlaced) ? (idx & 1) : 0;
idx = (interlaced) ? (idx / 2) : idx;
slices = (interlaced) ? (jobs / 2) : jobs;
@@ -1865,7 +1880,11 @@ static void convert_image_rgb(producer_avformat self,
uint8_t *out_data[4];
int out_stride[4];
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ if (src_pix_fmt == AV_PIX_FMT_YUV420P && (frame->flags & AV_FRAME_FLAG_INTERLACED)) {
+#else
if (src_pix_fmt == AV_PIX_FMT_YUV420P && frame->interlaced_frame) {
+#endif
// Perform field-aware conversion for 4:2:0
int field_height = height / 2;
const uint8_t *in_data[4];
@@ -2041,8 +2060,13 @@ static int convert_image(producer_avformat self,
int sliced = !getenv("MLT_AVFORMAT_SLICED_PIXFMT_DISABLE") && src_pix_fmt != ctx.dst_format;
if (sliced) {
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ ctx.slice_w = (width < 1000) ? (256 >> (frame->flags & AV_FRAME_FLAG_INTERLACED))
+ : (512 >> (frame->flags & AV_FRAME_FLAG_INTERLACED));
+#else
ctx.slice_w = (width < 1000) ? (256 >> frame->interlaced_frame)
: (512 >> frame->interlaced_frame);
+#endif
} else {
ctx.slice_w = width;
}
@@ -2052,10 +2076,18 @@ static int convert_image(producer_avformat self,
if (sliced && (last_slice_w % 8) == 0
&& !(ctx.src_format == AV_PIX_FMT_YUV422P && last_slice_w % 16)) {
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ c *= (frame->flags & AV_FRAME_FLAG_INTERLACED) ? 2 : 1;
+#else
c *= frame->interlaced_frame ? 2 : 1;
+#endif
mlt_slices_run_normal(c, sliced_h_pix_fmt_conv_proc, &ctx);
} else {
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ c = (frame->flags & AV_FRAME_FLAG_INTERLACED) ? 2 : 1;
+#else
c = frame->interlaced_frame ? 2 : 1;
+#endif
ctx.slice_w = width;
for (i = 0; i < c; i++)
sliced_h_pix_fmt_conv_proc(i, i, c, &ctx);
@@ -2524,7 +2556,11 @@ static int producer_get_image(mlt_frame frame,
// there are I frames, and find_first_pts() fails as a result.
// Try to set first_pts here after getting pict_type.
if (self->first_pts == AV_NOPTS_VALUE
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ && ((self->video_frame->flags & AV_FRAME_FLAG_KEY)
+#else
&& (self->video_frame->key_frame
+#endif
|| self->video_frame->pict_type == AV_PICTURE_TYPE_I))
self->first_pts = pts;
if (self->first_pts != AV_NOPTS_VALUE)
@@ -2558,22 +2594,45 @@ static int producer_get_image(mlt_frame frame,
if (mlt_properties_get(properties, "force_progressive")) {
self->progressive = !!mlt_properties_get_int(properties, "force_progressive");
} else if (self->video_frame && codec_params) {
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ self->progressive = !(self->video_frame->flags & AV_FRAME_FLAG_INTERLACED)
+#else
self->progressive = !self->video_frame->interlaced_frame
+#endif
&& (codec_params->field_order == AV_FIELD_PROGRESSIVE
|| codec_params->field_order == AV_FIELD_UNKNOWN);
} else {
self->progressive = 0;
}
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ if (!self->progressive)
+ self->video_frame->flags |= AV_FRAME_FLAG_INTERLACED;
+ else
+ self->video_frame->flags &= ~AV_FRAME_FLAG_INTERLACED;
+#else
self->video_frame->interlaced_frame = !self->progressive;
+#endif
// Detect and correct field order
if (mlt_properties_get(properties, "force_tff")) {
self->top_field_first = !!mlt_properties_get_int(properties, "force_tff");
} else {
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ self->top_field_first = (self->video_frame->flags
+ & AV_FRAME_FLAG_TOP_FIELD_FIRST)
+#else
self->top_field_first = self->video_frame->top_field_first
+#endif
|| codec_params->field_order == AV_FIELD_TT
|| codec_params->field_order == AV_FIELD_TB;
}
+#if LIBAVUTIL_VERSION_INT >= ((58 << 16) + (7 << 8) + 100)
+ if (self->top_field_first)
+ self->video_frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
+ else
+ self->video_frame->flags &= ~AV_FRAME_FLAG_TOP_FIELD_FIRST;
+#else
self->video_frame->top_field_first = self->top_field_first;
+#endif
#ifdef AVFILTER
if ((self->autorotate || mlt_properties_get(properties, "filtergraph"))
&& !setup_filters(self) && self->vfilter_graph) {
@@ -3690,7 +3749,7 @@ static int audio_codec_init(producer_avformat self, int index, mlt_properties pr
if (codec && avcodec_open2(codec_context, codec, NULL) >= 0) {
// Now store the codec with its destructor
if (self->audio_codec[index])
- avcodec_close(self->audio_codec[index]);
+ avcodec_free_context(&self->audio_codec[index]);
self->audio_codec[index] = codec_context;
self->audio_index = index;
} else {
--
2.51.0