comparison libmpcodecs/vf_lavfi.c @ 34102:dd8320c2a2cb

libmpcodec: add vf_lavfi. This filter wraps a complete libavfilter filter graph. As the API of libavfilter is not completely stable yet, the filter is not enabled by default, so as not to let mplayer unbuildable. Some strange behaviours may appear due to the very different model of buffer allocation between mplayer and lavfi.
author cigaes
date Wed, 12 Oct 2011 11:38:10 +0000
parents
children a93891202051
comparison
equal deleted inserted replaced
34101:bffc842649c2 34102:dd8320c2a2cb
1 /*
2 * Copyright (C) 2011 Nicolas George <nicolas.george@normalesup.org>
3 *
4 * This file is part of MPlayer.
5 *
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "vf.h"
22 #include "m_struct.h"
23 #include "fmt-conversion.h"
24 #include "libavfilter/avfilter.h"
25 #include "libavfilter/avfiltergraph.h"
26 #include "libavutil/pixdesc.h"
27
28 struct vf_priv_s {
29 AVFilterGraph *graph;
30 AVFilterContext *in;
31 AVFilterContext *out;
32 int in_w;
33 int in_h;
34 enum PixelFormat in_pixfmt;
35 int in_imgfmt;
36 AVRational in_sar;
37 int out_w;
38 int out_h;
39 enum PixelFormat out_pixfmt;
40 int out_imgfmt;
41 AVRational out_sar;
42 struct AVFilterBufferRef *in_buf;
43 mp_image_t *in_mpi;
44 };
45
46 static void buf_mpi_free(AVFilterBuffer *buf)
47 {
48 ((mp_image_t *)buf->priv)->usage_count--;
49 av_free(buf);
50 }
51
52 static AVFilterBufferRef *mpi_to_bufref(mp_image_t *mpi, enum PixelFormat fmt,
53 AVRational sar)
54 {
55 AVFilterBufferRef *buf;
56 int perms = AV_PERM_READ;
57
58 if ((mpi->flags & MP_IMGFLAG_ALLOCATED))
59 perms |= AV_PERM_REUSE2;
60 if (!(mpi->flags & MP_IMGFLAG_PRESERVE))
61 perms |= AV_PERM_WRITE;
62 buf = avfilter_get_video_buffer_ref_from_arrays(mpi->planes, mpi->stride,
63 perms,
64 mpi->w, mpi->h,
65 fmt);
66 buf->video->sample_aspect_ratio = sar;
67 buf->buf->priv = mpi;
68 buf->buf->free = buf_mpi_free;
69 return buf;
70 }
71
72 static void bufref_to_mpi(AVFilterBufferRef *ref, mp_image_t *mpi)
73 {
74 memcpy(mpi->planes, ref->data, sizeof(ref->data));
75 memcpy(mpi->stride, ref->linesize, sizeof(ref->linesize));
76 }
77
78 struct mpsink_priv {
79 struct vf_instance *vf;
80 };
81
82 static int mpsink_init(AVFilterContext *ctx,
83 av_unused const char *args, void *opaque)
84 {
85 struct mpsink_priv *c = ctx->priv;
86 c->vf = opaque;
87 return 0;
88 }
89
90 static int mpsink_query_formats(AVFilterContext *ctx)
91 {
92 struct mpsink_priv *c = ctx->priv;
93 struct vf_instance *vf = c->vf;
94 AVFilterFormats *all;
95 enum PixelFormat *sup;
96 unsigned i, nsup = 0;
97 int ifmt;
98
99 all = avfilter_all_formats(AVMEDIA_TYPE_VIDEO);
100 sup = av_mallocz(sizeof(*sup) * (all->format_count + 1));
101 if (!sup)
102 return AVERROR(errno);
103 for(i = 0; i < all->format_count; i++) {
104 ifmt = pixfmt2imgfmt(all->formats[i]);
105 if (vf->next->query_format(vf->next, ifmt) > 0)
106 sup[nsup++] = all->formats[i];
107 }
108 sup[nsup++] = PIX_FMT_NONE;
109 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(sup));
110 av_free(sup);
111 return 0;
112 }
113
114 static AVFilterBufferRef *mpsink_get_video_buffer(AVFilterLink *link,
115 int perms, int w, int h)
116 {
117 struct mpsink_priv *c = link->dst->priv;
118 struct vf_instance *vf = c->vf;
119 mp_image_t *dmpi;
120 int type;
121 int flags = 0;
122
123 type = MP_IMGTYPE_NUMBERED | (-1 << 16);
124 if ((perms & AV_PERM_PRESERVE))
125 flags |= MP_IMGFLAG_PRESERVE;
126 if ((perms & AV_PERM_READ))
127 flags |= MP_IMGFLAG_READABLE;
128 if ((perms & AV_PERM_NEG_LINESIZES))
129 flags |= MP_IMGFLAG_ACCEPT_STRIDE;
130 if (vf->priv->in_mpi) {
131 type = vf->priv->in_mpi->type;
132 vf->priv->in_mpi = NULL;
133 }
134 dmpi = vf_get_image(vf->next, vf->priv->out_imgfmt, type, flags, w, h);
135 return mpi_to_bufref(dmpi, vf->priv->out_pixfmt, vf->priv->out_sar);
136 }
137
138 static void mpsink_end_frame(AVFilterLink *link)
139 {
140 struct mpsink_priv *c = link->dst->priv;
141 struct vf_instance *vf = c->vf;
142 AVFilterBufferRef *buf = link->cur_buf;
143 mp_image_t *mpi = buf->buf->priv;
144 double pts;
145
146 pts = buf->pts == (int64_t)AV_NOPTS_VALUE ? MP_NOPTS_VALUE :
147 buf->pts * av_q2d(link->time_base);
148 mpi->pict_type = buf->video->pict_type;
149 mpi->fields = (buf->video->interlaced ? MP_IMGFIELD_INTERLACED : 0) |
150 (buf->video->top_field_first ? MP_IMGFIELD_TOP_FIRST : 0);
151 vf_next_put_image(vf, mpi, pts);
152 avfilter_unref_buffer(link->cur_buf);
153 }
154
155 static AVFilter mpsink = {
156 .name = "mpsink",
157 .description = "Video sink for mplayer interaction",
158 .priv_size = sizeof(struct mpsink_priv),
159
160 .init = mpsink_init,
161 .query_formats = mpsink_query_formats,
162
163 .inputs = (AVFilterPad[]) {{ .name = "default",
164 .type = AVMEDIA_TYPE_VIDEO,
165 .end_frame = mpsink_end_frame,
166 .get_video_buffer = mpsink_get_video_buffer,
167 .min_perms = AV_PERM_READ, },
168 { .name = NULL }},
169 .outputs = (AVFilterPad[]) {{ .name = NULL }},
170 };
171
172 struct mpsrc_priv {
173 struct vf_instance *vf;
174 };
175
176 static int mpsrc_init(AVFilterContext *ctx,
177 av_unused const char *args, void *opaque)
178 {
179 struct mpsrc_priv *c = ctx->priv;
180 c->vf = opaque;
181 return 0;
182 }
183
184 static int mpsrc_query_formats(AVFilterContext *ctx)
185 {
186 struct mpsrc_priv *c = ctx->priv;
187 enum PixelFormat pix_fmts[] = { c->vf->priv->in_pixfmt, PIX_FMT_NONE };
188 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
189 return 0;
190 }
191
192 static int mpsrc_config_props(AVFilterLink *link)
193 {
194 struct mpsrc_priv *c = link->src->priv;
195 struct vf_instance *vf = c->vf;
196 link->w = vf->priv->in_w;
197 link->h = vf->priv->in_h;
198 link->sample_aspect_ratio = vf->priv->in_sar;
199 link->time_base = AV_TIME_BASE_Q;
200 return 0;
201 }
202
203 static int mpsrc_request_frame(AVFilterLink *link)
204 {
205 struct mpsrc_priv *c = link->src->priv;
206 struct vf_instance *vf = c->vf;
207
208 if (!vf->priv->in_buf)
209 return AVERROR(EINVAL);
210 avfilter_start_frame(link, avfilter_ref_buffer(vf->priv->in_buf, ~0));
211 avfilter_draw_slice(link, 0, link->h, 1);
212 avfilter_end_frame(link);
213 vf->priv->in_buf = NULL;
214 return 0;
215 }
216
217 static int mpsrc_poll_frame(AVFilterLink *link)
218 {
219 struct mpsrc_priv *c = link->src->priv;
220 struct vf_instance *vf = c->vf;
221 return vf->priv->in_buf != NULL;
222 }
223
224 AVFilter mpsrc = {
225 .name = "mpsrc",
226 .description = "Video source for mplayer interaction",
227 .priv_size = sizeof(struct mpsrc_priv),
228 .query_formats = mpsrc_query_formats,
229
230 .init = mpsrc_init,
231
232 .inputs = (AVFilterPad[]) {{ .name = NULL }},
233 .outputs = (AVFilterPad[]) {{ .name = "default",
234 .type = AVMEDIA_TYPE_VIDEO,
235 .request_frame = mpsrc_request_frame,
236 .poll_frame = mpsrc_poll_frame,
237 .config_props = mpsrc_config_props, },
238 { .name = NULL }},
239 };
240
241 static int config(struct vf_instance *vf, int w, int h, int dw, int dh,
242 unsigned flags, unsigned fmt)
243 {
244 int ret;
245 AVFilterLink *out;
246 AVRational iar, dar;
247
248 av_reduce(&iar.num, &iar.den, w, h, INT_MAX);
249 av_reduce(&dar.num, &dar.den, dw, dh, INT_MAX);
250 vf->priv->in_pixfmt = imgfmt2pixfmt(fmt);
251 vf->priv->in_imgfmt = fmt;
252 vf->priv->in_w = w;
253 vf->priv->in_h = h;
254 vf->priv->in_sar = av_div_q(dar, iar);
255 ret = avfilter_graph_config(vf->priv->graph, NULL);
256 if (ret < 0)
257 return 0;
258 out = vf->priv->out->inputs[0];
259 vf->priv->out_w = out->w;
260 vf->priv->out_h = out->h;
261 vf->priv->out_pixfmt = out->format;
262 vf->priv->out_imgfmt = pixfmt2imgfmt(out->format);
263 vf->priv->out_sar = out->sample_aspect_ratio;
264 if (vf->priv->out_sar.num != vf->priv->in_sar.num ||
265 vf->priv->out_sar.den != vf->priv->in_sar.den ||
266 out->w != w || out->h != h) {
267 av_reduce(&iar.num, &iar.den, out->w, out->h, INT_MAX);
268 dar = av_mul_q(iar, out->sample_aspect_ratio);
269 if (av_cmp_q(dar, iar) >= 0) {
270 dh = out->h;
271 dw = av_rescale(dh, dar.num, dar.den);
272 } else {
273 dw = out->w;
274 dh = av_rescale(dw, dar.den, dar.num);
275 }
276 }
277 return vf_next_config(vf, out->w, out->h, dw, dh, flags, fmt);
278 }
279
280 static void get_image(struct vf_instance *vf, mp_image_t *mpi)
281 {
282 AVFilterBufferRef *buf;
283 unsigned perms = AV_PERM_WRITE | AV_PERM_REUSE2;
284
285 avfilter_unref_buffer(mpi->priv);
286 mpi->priv = NULL; /* for safety */
287 if (mpi->flags & MP_IMGFLAG_READABLE)
288 perms |= AV_PERM_READ;
289 if (mpi->flags & MP_IMGFLAG_PRESERVE)
290 perms |= AV_PERM_PRESERVE;
291 vf->priv->in_mpi = mpi;
292 buf = avfilter_get_video_buffer(vf->priv->in->outputs[0], perms,
293 mpi->w, mpi->h);
294 vf->priv->in_mpi = NULL;
295 bufref_to_mpi(buf, mpi);
296 mpi->flags |= MP_IMGFLAG_DIRECT;
297 mpi->flags &= ~MP_IMGFLAG_ALLOCATED;
298 mpi->priv = buf;
299 }
300
301 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
302 {
303 AVFilterBufferRef *buf;
304 mp_image_t *cmpi = NULL;
305
306 if (!(mpi->flags & MP_IMGFLAG_DIRECT)) {
307 cmpi = vf_get_image(vf, mpi->imgfmt, MP_IMGTYPE_TEMP,
308 MP_IMGFLAG_PREFER_ALIGNED_STRIDE,
309 mpi->w, mpi->h);
310 copy_mpi(cmpi, mpi);
311 buf = cmpi->priv;
312 } else {
313 buf = mpi->priv;
314 }
315 buf->video->key_frame = mpi->pict_type == 1;
316 buf->video->pict_type = mpi->pict_type; /* seems to be the same code */
317 buf->video->interlaced = !!(mpi->fields & MP_IMGFIELD_INTERLACED);
318 buf->video->top_field_first = !!(mpi->fields & MP_IMGFIELD_TOP_FIRST);
319 vf->priv->in_buf = buf;
320 if (pts != MP_NOPTS_VALUE)
321 buf->pts = pts * AV_TIME_BASE;
322 while (avfilter_poll_frame(vf->priv->out->inputs[0])) {
323 if (avfilter_request_frame(vf->priv->out->inputs[0]))
324 break;
325 }
326 return 1;
327 }
328
329 static void uninit(struct vf_instance *vf)
330 {
331 unsigned i;
332
333 #define FREE_MPI_ARRAY(field) \
334 for (i = 0; i < FF_ARRAY_ELEMS(vf->imgctx.field); i++) \
335 if (vf->imgctx.field[i]) \
336 avfilter_unref_buffer(vf->imgctx.field[i]->priv);
337 FREE_MPI_ARRAY(static_images);
338 FREE_MPI_ARRAY(temp_images);
339 FREE_MPI_ARRAY(export_images);
340 FREE_MPI_ARRAY(numbered_images);
341 avfilter_graph_free(&vf->priv->graph);
342 av_free(vf->priv);
343 }
344
345 static int lavfi_open(struct vf_instance *vf, char *args)
346 {
347 AVFilterInOut *outputs;
348 AVFilterInOut *inputs;
349 int ret;
350
351 avfilter_register_all();
352 if (!args) {
353 mp_msg(MSGT_VFILTER, MSGL_ERR, "lavfi: filtergraph needed\n");
354 goto fail;
355 }
356 if (args[0] == '$') {
357 char *e = getenv(args + 1);
358 if (!e) {
359 mp_msg(MSGT_VFILTER, MSGL_ERR, "lavfi: %s not defined\n", args);
360 goto fail;
361 }
362 args = e;
363 }
364 vf->priv = av_mallocz(sizeof(struct vf_priv_s));
365 if (!vf->priv)
366 return 0;
367
368 vf->priv->graph = avfilter_graph_alloc();
369 if (!vf->priv->graph)
370 goto fail;
371 ret = avfilter_graph_create_filter(&vf->priv->in, &mpsrc, "in",
372 NULL, vf, vf->priv->graph);
373 if (ret < 0)
374 goto fail;
375 ret = avfilter_graph_create_filter(&vf->priv->out, &mpsink, "out",
376 NULL, vf, vf->priv->graph);
377 if (ret < 0)
378 return 0;
379 outputs = avfilter_inout_alloc();
380 inputs = avfilter_inout_alloc();
381 if (!outputs || !inputs)
382 goto fail;
383 outputs->name = av_strdup("in");
384 outputs->filter_ctx = vf->priv->in;
385 outputs->pad_idx = 0;
386 outputs->next = NULL;
387 inputs->name = av_strdup("out");
388 inputs->filter_ctx = vf->priv->out;
389 inputs->pad_idx = 0;
390 inputs->next = NULL;
391 ret = avfilter_graph_parse(vf->priv->graph, args, &inputs, &outputs, NULL);
392 if (ret < 0)
393 goto fail;
394
395 vf->config = config;
396 vf->uninit = uninit;
397 vf->put_image = put_image;
398 vf->get_image = get_image;
399 return 1;
400
401 fail:
402 avfilter_inout_free(&inputs);
403 avfilter_inout_free(&outputs);
404 avfilter_graph_free(&vf->priv->graph);
405 av_free(vf->priv);
406 return 0;
407 }
408
409 static const m_option_t vf_opts_fields[] = { { .name = NULL } };
410
411 const vf_info_t vf_info_lavfi = {
412 "libavfilter wrapper",
413 "lavfi",
414 "Nicolas George",
415 "",
416 lavfi_open,
417 NULL,
418 };