[FFmpeg-devel] [PATCH] lavd/alsa: implement get_device_list callbacks

wm4 nfxjfg at googlemail.com
Sun Oct 19 16:27:49 CEST 2014


On Sat, 18 Oct 2014 20:36:22 +0200
Lukasz Marek <lukasz.m.luki2 at gmail.com> wrote:

> ---
>  libavdevice/alsa-audio-common.c | 60 +++++++++++++++++++++++++++++++++++++++++
>  libavdevice/alsa-audio-dec.c    |  6 +++++
>  libavdevice/alsa-audio-enc.c    |  6 +++++
>  libavdevice/alsa-audio.h        |  2 ++
>  4 files changed, 74 insertions(+)
> 
> diff --git a/libavdevice/alsa-audio-common.c b/libavdevice/alsa-audio-common.c
> index 4e63397..1061917 100644
> --- a/libavdevice/alsa-audio-common.c
> +++ b/libavdevice/alsa-audio-common.c
> @@ -343,3 +343,63 @@ int ff_alsa_extend_reorder_buf(AlsaData *s, int min_size)
>      s->reorder_buf_size = size;
>      return 0;
>  }
> +
> +/* ported from alsa-utils/aplay.c */
> +int ff_alsa_get_device_list(AVDeviceInfoList *device_list, snd_pcm_stream_t stream_type)
> +{
> +    int ret;
> +    void **hints, **n;
> +    char *name = NULL, *descr = NULL, *io = NULL, *tmp;
> +    AVDeviceInfo *new_device = NULL;
> +    const char *filter = stream_type == SND_PCM_STREAM_PLAYBACK ? "Output" : "Input";
> +
> +    av_log(NULL, AV_LOG_INFO, "%s\n", filter);
> +
> +    if (snd_device_name_hint(-1, "pcm", &hints) < 0)
> +        return AVERROR_EXTERNAL;
> +    n = hints;
> +    while (*n) {
> +        name = snd_device_name_get_hint(*n, "NAME");
> +        descr = snd_device_name_get_hint(*n, "DESC");
> +        io = snd_device_name_get_hint(*n, "IOID");
> +        if (!io || !strcmp(io, filter)) {
> +            new_device = av_mallocz(sizeof(AVDeviceInfo));
> +            if (!new_device) {
> +                ret = AVERROR(ENOMEM);
> +                goto fail;
> +            }
> +            new_device->device_name = name;
> +            name = NULL;
> +            if ((tmp = strrchr(descr, '\n')) && tmp[1]) {
> +                new_device->device_description = av_strdup(&tmp[1]);
> +                if (!new_device->device_description) {
> +                    ret = AVERROR(ENOMEM);
> +                    goto fail;
> +                }
> +            } else {
> +                new_device->device_description = descr;
> +                descr = NULL;
> +            }
> +            if ((ret = av_dynarray_add_nofree(&device_list->devices,
> +                                              &device_list->nb_devices, new_device)) < 0) {
> +                goto fail;
> +            }
> +            new_device = NULL;
> +        }
> +        av_freep(&io);
> +        av_freep(&name);
> +        av_freep(&descr);
> +        n++;
> +    }
> +  fail:
> +    av_free(io);
> +    av_free(name);
> +    av_free(descr);
> +    if (new_device) {
> +        av_free(new_device->device_description);
> +        av_free(new_device->device_name);
> +        av_free(new_device);
> +    }
> +    snd_device_name_free_hint(hints);
> +    return ret;
> +}
> diff --git a/libavdevice/alsa-audio-dec.c b/libavdevice/alsa-audio-dec.c
> index 2cdf356..7f8f8cd 100644
> --- a/libavdevice/alsa-audio-dec.c
> +++ b/libavdevice/alsa-audio-dec.c
> @@ -132,6 +132,11 @@ static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
>      return 0;
>  }

This will list all pseudo-devices. I concluded that this doesn't really
work. The device name also controls the channel layout, and listing the
device "hints" includes those multichannel pseudo-devies (e.g
"surround51:CARD=Intel,DEV=0"). But shouldn't you select the device
name based on the input audio channel layout you get? There are other
reasons to change the device name, e.g. adding the "plug" converter
plugin.

So I'm not sure what would be the best. Maybe enumerate raw devices
only?

> +static int audio_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_list)
> +{
> +    return ff_alsa_get_device_list(device_list, SND_PCM_STREAM_CAPTURE);
> +}
> +
>  static const AVOption options[] = {
>      { "sample_rate", "", offsetof(AlsaData, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
>      { "channels",    "", offsetof(AlsaData, channels),    AV_OPT_TYPE_INT, {.i64 = 2},     1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM },
> @@ -153,6 +158,7 @@ AVInputFormat ff_alsa_demuxer = {
>      .read_header    = audio_read_header,
>      .read_packet    = audio_read_packet,
>      .read_close     = ff_alsa_close,
> +    .get_device_list = audio_get_device_list,
>      .flags          = AVFMT_NOFILE,
>      .priv_class     = &alsa_demuxer_class,
>  };
> diff --git a/libavdevice/alsa-audio-enc.c b/libavdevice/alsa-audio-enc.c
> index e42cc8f..43d097d 100644
> --- a/libavdevice/alsa-audio-enc.c
> +++ b/libavdevice/alsa-audio-enc.c
> @@ -142,6 +142,11 @@ audio_get_output_timestamp(AVFormatContext *s1, int stream,
>      *dts = s->timestamp - delay;
>  }
>  
> +static int audio_get_device_list(AVFormatContext *h, AVDeviceInfoList *device_list)
> +{
> +    return ff_alsa_get_device_list(device_list, SND_PCM_STREAM_PLAYBACK);
> +}
> +
>  static const AVClass alsa_muxer_class = {
>      .class_name     = "ALSA muxer",
>      .item_name      = av_default_item_name,
> @@ -159,6 +164,7 @@ AVOutputFormat ff_alsa_muxer = {
>      .write_packet   = audio_write_packet,
>      .write_trailer  = ff_alsa_close,
>      .write_uncoded_frame = audio_write_frame,
> +    .get_device_list = audio_get_device_list,
>      .get_output_timestamp = audio_get_output_timestamp,
>      .flags          = AVFMT_NOFILE,
>      .priv_class     = &alsa_muxer_class,
> diff --git a/libavdevice/alsa-audio.h b/libavdevice/alsa-audio.h
> index 583c911..cf0e942 100644
> --- a/libavdevice/alsa-audio.h
> +++ b/libavdevice/alsa-audio.h
> @@ -99,4 +99,6 @@ int ff_alsa_xrun_recover(AVFormatContext *s1, int err);
>  
>  int ff_alsa_extend_reorder_buf(AlsaData *s, int size);
>  
> +int ff_alsa_get_device_list(AVDeviceInfoList *device_list, snd_pcm_stream_t stream_type);
> +
>  #endif /* AVDEVICE_ALSA_AUDIO_H */



More information about the ffmpeg-devel mailing list