Re: git: 2d664816a4a4 - main - audio/cmus: Fix build with FFmpeg 8
- In reply to: Nuno Teixeira : "git: 2d664816a4a4 - main - audio/cmus: Fix build with FFmpeg 8"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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