summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-07-07 17:37:23 +0200
committerwm4 <wm4@nowhere>2017-07-07 17:56:18 +0200
commit4cb5e53ada84f73f29de0d15a7b67cd32631536a (patch)
treeffe63150d1130cad59ea2162901a54b448c84977
parent90dd2298713d3414bad39b6e8648490cd9f52603 (diff)
downloadmpv-4cb5e53ada84f73f29de0d15a7b67cd32631536a.tar.bz2
mpv-4cb5e53ada84f73f29de0d15a7b67cd32631536a.tar.xz
ao_alsa: drop use of AF_FORMAT_S24
Instead of the infrastructure added in the previous commit to do the conversion within the AO. If this is used, and snd_pcm_status_get_avail() returns more frames than snd_pcm_write*() actually accepts, you will get some nice audio corruption. Also, this mutates the data passed via play(), which is rather fishy, but sort of doesn't matter for now. Surely this will cause unintended bugs and WTFs.
-rw-r--r--audio/out/ao_alsa.c77
1 files changed, 56 insertions, 21 deletions
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index b0099011dc..900cbafd03 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -91,6 +91,8 @@ struct priv {
snd_output_t *output;
+ struct ao_convert_fmt convert;
+
struct ao_alsa_opts *opts;
};
@@ -246,28 +248,36 @@ alsa_error:
return CONTROL_ERROR;
}
-static const int mp_to_alsa_format[][2] = {
+struct alsa_fmt {
+ int mp_format;
+ int alsa_format;
+ int bits; // alsa format full sample size (optional)
+ int pad_msb; // how many MSB bits are 0 (optional)
+};
+
+// Entries that have the same mp_format must be:
+// 1. consecutive
+// 2. sorted by preferred format (worst comes last)
+static const struct alsa_fmt mp_alsa_formats[] = {
{AF_FORMAT_U8, SND_PCM_FORMAT_U8},
{AF_FORMAT_S16, SND_PCM_FORMAT_S16},
{AF_FORMAT_S32, SND_PCM_FORMAT_S32},
- {AF_FORMAT_S24,
- MP_SELECT_LE_BE(SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S24_3BE)},
+ {AF_FORMAT_S32, SND_PCM_FORMAT_S24, .bits = 32, .pad_msb = 8},
+ {AF_FORMAT_S32,
+ MP_SELECT_LE_BE(SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_S24_3BE),
+ .bits = 24, .pad_msb = 0},
{AF_FORMAT_FLOAT, SND_PCM_FORMAT_FLOAT},
{AF_FORMAT_DOUBLE, SND_PCM_FORMAT_FLOAT64},
- {AF_FORMAT_S_MP3, SND_PCM_FORMAT_MPEG},
- {AF_FORMAT_UNKNOWN, SND_PCM_FORMAT_UNKNOWN},
+ {0},
};
-static int find_alsa_format(int af_format)
+static const struct alsa_fmt *find_alsa_format(int mp_format)
{
- af_format = af_fmt_from_planar(af_format);
- for (int n = 0; mp_to_alsa_format[n][0] != AF_FORMAT_UNKNOWN; n++) {
- if (mp_to_alsa_format[n][0] == af_format)
- return mp_to_alsa_format[n][1];
+ for (int n = 0; mp_alsa_formats[n].mp_format; n++) {
+ if (mp_alsa_formats[n].mp_format == mp_format)
+ return &mp_alsa_formats[n];
}
- if (af_fmt_is_spdif(af_format))
- return SND_PCM_FORMAT_S16;
- return SND_PCM_FORMAT_UNKNOWN;
+ return NULL;
}
#if HAVE_CHMAP_API
@@ -648,6 +658,8 @@ static int init_device(struct ao *ao, int mode)
size_t tmp_s;
int err;
+ p->alsa_fmt = SND_PCM_FORMAT_UNKNOWN;
+
err = snd_output_buffer_open(&p->output);
CHECK_ALSA_ERROR("Unable to create output buffer");
@@ -699,15 +711,34 @@ static int init_device(struct ao *ao, int mode)
bool found_format = false;
int try_formats[AF_FORMAT_COUNT];
af_get_best_sample_formats(ao->format, try_formats);
- for (int n = 0; try_formats[n]; n++) {
- if (af_fmt_is_planar(ao->format) != af_fmt_is_planar(try_formats[n]))
+ for (int n = 0; try_formats[n] && !found_format; n++) {
+ int mp_format = try_formats[n];
+ if (af_fmt_is_planar(ao->format) != af_fmt_is_planar(mp_format))
continue; // implied SND_PCM_ACCESS mismatches
- p->alsa_fmt = find_alsa_format(try_formats[n]);
- MP_VERBOSE(ao, "trying format %s\n", af_fmt_to_str(try_formats[n]));
- if (snd_pcm_hw_params_test_format(p->alsa, alsa_hwparams, p->alsa_fmt) >= 0) {
- ao->format = try_formats[n];
- found_format = true;
- break;
+ int mp_pformat = af_fmt_from_planar(mp_format);
+ if (af_fmt_is_spdif(mp_pformat))
+ mp_pformat = AF_FORMAT_S16;
+ const struct alsa_fmt *fmt = find_alsa_format(mp_pformat);
+ if (!fmt)
+ continue;
+ for (; fmt->mp_format == mp_pformat; fmt++) {
+ p->alsa_fmt = fmt->alsa_format;
+ p->convert = (struct ao_convert_fmt){
+ .src_fmt = mp_format,
+ .dst_bits = fmt->bits ? fmt->bits : af_fmt_to_bytes(mp_format) * 8,
+ .pad_msb = fmt->pad_msb,
+ };
+ if (!ao_can_convert_inplace(&p->convert))
+ continue;
+ MP_VERBOSE(ao, "trying format %s/%d\n", af_fmt_to_str(mp_pformat),
+ p->alsa_fmt);
+ if (snd_pcm_hw_params_test_format(p->alsa, alsa_hwparams,
+ p->alsa_fmt) >= 0)
+ {
+ ao->format = mp_format;
+ found_format = true;
+ break;
+ }
}
}
@@ -842,6 +873,8 @@ static int init_device(struct ao *ao, int mode)
ao->device_buffer = p->buffersize;
ao->period_size = p->outburst;
+ p->convert.channels = ao->channels.num;
+
return 0;
alsa_error:
@@ -1067,6 +1100,8 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return 0;
do {
+ ao_convert_inplace(&p->convert, data, samples);
+
if (af_fmt_is_planar(ao->format)) {
res = snd_pcm_writen(p->alsa, data, samples);
} else {