git: bf7ece95e3f1 - main - multimedia/olive: Unbreak

From: Yuri Victorovich <yuri_at_FreeBSD.org>
Date: Sun, 01 Mar 2026 02:27:30 UTC
The branch main has been updated by yuri:

URL: https://cgit.FreeBSD.org/ports/commit/?id=bf7ece95e3f131ec10258dd1fe2a52d13eefec7c

commit bf7ece95e3f131ec10258dd1fe2a52d13eefec7c
Author:     Yuri Victorovich <yuri@FreeBSD.org>
AuthorDate: 2026-03-01 02:27:06 +0000
Commit:     Yuri Victorovich <yuri@FreeBSD.org>
CommitDate: 2026-03-01 02:27:28 +0000

    multimedia/olive: Unbreak
---
 multimedia/olive/Makefile                          |   2 -
 .../olive/files/patch-app_audio_audioprocessor.cpp |  15 +++
 .../files/patch-app_codec_ffmpeg_ffmpegdecoder.cpp | 123 +++++++++++++++++++++
 .../files/patch-app_codec_ffmpeg_ffmpegencoder.cpp | 108 ++++++++++++++++++
 .../files/patch-app_codec_oiio_oiiodecoder.cpp     |  23 ++++
 .../patch-ext_core_src_render_audioparams.cpp      |  22 ++++
 6 files changed, 291 insertions(+), 2 deletions(-)

diff --git a/multimedia/olive/Makefile b/multimedia/olive/Makefile
index 6098406b3356..632918e153fa 100644
--- a/multimedia/olive/Makefile
+++ b/multimedia/olive/Makefile
@@ -13,8 +13,6 @@ COMMENT=	Non-linear video editor
 WWW=		https://olivevideoeditor.org/ \
 		https://github.com/olive-editor/olive
 
-BROKEN=		Does not build with ffmpeg > 6
-
 LICENSE=	GPLv3
 LICENSE_FILE=	${WRKSRC}/LICENSE
 
diff --git a/multimedia/olive/files/patch-app_audio_audioprocessor.cpp b/multimedia/olive/files/patch-app_audio_audioprocessor.cpp
new file mode 100644
index 000000000000..4c0acc8728ba
--- /dev/null
+++ b/multimedia/olive/files/patch-app_audio_audioprocessor.cpp
@@ -0,0 +1,15 @@
+--- app/audio/audioprocessor.cpp.orig	2026-02-28 23:14:00 UTC
++++ app/audio/audioprocessor.cpp
+@@ -169,8 +169,12 @@ bool AudioProcessor::Open(const AudioParams &from, con
+   if (in_frame_) {
+     in_frame_->sample_rate = from.sample_rate();
+     in_frame_->format = from_fmt_;
++#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
++    av_channel_layout_from_mask(&in_frame_->ch_layout, from.channel_layout());
++#else
+     in_frame_->channel_layout = from.channel_layout();
+     in_frame_->channels = from.channel_count();
++#endif
+     in_frame_->pts = 0;
+   } else {
+     qCritical() << "Failed to allocate input frame";
diff --git a/multimedia/olive/files/patch-app_codec_ffmpeg_ffmpegdecoder.cpp b/multimedia/olive/files/patch-app_codec_ffmpeg_ffmpegdecoder.cpp
new file mode 100644
index 000000000000..fae98a10ad3c
--- /dev/null
+++ b/multimedia/olive/files/patch-app_codec_ffmpeg_ffmpegdecoder.cpp
@@ -0,0 +1,123 @@
+--- app/codec/ffmpeg/ffmpegdecoder.cpp.orig	2024-12-04 17:13:33 UTC
++++ app/codec/ffmpeg/ffmpegdecoder.cpp
+@@ -355,8 +355,15 @@ FootageDescription FFmpegDecoder::Probe(const QString 
+               // Read first frame and retrieve some metadata
+               if (instance.GetFrame(pkt, frame) >= 0) {
+                 // Check if video is interlaced and what field dominance it has if so
++#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 0, 100)
++                int interlaced = (frame->flags & AV_FRAME_FLAG_INTERLACED);
++                int top_field_first = (frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST);
++                if (interlaced) {
++                  if (top_field_first) {
++#else
+                 if (frame->interlaced_frame) {
+                   if (frame->top_field_first) {
++#endif
+                     interlacing = VideoParams::kInterlacedTopFirst;
+                   } else {
+                     interlacing = VideoParams::kInterlacedBottomFirst;
+@@ -439,10 +446,30 @@ FootageDescription FFmpegDecoder::Probe(const QString 
+         } else if (avstream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
+ 
+           // Create an audio stream object
++#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
++          uint64_t channel_layout;
++          if (avstream->codecpar->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
++            AVChannelLayout ch_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++            av_channel_layout_copy(&ch_layout, &avstream->codecpar->ch_layout);
++            if (ch_layout.order == AV_CHANNEL_ORDER_NATIVE && ch_layout.u.mask) {
++              channel_layout = ch_layout.u.mask;
++            } else {
++              av_channel_layout_default(&ch_layout, avstream->codecpar->ch_layout.nb_channels);
++              channel_layout = ch_layout.u.mask;
++            }
++            av_channel_layout_uninit(&ch_layout);
++          } else {
++            AVChannelLayout ch_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++            av_channel_layout_default(&ch_layout, avstream->codecpar->ch_layout.nb_channels);
++            channel_layout = ch_layout.u.mask;
++            av_channel_layout_uninit(&ch_layout);
++          }
++#else
+           uint64_t channel_layout = avstream->codecpar->channel_layout;
+           if (!channel_layout) {
+             channel_layout = static_cast<uint64_t>(av_get_default_channel_layout(avstream->codecpar->channels));
+           }
++#endif
+ 
+           if (avstream->duration == AV_NOPTS_VALUE || duration_guessed_from_bitrate) {
+             // Loop through stream until we get the whole duration
+@@ -558,6 +585,29 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector
+   }
+ 
+   // Create resampling context
++#if LIBSWRESAMPLE_VERSION_INT >= AV_VERSION_INT(4, 5, 100)
++  AVChannelLayout out_ch_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++  AVChannelLayout in_ch_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++  av_channel_layout_from_mask(&out_ch_layout, params.channel_layout());
++  av_channel_layout_from_mask(&in_ch_layout, channel_layout);
++  
++  SwrContext* resampler = nullptr;
++  int swr_ret = swr_alloc_set_opts2(&resampler,
++                                    &out_ch_layout,
++                                    FFmpegUtils::GetFFmpegSampleFormat(params.format()),
++                                    params.sample_rate(),
++                                    &in_ch_layout,
++                                    static_cast<AVSampleFormat>(instance_.avstream()->codecpar->format),
++                                    instance_.avstream()->codecpar->sample_rate,
++                                    0,
++                                    nullptr);
++  av_channel_layout_uninit(&out_ch_layout);
++  av_channel_layout_uninit(&in_ch_layout);
++  
++  if (swr_ret < 0) {
++    return false;
++  }
++#else
+   SwrContext* resampler = swr_alloc_set_opts(nullptr,
+                                              params.channel_layout(),
+                                              FFmpegUtils::GetFFmpegSampleFormat(params.format()),
+@@ -567,6 +617,7 @@ bool FFmpegDecoder::ConformAudioInternal(const QVector
+                                              instance_.avstream()->codecpar->sample_rate,
+                                              0,
+                                              nullptr);
++#endif
+ 
+   swr_init(resampler);
+ 
+@@ -691,11 +742,35 @@ uint64_t FFmpegDecoder::ValidateChannelLayout(AVStream
+ 
+ uint64_t FFmpegDecoder::ValidateChannelLayout(AVStream* stream)
+ {
++#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
++  if (stream->codecpar->ch_layout.order != AV_CHANNEL_ORDER_UNSPEC) {
++    AVChannelLayout ch_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++    av_channel_layout_copy(&ch_layout, &stream->codecpar->ch_layout);
++    uint64_t mask = 0;
++    if (ch_layout.order == AV_CHANNEL_ORDER_NATIVE && ch_layout.u.mask) {
++      mask = ch_layout.u.mask;
++    } else {
++      AVChannelLayout default_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++      av_channel_layout_default(&default_layout, stream->codecpar->ch_layout.nb_channels);
++      mask = default_layout.u.mask;
++      av_channel_layout_uninit(&default_layout);
++    }
++    av_channel_layout_uninit(&ch_layout);
++    return mask;
++  }
++
++  AVChannelLayout ch_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++  av_channel_layout_default(&ch_layout, stream->codecpar->ch_layout.nb_channels);
++  uint64_t mask = ch_layout.u.mask;
++  av_channel_layout_uninit(&ch_layout);
++  return mask;
++#else
+   if (stream->codecpar->channel_layout) {
+     return stream->codecpar->channel_layout;
+   }
+ 
+   return av_get_default_channel_layout(stream->codecpar->channels);
++#endif
+ }
+ 
+ const char *FFmpegDecoder::GetInterlacingModeInFFmpeg(VideoParams::Interlacing interlacing)
diff --git a/multimedia/olive/files/patch-app_codec_ffmpeg_ffmpegencoder.cpp b/multimedia/olive/files/patch-app_codec_ffmpeg_ffmpegencoder.cpp
new file mode 100644
index 000000000000..943c59accca8
--- /dev/null
+++ b/multimedia/olive/files/patch-app_codec_ffmpeg_ffmpegencoder.cpp
@@ -0,0 +1,108 @@
+--- app/codec/ffmpeg/ffmpegencoder.cpp.orig	2024-12-04 17:13:33 UTC
++++ app/codec/ffmpeg/ffmpegencoder.cpp
+@@ -334,7 +334,11 @@ bool FFmpegEncoder::WriteAudioData(const AudioParams &
+   int output_sample_count = input_sample_count ? swr_get_out_samples(audio_resample_ctx_, input_sample_count) : 102400;
+   uint8_t** output_data = nullptr;
+   int output_linesize;
++#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
++  av_samples_alloc_array_and_samples(&output_data, &output_linesize, audio_stream_->codecpar->ch_layout.nb_channels,
++#else
+   av_samples_alloc_array_and_samples(&output_data, &output_linesize, audio_stream_->codecpar->channels,
++#endif
+                                      output_sample_count, static_cast<AVSampleFormat>(audio_stream_->codecpar->format), 0);
+ 
+   // Perform conversion
+@@ -349,7 +353,11 @@ bool FFmpegEncoder::WriteAudioData(const AudioParams &
+ 
+       av_samples_copy(audio_frame_->data, output_data, audio_frame_offset_, i,
+                       copy_length,
++#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
++                      audio_frame_->ch_layout.nb_channels, static_cast<AVSampleFormat>(audio_frame_->format));
++#else
+                       audio_frame_->channels, static_cast<AVSampleFormat>(audio_frame_->format));
++#endif
+ 
+       audio_frame_offset_ += copy_length;
+       i += copy_length;
+@@ -690,8 +698,12 @@ bool FFmpegEncoder::InitializeStream(AVMediaType type,
+ 
+     // Assume audio stream
+     codec_ctx->sample_rate = params().audio_params().sample_rate();
++#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
++    av_channel_layout_from_mask(&codec_ctx->ch_layout, params().audio_params().channel_layout());
++#else
+     codec_ctx->channel_layout = params().audio_params().channel_layout();
+     codec_ctx->channels = av_get_channel_layout_nb_channels(codec_ctx->channel_layout);
++#endif
+     codec_ctx->sample_fmt = FFmpegUtils::GetFFmpegSampleFormat(params().audio_params().format());
+     codec_ctx->time_base = {1, codec_ctx->sample_rate};
+ 
+@@ -787,12 +799,19 @@ void FFmpegEncoder::FlushEncoders()
+   }
+ 
+   if (fmt_ctx_) {
++#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(59, 0, 100)
++    // AVFMT_ALLOW_FLUSH removed in ffmpeg 7+, always allow flush now
++    int r = av_interleaved_write_frame(fmt_ctx_, nullptr);
++#else
+     if (fmt_ctx_->oformat->flags & AVFMT_ALLOW_FLUSH) {
+       int r = av_interleaved_write_frame(fmt_ctx_, nullptr);
++#endif
+       if (r < 0) {
+         FFmpegError(tr("Failed to write interleaved packet"), r);
+       }
++#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(59, 0, 100)
+     }
++#endif
+   }
+ }
+ 
+@@ -829,6 +848,28 @@ bool FFmpegEncoder::InitializeResampleContext(const Au
+   }
+ 
+   // Create resample context
++#if LIBSWRESAMPLE_VERSION_INT >= AV_VERSION_INT(4, 5, 100)
++  AVChannelLayout out_ch_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++  AVChannelLayout in_ch_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++  av_channel_layout_from_mask(&out_ch_layout, audio_codec_ctx_->ch_layout.u.mask ? audio_codec_ctx_->ch_layout.u.mask : AV_CH_LAYOUT_STEREO);
++  av_channel_layout_from_mask(&in_ch_layout, audio.channel_layout());
++  
++  int ret = swr_alloc_set_opts2(&audio_resample_ctx_,
++                                &out_ch_layout,
++                                audio_codec_ctx_->sample_fmt,
++                                audio_codec_ctx_->sample_rate,
++                                &in_ch_layout,
++                                FFmpegUtils::GetFFmpegSampleFormat(audio.format()),
++                                audio.sample_rate(),
++                                0,
++                                nullptr);
++  av_channel_layout_uninit(&out_ch_layout);
++  av_channel_layout_uninit(&in_ch_layout);
++  
++  if (ret < 0) {
++    return false;
++  }
++#else
+   audio_resample_ctx_ = swr_alloc_set_opts(nullptr,
+                                            static_cast<int64_t>(audio_codec_ctx_->channel_layout),
+                                            audio_codec_ctx_->sample_fmt,
+@@ -838,6 +879,7 @@ bool FFmpegEncoder::InitializeResampleContext(const Au
+                                            audio.sample_rate(),
+                                            0,
+                                            nullptr);
++#endif
+   if (!audio_resample_ctx_) {
+     return false;
+   }
+@@ -865,7 +907,11 @@ bool FFmpegEncoder::InitializeResampleContext(const Au
+     return false;
+   }
+ 
++#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
++  av_channel_layout_copy(&audio_frame_->ch_layout, &audio_codec_ctx_->ch_layout);
++#else
+   audio_frame_->channel_layout = audio_codec_ctx_->channel_layout;
++#endif
+   audio_frame_->format = audio_codec_ctx_->sample_fmt;
+   audio_frame_->nb_samples = audio_max_samples_;
+ 
diff --git a/multimedia/olive/files/patch-app_codec_oiio_oiiodecoder.cpp b/multimedia/olive/files/patch-app_codec_oiio_oiiodecoder.cpp
new file mode 100644
index 000000000000..cf080193683b
--- /dev/null
+++ b/multimedia/olive/files/patch-app_codec_oiio_oiiodecoder.cpp
@@ -0,0 +1,23 @@
+--- app/codec/oiio/oiiodecoder.cpp.orig	2026-02-28 23:20:04 UTC
++++ app/codec/oiio/oiiodecoder.cpp
+@@ -134,10 +134,20 @@ TexturePtr OIIODecoder::RetrieveVideoInternal(const Re
+ 
+     if (p.divider == 1) {
+       // Just upload straight to the buffer
++#if OIIO_VERSION >= OIIO_MAKE_VERSION(3, 0, 0)
++      // OpenImageIO 3.0+ requires subimage, miplevel, chbegin, chend parameters
++      image_->read_image(0, 0, 0, image_->spec().nchannels, oiio_pix_fmt_, buffer_.data(), OIIO::AutoStride, buffer_.linesize_bytes());
++#else
+       image_->read_image(oiio_pix_fmt_, buffer_.data(), OIIO::AutoStride, buffer_.linesize_bytes());
++#endif
+     } else {
+       OIIO::ImageBuf buf(image_->spec());
++#if OIIO_VERSION >= OIIO_MAKE_VERSION(3, 0, 0)
++      // OpenImageIO 3.0+ requires subimage, miplevel, chbegin, chend parameters
++      image_->read_image(0, 0, 0, image_->spec().nchannels, image_->spec().format, buf.localpixels(), buf.pixel_stride(), buf.scanline_stride(), buf.z_stride());
++#else
+       image_->read_image(image_->spec().format, buf.localpixels(), buf.pixel_stride(), buf.scanline_stride(), buf.z_stride());
++#endif
+ 
+       // Roughly downsample image for divider (for some reason OIIO::ImageBufAlgo::resample failed here)
+       int px_sz = vp.GetBytesPerPixel();
diff --git a/multimedia/olive/files/patch-ext_core_src_render_audioparams.cpp b/multimedia/olive/files/patch-ext_core_src_render_audioparams.cpp
new file mode 100644
index 000000000000..013260a0ff3f
--- /dev/null
+++ b/multimedia/olive/files/patch-ext_core_src_render_audioparams.cpp
@@ -0,0 +1,22 @@
+--- ext/core/src/render/audioparams.cpp.orig	2026-02-28 23:05:00 UTC
++++ ext/core/src/render/audioparams.cpp
+@@ -159,7 +159,19 @@ void AudioParams::calculate_channel_count()
+ 
+ void AudioParams::calculate_channel_count()
+ {
++#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
++  // ffmpeg 5.1+ uses new channel layout API
++  AVChannelLayout ch_layout = AV_CHANNEL_LAYOUT_MASK(0, 0);
++  if (channel_layout() > 0) {
++    av_channel_layout_from_mask(&ch_layout, channel_layout());
++    channel_count_ = ch_layout.nb_channels;
++    av_channel_layout_uninit(&ch_layout);
++  } else {
++    channel_count_ = 0;
++  }
++#else
+   channel_count_ = av_get_channel_layout_nb_channels(channel_layout());
++#endif
+ }
+ 
+ }