Merge remote-tracking branch 'qatar/master'
[ffmpeg.git] / libavfilter / defaults.c
index 6d9003d..e71041e 100644 (file)
@@ -2,30 +2,30 @@
  * Filter layer - default implementations
  * Copyright (c) 2007 Bobby Bingham
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * 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.
  *
- * Libav is distributed in the hope that it will be useful,
+ * 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 Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/avassert.h"
 #include "libavutil/audioconvert.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/samplefmt.h"
 #include "avfilter.h"
 #include "internal.h"
 
-/* TODO: buffer pool.  see comment for avfilter_default_get_video_buffer() */
 void ff_avfilter_default_free_buffer(AVFilterBuffer *ptr)
 {
     av_free(ptr->data[0]);
@@ -39,10 +39,35 @@ AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int per
 {
     int linesize[4];
     uint8_t *data[4];
+    int i;
     AVFilterBufferRef *picref = NULL;
+    AVFilterPool *pool = link->pool;
+
+    if (pool) {
+        for (i = 0; i < POOL_SIZE; i++) {
+            picref = pool->pic[i];
+            if (picref && picref->buf->format == link->format && picref->buf->w == w && picref->buf->h == h) {
+                AVFilterBuffer *pic = picref->buf;
+                pool->pic[i] = NULL;
+                pool->count--;
+                picref->video->w = w;
+                picref->video->h = h;
+                picref->perms = perms | AV_PERM_READ;
+                picref->format = link->format;
+                pic->refcount = 1;
+                memcpy(picref->data,     pic->data,     sizeof(picref->data));
+                memcpy(picref->linesize, pic->linesize, sizeof(picref->linesize));
+                pool->refcount++;
+                return picref;
+            }
+        }
+    } else {
+        pool = link->pool = av_mallocz(sizeof(AVFilterPool));
+        pool->refcount = 1;
+    }
 
-    // +2 is needed for swscaler, +16 to be SIMD-friendly
-    if (av_image_alloc(data, linesize, w, h, link->format, 16) < 0)
+    // align: +2 is needed for swscaler, +16 to be SIMD-friendly
+    if ((i = av_image_alloc(data, linesize, w, h, link->format, 32)) < 0)
         return NULL;
 
     picref = avfilter_get_video_buffer_ref_from_arrays(data, linesize,
@@ -51,86 +76,45 @@ AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int per
         av_free(data[0]);
         return NULL;
     }
+    memset(data[0], 128, i);
+
+    picref->buf->priv = pool;
+    picref->buf->free = NULL;
+    pool->refcount++;
 
     return picref;
 }
 
 AVFilterBufferRef *avfilter_default_get_audio_buffer(AVFilterLink *link, int perms,
-                                                     enum AVSampleFormat sample_fmt, int size,
-                                                     uint64_t channel_layout, int planar)
+                                                     int nb_samples)
 {
-    AVFilterBuffer *samples = av_mallocz(sizeof(AVFilterBuffer));
-    AVFilterBufferRef *ref = NULL;
-    int i, sample_size, chans_nb, bufsize, per_channel_size, step_size = 0;
-    char *buf;
-
-    if (!samples || !(ref = av_mallocz(sizeof(AVFilterBufferRef))))
-        goto fail;
-
-    ref->buf                   = samples;
-    ref->format                = sample_fmt;
-
-    ref->audio = av_mallocz(sizeof(AVFilterBufferRefAudioProps));
-    if (!ref->audio)
-        goto fail;
-
-    ref->audio->channel_layout = channel_layout;
-    ref->audio->size           = size;
-    ref->audio->planar         = planar;
-
-    /* make sure the buffer gets read permission or it's useless for output */
-    ref->perms = perms | AV_PERM_READ;
-
-    samples->refcount   = 1;
-    samples->free       = ff_avfilter_default_free_buffer;
+    AVFilterBufferRef *samplesref = NULL;
+    int linesize[8] = {0};
+    uint8_t *data[8] = {0};
+    int ch, nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
 
-    sample_size = av_get_bytes_per_sample(sample_fmt);
-    chans_nb = av_get_channel_layout_nb_channels(channel_layout);
-
-    per_channel_size = size/chans_nb;
-    ref->audio->nb_samples = 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 < chans_nb; i++)
-        samples->linesize[i] = planar > 0 ? per_channel_size : sample_size;
-    memset(&samples->linesize[chans_nb], 0, (8-chans_nb) * sizeof(samples->linesize[0]));
+    /* right now we don't support more than 8 channels */
+    av_assert0(nb_channels <= 8);
 
     /* Calculate total buffer size, round to multiple of 16 to be SIMD friendly */
-    bufsize = (size + 15)&~15;
-    buf = av_malloc(bufsize);
-    if (!buf)
-        goto fail;
-
-    /* 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
-     */
-    samples->data[0] = buf;
-    if (buf && planar) {
-        for (i = 1; i < chans_nb; i++) {
-            step_size += per_channel_size;
-            samples->data[i] = buf + step_size;
-        }
-    } else {
-        for (i = 1; i < chans_nb; i++)
-            samples->data[i] = buf;
-    }
-
-    memset(&samples->data[chans_nb], 0, (8-chans_nb) * sizeof(samples->data[0]));
-
-    memcpy(ref->data,     samples->data,     sizeof(ref->data));
-    memcpy(ref->linesize, samples->linesize, sizeof(ref->linesize));
+    if (av_samples_alloc(data, linesize,
+                         nb_channels, nb_samples,
+                         av_get_alt_sample_fmt(link->format, link->planar),
+                         16) < 0)
+        return NULL;
 
-    return ref;
+    for (ch = 1; link->planar && ch < nb_channels; ch++)
+        linesize[ch] = linesize[0];
+    samplesref =
+        avfilter_get_audio_buffer_ref_from_arrays(data, linesize, perms,
+                                                  nb_samples, link->format,
+                                                  link->channel_layout, link->planar);
+    if (!samplesref) {
+        av_free(data[0]);
+        return NULL;
+    }
 
-fail:
-    if (ref)
-        av_free(ref->audio);
-    av_free(ref);
-    av_free(samples);
-    return NULL;
+    return samplesref;
 }
 
 void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
@@ -186,10 +170,8 @@ void avfilter_default_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *sa
         outlink = inlink->dst->outputs[0];
 
     if (outlink) {
-        outlink->out_buf = avfilter_default_get_audio_buffer(inlink, AV_PERM_WRITE, samplesref->format,
-                                                             samplesref->audio->size,
-                                                             samplesref->audio->channel_layout,
-                                                             samplesref->audio->planar);
+        outlink->out_buf = avfilter_default_get_audio_buffer(inlink, AV_PERM_WRITE,
+                                                             samplesref->audio->nb_samples);
         outlink->out_buf->pts                = samplesref->pts;
         outlink->out_buf->audio->sample_rate = samplesref->audio->sample_rate;
         avfilter_filter_samples(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
@@ -200,68 +182,62 @@ void avfilter_default_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *sa
     inlink->cur_buf = NULL;
 }
 
-/**
- * default config_link() implementation for output video links to simplify
- * the implementation of one input one output video filters */
-int avfilter_default_config_output_link(AVFilterLink *link)
+static void set_common_formats(AVFilterContext *ctx, AVFilterFormats *fmts,
+                               enum AVMediaType type, int offin, int offout)
 {
-    if (link->src->input_count && link->src->inputs[0]) {
-        if (link->type == AVMEDIA_TYPE_VIDEO) {
-            link->w = link->src->inputs[0]->w;
-            link->h = link->src->inputs[0]->h;
-            link->time_base = link->src->inputs[0]->time_base;
-        } else if (link->type == AVMEDIA_TYPE_AUDIO) {
-            link->channel_layout = link->src->inputs[0]->channel_layout;
-            link->sample_rate    = link->src->inputs[0]->sample_rate;
-        }
-    } else {
-        /* XXX: any non-simple filter which would cause this branch to be taken
-         * really should implement its own config_props() for this link. */
-        return -1;
+    int i;
+    for (i = 0; i < ctx->input_count; i++)
+        if (ctx->inputs[i] && ctx->inputs[i]->type == type)
+            avfilter_formats_ref(fmts,
+                                 (AVFilterFormats **)((uint8_t *)ctx->inputs[i]+offout));
+
+    for (i = 0; i < ctx->output_count; i++)
+        if (ctx->outputs[i] && ctx->outputs[i]->type == type)
+            avfilter_formats_ref(fmts,
+                                 (AVFilterFormats **)((uint8_t *)ctx->outputs[i]+offin));
+
+    if (!fmts->refcount) {
+        av_free(fmts->formats);
+        av_free(fmts->refs);
+        av_free(fmts);
     }
+}
 
-    return 0;
+void avfilter_set_common_pixel_formats(AVFilterContext *ctx, AVFilterFormats *formats)
+{
+    set_common_formats(ctx, formats, AVMEDIA_TYPE_VIDEO,
+                       offsetof(AVFilterLink, in_formats),
+                       offsetof(AVFilterLink, out_formats));
 }
 
-/**
- * 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
- * freed.
- *
- * FIXME: this will need changed for filters with a mix of pad types
- * (video + audio, etc)
- */
-void avfilter_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
+void avfilter_set_common_sample_formats(AVFilterContext *ctx, AVFilterFormats *formats)
 {
-    int count = 0, i;
+    set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
+                       offsetof(AVFilterLink, in_formats),
+                       offsetof(AVFilterLink, out_formats));
+}
 
-    for (i = 0; i < ctx->input_count; i++) {
-        if (ctx->inputs[i]) {
-            avfilter_formats_ref(formats, &ctx->inputs[i]->out_formats);
-            count++;
-        }
-    }
-    for (i = 0; i < ctx->output_count; i++) {
-        if (ctx->outputs[i]) {
-            avfilter_formats_ref(formats, &ctx->outputs[i]->in_formats);
-            count++;
-        }
-    }
+void avfilter_set_common_channel_layouts(AVFilterContext *ctx, AVFilterFormats *formats)
+{
+    set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
+                       offsetof(AVFilterLink, in_chlayouts),
+                       offsetof(AVFilterLink, out_chlayouts));
+}
 
-    if (!count) {
-        av_free(formats->formats);
-        av_free(formats->refs);
-        av_free(formats);
-    }
+void avfilter_set_common_packing_formats(AVFilterContext *ctx, AVFilterFormats *formats)
+{
+    set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
+                       offsetof(AVFilterLink, in_packing),
+                       offsetof(AVFilterLink, out_packing));
 }
 
 int avfilter_default_query_formats(AVFilterContext *ctx)
 {
-    enum AVMediaType type = ctx->inputs  && ctx->inputs [0] ? ctx->inputs [0]->type :
-                            ctx->outputs && ctx->outputs[0] ? ctx->outputs[0]->type :
-                            AVMEDIA_TYPE_VIDEO;
+    avfilter_set_common_pixel_formats(ctx, avfilter_make_all_formats(AVMEDIA_TYPE_VIDEO));
+    avfilter_set_common_sample_formats(ctx, avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO));
+    avfilter_set_common_channel_layouts(ctx, avfilter_make_all_channel_layouts());
+    avfilter_set_common_packing_formats(ctx, avfilter_make_all_packing_formats());
 
-    avfilter_set_common_formats(ctx, avfilter_all_formats(type));
     return 0;
 }
 
@@ -291,9 +267,7 @@ AVFilterBufferRef *avfilter_null_get_video_buffer(AVFilterLink *link, int perms,
 }
 
 AVFilterBufferRef *avfilter_null_get_audio_buffer(AVFilterLink *link, int perms,
-                                                  enum AVSampleFormat sample_fmt, int size,
-                                                  uint64_t channel_layout, int packed)
+                                                  int nb_samples)
 {
-    return avfilter_get_audio_buffer(link->dst->outputs[0], perms, sample_fmt,
-                                     size, channel_layout, packed);
+    return avfilter_get_audio_buffer(link->dst->outputs[0], perms, nb_samples);
 }