Mercurial > mplayer.hg
annotate libmpcodecs/vf_lavfi.c @ 34341:946ecaf41dc1
Don't allow option gui-include in config files.
This option may only be evaluated after MPlayer has called cfg_read()
or a segmentation fault occurs. Prevent this by restricting its usage.
author | ib |
---|---|
date | Sun, 11 Dec 2011 14:54:56 +0000 |
parents | a93891202051 |
children | b6191f9936ec |
rev | line source |
---|---|
34102 | 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" | |
34174
a93891202051
Add missing mp_msg.h #includes, remove some unnecessary ones.
diego
parents:
34102
diff
changeset
|
24 #include "mp_msg.h" |
34102 | 25 #include "libavfilter/avfilter.h" |
26 #include "libavfilter/avfiltergraph.h" | |
27 #include "libavutil/pixdesc.h" | |
28 | |
29 struct vf_priv_s { | |
30 AVFilterGraph *graph; | |
31 AVFilterContext *in; | |
32 AVFilterContext *out; | |
33 int in_w; | |
34 int in_h; | |
35 enum PixelFormat in_pixfmt; | |
36 int in_imgfmt; | |
37 AVRational in_sar; | |
38 int out_w; | |
39 int out_h; | |
40 enum PixelFormat out_pixfmt; | |
41 int out_imgfmt; | |
42 AVRational out_sar; | |
43 struct AVFilterBufferRef *in_buf; | |
44 mp_image_t *in_mpi; | |
45 }; | |
46 | |
47 static void buf_mpi_free(AVFilterBuffer *buf) | |
48 { | |
49 ((mp_image_t *)buf->priv)->usage_count--; | |
50 av_free(buf); | |
51 } | |
52 | |
53 static AVFilterBufferRef *mpi_to_bufref(mp_image_t *mpi, enum PixelFormat fmt, | |
54 AVRational sar) | |
55 { | |
56 AVFilterBufferRef *buf; | |
57 int perms = AV_PERM_READ; | |
58 | |
59 if ((mpi->flags & MP_IMGFLAG_ALLOCATED)) | |
60 perms |= AV_PERM_REUSE2; | |
61 if (!(mpi->flags & MP_IMGFLAG_PRESERVE)) | |
62 perms |= AV_PERM_WRITE; | |
63 buf = avfilter_get_video_buffer_ref_from_arrays(mpi->planes, mpi->stride, | |
64 perms, | |
65 mpi->w, mpi->h, | |
66 fmt); | |
67 buf->video->sample_aspect_ratio = sar; | |
68 buf->buf->priv = mpi; | |
69 buf->buf->free = buf_mpi_free; | |
70 return buf; | |
71 } | |
72 | |
73 static void bufref_to_mpi(AVFilterBufferRef *ref, mp_image_t *mpi) | |
74 { | |
75 memcpy(mpi->planes, ref->data, sizeof(ref->data)); | |
76 memcpy(mpi->stride, ref->linesize, sizeof(ref->linesize)); | |
77 } | |
78 | |
79 struct mpsink_priv { | |
80 struct vf_instance *vf; | |
81 }; | |
82 | |
83 static int mpsink_init(AVFilterContext *ctx, | |
84 av_unused const char *args, void *opaque) | |
85 { | |
86 struct mpsink_priv *c = ctx->priv; | |
87 c->vf = opaque; | |
88 return 0; | |
89 } | |
90 | |
91 static int mpsink_query_formats(AVFilterContext *ctx) | |
92 { | |
93 struct mpsink_priv *c = ctx->priv; | |
94 struct vf_instance *vf = c->vf; | |
95 AVFilterFormats *all; | |
96 enum PixelFormat *sup; | |
97 unsigned i, nsup = 0; | |
98 int ifmt; | |
99 | |
100 all = avfilter_all_formats(AVMEDIA_TYPE_VIDEO); | |
101 sup = av_mallocz(sizeof(*sup) * (all->format_count + 1)); | |
102 if (!sup) | |
103 return AVERROR(errno); | |
104 for(i = 0; i < all->format_count; i++) { | |
105 ifmt = pixfmt2imgfmt(all->formats[i]); | |
106 if (vf->next->query_format(vf->next, ifmt) > 0) | |
107 sup[nsup++] = all->formats[i]; | |
108 } | |
109 sup[nsup++] = PIX_FMT_NONE; | |
110 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(sup)); | |
111 av_free(sup); | |
112 return 0; | |
113 } | |
114 | |
115 static AVFilterBufferRef *mpsink_get_video_buffer(AVFilterLink *link, | |
116 int perms, int w, int h) | |
117 { | |
118 struct mpsink_priv *c = link->dst->priv; | |
119 struct vf_instance *vf = c->vf; | |
120 mp_image_t *dmpi; | |
121 int type; | |
122 int flags = 0; | |
123 | |
124 type = MP_IMGTYPE_NUMBERED | (-1 << 16); | |
125 if ((perms & AV_PERM_PRESERVE)) | |
126 flags |= MP_IMGFLAG_PRESERVE; | |
127 if ((perms & AV_PERM_READ)) | |
128 flags |= MP_IMGFLAG_READABLE; | |
129 if ((perms & AV_PERM_NEG_LINESIZES)) | |
130 flags |= MP_IMGFLAG_ACCEPT_STRIDE; | |
131 if (vf->priv->in_mpi) { | |
132 type = vf->priv->in_mpi->type; | |
133 vf->priv->in_mpi = NULL; | |
134 } | |
135 dmpi = vf_get_image(vf->next, vf->priv->out_imgfmt, type, flags, w, h); | |
136 return mpi_to_bufref(dmpi, vf->priv->out_pixfmt, vf->priv->out_sar); | |
137 } | |
138 | |
139 static void mpsink_end_frame(AVFilterLink *link) | |
140 { | |
141 struct mpsink_priv *c = link->dst->priv; | |
142 struct vf_instance *vf = c->vf; | |
143 AVFilterBufferRef *buf = link->cur_buf; | |
144 mp_image_t *mpi = buf->buf->priv; | |
145 double pts; | |
146 | |
147 pts = buf->pts == (int64_t)AV_NOPTS_VALUE ? MP_NOPTS_VALUE : | |
148 buf->pts * av_q2d(link->time_base); | |
149 mpi->pict_type = buf->video->pict_type; | |
150 mpi->fields = (buf->video->interlaced ? MP_IMGFIELD_INTERLACED : 0) | | |
151 (buf->video->top_field_first ? MP_IMGFIELD_TOP_FIRST : 0); | |
152 vf_next_put_image(vf, mpi, pts); | |
153 avfilter_unref_buffer(link->cur_buf); | |
154 } | |
155 | |
156 static AVFilter mpsink = { | |
157 .name = "mpsink", | |
158 .description = "Video sink for mplayer interaction", | |
159 .priv_size = sizeof(struct mpsink_priv), | |
160 | |
161 .init = mpsink_init, | |
162 .query_formats = mpsink_query_formats, | |
163 | |
164 .inputs = (AVFilterPad[]) {{ .name = "default", | |
165 .type = AVMEDIA_TYPE_VIDEO, | |
166 .end_frame = mpsink_end_frame, | |
167 .get_video_buffer = mpsink_get_video_buffer, | |
168 .min_perms = AV_PERM_READ, }, | |
169 { .name = NULL }}, | |
170 .outputs = (AVFilterPad[]) {{ .name = NULL }}, | |
171 }; | |
172 | |
173 struct mpsrc_priv { | |
174 struct vf_instance *vf; | |
175 }; | |
176 | |
177 static int mpsrc_init(AVFilterContext *ctx, | |
178 av_unused const char *args, void *opaque) | |
179 { | |
180 struct mpsrc_priv *c = ctx->priv; | |
181 c->vf = opaque; | |
182 return 0; | |
183 } | |
184 | |
185 static int mpsrc_query_formats(AVFilterContext *ctx) | |
186 { | |
187 struct mpsrc_priv *c = ctx->priv; | |
188 enum PixelFormat pix_fmts[] = { c->vf->priv->in_pixfmt, PIX_FMT_NONE }; | |
189 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts)); | |
190 return 0; | |
191 } | |
192 | |
193 static int mpsrc_config_props(AVFilterLink *link) | |
194 { | |
195 struct mpsrc_priv *c = link->src->priv; | |
196 struct vf_instance *vf = c->vf; | |
197 link->w = vf->priv->in_w; | |
198 link->h = vf->priv->in_h; | |
199 link->sample_aspect_ratio = vf->priv->in_sar; | |
200 link->time_base = AV_TIME_BASE_Q; | |
201 return 0; | |
202 } | |
203 | |
204 static int mpsrc_request_frame(AVFilterLink *link) | |
205 { | |
206 struct mpsrc_priv *c = link->src->priv; | |
207 struct vf_instance *vf = c->vf; | |
208 | |
209 if (!vf->priv->in_buf) | |
210 return AVERROR(EINVAL); | |
211 avfilter_start_frame(link, avfilter_ref_buffer(vf->priv->in_buf, ~0)); | |
212 avfilter_draw_slice(link, 0, link->h, 1); | |
213 avfilter_end_frame(link); | |
214 vf->priv->in_buf = NULL; | |
215 return 0; | |
216 } | |
217 | |
218 static int mpsrc_poll_frame(AVFilterLink *link) | |
219 { | |
220 struct mpsrc_priv *c = link->src->priv; | |
221 struct vf_instance *vf = c->vf; | |
222 return vf->priv->in_buf != NULL; | |
223 } | |
224 | |
225 AVFilter mpsrc = { | |
226 .name = "mpsrc", | |
227 .description = "Video source for mplayer interaction", | |
228 .priv_size = sizeof(struct mpsrc_priv), | |
229 .query_formats = mpsrc_query_formats, | |
230 | |
231 .init = mpsrc_init, | |
232 | |
233 .inputs = (AVFilterPad[]) {{ .name = NULL }}, | |
234 .outputs = (AVFilterPad[]) {{ .name = "default", | |
235 .type = AVMEDIA_TYPE_VIDEO, | |
236 .request_frame = mpsrc_request_frame, | |
237 .poll_frame = mpsrc_poll_frame, | |
238 .config_props = mpsrc_config_props, }, | |
239 { .name = NULL }}, | |
240 }; | |
241 | |
242 static int config(struct vf_instance *vf, int w, int h, int dw, int dh, | |
243 unsigned flags, unsigned fmt) | |
244 { | |
245 int ret; | |
246 AVFilterLink *out; | |
247 AVRational iar, dar; | |
248 | |
249 av_reduce(&iar.num, &iar.den, w, h, INT_MAX); | |
250 av_reduce(&dar.num, &dar.den, dw, dh, INT_MAX); | |
251 vf->priv->in_pixfmt = imgfmt2pixfmt(fmt); | |
252 vf->priv->in_imgfmt = fmt; | |
253 vf->priv->in_w = w; | |
254 vf->priv->in_h = h; | |
255 vf->priv->in_sar = av_div_q(dar, iar); | |
256 ret = avfilter_graph_config(vf->priv->graph, NULL); | |
257 if (ret < 0) | |
258 return 0; | |
259 out = vf->priv->out->inputs[0]; | |
260 vf->priv->out_w = out->w; | |
261 vf->priv->out_h = out->h; | |
262 vf->priv->out_pixfmt = out->format; | |
263 vf->priv->out_imgfmt = pixfmt2imgfmt(out->format); | |
264 vf->priv->out_sar = out->sample_aspect_ratio; | |
265 if (vf->priv->out_sar.num != vf->priv->in_sar.num || | |
266 vf->priv->out_sar.den != vf->priv->in_sar.den || | |
267 out->w != w || out->h != h) { | |
268 av_reduce(&iar.num, &iar.den, out->w, out->h, INT_MAX); | |
269 dar = av_mul_q(iar, out->sample_aspect_ratio); | |
270 if (av_cmp_q(dar, iar) >= 0) { | |
271 dh = out->h; | |
272 dw = av_rescale(dh, dar.num, dar.den); | |
273 } else { | |
274 dw = out->w; | |
275 dh = av_rescale(dw, dar.den, dar.num); | |
276 } | |
277 } | |
278 return vf_next_config(vf, out->w, out->h, dw, dh, flags, fmt); | |
279 } | |
280 | |
281 static void get_image(struct vf_instance *vf, mp_image_t *mpi) | |
282 { | |
283 AVFilterBufferRef *buf; | |
284 unsigned perms = AV_PERM_WRITE | AV_PERM_REUSE2; | |
285 | |
286 avfilter_unref_buffer(mpi->priv); | |
287 mpi->priv = NULL; /* for safety */ | |
288 if (mpi->flags & MP_IMGFLAG_READABLE) | |
289 perms |= AV_PERM_READ; | |
290 if (mpi->flags & MP_IMGFLAG_PRESERVE) | |
291 perms |= AV_PERM_PRESERVE; | |
292 vf->priv->in_mpi = mpi; | |
293 buf = avfilter_get_video_buffer(vf->priv->in->outputs[0], perms, | |
294 mpi->w, mpi->h); | |
295 vf->priv->in_mpi = NULL; | |
296 bufref_to_mpi(buf, mpi); | |
297 mpi->flags |= MP_IMGFLAG_DIRECT; | |
298 mpi->flags &= ~MP_IMGFLAG_ALLOCATED; | |
299 mpi->priv = buf; | |
300 } | |
301 | |
302 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |
303 { | |
304 AVFilterBufferRef *buf; | |
305 mp_image_t *cmpi = NULL; | |
306 | |
307 if (!(mpi->flags & MP_IMGFLAG_DIRECT)) { | |
308 cmpi = vf_get_image(vf, mpi->imgfmt, MP_IMGTYPE_TEMP, | |
309 MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |
310 mpi->w, mpi->h); | |
311 copy_mpi(cmpi, mpi); | |
312 buf = cmpi->priv; | |
313 } else { | |
314 buf = mpi->priv; | |
315 } | |
316 buf->video->key_frame = mpi->pict_type == 1; | |
317 buf->video->pict_type = mpi->pict_type; /* seems to be the same code */ | |
318 buf->video->interlaced = !!(mpi->fields & MP_IMGFIELD_INTERLACED); | |
319 buf->video->top_field_first = !!(mpi->fields & MP_IMGFIELD_TOP_FIRST); | |
320 vf->priv->in_buf = buf; | |
321 if (pts != MP_NOPTS_VALUE) | |
322 buf->pts = pts * AV_TIME_BASE; | |
323 while (avfilter_poll_frame(vf->priv->out->inputs[0])) { | |
324 if (avfilter_request_frame(vf->priv->out->inputs[0])) | |
325 break; | |
326 } | |
327 return 1; | |
328 } | |
329 | |
330 static void uninit(struct vf_instance *vf) | |
331 { | |
332 unsigned i; | |
333 | |
334 #define FREE_MPI_ARRAY(field) \ | |
335 for (i = 0; i < FF_ARRAY_ELEMS(vf->imgctx.field); i++) \ | |
336 if (vf->imgctx.field[i]) \ | |
337 avfilter_unref_buffer(vf->imgctx.field[i]->priv); | |
338 FREE_MPI_ARRAY(static_images); | |
339 FREE_MPI_ARRAY(temp_images); | |
340 FREE_MPI_ARRAY(export_images); | |
341 FREE_MPI_ARRAY(numbered_images); | |
342 avfilter_graph_free(&vf->priv->graph); | |
343 av_free(vf->priv); | |
344 } | |
345 | |
346 static int lavfi_open(struct vf_instance *vf, char *args) | |
347 { | |
348 AVFilterInOut *outputs; | |
349 AVFilterInOut *inputs; | |
350 int ret; | |
351 | |
352 avfilter_register_all(); | |
353 if (!args) { | |
354 mp_msg(MSGT_VFILTER, MSGL_ERR, "lavfi: filtergraph needed\n"); | |
355 goto fail; | |
356 } | |
357 if (args[0] == '$') { | |
358 char *e = getenv(args + 1); | |
359 if (!e) { | |
360 mp_msg(MSGT_VFILTER, MSGL_ERR, "lavfi: %s not defined\n", args); | |
361 goto fail; | |
362 } | |
363 args = e; | |
364 } | |
365 vf->priv = av_mallocz(sizeof(struct vf_priv_s)); | |
366 if (!vf->priv) | |
367 return 0; | |
368 | |
369 vf->priv->graph = avfilter_graph_alloc(); | |
370 if (!vf->priv->graph) | |
371 goto fail; | |
372 ret = avfilter_graph_create_filter(&vf->priv->in, &mpsrc, "in", | |
373 NULL, vf, vf->priv->graph); | |
374 if (ret < 0) | |
375 goto fail; | |
376 ret = avfilter_graph_create_filter(&vf->priv->out, &mpsink, "out", | |
377 NULL, vf, vf->priv->graph); | |
378 if (ret < 0) | |
379 return 0; | |
380 outputs = avfilter_inout_alloc(); | |
381 inputs = avfilter_inout_alloc(); | |
382 if (!outputs || !inputs) | |
383 goto fail; | |
384 outputs->name = av_strdup("in"); | |
385 outputs->filter_ctx = vf->priv->in; | |
386 outputs->pad_idx = 0; | |
387 outputs->next = NULL; | |
388 inputs->name = av_strdup("out"); | |
389 inputs->filter_ctx = vf->priv->out; | |
390 inputs->pad_idx = 0; | |
391 inputs->next = NULL; | |
392 ret = avfilter_graph_parse(vf->priv->graph, args, &inputs, &outputs, NULL); | |
393 if (ret < 0) | |
394 goto fail; | |
395 | |
396 vf->config = config; | |
397 vf->uninit = uninit; | |
398 vf->put_image = put_image; | |
399 vf->get_image = get_image; | |
400 return 1; | |
401 | |
402 fail: | |
403 avfilter_inout_free(&inputs); | |
404 avfilter_inout_free(&outputs); | |
405 avfilter_graph_free(&vf->priv->graph); | |
406 av_free(vf->priv); | |
407 return 0; | |
408 } | |
409 | |
410 static const m_option_t vf_opts_fields[] = { { .name = NULL } }; | |
411 | |
412 const vf_info_t vf_info_lavfi = { | |
413 "libavfilter wrapper", | |
414 "lavfi", | |
415 "Nicolas George", | |
416 "", | |
417 lavfi_open, | |
418 NULL, | |
419 }; |