summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/decode/ad_lavc.c7
-rw-r--r--audio/decode/ad_spdif.c7
-rw-r--r--audio/filter/af_lavcac3enc.c180
-rw-r--r--audio/out/ao_alsa.c78
-rw-r--r--audio/out/ao_coreaudio.c5
-rw-r--r--audio/out/ao_coreaudio_utils.c27
-rw-r--r--audio/out/ao_coreaudio_utils.h1
-rw-r--r--audio/out/ao_lavc.c82
-rw-r--r--audio/out/ao_opensles.c1
-rw-r--r--audio/out/ao_oss.c2
-rw-r--r--audio/out/ao_wasapi.c4
-rw-r--r--audio/out/ao_wasapi_changenotify.c1
-rw-r--r--audio/out/push.c27
13 files changed, 282 insertions, 140 deletions
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index 8a6bb4061b..f48993f81f 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -45,6 +45,7 @@ struct priv {
uint32_t skip_samples, trim_samples;
bool preroll_done;
double next_pts;
+ bool needs_reset;
AVRational codec_timebase;
};
@@ -173,6 +174,7 @@ static int control(struct dec_audio *da, int cmd, void *arg)
ctx->trim_samples = 0;
ctx->preroll_done = false;
ctx->next_pts = MP_NOPTS_VALUE;
+ ctx->needs_reset = false;
return CONTROL_TRUE;
}
return CONTROL_UNKNOWN;
@@ -192,6 +194,9 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
int got_frame = 0;
av_frame_unref(priv->avframe);
+ if (priv->needs_reset)
+ control(da, ADCTRL_RESET, NULL);
+
#if HAVE_AVCODEC_NEW_CODEC_API
int ret = avcodec_send_packet(avctx, &pkt);
if (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
@@ -200,6 +205,8 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
ret = avcodec_receive_frame(avctx, priv->avframe);
if (ret >= 0)
got_frame = 1;
+ if (ret == AVERROR_EOF)
+ priv->needs_reset = true;
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
ret = 0;
}
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c
index eb2e2bb0a9..56e4a8102d 100644
--- a/audio/decode/ad_spdif.c
+++ b/audio/decode/ad_spdif.c
@@ -116,9 +116,16 @@ static int determine_codec_profile(struct dec_audio *da, AVPacket *pkt)
goto done;
}
+#if HAVE_AVCODEC_NEW_CODEC_API
+ if (avcodec_send_packet(ctx, pkt) < 0)
+ goto done;
+ if (avcodec_receive_frame(ctx, frame) < 0)
+ goto done;
+#else
int got_frame = 0;
if (avcodec_decode_audio4(ctx, frame, &got_frame, pkt) < 1 || !got_frame)
goto done;
+#endif
profile = ctx->profile;
diff --git a/audio/filter/af_lavcac3enc.c b/audio/filter/af_lavcac3enc.c
index 973e688aaa..26c9cbff58 100644
--- a/audio/filter/af_lavcac3enc.c
+++ b/audio/filter/af_lavcac3enc.c
@@ -31,9 +31,12 @@
#include <libavutil/bswap.h>
#include <libavutil/mem.h>
+#include "config.h"
+
#include "common/common.h"
#include "af.h"
#include "audio/audio_buffer.h"
+#include "audio/chmap_sel.h"
#include "audio/fmt-conversion.h"
@@ -54,13 +57,50 @@ typedef struct af_ac3enc_s {
struct mp_audio *pending; // unconsumed input data
int in_samples; // samples of input per AC3 frame
int out_samples; // upper bound on encoded output per AC3 frame
- int in_sampleformat;
int cfg_add_iec61937_header;
int cfg_bit_rate;
int cfg_min_channel_num;
+ char *cfg_encoder;
} af_ac3enc_t;
+// fmt carries the input format. Change it to the best next-possible format
+// the encoder likely accepts.
+static void select_encode_format(AVCodecContext *c, struct mp_audio *fmt)
+{
+ int formats[AF_FORMAT_COUNT];
+ af_get_best_sample_formats(fmt->format, formats);
+
+ for (int n = 0; formats[n]; n++) {
+ const enum AVSampleFormat *lf = c->codec->sample_fmts;
+ for (int i = 0; lf && lf[i] != AV_SAMPLE_FMT_NONE; i++) {
+ int mpfmt = af_from_avformat(lf[i]);
+ if (mpfmt && mpfmt == formats[n]) {
+ mp_audio_set_format(fmt, mpfmt);
+ goto done_fmt;
+ }
+ }
+ }
+done_fmt: ;
+
+ int rate =
+ af_select_best_samplerate(fmt->rate, c->codec->supported_samplerates);
+ if (rate > 0)
+ fmt->rate = rate;
+
+ struct mp_chmap_sel sel = {0};
+ const uint64_t *lch = c->codec->channel_layouts;
+ for (int n = 0; lch && lch[n]; n++) {
+ struct mp_chmap chmap = {0};
+ mp_chmap_from_lavc(&chmap, lch[n]);
+ mp_chmap_sel_add_map(&sel, &chmap);
+ }
+ struct mp_chmap res = fmt->channels;
+ mp_chmap_sel_adjust(&sel, &res);
+ if (!mp_chmap_is_empty(&res))
+ mp_audio_set_channels(fmt, &res);
+}
+
// Initialization and runtime control
static int control(struct af_instance *af, int cmd, void *arg)
{
@@ -76,23 +116,17 @@ static int control(struct af_instance *af, int cmd, void *arg)
if (!af_fmt_is_pcm(in->format) || in->nch < s->cfg_min_channel_num)
return AF_DETACH;
- mp_audio_set_format(in, s->in_sampleformat);
+ // At least currently, the AC3 encoder doesn't export sample rates.
+ in->rate = 48000;
+ select_encode_format(s->lavc_actx, in);
- if (in->rate != 48000 && in->rate != 44100 && in->rate != 32000)
- in->rate = 48000;
af->data->rate = in->rate;
-
- mp_chmap_reorder_to_lavc(&in->channels);
- if (in->nch > AC3_MAX_CHANNELS)
- mp_audio_set_num_channels(in, AC3_MAX_CHANNELS);
-
mp_audio_set_format(af->data, AF_FORMAT_S_AC3);
mp_audio_set_num_channels(af->data, 2);
if (!mp_audio_config_equals(in, &orig_in))
return AF_FALSE;
- s->in_samples = AC3_FRAME_SIZE;
if (s->cfg_add_iec61937_header) {
s->out_samples = AC3_FRAME_SIZE;
} else {
@@ -100,14 +134,11 @@ static int control(struct af_instance *af, int cmd, void *arg)
}
mp_audio_copy_config(s->input, in);
- mp_audio_realloc(s->input, s->in_samples);
- s->input->samples = 0;
talloc_free(s->pending);
s->pending = NULL;
- MP_DBG(af, "af_lavcac3enc reinit: %d, %d, %d.\n",
- in->nch, in->rate, s->in_samples);
+ MP_DBG(af, "reinit: %d, %d, %d.\n", in->nch, in->rate, s->in_samples);
int bit_rate = s->bit_rate ? s->bit_rate : default_bit_rate[in->nch];
@@ -118,6 +149,7 @@ static int control(struct af_instance *af, int cmd, void *arg)
avcodec_close(s->lavc_actx);
// Put sample parameters
+ s->lavc_actx->sample_fmt = af_to_avformat(in->format);
s->lavc_actx->channels = in->nch;
s->lavc_actx->channel_layout = mp_chmap_to_lavc(&in->channels);
s->lavc_actx->sample_rate = in->rate;
@@ -127,14 +159,24 @@ static int control(struct af_instance *af, int cmd, void *arg)
MP_ERR(af, "Couldn't open codec %s, br=%d.\n", "ac3", bit_rate);
return AF_ERROR;
}
+
+ if (s->lavc_actx->frame_size < 1) {
+ MP_ERR(af, "encoder didn't specify input frame size\n");
+ return AF_ERROR;
+ }
}
- if (s->lavc_actx->frame_size != AC3_FRAME_SIZE) {
- MP_ERR(af, "lavcac3enc: unexpected ac3 "
- "encoder frame size %d\n", s->lavc_actx->frame_size);
- return AF_ERROR;
- }
+ s->in_samples = s->lavc_actx->frame_size;
+ mp_audio_realloc(s->input, s->in_samples);
+ s->input->samples = 0;
return AF_OK;
}
+ case AF_CONTROL_RESET:
+ if (avcodec_is_open(s->lavc_actx))
+ avcodec_flush_buffers(s->lavc_actx);
+ talloc_free(s->pending);
+ s->pending = NULL;
+ s->input->samples = 0;
+ return AF_OK;
}
return AF_UNKNOWN;
}
@@ -199,31 +241,75 @@ static bool fill_buffer(struct af_instance *af)
return s->input->samples >= s->in_samples;
}
-static int filter_out(struct af_instance *af)
+// Return <0 on error, 0 on need more input, 1 on success (and *frame set).
+// To actually advance the read pointer, set s->input->samples=0 afterwards.
+static int read_input_frame(struct af_instance *af, AVFrame *frame)
{
af_ac3enc_t *s = af->priv;
if (!fill_buffer(af))
return 0; // need more input
- AVFrame *frame = av_frame_alloc();
- if (!frame) {
- MP_FATAL(af, "Could not allocate memory \n");
- return -1;
- }
- int err = -1;
-
frame->nb_samples = s->in_samples;
frame->format = s->lavc_actx->sample_fmt;
frame->channel_layout = s->lavc_actx->channel_layout;
+#if LIBAVUTIL_VERSION_MICRO >= 100
+ frame->channels = s->lavc_actx->channels;
+#endif
assert(s->input->num_planes <= AV_NUM_DATA_POINTERS);
frame->extended_data = frame->data;
for (int n = 0; n < s->input->num_planes; n++)
frame->data[n] = s->input->planes[n];
frame->linesize[0] = s->input->samples * s->input->sstride;
+ return 1;
+}
+
+static int filter_out(struct af_instance *af)
+{
+ af_ac3enc_t *s = af->priv;
+
+ AVFrame *frame = av_frame_alloc();
+ if (!frame) {
+ MP_FATAL(af, "Could not allocate memory \n");
+ return -1;
+ }
+ int err = -1;
+
AVPacket pkt = {0};
av_init_packet(&pkt);
+#if HAVE_AVCODEC_NEW_CODEC_API
+ // Send input as long as it wants.
+ while (1) {
+ err = read_input_frame(af, frame);
+ if (err < 0)
+ goto done;
+ if (err == 0)
+ break;
+ err = -1;
+ int lavc_ret = avcodec_send_frame(s->lavc_actx, frame);
+ // On EAGAIN, we're supposed to read remaining output.
+ if (lavc_ret == AVERROR(EAGAIN))
+ break;
+ if (lavc_ret < 0) {
+ MP_FATAL(af, "Encode failed.\n");
+ goto done;
+ }
+ s->input->samples = 0;
+ }
+ int lavc_ret = avcodec_receive_packet(s->lavc_actx, &pkt);
+ if (lavc_ret == AVERROR(EAGAIN)) {
+ // Need to buffer more input.
+ err = 0;
+ goto done;
+ }
+#else
+ err = read_input_frame(af, frame);
+ if (err < 0)
+ goto done;
+ if (err == 0)
+ goto done;
+ err = -1;
int ok;
int lavc_ret = avcodec_encode_audio2(s->lavc_actx, &pkt, frame, &ok);
av_frame_free(&frame);
@@ -232,9 +318,10 @@ static int filter_out(struct af_instance *af)
MP_FATAL(af, "Encode failed.\n");
goto done;
}
+#endif
MP_DBG(af, "avcodec_encode_audio got %d, pending %d.\n",
- pkt.size, s->pending->samples);
+ pkt.size, s->pending->samples);
struct mp_audio *out =
mp_audio_pool_get(af->out_pool, af->data, s->out_samples);
@@ -287,9 +374,9 @@ static int af_open(struct af_instance* af){
af->filter_frame = filter_frame;
af->filter_out = filter_out;
- s->lavc_acodec = avcodec_find_encoder_by_name("ac3");
+ s->lavc_acodec = avcodec_find_encoder_by_name(s->cfg_encoder);
if (!s->lavc_acodec) {
- MP_ERR(af, "Audio LAVC, couldn't find encoder for codec %s.\n", "ac3");
+ MP_ERR(af, "Couldn't find encoder %s.\n", s->cfg_encoder);
return AF_ERROR;
}
@@ -298,35 +385,30 @@ static int af_open(struct af_instance* af){
MP_ERR(af, "Audio LAVC, couldn't allocate context!\n");
return AF_ERROR;
}
- const enum AVSampleFormat *fmts = s->lavc_acodec->sample_fmts;
- for (int i = 0; fmts[i] != AV_SAMPLE_FMT_NONE; i++) {
- s->in_sampleformat = af_from_avformat(fmts[i]);
- if (s->in_sampleformat) {
- s->lavc_actx->sample_fmt = fmts[i];
- break;
- }
- }
- if (!s->in_sampleformat) {
- MP_ERR(af, "Audio LAVC, encoder doesn't "
- "support expected sample formats!\n");
+ // For this one, we require the decoder to expert lists of all supported
+ // parameters. (Not all decoders do that, but the ones we're interested
+ // in do.)
+ if (!s->lavc_acodec->sample_fmts ||
+ !s->lavc_acodec->channel_layouts)
+ {
+ MP_ERR(af, "Audio encoder doesn't list supported parameters.\n");
return AF_ERROR;
}
- MP_VERBOSE(af, "[af_lavcac3enc]: in sample format: %s\n",
- af_fmt_to_str(s->in_sampleformat));
s->input = talloc_zero(s, struct mp_audio);
if (s->cfg_bit_rate) {
int i;
for (i = 0; i < 19; i++) {
- if (ac3_bitrate_tab[i] == s->cfg_bit_rate)
+ if (ac3_bitrate_tab[i] == s->cfg_bit_rate) {
+ s->bit_rate = ac3_bitrate_tab[i] * 1000;
break;
+ }
}
if (i >= 19) {
- MP_WARN(af, "af_lavcac3enc unable set unsupported "
- "bitrate %d, use default bitrate (check manpage to see "
- "supported bitrates).\n", s->cfg_bit_rate);
- s->cfg_bit_rate = 0;
+ MP_WARN(af, "unable set unsupported bitrate %d, use default "
+ "bitrate (check manpage to see supported bitrates).\n",
+ s->cfg_bit_rate);
}
}
@@ -344,12 +426,14 @@ const struct af_info af_info_lavcac3enc = {
.cfg_add_iec61937_header = 1,
.cfg_bit_rate = 640,
.cfg_min_channel_num = 3,
+ .cfg_encoder = "ac3",
},
.options = (const struct m_option[]) {
OPT_FLAG("tospdif", cfg_add_iec61937_header, 0),
OPT_CHOICE_OR_INT("bitrate", cfg_bit_rate, 0, 32, 640,
({"auto", 0}, {"default", 0})),
OPT_INTRANGE("minch", cfg_min_channel_num, 0, 2, 6),
+ OPT_STRING("encoder", cfg_encoder, 0),
{0}
},
};
diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c
index 9ffd4792ee..d09f5fc499 100644
--- a/audio/out/ao_alsa.c
+++ b/audio/out/ao_alsa.c
@@ -58,6 +58,8 @@ struct priv {
snd_pcm_uframes_t buffersize;
snd_pcm_uframes_t outburst;
+ snd_output_t *output;
+
char *cfg_device;
char *cfg_mixer_device;
char *cfg_mixer_name;
@@ -477,6 +479,22 @@ static int set_chmap(struct ao *ao, struct mp_chmap *dev_chmap, int num_channels
#endif /* else HAVE_CHMAP_API */
+static void dump_hw_params(struct ao *ao, int msglevel, const char *msg,
+ snd_pcm_hw_params_t *hw_params)
+{
+ struct priv *p = ao->priv;
+ int err;
+
+ err = snd_pcm_hw_params_dump(hw_params, p->output);
+ CHECK_ALSA_WARN("Dump hwparams error");
+
+ char *tmp = NULL;
+ size_t tmp_s = snd_output_buffer_string(p->output, &tmp);
+ if (tmp)
+ mp_msg(ao->log, msglevel, "%s---\n%.*s---\n", msg, (int)tmp_s, tmp);
+ snd_output_flush(p->output);
+}
+
static int map_iec958_srate(int srate)
{
switch (srate) {
@@ -520,7 +538,7 @@ static char *append_params(void *ta_parent, const char *device, const char *p)
abort();
}
-static int try_open_device(struct ao *ao, const char *device)
+static int try_open_device(struct ao *ao, const char *device, int mode)
{
struct priv *p = ao->priv;
int err;
@@ -534,7 +552,7 @@ static int try_open_device(struct ao *ao, const char *device)
map_iec958_srate(ao->samplerate));
const char *ac3_device = append_params(tmp, device, params);
MP_VERBOSE(ao, "opening device '%s' => '%s'\n", device, ac3_device);
- err = snd_pcm_open(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, 0);
+ err = snd_pcm_open(&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, mode);
if (err < 0) {
// Some spdif-capable devices do not accept the AES0 parameter,
// and instead require the iec958 pseudo-device (they will play
@@ -547,13 +565,13 @@ static int try_open_device(struct ao *ao, const char *device)
MP_VERBOSE(ao, "got error %d; opening iec fallback device '%s'\n",
err, ac3_device);
err = snd_pcm_open
- (&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, 0);
+ (&p->alsa, ac3_device, SND_PCM_STREAM_PLAYBACK, mode);
}
}
talloc_free(tmp);
} else {
MP_VERBOSE(ao, "opening device '%s'\n", device);
- err = snd_pcm_open(&p->alsa, device, SND_PCM_STREAM_PLAYBACK, 0);
+ err = snd_pcm_open(&p->alsa, device, SND_PCM_STREAM_PLAYBACK, mode);
}
return err;
@@ -563,6 +581,10 @@ static void uninit(struct ao *ao)
{
struct priv *p = ao->priv;
+ if (p->output)
+ snd_output_close(p->output);
+ p->output = NULL;
+
if (p->alsa) {
int err;
@@ -574,20 +596,35 @@ static void uninit(struct ao *ao)
alsa_error: ;
}
-static int init_device(struct ao *ao)
+#define INIT_DEVICE_ERR_GENERIC -1
+#define INIT_DEVICE_ERR_HWPARAMS -2
+static int init_device(struct ao *ao, int mode)
{
struct priv *p = ao->priv;
+ int ret = INIT_DEVICE_ERR_GENERIC;
+ char *tmp;
+ size_t tmp_s;
int err;
+ err = snd_output_buffer_open(&p->output);
+ CHECK_ALSA_ERROR("Unable to create output buffer");
+
const char *device = "default";
if (ao->device)
device = ao->device;
if (p->cfg_device && p->cfg_device[0])
device = p->cfg_device;
- err = try_open_device(ao, device);
+ err = try_open_device(ao, device, mode);
CHECK_ALSA_ERROR("Playback open error");
+ err = snd_pcm_dump(p->alsa, p->output);
+ CHECK_ALSA_WARN("Dump PCM error");
+ tmp_s = snd_output_buffer_string(p->output, &tmp);
+ if (tmp)
+ MP_DBG(ao, "PCM setup:\n---\n%.*s---\n", (int)tmp_s, tmp);
+ snd_output_flush(p->output);
+
err = snd_pcm_nonblock(p->alsa, 0);
CHECK_ALSA_WARN("Unable to set blocking mode");
@@ -597,12 +634,15 @@ static int init_device(struct ao *ao)
err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams);
CHECK_ALSA_ERROR("Unable to get initial parameters");
+ dump_hw_params(ao, MSGL_DEBUG, "Start HW params:\n", alsa_hwparams);
+
// Some ALSA drivers have broken delay reporting, so disable the ALSA
// resampling plugin by default.
if (!p->cfg_resample) {
err = snd_pcm_hw_params_set_rate_resample(p->alsa, alsa_hwparams, 0);
CHECK_ALSA_ERROR("Unable to disable resampling");
}
+ dump_hw_params(ao, MSGL_DEBUG, "HW params after rate:\n", alsa_hwparams);
snd_pcm_access_t access = af_fmt_is_planar(ao->format)
? SND_PCM_ACCESS_RW_NONINTERLEAVED
@@ -614,6 +654,7 @@ static int init_device(struct ao *ao)
err = snd_pcm_hw_params_set_access(p->alsa, alsa_hwparams, access);
}
CHECK_ALSA_ERROR("Unable to set access type");
+ dump_hw_params(ao, MSGL_DEBUG, "HW params after access:\n", alsa_hwparams);
bool found_format = false;
int try_formats[AF_FORMAT_COUNT];
@@ -637,6 +678,7 @@ static int init_device(struct ao *ao)
err = snd_pcm_hw_params_set_format(p->alsa, alsa_hwparams, p->alsa_fmt);
CHECK_ALSA_ERROR("Unable to set format");
+ dump_hw_params(ao, MSGL_DEBUG, "HW params after format:\n", alsa_hwparams);
struct mp_chmap dev_chmap = ao->channels;
if (af_fmt_is_spdif(ao->format) || p->cfg_ignore_chmap) {
@@ -656,6 +698,7 @@ static int init_device(struct ao *ao)
err = snd_pcm_hw_params_set_channels_near
(p->alsa, alsa_hwparams, &num_channels);
CHECK_ALSA_ERROR("Unable to set channels");
+ dump_hw_params(ao, MSGL_DEBUG, "HW params after channels:\n", alsa_hwparams);
if (num_channels > MP_NUM_CHANNELS) {
MP_FATAL(ao, "Too many audio channels (%d).\n", num_channels);
@@ -665,6 +708,7 @@ static int init_device(struct ao *ao)
err = snd_pcm_hw_params_set_rate_near
(p->alsa, alsa_hwparams, &ao->samplerate, NULL);
CHECK_ALSA_ERROR("Unable to set samplerate-2");
+ dump_hw_params(ao, MSGL_DEBUG, "HW params after rate-2:\n", alsa_hwparams);
snd_pcm_hw_params_t *hwparams_backup;
snd_pcm_hw_params_alloca(&hwparams_backup);
@@ -682,9 +726,14 @@ static int init_device(struct ao *ao)
if (err < 0)
snd_pcm_hw_params_copy(alsa_hwparams, hwparams_backup);
+ dump_hw_params(ao, MSGL_V, "Going to set final HW params:\n", alsa_hwparams);
+
/* finally install hardware parameters */
err = snd_pcm_hw_params(p->alsa, alsa_hwparams);
+ ret = INIT_DEVICE_ERR_HWPARAMS;
CHECK_ALSA_ERROR("Unable to set hw-parameters");
+ ret = INIT_DEVICE_ERR_GENERIC;
+ dump_hw_params(ao, MSGL_DEBUG, "Final HW params:\n", alsa_hwparams);
if (set_chmap(ao, &dev_chmap, num_channels) < 0)
goto alsa_error;
@@ -740,7 +789,7 @@ static int init_device(struct ao *ao)
alsa_error:
uninit(ao);
- return -1;
+ return ret;
}
static int init(struct ao *ao)
@@ -751,7 +800,18 @@ static int init(struct ao *ao)
MP_VERBOSE(ao, "using ALSA version: %s\n", snd_asoundlib_version());
- int r = init_device(ao);
+ int mode = 0;
+ int r = init_device(ao, mode);
+ if (r == INIT_DEVICE_ERR_HWPARAMS) {
+ // With some drivers, ALSA appears to be unable to set valid hwparams,
+ // but they work if at least SND_PCM_NO_AUTO_FORMAT is set. Also, it
+ // appears you can set this flag only on opening a device, thus there
+ // is the need to retry opening the device.
+ MP_WARN(ao, "Attempting to work around even more ALSA bugs...\n");
+ mode |= SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT |
+ SND_PCM_NO_AUTO_RESAMPLE;
+ r = init_device(ao, mode);
+ }
// Sometimes, ALSA will advertise certain chmaps, but it's not possible to
// set them. This can happen with dmix: as of alsa 1.0.29, dmix can do
@@ -773,7 +833,7 @@ static int init(struct ao *ao)
MP_VERBOSE(ao, "Working around braindead dmix multichannel behavior.\n");
uninit(ao);
ao->channels = without_na;
- r = init_device(ao);
+ r = init_device(ao, mode);
}
}
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index 471ab6d928..b0a5dc0da1 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -133,11 +133,6 @@ static bool reinit_device(struct ao *ao) {
OSStatus err = ca_select_device(ao, ao->device, &p->device);
CHECK_CA_ERROR("failed to select device");
- char *uid;
- err = CA_GET_STR(p->device, kAudioDevicePropertyDeviceUID, &uid);
- CHECK_CA_ERROR("failed to get device UID");
- ao->detected_device = talloc_steal(ao, uid);
-
return true;
coreaudio_error:
diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c
index 6b5d8a7195..8f9690fc22 100644
--- a/audio/out/ao_coreaudio_utils.c
+++ b/audio/out/ao_coreaudio_utils.c
@@ -323,6 +323,9 @@ bool ca_stream_supports_compressed(struct ao *ao, AudioStreamID stream)
for (int i = 0; i < n_formats; i++) {
AudioStreamBasicDescription asbd = formats[i].mFormat;
+
+ ca_print_asbd(ao, "- ", &asbd);
+
if (ca_formatid_is_compressed(asbd.mFormatID)) {
talloc_free(formats);
return true;
@@ -334,30 +337,6 @@ coreaudio_error:
return false;
}
-bool ca_device_supports_compressed(struct ao *ao, AudioDeviceID device)
-{
- AudioStreamID *streams = NULL;
- size_t n_streams;
-
- /* Retrieve all the output streams. */
- OSStatus err =
- CA_GET_ARY_O(device, kAudioDevicePropertyStreams, &streams, &n_streams);
-
- CHECK_CA_ERROR("could not get number of streams.");
-
- for (int i = 0; i < n_streams; i++) {
- if (ca_stream_supports_compressed(ao, streams[i])) {
- talloc_free(streams);
- return true;
- }
- }
-
- talloc_free(streams);
-
-coreaudio_error:
- return false;
-}
-
OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid)
{
*pid = getpid();
diff --git a/audio/out/ao_coreaudio_utils.h b/audio/out/ao_coreaudio_utils.h
index 780c56864b..5cc7db53be 100644
--- a/audio/out/ao_coreaudio_utils.h
+++ b/audio/out/ao_coreaudio_utils.h
@@ -65,7 +65,6 @@ bool ca_asbd_is_better(AudioStreamBasicDescription *req,
int64_t ca_frames_to_us(struct ao *ao, uint32_t frames);
int64_t ca_get_latency(const AudioTimeStamp *ts);
-bool ca_device_supports_compressed(struct ao *ao, AudioDeviceID device);
bool ca_stream_supports_compressed(struct ao *ao, AudioStreamID stream);
OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid);
OSStatus ca_unlock_device(AudioDeviceID device, pid_t *pid);
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index bf1728682a..572874d27c 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -42,6 +42,7 @@ struct priv {
uint8_t *buffer;
size_t buffer_size;
AVStream *stream;
+ AVCodecContext *codec;
int pcmhack;
int aframesize;
int aframecount;
@@ -98,15 +99,14 @@ static int init(struct ao *ao)
pthread_mutex_lock(&ao->encode_lavc_ctx->lock);
- ac->stream = encode_lavc_alloc_stream(ao->encode_lavc_ctx,
- AVMEDIA_TYPE_AUDIO);
-
- if (!ac->stream) {
- MP_ERR(ao, "could not get a new audio stream\n");
- goto fail;
+ if (encode_lavc_alloc_stream(ao->encode_lavc_ctx,
+ AVMEDIA_TYPE_AUDIO,
+ &ac->stream, &ac->codec) < 0) {
+ MP_ERR(ao, "could not get a new audio stream\n");
+ goto fail;
}
- codec = encode_lavc_get_codec(ao->encode_lavc_ctx, ac->stream);
+ codec = ao->encode_lavc_ctx->ac;
int samplerate = af_select_best_samplerate(ao->samplerate,
codec->supported_samplerates);
@@ -118,40 +118,40 @@ static int init(struct ao *ao)
// Using codec->time_bvase is deprecated, but needed for older lavf.
ac->stream->time_base.num = 1;
ac->stream->time_base.den = ao->samplerate;
- ac->stream->codec->time_base.num = 1;
- ac->stream->codec->time_base.den = ao->samplerate;
+ ac->codec->time_base.num = 1;
+ ac->codec->time_base.den = ao->samplerate;
- ac->stream->codec->sample_rate = ao->samplerate;
+ ac->codec->sample_rate = ao->samplerate;
struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_any(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
goto fail;
mp_chmap_reorder_to_lavc(&ao->channels);
- ac->stream->codec->channels = ao->channels.num;
- ac->stream->codec->channel_layout = mp_chmap_to_lavc(&ao->channels);
+ ac->codec->channels = ao->channels.num;
+ ac->codec->channel_layout = mp_chmap_to_lavc(&ao->channels);
- ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE;
+ ac->codec->sample_fmt = AV_SAMPLE_FMT_NONE;
select_format(ao, codec);
ac->sample_size = af_fmt_to_bytes(ao->format);
- ac->stream->codec->sample_fmt = af_to_avformat(ao->format);
- ac->stream->codec->bits_per_raw_sample = ac->sample_size * 8;
+ ac->codec->sample_fmt = af_to_avformat(ao->format);
+ ac->codec->bits_per_raw_sample = ac->sample_size * 8;
- if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->stream) < 0)
+ if (encode_lavc_open_codec(ao->encode_lavc_ctx, ac->codec) < 0)
goto fail;
ac->pcmhack = 0;
- if (ac->stream->codec->frame_size <= 1)
- ac->pcmhack = av_get_bits_per_sample(ac->stream->codec->codec_id) / 8;
+ if (ac->codec->frame_size <= 1)
+ ac->pcmhack = av_get_bits_per_sample(ac->codec->codec_id) / 8;
if (ac->pcmhack) {
ac->aframesize = 16384; // "enough"
ac->buffer_size =
ac->aframesize * ac->pcmhack * ao->channels.num * 2 + 200;
} else {
- ac->aframesize = ac->stream->codec->frame_size;
+ ac->aframesize = ac->codec->frame_size;
ac->buffer_size =
ac->aframesize * ac->sample_size * ao->channels.num * 2 + 200;
}
@@ -203,7 +203,7 @@ static void uninit(struct ao *ao)
double outpts = ac->expected_next_pts;
if (!ectx->options->rawts && ectx->options->copyts)
outpts += ectx->discontinuity_pts_offset;
- outpts += encode_lavc_getoffset(ectx, ac->stream);
+ outpts += encode_lavc_getoffset(ectx, ac->codec);
while (encode(ao, outpts, NULL) > 0) ;
}
@@ -252,25 +252,25 @@ static int encode(struct ao *ao, double apts, void **data)
if (ectx->options->rawts || ectx->options->copyts) {
// real audio pts
- frame->pts = floor(apts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5);
+ frame->pts = floor(apts * ac->codec->time_base.den / ac->codec->time_base.num + 0.5);
} else {
// audio playback time
- frame->pts = floor(realapts * ac->stream->codec->time_base.den / ac->stream->codec->time_base.num + 0.5);
+ frame->pts = floor(realapts * ac->codec->time_base.den / ac->codec->time_base.num + 0.5);
}
- int64_t frame_pts = av_rescale_q(frame->pts, ac->stream->codec->time_base, ac->worst_time_base);
+ int64_t frame_pts = av_rescale_q(frame->pts, ac->codec->time_base, ac->worst_time_base);
if (ac->lastpts != AV_NOPTS_VALUE && frame_pts <= ac->lastpts) {
// this indicates broken video
// (video pts failing to increase fast enough to match audio)
MP_WARN(ao, "audio frame pts went backwards (%d <- %d), autofixed\n",
(int)frame->pts, (int)ac->lastpts);
frame_pts = ac->lastpts + 1;
- frame->pts = av_rescale_q(frame_pts, ac->worst_time_base, ac->stream->codec->time_base);
+ frame->pts = av_rescale_q(frame_pts, ac->worst_time_base, ac->codec->time_base);
}
ac->lastpts = frame_pts;
- frame->quality = ac->stream->codec->global_quality;
- status = avcodec_encode_audio2(ac->stream->codec, &packet, frame, &gotpacket);
+ frame->quality = ac->codec->global_quality;
+ status = avcodec_encode_audio2(ac->codec, &packet, frame, &gotpacket);
if (!status) {
if (ac->savepts == AV_NOPTS_VALUE)
@@ -281,7 +281,7 @@ static int encode(struct ao *ao, double apts, void **data)
}
else
{
- status = avcodec_encode_audio2(ac->stream->codec, &packet, NULL, &gotpacket);
+ status = avcodec_encode_audio2(ac->codec, &packet, NULL, &gotpacket);
}
if(status) {
@@ -295,7 +295,7 @@ static int encode(struct ao *ao, double apts, void **data)
MP_DBG(ao, "got pts %f (playback time: %f); out size: %d\n",
apts, realapts, packet.size);
- encode_lavc_write_stats(ao->encode_lavc_ctx, ac->stream);
+ encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec);
packet.stream_index = ac->stream->index;
@@ -307,20 +307,20 @@ static int encode(struct ao *ao, double apts, void **data)
}
if (packet.pts != AV_NOPTS_VALUE)
- packet.pts = av_rescale_q(packet.pts, ac->stream->codec->time_base,
+ packet.pts = av_rescale_q(packet.pts, ac->codec->time_base,
ac->stream->time_base);
if (packet.dts != AV_NOPTS_VALUE)
- packet.dts = av_rescale_q(packet.dts, ac->stream->codec->time_base,
+ packet.dts = av_rescale_q(packet.dts, ac->codec->time_base,
ac->stream->time_base);
if(packet.duration > 0)
- packet.duration = av_rescale_q(packet.duration, ac->stream->codec->time_base,
+ packet.duration = av_rescale_q(packet.duration, ac->codec->time_base,
ac->stream->time_base);
ac->savepts = AV_NOPTS_VALUE;
- if (encode_lavc_write_frame(ao->encode_lavc_ctx, &packet) < 0) {
+ if (encode_lavc_write_frame(ao->encode_lavc_ctx, ac->stream, &packet) < 0) {
MP_ERR(ao, "error writing at %f %f/%f\n",
realapts, (double) ac->stream->time_base.num,
(double) ac->stream->time_base.den);
@@ -377,22 +377,22 @@ static int play(struct ao *ao, void **data, int samples, int flags)
}
if (ac->worst_time_base.den == 0) {
- //if (ac->stream->codec->time_base.num / ac->stream->codec->time_base.den >= ac->stream->time_base.num / ac->stream->time_base.den)
- if (ac->stream->codec->time_base.num * (double) ac->stream->time_base.den >=
- ac->stream->time_base.num * (double) ac->stream->codec->time_base.den