diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/audio.c | 12 | ||||
-rw-r--r-- | audio/audio.h | 1 | ||||
-rw-r--r-- | audio/decode/ad_lavc.c | 6 | ||||
-rw-r--r-- | audio/decode/dec_audio.c | 9 | ||||
-rw-r--r-- | audio/filter/af.c | 39 | ||||
-rw-r--r-- | audio/mixer.c | 277 | ||||
-rw-r--r-- | audio/mixer.h | 11 | ||||
-rw-r--r-- | audio/out/ao.c | 5 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_utils.c | 7 | ||||
-rw-r--r-- | audio/out/ao_lavc.c | 197 | ||||
-rw-r--r-- | audio/out/ao_oss.c | 7 | ||||
-rw-r--r-- | audio/out/ao_wasapi.c | 2 | ||||
-rw-r--r-- | audio/out/ao_wasapi_changenotify.c | 2 |
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 = { .drain = drain, .wait = audio_wait, .wakeup = ao_wakeup_poll, + .list_devs = list_devs, .priv_size = sizeof(struct priv), .priv_defaults = &(const struct priv) { .audio_fd = -1, diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c index ae6bd3d9dc..325a7cf72b 100644 --- a/audio/out/ao_wasapi.c +++ b/audio/out/ao_wasapi.c @@ -132,7 +132,7 @@ static bool thread_feed(struc |