FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_pullup.c
Go to the documentation of this file.
1 /*
2  * This file is part of MPlayer.
3  *
4  * MPlayer is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * MPlayer is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #include "config.h"
24 #include "mp_msg.h"
25 #include "cpudetect.h"
26 
27 #include "img_format.h"
28 #include "mp_image.h"
29 #include "vf.h"
30 
31 #include "libvo/fastmemcpy.h"
32 
33 #include "pullup.h"
34 
35 #undef MAX
36 #define MAX(a,b) ((a)>(b)?(a):(b))
37 
38 struct vf_priv_s {
40  int init;
41  int fakecount;
42  char *qbuf;
43 };
44 
45 static void init_pullup(struct vf_instance *vf, mp_image_t *mpi)
46 {
47  struct pullup_context *c = vf->priv->ctx;
48 
49  if (mpi->flags & MP_IMGFLAG_PLANAR) {
50  c->format = PULLUP_FMT_Y;
51  c->nplanes = 4;
53  c->bpp[0] = c->bpp[1] = c->bpp[2] = 8;
54  c->w[0] = mpi->w;
55  c->h[0] = mpi->h;
56  c->w[1] = c->w[2] = mpi->chroma_width;
57  c->h[1] = c->h[2] = mpi->chroma_height;
58  c->w[3] = ((mpi->w+15)/16) * ((mpi->h+15)/16);
59  c->h[3] = 2;
60  c->stride[0] = mpi->width;
61  c->stride[1] = c->stride[2] = mpi->chroma_width;
62  c->stride[3] = c->w[3];
63  c->background[1] = c->background[2] = 128;
64  }
65 
72 
74 
75  vf->priv->init = 1;
76  vf->priv->qbuf = malloc(c->w[3]);
77 }
78 
79 
80 #if 0
81 static void get_image(struct vf_instance *vf, mp_image_t *mpi)
82 {
83  struct pullup_context *c = vf->priv->ctx;
84  struct pullup_buffer *b;
85 
86  if (mpi->type == MP_IMGTYPE_STATIC) return;
87 
88  if (!vf->priv->init) init_pullup(vf, mpi);
89 
90  b = ff_pullup_get_buffer(c, 2);
91  if (!b) return; /* shouldn't happen... */
92 
93  mpi->priv = b;
94 
95  mpi->planes[0] = b->planes[0];
96  mpi->planes[1] = b->planes[1];
97  mpi->planes[2] = b->planes[2];
98  mpi->stride[0] = c->stride[0];
99  mpi->stride[1] = c->stride[1];
100  mpi->stride[2] = c->stride[2];
101 
102  mpi->flags |= MP_IMGFLAG_DIRECT;
104 }
105 #endif
106 
107 static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts)
108 {
109  struct pullup_context *c = vf->priv->ctx;
110  struct pullup_buffer *b;
111  struct pullup_frame *f;
112  mp_image_t *dmpi;
113  int ret;
114  int p;
115  int i;
116 
117  if (!vf->priv->init) init_pullup(vf, mpi);
118 
119  if (mpi->flags & MP_IMGFLAG_DIRECT) {
120  b = mpi->priv;
121  mpi->priv = 0;
122  } else {
123  b = ff_pullup_get_buffer(c, 2);
124  if (!b) {
125  ff_mp_msg(MSGT_VFILTER,MSGL_ERR,"Could not get buffer from pullup!\n");
126  f = ff_pullup_get_frame(c);
128  return 0;
129  }
130  memcpy_pic(b->planes[0], mpi->planes[0], mpi->w, mpi->h,
131  c->stride[0], mpi->stride[0]);
132  if (mpi->flags & MP_IMGFLAG_PLANAR) {
133  memcpy_pic(b->planes[1], mpi->planes[1],
134  mpi->chroma_width, mpi->chroma_height,
135  c->stride[1], mpi->stride[1]);
136  memcpy_pic(b->planes[2], mpi->planes[2],
137  mpi->chroma_width, mpi->chroma_height,
138  c->stride[2], mpi->stride[2]);
139  }
140  }
141  if (mpi->qscale) {
142  fast_memcpy(b->planes[3], mpi->qscale, c->w[3]);
143  fast_memcpy(b->planes[3]+c->w[3], mpi->qscale, c->w[3]);
144  }
145 
146  p = mpi->fields & MP_IMGFIELD_TOP_FIRST ? 0 :
147  (mpi->fields & MP_IMGFIELD_ORDERED ? 1 : 0);
148  ff_pullup_submit_field(c, b, p);
149  ff_pullup_submit_field(c, b, p^1);
150  if (mpi->fields & MP_IMGFIELD_REPEAT_FIRST)
151  ff_pullup_submit_field(c, b, p);
152 
154 
155  f = ff_pullup_get_frame(c);
156 
157  /* Fake yes for first few frames (buffer depth) to keep from
158  * breaking A/V sync with G1's bad architecture... */
159  if (!f) return vf->priv->fakecount ? (--vf->priv->fakecount,1) : 0;
160 
161  if (f->length < 2) {
163  f = ff_pullup_get_frame(c);
164  if (!f) return 0;
165  if (f->length < 2) {
167  if (!(mpi->fields & MP_IMGFIELD_REPEAT_FIRST))
168  return 0;
169  f = ff_pullup_get_frame(c);
170  if (!f) return 0;
171  if (f->length < 2) {
173  return 0;
174  }
175  }
176  }
177 
178 #if 0
179  /* Average qscale tables from both frames. */
180  if (mpi->qscale) {
181  for (i=0; i<c->w[3]; i++) {
182  vf->priv->qbuf[i] = (f->ofields[0]->planes[3][i]
183  + f->ofields[1]->planes[3][i+c->w[3]])>>1;
184  }
185  }
186 #else
187  /* Take worst of qscale tables from both frames. */
188  if (mpi->qscale) {
189  for (i=0; i<c->w[3]; i++) {
190  vf->priv->qbuf[i] = MAX(f->ofields[0]->planes[3][i], f->ofields[1]->planes[3][i+c->w[3]]);
191  }
192  }
193 #endif
194 
195  /* If the frame isn't already exportable... */
196  while (!f->buffer) {
197  dmpi = ff_vf_get_image(vf->next, mpi->imgfmt,
199  mpi->width, mpi->height);
200  /* FIXME: Is it ok to discard dmpi if it's not direct? */
201  if (!(dmpi->flags & MP_IMGFLAG_DIRECT)) {
202  ff_pullup_pack_frame(c, f);
203  break;
204  }
205  /* Direct render fields into output buffer */
206  my_memcpy_pic(dmpi->planes[0], f->ofields[0]->planes[0],
207  mpi->w, mpi->h/2, dmpi->stride[0]*2, c->stride[0]*2);
208  my_memcpy_pic(dmpi->planes[0] + dmpi->stride[0],
209  f->ofields[1]->planes[0] + c->stride[0],
210  mpi->w, mpi->h/2, dmpi->stride[0]*2, c->stride[0]*2);
211  if (mpi->flags & MP_IMGFLAG_PLANAR) {
212  my_memcpy_pic(dmpi->planes[1], f->ofields[0]->planes[1],
213  mpi->chroma_width, mpi->chroma_height/2,
214  dmpi->stride[1]*2, c->stride[1]*2);
215  my_memcpy_pic(dmpi->planes[1] + dmpi->stride[1],
216  f->ofields[1]->planes[1] + c->stride[1],
217  mpi->chroma_width, mpi->chroma_height/2,
218  dmpi->stride[1]*2, c->stride[1]*2);
219  my_memcpy_pic(dmpi->planes[2], f->ofields[0]->planes[2],
220  mpi->chroma_width, mpi->chroma_height/2,
221  dmpi->stride[2]*2, c->stride[2]*2);
222  my_memcpy_pic(dmpi->planes[2] + dmpi->stride[2],
223  f->ofields[1]->planes[2] + c->stride[2],
224  mpi->chroma_width, mpi->chroma_height/2,
225  dmpi->stride[2]*2, c->stride[2]*2);
226  }
228  if (mpi->qscale) {
229  dmpi->qscale = vf->priv->qbuf;
230  dmpi->qstride = mpi->qstride;
231  dmpi->qscale_type = mpi->qscale_type;
232  }
233  return ff_vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
234  }
235  dmpi = ff_vf_get_image(vf->next, mpi->imgfmt,
237  mpi->width, mpi->height);
238 
239  dmpi->planes[0] = f->buffer->planes[0];
240  dmpi->planes[1] = f->buffer->planes[1];
241  dmpi->planes[2] = f->buffer->planes[2];
242 
243  dmpi->stride[0] = c->stride[0];
244  dmpi->stride[1] = c->stride[1];
245  dmpi->stride[2] = c->stride[2];
246 
247  if (mpi->qscale) {
248  dmpi->qscale = vf->priv->qbuf;
249  dmpi->qstride = mpi->qstride;
250  dmpi->qscale_type = mpi->qscale_type;
251  }
252  ret = ff_vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE);
254  return ret;
255 }
256 
257 static int query_format(struct vf_instance *vf, unsigned int fmt)
258 {
259  /* FIXME - support more formats */
260  switch (fmt) {
261  case IMGFMT_YV12:
262  case IMGFMT_IYUV:
263  case IMGFMT_I420:
264  return ff_vf_next_query_format(vf, fmt);
265  }
266  return 0;
267 }
268 
269 static int config(struct vf_instance *vf,
270  int width, int height, int d_width, int d_height,
271  unsigned int flags, unsigned int outfmt)
272 {
273  if (height&3) {
274  ff_mp_msg(MSGT_VFILTER, MSGL_ERR, "height must be divisible by four\n");
275  return 0;
276  }
277  return ff_vf_next_config(vf, width, height, d_width, d_height, flags, outfmt);
278 }
279 
280 static void uninit(struct vf_instance *vf)
281 {
282  ff_pullup_free_context(vf->priv->ctx);
283  free(vf->priv);
284 }
285 
286 static int vf_open(vf_instance_t *vf, char *args)
287 {
288  struct vf_priv_s *p;
289  struct pullup_context *c;
290  //vf->get_image = get_image;
291  vf->put_image = put_image;
292  vf->config = config;
294  vf->uninit = uninit;
296  vf->priv = p = calloc(1, sizeof(struct vf_priv_s));
297  p->ctx = c = ff_pullup_alloc_context();
298  p->fakecount = 1;
299  c->junk_left = c->junk_right = 1;
300  c->junk_top = c->junk_bottom = 4;
301  c->strict_breaks = 0;
302  c->metric_plane = 0;
303  if (args) {
304  sscanf(args, "%d:%d:%d:%d:%d:%d", &c->junk_left, &c->junk_right, &c->junk_top, &c->junk_bottom, &c->strict_breaks, &c->metric_plane);
305  }
306  return 1;
307 }
308 
310  "pullup (from field sequence to frames)",
311  "pullup",
312  "Rich Felker",
313  "",
314  vf_open,
315  NULL
316 };