summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-06-12 17:53:23 +0200
committerwm4 <wm4@nowhere>2015-06-12 17:53:23 +0200
commit433402b56cdc2a32a6cb45d13a234b9617a3c9f9 (patch)
tree3031f6bf25d4905212fc8632aa42569463524396
parentc890eeac47476acda3ae4e2579b021102139f12c (diff)
downloadmpv-433402b56cdc2a32a6cb45d13a234b9617a3c9f9.tar.bz2
mpv-433402b56cdc2a32a6cb45d13a234b9617a3c9f9.tar.xz
audio: fill NA channels with silence
Until now, we didn't do this, because it required some effort, and didn't seem to be necessary. It probably still isn't, but it sounds like a good idea not to output arbitrary data on these channels. The situation is complicated by the fact that just adding new channels to a planar frame would require messing with buffers. So we would have to allocate new buffers and add them to the frame. We could have to maintain an extra buffer pool for this. Avoid this by being "clever", and just allocate a frame with enough channels in the first place. libav/swresample won't know about these channels and won't write to them, but we can grab them in reorder_planes() and use them for the NA channels.
-rw-r--r--audio/filter/af_lavrresample.c40
1 files changed, 29 insertions, 11 deletions
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c
index 869f5840ab..4683025a7e 100644
--- a/audio/filter/af_lavrresample.c
+++ b/audio/filter/af_lavrresample.c
@@ -81,6 +81,7 @@ struct af_resample {
bool avrctx_ok;
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 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
@@ -273,6 +274,14 @@ 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));
+ // 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
+ // NA channels can be trivially added.
+ s->pool_fmt = s->avrctx_fmt;
+ if (map_out.num > out_lavc.num)
+ mp_audio_set_channels(&s->pool_fmt, &map_out);
+
// Real conversion; output is input to avrctx_out.
av_opt_set_int(s->avrctx, "in_channel_layout", in_ch_layout, 0);
av_opt_set_int(s->avrctx, "out_channel_layout", out_ch_layout, 0);
@@ -390,22 +399,28 @@ static void uninit(struct af_instance *af)
avresample_free(&s->avrctx_out);
}
+// This relies on the tricky way mpa was allocated.
static void reorder_planes(struct mp_audio *mpa, int *reorder,
struct mp_chmap *newmap)
{
struct mp_audio prev = *mpa;
+ mp_audio_set_channels(mpa, newmap);
+
+ // The trailing planes were never written by avrctx, they're the NA channels.
+ int next_na = prev.num_planes;
- for (int n = 0; n < newmap->num; n++) {
+ for (int n = 0; n < mpa->num_planes; n++) {
int src = reorder[n];
- if (src < 0) {
- src = 0; // Use the first plane for padding channels.
- mpa->readonly = true;
+ assert(src >= -1 && src < prev.num_planes);
+ if (src >= 0) {
+ mpa->planes[n] = prev.planes[src];
+ } else {
+ assert(next_na < mpa->num_planes);
+ mpa->planes[n] = prev.planes[next_na++];
+ af_fill_silence(mpa->planes[n], mpa->sstride * mpa->samples,
+ mpa->format);
}
- assert(src < mpa->num_planes);
- mpa->planes[n] = prev.planes[src];
}
-
- mp_audio_set_channels(mpa, newmap);
}
static int filter(struct af_instance *af, struct mp_audio *in)
@@ -414,7 +429,7 @@ static int filter(struct af_instance *af, struct mp_audio *in)
int samples = get_out_samples(s, in ? in->samples : 0);
- struct mp_audio out_format = s->avrctx_fmt;
+ struct mp_audio out_format = s->pool_fmt;
struct mp_audio *out = mp_audio_pool_get(af->out_pool, &out_format, samples);
if (!out)
goto error;
@@ -427,9 +442,12 @@ static int filter(struct af_instance *af, struct mp_audio *in)
goto error;
}
+ struct mp_audio real_out = *out;
+ mp_audio_copy_config(out, &s->avrctx_fmt);
+
if (out->samples && !mp_audio_config_equals(out, af->data)) {
- assert(AF_FORMAT_IS_PLANAR(out->format));
- reorder_planes(out, s->reorder_out, &af->data->channels);
+ 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,
out->samples);