libavfilter/sink_buffer.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Stefano Sabatini
00003  *
00004  * This file is part of FFmpeg.
00005  *
00006  * FFmpeg is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * FFmpeg is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with FFmpeg; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00026 #include "libavutil/fifo.h"
00027 #include "avfilter.h"
00028 #include "buffersink.h"
00029 #include "internal.h"
00030 
00031 AVBufferSinkParams *av_buffersink_params_alloc(void)
00032 {
00033     static const int pixel_fmts[] = { -1 };
00034     AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
00035     if (!params)
00036         return NULL;
00037 
00038     params->pixel_fmts = pixel_fmts;
00039     return params;
00040 }
00041 
00042 AVABufferSinkParams *av_abuffersink_params_alloc(void)
00043 {
00044     static const int sample_fmts[] = { -1 };
00045     static const int packing_fmts[] = { -1 };
00046     static const int64_t channel_layouts[] = { -1 };
00047     AVABufferSinkParams *params = av_malloc(sizeof(AVABufferSinkParams));
00048 
00049     if (!params)
00050         return NULL;
00051 
00052     params->sample_fmts = sample_fmts;
00053     params->channel_layouts = channel_layouts;
00054     params->packing_fmts = packing_fmts;
00055     return params;
00056 }
00057 
00058 typedef struct {
00059     AVFifoBuffer *fifo;                      
00060 
00061     /* only used for video */
00062     enum PixelFormat *pixel_fmts;           
00063 
00064     /* only used for audio */
00065     enum AVSampleFormat *sample_fmts;       
00066     int64_t *channel_layouts;               
00067     int *packing_fmts;                      
00068 } BufferSinkContext;
00069 
00070 #define FIFO_INIT_SIZE 8
00071 
00072 static av_cold int common_init(AVFilterContext *ctx)
00073 {
00074     BufferSinkContext *buf = ctx->priv;
00075 
00076     buf->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef *));
00077     if (!buf->fifo) {
00078         av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
00079         return AVERROR(ENOMEM);
00080     }
00081     return 0;
00082 }
00083 
00084 static av_cold void common_uninit(AVFilterContext *ctx)
00085 {
00086     BufferSinkContext *buf = ctx->priv;
00087     AVFilterBufferRef *picref;
00088 
00089     if (buf->fifo) {
00090         while (av_fifo_size(buf->fifo) >= sizeof(AVFilterBufferRef *)) {
00091             av_fifo_generic_read(buf->fifo, &picref, sizeof(picref), NULL);
00092             avfilter_unref_buffer(picref);
00093         }
00094         av_fifo_free(buf->fifo);
00095         buf->fifo = NULL;
00096     }
00097 }
00098 
00099 static void end_frame(AVFilterLink *inlink)
00100 {
00101     AVFilterContext *ctx = inlink->dst;
00102     BufferSinkContext *buf = inlink->dst->priv;
00103 
00104     if (av_fifo_space(buf->fifo) < sizeof(AVFilterBufferRef *)) {
00105         /* realloc fifo size */
00106         if (av_fifo_realloc2(buf->fifo, av_fifo_size(buf->fifo) * 2) < 0) {
00107             av_log(ctx, AV_LOG_ERROR,
00108                    "Cannot buffer more frames. Consume some available frames "
00109                    "before adding new ones.\n");
00110             return;
00111         }
00112     }
00113 
00114     /* cache frame */
00115     av_fifo_generic_write(buf->fifo,
00116                           &inlink->cur_buf, sizeof(AVFilterBufferRef *), NULL);
00117 }
00118 
00119 int av_buffersink_get_buffer_ref(AVFilterContext *ctx,
00120                                   AVFilterBufferRef **bufref, int flags)
00121 {
00122     BufferSinkContext *buf = ctx->priv;
00123     AVFilterLink *inlink = ctx->inputs[0];
00124     int ret;
00125     *bufref = NULL;
00126 
00127     /* no picref available, fetch it from the filterchain */
00128     if (!av_fifo_size(buf->fifo)) {
00129         if ((ret = avfilter_request_frame(inlink)) < 0)
00130             return ret;
00131     }
00132 
00133     if (!av_fifo_size(buf->fifo))
00134         return AVERROR(EINVAL);
00135 
00136     if (flags & AV_BUFFERSINK_FLAG_PEEK)
00137         *bufref = *((AVFilterBufferRef **)av_fifo_peek2(buf->fifo, 0));
00138     else
00139         av_fifo_generic_read(buf->fifo, bufref, sizeof(*bufref), NULL);
00140 
00141     return 0;
00142 }
00143 
00144 int av_buffersink_poll_frame(AVFilterContext *ctx)
00145 {
00146     BufferSinkContext *buf = ctx->priv;
00147     AVFilterLink *inlink = ctx->inputs[0];
00148 
00149     return av_fifo_size(buf->fifo)/sizeof(AVFilterBufferRef *) + avfilter_poll_frame(inlink);
00150 }
00151 
00152 #if FF_API_OLD_VSINK_API
00153 int av_vsink_buffer_get_video_buffer_ref(AVFilterContext *ctx,
00154                                          AVFilterBufferRef **picref, int flags)
00155 {
00156     return av_buffersink_get_buffer_ref(ctx, picref, flags);
00157 }
00158 #endif
00159 
00160 #if CONFIG_BUFFERSINK_FILTER
00161 
00162 static av_cold int vsink_init(AVFilterContext *ctx, const char *args, void *opaque)
00163 {
00164     BufferSinkContext *buf = ctx->priv;
00165     av_unused AVBufferSinkParams *params;
00166 
00167     if (!opaque) {
00168         av_log(ctx, AV_LOG_ERROR,
00169                "No opaque field provided\n");
00170         return AVERROR(EINVAL);
00171     } else {
00172 #if FF_API_OLD_VSINK_API
00173         const int *pixel_fmts = (const enum PixelFormat *)opaque;
00174 #else
00175         params = (AVBufferSinkParams *)opaque;
00176         const int *pixel_fmts = params->pixel_fmts;
00177 #endif
00178         buf->pixel_fmts = ff_copy_int_list(pixel_fmts);
00179         if (!buf->pixel_fmts)
00180             return AVERROR(ENOMEM);
00181     }
00182 
00183     return common_init(ctx);
00184 }
00185 
00186 static av_cold void vsink_uninit(AVFilterContext *ctx)
00187 {
00188     BufferSinkContext *buf = ctx->priv;
00189     av_freep(&buf->pixel_fmts);
00190     return common_uninit(ctx);
00191 }
00192 
00193 static int vsink_query_formats(AVFilterContext *ctx)
00194 {
00195     BufferSinkContext *buf = ctx->priv;
00196 
00197     avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(buf->pixel_fmts));
00198     return 0;
00199 }
00200 
00201 AVFilter avfilter_vsink_buffersink = {
00202     .name      = "buffersink",
00203     .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
00204     .priv_size = sizeof(BufferSinkContext),
00205     .init      = vsink_init,
00206     .uninit    = vsink_uninit,
00207 
00208     .query_formats = vsink_query_formats,
00209 
00210     .inputs    = (const AVFilterPad[]) {{ .name    = "default",
00211                                     .type          = AVMEDIA_TYPE_VIDEO,
00212                                     .end_frame     = end_frame,
00213                                     .min_perms     = AV_PERM_READ, },
00214                                   { .name = NULL }},
00215     .outputs   = (const AVFilterPad[]) {{ .name = NULL }},
00216 };
00217 
00218 #endif /* CONFIG_BUFFERSINK_FILTER */
00219 
00220 #if CONFIG_ABUFFERSINK_FILTER
00221 
00222 static void filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
00223 {
00224     end_frame(link);
00225 }
00226 
00227 static av_cold int asink_init(AVFilterContext *ctx, const char *args, void *opaque)
00228 {
00229     BufferSinkContext *buf = ctx->priv;
00230     AVABufferSinkParams *params;
00231 
00232     if (!opaque) {
00233         av_log(ctx, AV_LOG_ERROR,
00234                "No opaque field provided, an AVABufferSinkParams struct is required\n");
00235         return AVERROR(EINVAL);
00236     } else
00237         params = (AVABufferSinkParams *)opaque;
00238 
00239     buf->sample_fmts     = ff_copy_int_list  (params->sample_fmts);
00240     buf->channel_layouts = ff_copy_int64_list(params->channel_layouts);
00241     buf->packing_fmts    = ff_copy_int_list  (params->packing_fmts);
00242     if (!buf->sample_fmts || !buf->channel_layouts || !buf->sample_fmts) {
00243         av_freep(&buf->sample_fmts);
00244         av_freep(&buf->channel_layouts);
00245         av_freep(&buf->packing_fmts);
00246         return AVERROR(ENOMEM);
00247     }
00248 
00249     return common_init(ctx);
00250 }
00251 
00252 static av_cold void asink_uninit(AVFilterContext *ctx)
00253 {
00254     BufferSinkContext *buf = ctx->priv;
00255 
00256     av_freep(&buf->sample_fmts);
00257     av_freep(&buf->channel_layouts);
00258     av_freep(&buf->packing_fmts);
00259     return common_uninit(ctx);
00260 }
00261 
00262 static int asink_query_formats(AVFilterContext *ctx)
00263 {
00264     BufferSinkContext *buf = ctx->priv;
00265     AVFilterFormats *formats = NULL;
00266 
00267     if (!(formats = avfilter_make_format_list(buf->sample_fmts)))
00268         return AVERROR(ENOMEM);
00269     avfilter_set_common_sample_formats(ctx, formats);
00270 
00271     if (!(formats = avfilter_make_format64_list(buf->channel_layouts)))
00272         return AVERROR(ENOMEM);
00273     avfilter_set_common_channel_layouts(ctx, formats);
00274 
00275     if (!(formats = avfilter_make_format_list(buf->packing_fmts)))
00276         return AVERROR(ENOMEM);
00277     avfilter_set_common_packing_formats(ctx, formats);
00278 
00279     return 0;
00280 }
00281 
00282 AVFilter avfilter_asink_abuffersink = {
00283     .name      = "abuffersink",
00284     .description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
00285     .init      = asink_init,
00286     .uninit    = asink_uninit,
00287     .priv_size = sizeof(BufferSinkContext),
00288     .query_formats = asink_query_formats,
00289 
00290     .inputs    = (const AVFilterPad[]) {{ .name     = "default",
00291                                     .type           = AVMEDIA_TYPE_AUDIO,
00292                                     .filter_samples = filter_samples,
00293                                     .min_perms      = AV_PERM_READ, },
00294                                   { .name = NULL }},
00295     .outputs   = (const AVFilterPad[]) {{ .name = NULL }},
00296 };
00297 
00298 #endif /* CONFIG_ABUFFERSINK_FILTER */