summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-06-16 22:38:37 +0200
committerwm4 <wm4@nowhere>2015-06-16 22:38:37 +0200
commit5a9f817bfde81d41b14dde44893dbc4855876e49 (patch)
treed4b3a3e099d6356bb8a0bf190ed905cf3e407225
parent8ee9c170bec573e7c703d6902d0478f49d987b3e (diff)
downloadmpv-5a9f817bfde81d41b14dde44893dbc4855876e49.tar.bz2
mpv-5a9f817bfde81d41b14dde44893dbc4855876e49.tar.xz
af_lavrresample: integrate 24 bit (3 bytes per sample) output
Now af_lavrresample can output 24 bit samples directly, by doing the conversion "inline". Luckily, S32->S24 can be done in-place, so this isn't too much work. But the output conversion logic (which seems to be adding up) gets slightly more complicated again. Normally this is done by af_convert24. But having multiple conversion filters complicates some aspects of the filter chain. S24 output is the only thing the code for multiple conversion filters is still needed for, and getting rid of that is preferable.
-rw-r--r--audio/filter/af_lavrresample.c57
1 files changed, 48 insertions, 9 deletions
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c
index 77e2dde50e..cfc3bc847d 100644
--- a/audio/filter/af_lavrresample.c
+++ b/audio/filter/af_lavrresample.c
@@ -82,6 +82,7 @@ struct af_resample {
struct AVAudioResampleContext *avrctx;
struct mp_audio avrctx_fmt; // output format of avrctx
struct mp_audio pool_fmt; // format used to allocate frames for avrctx output
+ struct mp_audio pre_out_fmt; // format before final conversion (S24)
struct AVAudioResampleContext *avrctx_out; // for output channel reordering
struct af_resample_opts ctx; // opts in the context
struct af_resample_opts opts; // opts requested by the user
@@ -165,10 +166,21 @@ static bool needs_lavrctx_reconfigure(struct af_resample *s,
}
+// Return the format libavresample should convert to, given the input format
+// mp_format. In some cases (S24) we perform an extra conversion step, and
+// signal here what exactly libavresample should output. It will be the input
+// to the final conversion to mp_format.
+static int check_output_conversion(int mp_format)
+{
+ if (mp_format == AF_FORMAT_S24)
+ return AV_SAMPLE_FMT_S32;
+ return af_to_avformat(mp_format);
+}
+
static bool test_conversion(int src_format, int dst_format)
{
return af_to_avformat(src_format) != AV_SAMPLE_FMT_NONE &&
- af_to_avformat(dst_format) != AV_SAMPLE_FMT_NONE;
+ check_output_conversion(dst_format) != AV_SAMPLE_FMT_NONE;
}
// mp_chmap_get_reorder() performs:
@@ -195,9 +207,8 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
s->avrctx_ok = false;
enum AVSampleFormat in_samplefmt = af_to_avformat(in->format);
- enum AVSampleFormat out_samplefmt = af_to_avformat(out->format);
- enum AVSampleFormat out_samplefmtp =
- af_to_avformat(af_fmt_to_planar(out->format));
+ enum AVSampleFormat out_samplefmt = check_output_conversion(out->format);
+ enum AVSampleFormat out_samplefmtp = av_get_planar_sample_fmt(out_samplefmt);
if (in_samplefmt == AV_SAMPLE_FMT_NONE ||
out_samplefmt == AV_SAMPLE_FMT_NONE ||
@@ -274,6 +285,9 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
mp_audio_set_channels(&s->avrctx_fmt, &out_lavc);
mp_audio_set_format(&s->avrctx_fmt, af_from_avformat(out_samplefmtp));
+ s->pre_out_fmt = *out;
+ mp_audio_set_format(&s->pre_out_fmt, af_from_avformat(out_samplefmt));
+
// If there are NA channels, the final output will have more channels than
// the avrctx output. Also, avrctx will output planar (out_samplefmtp was
// not overwritten). Allocate the output frame with more channels, so the
@@ -343,7 +357,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (af_to_avformat(in->format) == AV_SAMPLE_FMT_NONE)
mp_audio_set_format(in, AF_FORMAT_FLOAT);
- if (af_to_avformat(out->format) == AV_SAMPLE_FMT_NONE)
+ if (check_output_conversion(out->format) == AV_SAMPLE_FMT_NONE)
mp_audio_set_format(out, in->format);
int r = ((in->format == orig_in.format) &&
@@ -356,7 +370,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
}
case AF_CONTROL_SET_FORMAT: {
int format = *(int *)arg;
- if (format && af_to_avformat(format) == AV_SAMPLE_FMT_NONE)
+ if (format && check_output_conversion(format) == AV_SAMPLE_FMT_NONE)
return AF_FALSE;
mp_audio_set_format(af->data, format);
@@ -399,6 +413,28 @@ static void uninit(struct af_instance *af)
avresample_free(&s->avrctx_out);
}
+// The LSB is always ignored.
+#if BYTE_ORDER == BIG_ENDIAN
+#define SHIFT24(x) ((3-(x))*8)
+#else
+#define SHIFT24(x) (((x)+1)*8)
+#endif
+
+static void extra_output_conversion(struct af_instance *af, struct mp_audio *mpa)
+{
+ if (mpa->format == AF_FORMAT_S32 && af->data->format == AF_FORMAT_S24) {
+ size_t len = mp_audio_psize(mpa) / mpa->bps;
+ for (int s = 0; s < len; s++) {
+ uint32_t val = *((uint32_t *)mpa->planes[0] + s);
+ uint8_t *ptr = (uint8_t *)mpa->planes[0] + s * 3;
+ ptr[0] = val >> SHIFT24(0);
+ ptr[1] = val >> SHIFT24(1);
+ ptr[2] = val >> SHIFT24(2);
+ }
+ mp_audio_set_format(mpa, AF_FORMAT_S24);
+ }
+}
+
// This relies on the tricky way mpa was allocated.
static void reorder_planes(struct mp_audio *mpa, int *reorder,
struct mp_chmap *newmap)
@@ -445,11 +481,12 @@ static int filter(struct af_instance *af, struct mp_audio *in)
struct mp_audio real_out = *out;
mp_audio_copy_config(out, &s->avrctx_fmt);
- if (out->samples && !mp_audio_config_equals(out, af->data)) {
+ if (out->samples && !mp_audio_config_equals(out, &s->pre_out_fmt)) {
assert(AF_FORMAT_IS_PLANAR(out->format) && out->format == real_out.format);
reorder_planes(out, s->reorder_out, &s->pool_fmt.channels);
- if (!mp_audio_config_equals(out, af->data)) {
- struct mp_audio *new = mp_audio_pool_get(s->reorder_buffer, af->data,
+ if (!mp_audio_config_equals(out, &s->pre_out_fmt)) {
+ struct mp_audio *new = mp_audio_pool_get(s->reorder_buffer,
+ &s->pre_out_fmt,
out->samples);
if (!new)
goto error;
@@ -462,6 +499,8 @@ static int filter(struct af_instance *af, struct mp_audio *in)
}
}
+ extra_output_conversion(af, out);
+
talloc_free(in);
if (out->samples) {
af_add_output_frame(af, out);