summaryrefslogtreecommitdiff
path: root/audio/resampler.c
diff options
context:
space:
mode:
authorbbergeron <[email protected]>2024-04-03 17:32:01 -0400
committerbbergeron <[email protected]>2024-04-03 17:32:01 -0400
commitc1cb78d574c0429aa5e3ff3a2b3886e4bc153212 (patch)
treebf68806bcbddcafafc015b28c25550ea457eeecc /audio/resampler.c
Reset Git repo and use a pseudonym to sign commits
I used to sign my commits with my real name and my personal email address, which I wanted scrubbed off the "B." pseudosphere. Re-creating a new git repository was safer than simpler than re-writing the history (although the latter could've also worked but, oh well).
Diffstat (limited to 'audio/resampler.c')
-rw-r--r--audio/resampler.c121
1 files changed, 121 insertions, 0 deletions
diff --git a/audio/resampler.c b/audio/resampler.c
new file mode 100644
index 0000000..6906d05
--- /dev/null
+++ b/audio/resampler.c
@@ -0,0 +1,121 @@
+#include <asm-generic/errno-base.h>
+#include <assert.h>
+#include <libavcodec/avcodec.h>
+#include <libavutil/error.h>
+#include <libavutil/opt.h>
+#include <libswresample/swresample.h>
+#include "resampler.h"
+
+#define MICROSECOND 1000000
+
+static inline uint64_t div_uint64_ceil(uint64_t num, uint64_t den)
+{
+ return (num / den) + (num % den != 0);
+}
+
+static int resampler_init (struct Resampler *resampler, const AVChannelLayout *out_chlayout, enum AVSampleFormat out_sample_fmt, int64_t out_sample_rate, uint64_t out_frame_size)
+{
+ /* Let me tell you something; you --don't want-- CAN'T configure a
+ * SwrContext manually, GOOD ****ING LUCK DOING THAT. The documentation is
+ * so bad on that matter, it only referes to "tHe PaRaMeTeRs" or show off a
+ * list of deprecated attribute which looks nothing like what's actually
+ * used in their API. I tried to copy what's being done in their a API but
+ * whatever I do would either not work or be liable to change since it's not
+ * documented for shit (even the documented stuff doesn't appears stable, so
+ * wtf am I saying anyway). A ****ing joke, I tell you that.
+ *
+ * Pardon my french.
+ *
+ * Anywho, instead of configuring the input parameter directly, we shove
+ * them in resampler so we can recall them before calling ffmpeg's SWR
+ * allocator.
+ */
+ resampler->out_chlayout = out_chlayout;
+ resampler->out_sample_fmt = out_sample_fmt;
+ resampler->out_sample_rate = out_sample_rate;
+ resampler->out_frame_size = out_frame_size;
+ resampler->swr = NULL;
+ return 0;
+}
+
+static int resampler_conf (struct Resampler *resampler, const AVChannelLayout *in_chlayout, enum AVSampleFormat in_sample_fmt, int64_t in_sample_rate)
+{
+ int err;
+
+ err = swr_alloc_set_opts2(
+ &resampler->swr,
+ resampler->out_chlayout,
+ resampler->out_sample_fmt,
+ resampler->out_sample_rate,
+ in_chlayout,
+ in_sample_fmt,
+ in_sample_rate,
+ 0, 0);
+ if (err) return err;
+
+ if (!swr_is_initialized(resampler->swr))
+ if ((err = swr_init(resampler->swr)))
+ return err;
+
+ resampler->in_sample_rate = in_sample_rate;
+ resampler->needed = div_uint64_ceil(resampler->out_frame_size * in_sample_rate, resampler->out_sample_rate);
+
+ return 0;
+}
+
+int resampler_send_frame (struct Resampler *resampler, AVFrame *in)
+{
+ int err;
+
+ if ((err = swr_convert(resampler->swr, NULL, 0, (const uint8_t **)in->extended_data, in->nb_samples)) < 0)
+ return err;
+ resampler->stored += in->nb_samples;
+ return 0;
+}
+
+int resampler_send_empty (struct Resampler *resampler, unsigned int microsecond)
+{
+ // TODO: Check for downcasting
+ int nb_samples;
+ nb_samples = div_uint64_ceil(microsecond * resampler->in_sample_rate, 1000);
+ return swr_inject_silence(resampler->swr, nb_samples);
+}
+
+int resampler_convert (struct Resampler *resampler, AVFrame *out)
+{
+ int err;
+ assert(out != NULL);
+ assert(resampler->swr != NULL);
+
+ if (resampler->stored < resampler->needed) {
+ return AVERROR(EAGAIN);
+ /*
+ err = swr_inject_silence(resampler->swr, resampler->needed - resampler->stored);
+ if (err < 0) return err;
+ */
+ }
+
+ err = swr_convert(resampler->swr, out->extended_data, out->nb_samples, NULL, 0);
+ if (err < 0) return err;
+ resampler->stored = 0;
+
+ return 0;
+}
+
+void resampler_free (struct Resampler *resampler)
+{
+ if (resampler == NULL) return;
+ swr_free(&resampler->swr);
+}
+
+int resampler_init_for_encoder (struct Resampler *resampler, const struct Encoder *encoder)
+{
+ AVCodecContext *avctx = encoder->avctx;
+ return resampler_init(resampler, &avctx->ch_layout, avctx->sample_fmt, avctx->sample_rate, avctx->frame_size);
+}
+
+int resampler_conf_for_decoder (struct Resampler *resampler, const struct Decoder *decoder)
+{
+ AVCodecContext *avctx = decoder->avctx;
+ return resampler_conf(resampler, &avctx->ch_layout, avctx->sample_fmt, avctx->sample_rate);
+}