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 */