File ffmpeg-8-compat.patch of Package cmus
From 3d1f50e74bc46af42a35771ccae2225826ebfed3 Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Thu, 14 Aug 2025 12:44:10 +0300
Subject: [PATCH 01/13] 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 a/ip/ffmpeg.c b/ip/ffmpeg.c
index 21b9a01f4..ecbf00582 100644
--- a/ip/ffmpeg.c
+++ b/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 d4c60887daca3700be3df99ea5067bbddc1b9a26 Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Fri, 15 Aug 2025 21:42:19 +0300
Subject: [PATCH 02/13] ip/ffmpeg: skip samples only when needed
---
ip/ffmpeg.c | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index ecbf00582..5f5a4f37b 100644
--- a/ip/ffmpeg.c
+++ b/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 07e4c10d1f61575d6acbd457a1dcb4d57d8b6535 Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Sat, 16 Aug 2025 02:43:55 +0300
Subject: [PATCH 03/13] 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 a/ip/ffmpeg.c b/ip/ffmpeg.c
index 5f5a4f37b..f6a11f450 100644
--- a/ip/ffmpeg.c
+++ b/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 791d190b532eef4d833d0325e8f56b069168b096 Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Sun, 17 Aug 2025 04:05:36 +0300
Subject: [PATCH 04/13] ip/ffmpeg: major refactor
---
ip/ffmpeg.c | 643 +++++++++++++++++++++++++++-------------------------
1 file changed, 330 insertions(+), 313 deletions(-)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index f6a11f450..42f630ee7 100644
--- a/ip/ffmpeg.c
+++ b/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);
- av_opt_set_sample_fmt(swr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
- break;
+
+ frame->sample_rate = sf_get_rate(sf);
+ frame->format = out_sample_fmt;
+
+ /* NOTE: 10 sec is probably too much, but the amount of space
+ * needed for swr_convert() is unpredictable */
+ frame->nb_samples = 10 * sf_get_rate(sf);
+ int res = av_frame_get_buffer(frame, 0);
+ if (res < 0) {
+ d_print("av_frame_get_buffer(): %s\n", ffmpeg_errmsg(res));
+ return -IP_ERROR_INTERNAL;
}
- swr_init(swr);
- ip_data->sf |= sf_host_endian();
+ frame->nb_samples = 0;
+
+ priv->swr_frame = frame;
+ return 0;
+}
+
+static void ffmpeg_free(struct ffmpeg_private *priv)
+{
+ avcodec_close(priv->codec_ctx);
+ avcodec_free_context(&priv->codec_ctx);
+ avformat_close_input(&priv->format_ctx);
+
+ swr_free(&priv->swr);
+
+ av_frame_free(&priv->frame);
+ av_packet_free(&priv->pkt);
+ av_frame_free(&priv->swr_frame);
+}
+
+static int ffmpeg_open(struct input_plugin_data *ip_data)
+{
+ struct ffmpeg_private priv;
+ enum AVSampleFormat out_sample_fmt;
+ memset(&priv, 0, sizeof(struct ffmpeg_private));
+
+ ffmpeg_init();
+
+ int err = ffmpeg_open_input(ip_data, &priv);
+ if (err < 0)
+ return err;
+
+ priv.pkt = av_packet_alloc();
+ priv.frame = av_frame_alloc();
+ priv.seek_ts = -1;
+ priv.prev_frame_end = -1;
+
+ priv.swr = swr_alloc();
+ ffmpeg_set_sf_and_swr_opts(priv.swr, priv.codec_ctx,
+ &ip_data->sf, &out_sample_fmt);
+ swr_init(priv.swr);
+
+ err = ffmpeg_init_swr_frame(&priv, ip_data->sf, out_sample_fmt);
+ if (err < 0) {
+ ffmpeg_free(&priv);
+ return err;
+ }
+
#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);
+ channel_map_init_waveex(priv.codec_ctx->ch_layout.nb_channels,
+ priv.codec_ctx->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(priv.codec_ctx->channels,
+ priv.codec_ctx->channel_layout, ip_data->channel_map);
#endif
+
+ ip_data->private = xnew(struct ffmpeg_private, 1);
+ memcpy(ip_data->private, &priv, sizeof(struct ffmpeg_private));
return 0;
}
static int ffmpeg_close(struct input_plugin_data *ip_data)
{
- struct ffmpeg_private *priv = ip_data->private;
-
- avcodec_close(priv->codec_context);
- avcodec_free_context(&priv->codec_context);
- avformat_close_input(&priv->input_context);
- swr_free(&priv->swr);
- ffmpeg_input_free(priv->input);
- ffmpeg_output_free(priv->output);
- free(priv);
+ ffmpeg_free(ip_data->private);
+ free(ip_data->private);
ip_data->private = NULL;
return 0;
}
/*
- * This returns the number of bytes added to the buffer.
- * It returns < 0 on error. 0 on EOF.
+ * return:
+ * 0 - retry
+ * >0 - ok
*/
-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_seek_into_frame(struct ffmpeg_private *priv, int64_t frame_ts)
{
- AVFrame *frame = av_frame_alloc();
- while (1) {
- if (input->curr_pkt_size <= 0) {
- av_packet_unref(&input->pkt);
- if (av_read_frame(ic, &input->pkt) < 0) {
- /* Force EOF once we can read no longer. */
- av_frame_free(&frame);
- return 0;
- }
-
- if (input->pkt.stream_index != input->stream_index)
- continue;
- input->curr_pkt_size = input->pkt.size;
- input->curr_size += input->pkt.size;
- input->curr_duration += input->pkt.duration;
-
- 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");
- }
- return -IP_ERROR_INTERNAL;
- }
- }
+ if (frame_ts >= 0) {
+ AVStream *s = priv->format_ctx->streams[priv->stream_index];
+ frame_ts = av_rescale_q(frame_ts, s->time_base, AV_TIME_BASE_Q);
+ } else {
+ frame_ts = priv->prev_frame_end;
+ }
- int recv_result = avcodec_receive_frame(cc, frame);
- if (recv_result < 0) {
- input->curr_pkt_size = 0;
- continue;
- }
+ if (frame_ts >= priv->seek_ts)
+ return 1;
- int64_t frame_ts = -1;
- if (frame->pts)
- frame_ts = frame->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;
-
- if (frame_ts < input->seek_ts) {
- 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);
- if (frame_end <= input->seek_ts)
- continue;
-
- /* skip part of this frame */
- 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 < sf_get_channels(ip_data->sf); i++) {
- in[i] += skip_samples * sf_get_sample_size(ip_data->sf);
- }
- } else {
- *in += skip_samples * sf_get_frame_size(ip_data->sf);
- }
- d_print("skipping %ld samples\n", skip_samples);
- }
-
- input->seek_ts = -1;
- input->prev_frame_end = -1;
- }
+ int64_t frame_dur = av_rescale(priv->frame->nb_samples,
+ AV_TIME_BASE, priv->frame->sample_rate);
+ int64_t frame_end = frame_ts + frame_dur;
+ priv->prev_frame_end = frame_end;
+
+ d_print("seek_ts: %ld, frame_ts: %ld, frame_end: %ld\n",
+ priv->seek_ts, frame_ts, frame_end);
+
+ if (frame_end <= priv->seek_ts)
+ return 0;
+
+ int64_t skip_samples = av_rescale(priv->seek_ts - frame_ts,
+ priv->frame->sample_rate, AV_TIME_BASE);
+ priv->frame->nb_samples -= skip_samples;
+
+ int bps = av_get_bytes_per_sample(priv->frame->format);
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100)
+ int channels = priv->codec_ctx->ch_layout.nb_channels;
+#else
+ int channels = priv->codec_ctx->channels;
+#endif
+
+ /* Just modify frame's data pointer because it's throw-away */
+ if (av_sample_fmt_is_planar(priv->frame->format)) {
+ for (int i = 0; i < channels; i++)
+ priv->frame->extended_data[i] += skip_samples * bps;
+ } else {
+ priv->frame->extended_data[0] += skip_samples * channels * bps;
+ }
+ d_print("skipping %ld samples\n", skip_samples);
+ return 1;
+}
- int res = swr_convert(swr,
- &output->buffer,
- frame->nb_samples,
- in,
- in_count);
+/*
+ * return:
+ * <0 - error
+ * 0 - retry
+ * >0 - ok
+ */
+static int ffmpeg_get_frame(struct ffmpeg_private *priv)
+{
+ int res = avcodec_receive_frame(priv->codec_ctx, priv->frame);
+ if (res == AVERROR(EAGAIN)) {
+ av_packet_unref(priv->pkt);
+ res = av_read_frame(priv->format_ctx, priv->pkt);
if (res < 0)
- res = 0;
+ return res;
+
+ if (priv->pkt->stream_index != priv->stream_index)
+ return 0;
- output->buffer_pos = output->buffer;
- output->buffer_used_len = res * sf_get_frame_size(ip_data->sf);
+ priv->curr_size += priv->pkt->size;
+ priv->curr_duration += priv->pkt->duration;
- av_frame_free(&frame);
- return output->buffer_used_len;
+ res = avcodec_send_packet(priv->codec_ctx, priv->pkt);
+ if (res == AVERROR(EAGAIN))
+ return 0;
}
- /* This should never get here. */
- return -IP_ERROR_INTERNAL;
+ if (res < 0)
+ return res;
+
+ int64_t frame_ts = -1;
+ if (priv->frame->pts >= 0)
+ frame_ts = priv->frame->pts;
+ else if (priv->frame->pkt_dts >= 0)
+ frame_ts = priv->frame->pkt_dts;
+
+ if (priv->seek_ts > 0 && (frame_ts >= 0 || priv->prev_frame_end >= 0)) {
+ if (ffmpeg_seek_into_frame(priv, frame_ts) == 0)
+ return 0;
+ priv->seek_ts = -1;
+ priv->prev_frame_end = -1;
+ }
+ return 1;
+}
+
+static int ffmpeg_convert_frame(struct ffmpeg_private *priv)
+{
+ int res = swr_convert(priv->swr,
+ priv->swr_frame->extended_data,
+ /* TODO: proper buffer capacity */
+ priv->frame->nb_samples,
+ (const uint8_t **)priv->frame->extended_data,
+ priv->frame->nb_samples);
+ if (res >= 0) {
+ priv->swr_frame->nb_samples = res;
+ priv->swr_frame_start = 0;
+ }
+ return res;
}
static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int count)
{
struct ffmpeg_private *priv = ip_data->private;
- struct ffmpeg_output *output = priv->output;
- int rc;
- int out_size;
-
- if (output->buffer_used_len == 0) {
- rc = ffmpeg_fill_buffer(ip_data,
- priv->input_context, priv->codec_context,
- priv->input, priv->output, priv->swr);
- if (rc <= 0)
- return rc;
+ int written = 0;
+ int res;
+
+ count /= sf_get_frame_size(ip_data->sf);
+
+ while (count) {
+ if (priv->swr_frame->nb_samples == 0) {
+ res = ffmpeg_get_frame(priv);
+ if (res == AVERROR_EOF)
+ break;
+ else if (res == 0)
+ continue;
+ else if (res < 0)
+ goto err;
+
+ res = ffmpeg_convert_frame(priv);
+ if (res < 0)
+ goto err;
+ }
+
+ int copy_frames = min_i(count, priv->swr_frame->nb_samples);
+ int copy_bytes = copy_frames * sf_get_frame_size(ip_data->sf);
+ void *dst = priv->swr_frame->extended_data[0] + priv->swr_frame_start;
+ memcpy(buffer + written, dst, copy_bytes);
+
+ priv->swr_frame->nb_samples -= copy_frames;
+ priv->swr_frame_start += copy_bytes;
+ count -= copy_frames;
+ written += copy_bytes;
}
- out_size = min_i(output->buffer_used_len, count);
- memcpy(buffer, output->buffer_pos, out_size);
- output->buffer_used_len -= out_size;
- output->buffer_pos += out_size;
- return out_size;
+ return written;
+err:
+ d_print("%s\n", ffmpeg_errmsg(res));
+ return -IP_ERROR_INTERNAL;
}
static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset)
{
struct ffmpeg_private *priv = ip_data->private;
- AVStream *st = priv->input_context->streams[priv->input->stream_index];
- int ret;
+ AVStream *st = priv->format_ctx->streams[priv->stream_index];
- priv->input->seek_ts = offset * AV_TIME_BASE;
- priv->input->prev_frame_end = -1;
+ priv->seek_ts = offset * AV_TIME_BASE;
+ priv->prev_frame_end = -1;
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;
-
- ret = avformat_seek_file(priv->input_context,
- priv->input->stream_index, 0, ts, ts, 0);
-
- if (ret < 0) {
+ int ret = avformat_seek_file(priv->format_ctx,
+ priv->stream_index, 0, ts, ts, 0);
+ if (ret < 0)
return -IP_ERROR_FUNCTION_NOT_SUPPORTED;
- } else {
- ffmpeg_buffer_flush(priv->output);
- return 0;
- }
+
+ priv->swr_frame->nb_samples = 0;
+ avcodec_flush_buffers(priv->codec_ctx);
+ /* also flush swresample buffers? */
+ return 0;
}
static void ffmpeg_read_metadata(struct growing_keyvals *c, AVDictionary *metadata)
@@ -445,7 +462,7 @@ 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;
+ AVFormatContext *ic = priv->format_ctx;
GROWING_KEYVALS(c);
@@ -463,29 +480,29 @@ static int ffmpeg_read_comments(struct input_plugin_data *ip_data,
static int ffmpeg_duration(struct input_plugin_data *ip_data)
{
struct ffmpeg_private *priv = ip_data->private;
- return priv->input_context->duration / AV_TIME_BASE;
+ return priv->format_ctx->duration / AV_TIME_BASE;
}
static long ffmpeg_bitrate(struct input_plugin_data *ip_data)
{
struct ffmpeg_private *priv = ip_data->private;
- long bitrate = priv->input_context->bit_rate;
+ long bitrate = priv->format_ctx->bit_rate;
return bitrate ? bitrate : -IP_ERROR_FUNCTION_NOT_SUPPORTED;
}
static long ffmpeg_current_bitrate(struct input_plugin_data *ip_data)
{
struct ffmpeg_private *priv = ip_data->private;
- AVStream *st = priv->input_context->streams[priv->input->stream_index];
+ AVStream *st = priv->format_ctx->streams[priv->stream_index];
long bitrate = -1;
/* ape codec returns silly numbers */
if (priv->codec->id == AV_CODEC_ID_APE)
return -1;
- if (priv->input->curr_duration > 0) {
- double seconds = priv->input->curr_duration * av_q2d(st->time_base);
- bitrate = (8 * priv->input->curr_size) / seconds;
- priv->input->curr_size = 0;
- priv->input->curr_duration = 0;
+ if (priv->curr_duration > 0) {
+ double seconds = priv->curr_duration * av_q2d(st->time_base);
+ bitrate = (8 * priv->curr_size) / seconds;
+ priv->curr_size = 0;
+ priv->curr_duration = 0;
}
return bitrate;
}
@@ -500,7 +517,7 @@ static char *ffmpeg_codec_profile(struct input_plugin_data *ip_data)
{
struct ffmpeg_private *priv = ip_data->private;
const char *profile;
- profile = av_get_profile_name(priv->codec, priv->codec_context->profile);
+ profile = av_get_profile_name(priv->codec, priv->codec_ctx->profile);
return profile ? xstrdup(profile) : NULL;
}
From 92580b01661a118ec2bf79c5f2097388e34c1fc2 Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Sun, 17 Aug 2025 14:28:46 +0300
Subject: [PATCH 05/13] Validate sample format in ip_open()
To prevent segfault in ip_setup() because channels=0, validate ip_data->sf
after opening ip.
---
input.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/input.c b/input.c
index c20cb3f6a..f5c5b3c24 100644
--- a/input.c
+++ b/input.c
@@ -605,6 +605,16 @@ int ip_open(struct input_plugin *ip)
ip_reset(ip, 1);
return rc;
}
+
+ unsigned bits = sf_get_bits(ip->data.sf);
+ unsigned channels = sf_get_channels(ip->data.sf);
+ unsigned rate = sf_get_rate(ip->data.sf);
+ if (!bits || !channels || !rate) {
+ d_print("corrupt file: bits = %u, channels = %u, rate = %u\n",
+ bits, channels, rate);
+ return -IP_ERROR_FILE_FORMAT;
+ }
+
ip->open = 1;
return 0;
}
From 4fab7c4246e7c99c0f867585282ff66a62af043b Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Sun, 17 Aug 2025 14:53:52 +0300
Subject: [PATCH 06/13] ip/ffmpeg: flush swresample buffer when seeking
---
ip/ffmpeg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index 42f630ee7..775e7de1d 100644
--- a/ip/ffmpeg.c
+++ b/ip/ffmpeg.c
@@ -444,7 +444,7 @@ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset)
priv->swr_frame->nb_samples = 0;
avcodec_flush_buffers(priv->codec_ctx);
- /* also flush swresample buffers? */
+ swr_convert(priv->swr, NULL, 0, NULL, 0); /* flush swr buffer */
return 0;
}
From 0192d8abd980a12eb438c425db60dcf4a353f0fc Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Sun, 17 Aug 2025 15:02:34 +0300
Subject: [PATCH 07/13] ip/ffmpeg: remember swr_frame's capacity
---
ip/ffmpeg.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index 775e7de1d..c659c1330 100644
--- a/ip/ffmpeg.c
+++ b/ip/ffmpeg.c
@@ -49,6 +49,7 @@ struct ffmpeg_private {
/* A buffer to hold swr_convert()-ed samples */
AVFrame *swr_frame;
+ int swr_frame_samples_cap;
int swr_frame_start;
/* Bitrate estimation */
@@ -213,6 +214,7 @@ static int ffmpeg_init_swr_frame(struct ffmpeg_private *priv,
d_print("av_frame_get_buffer(): %s\n", ffmpeg_errmsg(res));
return -IP_ERROR_INTERNAL;
}
+ priv->swr_frame_samples_cap = frame->nb_samples;
frame->nb_samples = 0;
priv->swr_frame = frame;
@@ -378,8 +380,7 @@ static int ffmpeg_convert_frame(struct ffmpeg_private *priv)
{
int res = swr_convert(priv->swr,
priv->swr_frame->extended_data,
- /* TODO: proper buffer capacity */
- priv->frame->nb_samples,
+ priv->swr_frame_samples_cap,
(const uint8_t **)priv->frame->extended_data,
priv->frame->nb_samples);
if (res >= 0) {
From 02943fba13697749decff9375b89b9dfa05f04af Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Sun, 17 Aug 2025 15:54:19 +0300
Subject: [PATCH 08/13] ip/ffmpeg: reset swr_frame_start when seeking
---
ip/ffmpeg.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index c659c1330..71cc51116 100644
--- a/ip/ffmpeg.c
+++ b/ip/ffmpeg.c
@@ -444,6 +444,7 @@ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset)
return -IP_ERROR_FUNCTION_NOT_SUPPORTED;
priv->swr_frame->nb_samples = 0;
+ priv->swr_frame_start = 0;
avcodec_flush_buffers(priv->codec_ctx);
swr_convert(priv->swr, NULL, 0, NULL, 0); /* flush swr buffer */
return 0;
From 608c80b3ce12fa535fdeb6ea4aebe851b433a70c Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Sun, 17 Aug 2025 17:27:20 +0300
Subject: [PATCH 09/13] ip/ffmpeg: better frame skipping logic
---
ip/ffmpeg.c | 82 ++++++++++++++++++++++++++---------------------------
1 file changed, 41 insertions(+), 41 deletions(-)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index 71cc51116..af6ecfb8d 100644
--- a/ip/ffmpeg.c
+++ b/ip/ffmpeg.c
@@ -44,8 +44,8 @@ struct ffmpeg_private {
AVPacket *pkt;
AVFrame *frame;
- int64_t seek_ts;
- int64_t prev_frame_end;
+ double seek_ts;
+ int64_t skip_samples;
/* A buffer to hold swr_convert()-ed samples */
AVFrame *swr_frame;
@@ -249,7 +249,6 @@ static int ffmpeg_open(struct input_plugin_data *ip_data)
priv.pkt = av_packet_alloc();
priv.frame = av_frame_alloc();
priv.seek_ts = -1;
- priv.prev_frame_end = -1;
priv.swr = swr_alloc();
ffmpeg_set_sf_and_swr_opts(priv.swr, priv.codec_ctx,
@@ -283,37 +282,37 @@ static int ffmpeg_close(struct input_plugin_data *ip_data)
return 0;
}
-/*
- * return:
- * 0 - retry
- * >0 - ok
- */
-static int ffmpeg_seek_into_frame(struct ffmpeg_private *priv, int64_t frame_ts)
+static int64_t ffmpeg_calc_skip_samples(struct ffmpeg_private *priv)
{
- if (frame_ts >= 0) {
- AVStream *s = priv->format_ctx->streams[priv->stream_index];
- frame_ts = av_rescale_q(frame_ts, s->time_base, AV_TIME_BASE_Q);
+ int64_t ts;
+ if (priv->frame->pts >= 0) {
+ ts = priv->frame->pts;
+ } else if (priv->frame->pkt_dts >= 0) {
+ ts = priv->frame->pkt_dts;
} else {
- frame_ts = priv->prev_frame_end;
+ d_print("AVFrame.pts and AVFrame.pkt_dts are unset\n");
+ return -1;
}
- if (frame_ts >= priv->seek_ts)
- return 1;
-
- int64_t frame_dur = av_rescale(priv->frame->nb_samples,
- AV_TIME_BASE, priv->frame->sample_rate);
- int64_t frame_end = frame_ts + frame_dur;
- priv->prev_frame_end = frame_end;
+ AVStream *s = priv->format_ctx->streams[priv->stream_index];
+ double frame_ts = ts * av_q2d(s->time_base);
- d_print("seek_ts: %ld, frame_ts: %ld, frame_end: %ld\n",
- priv->seek_ts, frame_ts, frame_end);
+ d_print("seek_ts: %.6fs, frame_ts: %.6fs\n", priv->seek_ts, frame_ts);
- if (frame_end <= priv->seek_ts)
+ if (frame_ts >= priv->seek_ts)
return 0;
+ return (priv->seek_ts - frame_ts) * priv->frame->sample_rate;
+}
- int64_t skip_samples = av_rescale(priv->seek_ts - frame_ts,
- priv->frame->sample_rate, AV_TIME_BASE);
- priv->frame->nb_samples -= skip_samples;
+static void ffmpeg_skip_frame_part(struct ffmpeg_private *priv)
+{
+ if (priv->skip_samples >= priv->frame->nb_samples) {
+ d_print("skipping frame: %d samples\n",
+ priv->frame->nb_samples);
+ priv->skip_samples -= priv->frame->nb_samples;
+ priv->frame->nb_samples = 0;
+ return;
+ }
int bps = av_get_bytes_per_sample(priv->frame->format);
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(59, 24, 100)
@@ -322,15 +321,17 @@ static int ffmpeg_seek_into_frame(struct ffmpeg_private *priv, int64_t frame_ts)
int channels = priv->codec_ctx->channels;
#endif
+ priv->frame->nb_samples -= priv->skip_samples;
+
/* Just modify frame's data pointer because it's throw-away */
if (av_sample_fmt_is_planar(priv->frame->format)) {
for (int i = 0; i < channels; i++)
- priv->frame->extended_data[i] += skip_samples * bps;
+ priv->frame->extended_data[i] += priv->skip_samples * bps;
} else {
- priv->frame->extended_data[0] += skip_samples * channels * bps;
+ priv->frame->extended_data[0] += priv->skip_samples * channels * bps;
}
- d_print("skipping %ld samples\n", skip_samples);
- return 1;
+ d_print("skipping %ld samples\n", priv->skip_samples);
+ priv->skip_samples = 0;
}
/*
@@ -361,17 +362,16 @@ static int ffmpeg_get_frame(struct ffmpeg_private *priv)
if (res < 0)
return res;
- int64_t frame_ts = -1;
- if (priv->frame->pts >= 0)
- frame_ts = priv->frame->pts;
- else if (priv->frame->pkt_dts >= 0)
- frame_ts = priv->frame->pkt_dts;
+ if (priv->seek_ts > 0) {
+ priv->skip_samples = ffmpeg_calc_skip_samples(priv);
+ if (priv->skip_samples >= 0)
+ priv->seek_ts = -1;
+ }
- if (priv->seek_ts > 0 && (frame_ts >= 0 || priv->prev_frame_end >= 0)) {
- if (ffmpeg_seek_into_frame(priv, frame_ts) == 0)
+ if (priv->skip_samples > 0) {
+ ffmpeg_skip_frame_part(priv);
+ if (priv->frame->nb_samples == 0)
return 0;
- priv->seek_ts = -1;
- priv->prev_frame_end = -1;
}
return 1;
}
@@ -434,8 +434,8 @@ static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset)
struct ffmpeg_private *priv = ip_data->private;
AVStream *st = priv->format_ctx->streams[priv->stream_index];
- priv->seek_ts = offset * AV_TIME_BASE;
- priv->prev_frame_end = -1;
+ priv->seek_ts = offset;
+ priv->skip_samples = 0;
int64_t ts = av_rescale(offset, st->time_base.den, st->time_base.num);
int ret = avformat_seek_file(priv->format_ctx,
From bb99dc0ccc57adb0559cee21c6bfca25e8e40834 Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Sun, 17 Aug 2025 19:22:50 +0300
Subject: [PATCH 10/13] ip/ffmpeg: don't process empty frames
---
ip/ffmpeg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index af6ecfb8d..dd9061aba 100644
--- a/ip/ffmpeg.c
+++ b/ip/ffmpeg.c
@@ -356,7 +356,7 @@ static int ffmpeg_get_frame(struct ffmpeg_private *priv)
priv->curr_duration += priv->pkt->duration;
res = avcodec_send_packet(priv->codec_ctx, priv->pkt);
- if (res == AVERROR(EAGAIN))
+ if (res == 0 || res == AVERROR(EAGAIN))
return 0;
}
if (res < 0)
From 7e4935eee4668a8428a3e3bf73b866b09f3ed067 Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Mon, 18 Aug 2025 03:32:22 +0300
Subject: [PATCH 11/13] ip/ffmpeg: improve readability
Previously ffmpeg_read()'s while loop was kinda leaking into
ffmpeg_get_frame(), now it doesn't.
---
ip/ffmpeg.c | 36 ++++++++++++++++++++----------------
1 file changed, 20 insertions(+), 16 deletions(-)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index dd9061aba..fc748951f 100644
--- a/ip/ffmpeg.c
+++ b/ip/ffmpeg.c
@@ -337,30 +337,32 @@ static void ffmpeg_skip_frame_part(struct ffmpeg_private *priv)
/*
* return:
* <0 - error
- * 0 - retry
+ * 0 - eof
* >0 - ok
*/
static int ffmpeg_get_frame(struct ffmpeg_private *priv)
{
- int res = avcodec_receive_frame(priv->codec_ctx, priv->frame);
+ int res;
+retry:
+ res = avcodec_receive_frame(priv->codec_ctx, priv->frame);
if (res == AVERROR(EAGAIN)) {
av_packet_unref(priv->pkt);
res = av_read_frame(priv->format_ctx, priv->pkt);
if (res < 0)
- return res;
+ goto err;
if (priv->pkt->stream_index != priv->stream_index)
- return 0;
+ goto retry;
priv->curr_size += priv->pkt->size;
priv->curr_duration += priv->pkt->duration;
res = avcodec_send_packet(priv->codec_ctx, priv->pkt);
if (res == 0 || res == AVERROR(EAGAIN))
- return 0;
+ goto retry;
}
if (res < 0)
- return res;
+ goto err;
if (priv->seek_ts > 0) {
priv->skip_samples = ffmpeg_calc_skip_samples(priv);
@@ -371,9 +373,14 @@ static int ffmpeg_get_frame(struct ffmpeg_private *priv)
if (priv->skip_samples > 0) {
ffmpeg_skip_frame_part(priv);
if (priv->frame->nb_samples == 0)
- return 0;
+ goto retry;
}
return 1;
+err:
+ if (res == AVERROR_EOF)
+ return 0;
+ d_print("%s\n", ffmpeg_errmsg(res));
+ return -IP_ERROR_INTERNAL;
}
static int ffmpeg_convert_frame(struct ffmpeg_private *priv)
@@ -386,8 +393,10 @@ static int ffmpeg_convert_frame(struct ffmpeg_private *priv)
if (res >= 0) {
priv->swr_frame->nb_samples = res;
priv->swr_frame_start = 0;
+ return res;
}
- return res;
+ d_print("%s\n", ffmpeg_errmsg(res));
+ return -IP_ERROR_INTERNAL;
}
static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int count)
@@ -401,16 +410,14 @@ static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int coun
while (count) {
if (priv->swr_frame->nb_samples == 0) {
res = ffmpeg_get_frame(priv);
- if (res == AVERROR_EOF)
+ if (res == 0)
break;
- else if (res == 0)
- continue;
else if (res < 0)
- goto err;
+ return res;
res = ffmpeg_convert_frame(priv);
if (res < 0)
- goto err;
+ return res;
}
int copy_frames = min_i(count, priv->swr_frame->nb_samples);
@@ -424,9 +431,6 @@ static int ffmpeg_read(struct input_plugin_data *ip_data, char *buffer, int coun
written += copy_bytes;
}
return written;
-err:
- d_print("%s\n", ffmpeg_errmsg(res));
- return -IP_ERROR_INTERNAL;
}
static int ffmpeg_seek(struct input_plugin_data *ip_data, double offset)
From 23da0dbc7bf34655041195a7189a92b8018e9f12 Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Sun, 24 Aug 2025 19:16:57 +0300
Subject: [PATCH 12/13] ip/ffmpeg: fix building for ffmpeg 8.0
avcodec_close() can be safely removed because avcodec_free_context()
is its replacement since 2016. See ffmpeg commit 2ef6dab0a79
Builds with v3.3.9 v4.0.6 v6.1.3 v7.1.1 v8.0
---
ip/ffmpeg.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index fc748951f..2cb07671c 100644
--- a/ip/ffmpeg.c
+++ b/ip/ffmpeg.c
@@ -223,7 +223,6 @@ static int ffmpeg_init_swr_frame(struct ffmpeg_private *priv,
static void ffmpeg_free(struct ffmpeg_private *priv)
{
- avcodec_close(priv->codec_ctx);
avcodec_free_context(&priv->codec_ctx);
avformat_close_input(&priv->format_ctx);
From 625ea17808896daf2d02fa92b3766d10796209cb Mon Sep 17 00:00:00 2001
From: ihy123 <aladinandreyy@gmail.com>
Date: Mon, 25 Aug 2025 11:17:06 +0300
Subject: [PATCH 13/13] ip/ffmpeg: change sample format conversions
---
ip/ffmpeg.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/ip/ffmpeg.c b/ip/ffmpeg.c
index 2cb07671c..2d3c610f2 100644
--- a/ip/ffmpeg.c
+++ b/ip/ffmpeg.c
@@ -157,13 +157,11 @@ static void ffmpeg_set_sf_and_swr_opts(SwrContext *swr, AVCodecContext *cc,
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:
+ switch (cc->sample_fmt) {
+ case AV_SAMPLE_FMT_FLT: case AV_SAMPLE_FMT_FLTP:
+ case AV_SAMPLE_FMT_S32: case AV_SAMPLE_FMT_S32P:
sf |= sf_bits(32) | sf_signed(1);
+ *out_sample_fmt = AV_SAMPLE_FMT_S32;
break;
default:
sf |= sf_bits(16) | sf_signed(1);