On 05/24/2011 08:14 AM, Anton Khirnov wrote:
> From: Nicolas George <[email protected]>
>
> Currently, only S16 quad, 5.1 and 7.1 are implemented.
> Implementing support for other formats/layouts and capture should be
> straightforward.
>
> 7.1 support by Carl Eugen Hoyos.
>
> Signed-off-by: Anton Khirnov <[email protected]>
> ---
> libavdevice/alsa-audio-common.c | 90
> +++++++++++++++++++++++++++++++++++++++
> libavdevice/alsa-audio-enc.c | 10 ++++-
> libavdevice/alsa-audio.h | 7 +++
> 3 files changed, 106 insertions(+), 1 deletions(-)
>
> diff --git a/libavdevice/alsa-audio-common.c b/libavdevice/alsa-audio-common.c
> index ff6c9f8..e7fee7b 100644
> --- a/libavdevice/alsa-audio-common.c
> +++ b/libavdevice/alsa-audio-common.c
> @@ -43,6 +43,59 @@ static av_cold snd_pcm_format_t codec_id_to_pcm_format(int
> codec_id)
> }
> }
>
> +static void alsa_reorder_s16_out_51(const void *in_v, void *out_v, int n)
> +{
> + const int16_t *in = in_v;
> + int16_t *out = out_v;
> +
> + while (n-- > 0) {
> + out[0] = in[0];
> + out[1] = in[1];
> + out[2] = in[4];
> + out[3] = in[5];
> + out[4] = in[2];
> + out[5] = in[3];
> + in += 6;
> + out += 6;
> + }
> +}
> +
> +static void alsa_reorder_s16_out_71(const void *in_v, void *out_v, int n)
> +{
> + const int16_t *in = in_v;
> + int16_t *out = out_v;
> +
> + while (n-- > 0) {
> + out[0] = in[0];
> + out[1] = in[1];
> + out[2] = in[4];
> + out[3] = in[5];
> + out[4] = in[2];
> + out[5] = in[3];
> + out[6] = in[6];
> + out[7] = in[7];
> + in += 8;
> + out += 8;
> + }
> +}
I'm sure these could be more optimized, but I guess it doesn't matter
that much with ALSA output. First thing that comes to mind is memcpy()
then loop doing FFSWAP() of 2/3 and 4/5 as int32_t. These are also
great candidates for SIMD. But then again... maybe not that important
in this case.
> +
> +#define REORDER_DUMMY ((void *)1)
> +
> +static av_cold ff_reorder_func find_reorder_func(int codec_id,
> + int64_t layout,
> + int out)
> +{
> + return
> + codec_id == CODEC_ID_PCM_S16LE || codec_id == CODEC_ID_PCM_S16BE ?
> + layout == AV_CH_LAYOUT_QUAD ? REORDER_DUMMY :
> + layout == AV_CH_LAYOUT_5POINT1_BACK || layout ==
> AV_CH_LAYOUT_5POINT1 ?
> + out ? alsa_reorder_s16_out_51 : NULL :
> + layout == AV_CH_LAYOUT_7POINT1 ?
> + out ? alsa_reorder_s16_out_71 : NULL :
> + NULL :
> + NULL;
> +}
> +
This is one of the ugliest pieces of C I've seen in a while... how about
something like:
static av_cold ff_reorder_func find_reorder_func(int codec_id,
int64_t layout,
int out)
{
/* only 16-bit channel reordering is currently supported */
if (!(codec_id == CODEC_ID_PCM_S16LE ||
codec_id == CODEC_ID_PCM_S16BE))
return NULL;
/* reordering is not needed for QUAD layout */
if (layout == AV_CH_LAYOUT_QUAD)
return REORDER_DUMMY;
/* reordering input is not currently supported */
if (!out)
return NULL;
if (layout == AV_CH_LAYOUT_5POINT1_BACK ||
layout == AV_CH_LAYOUT_5POINT1)
return alsa_reorder_s16_out_51;
if (layout == AV_CH_LAYOUT_7POINT1)
return alsa_reorder_s16_out_71;
return NULL;
}
> av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode,
> unsigned int *sample_rate,
> int channels, enum CodecID *codec_id)
> @@ -54,6 +107,7 @@ av_cold int ff_alsa_open(AVFormatContext *ctx,
> snd_pcm_stream_t mode,
> snd_pcm_t *h;
> snd_pcm_hw_params_t *hw_params;
> snd_pcm_uframes_t buffer_size, period_size;
> + int64_t layout = ctx->streams[0]->codec->channel_layout;
>
> if (ctx->filename[0] == 0) audio_device = "default";
> else audio_device = ctx->filename;
> @@ -146,6 +200,26 @@ av_cold int ff_alsa_open(AVFormatContext *ctx,
> snd_pcm_stream_t mode,
>
> snd_pcm_hw_params_free(hw_params);
>
> + if (channels > 2 && layout) {
> + s->reorder_func = find_reorder_func(*codec_id, layout,
> + mode == SND_PCM_STREAM_PLAYBACK);
> + if (s->reorder_func == REORDER_DUMMY) {
> + s->reorder_func = NULL;
> + } else if (s->reorder_func) {
> + s->reorder_buf_size = buffer_size;
> + s->reorder_buf = av_malloc(s->reorder_buf_size * s->frame_size);
> + if (!s->reorder_buf)
> + goto fail1;
> + } else {
> + char name[16];
16 is too small. should be at least 32 if not more. channel layout names
can be things like: "FL|FR|FC|LFE|BL|BR|FLC|FRC"
> + av_get_channel_layout_string(name, sizeof(name), channels,
> layout);
> + av_log(ctx, AV_LOG_WARNING,
> + "ALSA channel layout unknown or unimplemented for %s
> %s.\n",
> + name,
> + mode == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture");
> + }
> + }
> +
> s->h = h;
> return 0;
>
> @@ -160,6 +234,7 @@ av_cold int ff_alsa_close(AVFormatContext *s1)
> {
> AlsaData *s = s1->priv_data;
>
> + av_freep(&s->reorder_buf);
> snd_pcm_close(s->h);
> return 0;
> }
> @@ -184,3 +259,18 @@ int ff_alsa_xrun_recover(AVFormatContext *s1, int err)
> }
> return err;
> }
> +
> +int ff_alsa_extend_reorder_buf(AlsaData *s, int min_size)
> +{
> + int size = s->reorder_buf_size;
> + void *r;
> +
> + while (size < min_size)
> + size *= 2;
> + r = av_realloc(s->reorder_buf, size * s->frame_size);
> + if (!r)
> + return AVERROR(ENOMEM);
> + s->reorder_buf = r;
> + s->reorder_buf_size = size;
> + return 0;
> +}
> diff --git a/libavdevice/alsa-audio-enc.c b/libavdevice/alsa-audio-enc.c
> index ebe598c..f3782c5 100644
> --- a/libavdevice/alsa-audio-enc.c
> +++ b/libavdevice/alsa-audio-enc.c
> @@ -76,7 +76,15 @@ static int audio_write_packet(AVFormatContext *s1,
> AVPacket *pkt)
> int size = pkt->size;
> uint8_t *buf = pkt->data;
>
> - while((res = snd_pcm_writei(s->h, buf, size / s->frame_size)) < 0) {
> + size /= s->frame_size;
> + if (s->reorder_func) {
> + if (size > s->reorder_buf_size)
> + if (ff_alsa_extend_reorder_buf(s, size))
> + return AVERROR(ENOMEM);
> + s->reorder_func(buf, s->reorder_buf, size);
> + buf = s->reorder_buf;
> + }
> + while ((res = snd_pcm_writei(s->h, buf, size)) < 0) {
> if (res == -EAGAIN) {
>
> return AVERROR(EAGAIN);
> diff --git a/libavdevice/alsa-audio.h b/libavdevice/alsa-audio.h
> index 7a1b018..2f25ce4 100644
> --- a/libavdevice/alsa-audio.h
> +++ b/libavdevice/alsa-audio.h
> @@ -39,10 +39,15 @@
> other formats */
> #define DEFAULT_CODEC_ID AV_NE(CODEC_ID_PCM_S16BE, CODEC_ID_PCM_S16LE)
>
> +typedef void (*ff_reorder_func)(const void *, void *, int);
> +
> typedef struct {
> snd_pcm_t *h;
> int frame_size; ///< preferred size for reads and writes
> int period_size; ///< bytes per sample * channels
> + ff_reorder_func reorder_func;
> + void *reorder_buf;
> + int reorder_buf_size; ///< in frames
> } AlsaData;
>
> /**
> @@ -82,4 +87,6 @@ int ff_alsa_close(AVFormatContext *s1);
> */
> int ff_alsa_xrun_recover(AVFormatContext *s1, int err);
>
> +int ff_alsa_extend_reorder_buf(AlsaData *s, int size);
> +
> #endif /* AVDEVICE_ALSA_AUDIO_H */
patch looks alright otherwise.
-Justin
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel