[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