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