[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