[FFmpeg-devel] [PATCH] libavfilter: added atempo filter (revised patch)

Pavel Koshevoy pkoshevoy at gmail.com
Fri Jun 8 07:39:29 CEST 2012


On 06/07/2012 03:00 AM, Stefano Sabatini wrote:
> Nit: commit title may be:
> libavfilter: add atempo filter

done

[...]

>> +/**
>> + * @file
>> + * tempo scaling audio filter -- an implementation of WSOLA algorithm
>> + */
> please mention the original source, if the filter was based on another
> implementation

Done.  The original source is my video player, Apprentice Video, hosted on 
sourceforge.



[...]
>> +typedef enum {
>> +    kLoadFragment     = 0,
>> +    kAdjustPosition   = 1,
>> +    kReloadFragment   = 2,
>> +    kOutputOverlapAdd = 3,
>> +    kFlushOutput      = 4
> what's the "k" good for?

In QuickTime and other frameworks I've worked with k prefix denotes a constant 
value (a const variable or enumeration value).  However, since the mere presence 
of this prefix raised a question I have removed it.


>> +
>> +} TState;
> the "T" in TAudioFragment and TState is weird.

I used to put  _t on all my type names, however I later discovered that _t is 
reserved for POSIX types.  When I switched to CamelCase a lot of the code I 
encountered was prefixed with C (for class, I guess).  I prefer to prefix type 
names with T instead, because it applies equally well to a struct, class, enum, 
typedef...  Anyway, since it looks odd to you I have renamed TAudioFragment to 
AudioFragment, and TState to FilterState.

[...]

>> +/**
>> + * Initialize filter state.
>> + */
>> +static void yae_constructor(ATempoContext *atempo)
> what "yae" stands for?

yae is the namespace name I use in the original C++ version of this filter.  Yae 
is a letter in the Cyrillic script -- 
http://en.wikipedia.org/wiki/Yae_%28Cyrillic%29


> Nit: the name "yae_constructor" sounds weird, the predominant
> convention is to use a verbal form rather than a noun for naming a
> function (like: yae_build or yae_init).

Done.  I got rid of yae_constructor and moved relevant code to init(..) 
instead.  I also got rid of yae_destructor and moved relevant code to uninit(..)


>> +{
>> +    atempo->ring = 0;
>> +    atempo->size = 0;
>> +    atempo->head = 0;
>> +    atempo->tail = 0;
>> +
>> +    atempo->format = AV_SAMPLE_FMT_NONE;
>> +    atempo->channels = 0;
>> +
>> +    atempo->window = 0;
>> +    atempo->tempo = 1.0;
>> +    atempo->drift = 0;
>> +
>> +    memset(&atempo->frag[0], 0, sizeof(atempo->frag));
>> +
>> +    atempo->nfrag = 0;
>> +    atempo->state = kLoadFragment;
>> +
>> +    atempo->position[0] = 0;
>> +    atempo->position[1] = 0;
>> +
>> +    atempo->fft_forward = NULL;
>> +    atempo->fft_inverse = NULL;
>> +    atempo->correlation = NULL;
>> +
>> +    atempo->request_fulfilled = 0;
>> +    atempo->dst_buffer = NULL;
>> +    atempo->dst = NULL;
>> +    atempo->dst_end = NULL;
>> +    atempo->nsamples_in = 0;
>> +    atempo->nsamples_out = 0;
> I think a memset to 0, followed by the explicit initialization of the
> few non-zero fields will be simpler.

I was assured that the filter context private data is memset to 0 before init is 
called, therefore I got rid of the redundant initialization.


>> +/**
>> + * Reset filter to initial state
>> + */
>> +static void yae_clear(ATempoContext *atempo)
>> +{
>> +    atempo->size = 0;
>> +    atempo->head = 0;
>> +    atempo->tail = 0;
>> +
>> +    atempo->drift = 0;
>> +    atempo->nfrag = 0;
>> +    atempo->state = kLoadFragment;
>> +
>> +    atempo->position[0] = 0;
>> +    atempo->position[1] = 0;
>> +
>> +    yae_clear_frag(&atempo->frag[0]);
>> +    yae_clear_frag(&atempo->frag[1]);
>> +
>> +    // shift left position of 1st fragment by half a window
>> +    // so that no re-normalization would be required for
>> +    // the left half of the 1st fragment:
>> +    atempo->frag[0].position[0] = -(int64_t)(atempo->window / 2);
>> +    atempo->frag[0].position[1] = -(int64_t)(atempo->window / 2);
>> +
>> +    if (atempo->dst_buffer) {
>> +        avfilter_unref_buffer(atempo->dst_buffer);
>> +        atempo->dst_buffer = NULL;
>> +        atempo->dst        = NULL;
>> +        atempo->dst_end    = NULL;
>> +    }
>> +
>> +    atempo->request_fulfilled = 0;
>> +    atempo->nsamples_in       = 0;
>> +    atempo->nsamples_out      = 0;
>> +}
> again this can be simplified / factorized with yae_constructor

Not really, this function can be called at any time after init(..), where as 
init(..) probably should be called only once.

[...]

>> +inline static TAudioFragment * yae_curr_frag(ATempoContext *atempo)
> nit: *yae_curr_frag, const ATempoContext *atempo

Done *yae_curr_frag(..), can't do const ATempoContext * because it will result 
in compiler warnings about discarded const qualifier.



>> +{
>> +    return&atempo->frag[atempo->nfrag % 2];
>> +}
>> +
>> +inline static TAudioFragment * yae_prev_frag(ATempoContext *atempo)
> ditto

same answer.



>> +{
>> +    return&atempo->frag[(atempo->nfrag + 1) % 2];
>> +}
>> +
>> +/**
>> + * Find the minimum of two scalars
>> + */
>> +#define yae_min(TScalar, a, b)                          \
> Uh? where was TScalar defined?
> Also can't you use FFMAX/FFMIN for such purposes?

   yae_min(TScalar, a, b)

is analogous to C++

   template <typename TScalar>
   const TScalar &
   std::min(const TScalar & a, const TScalar & b)

Here, TScalar is a template parameter specifying the type of function parameters.

Anyway, I was able to use FFMIN and FFMAX instead.

[...]

>> +static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
>> +{
>> +    ATempoContext *atempo = ctx->priv;
>> +    yae_constructor(atempo);
>> +
>> +    if (args) {
>> +        char   *tail = NULL;
>> +        double tempo = av_strtod(args,&tail);
> please check that tail is NULL&  fail otherwise like "Invalid scale
> factor '%s' provided, good for catching typos.

done


>> +/**
>> + * Deallocate any memory held by the filter,
>> + * release any buffer references, etc.
>> + *
>> + * This does not need to deallocate the AVFilterContext::priv memory itself.
>> + */
> Nit: generic comments are good in template code (and maybe we need
> it), but they are usually a bit annoying to deal with in working code
> (e.g. when you update API).

Agreed, although I've kept some of the comments as a reminder of what the less 
obvious functions are supposed to do.

[...]

>
>> +    enum AVSampleFormat format = (enum AVSampleFormat)inlink->format;
> unnecessary cast?

fixed


[...]

>> +/**
>> + * Samples filtering callback that.
>> + * This is where a filter receives audio data and processes it.
>> + */
> same comment as above

generic comment removed


> [...]
>> diff --git a/libavfilter/version.h b/libavfilter/version.h
>> index 76f649e..c90b4ad 100644
>> --- a/libavfilter/version.h
>> +++ b/libavfilter/version.h
>> @@ -30,7 +30,7 @@
>>
>>   #define LIBAVFILTER_VERSION_MAJOR  2
>>   #define LIBAVFILTER_VERSION_MINOR 78
>> -#define LIBAVFILTER_VERSION_MICRO 100
>> +#define LIBAVFILTER_VERSION_MICRO 101
> Minor bump, but leave this to the committer so you won't have to
> update again and again your patch.

I've removed my changes from libavfilter/version.h


> Thanks for the cool patch.


Thank you.  I have already submitted another patch incorporating the requested 
changes.

     Pavel.



More information about the ffmpeg-devel mailing list