[FFmpeg-devel] [RFC] libavfilter audio API and related issues

Stefano Sabatini stefano.sabatini-lala
Sun Jul 4 17:20:13 CEST 2010


On date Thursday 2010-07-01 01:47:01 -0700, S.N. Hemanth Meenakshisundaram encoded:
> On 07/01/2010 01:42 AM, S.N. Hemanth Meenakshisundaram wrote:
> >On 06/25/2010 05:10 PM, Stefano Sabatini wrote:
> >>On date Friday 2010-06-25 03:52:45 -0700, S.N. Hemanth
> >>Meenakshisundaram encoded:
> >>>[...]
> >>
> >
> >Hi All,
> >
> >Here is the working af_resample.c and associated Makefile and
> >allfilters.c changes.
> >
> >[...]
> 
> Here are the up to date changes to libavfilter files for audio
> filtering framework.
> 
> Regards,
> 

> diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
> index 38ca3b1..462e6fe 100644
> --- a/libavfilter/avfilter.c
> +++ b/libavfilter/avfilter.c
> @@ -60,6 +60,22 @@ void avfilter_unref_pic(AVFilterPicRef *ref)
>      av_free(ref);
>  }
>  
> +AVFilterSamplesRef *avfilter_ref_samples(AVFilterSamplesRef *ref, int pmask)
> +{
> +    AVFilterSamplesRef *ret = av_malloc(sizeof(AVFilterSamplesRef));
> +    *ret = *ref;
> +    ret->perms &= pmask;
> +    ret->buffer->refcount++;
> +    return ret;
> +}
> +

> +void avfilter_unref_samples(AVFilterSamplesRef *ref)
> +{
> +    if(!(--ref->buffer->refcount))
> +        ref->buffer->free(ref->buffer);
> +    av_free(ref);
> +}

Nits: for_(, if_(, here and below

> +
>  void avfilter_insert_pad(unsigned idx, unsigned *count, size_t padidx_off,
>                           AVFilterPad **pads, AVFilterLink ***links,
>                           AVFilterPad *newpad)
> @@ -97,7 +113,9 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad,
>      link->dst     = dst;
>      link->srcpad  = srcpad;
>      link->dstpad  = dstpad;
> +    link->type    = src->output_pads[srcpad].type;
>      link->format  = PIX_FMT_NONE;
> +    link->aformat = SAMPLE_FMT_NONE;
>  
>      return 0;
>  }
> @@ -210,6 +228,20 @@ AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms, int w,
>      return ret;
>  }
>  
> +AVFilterSamplesRef *avfilter_get_samples_ref(AVFilterLink *link, int perms, int size,
> +                                              int64_t channel_layout, enum SampleFormat sample_fmt, int planar)
> +{
> +    AVFilterSamplesRef *ret = NULL;
> +
> +    if (link_dpad(link).get_samples_ref)
> +        ret = link_dpad(link).get_samples_ref(link, perms, size, channel_layout, sample_fmt, planar);
> +
> +    if(!ret)
> +        ret = avfilter_default_get_samples_ref(link, perms, size, channel_layout, sample_fmt, planar);
> +
> +    return ret;
> +}
> +
>  int avfilter_request_frame(AVFilterLink *link)
>  {
>      DPRINTF_START(NULL, request_frame); dprintf_link(NULL, link, 1);
> @@ -221,6 +253,14 @@ int avfilter_request_frame(AVFilterLink *link)
>      else return -1;
>  }
>  
> +int avfilter_request_samples(AVFilterLink *link)
> +{
> +    if(link_spad(link).request_samples)
> +        return link_spad(link).request_samples(link);
> +    else if(link->src->inputs[0])
> +        return avfilter_request_samples(link->src->inputs[0]);
> +    else return AVERROR(EINVAL);
> +}
>  int avfilter_poll_frame(AVFilterLink *link)
>  {
>      int i, min=INT_MAX;
> @@ -334,6 +374,31 @@ void avfilter_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
>      draw_slice(link, y, h, slice_dir);
>  }
>  
> +void avfilter_filter_samples(AVFilterLink *link, AVFilterSamplesRef *samplesref)
> +{
> +    void (*filter_samples)(AVFilterLink *, AVFilterSamplesRef *);
> +    AVFilterPad *dst = &link_dpad(link);
> +
> +    if(!(filter_samples = dst->filter_samples))
> +        filter_samples = avfilter_default_filter_samples;
> +

> +    /* prepare to copy the samples if the buffer has insufficient permissions */
> +    if((dst->min_perms & samplesref->perms) != dst->min_perms ||
> +        dst->rej_perms & samplesref->perms) {
> +
> +        link->cur_samples = avfilter_default_get_samples_ref(link, dst->min_perms,
> +                                                              samplesref->size, samplesref->channel_layout,
> +                                                              samplesref->sample_fmt, samplesref->planar);

Please add a debug log here, it should help to inspect permission
issues (something like in avfilter_start_frame, but not commented out).

> +        link->cur_samples->pts            = samplesref->pts;
> +        link->cur_samples->sample_rate    = samplesref->sample_rate;
> +        avfilter_unref_samples(samplesref);
> +    }
> +    else
> +        link->cur_samples = samplesref;
> +
> +    filter_samples(link, link->cur_samples);
> +}
> +
>  #define MAX_REGISTERED_AVFILTERS_NB 64
>  
>  static AVFilter *registered_avfilters[MAX_REGISTERED_AVFILTERS_NB + 1];
> diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
> index 716dc0b..63dbadb 100644
> --- a/libavfilter/avfilter.h
> +++ b/libavfilter/avfilter.h
> @@ -88,6 +88,29 @@ typedef struct AVFilterPic
>      int w, h;                  ///< width and height of the allocated buffer
>  } AVFilterPic;
>  
> +/*
> + * Temporary structure for audio data used by the filter system. Later to be
> + * merged with FilterPic above and generalized.
> + */
> +typedef struct AVFilterBuffer
> +{
> +    uint8_t *data[8];           ///< audio data for each channel
> +    int linesize[8];            ///< number of bytes to next sample
> +
> +    unsigned refcount;          ///< number of references to this buffer
> +
> +    /** private data to be used by a custom free function */
> +    void *priv;
> +    /**
> +     * A pointer to the function to deallocate this buffer if the default
> +     * function is not sufficient. This could, for example, add the memory
> +     * back into a memory pool to be reused later without the overhead of
> +     * reallocating it from scratch.
> +     */
> +    void (*free)(struct AVFilterBuffer *buffer);
> +
> +} AVFilterBuffer;
> +
>  /**
>   * A reference to an AVFilterPic. Since filters can manipulate the origin of
>   * a picture to, for example, crop image without any memcpy, the picture origin
> @@ -96,31 +119,57 @@ typedef struct AVFilterPic
>   *
>   * TODO: add anything necessary for frame reordering
>   */
> +#define AV_PERM_READ     0x01   ///< can read from the buffer
> +#define AV_PERM_WRITE    0x02   ///< can write to the buffer
> +#define AV_PERM_PRESERVE 0x04   ///< nobody else can overwrite the buffer
> +#define AV_PERM_REUSE    0x08   ///< can output the buffer multiple times, with the same contents each time
> +#define AV_PERM_REUSE2   0x10   ///< can output the buffer multiple times, modified each time
>  typedef struct AVFilterPicRef
>  {
>      AVFilterPic *pic;           ///< the picture that this is a reference to
>      uint8_t *data[4];           ///< picture data for each plane
>      int linesize[4];            ///< number of bytes per line

> -    int w;                      ///< image width
> -    int h;                      ///< image height
> -
>      int64_t pts;                ///< presentation timestamp in units of 1/AV_TIME_BASE
>      int64_t pos;                ///< byte position in stream, -1 if unknown
>  
> +    int w;                      ///< image width
> +    int h;                      ///< image height
> +

cosmetics, and breaking ABI (not that we care right now, but should be
avoided when possible)

>      AVRational pixel_aspect;    ///< pixel aspect ratio
>  
>      int perms;                  ///< permissions

> -#define AV_PERM_READ     0x01   ///< can read from the buffer
> -#define AV_PERM_WRITE    0x02   ///< can write to the buffer
> -#define AV_PERM_PRESERVE 0x04   ///< nobody else can overwrite the buffer
> -#define AV_PERM_REUSE    0x08   ///< can output the buffer multiple times, with the same contents each time
> -#define AV_PERM_REUSE2   0x10   ///< can output the buffer multiple times, modified each time

The AV_PERM_* moving can go to a separate patch.
  
>      int interlaced;             ///< is frame interlaced
>      int top_field_first;
>  } AVFilterPicRef;
>  
>  /**
> + * A reference to an AVFilterBuffer for audio. Since filters can manipulate the
> + * origin of an audio buffer to, for example, reduce precision without any memcpy,
> + * sample format and channel_layout are per-reference properties. Sample step is
> + * also useful when reducing the number of channels, etc, and so is also per-reference.
> + */
> +typedef struct AVFilterSamplesRef
> +{
> +    AVFilterBuffer *buffer;       ///< the audio buffer that this is a reference to
> +    uint8_t *data[8];             ///< audio data for each channel
> +    int linesize[8];              ///< number of bytes to next sample
> +    int64_t pts;                  ///< presentation timestamp in units of 1/AV_TIME_BASE
> +
> +    int64_t channel_layout;       ///< channel layout of current buffer (see avcodec.h)
> +    int64_t sample_rate;          ///< samples per second

> +    enum SampleFormat sample_fmt; ///< sample format (see avcodec.h)

remove the see ..., this will be changed when we'll move the definition.

> +
> +    int samples_nb;               ///< number of samples in this buffer
> +    /* Should this go here or in the AVFilterBuffer struct? */
> +    int size;                     ///< size of buffer
> +
> +    int perms;                    ///< permissions
> +
> +    int planar;                   ///< is buffer planar or packed
> +} AVFilterSamplesRef;
> +
> +/**
>   * Adds a new reference to a picture.
>   * @param ref   an existing reference to the picture
>   * @param pmask a bitmask containing the allowable permissions in the new
> @@ -138,6 +187,25 @@ AVFilterPicRef *avfilter_ref_pic(AVFilterPicRef *ref, int pmask);
>  void avfilter_unref_pic(AVFilterPicRef *ref);
>  

>  /**
> + * Adds a new reference to an audio samples buffer.

Please update all the doxies to make them comply with the latest
sanctioned style change, use impersonal form...

> + *
> + * @param ref   an existing reference to the buffer
> + * @param pmask a bitmask containing the allowable permissions in the new
> + *              reference
> + * @return      a new reference to the buffer with the same properties as the
> + *              old, excluding any permissions denied by pmask
> + */
> +AVFilterSamplesRef *avfilter_ref_samples(AVFilterSamplesRef *ref, int pmask);
> +
> +/**
> + * Removes a reference to a buffer of audio samples. If this is the last reference
> + * to the buffer, the buffer itself is also automatically freed.
> + *
> + * @param ref reference to the buffer
> + */
> +void avfilter_unref_samples(AVFilterSamplesRef *ref);
> +
> +/**
>   * A list of supported formats for one end of a filter link. This is used
>   * during the format negotiation process to try to pick the best format to
>   * use to minimize the number of necessary conversions. Each filter gives a
> @@ -181,15 +249,17 @@ typedef struct AVFilterFormats AVFilterFormats;
>  struct AVFilterFormats
>  {
>      unsigned format_count;      ///< number of formats
> -    enum PixelFormat *formats;  ///< list of pixel formats
> +    enum AVMediaType type;      ///< filter type
> +    enum PixelFormat *formats;   ///< list of pixel formats for video
> +    enum SampleFormat *aformats; ///< list of sample formats for audio
>  
>      unsigned refcount;          ///< number of references to this list
>      AVFilterFormats ***refs;    ///< references to this list
>  };
>  
>  /**
> - * Creates a list of supported formats. This is intended for use in
> - * AVFilter->query_formats().
> + * Creates a list of supported pixel formats. This is intended for use in
> + * AVFilter->query_formats() for video filters.
>   * @param pix_fmt list of pixel formats, terminated by PIX_FMT_NONE
>   * @return the format list, with no existing references
>   */
> @@ -211,6 +281,30 @@ int avfilter_add_colorspace(AVFilterFormats **avff, enum PixelFormat pix_fmt);
>  AVFilterFormats *avfilter_all_colorspaces(void);
>  
>  /**
> + * Creates a list of supported sample formats. This is intended for use in
> + * AVFilter->query_formats() for audio filters.
> + *
> + * @param sample_fmt list of sample formats, terminated by SAMPLE_FMT_NONE
> + * @return the format list, with no existing references
> + */
> +AVFilterFormats *avfilter_make_aformat_list(const enum SampleFormat *sample_fmts);
> +
> +/**
> + * Adds sample_fmt to the list of sample formats contained in *avff.
> + * If *avff is NULL the function allocates the filter formats struct
> + * and puts its pointer in *avff.
> + *
> + * @return a non negative value in case of success, or a negative
> + * value corresponding to an AVERROR code in case of error
> + */
> +int avfilter_add_sampleformat(AVFilterFormats **avff, enum SampleFormat sample_fmt);
> +
> +/**
> + * Returns a list of all sampleformats supported by FFmpeg.
> + */
> +AVFilterFormats *avfilter_all_sampleformats(void);
> +
> +/**
>   * Returns a format list which contains the intersection of the formats of
>   * a and b. Also, all the references of a, all the references of b, and
>   * a and b themselves will be deallocated.
> @@ -280,8 +374,7 @@ struct AVFilterPad
>      const char *name;
>  
>      /**
> -     * AVFilterPad type. Only video supported now, hopefully someone will
> -     * add audio in the future.
> +     * AVFilterPad type. Audio support still in progress.
>       */
>      enum AVMediaType type;
>  
> @@ -315,7 +408,7 @@ struct AVFilterPad
>      void (*start_frame)(AVFilterLink *link, AVFilterPicRef *picref);
>  
>      /**
> -     * Callback function to get a buffer. If NULL, the filter system will
> +     * Callback function to get a video buffer. If NULL, the filter system will
>       * use avfilter_default_get_video_buffer().
>       *
>       * Input video pads only.
> @@ -323,6 +416,16 @@ struct AVFilterPad
>      AVFilterPicRef *(*get_video_buffer)(AVFilterLink *link, int perms, int w, int h);
>  
>      /**
> +     * Callback function to get an audio buffer. If NULL, the filter system will
> +     * use avfilter_default_get_samples_ref().
> +     *
> +     * Input audio pads only.
> +     */
> +    AVFilterSamplesRef *(*get_samples_ref)(AVFilterLink *link, int perms,
> +                                            int size, int64_t channel_layout,
> +                                            enum SampleFormat sample_fmt, int planar);
> +
> +    /**
>       * Callback called after the slices of a frame are completely sent. If
>       * NULL, the filter layer will default to releasing the reference stored
>       * in the link structure during start_frame().
> @@ -340,6 +443,14 @@ struct AVFilterPad
>      void (*draw_slice)(AVFilterLink *link, int y, int height, int slice_dir);
>  
>      /**
> +     * Samples filtering callback. This is where a filter receives audio data
> +     * and should do its processing.
> +     *
> +     * Input audio pads only.
> +     */
> +    void (*filter_samples)(AVFilterLink *link, AVFilterSamplesRef *samplesref);
> +
> +    /**
>       * Frame poll callback. This returns the number of immediately available
>       * frames. It should return a positive value if the next request_frame()
>       * is guaranteed to return one frame (with no delay).
> @@ -360,6 +471,15 @@ struct AVFilterPad
>      int (*request_frame)(AVFilterLink *link);
>  
>      /**
> +     * Samples request callback. A call to this should result in at least one
> +     * sample being output over the given link. This should return zero on
> +     * success, and another value on error.
> +     *
> +     * Output audio pads only.
> +     */
> +    int (*request_samples)(AVFilterLink *link);
> +
> +    /**
>       * Link configuration callback.
>       *
>       * For output pads, this should set the link properties such as
> @@ -382,13 +502,19 @@ void avfilter_default_start_frame(AVFilterLink *link, AVFilterPicRef *picref);
>  void avfilter_default_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
>  /** default handler for end_frame() for video inputs */
>  void avfilter_default_end_frame(AVFilterLink *link);
> -/** default handler for config_props() for video outputs */
> +/** default handler for filter_samples() for audio inputs */
> +void avfilter_default_filter_samples(AVFilterLink *link, AVFilterSamplesRef *samplesref);
> +/** default handler for config_props() for audio/video outputs */
>  int avfilter_default_config_output_link(AVFilterLink *link);
> -/** default handler for config_props() for video inputs */
> +/** default handler for config_props() for audio/video inputs */
>  int avfilter_default_config_input_link (AVFilterLink *link);
>  /** default handler for get_video_buffer() for video inputs */
>  AVFilterPicRef *avfilter_default_get_video_buffer(AVFilterLink *link,
>                                                    int perms, int w, int h);

> +/** default handler for get_samples_ref() for audio inputs */
> +AVFilterSamplesRef *avfilter_default_get_samples_ref(AVFilterLink *link, int perms,
> +                                                      int size, int64_t channel_layout,
> +                                                      enum SampleFormat sample_fmt, int planar);

indent

>  /**
>   * A helper for query_formats() which sets all links to the same list of
>   * formats. If there are no links hooked to this filter, the list of formats is
> @@ -407,10 +533,18 @@ void avfilter_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
>  /** end_frame() handler for filters which simply pass video along */
>  void avfilter_null_end_frame(AVFilterLink *link);
>  
> +/** filter_samples() handler for filters which simply pass audio along */
> +void avfilter_null_filter_samples(AVFilterLink *link, AVFilterSamplesRef *samplesref);
> +
>  /** get_video_buffer() handler for filters which simply pass video along */
>  AVFilterPicRef *avfilter_null_get_video_buffer(AVFilterLink *link,
>                                                    int perms, int w, int h);
>  
> +/** get_samples_ref() handler for filters which simply pass audio along */
> +AVFilterSamplesRef *avfilter_null_get_samples_ref(AVFilterLink *link, int perms,
> +                                                   int size, int64_t channel_layout,
> +                                                   enum SampleFormat sample_fmt, int planar);
> +
>  /**
>   * Filter definition. This defines the pads a filter contains, and all the
>   * callback functions used to interact with the filter.
> @@ -498,10 +632,22 @@ struct AVFilterLink
>          AVLINK_INIT             ///< complete
>      } init_state;
>  
> +    /**
> +     * AVFilterPad type. Audio support still in progress.
> +     */
> +    enum AVMediaType type;
> +
> +    /* These three parameters apply only to video */
>      int w;                      ///< agreed upon image width
>      int h;                      ///< agreed upon image height
>      enum PixelFormat format;    ///< agreed upon image colorspace
>  
> +    /* These four parameters apply only to audio */
> +    int samples_nb;             ///< number of samples in this buffer
> +    int64_t channel_layout;     ///< channel layout of current buffer (see avcodec.h)
> +    int64_t sample_rate;        ///< samples per second
> +    enum SampleFormat aformat;  ///< sample format (see avcodec.h)
> + 
>      /**
>       * Lists of formats supported by the input and output filters respectively.
>       * These lists are used for negotiating the format to actually be used,
> @@ -511,16 +657,21 @@ struct AVFilterLink
>      AVFilterFormats *out_formats;
>  
>      /**
> -     * The picture reference currently being sent across the link by the source
> -     * filter. This is used internally by the filter system to allow
> -     * automatic copying of pictures which do not have sufficient permissions
> -     * for the destination. This should not be accessed directly by the
> -     * filters.
> +     * The picture (for video) or samples (for audio) reference currently being
> +     * sent across the link by the source filter. This is used internally by the
> +     * filter system to allow automatic copying of pictures/samples which do not
> +     * have sufficient permissions for the destination. This should not be accessed
> +     * directly by the filters.
>       */
>      AVFilterPicRef *srcpic;
>  
>      AVFilterPicRef *cur_pic;
>      AVFilterPicRef *outpic;

> +
> +    AVFilterSamplesRef *src_samples;
> +
> +    AVFilterSamplesRef *cur_samples;
> +    AVFilterSamplesRef *out_samples;

Please add docs.

>  };
>  
>  /**
> @@ -555,6 +706,22 @@ AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms,
>                                            int w, int h);
>  
>  /**
> + * Requests an audio samples buffer with a specific set of permissions.
> + *
> + * @param link           the output link to the filter from which the buffer will
> + *                       be requested
> + * @param perms          the required access permissions
> + * @param samples_nb     the number of samples in the buffer to allocate

> + * @param channel_layout the no. & type of channels per sample in the buffer to allocate

no. -> number
&   -> and

yes we're boring

> + * @param sample_fmt     the format of each sample in the buffer to allocate
> + * @return               A reference to the samples. This must be unreferenced with
> + *                       avfilter_unref_samples when you are finished with it.
> + */
> +AVFilterSamplesRef *avfilter_get_samples_ref(AVFilterLink *link, int perms,
> +                                             int size, int64_t channel_layout,
> +                                             enum SampleFormat sample_fmt, int planar);
> +
> +/**
>   * Requests an input frame from the filter at the other end of the link.
>   * @param link the input link
>   * @return     zero on success
> @@ -562,6 +729,14 @@ AVFilterPicRef *avfilter_get_video_buffer(AVFilterLink *link, int perms,
>  int avfilter_request_frame(AVFilterLink *link);
>  
>  /**
> + * Requests input audio samples from the filter at the other end of the link.
> + *
> + * @param  link the input link
> + * @return zero on success
> + */
> +int avfilter_request_samples(AVFilterLink *link);
> +
> +/**
>   * Polls a frame from the filter chain.
>   * @param  link the input link
>   * @return the number of immediately available frames, a negative
> @@ -602,6 +777,14 @@ void avfilter_end_frame(AVFilterLink *link);
>   */
>  void avfilter_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
>  
> +/**
> + * Sends a buffer of audio samples to the next filter.
> + *
> + * @param link   the output link over which the audio samples are being sent
> + * @param planar samples are packed if 0 or planar if 1
> + */
> +void avfilter_filter_samples(AVFilterLink *link, AVFilterSamplesRef *samplesref);
> +
>  /** Initializes the filter system. Registers all builtin filters. */
>  void avfilter_register_all(void);
>  
> diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
> index 9ad6536..d24f654 100644
> --- a/libavfilter/avfiltergraph.c
> +++ b/libavfilter/avfiltergraph.c
> @@ -111,12 +111,13 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
>      int scaler_count = 0;
>      char inst_name[30];
>  
> -    /* ask all the sub-filters for their supported colorspaces */
> +    /* ask all the sub-filters for their supported colorspaces/sample formats */

>      for(i = 0; i < graph->filter_count; i ++) {
> -        if(graph->filters[i]->filter->query_formats)
> +        if(graph->filters[i]->filter->query_formats) {
>              graph->filters[i]->filter->query_formats(graph->filters[i]);
> -        else
> +        } else {
>              avfilter_default_query_formats(graph->filters[i]);
> +        }

cosmetics

>      }
>  
>      /* go through and merge as many format lists as possible */
> @@ -125,6 +126,7 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
>  
>          for(j = 0; j < filter->input_count; j ++) {
>              AVFilterLink *link = filter->inputs[j];
> +

ditto

>              if(link && link->in_formats != link->out_formats) {
>                  if(!avfilter_merge_formats(link->in_formats,
>                                             link->out_formats)) {
> @@ -170,7 +172,10 @@ static void pick_format(AVFilterLink *link)
>          return;
>  
>      link->in_formats->format_count = 1;

> -    link->format = link->in_formats->formats[0];
> +    if (link->type == AVMEDIA_TYPE_VIDEO)
> +        link->format = link->in_formats->formats[0];
> +    else if (link->type == AVMEDIA_TYPE_AUDIO)
> +        link->aformat = link->in_formats->aformats[0];

simpler: link->format = type == VIDEO ? link->in_formats->formats[0] : link->in_formats->aformats[0];

>  
>      avfilter_formats_unref(&link->in_formats);
>      avfilter_formats_unref(&link->out_formats);
> diff --git a/libavfilter/defaults.c b/libavfilter/defaults.c
> index 0ac88f8..077b236 100644
> --- a/libavfilter/defaults.c
> +++ b/libavfilter/defaults.c
> @@ -21,6 +21,7 @@
>  
>  #include "libavcodec/imgconvert.h"
>  #include "avfilter.h"

> +#include "libavutil/audiodesc.h"

Directly include the libavcodec files, will fix it when audiodesc will
be committed to lavu.

>  /* TODO: buffer pool.  see comment for avfilter_default_get_video_buffer() */
>  static void avfilter_default_free_video_buffer(AVFilterPic *pic)
> @@ -29,6 +30,12 @@ static void avfilter_default_free_video_buffer(AVFilterPic *pic)
>      av_free(pic);
>  }
>  
> +static void avfilter_default_free_audio_buffer(AVFilterBuffer *buffer)
> +{
> +    av_free(buffer->data[0]);
> +    av_free(buffer);
> +}
> +
>  /* TODO: set the buffer's priv member to a context structure for the whole
>   * filter chain.  This will allow for a buffer pool instead of the constant
>   * alloc & free cycle currently implemented. */
> @@ -65,6 +72,65 @@ AVFilterPicRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms,
>      return ref;
>  }
>  
> +AVFilterSamplesRef *avfilter_default_get_samples_ref(AVFilterLink *link, int perms,
> +                                                      int size, int64_t channel_layout,
> +                                                      enum SampleFormat sample_fmt, int planar)
> +{
> +    AVFilterBuffer *buffer = av_mallocz(sizeof(AVFilterBuffer));
> +    AVFilterSamplesRef *ref = av_mallocz(sizeof(AVFilterSamplesRef));
> +    int i, sample_size, num_chans, bufsize, per_channel_size, step_size = 0;
> +    char *buf;
> +
> +    ref->buffer         = buffer;
> +    ref->channel_layout = channel_layout;
> +    ref->sample_fmt     = sample_fmt;
> +    ref->size           = size;
> +    ref->planar         = planar;
> +
> +    /* make sure the buffer gets read permission or it's useless for output */
> +    ref->perms = perms | AV_PERM_READ;
> +
> +    buffer->refcount   = 1;
> +    buffer->free       = avfilter_default_free_audio_buffer;
> +
> +    sample_size = (av_get_bits_per_sample_fmt(sample_fmt))>>3;
> +    num_chans = av_channel_layout_num_channels(channel_layout);
> +
> +    per_channel_size = size/num_chans;
> +    ref->samples_nb = per_channel_size/sample_size;
> +
> +    /* Set the number of bytes to traverse to reach next sample of a particular channel:
> +     * For planar, this is simply the sample size.
> +     * For packed, this is the number of samples * sample_size.
> +     */
> +    for (i = 0; i < num_chans; i++)
> +        buffer->linesize[i] = (planar > 0)?(per_channel_size):sample_size;
> +    memset(&buffer->linesize[num_chans], 0, (8-num_chans)*sizeof(buffer->linesize[0]));
> +
> +    /* Calculate total buffer size, round to multiple of 16 to be SIMD friendly */
> +    bufsize = (size + 15)&~15;
> +    buf = av_malloc(bufsize);
> +
> +    /* For planar, set the start point of each channel's data within the buffer
> +     * For packed, set the start point of the entire buffer only
> +     */
> +    buffer->data[0] = buf;
> +    if(planar > 0) {
> +        for(i = 1; i < num_chans; i++) {
> +            step_size += per_channel_size;
> +            buffer->data[i] = buf + step_size;
> +        }
> +    } else {
> +        memset(&buffer->data[1], (long)buf, (num_chans-1)*sizeof(buffer->data[0]));
> +    }
> +    memset(&buffer->data[num_chans], 0, (8-num_chans)*sizeof(buffer->data[0]));
> +
> +    memcpy(ref->data,     buffer->data,     sizeof(buffer->data));
> +    memcpy(ref->linesize, buffer->linesize, sizeof(buffer->linesize));
> +
> +    return ref;
> +}
> +
>  void avfilter_default_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
>  {
>      AVFilterLink *out = NULL;
> @@ -113,6 +179,23 @@ void avfilter_default_end_frame(AVFilterLink *link)
>      }
>  }
>  
> +void avfilter_default_filter_samples(AVFilterLink *link, AVFilterSamplesRef *samplesref)
> +{
> +    AVFilterLink *out = NULL;
> +
> +    if(link->dst->output_count)
> +        out = link->dst->outputs[0];
> +
> +    if(out) {
> +        out->out_samples = avfilter_default_get_samples_ref(link, AV_PERM_WRITE, samplesref->size,
> +                                                            samplesref->channel_layout,
> +                                                            samplesref->sample_fmt, samplesref->planar);
> +        out->out_samples->pts            = samplesref->pts;
> +        out->out_samples->sample_rate    = samplesref->sample_rate;
> +        avfilter_filter_samples(out, avfilter_ref_samples(out->out_samples, ~0));
> +    }
> +}
> +
>  /**
>   * default config_link() implementation for output video links to simplify
>   * the implementation of one input one output video filters */
> @@ -157,6 +240,7 @@ void avfilter_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
>  
>      if(!count) {
>          av_free(formats->formats);
> +        av_free(formats->aformats);
>          av_free(formats->refs);
>          av_free(formats);
>      }
> @@ -183,8 +267,21 @@ void avfilter_null_end_frame(AVFilterLink *link)
>      avfilter_end_frame(link->dst->outputs[0]);
>  }
>  
> +void avfilter_null_filter_samples(AVFilterLink *link, AVFilterSamplesRef *samplesref)
> +{
> +    avfilter_filter_samples(link->dst->outputs[0], samplesref);
> +}
> +
>  AVFilterPicRef *avfilter_null_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
>  {
>      return avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h);
>  }
>  
> +AVFilterSamplesRef *avfilter_null_get_samples_ref(AVFilterLink *link, int perms, int size,
> +                                                   int64_t channel_layout,
> +                                                   enum SampleFormat sample_fmt, int packed)
> +{
> +    return avfilter_get_samples_ref(link->dst->outputs[0], perms, size,
> +                                     channel_layout, sample_fmt, packed);
> +}
> +
> diff --git a/libavfilter/formats.c b/libavfilter/formats.c
> index 2a9bdb0..822c5e9 100644
> --- a/libavfilter/formats.c
> +++ b/libavfilter/formats.c
> @@ -36,9 +36,17 @@ static void merge_ref(AVFilterFormats *ret, AVFilterFormats *a)
>  
>      av_free(a->refs);
>      av_free(a->formats);
> +    av_free(a->aformats);
>      av_free(a);
>  }
>  


> +#define CMP_AND_ADD(acount, bcount, afmt, bfmt, retfmt) { \
> +    for(i = 0; i < acount; i++) \
> +        for(j = 0; j < bcount; j++) \
> +            if(afmt[i] == bfmt[j]) \
> +                retfmt[k++] = afmt[i]; \
> +}        
> +
>  AVFilterFormats *avfilter_merge_formats(AVFilterFormats *a, AVFilterFormats *b)
>  {
>      AVFilterFormats *ret;
> @@ -46,13 +54,19 @@ AVFilterFormats *avfilter_merge_formats(AVFilterFormats *a, AVFilterFormats *b)
>  
>      ret = av_mallocz(sizeof(AVFilterFormats));
>  
> -    /* merge list of formats */
> -    ret->formats = av_malloc(sizeof(*ret->formats) * FFMIN(a->format_count,
> +    if(a->type == AVMEDIA_TYPE_VIDEO) {
> +        /* merge list of formats */
> +        ret->formats = av_malloc(sizeof(*ret->formats) * FFMIN(a->format_count,
> +                                                           b->format_count));
> +        ret->type = AVMEDIA_TYPE_VIDEO;         
> +        CMP_AND_ADD(a->format_count, b->format_count, a->formats, b->formats, ret->formats);
> +    } else if(a->type == AVMEDIA_TYPE_AUDIO) {
> +        /* merge list of formats */
> +        ret->aformats = av_malloc(sizeof(*ret->aformats) * FFMIN(a->format_count,
>                                                             b->format_count));
> -    for(i = 0; i < a->format_count; i ++)
> -        for(j = 0; j < b->format_count; j ++)
> -            if(a->formats[i] == b->formats[j])
> -                ret->formats[k++] = a->formats[i];
> +        CMP_AND_ADD(a->format_count, b->format_count, a->aformats, b->aformats, ret->aformats);

This refactoring is nice but please split it in a separate patch (and
separate thread).

> +        ret->type = AVMEDIA_TYPE_AUDIO;         
> +    }
>  
>      ret->format_count = k;
>      /* check that there was at least one common format */
> @@ -81,6 +95,7 @@ AVFilterFormats *avfilter_make_format_list(const enum PixelFormat *pix_fmts)
>      formats               = av_mallocz(sizeof(AVFilterFormats));
>      formats->formats      = av_malloc(sizeof(*formats->formats) * count);
>      formats->format_count = count;
> +    formats->type = AVMEDIA_TYPE_VIDEO;
>      memcpy(formats->formats, pix_fmts, sizeof(*formats->formats) * count);
>  
>      return formats;
> @@ -115,6 +130,53 @@ AVFilterFormats *avfilter_all_colorspaces(void)
>      return ret;
>  }
>  
> +AVFilterFormats *avfilter_make_aformat_list(const enum SampleFormat *sample_fmts)
> +{
> +    AVFilterFormats *formats;
> +    int count;
> +
> +    for (count = 0; sample_fmts[count] != SAMPLE_FMT_NONE; count++)
> +        ;
> +
> +    formats               = av_mallocz(sizeof(AVFilterFormats));
> +    formats->aformats     = av_malloc(sizeof(*formats->aformats) * count);
> +    formats->format_count = count;
> +    formats->type = AVMEDIA_TYPE_AUDIO;
> +    memcpy(formats->aformats, sample_fmts, sizeof(*formats->aformats) * count);
> +
> +    return formats;
> +}
> +
> +int avfilter_add_sampleformat(AVFilterFormats **avff, enum SampleFormat sample_fmt)
> +{
> +    enum SampleFormat *sample_fmts;
> +
> +    if (!(*avff) && !(*avff = av_mallocz(sizeof(AVFilterFormats))))
> +        return AVERROR(ENOMEM);
> +
> +    sample_fmts = av_realloc((*avff)->aformats,
> +                          sizeof((*avff)->aformats) * ((*avff)->format_count+1));
> +    if (!sample_fmts)
> +        return AVERROR(ENOMEM);
> +
> +    (*avff)->aformats = sample_fmts;
> +    (*avff)->aformats[(*avff)->format_count++] = sample_fmt;
> +    return 0;
> +}
> +
> +AVFilterFormats *avfilter_all_sampleformats(void)
> +{
> +    AVFilterFormats *ret = NULL;
> +    enum SampleFormat sample_fmt;
> +
> +    for (sample_fmt = 0; sample_fmt < SAMPLE_FMT_NB; sample_fmt++)
> +        avfilter_add_sampleformat(&ret, sample_fmt);
> +
> +    ret->type = AVMEDIA_TYPE_AUDIO;
> +
> +    return ret;
> +}
> +
>  void avfilter_formats_ref(AVFilterFormats *f, AVFilterFormats **ref)
>  {
>      *ref = f;
> @@ -146,6 +208,7 @@ void avfilter_formats_unref(AVFilterFormats **ref)
>  
>      if(!--(*ref)->refcount) {
>          av_free((*ref)->formats);
> +        av_free((*ref)->aformats);
>          av_free((*ref)->refs);
>          av_free(*ref);
>      }

Regards.
-- 
FFmpeg = Foolish and Faithless Meaningless Pitiless Enigmatic Ghost



More information about the ffmpeg-devel mailing list