00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include "avfilter.h"
00027 #include "buffersrc.h"
00028 #include "vsrc_buffer.h"
00029 #include "libavutil/imgutils.h"
00030
00031 typedef struct {
00032 AVFilterBufferRef *buf;
00033 int h, w;
00034 enum PixelFormat pix_fmt;
00035 AVRational time_base;
00036 AVRational pixel_aspect;
00037 } BufferSourceContext;
00038
00039 #define CHECK_PARAM_CHANGE(s, c, width, height, format)\
00040 if (c->w != width || c->h != height || c->pix_fmt != format) {\
00041 av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\
00042 return AVERROR(EINVAL);\
00043 }
00044
00045 int av_vsrc_buffer_add_frame(AVFilterContext *buffer_filter, AVFrame *frame,
00046 int64_t pts, AVRational pixel_aspect)
00047 {
00048 BufferSourceContext *c = buffer_filter->priv;
00049
00050 if (c->buf) {
00051 av_log(buffer_filter, AV_LOG_ERROR,
00052 "Buffering several frames is not supported. "
00053 "Please consume all available frames before adding a new one.\n"
00054 );
00055
00056 }
00057
00058 CHECK_PARAM_CHANGE(buffer_filter, c, frame->width, frame->height, frame->format);
00059
00060 c->buf = avfilter_get_video_buffer(buffer_filter->outputs[0], AV_PERM_WRITE,
00061 c->w, c->h);
00062 av_image_copy(c->buf->data, c->buf->linesize, frame->data, frame->linesize,
00063 c->pix_fmt, c->w, c->h);
00064
00065 avfilter_copy_frame_props(c->buf, frame);
00066 c->buf->pts = pts;
00067 c->buf->video->pixel_aspect = pixel_aspect;
00068
00069 return 0;
00070 }
00071
00072 int av_buffersrc_buffer(AVFilterContext *s, AVFilterBufferRef *buf)
00073 {
00074 BufferSourceContext *c = s->priv;
00075
00076 if (c->buf) {
00077 av_log(s, AV_LOG_ERROR,
00078 "Buffering several frames is not supported. "
00079 "Please consume all available frames before adding a new one.\n"
00080 );
00081 return AVERROR(EINVAL);
00082 }
00083
00084 CHECK_PARAM_CHANGE(s, c, buf->video->w, buf->video->h, buf->format);
00085
00086 c->buf = buf;
00087
00088 return 0;
00089 }
00090
00091 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
00092 {
00093 BufferSourceContext *c = ctx->priv;
00094 char pix_fmt_str[128];
00095 int n = 0;
00096
00097 if (!args ||
00098 (n = sscanf(args, "%d:%d:%127[^:]:%d:%d:%d:%d", &c->w, &c->h, pix_fmt_str,
00099 &c->time_base.num, &c->time_base.den,
00100 &c->pixel_aspect.num, &c->pixel_aspect.den)) != 7) {
00101 av_log(ctx, AV_LOG_ERROR, "Expected 7 arguments, but %d found in '%s'\n", n, args);
00102 return AVERROR(EINVAL);
00103 }
00104 if ((c->pix_fmt = av_get_pix_fmt(pix_fmt_str)) == PIX_FMT_NONE) {
00105 char *tail;
00106 c->pix_fmt = strtol(pix_fmt_str, &tail, 10);
00107 if (*tail || c->pix_fmt < 0 || c->pix_fmt >= PIX_FMT_NB) {
00108 av_log(ctx, AV_LOG_ERROR, "Invalid pixel format string '%s'\n", pix_fmt_str);
00109 return AVERROR(EINVAL);
00110 }
00111 }
00112
00113 av_log(ctx, AV_LOG_INFO, "w:%d h:%d pixfmt:%s\n", c->w, c->h, av_pix_fmt_descriptors[c->pix_fmt].name);
00114 return 0;
00115 }
00116
00117 static av_cold void uninit(AVFilterContext *ctx)
00118 {
00119 BufferSourceContext *s = ctx->priv;
00120 if (s->buf)
00121 avfilter_unref_buffer(s->buf);
00122 s->buf = NULL;
00123 }
00124
00125 static int query_formats(AVFilterContext *ctx)
00126 {
00127 BufferSourceContext *c = ctx->priv;
00128 enum PixelFormat pix_fmts[] = { c->pix_fmt, PIX_FMT_NONE };
00129
00130 avfilter_set_common_formats(ctx, avfilter_make_format_list(pix_fmts));
00131 return 0;
00132 }
00133
00134 static int config_props(AVFilterLink *link)
00135 {
00136 BufferSourceContext *c = link->src->priv;
00137
00138 link->w = c->w;
00139 link->h = c->h;
00140 link->sample_aspect_ratio = c->pixel_aspect;
00141 link->time_base = c->time_base;
00142
00143 return 0;
00144 }
00145
00146 static int request_frame(AVFilterLink *link)
00147 {
00148 BufferSourceContext *c = link->src->priv;
00149
00150 if (!c->buf) {
00151 av_log(link->src, AV_LOG_ERROR,
00152 "request_frame() called with no available frame!\n");
00153
00154 }
00155
00156 avfilter_start_frame(link, avfilter_ref_buffer(c->buf, ~0));
00157 avfilter_draw_slice(link, 0, link->h, 1);
00158 avfilter_end_frame(link);
00159 avfilter_unref_buffer(c->buf);
00160 c->buf = NULL;
00161
00162 return 0;
00163 }
00164
00165 static int poll_frame(AVFilterLink *link)
00166 {
00167 BufferSourceContext *c = link->src->priv;
00168 return !!c->buf;
00169 }
00170
00171 AVFilter avfilter_vsrc_buffer = {
00172 .name = "buffer",
00173 .description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."),
00174 .priv_size = sizeof(BufferSourceContext),
00175 .query_formats = query_formats,
00176
00177 .init = init,
00178 .uninit = uninit,
00179
00180 .inputs = (AVFilterPad[]) {{ .name = NULL }},
00181 .outputs = (AVFilterPad[]) {{ .name = "default",
00182 .type = AVMEDIA_TYPE_VIDEO,
00183 .request_frame = request_frame,
00184 .poll_frame = poll_frame,
00185 .config_props = config_props, },
00186 { .name = NULL}},
00187 };