summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
authorMartin Herkt <lachs0r@srsfckn.biz>2016-07-10 01:06:17 +0200
committerMartin Herkt <lachs0r@srsfckn.biz>2016-07-10 01:06:17 +0200
commit76354385929b76b02b8c32a7b1cd4d669a8f2e0a (patch)
tree738a432ac5648098cf93101bf64a010cff47486a /audio
parent69e7b0d3ea4b75a8040ede5b9b7e6fa93ec68056 (diff)
parente518bf2c72fc862fbe1de1c98313a03fa0db2e98 (diff)
downloadmpv-76354385929b76b02b8c32a7b1cd4d669a8f2e0a.tar.bz2
mpv-76354385929b76b02b8c32a7b1cd4d669a8f2e0a.tar.xz
Merge branch 'master' into release/current
Diffstat (limited to 'audio')
-rw-r--r--audio/audio.c12
-rw-r--r--audio/audio.h1
-rw-r--r--audio/decode/ad_lavc.c6
-rw-r--r--audio/decode/dec_audio.c9
-rw-r--r--audio/filter/af.c39
-rw-r--r--audio/mixer.c277
-rw-r--r--audio/mixer.h11
-rw-r--r--audio/out/ao.c5
-rw-r--r--audio/out/ao_coreaudio_utils.c7
-rw-r--r--audio/out/ao_lavc.c197
-rw-r--r--audio/out/ao_oss.c7
-rw-r--r--audio/out/ao_wasapi.c2
-rw-r--r--audio/out/ao_wasapi_changenotify.c2
13 files changed, 181 insertions, 394 deletions
diff --git a/audio/audio.c b/audio/audio.c
index ae85a4bf08..306401b5a4 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -257,13 +257,21 @@ void mp_audio_skip_samples(struct mp_audio *data, int samples)
data->pts += samples / (double)data->rate;
}
+// Return the timestamp of the sample just after the end of this frame.
+double mp_audio_end_pts(struct mp_audio *f)
+{
+ if (f->pts == MP_NOPTS_VALUE || f->rate < 1)
+ return MP_NOPTS_VALUE;
+ return f->pts + f->samples / (double)f->rate;
+}
+
// Clip the given frame to the given timestamp range. Adjusts the frame size
// and timestamp.
void mp_audio_clip_timestamps(struct mp_audio *f, double start, double end)
{
- if (f->pts == MP_NOPTS_VALUE || f->rate < 1)
+ double f_end = mp_audio_end_pts(f);
+ if (f_end == MP_NOPTS_VALUE)
return;
- double f_end = f->pts + f->samples / (double)f->rate;
if (end != MP_NOPTS_VALUE) {
if (f_end >= end) {
if (f->pts >= end) {
diff --git a/audio/audio.h b/audio/audio.h
index c469f7a21e..e126e93b66 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -73,6 +73,7 @@ void mp_audio_copy(struct mp_audio *dst, int dst_offset,
void mp_audio_copy_attributes(struct mp_audio *dst, struct mp_audio *src);
void mp_audio_skip_samples(struct mp_audio *data, int samples);
void mp_audio_clip_timestamps(struct mp_audio *f, double start, double end);
+double mp_audio_end_pts(struct mp_audio *data);
bool mp_audio_is_writeable(struct mp_audio *data);
int mp_audio_make_writeable(struct mp_audio *data);
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index f48993f81f..0316f6b7d1 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -186,6 +186,12 @@ static int decode_packet(struct dec_audio *da, struct demux_packet *mpkt,
struct priv *priv = da->priv;
AVCodecContext *avctx = priv->avctx;
+ // If the decoder discards the timestamp for some reason, we use the
+ // interpolated PTS. Initialize it so that it works for the initial
+ // packet as well.
+ if (mpkt && priv->next_pts == MP_NOPTS_VALUE)
+ priv->next_pts = mpkt->pts;
+
int in_len = mpkt ? mpkt->len : 0;
AVPacket pkt;
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index e60ebe370f..d455770a74 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -200,7 +200,9 @@ void audio_work(struct dec_audio *da)
if (da->current_frame)
return;
- if (!da->packet && demux_read_packet_async(da->header, &da->packet) == 0) {
+ if (!da->packet && !da->new_segment &&
+ demux_read_packet_async(da->header, &da->packet) == 0)
+ {
da->current_state = DATA_WAIT;
return;
}
@@ -211,6 +213,7 @@ void audio_work(struct dec_audio *da)
da->packet = NULL;
}
+ bool had_input_packet = !!da->packet;
bool had_packet = da->packet || da->new_segment;
int ret = da->ad_driver->decode_packet(da, da->packet, &da->current_frame);
@@ -233,12 +236,12 @@ void audio_work(struct dec_audio *da)
fix_audio_pts(da);
- bool segment_end = true;
+ bool segment_end = !da->current_frame && !had_input_packet;
if (da->current_frame) {
mp_audio_clip_timestamps(da->current_frame, da->start, da->end);
if (da->current_frame->pts != MP_NOPTS_VALUE && da->start != MP_NOPTS_VALUE)
- segment_end = da->current_frame->pts >= da->start;
+ segment_end = da->current_frame->pts >= da->end;
if (da->current_frame->samples == 0) {
talloc_free(da->current_frame);
da->current_frame = NULL;
diff --git a/audio/filter/af.c b/audio/filter/af.c
index ac1b4926d8..21b0982692 100644
--- a/audio/filter/af.c
+++ b/audio/filter/af.c
@@ -210,29 +210,6 @@ static struct af_instance *af_prepend(struct af_stream *s,
return new;
}
-/* Create and insert a new filter of type name after the filter in the
- argument. This function can be called during runtime, the return
- value is the new filter */
-static struct af_instance *af_append(struct af_stream *s,
- struct af_instance *af,
- char *name, char **args)
-{
- if (!af)
- af = s->first;
- if (af == s->last)
- af = s->last->prev;
- // Create the new filter and make sure it is OK
- struct af_instance *new = af_create(s, name, args);
- if (!new)
- return NULL;
- // Update pointers
- new->prev = af;
- new->next = af->next;
- af->next = new;
- new->next->prev = new;
- return new;
-}
-
// Uninit and remove the filter "af"
static void af_remove(struct af_stream *s, struct af_instance *af)
{
@@ -275,6 +252,8 @@ static void af_print_filter_chain(struct af_stream *s, struct af_instance *at,
while (af) {
char b[128] = {0};
mp_snprintf_cat(b, sizeof(b), " [%s] ", af->info->name);
+ if (af->label)
+ mp_snprintf_cat(b, sizeof(b), "\"%s\" ", af->label);
if (af->data)
mp_snprintf_cat(b, sizeof(b), "%s", mp_audio_config_to_str(af->data));
if (af == at)
@@ -287,11 +266,6 @@ static void af_print_filter_chain(struct af_stream *s, struct af_instance *at,
MP_MSG(s, msg_level, " [ao] %s\n", mp_audio_config_to_str(&s->output));
}
-static bool af_is_conversion_filter(struct af_instance *af)
-{
- return af && strcmp(af->info->name, "lavrresample") == 0;
-}
-
// in is what af can take as input - insert a conversion filter if the actual
// input format doesn't match what af expects.
// Returns:
@@ -557,7 +531,7 @@ void af_destroy(struct af_stream *s)
format of the preferred output respectively. The function is
reentrant i.e. if called with an already initialized stream the
stream will be reinitialized.
- If one of the prefered output parameters is 0 the one that needs
+ If one of the preferred output parameters is 0 the one that needs
no conversion is used (i.e. the output format in the last filter).
The return value is 0 if success and -1 if failure */
int af_init(struct af_stream *s)
@@ -602,12 +576,7 @@ struct af_instance *af_add(struct af_stream *s, char *name, char *label,
if (af_find_by_label(s, label))
return NULL;
- struct af_instance *new;
- // Insert the filter somewhere nice
- if (af_is_conversion_filter(s->first->next))
- new = af_append(s, s->first->next, name, args);
- else
- new = af_prepend(s, s->first->next, name, args);
+ struct af_instance *new = af_prepend(s, s->last, name, args);
if (!new)
return NULL;
new->label = talloc_strdup(new, label);
diff --git a/audio/mixer.c b/audio/mixer.c
index 01bb4d5088..a58a814649 100644
--- a/audio/mixer.c
+++ b/audio/mixer.c
@@ -35,18 +35,6 @@ struct mixer {
struct MPOpts *opts;
struct ao *ao;
struct af_stream *af;
- // Static, dependent on ao/softvol settings
- bool softvol; // use AO (false) or af_volume (true)
- bool persistent_volume; // volume does not need to be restored
- bool emulate_mute; // if true, emulate mute with volume=0
- // Last known values (possibly out of sync with reality)
- float vol_l, vol_r;
- bool muted;
- // Used to decide whether we should unmute on uninit
- bool muted_by_us;
- /* Contains ao driver name or "softvol" if volume is not persistent
- * and needs to be restored after the driver is reinitialized. */
- const char *driver;
// Other stuff
float balance;
};
@@ -57,82 +45,25 @@ struct mixer *mixer_init(void *talloc_ctx, struct mpv_global *global)
*mixer = (struct mixer) {
.log = mp_log_new(mixer, global->log, "mixer"),
.opts = global->opts,
- .vol_l = 100,
- .vol_r = 100,
- .driver = "",
};
return mixer;
}
bool mixer_audio_initialized(struct mixer *mixer)
{
- return !!mixer->ao;
+ return !!mixer->af;
}
-float mixer_getmaxvolume(struct mixer *mixer)
+// Called when opts->softvol_volume or opts->softvol_mute were changed.
+void mixer_update_volume(struct mixer *mixer)
{
- // gain == 1
- return mixer->softvol ? mixer->opts->softvol_max : 100;
-}
-
-static void checkvolume(struct mixer *mixer)
-{
- if (!mixer->ao)
+ if (!mixer->af)
return;
- ao_control_vol_t vol = {mixer->vol_l, mixer->vol_r};
- if (mixer->softvol) {
- float gain;
- if (!af_control_any_rev(mixer->af, AF_CONTROL_GET_VOLUME, &gain))
- gain = 1.0;
- vol.left = gain * 100.0;
- vol.right = gain * 100.0;
- } else {
- MP_DBG(mixer, "Reading volume from AO.\n");
- // Rely on the values not changing if the query is not supported
- ao_control(mixer->ao, AOCONTROL_GET_VOLUME, &vol);
- ao_control(mixer->ao, AOCONTROL_GET_MUTE, &mixer->muted);
- }
- float l = mixer->vol_l;
- float r = mixer->vol_r;
- if (mixer->emulate_mute && mixer->muted)
- l = r = 0;
- /* Try to detect cases where the volume has been changed by some external
- * action (such as something else changing a shared system-wide volume).
- * We don't test for exact equality, as some AOs may round the value
- * we last set to some nearby supported value. 3 has been the default
- * volume step for increase/decrease keys, and is apparently big enough
- * to step to the next possible value in most setups.
- */
- if (FFABS(vol.left - l) >= 3 || FFABS(vol.right - r) >= 3) {
- mixer->vol_l = vol.left;
- mixer->vol_r = vol.right;
- if (mixer->emulate_mute)
- mixer->muted = false;
- }
- mixer->muted_by_us &= mixer->muted;
-}
+ float gain = MPMAX(mixer->opts->softvol_volume / 100.0, 0);
+ if (mixer->opts->softvol_mute == 1)
+ gain = 0.0;
-void mixer_getvolume(struct mixer *mixer, float *l, float *r)
-{
- checkvolume(mixer);
- *l = mixer->vol_l;
- *r = mixer->vol_r;
-}
-
-static void setvolume_internal(struct mixer *mixer)
-{
- float l = mixer->vol_l, r = mixer->vol_r;
- if (mixer->emulate_mute && mixer->muted)
- l = r = 0;
- if (!mixer->softvol) {
- MP_DBG(mixer, "Setting volume on AO.\n");
- struct ao_control_vol vol = {.left = l, .right = r};
- if (ao_control(mixer->ao, AOCONTROL_SET_VOLUME, &vol) != CONTROL_OK)
- MP_ERR(mixer, "Failed to change audio output volume.\n");
- return;
- }
- float gain = (l + r) / 2.0 / 100.0;
if (!af_control_any_rev(mixer->af, AF_CONTROL_SET_VOLUME, &gain)) {
if (gain == 1.0)
return;
@@ -143,57 +74,6 @@ static void setvolume_internal(struct mixer *mixer)
}
}
-void mixer_setvolume(struct mixer *mixer, float l, float r)
-{
- checkvolume(mixer); // to check mute status
-
- float max = mixer_getmaxvolume(mixer);
- mixer->vol_l = MPCLAMP(l, 0, max);
- mixer->vol_r = MPCLAMP(r, 0, max);
- if (mixer->ao)
- setvolume_internal(mixer);
-}
-
-void mixer_getbothvolume(struct mixer *mixer, float *b)
-{
- float mixer_l, mixer_r;
- mixer_getvolume(mixer, &mixer_l, &mixer_r);
- *b = (mixer_l + mixer_r) / 2;
-}
-
-void mixer_setmute(struct mixer *mixer, bool mute)
-{
- checkvolume(mixer);
- if (mute == mixer->muted)
- return;
- if (mixer->ao) {
- mixer->muted = mute;
- mixer->muted_by_us = mute;
- if (mixer->emulate_mute) {
- setvolume_internal(mixer);
- } else {
- ao_control(mixer->ao, AOCONTROL_SET_MUTE, &mute);
- }
- checkvolume(mixer);
- } else {
- mixer->muted = mute;
- mixer->muted_by_us = mute;
- }
-}
-
-bool mixer_getmute(struct mixer *mixer)
-{
- checkvolume(mixer);
- return mixer->muted;
-}
-
-void mixer_addvolume(struct mixer *mixer, float step)
-{
- float vol_l, vol_r;
- mixer_getvolume(mixer, &vol_l, &vol_r);
- mixer_setvolume(mixer, vol_l + step, vol_r + step);
-}
-
void mixer_getbalance(struct mixer *mixer, float *val)
{
if (mixer->af)
@@ -242,130 +122,18 @@ void mixer_setbalance(struct mixer *mixer, float val)
af_pan_balance->control(af_pan_balance, AF_CONTROL_SET_PAN_BALANCE, &val);
}
-char *mixer_get_volume_restore_data(struct mixer *mixer)
-{
- if (!mixer->driver[0])
- return NULL;
- return talloc_asprintf(NULL, "%s:%f:%f:%d", mixer->driver, mixer->vol_l,
- mixer->vol_r, mixer->muted_by_us);
-}
-
-static void probe_softvol(struct mixer *mixer)
-{
- bool ao_perapp = ao_control(mixer->ao, AOCONTROL_HAS_PER_APP_VOLUME, 0) == 1;
- bool ao_softvol = ao_control(mixer->ao, AOCONTROL_HAS_SOFT_VOLUME, 0) == 1;
- assert(!(ao_perapp && ao_softvol));
- mixer->persistent_volume = !ao_softvol;
-
- if (mixer->opts->softvol == SOFTVOL_AUTO) {
- // No system-wide volume => fine with AO volume control.
- mixer->softvol = !ao_softvol && !ao_perapp;
- } else {
- mixer->softvol = mixer->opts->softvol == SOFTVOL_YES;
- }
-
- if (mixer->softvol)
- mixer->persistent_volume = false;
-
- MP_DBG(mixer, "Will use af_volume: %s\n", mixer->softvol ? "yes" : "no");
-
- // If we can't use real volume control => force softvol.
- if (!mixer->softvol) {
- ao_control_vol_t vol;
- if (ao_control(mixer->ao, AOCONTROL_GET_VOLUME, &vol) != CONTROL_OK) {
- mixer->softvol = true;
- MP_WARN(mixer, "Hardware volume control unavailable.\n");
- }
- }
-
- // Probe native mute support.
- mixer->emulate_mute = true;
- if (!mixer->softvol) {
- if (ao_control(mixer->ao, AOCONTROL_GET_MUTE, &(bool){0}) == CONTROL_OK)
- mixer->emulate_mute = false;
- }
-}
-
-static void restore_volume(struct mixer *mixer)
-{
- struct MPOpts *opts = mixer->opts;
- struct ao *ao = mixer->ao;
-
- float force_vol_l = -1, force_vol_r = -1;
- int force_mute = -1;
-
- const char *prev_driver = mixer->driver;
- mixer->driver = mixer->softvol ? "softvol" : ao_get_name(ao);
- if (!prev_driver[0])
- prev_driver = mixer->driver;
-
- // Restore old parameters if volume won't survive reinitialization.
- // But not if volume scale is possibly different.
- if (!mixer->persistent_volume && strcmp(mixer->driver, prev_driver) == 0) {
- force_vol_l = mixer->vol_l;
- force_vol_r = mixer->vol_r;
- }
-
- // Set mute if we disabled it on uninit last time.
- if (mixer->muted_by_us)
- force_mute = 1;
-
- // Set parameters from command line.
- if (opts->mixer_init_volume >= 0)
- force_vol_l = force_vol_r = opts->mixer_init_volume;
- if (opts->mixer_init_mute >= 0)
- force_mute = opts->mixer_init_mute;
-
- // Set parameters from playback resume.
- char *data = mixer->opts->mixer_restore_volume_data;
- if (!mixer->persistent_volume && data && data[0]) {
- char drv[40];
- float v_l, v_r;
- int m;
- if (sscanf(data, "%39[^:]:%f:%f:%d", drv, &v_l, &v_r, &m) == 4) {
- if (strcmp(mixer->driver, drv) == 0) {
- force_vol_l = v_l;
- force_vol_r = v_r;
- force_mute = !!m;
- MP_DBG(mixer, "Restoring volume from resume config.\n");
- }
- }
- talloc_free(mixer->opts->mixer_restore_volume_data);
- mixer->opts->mixer_restore_volume_data = NULL;
- }
-
- // Using --volume should not reset the volume on every file (i.e. reinit),
- // OTOH mpv --{ --volume 10 f1.mkv --} --{ --volume 20 f2.mkv --} must work.
- // Resetting the option volumes to "auto" (-1) is easiest. If file local
- // options (as shown above) are used, the option handler code will reset
- // them to other values, and force the volume to be reset as well.
- opts->mixer_init_volume = -1;
- opts->mixer_init_mute = -1;
-
- checkvolume(mixer);
- if (force_vol_l >= 0 && force_vol_r >= 0) {
- MP_DBG(mixer, "Restoring previous volume.\n");
- mixer_setvolume(mixer, force_vol_l, force_vol_r);
- }
- if (force_mute >= 0) {
- MP_DBG(mixer, "Restoring previous mute toggle.\n");
- mixer_setmute(mixer, force_mute);
- }
-}
-
// Called after the audio filter chain is built or rebuilt.
// (Can be called multiple times, even without mixer_uninit() in-between.)
-void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af)
+void mixer_reinit_audio(struct mixer *mixer, struct af_stream *af)
{
- if (!ao || !af)
- return;
- mixer->ao = ao;
mixer->af = af;
+ if (!af)
+ return;
- MP_DBG(mixer, "Reinit...\n");
+ if (mixer->opts->softvol == SOFTVOL_NO)
+ MP_ERR(mixer, "--softvol=no is not supported anymore.\n");
- probe_softvol(mixer);
- restore_volume(mixer);
+ mixer_update_volume(mixer);
if (mixer->balance != 0)
mixer_setbalance(mixer, mixer->balance);
@@ -380,24 +148,5 @@ void mixer_uninit_audio(struct mixer *mixer)
if (!mixer->ao)
return;
- MP_DBG(mixer, "Uninit...\n");
-
- checkvolume(mixer);
- if (mixer->muted_by_us && mixer->persistent_volume) {
- MP_DBG(mixer, "Draining.\n");
- /* Current audio output API combines playing the remaining buffered
- * audio and uninitializing the AO into one operation, even though
- * ideally unmute would happen between those two steps. We can't do
- * volume changes after uninitialization, but we don't want the
- * remaining audio to play at full volume either. Thus this
- * workaround to drop remaining audio first. */
- ao_reset(mixer->ao);
- mixer_setmute(mixer, false);
- /* We remember mute status and re-enable it if we play more audio
- * in the same process. */
- mixer->muted_by_us = true;
- }
- mixer->ao = NULL;
mixer->af = NULL;
- mixer->softvol = false;
}
diff --git a/audio/mixer.h b/audio/mixer.h
index 4e2ff350ff..b475c12700 100644
--- a/audio/mixer.h
+++ b/audio/mixer.h
@@ -33,18 +33,11 @@ struct af_stream;
struct mixer;
struct mixer *mixer_init(void *talloc_ctx, struct mpv_global *global);
-void mixer_reinit_audio(struct mixer *mixer, struct ao *ao, struct af_stream *af);
+void mixer_reinit_audio(struct mixer *mixer, struct af_stream *af);
void mixer_uninit_audio(struct mixer *mixer);
bool mixer_audio_initialized(struct mixer *mixer);
-void mixer_getvolume(struct mixer *mixer, float *l, float *r);
-void mixer_setvolume(struct mixer *mixer, float l, float r);
-void mixer_addvolume(struct mixer *mixer, float step);
-void mixer_getbothvolume(struct mixer *mixer, float *b);
-void mixer_setmute(struct mixer *mixer, bool mute);
-bool mixer_getmute(struct mixer *mixer);
+void mixer_update_volume(struct mixer *mixer);
void mixer_getbalance(struct mixer *mixer, float *bal);
void mixer_setbalance(struct mixer *mixer, float bal);
-float mixer_getmaxvolume(struct mixer *mixer);
-char *mixer_get_volume_restore_data(struct mixer *mixer);
#endif /* MPLAYER_MIXER_H */
diff --git a/audio/out/ao.c b/audio/out/ao.c
index 9c0f644c75..c9d8f42b4a 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -490,10 +490,9 @@ struct ao_hotplug *ao_hotplug_create(struct mpv_global *global,
static void get_devices(struct ao *ao, struct ao_device_list *list)
{
int num = list->num_devices;
- if (ao->driver->list_devs)
+ if (ao->driver->list_devs) {
ao->driver->list_devs(ao, list);
- // Add at least a default entry
- if (list->num_devices == num) {
+ } else {
char name[80] = "Default";
if (num > 1)
mp_snprintf_cat(name, sizeof(name), " (%s)", ao->driver->name);
diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c
index 8f9690fc22..0bcc0d62a1 100644
--- a/audio/out/ao_coreaudio_utils.c
+++ b/audio/out/ao_coreaudio_utils.c
@@ -114,6 +114,13 @@ OSStatus ca_select_device(struct ao *ao, char* name, AudioDeviceID *device)
kAudioObjectSystemObject, &p_addr, 0, 0, &size, &v);
CFRelease(uid);
CHECK_CA_ERROR("unable to query for device UID");
+
+ uint32_t is_alive = 1;
+ err = CA_GET(*device, kAudioDevicePropertyDeviceIsAlive, &is_alive);
+ CHECK_CA_ERROR("could not check whether device is alive (invalid device?)");
+
+ if (!is_alive)
+ MP_WARN(ao, "device is not alive!\n");
} else {
// device not set by user, get the default one
err = CA_GET(kAudioObjectSystemObject,
diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c
index 572874d27c..6b4279ca87 100644
--- a/audio/out/ao_lavc.c
+++ b/audio/out/ao_lavc.c
@@ -39,8 +39,6 @@
#include "common/encode_lavc.h"
struct priv {
- uint8_t *buffer;
- size_t buffer_size;
AVStream *stream;
AVCodecContext *codec;
int pcmhack;
@@ -146,18 +144,10 @@ static int init(struct ao *ao)
if (ac->codec->frame_size <= 1)
ac->pcmhack = av_get_bits_per_sample(ac->codec->codec_id) / 8;
- if (ac->pcmhack) {
+ if (ac->pcmhack)
ac->aframesize = 16384; // "enough"
- ac->buffer_size =
- ac->aframesize * ac->pcmhack * ao->channels.num * 2 + 200;
- } else {
+ else
ac->aframesize = ac->codec->frame_size;
- ac->buffer_size =
- ac->aframesize * ac->sample_size * ao->channels.num * 2 + 200;
- }
- if (ac->buffer_size < FF_MIN_BUFFER_SIZE)
- ac->buffer_size = FF_MIN_BUFFER_SIZE;
- ac->buffer = talloc_size(ac, ac->buffer_size);
// enough frames for at least 0.25 seconds
ac->framecount = ceil(ao->samplerate * 0.25 / ac->aframesize);
@@ -182,7 +172,7 @@ fail:
}
// close audio device
-static int encode(struct ao *ao, double apts, void **data);
+static void encode(struct ao *ao, double apts, void **data);
static void uninit(struct ao *ao)
{
struct priv *ac = ao->priv;
@@ -199,12 +189,12 @@ static void uninit(struct ao *ao)
return;
}
- if (ac->buffer) {
+ if (ac->stream) {
double outpts = ac->expected_next_pts;
if (!ectx->options->rawts && ectx->options->copyts)
outpts += ectx->discontinuity_pts_offset;
outpts += encode_lavc_getoffset(ectx, ac->codec);
- while (encode(ao, outpts, NULL) > 0) ;
+ encode(ao, outpts, NULL);
}
pthread_mutex_unlock(&ectx->lock);
@@ -220,24 +210,130 @@ static int get_space(struct ao *ao)
return ac->aframesize * ac->framecount;
}
+static void write_packet(struct ao *ao, AVPacket *packet)
+{
+ // TODO: Can we unify this with the equivalent video code path?
+ struct priv *ac = ao->priv;
+
+ packet->stream_index = ac->stream->index;
+ if (packet->pts != AV_NOPTS_VALUE) {
+ packet->pts = av_rescale_q(packet->pts,
+ ac->codec->time_base,
+ ac->stream->time_base);
+ } else {
+ // Do we need this at all? Better be safe than sorry...
+ MP_WARN(ao, "encoder lost pts, why?\n");
+ if (ac->savepts != MP_NOPTS_VALUE) {
+ packet->pts = av_rescale_q(ac->savepts,
+ ac->codec->time_base,
+ ac->stream->time_base);
+ }
+ }
+ if (packet->dts != AV_NOPTS_VALUE) {
+ 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->codec->time_base,
+ ac->stream->time_base);
+ }
+
+ ac->savepts = AV_NOPTS_VALUE;
+
+ if (encode_lavc_write_frame(ao->encode_lavc_ctx,
+ ac->stream, packet) < 0) {
+ MP_ERR(ao, "error writing at %d %d/%d\n",
+ (int) packet->pts,
+ ac->stream->time_base.num,
+ ac->stream->time_base.den);
+ return;
+ }
+}
+
+static void encode_audio_and_write(struct ao *ao, AVFrame *frame)
+{
+ // TODO: Can we unify this with the equivalent video code path?
+ struct priv *ac = ao->priv;
+ AVPacket packet = {0};
+
+#if HAVE_AVCODEC_NEW_CODEC_API
+ int status = avcodec_send_frame(ac->codec, frame);
+ if (status < 0) {
+ MP_ERR(ao, "error encoding at %d %d/%d\n",
+ frame ? (int) frame->pts : -1,
+ ac->codec->time_base.num,
+ ac->codec->time_base.den);
+ return;
+ }
+ for (;;) {
+ av_init_packet(&packet);
+ status = avcodec_receive_packet(ac->codec, &packet);
+ if (status == AVERROR(EAGAIN)) { // No more packets for now.
+ if (frame == NULL) {
+ MP_ERR(ao, "sent flush frame, got EAGAIN");
+ }
+ break;
+ }
+ if (status == AVERROR_EOF) { // No more packets, ever.
+ if (frame != NULL) {
+ MP_ERR(ao, "sent audio frame, got EOF");
+ }
+ break;
+ }
+ if (status < 0) {
+ MP_ERR(ao, "error encoding at %d %d/%d\n",
+ frame ? (int) frame->pts : -1,
+ ac->codec->time_base.num,
+ ac->codec->time_base.den);
+ break;
+ }
+ if (frame) {
+ if (ac->savepts == AV_NOPTS_VALUE)
+ ac->savepts = frame->pts;
+ }
+ encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec);
+ write_packet(ao, &packet);
+ av_packet_unref(&packet);
+ }
+#else
+ av_init_packet(&packet);
+ int got_packet = 0;
+ int status = avcodec_encode_audio2(ac->codec, &packet, frame, &got_packet);
+ if (status < 0) {
+ MP_ERR(ao, "error encoding at %d %d/%d\n",
+ frame ? (int) frame->pts : -1,
+ ac->codec->time_base.num,
+ ac->codec->time_base.den);
+ return;
+ }
+ if (!got_packet) {
+ return;
+ }
+ if (frame) {
+ if (ac->savepts == AV_NOPTS_VALUE)
+ ac->savepts = frame->pts;
+ }
+ encode_lavc_write_stats(ao->encode_lavc_ctx, ac->codec);
+ write_packet(ao, &packet);
+ av_packet_unref(&packet);
+#endif
+}
+
// must get exactly ac->aframesize amount of data
-static int encode(struct ao *ao, double apts, void **data)
+static void encode(struct ao *ao, double apts, void **data)
{
- AVPacket packet;
struct priv *ac = ao->priv;
struct encode_lavc_context *ectx = ao->encode_lavc_ctx;
double realapts = ac->aframecount * (double) ac->aframesize /
ao->samplerate;
- int status, gotpacket;
ac->aframecount++;
if (data)
ectx->audio_pts_offset = realapts - apts;
- av_init_packet(&packet);
- packet.data = ac->buffer;
- packet.size = ac->buffer_size;
if(data) {
AVFrame *frame = av_frame_alloc();
frame->format = af_to_avformat(ao->format);
@@ -270,64 +366,11 @@ static int encode(struct ao *ao, double apts, void **data)
ac->lastpts = frame_pts;
frame->quality = ac->codec->global_quality;
- status = avcodec_encode_audio2(ac->codec, &packet, frame, &gotpacket);
-
- if (!status) {
- if (ac->savepts == AV_NOPTS_VALUE)
- ac->savepts = frame->pts;
- }
-
+ encode_audio_and_write(ao, frame);
av_frame_free(&frame);
}
else
- {
- status = avcodec_encode_audio2(ac->codec, &packet, NULL, &gotpacket);
- }
-
- if(status) {
- MP_ERR(ao, "error encoding\n");
- return -1;
- }
-
- if(!gotpacket)
- return 0;
-
- 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->codec);
-
- packet.stream_index = ac->stream->index;
-
- // Do we need this at all? Better be safe than sorry...
- if (packet.pts == AV_NOPTS_VALUE) {
- MP_WARN(ao, "encoder lost pts, why?\n");
- if (ac->savepts != MP_NOPTS_VALUE)
- packet.pts = ac->savepts;
- }
-
- if (packet.pts != AV_NOPTS_VALUE)
- 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->codec->time_base,
- ac->stream->time_base);
-
- if(packet.duration > 0)
- 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, 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);
- return -1;
- }
-
- return packet.size;
+ encode_audio_and_write(ao, NULL);
}
// this should round samples down to frame sizes
@@ -492,3 +535,5 @@ const struct ao_driver audio_out_lavc = {
.play = play,
.drain = drain,
};
+
+// vim: sw=4 ts=4 et tw=80
diff --git a/audio/out/ao_oss.c b/audio/out/ao_oss.c
index 3216d673e1..90d3b3e5c5 100644
--- a/audio/out/ao_oss.c
+++ b/audio/out/ao_oss.c
@@ -612,6 +612,12 @@ static int audio_wait(struct ao *ao, pthread_mutex_t *lock)
return r;
}
+static void list_devs(struct ao *ao, struct ao_device_list *list)
+{
+ if (stat(PATH_DEV_DSP, &(struct stat){0}) == 0)
+ ao_device_list_add(list, ao, &(struct ao_device_desc){"", "Default"});
+}
+
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_oss = {
@@ -629,6 +635,7 @@ const struct ao_driver audio_out_oss = {