Re: git: 2d664816a4a4 - main - audio/cmus: Fix build with FFmpeg 8

From: Nuno Teixeira <eduardo_at_freebsd.org>
Date: Sun, 24 Aug 2025 19:29:38 UTC
Forgot to include PR: 289073 (
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289073 )

Nuno Teixeira <eduardo@freebsd.org> escreveu (domingo, 24/08/2025 à(s)
20:25):

> The branch main has been updated by eduardo:
>
> URL:
> https://cgit.FreeBSD.org/ports/commit/?id=2d664816a4a4ec943cfde8227013744c3d3719fb
>
> commit 2d664816a4a4ec943cfde8227013744c3d3719fb
> Author:     Nuno Teixeira <eduardo@FreeBSD.org>
> AuthorDate: 2025-08-24 19:13:46 +0000
> Commit:     Nuno Teixeira <eduardo@FreeBSD.org>
> CommitDate: 2025-08-24 19:19:00 +0000
>
>     audio/cmus: Fix build with FFmpeg 8
>
>     Apply upstream patch to fix build
> ---
>  audio/cmus/files/patch-fix-ffmpeg8 | 1841
> ++++++++++++++++++++++++++++++++++++
>  1 file changed, 1841 insertions(+)
>
> diff --git a/audio/cmus/files/patch-fix-ffmpeg8
> b/audio/cmus/files/patch-fix-ffmpeg8
> new file mode 100644
> index 000000000000..ff1407a55467
> --- /dev/null
> +++ b/audio/cmus/files/patch-fix-ffmpeg8
> @@ -0,0 +1,1841 @@
> +From 9f3b9efd8bd5508ffd069cbd0c228857ee11e1e5 Mon Sep 17 00:00:00 2001
> +From: ihy123 <aladinandreyy@gmail.com>
> +Date: Thu, 14 Aug 2025 12:44:10 +0300
> +Subject: [PATCH 01/12] ip/ffmpeg: more precise seeking
> +
> +av_seek_frame() and avformat_seek_file() seek to nearest "keyframe". For
> +codecs like, for example, ape this means that seeking will be very off
> +(5 seconds or more). So what we do is:
> +1. seek to nearest "keyframe" before the desired time,
> +2. discard some frames to approach the desired time.
> +---
> + ip/ffmpeg.c | 154 ++++++++++++++++++++++++++++++++--------------------
> + 1 file changed, 94 insertions(+), 60 deletions(-)
> +
> +diff --git  ip/ffmpeg.c  ip/ffmpeg.c
> +index 21b9a01f4..ecbf00582 100644
> +---  ip/ffmpeg.c
> ++++  ip/ffmpeg.c
> +@@ -44,6 +44,8 @@ struct ffmpeg_input {
> +       AVPacket pkt;
> +       int curr_pkt_size;
> +       uint8_t *curr_pkt_buf;
> ++      int64_t seek_ts;
> ++      int64_t prev_frame_end;
> +       int stream_index;
> +
> +       unsigned long curr_size;
> +@@ -76,6 +78,8 @@ static struct ffmpeg_input *ffmpeg_input_create(void)
> +               return NULL;
> +       }
> +       input->curr_pkt_size = 0;
> ++      input->seek_ts = -1;
> ++      input->prev_frame_end = -1;
> +       input->curr_pkt_buf = input->pkt.data;
> +       return input;
> + }
> +@@ -314,10 +318,7 @@ static int ffmpeg_fill_buffer(struct
> input_plugin_data *ip_data, AVFormatContext
> + #else
> +       AVFrame *frame = avcodec_alloc_frame();
> + #endif
> +-      int got_frame;
> +       while (1) {
> +-              int len;
> +-
> +               if (input->curr_pkt_size <= 0) {
> + #if LIBAVCODEC_VERSION_MAJOR >= 56
> +                       av_packet_unref(&input->pkt);
> +@@ -333,78 +334,108 @@ static int ffmpeg_fill_buffer(struct
> input_plugin_data *ip_data, AVFormatContext
> + #endif
> +                               return 0;
> +                       }
> +-                      if (input->pkt.stream_index ==
> input->stream_index) {
> +-                              input->curr_pkt_size = input->pkt.size;
> +-                              input->curr_pkt_buf = input->pkt.data;
> +-                              input->curr_size += input->pkt.size;
> +-                              input->curr_duration +=
> input->pkt.duration;
> +-                      }
> +-                      continue;
> +-              }
> +
> +-              {
> +-                      AVPacket avpkt;
> +-                      av_new_packet(&avpkt, input->curr_pkt_size);
> +-                      memcpy(avpkt.data, input->curr_pkt_buf,
> input->curr_pkt_size);
> ++                      if (input->pkt.stream_index != input->stream_index)
> ++                              continue;
> ++                      input->curr_pkt_size = input->pkt.size;
> ++                      input->curr_pkt_buf = input->pkt.data;
> ++                      input->curr_size += input->pkt.size;
> ++                      input->curr_duration += input->pkt.duration;
> ++
> + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> +-                      int send_result = avcodec_send_packet(cc, &avpkt);
> +-                      if (send_result != 0) {
> +-                              if (send_result != AVERROR(EAGAIN)) {
> +-                                      d_print("avcodec_send_packet()
> returned %d\n", send_result);
> +-                                      char
> errstr[AV_ERROR_MAX_STRING_SIZE];
> +-                                      if (!av_strerror(send_result,
> errstr, AV_ERROR_MAX_STRING_SIZE ))
> +-                                      {
> +-                                              d_print("av_strerror():
> %s\n", errstr);
> +-                                      } else {
> +-                                              d_print("av_strerror():
> Description for error cannot be found\n");
> +-                                      }
> +-                                      av_packet_unref(&avpkt);
> +-                                      return -IP_ERROR_INTERNAL;
> ++                      int send_result = avcodec_send_packet(cc,
> &input->pkt);
> ++                      if (send_result != 0 && send_result !=
> AVERROR(EAGAIN)) {
> ++                              d_print("avcodec_send_packet() returned
> %d\n", send_result);
> ++                              char errstr[AV_ERROR_MAX_STRING_SIZE];
> ++                              if (!av_strerror(send_result, errstr,
> AV_ERROR_MAX_STRING_SIZE ))
> ++                              {
> ++                                      d_print("av_strerror(): %s\n",
> errstr);
> ++                              } else {
> ++                                      d_print("av_strerror():
> Description for error cannot be found\n");
> +                               }
> +-                              len = 0;
> +-                      } else {
> +-                              len = input->curr_pkt_size;
> ++                              return -IP_ERROR_INTERNAL;
> +                       }
> +-
> +-                      int recv_result = avcodec_receive_frame(cc, frame);
> +-                      got_frame = (recv_result == 0) ? 1 : 0;
> +-#else
> +-                      len = avcodec_decode_audio4(cc, frame, &got_frame,
> &avpkt);
> +-#endif
> +-#if LIBAVCODEC_VERSION_MAJOR >= 56
> +-                      av_packet_unref(&avpkt);
> +-#else
> +-                      av_free_packet(&avpkt);
> + #endif
> +               }
> ++
> ++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> ++              int recv_result = avcodec_receive_frame(cc, frame);
> ++              if (recv_result < 0) {
> ++                      input->curr_pkt_size = 0;
> ++                      continue;
> ++              }
> ++#else
> ++              int got_frame;
> ++              int len = avcodec_decode_audio4(cc, frame, &got_frame,
> &input->pkt);
> +               if (len < 0) {
> +                       /* this is often reached when seeking, not sure
> why */
> +                       input->curr_pkt_size = 0;
> +                       continue;
> +               }
> +-              input->curr_pkt_size -= len;
> +-              input->curr_pkt_buf += len;
> +-              if (got_frame) {
> +-                      int res = swr_convert(swr,
> +-                                      &output->buffer,
> +-                                      frame->nb_samples,
> +-                                      (const uint8_t
> **)frame->extended_data,
> +-                                      frame->nb_samples);
> +-                      if (res < 0)
> +-                              res = 0;
> +-                      output->buffer_pos = output->buffer;
> ++              if (!got_frame)
> ++                      continue;
> ++#endif
> ++
> ++              int64_t frame_ts = -1;
> ++              if (frame->pts)
> ++                      frame_ts = frame->pts;
> ++              else if (frame->pkt_pts)
> ++                      frame_ts = frame->pkt_pts;
> ++              else if (frame->pkt_dts)
> ++                      frame_ts = frame->pkt_dts;
> ++
> ++              const uint8_t **in = (const uint8_t
> **)frame->extended_data;
> ++              int in_count = frame->nb_samples;
> ++              if (input->seek_ts > 0 && (frame_ts >= 0 ||
> input->prev_frame_end >= 0)) {
> ++                      struct ffmpeg_private *priv = ip_data->private;
> ++                      AVStream *st =
> priv->input_context->streams[priv->input->stream_index];
> ++                      if (frame_ts >= 0)
> ++                              frame_ts = av_rescale_q(frame_ts,
> st->time_base, AV_TIME_BASE_Q);
> ++                      else
> ++                              frame_ts = input->prev_frame_end;
> ++                      int64_t frame_dur = av_rescale(frame->nb_samples,
> AV_TIME_BASE, sf_get_rate(ip_data->sf));
> ++                      int64_t frame_end = frame_ts + frame_dur;
> ++                      input->prev_frame_end = frame_end;
> ++                      d_print("seek_ts: %ld, frame_ts: %ld, frame_end:
> %ld\n", input->seek_ts, frame_ts, frame_end);
> ++                      if (frame_end <= input->seek_ts)
> ++                              continue;
> ++
> ++                      /* skip part of this frame */
> ++                      int64_t skip_samples = av_rescale(input->seek_ts -
> frame_ts, sf_get_rate(ip_data->sf), AV_TIME_BASE);
> ++                      in_count -= skip_samples;
> ++                      if (av_sample_fmt_is_planar(frame->format)) {
> ++                              for (int i = 0; i < cc->channels; i++) {
> ++                                      in[i] += skip_samples *
> sf_get_sample_size(ip_data->sf);
> ++                              }
> ++                      } else {
> ++                              *in += skip_samples * cc->channels *
> sf_get_sample_size(ip_data->sf);
> ++                      }
> ++
> ++                      input->seek_ts = -1;
> ++                      input->prev_frame_end = -1;
> ++              }
> ++
> ++              int res = swr_convert(swr,
> ++                              &output->buffer,
> ++                              frame->nb_samples,
> ++                              in,
> ++                              in_count);
> ++              if (res < 0)
> ++                      res = 0;
> ++
> ++              output->buffer_pos = output->buffer;
> + #if LIBAVCODEC_VERSION_MAJOR >= 60
> +-                      output->buffer_used_len = res *
> cc->ch_layout.nb_channels * sf_get_sample_size(ip_data->sf);
> ++              output->buffer_used_len = res * cc->ch_layout.nb_channels
> * sf_get_sample_size(ip_data->sf);
> + #else
> +-                      output->buffer_used_len = res * cc->channels *
> sf_get_sample_size(ip_data->sf);
> ++              output->buffer_used_len = res * cc->channels *
> sf_get_sample_size(ip_data->sf);
> + #endif
> ++
> + #if LIBAVCODEC_VERSION_MAJOR >= 56
> +-                      av_frame_free(&frame);
> ++              av_frame_free(&frame);
> + #else
> +-                      avcodec_free_frame(&frame);
> ++              avcodec_free_frame(&frame);
> + #endif
> +-                      return output->buffer_used_len;
> +-              }
> ++              return output->buffer_used_len;
> +       }
> +       /* This should never get here. */
> +       return -IP_ERROR_INTERNAL;
> +@@ -437,13 +468,16 @@ static int ffmpeg_seek(struct input_plugin_data
> *ip_data, double offset)
> +       AVStream *st =
> priv->input_context->streams[priv->input->stream_index];
> +       int ret;
> +
> +-      int64_t pts = av_rescale_q(offset * AV_TIME_BASE, AV_TIME_BASE_Q,
> st->time_base);
> ++      priv->input->seek_ts = offset * AV_TIME_BASE;
> ++      priv->input->prev_frame_end = -1;
> ++      int64_t ts = av_rescale(offset, st->time_base.den,
> st->time_base.num);
> +
> +       avcodec_flush_buffers(priv->codec_context);
> +       /* Force reading a new packet in next ffmpeg_fill_buffer(). */
> +       priv->input->curr_pkt_size = 0;
> +
> +-      ret = av_seek_frame(priv->input_context,
> priv->input->stream_index, pts, 0);
> ++      ret = avformat_seek_file(priv->input_context,
> ++                      priv->input->stream_index, 0, ts, ts, 0);
> +
> +       if (ret < 0) {
> +               return -IP_ERROR_FUNCTION_NOT_SUPPORTED;
> +
> +From ec84fa7b4b4a72c19e2ab04eac864c99df6d2e4e Mon Sep 17 00:00:00 2001
> +From: ihy123 <aladinandreyy@gmail.com>
> +Date: Fri, 15 Aug 2025 21:42:19 +0300
> +Subject: [PATCH 02/12] ip/ffmpeg: skip samples only when needed
> +
> +---
> + ip/ffmpeg.c | 32 ++++++++++++++++++--------------
> + 1 file changed, 18 insertions(+), 14 deletions(-)
> +
> +diff --git  ip/ffmpeg.c  ip/ffmpeg.c
> +index ecbf00582..5f5a4f37b 100644
> +---  ip/ffmpeg.c
> ++++  ip/ffmpeg.c
> +@@ -393,22 +393,26 @@ static int ffmpeg_fill_buffer(struct
> input_plugin_data *ip_data, AVFormatContext
> +                               frame_ts = av_rescale_q(frame_ts,
> st->time_base, AV_TIME_BASE_Q);
> +                       else
> +                               frame_ts = input->prev_frame_end;
> +-                      int64_t frame_dur = av_rescale(frame->nb_samples,
> AV_TIME_BASE, sf_get_rate(ip_data->sf));
> +-                      int64_t frame_end = frame_ts + frame_dur;
> +-                      input->prev_frame_end = frame_end;
> +-                      d_print("seek_ts: %ld, frame_ts: %ld, frame_end:
> %ld\n", input->seek_ts, frame_ts, frame_end);
> +-                      if (frame_end <= input->seek_ts)
> +-                              continue;
> +
> +-                      /* skip part of this frame */
> +-                      int64_t skip_samples = av_rescale(input->seek_ts -
> frame_ts, sf_get_rate(ip_data->sf), AV_TIME_BASE);
> +-                      in_count -= skip_samples;
> +-                      if (av_sample_fmt_is_planar(frame->format)) {
> +-                              for (int i = 0; i < cc->channels; i++) {
> +-                                      in[i] += skip_samples *
> sf_get_sample_size(ip_data->sf);
> ++                      if (frame_ts < input->seek_ts) {
> ++                              int64_t frame_dur =
> av_rescale(frame->nb_samples, AV_TIME_BASE, sf_get_rate(ip_data->sf));
> ++                              int64_t frame_end = frame_ts + frame_dur;
> ++                              input->prev_frame_end = frame_end;
> ++                              d_print("seek_ts: %ld, frame_ts: %ld,
> frame_end: %ld\n", input->seek_ts, frame_ts, frame_end);
> ++                              if (frame_end <= input->seek_ts)
> ++                                      continue;
> ++
> ++                              /* skip part of this frame */
> ++                              int64_t skip_samples =
> av_rescale(input->seek_ts - frame_ts, sf_get_rate(ip_data->sf),
> AV_TIME_BASE);
> ++                              in_count -= skip_samples;
> ++                              if
> (av_sample_fmt_is_planar(frame->format)) {
> ++                                      for (int i = 0; i < cc->channels;
> i++) {
> ++                                              in[i] += skip_samples *
> sf_get_sample_size(ip_data->sf);
> ++                                      }
> ++                              } else {
> ++                                      *in += skip_samples * cc->channels
> * sf_get_sample_size(ip_data->sf);
> +                               }
> +-                      } else {
> +-                              *in += skip_samples * cc->channels *
> sf_get_sample_size(ip_data->sf);
> ++                              d_print("skipping %ld samples\n",
> skip_samples);
> +                       }
> +
> +                       input->seek_ts = -1;
> +
> +From 70a8761fc1d30bfa302332d0807b89c3776d3f31 Mon Sep 17 00:00:00 2001
> +From: ihy123 <aladinandreyy@gmail.com>
> +Date: Sat, 16 Aug 2025 02:43:55 +0300
> +Subject: [PATCH 03/12] ip/ffmpeg: remove excessive version checks
> +
> +ffmpeg download page states that v4.0.6 has
> +- libavutil 56.14.100
> +- libavcodec 58.18.100
> +- libavformat 58.12.100
> +(https://ffmpeg.org/olddownload.html)
> +
> +After removing all checks for versions lower than these, the plugin
> +still compiles with v3.3.9 headers.
> +
> +After all, why be better with compatibility than developers themselves?
> +---
> + ip/ffmpeg.c | 109 +++++++++++-----------------------------------------
> + 1 file changed, 23 insertions(+), 86 deletions(-)
> +
> +diff --git  ip/ffmpeg.c  ip/ffmpeg.c
> +index 5f5a4f37b..f6a11f450 100644
> +---  ip/ffmpeg.c
> ++++  ip/ffmpeg.c
> +@@ -25,7 +25,6 @@
> + #include "../config/ffmpeg.h"
> + #endif
> +
> +-#include <stdio.h>
> + #include <libavcodec/avcodec.h>
> + #include <libavformat/avformat.h>
> + #include <libavformat/avio.h>
> +@@ -43,7 +42,6 @@
> + struct ffmpeg_input {
> +       AVPacket pkt;
> +       int curr_pkt_size;
> +-      uint8_t *curr_pkt_buf;
> +       int64_t seek_ts;
> +       int64_t prev_frame_end;
> +       int stream_index;
> +@@ -80,17 +78,12 @@ static struct ffmpeg_input *ffmpeg_input_create(void)
> +       input->curr_pkt_size = 0;
> +       input->seek_ts = -1;
> +       input->prev_frame_end = -1;
> +-      input->curr_pkt_buf = input->pkt.data;
> +       return input;
> + }
> +
> + static void ffmpeg_input_free(struct ffmpeg_input *input)
> + {
> +-#if LIBAVCODEC_VERSION_MAJOR >= 56
> +       av_packet_unref(&input->pkt);
> +-#else
> +-      av_free_packet(&input->pkt);
> +-#endif
> +       free(input);
> + }
> +
> +@@ -132,7 +125,7 @@ static void ffmpeg_init(void)
> +
> +       av_log_set_level(AV_LOG_QUIET);
> +
> +-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 18, 100)
> ++#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
> +       /* We could register decoders explicitly to save memory, but we
> have to
> +        * be careful about compatibility. */
> +       av_register_all();
> +@@ -149,9 +142,7 @@ static int ffmpeg_open(struct input_plugin_data
> *ip_data)
> +       AVCodec const *codec;
> +       AVCodecContext *cc = NULL;
> +       AVFormatContext *ic = NULL;
> +-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> +       AVCodecParameters *cp = NULL;
> +-#endif
> +       SwrContext *swr = NULL;
> +
> +       ffmpeg_init();
> +@@ -171,20 +162,11 @@ static int ffmpeg_open(struct input_plugin_data
> *ip_data)
> +               }
> +
> +               for (i = 0; i < ic->nb_streams; i++) {
> +-
> +-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> +                       cp = ic->streams[i]->codecpar;
> +                       if (cp->codec_type == AVMEDIA_TYPE_AUDIO) {
> +                               stream_index = i;
> +                               break;
> +                       }
> +-#else
> +-                      cc = ic->streams[i]->codec;
> +-                      if (cc->codec_type == AVMEDIA_TYPE_AUDIO) {
> +-                              stream_index = i;
> +-                              break;
> +-                      }
> +-#endif
> +               }
> +
> +               if (stream_index == -1) {
> +@@ -193,13 +175,9 @@ static int ffmpeg_open(struct input_plugin_data
> *ip_data)
> +                       break;
> +               }
> +
> +-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> +               codec = avcodec_find_decoder(cp->codec_id);
> +               cc = avcodec_alloc_context3(codec);
> +               avcodec_parameters_to_context(cc, cp);
> +-#else
> +-              codec = avcodec_find_decoder(cc->codec_id);
> +-#endif
> +               if (!codec) {
> +                       d_print("codec not found: %d, %s\n", cc->codec_id,
> avcodec_get_name(cc->codec_id));
> +                       err = -IP_ERROR_UNSUPPORTED_FILE_TYPE;
> +@@ -217,9 +195,7 @@ static int ffmpeg_open(struct input_plugin_data
> *ip_data)
> +
> +       if (err < 0) {
> +               /* Clean up.  cc is never opened at this point.  (See
> above assumption.) */
> +-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> +               avcodec_free_context(&cc);
> +-#endif
> +               avformat_close_input(&ic);
> +               return err;
> +       }
> +@@ -231,9 +207,7 @@ static int ffmpeg_open(struct input_plugin_data
> *ip_data)
> +       priv->input = ffmpeg_input_create();
> +       if (priv->input == NULL) {
> +               avcodec_close(cc);
> +-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> +               avcodec_free_context(&cc);
> +-#endif
> +               avformat_close_input(&ic);
> +               free(priv);
> +               return -IP_ERROR_INTERNAL;
> +@@ -244,7 +218,7 @@ static int ffmpeg_open(struct input_plugin_data
> *ip_data)
> +       /* Prepare for resampling. */
> +       out_sample_rate = min_u(cc->sample_rate, 384000);
> +       swr = swr_alloc();
> +-#if LIBAVCODEC_VERSION_MAJOR >= 60
> ++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100)
> +       if (cc->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
> +               av_channel_layout_default(&cc->ch_layout,
> cc->ch_layout.nb_channels);
> +       av_opt_set_chlayout(swr, "in_chlayout",   &cc->ch_layout, 0);
> +@@ -259,7 +233,7 @@ static int ffmpeg_open(struct input_plugin_data
> *ip_data)
> +       priv->swr = swr;
> +
> +       ip_data->private = priv;
> +-#if LIBAVCODEC_VERSION_MAJOR >= 60
> ++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100)
> +       ip_data->sf = sf_rate(out_sample_rate) |
> sf_channels(cc->ch_layout.nb_channels);
> + #else
> +       ip_data->sf = sf_rate(out_sample_rate) | sf_channels(cc->channels);
> +@@ -281,10 +255,12 @@ static int ffmpeg_open(struct input_plugin_data
> *ip_data)
> +       }
> +       swr_init(swr);
> +       ip_data->sf |= sf_host_endian();
> +-#if LIBAVCODEC_VERSION_MAJOR >= 60
> +-      channel_map_init_waveex(cc->ch_layout.nb_channels,
> cc->ch_layout.u.mask, ip_data->channel_map);
> ++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100)
> ++      channel_map_init_waveex(cc->ch_layout.nb_channels,
> ++                      cc->ch_layout.u.mask, ip_data->channel_map);
> + #else
> +-      channel_map_init_waveex(cc->channels, cc->channel_layout,
> ip_data->channel_map);
> ++      channel_map_init_waveex(cc->channels,
> ++                      cc->channel_layout, ip_data->channel_map);
> + #endif
> +       return 0;
> + }
> +@@ -294,9 +270,7 @@ static int ffmpeg_close(struct input_plugin_data
> *ip_data)
> +       struct ffmpeg_private *priv = ip_data->private;
> +
> +       avcodec_close(priv->codec_context);
> +-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> +       avcodec_free_context(&priv->codec_context);
> +-#endif
> +       avformat_close_input(&priv->input_context);
> +       swr_free(&priv->swr);
> +       ffmpeg_input_free(priv->input);
> +@@ -310,39 +284,27 @@ static int ffmpeg_close(struct input_plugin_data
> *ip_data)
> +  * This returns the number of bytes added to the buffer.
> +  * It returns < 0 on error.  0 on EOF.
> +  */
> +-static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data,
> AVFormatContext *ic, AVCodecContext *cc,
> +-                            struct ffmpeg_input *input, struct
> ffmpeg_output *output, SwrContext *swr)
> ++static int ffmpeg_fill_buffer(struct input_plugin_data *ip_data,
> ++              AVFormatContext *ic, AVCodecContext *cc,
> ++              struct ffmpeg_input *input, struct ffmpeg_output *output,
> ++              SwrContext *swr)
> + {
> +-#if LIBAVCODEC_VERSION_MAJOR >= 56
> +       AVFrame *frame = av_frame_alloc();
> +-#else
> +-      AVFrame *frame = avcodec_alloc_frame();
> +-#endif
> +       while (1) {
> +               if (input->curr_pkt_size <= 0) {
> +-#if LIBAVCODEC_VERSION_MAJOR >= 56
> +                       av_packet_unref(&input->pkt);
> +-#else
> +-                      av_free_packet(&input->pkt);
> +-#endif
> +                       if (av_read_frame(ic, &input->pkt) < 0) {
> +                               /* Force EOF once we can read no longer. */
> +-#if LIBAVCODEC_VERSION_MAJOR >= 56
> +                               av_frame_free(&frame);
> +-#else
> +-                              avcodec_free_frame(&frame);
> +-#endif
> +                               return 0;
> +                       }
> +
> +                       if (input->pkt.stream_index != input->stream_index)
> +                               continue;
> +                       input->curr_pkt_size = input->pkt.size;
> +-                      input->curr_pkt_buf = input->pkt.data;
> +                       input->curr_size += input->pkt.size;
> +                       input->curr_duration += input->pkt.duration;
> +
> +-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> +                       int send_result = avcodec_send_packet(cc,
> &input->pkt);
> +                       if (send_result != 0 && send_result !=
> AVERROR(EAGAIN)) {
> +                               d_print("avcodec_send_packet() returned
> %d\n", send_result);
> +@@ -355,32 +317,17 @@ static int ffmpeg_fill_buffer(struct
> input_plugin_data *ip_data, AVFormatContext
> +                               }
> +                               return -IP_ERROR_INTERNAL;
> +                       }
> +-#endif
> +               }
> +
> +-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
> +               int recv_result = avcodec_receive_frame(cc, frame);
> +               if (recv_result < 0) {
> +                       input->curr_pkt_size = 0;
> +                       continue;
> +               }
> +-#else
> +-              int got_frame;
> +-              int len = avcodec_decode_audio4(cc, frame, &got_frame,
> &input->pkt);
> +-              if (len < 0) {
> +-                      /* this is often reached when seeking, not sure
> why */
> +-                      input->curr_pkt_size = 0;
> +-                      continue;
> +-              }
> +-              if (!got_frame)
> +-                      continue;
> +-#endif
> +
> +               int64_t frame_ts = -1;
> +               if (frame->pts)
> +                       frame_ts = frame->pts;
> +-              else if (frame->pkt_pts)
> +-                      frame_ts = frame->pkt_pts;
> +               else if (frame->pkt_dts)
> +                       frame_ts = frame->pkt_dts;
> +
> +@@ -395,7 +342,7 @@ static int ffmpeg_fill_buffer(struct
> input_plugin_data *ip_data, AVFormatContext
> +                               frame_ts = input->prev_frame_end;
> +
> +                       if (frame_ts < input->seek_ts) {
> +-                              int64_t frame_dur =
> av_rescale(frame->nb_samples, AV_TIME_BASE, sf_get_rate(ip_data->sf));
> ++                              int64_t frame_dur =
> av_rescale(frame->nb_samples, AV_TIME_BASE, frame->sample_rate);
> +                               int64_t frame_end = frame_ts + frame_dur;
> +                               input->prev_frame_end = frame_end;
> +                               d_print("seek_ts: %ld, frame_ts: %ld,
> frame_end: %ld\n", input->seek_ts, frame_ts, frame_end);
> +@@ -403,14 +350,14 @@ static int ffmpeg_fill_buffer(struct
> input_plugin_data *ip_data, AVFormatContext
> +                                       continue;
> +
> +                               /* skip part of this frame */
> +-                              int64_t skip_samples =
> av_rescale(input->seek_ts - frame_ts, sf_get_rate(ip_data->sf),
> AV_TIME_BASE);
> ++                              int64_t skip_samples =
> av_rescale(input->seek_ts - frame_ts, frame->sample_rate, AV_TIME_BASE);
> +                               in_count -= skip_samples;
> +                               if
> (av_sample_fmt_is_planar(frame->format)) {
> +-                                      for (int i = 0; i < cc->channels;
> i++) {
> ++                                      for (int i = 0; i <
> sf_get_channels(ip_data->sf); i++) {
> +                                               in[i] += skip_samples *
> sf_get_sample_size(ip_data->sf);
> +                                       }
> +                               } else {
> +-                                      *in += skip_samples * cc->channels
> * sf_get_sample_size(ip_data->sf);
> ++                                      *in += skip_samples *
> sf_get_frame_size(ip_data->sf);
> +                               }
> +                               d_print("skipping %ld samples\n",
> skip_samples);
> +                       }
> +@@ -428,17 +375,9 @@ static int ffmpeg_fill_buffer(struct
> input_plugin_data *ip_data, AVFormatContext
> +                       res = 0;
> +
> +               output->buffer_pos = output->buffer;
> +-#if LIBAVCODEC_VERSION_MAJOR >= 60
> +-              output->buffer_used_len = res * cc->ch_layout.nb_channels
> * sf_get_sample_size(ip_data->sf);
> +-#else
> +-              output->buffer_used_len = res * cc->channels *
> sf_get_sample_size(ip_data->sf);
> +-#endif
> ++              output->buffer_used_len = res *
> sf_get_frame_size(ip_data->sf);
> +
> +-#if LIBAVCODEC_VERSION_MAJOR >= 56
> +               av_frame_free(&frame);
> +-#else
> +-              avcodec_free_frame(&frame);
> +-#endif
> +               return output->buffer_used_len;
> +       }
> +       /* This should never get here. */
> +@@ -453,11 +392,11 @@ static int ffmpeg_read(struct input_plugin_data
> *ip_data, char *buffer, int coun
> +       int out_size;
> +
> +       if (output->buffer_used_len == 0) {
> +-              rc = ffmpeg_fill_buffer(ip_data, priv->input_context,
> priv->codec_context,
> ++              rc = ffmpeg_fill_buffer(ip_data,
> ++                              priv->input_context, priv->codec_context,
> +                               priv->input, priv->output, priv->swr);
> +-              if (rc <= 0) {
> ++              if (rc <= 0)
> +                       return rc;
> +-              }
> +       }
> +       out_size = min_i(output->buffer_used_len, count);
> +       memcpy(buffer, output->buffer_pos, out_size);
> +@@ -477,6 +416,7 @@ static int ffmpeg_seek(struct input_plugin_data
> *ip_data, double offset)
> +       int64_t ts = av_rescale(offset, st->time_base.den,
> st->time_base.num);
> +
> +       avcodec_flush_buffers(priv->codec_context);
> ++      /* TODO: also flush swresample buffers */
> +       /* Force reading a new packet in next ffmpeg_fill_buffer(). */
> +       priv->input->curr_pkt_size = 0;
> +
> +@@ -501,7 +441,8 @@ static void ffmpeg_read_metadata(struct
> growing_keyvals *c, AVDictionary *metada
> +       }
> + }
> +
> +-static int ffmpeg_read_comments(struct input_plugin_data *ip_data,
> struct keyval **comments)
> ++static int ffmpeg_read_comments(struct input_plugin_data *ip_data,
> ++              struct keyval **comments)
> + {
> +       struct ffmpeg_private *priv = ip_data->private;
> +       AVFormatContext *ic = priv->input_context;
> +@@ -538,11 +479,7 @@ static long ffmpeg_current_bitrate(struct
> input_plugin_data *ip_data)
> +       AVStream *st =
> priv->input_context->streams[priv->input->stream_index];
> +       long bitrate = -1;
> +       /* ape codec returns silly numbers */
> +-#if LIBAVCODEC_VERSION_MAJOR >= 55
> +       if (priv->codec->id == AV_CODEC_ID_APE)
> +-#else
> +-      if (priv->codec->id == CODEC_ID_APE)
> +-#endif
> +               return -1;
> +       if (priv->input->curr_duration > 0) {
> +               double seconds = priv->input->curr_duration *
> av_q2d(st->time_base);
> +
> +From e1a2374a60a41987f95c7d892ebc1b150df7acb1 Mon Sep 17 00:00:00 2001
> +From: ihy123 <aladinandreyy@gmail.com>
> +Date: Sun, 17 Aug 2025 04:05:36 +0300
> +Subject: [PATCH 04/12] ip/ffmpeg: major refactor
> +
> +---
> + ip/ffmpeg.c | 643 +++++++++++++++++++++++++++-------------------------
> + 1 file changed, 330 insertions(+), 313 deletions(-)
> +
> +diff --git  ip/ffmpeg.c  ip/ffmpeg.c
> +index f6a11f450..42f630ee7 100644
> +---  ip/ffmpeg.c
> ++++  ip/ffmpeg.c
> +@@ -35,84 +35,32 @@
> + #include <libavutil/mathematics.h>
> + #endif
> +
> +-#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
> +-#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
> +-#endif
> ++struct ffmpeg_private {
> ++      AVCodecContext *codec_ctx;
> ++      AVFormatContext *format_ctx;
> ++      AVCodec const *codec;
> ++      SwrContext *swr;
> ++      int stream_index;
> +
> +-struct ffmpeg_input {
> +-      AVPacket pkt;
> +-      int curr_pkt_size;
> ++      AVPacket *pkt;
> ++      AVFrame *frame;
> +       int64_t seek_ts;
> +       int64_t prev_frame_end;
> +-      int stream_index;
> +
> ++      /* A buffer to hold swr_convert()-ed samples */
> ++      AVFrame *swr_frame;
> ++      int swr_frame_start;
> ++
> ++      /* Bitrate estimation */
> +       unsigned long curr_size;
> +       unsigned long curr_duration;
> + };
> +
> +-struct ffmpeg_output {
> +-      uint8_t *buffer;
> +-      uint8_t *buffer_malloc;
> +-      uint8_t *buffer_pos;    /* current buffer position */
> +-      int buffer_used_len;
> +-};
> +-
> +-struct ffmpeg_private {
> +-      AVCodecContext *codec_context;
> +-      AVFormatContext *input_context;
> +-      AVCodec const *codec;
> +-      SwrContext *swr;
> +-
> +-      struct ffmpeg_input *input;
> +-      struct ffmpeg_output *output;
> +-};
> +-
> +-static struct ffmpeg_input *ffmpeg_input_create(void)
> +-{
> +-      struct ffmpeg_input *input = xnew(struct ffmpeg_input, 1);
> +-
> +-      if (av_new_packet(&input->pkt, 0) != 0) {
> +-              free(input);
> +-              return NULL;
> +-      }
> +-      input->curr_pkt_size = 0;
> +-      input->seek_ts = -1;
> +-      input->prev_frame_end = -1;
> +-      return input;
> +-}
> +-
> +-static void ffmpeg_input_free(struct ffmpeg_input *input)
> +-{
> +-      av_packet_unref(&input->pkt);
> +-      free(input);
> +-}
> +-
> +-static struct ffmpeg_output *ffmpeg_output_create(void)
> +-{
> +-      struct ffmpeg_output *output = xnew(struct ffmpeg_output, 1);
> +-
> +-      output->buffer_malloc = xnew(uint8_t, AVCODEC_MAX_AUDIO_FRAME_SIZE
> + 15);
> +-      output->buffer = output->buffer_malloc;
> +-      /* align to 16 bytes so avcodec can SSE/Altivec/etc */
> +-      while ((intptr_t) output->buffer % 16)
> +-              output->buffer += 1;
> +-      output->buffer_pos = output->buffer;
> +-      output->buffer_used_len = 0;
> +-      return output;
> +-}
> +-
> +-static void ffmpeg_output_free(struct ffmpeg_output *output)
> +-{
> +-      free(output->buffer_malloc);
> +-      output->buffer_malloc = NULL;
> +-      output->buffer = NULL;
> +-      free(output);
> +-}
> +-
> +-static inline void ffmpeg_buffer_flush(struct ffmpeg_output *output)
> ++static const char *ffmpeg_errmsg(int err)
> + {
> +-      output->buffer_pos = output->buffer;
> +-      output->buffer_used_len = 0;
> ++      static char errstr[AV_ERROR_MAX_STRING_SIZE];
> ++      av_strerror(err, errstr, AV_ERROR_MAX_STRING_SIZE);
> ++      return errstr;
> + }
> +
> + static void ffmpeg_init(void)
> +@@ -132,303 +80,372 @@ static void ffmpeg_init(void)
> + #endif
> + }
> +
> +-static int ffmpeg_open(struct input_plugin_data *ip_data)
> ++static int ffmpeg_open_input(struct input_plugin_data *ip_data,
> ++              struct ffmpeg_private *priv)
> + {
> +-      struct ffmpeg_private *priv;
> +-      int err = 0;
> +-      int i;
> +-      int stream_index = -1;
> +-      int out_sample_rate;
> +-      AVCodec const *codec;
> +-      AVCodecContext *cc = NULL;
> +       AVFormatContext *ic = NULL;
> ++      AVCodecContext *cc = NULL;
> +       AVCodecParameters *cp = NULL;
> +-      SwrContext *swr = NULL;
> +-
> +-      ffmpeg_init();
> ++      AVCodec const *codec = NULL;
> ++      int stream_index = -1;
> +
> +-      err = avformat_open_input(&ic, ip_data->filename, NULL, NULL);
> +-      if (err < 0) {
> +-              d_print("av_open failed: %d\n", err);
> +-              return -IP_ERROR_FILE_FORMAT;
> ++      int err;
> ++      int res = avformat_open_input(&ic, ip_data->filename, NULL, NULL);
> ++      if (res < 0) {
> ++              err = -IP_ERROR_FILE_FORMAT;
> ++              goto err;
> +       }
> +
> +-      do {
> +-              err = avformat_find_stream_info(ic, NULL);
> +-              if (err < 0) {
> +-                      d_print("unable to find stream info: %d\n", err);
> +-                      err = -IP_ERROR_FILE_FORMAT;
> +-                      break;
> +-              }
> +-
> +-              for (i = 0; i < ic->nb_streams; i++) {
> +-                      cp = ic->streams[i]->codecpar;
> +-                      if (cp->codec_type == AVMEDIA_TYPE_AUDIO) {
> +-                              stream_index = i;
> +-                              break;
> +-                      }
> +-              }
> +-
> +-              if (stream_index == -1) {
> +-                      d_print("could not find audio stream\n");
> +-                      err = -IP_ERROR_FILE_FORMAT;
> +-                      break;
> +-              }
> +-
> +-              codec = avcodec_find_decoder(cp->codec_id);
> +-              cc = avcodec_alloc_context3(codec);
> +-              avcodec_parameters_to_context(cc, cp);
> +-              if (!codec) {
> +-                      d_print("codec not found: %d, %s\n", cc->codec_id,
> avcodec_get_name(cc->codec_id));
> +-                      err = -IP_ERROR_UNSUPPORTED_FILE_TYPE;
> +-                      break;
> +-              }
> ++      res = avformat_find_stream_info(ic, NULL);
> ++      if (res < 0) {
> ++              d_print("unable to find stream info\n");
> ++              err = -IP_ERROR_FILE_FORMAT;
> ++              goto err;
> ++      }
> +
> +-              if (avcodec_open2(cc, codec, NULL) < 0) {
> +-                      d_print("could not open codec: %d, %s\n",
> cc->codec_id, avcodec_get_name(cc->codec_id));
> +-                      err = -IP_ERROR_UNSUPPORTED_FILE_TYPE;
> ++      for (int i = 0; i < ic->nb_streams; i++) {
> ++              cp = ic->streams[i]->codecpar;
> ++              if (cp->codec_type == AVMEDIA_TYPE_AUDIO) {
> ++                      stream_index = i;
> +                       break;
> +               }
> ++      }
> +
> +-              /* We assume below that no more errors follow. */
> +-      } while (0);
> ++      if (stream_index == -1) {
> ++              d_print("could not find audio stream\n");
> ++              err = -IP_ERROR_FILE_FORMAT;
> ++              goto err_silent;
> ++      }
> +
> +-      if (err < 0) {
> +-              /* Clean up.  cc is never opened at this point.  (See
> above assumption.) */
> +-              avcodec_free_context(&cc);
> +-              avformat_close_input(&ic);
> +-              return err;
> ++      codec = avcodec_find_decoder(cp->codec_id);
> ++      if (!codec) {
> ++              d_print("codec (id: %d, name: %s) not found\n",
> ++                              cc->codec_id,
> avcodec_get_name(cc->codec_id));
> ++              err = -IP_ERROR_UNSUPPORTED_FILE_TYPE;
> ++              goto err_silent;
> ++      }
> ++      cc = avcodec_alloc_context3(codec);
> ++      avcodec_parameters_to_context(cc, cp);
> ++
> ++      res = avcodec_open2(cc, codec, NULL);
> ++      if (res < 0) {
> ++              d_print("could not open codec (id: %d, name: %s)\n",
> ++                              cc->codec_id,
> avcodec_get_name(cc->codec_id));
> ++              err = -IP_ERROR_UNSUPPORTED_FILE_TYPE;
> ++              goto err;
> +       }
> +
> +-      priv = xnew(struct ffmpeg_private, 1);
> +-      priv->codec_context = cc;
> +-      priv->input_context = ic;
> ++      priv->format_ctx = ic;
> ++      priv->codec_ctx = cc;
> +       priv->codec = codec;
> +-      priv->input = ffmpeg_input_create();
> +-      if (priv->input == NULL) {
> +-              avcodec_close(cc);
> +-              avcodec_free_context(&cc);
> +-              avformat_close_input(&ic);
> +-              free(priv);
> +-              return -IP_ERROR_INTERNAL;
> ++      priv->stream_index = stream_index;
> ++      return 0;
> ++err:
> ++      d_print("%s\n", ffmpeg_errmsg(res));
> ++err_silent:
> ++      avcodec_free_context(&cc);
> ++      avformat_close_input(&ic);
> ++      return err;
> ++}
> ++
> ++static void ffmpeg_set_sf_and_swr_opts(SwrContext *swr, AVCodecContext
> *cc,
> ++              sample_format_t *sf_out, enum AVSampleFormat
> *out_sample_fmt)
> ++{
> ++      int out_sample_rate = min_u(cc->sample_rate, 384000);
> ++      sample_format_t sf = sf_rate(out_sample_rate) | sf_host_endian();
> ++      av_opt_set_int(swr, "in_sample_rate", cc->sample_rate, 0);
> ++      av_opt_set_int(swr, "out_sample_rate", out_sample_rate, 0);
> ++
> ++      *out_sample_fmt = cc->sample_fmt;
> ++      switch (*out_sample_fmt) {
> ++              case AV_SAMPLE_FMT_U8:
> ++                      sf |= sf_bits(8) | sf_signed(0);
> ++                      break;
> ++              case AV_SAMPLE_FMT_S32:
> ++                      sf |= sf_bits(32) | sf_signed(1);
> ++                      break;
> ++              default:
> ++                      sf |= sf_bits(16) | sf_signed(1);
> ++                      *out_sample_fmt = AV_SAMPLE_FMT_S16;
> +       }
> +-      priv->input->stream_index = stream_index;
> +-      priv->output = ffmpeg_output_create();
> ++      av_opt_set_sample_fmt(swr, "in_sample_fmt", cc->sample_fmt, 0);
> ++      av_opt_set_sample_fmt(swr, "out_sample_fmt", *out_sample_fmt, 0);
> +
> +-      /* Prepare for resampling. */
> +-      out_sample_rate = min_u(cc->sample_rate, 384000);
> +-      swr = swr_alloc();
> + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100)
> ++      sf |= sf_channels(cc->ch_layout.nb_channels);
> ++
> +       if (cc->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
> +               av_channel_layout_default(&cc->ch_layout,
> cc->ch_layout.nb_channels);
> +-      av_opt_set_chlayout(swr, "in_chlayout",   &cc->ch_layout, 0);
> +-      av_opt_set_chlayout(swr, "out_chlayout",  &cc->ch_layout, 0);
> ++      av_opt_set_chlayout(swr, "in_chlayout", &cc->ch_layout, 0);
> ++      av_opt_set_chlayout(swr, "out_chlayout", &cc->ch_layout, 0);
> + #else
> +-      av_opt_set_int(swr, "in_channel_layout",
> av_get_default_channel_layout(cc->channels), 0);
> +-      av_opt_set_int(swr, "out_channel_layout",
> av_get_default_channel_layout(cc->channels), 0);
> ++      sf |= sf_channels(cc->channels);
> ++
> ++      av_opt_set_int(swr, "in_channel_layout",
> ++                      av_get_default_channel_layout(cc->channels), 0);
> ++      av_opt_set_int(swr, "out_channel_layout",
> ++                      av_get_default_channel_layout(cc->channels), 0);
> + #endif
> +-      av_opt_set_int(swr, "in_sample_rate",     cc->sample_rate, 0);
> +-      av_opt_set_int(swr, "out_sample_rate",    out_sample_rate, 0);
> +-      av_opt_set_sample_fmt(swr, "in_sample_fmt",  cc->sample_fmt, 0);
> +-      priv->swr = swr;
> +
> +-      ip_data->private = priv;
> ++      *sf_out = sf;
> ++}
> ++
> ++static int ffmpeg_init_swr_frame(struct ffmpeg_private *priv,
> ++              sample_format_t sf, enum AVSampleFormat out_sample_fmt)
> ++{
> ++      AVCodecContext *cc = priv->codec_ctx;
> ++      AVFrame *frame = av_frame_alloc();
> ++
> + #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100)
> +-      ip_data->sf = sf_rate(out_sample_rate) |
> sf_channels(cc->ch_layout.nb_channels);
> ++      av_channel_layout_copy(&frame->ch_layout, &cc->ch_layout);
> + #else
> +-      ip_data->sf = sf_rate(out_sample_rate) | sf_channels(cc->channels);
> ++      frame->channel_layout =
> av_get_default_channel_layout(cc->channels);
> + #endif
> +-      switch (cc->sample_fmt) {
> +-      case AV_SAMPLE_FMT_U8:
> +-              ip_data->sf |= sf_bits(8) | sf_signed(0);
> +-              av_opt_set_sample_fmt(swr, "out_sample_fmt",
> AV_SAMPLE_FMT_U8,  0);
> +-              break;
> +-      case AV_SAMPLE_FMT_S32:
> +-              ip_data->sf |= sf_bits(32) | sf_signed(1);
> +-              av_opt_set_sample_fmt(swr, "out_sample_fmt",
> AV_SAMPLE_FMT_S32,  0);
> +-              break;
> +-      /* AV_SAMPLE_FMT_S16 */
> +-      default:
> +-              ip_data->sf |= sf_bits(16) | sf_signed(1);
> *** 878 LINES SKIPPED ***
>


-- 
Nuno Teixeira
FreeBSD UNIX:  <eduardo@FreeBSD.org>   Web:  https://FreeBSD.org