[FFmpeg-devel] [PATCH] Add NULL mixer to AVSequencer.

Stefano Sabatini stefano.sabatini-lala
Sat Aug 14 19:45:21 CEST 2010


On date Saturday 2010-08-14 14:06:44 +0200, Sebastian Vater encoded:
> The NULL mixer does not output any PCM data but internally
> simulates the whole mixing process (i.e. calculation of
> sample positions and running the playback handler at
> correct timing), which is useful for playtime calculation.
> 
> -- 
> 
> Best regards,
>                    :-) Basty/CDGS (-:
> 

> diff --git a/libavsequencer/Makefile b/libavsequencer/Makefile
> index 3608dd7..21f561b 100644
> --- a/libavsequencer/Makefile
> +++ b/libavsequencer/Makefile
> @@ -8,4 +8,6 @@ HEADERS = avsequencer.h \
>  OBJS = allmixers.o      \
>         avsequencer.o    \
>  
> +OBJS-$(CONFIG_NULL_MIXER)           += null_mixer.o
> +
>  include $(SUBDIR)../subdir.mak
> diff --git a/libavsequencer/allmixers.c b/libavsequencer/allmixers.c
> index 7579ee7..4189406 100644
> --- a/libavsequencer/allmixers.c
> +++ b/libavsequencer/allmixers.c
> @@ -37,4 +37,7 @@ void avsequencer_register_all(void)
>      if (initialized)
>          return;
>      initialized = 1;
> +
> +    /* Mixers */
> +    REGISTER_MIXER (NULL, null);
>  }
> diff --git a/libavsequencer/null_mixer.c b/libavsequencer/null_mixer.c
> new file mode 100644
> index 0000000..7c915eb
> --- /dev/null
> +++ b/libavsequencer/null_mixer.c
> @@ -0,0 +1,877 @@
> +/*
> + * Sequencer null mixer
> + * Copyright (c) 2010 Sebastian Vater <cdgs.basty at googlemail.com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +/**
> + * @file
> + * Sequencer null mixer.
> + */
> +
> +#include "libavsequencer/mixer.h"
> +
> +typedef struct AVSequencerNULLMixerData {
> +    AVSequencerMixerData mixer_data;
> +    int32_t *buf;
> +    uint32_t buf_size;
> +    uint32_t mix_buf_size;
> +    struct AVSequencerNULLMixerChannelInfo *channel_info;
> +    uint32_t amplify;
> +    uint32_t mix_rate;
> +    uint32_t mix_rate_frac;
> +    uint32_t current_left;
> +    uint32_t current_left_frac;
> +    uint32_t pass_len;
> +    uint32_t pass_len_frac;
> +    uint16_t channels;
> +    uint8_t stereo_mode;
> +    uint8_t previous_stereo_mode;
> +} AVSequencerNULLMixerData;
> +
> +typedef struct AVSequencerNULLMixerChannelInfo {
> +    struct ChannelBlock {
> +        int16_t *sample_start_ptr;
> +        uint32_t sample_len;
> +        uint32_t offset;
> +        uint32_t fraction;
> +        uint32_t advance;
> +        uint32_t advance_frac;
> +        void (*mix_func)( AVSequencerNULLMixerData *mixer_data, struct AVSequencerNULLMixerChannelInfo *channel_info, int32_t **buf, uint32_t *offset, uint32_t *fraction, uint32_t advance, uint32_t adv_frac, uint16_t len );
> +        uint32_t end_offset;
> +        uint32_t restart_offset;
> +        uint32_t repeat;
> +        uint32_t repeat_len;
> +        uint32_t count_restart;
> +        uint32_t counted;
> +        uint32_t rate;
> +        void (*mix_backwards_func)( AVSequencerNULLMixerData *mixer_data, struct AVSequencerNULLMixerChannelInfo *channel_info, int32_t **buf, uint32_t *offset, uint32_t *fraction, uint32_t advance, uint32_t adv_frac, uint16_t len );
> +        uint8_t bits_per_sample;
> +        uint8_t flags;
> +        uint8_t volume;
> +        uint8_t panning;
> +    } current;
> +    struct ChannelBlock next;
> +} AVSequencerNULLMixerChannelInfo;
> +
> +#if CONFIG_NULL_MIXER


> +static av_cold AVSequencerMixerData *init ( AVSequencerMixerContext *mixctx, const char *args, void *opaque );
> +static av_cold int uninit ( AVSequencerMixerData *mixer_data );
> +static av_cold uint32_t set_rate ( AVSequencerMixerData *mixer_data, uint32_t new_mix_rate );
> +static av_cold uint32_t set_tempo ( AVSequencerMixerData *mixer_data, uint32_t new_tempo );
> +static av_cold uint32_t set_volume ( AVSequencerMixerData *mixer_data, uint32_t amplify, uint32_t left_volume, uint32_t right_volume, uint32_t channels );
> +static av_cold void get_channel ( AVSequencerMixerData *mixer_data, AVSequencerMixerChannel *mixer_channel, uint32_t channel );
> +static av_cold void set_channel ( AVSequencerMixerData *mixer_data, AVSequencerMixerChannel *mixer_channel, uint32_t channel );
> +static av_cold void set_channel_volume_panning_pitch ( AVSequencerMixerData *mixer_data, AVSequencerMixerChannel *mixer_channel, uint32_t channel );
> +static av_cold void set_channel_position_repeat_flags ( AVSequencerMixerData *mixer_data, AVSequencerMixerChannel *mixer_channel, uint32_t channel );
> +static av_cold void mix ( AVSequencerMixerData *mixer_data, int32_t *buf );

Avoid forward declarations, especially if they're useless.  You can
reference the functions after they've been defined.

> +
> +static const char *null_mixer_name(void *p)
> +{
> +    AVSequencerMixerContext *mixctx = p;
> +
> +    return mixctx->name;
> +}
> +
> +static const AVClass avseq_null_mixer_class = {
> +    "AVSequencer Null Mixer",
> +    null_mixer_name,
> +    NULL,
> +    LIBAVUTIL_VERSION_INT,
> +};
> +
> +AVSequencerMixerContext null_mixer = {
> +    .av_class                          = &avseq_null_mixer_class,
> +    .name                              = "Null mixer",
> +    .description                       = NULL_IF_CONFIG_SMALL("Always outputs silence and simulates basic mixing"),
> +
> +    .flags                             = AVSEQ_MIXER_CONTEXT_FLAG_STEREO|AVSEQ_MIXER_CONTEXT_FLAG_SURROUND|AVSEQ_MIXER_CONTEXT_FLAG_AVFILTER,
> +    .frequency                         = 44100,
> +    .frequency_min                     = 1000,
> +    .frequency_max                     = 768000,
> +    .buf_size                          = 4096,
> +    .buf_size_min                      = 512,
> +    .buf_size_max                      = 32768,
> +    .volume_boost                      = 0x10000,
> +    .channels_max                      = 65535,
> +
> +    .init                              = init,
> +    .uninit                            = uninit,
> +    .set_rate                          = set_rate,
> +    .set_tempo                         = set_tempo,
> +    .set_volume                        = set_volume,
> +    .get_channel                       = get_channel,
> +    .set_channel                       = set_channel,
> +    .set_channel_volume_panning_pitch  = set_channel_volume_panning_pitch,
> +    .set_channel_position_repeat_flags = set_channel_position_repeat_flags,
> +    .mix                               = mix,
> +};
> +

> +static int mixer_init ( AVSequencerMixerData *mixer_data, const char *args, void *opaque );
> +static void mix_sample ( AVSequencerNULLMixerData *mixer_data, int32_t *buf, uint32_t len );
> +static void set_sample_mix_rate ( AVSequencerNULLMixerData *mixer_data, AVSequencerNULLMixerChannelInfo *channel_info, uint32_t rate );
> +static void advance_ok ( AVSequencerNULLMixerData *mixer_data, AVSequencerNULLMixerChannelInfo *channel_info );

same as before, advance_ok is quite a poor name.

> +
> +#define MIX(type)                                                                   \
> +    static void mix_##type ( AVSequencerNULLMixerData *mixer_data,                  \
> +                             AVSequencerNULLMixerChannelInfo *channel_info,         \
> +                             int32_t **buf, uint32_t *offset, uint32_t *fraction,   \
> +                             uint32_t advance, uint32_t adv_frac, uint32_t len )
> +
> +MIX(skip);
> +MIX(skip_backwards);
> +
> +// TODO: Implement null quality mixer identification and configuration.
> +
> +static av_cold AVSequencerMixerData *init(AVSequencerMixerContext *mixctx, const char *args, void *opaque) {

nit: '{' on its own line, same below.

> +    AVSequencerNULLMixerData *res = NULL;
> +
> +    if (!(res = av_mallocz(sizeof (AVSequencerNULLMixerData)))) {
> +        av_log(mixctx, AV_LOG_ERROR, "Cannot allocate mixer data factory.\n");
> +
> +        return NULL;
> +    }
> +
> +    res->mixer_data.mixctx = mixctx;
> +
> +    if (mixer_init ( (AVSequencerMixerData *) res, args, opaque ) < 0) {

Nits: (_foo_) => (foo), same below.

> +        av_free(res);
> +
> +        return NULL;
> +    }
> +
> +    return (AVSequencerMixerData *) res;
> +}
> +
> +static av_cold int uninit(AVSequencerMixerData *mixer_data) {
> +    AVSequencerNULLMixerData *null_mixer_data = (AVSequencerNULLMixerData *) mixer_data;
> +
> +    if (!null_mixer_data)
> +        return AVERROR_INVALIDDATA;
> +
> +    av_freep ( &null_mixer_data->channel_info );
> +    av_freep ( &null_mixer_data->buf );
> +    av_free ( null_mixer_data );
> +
> +    return 0;
> +}
> +
> +static av_cold uint32_t set_rate ( AVSequencerMixerData *mixer_data, uint32_t new_mix_rate ) {
> +    AVSequencerNULLMixerData *null_mixer_data = (AVSequencerNULLMixerData *) mixer_data;
> +    uint32_t mix_rate, mix_rate_frac;
> +
> +    null_mixer_data->mixer_data.rate = new_mix_rate;
> +
> +    if (null_mixer_data->mixer_data.flags & AVSEQ_MIXER_DATA_FLAG_MIXING) {
> +        mix_rate      = new_mix_rate; // TODO: Add check here if this mix rate is supported by target device
> +        mix_rate_frac = 0;
> +
> +        if (null_mixer_data->mix_rate != mix_rate) {
> +            AVSequencerNULLMixerChannelInfo *channel_info = null_mixer_data->channel_info;
> +            uint16_t i;
> +
> +            null_mixer_data->mix_rate      = mix_rate;
> +            null_mixer_data->mix_rate_frac = mix_rate_frac;
> +
> +            set_tempo ( (AVSequencerMixerData *) mixer_data, null_mixer_data->mixer_data.tempo );
> +
> +            for (i = null_mixer_data->channels; i > 0; i--) {
> +                channel_info->current.advance      = channel_info->current.rate / mix_rate;
> +                channel_info->current.advance_frac = (((uint64_t) channel_info->current.rate % mix_rate) << 32) / mix_rate;
> +                channel_info->next.advance         = channel_info->next.rate / mix_rate;
> +                channel_info->next.advance_frac    = (((uint64_t) channel_info->next.rate % mix_rate) << 32) / mix_rate;
> +
> +                channel_info++;
> +            }
> +        }
> +    }
> +

> +    // TODO: Inform libavfilter that the target mixing rate has been changed.

uh? I believe this should be pretty independant from libavfilter, if
that's required that should be implemented through a generic callback
system.

[...]

Regards.
-- 
FFmpeg = Faithful and Forgiving Mastodontic Pacific Educated Guide



More information about the ffmpeg-devel mailing list