FFmpeg
vf_tinterlace.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017 Thomas Mundt <tmundt75@gmail.com>
3  * Copyright (c) 2011 Stefano Sabatini
4  * Copyright (c) 2010 Baptiste Coudurier
5  * Copyright (c) 2003 Michael Zucchi <notzed@ximian.com>
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with FFmpeg if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 /**
25  * @file
26  * temporal field interlace filter, ported from MPlayer/libmpcodecs
27  */
28 
29 #include "libavutil/opt.h"
30 #include "libavutil/imgutils.h"
31 #include "libavutil/avassert.h"
32 #include "avfilter.h"
33 #include "internal.h"
34 #include "tinterlace.h"
35 
36 #define OFFSET(x) offsetof(TInterlaceContext, x)
37 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
38 
39 static const AVOption tinterlace_options[] = {
40  {"mode", "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB-1, FLAGS, "mode"},
41  {"merge", "merge fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE}, INT_MIN, INT_MAX, FLAGS, "mode"},
42  {"drop_even", "drop even fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN}, INT_MIN, INT_MAX, FLAGS, "mode"},
43  {"drop_odd", "drop odd fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD}, INT_MIN, INT_MAX, FLAGS, "mode"},
44  {"pad", "pad alternate lines with black", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD}, INT_MIN, INT_MAX, FLAGS, "mode"},
45  {"interleave_top", "interleave top and bottom fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP}, INT_MIN, INT_MAX, FLAGS, "mode"},
46  {"interleave_bottom", "interleave bottom and top fields", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "mode"},
47  {"interlacex2", "interlace fields from two consecutive frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACEX2}, INT_MIN, INT_MAX, FLAGS, "mode"},
48  {"mergex2", "merge fields keeping same frame rate", 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGEX2}, INT_MIN, INT_MAX, FLAGS, "mode"},
49 
50  {"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, "flags" },
51  {"low_pass_filter", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
52  {"vlpf", "enable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
53  {"complex_filter", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
54  {"cvlpf", "enable complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
55  {"exact_tb", "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" },
56 
57  {NULL}
58 };
59 
60 AVFILTER_DEFINE_CLASS(tinterlace);
61 
62 static const AVOption interlace_options[] = {
63  { "scan", "scanning mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_TFF}, 0, 1, FLAGS, "mode"},
64  { "tff", "top field first", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_TFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"},
65  { "bff", "bottom field first", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_BFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"},
66  { "lowpass", "set vertical low-pass filter", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = TINTERLACE_FLAG_VLPF}, 0, 2, FLAGS, "flags" },
67  { "off", "disable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, FLAGS, "flags" },
68  { "linear", "linear vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
69  { "complex", "complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
70 
71  { NULL }
72 };
73 
74 AVFILTER_DEFINE_CLASS(interlace);
75 
76 #define FULL_SCALE_YUVJ_FORMATS \
77  AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
78 
79 static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = {
81 };
82 
83 static const AVRational standard_tbs[] = {
84  {1, 25},
85  {1, 30},
86  {1001, 30000},
87 };
88 
90 {
91  static const enum AVPixelFormat pix_fmts[] = {
103  };
104 
106  if (!fmts_list)
107  return AVERROR(ENOMEM);
108  return ff_set_common_formats(ctx, fmts_list);
109 }
110 
111 static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
112  ptrdiff_t mref, ptrdiff_t pref, int clip_max)
113 {
114  const uint8_t *srcp_above = srcp + mref;
115  const uint8_t *srcp_below = srcp + pref;
116  int i;
117  for (i = 0; i < width; i++) {
118  // this calculation is an integer representation of
119  // '0.5 * current + 0.25 * above + 0.25 * below'
120  // '1 +' is for rounding.
121  dstp[i] = (1 + srcp[i] + srcp[i] + srcp_above[i] + srcp_below[i]) >> 2;
122  }
123 }
124 
125 static void lowpass_line_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8,
126  ptrdiff_t mref, ptrdiff_t pref, int clip_max)
127 {
128  uint16_t *dstp = (uint16_t *)dst8;
129  const uint16_t *srcp = (const uint16_t *)src8;
130  const uint16_t *srcp_above = srcp + mref / 2;
131  const uint16_t *srcp_below = srcp + pref / 2;
132  int i, src_x;
133  for (i = 0; i < width; i++) {
134  // this calculation is an integer representation of
135  // '0.5 * current + 0.25 * above + 0.25 * below'
136  // '1 +' is for rounding.
137  src_x = av_le2ne16(srcp[i]) << 1;
138  dstp[i] = av_le2ne16((1 + src_x + av_le2ne16(srcp_above[i])
139  + av_le2ne16(srcp_below[i])) >> 2);
140  }
141 }
142 
143 static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
144  ptrdiff_t mref, ptrdiff_t pref, int clip_max)
145 {
146  const uint8_t *srcp_above = srcp + mref;
147  const uint8_t *srcp_below = srcp + pref;
148  const uint8_t *srcp_above2 = srcp + mref * 2;
149  const uint8_t *srcp_below2 = srcp + pref * 2;
150  int i, src_x, src_ab;
151  for (i = 0; i < width; i++) {
152  // this calculation is an integer representation of
153  // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
154  // '4 +' is for rounding.
155  src_x = srcp[i] << 1;
156  src_ab = srcp_above[i] + srcp_below[i];
157  dstp[i] = av_clip_uint8((4 + ((srcp[i] + src_x + src_ab) << 1)
158  - srcp_above2[i] - srcp_below2[i]) >> 3);
159  // Prevent over-sharpening:
160  // dst must not exceed src when the average of above and below
161  // is less than src. And the other way around.
162  if (src_ab > src_x) {
163  if (dstp[i] < srcp[i])
164  dstp[i] = srcp[i];
165  } else if (dstp[i] > srcp[i])
166  dstp[i] = srcp[i];
167  }
168 }
169 
170 static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8,
171  ptrdiff_t mref, ptrdiff_t pref, int clip_max)
172 {
173  uint16_t *dstp = (uint16_t *)dst8;
174  const uint16_t *srcp = (const uint16_t *)src8;
175  const uint16_t *srcp_above = srcp + mref / 2;
176  const uint16_t *srcp_below = srcp + pref / 2;
177  const uint16_t *srcp_above2 = srcp + mref;
178  const uint16_t *srcp_below2 = srcp + pref;
179  int i, dst_le, src_le, src_x, src_ab;
180  for (i = 0; i < width; i++) {
181  // this calculation is an integer representation of
182  // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
183  // '4 +' is for rounding.
184  src_le = av_le2ne16(srcp[i]);
185  src_x = src_le << 1;
186  src_ab = av_le2ne16(srcp_above[i]) + av_le2ne16(srcp_below[i]);
187  dst_le = av_clip((4 + ((src_le + src_x + src_ab) << 1)
188  - av_le2ne16(srcp_above2[i])
189  - av_le2ne16(srcp_below2[i])) >> 3, 0, clip_max);
190  // Prevent over-sharpening:
191  // dst must not exceed src when the average of above and below
192  // is less than src. And the other way around.
193  if (src_ab > src_x) {
194  if (dst_le < src_le)
195  dstp[i] = av_le2ne16(src_le);
196  else
197  dstp[i] = av_le2ne16(dst_le);
198  } else if (dst_le > src_le) {
199  dstp[i] = av_le2ne16(src_le);
200  } else
201  dstp[i] = av_le2ne16(dst_le);
202  }
203 }
204 
206 {
207  TInterlaceContext *tinterlace = ctx->priv;
208 
209  av_frame_free(&tinterlace->cur );
210  av_frame_free(&tinterlace->next);
211  av_freep(&tinterlace->black_data[0]);
212 }
213 
214 static int config_out_props(AVFilterLink *outlink)
215 {
216  AVFilterContext *ctx = outlink->src;
217  AVFilterLink *inlink = outlink->src->inputs[0];
219  TInterlaceContext *tinterlace = ctx->priv;
220  int i;
221 
222  tinterlace->vsub = desc->log2_chroma_h;
223  outlink->w = inlink->w;
224  outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2?
225  inlink->h*2 : inlink->h;
226  if (tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2)
227  outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio,
228  av_make_q(2, 1));
229 
230  if (tinterlace->mode == MODE_PAD) {
231  uint8_t black[4] = { 0, 0, 0, 16 };
232  int ret;
233  ff_draw_init(&tinterlace->draw, outlink->format, 0);
234  ff_draw_color(&tinterlace->draw, &tinterlace->color, black);
236  tinterlace->color.comp[0].u8[0] = 0;
237  ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize,
238  outlink->w, outlink->h, outlink->format, 16);
239  if (ret < 0)
240  return ret;
241 
242  ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data,
243  tinterlace->black_linesize, 0, 0, outlink->w, outlink->h);
244  }
245  if (tinterlace->flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF)
246  && !(tinterlace->mode == MODE_INTERLEAVE_TOP
247  || tinterlace->mode == MODE_INTERLEAVE_BOTTOM)) {
248  av_log(ctx, AV_LOG_WARNING, "low_pass_filter flags ignored with mode %d\n",
249  tinterlace->mode);
251  }
252  tinterlace->preout_time_base = inlink->time_base;
253  if (tinterlace->mode == MODE_INTERLACEX2) {
254  tinterlace->preout_time_base.den *= 2;
255  outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1});
256  outlink->time_base = av_mul_q(inlink->time_base , (AVRational){1,2});
257  } else if (tinterlace->mode == MODE_MERGEX2) {
258  outlink->frame_rate = inlink->frame_rate;
259  outlink->time_base = inlink->time_base;
260  } else if (tinterlace->mode != MODE_PAD) {
261  outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
262  outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1});
263  }
264 
265  for (i = 0; i<FF_ARRAY_ELEMS(standard_tbs); i++){
266  if (!av_cmp_q(standard_tbs[i], outlink->time_base))
267  break;
268  }
269  if (i == FF_ARRAY_ELEMS(standard_tbs) ||
270  (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB))
271  outlink->time_base = tinterlace->preout_time_base;
272 
273  tinterlace->csp = av_pix_fmt_desc_get(outlink->format);
274  if (tinterlace->flags & TINTERLACE_FLAG_CVLPF) {
275  if (tinterlace->csp->comp[0].depth > 8)
277  else
278  tinterlace->lowpass_line = lowpass_line_complex_c;
279  if (ARCH_X86)
280  ff_tinterlace_init_x86(tinterlace);
281  } else if (tinterlace->flags & TINTERLACE_FLAG_VLPF) {
282  if (tinterlace->csp->comp[0].depth > 8)
283  tinterlace->lowpass_line = lowpass_line_c_16;
284  else
285  tinterlace->lowpass_line = lowpass_line_c;
286  if (ARCH_X86)
287  ff_tinterlace_init_x86(tinterlace);
288  }
289 
290  av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n", tinterlace->mode,
291  (tinterlace->flags & TINTERLACE_FLAG_CVLPF) ? "complex" :
292  (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "linear" : "off",
293  inlink->h, outlink->h);
294 
295  return 0;
296 }
297 
298 #define FIELD_UPPER 0
299 #define FIELD_LOWER 1
300 #define FIELD_UPPER_AND_LOWER 2
301 
302 /**
303  * Copy picture field from src to dst.
304  *
305  * @param src_field copy from upper, lower field or both
306  * @param interleave leave a padding line between each copied line
307  * @param dst_field copy to upper or lower field,
308  * only meaningful when interleave is selected
309  * @param flags context flags
310  */
311 static inline
313  uint8_t *dst[4], int dst_linesize[4],
314  const uint8_t *src[4], int src_linesize[4],
315  enum AVPixelFormat format, int w, int src_h,
316  int src_field, int interleave, int dst_field,
317  int flags)
318 {
320  int hsub = desc->log2_chroma_w;
321  int plane, vsub = desc->log2_chroma_h;
322  int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2;
323  int h;
324 
325  for (plane = 0; plane < desc->nb_components; plane++) {
326  int lines = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(src_h, vsub) : src_h;
327  int cols = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT( w, hsub) : w;
328  uint8_t *dstp = dst[plane];
329  const uint8_t *srcp = src[plane];
330  int srcp_linesize = src_linesize[plane] * k;
331  int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1);
332  int clip_max = (1 << tinterlace->csp->comp[plane].depth) - 1;
333 
334  lines = (lines + (src_field == FIELD_UPPER)) / k;
335  if (src_field == FIELD_LOWER)
336  srcp += src_linesize[plane];
337  if (interleave && dst_field == FIELD_LOWER)
338  dstp += dst_linesize[plane];
339  // Low-pass filtering is required when creating an interlaced destination from
340  // a progressive source which contains high-frequency vertical detail.
341  // Filtering will reduce interlace 'twitter' and Moire patterning.
343  int x = !!(flags & TINTERLACE_FLAG_CVLPF);
344  for (h = lines; h > 0; h--) {
345  ptrdiff_t pref = src_linesize[plane];
346  ptrdiff_t mref = -pref;
347  if (h >= (lines - x)) mref = 0; // there is no line above
348  else if (h <= (1 + x)) pref = 0; // there is no line below
349 
350  tinterlace->lowpass_line(dstp, cols, srcp, mref, pref, clip_max);
351  dstp += dstp_linesize;
352  srcp += srcp_linesize;
353  }
354  } else {
355  if (tinterlace->csp->comp[plane].depth > 8)
356  cols *= 2;
357  av_image_copy_plane(dstp, dstp_linesize, srcp, srcp_linesize, cols, lines);
358  }
359  }
360 }
361 
363 {
364  AVFilterContext *ctx = inlink->dst;
365  AVFilterLink *outlink = ctx->outputs[0];
366  TInterlaceContext *tinterlace = ctx->priv;
367  AVFrame *cur, *next, *out;
368  int field, tff, ret;
369 
370  av_frame_free(&tinterlace->cur);
371  tinterlace->cur = tinterlace->next;
372  tinterlace->next = picref;
373 
374  cur = tinterlace->cur;
375  next = tinterlace->next;
376  /* we need at least two frames */
377  if (!tinterlace->cur)
378  return 0;
379 
380  switch (tinterlace->mode) {
381  case MODE_MERGEX2: /* move the odd frame into the upper field of the new image, even into
382  * the lower field, generating a double-height video at same framerate */
383  case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into
384  * the lower field, generating a double-height video at half framerate */
385  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
386  if (!out)
387  return AVERROR(ENOMEM);
388  av_frame_copy_props(out, cur);
389  out->height = outlink->h;
390  out->interlaced_frame = 1;
391  out->top_field_first = 1;
392  out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
393 
394  /* write odd frame lines into the upper field of the new frame */
395  copy_picture_field(tinterlace, out->data, out->linesize,
396  (const uint8_t **)cur->data, cur->linesize,
397  inlink->format, inlink->w, inlink->h,
398  FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags);
399  /* write even frame lines into the lower field of the new frame */
400  copy_picture_field(tinterlace, out->data, out->linesize,
401  (const uint8_t **)next->data, next->linesize,
402  inlink->format, inlink->w, inlink->h,
403  FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags);
404  if (tinterlace->mode != MODE_MERGEX2)
405  av_frame_free(&tinterlace->next);
406  break;
407 
408  case MODE_DROP_ODD: /* only output even frames, odd frames are dropped; height unchanged, half framerate */
409  case MODE_DROP_EVEN: /* only output odd frames, even frames are dropped; height unchanged, half framerate */
410  out = av_frame_clone(tinterlace->mode == MODE_DROP_EVEN ? cur : next);
411  if (!out)
412  return AVERROR(ENOMEM);
413  av_frame_free(&tinterlace->next);
414  break;
415 
416  case MODE_PAD: /* expand each frame to double height, but pad alternate
417  * lines with black; framerate unchanged */
418  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
419  if (!out)
420  return AVERROR(ENOMEM);
421  av_frame_copy_props(out, cur);
422  out->height = outlink->h;
423  out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
424 
425  field = (1 + tinterlace->frame) & 1 ? FIELD_UPPER : FIELD_LOWER;
426  /* copy upper and lower fields */
427  copy_picture_field(tinterlace, out->data, out->linesize,
428  (const uint8_t **)cur->data, cur->linesize,
429  inlink->format, inlink->w, inlink->h,
430  FIELD_UPPER_AND_LOWER, 1, field, tinterlace->flags);
431  /* pad with black the other field */
432  copy_picture_field(tinterlace, out->data, out->linesize,
433  (const uint8_t **)tinterlace->black_data, tinterlace->black_linesize,
434  inlink->format, inlink->w, inlink->h,
435  FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags);
436  break;
437 
438  /* interleave upper/lower lines from odd frames with lower/upper lines from even frames,
439  * halving the frame rate and preserving image height */
440  case MODE_INTERLEAVE_TOP: /* top field first */
441  case MODE_INTERLEAVE_BOTTOM: /* bottom field first */
442  tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
443  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
444  if (!out)
445  return AVERROR(ENOMEM);
446  av_frame_copy_props(out, cur);
447  out->interlaced_frame = 1;
448  out->top_field_first = tff;
449 
450  /* copy upper/lower field from cur */
451  copy_picture_field(tinterlace, out->data, out->linesize,
452  (const uint8_t **)cur->data, cur->linesize,
453  inlink->format, inlink->w, inlink->h,
454  tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
455  tinterlace->flags);
456  /* copy lower/upper field from next */
457  copy_picture_field(tinterlace, out->data, out->linesize,
458  (const uint8_t **)next->data, next->linesize,
459  inlink->format, inlink->w, inlink->h,
460  tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
461  tinterlace->flags);
462  av_frame_free(&tinterlace->next);
463  break;
464  case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */
465  /* output current frame first */
466  out = av_frame_clone(cur);
467  if (!out)
468  return AVERROR(ENOMEM);
469  out->interlaced_frame = 1;
470  if (cur->pts != AV_NOPTS_VALUE)
471  out->pts = cur->pts*2;
472 
473  out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
474  if ((ret = ff_filter_frame(outlink, out)) < 0)
475  return ret;
476 
477  /* output mix of current and next frame */
478  tff = next->top_field_first;
479  out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
480  if (!out)
481  return AVERROR(ENOMEM);
482  av_frame_copy_props(out, next);
483  out->interlaced_frame = 1;
484  out->top_field_first = !tff;
485 
486  if (next->pts != AV_NOPTS_VALUE && cur->pts != AV_NOPTS_VALUE)
487  out->pts = cur->pts + next->pts;
488  else
489  out->pts = AV_NOPTS_VALUE;
490  /* write current frame second field lines into the second field of the new frame */
491  copy_picture_field(tinterlace, out->data, out->linesize,
492  (const uint8_t **)cur->data, cur->linesize,
493  inlink->format, inlink->w, inlink->h,
494  tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
495  tinterlace->flags);
496  /* write next frame first field lines into the first field of the new frame */
497  copy_picture_field(tinterlace, out->data, out->linesize,
498  (const uint8_t **)next->data, next->linesize,
499  inlink->format, inlink->w, inlink->h,
500  tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
501  tinterlace->flags);
502  break;
503  default:
504  av_assert0(0);
505  }
506 
507  out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
508  ret = ff_filter_frame(outlink, out);
509  tinterlace->frame++;
510 
511  return ret;
512 }
513 
515 {
516  TInterlaceContext *tinterlace = ctx->priv;
517 
518  if (tinterlace->mode <= MODE_BFF)
519  tinterlace->mode += MODE_INTERLEAVE_TOP;
520 
521  return 0;
522 }
523 
524 static const AVFilterPad tinterlace_inputs[] = {
525  {
526  .name = "default",
527  .type = AVMEDIA_TYPE_VIDEO,
528  .filter_frame = filter_frame,
529  },
530  { NULL }
531 };
532 
533 static const AVFilterPad tinterlace_outputs[] = {
534  {
535  .name = "default",
536  .type = AVMEDIA_TYPE_VIDEO,
537  .config_props = config_out_props,
538  },
539  { NULL }
540 };
541 
543  .name = "tinterlace",
544  .description = NULL_IF_CONFIG_SMALL("Perform temporal field interlacing."),
545  .priv_size = sizeof(TInterlaceContext),
546  .uninit = uninit,
550  .priv_class = &tinterlace_class,
551 };
552 
553 
555  .name = "interlace",
556  .description = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."),
557  .priv_size = sizeof(TInterlaceContext),
558  .init = init_interlace,
559  .uninit = uninit,
563  .priv_class = &interlace_class,
564 };
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:99
filter_frame
static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
Definition: vf_tinterlace.c:362
MODE_MERGE
@ MODE_MERGE
Definition: tinterlace.h:41
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
init
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
init_interlace
static int init_interlace(AVFilterContext *ctx)
Definition: vf_tinterlace.c:514
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
ff_make_format_list
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:283
out
FILE * out
Definition: movenc.c:54
standard_tbs
static const AVRational standard_tbs[]
Definition: vf_tinterlace.c:83
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1080
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2522
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
TInterlaceContext::lowpass_line
void(* lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max)
Definition: tinterlace.h:71
lowpass_line_complex_c
static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max)
Definition: vf_tinterlace.c:143
FIELD_UPPER_AND_LOWER
#define FIELD_UPPER_AND_LOWER
Definition: vf_tinterlace.c:300
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
AVFrame::pts
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:388
w
uint8_t w
Definition: llviddspenc.c:38
TInterlaceContext
Definition: tinterlace.h:57
AVComponentDescriptor::depth
int depth
Number of bits in the component.
Definition: pixdesc.h:58
TInterlaceContext::color
FFDrawColor color
Definition: tinterlace.h:69
AVOption
AVOption.
Definition: opt.h:246
TInterlaceContext::black_linesize
int black_linesize[4]
Definition: tinterlace.h:67
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
AV_PIX_FMT_YUV440P
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:99
TInterlaceContext::black_data
uint8_t * black_data[4]
buffer used to fill padded lines
Definition: tinterlace.h:66
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:148
srcp
BYTE int const BYTE * srcp
Definition: avisynth_c.h:908
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:309
av_image_copy_plane
void av_image_copy_plane(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height)
Copy image plane from src to dst.
Definition: imgutils.c:338
AVFilterFormats
A list of supported formats for one end of a filter link.
Definition: formats.h:64
MODE_INTERLEAVE_TOP
@ MODE_INTERLEAVE_TOP
Definition: tinterlace.h:45
TInterlaceContext::vsub
int vsub
chroma vertical subsampling
Definition: tinterlace.h:63
TInterlaceContext::frame
int frame
number of the output frame
Definition: tinterlace.h:62
dstp
BYTE * dstp
Definition: avisynth_c.h:908
TInterlaceContext::preout_time_base
AVRational preout_time_base
Definition: tinterlace.h:60
AV_PIX_FMT_YUV420P12LE
@ AV_PIX_FMT_YUV420P12LE
planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
Definition: pixfmt.h:243
query_formats
static int query_formats(AVFilterContext *ctx)
Definition: vf_tinterlace.c:89
OFFSET
#define OFFSET(x)
Definition: vf_tinterlace.c:36
plane
int plane
Definition: avisynth_c.h:384
config_out_props
static int config_out_props(AVFilterLink *outlink)
Definition: vf_tinterlace.c:214
FIELD_LOWER
#define FIELD_LOWER
Definition: vf_tinterlace.c:299
tinterlace_inputs
static const AVFilterPad tinterlace_inputs[]
Definition: vf_tinterlace.c:524
src
#define src
Definition: vp8dsp.c:254
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:54
AV_PIX_FMT_YUV420P10LE
@ AV_PIX_FMT_YUV420P10LE
planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian
Definition: pixfmt.h:159
uninit
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_tinterlace.c:205
AV_PIX_FMT_YUV444P12LE
@ AV_PIX_FMT_YUV444P12LE
planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
Definition: pixfmt.h:251
avassert.h
av_cold
#define av_cold
Definition: attributes.h:84
MODE_MERGEX2
@ MODE_MERGEX2
Definition: tinterlace.h:48
ff_set_common_formats
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:568
TInterlaceContext::flags
int flags
flags affecting interlacing algorithm
Definition: tinterlace.h:61
TInterlaceContext::csp
const AVPixFmtDescriptor * csp
Definition: tinterlace.h:70
width
#define width
TInterlaceContext::cur
AVFrame * cur
Definition: tinterlace.h:64
AV_PIX_FMT_YUVA420P
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:101
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:58
format
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
outputs
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
TInterlaceContext::next
AVFrame * next
Definition: tinterlace.h:65
ctx
AVFormatContext * ctx
Definition: movenc.c:48
av_frame_clone
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:540
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
field
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this field
Definition: writing_filters.txt:78
ff_draw_init
int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags)
Init a draw context.
Definition: drawutils.c:178
ff_tinterlace_init_x86
void ff_tinterlace_init_x86(TInterlaceContext *interlace)
Definition: vf_tinterlace_init.c:58
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:66
AV_PIX_FMT_YUV444P10LE
@ AV_PIX_FMT_YUV444P10LE
planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian
Definition: pixfmt.h:165
AV_PIX_FMT_YUVA422P10LE
@ AV_PIX_FMT_YUVA422P10LE
planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian)
Definition: pixfmt.h:187
TINTERLACE_FLAG_EXACT_TB
#define TINTERLACE_FLAG_EXACT_TB
Definition: tinterlace.h:38
NULL
#define NULL
Definition: coverity.c:32
av_frame_copy_props
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:654
tinterlace_options
static const AVOption tinterlace_options[]
Definition: vf_tinterlace.c:39
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
AVFilterContext::inputs
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
TInterlaceContext::mode
int mode
TInterlaceMode, interlace mode selected.
Definition: tinterlace.h:59
ff_fmt_is_in
int ff_fmt_is_in(int fmt, const int *fmts)
Tell if an integer is contained in the provided -1-terminated list of integers.
Definition: formats.c:254
MODE_DROP_EVEN
@ MODE_DROP_EVEN
Definition: tinterlace.h:42
FFDrawColor::u8
uint8_t u8[16]
Definition: drawutils.h:67
AV_PIX_FMT_YUV440P10LE
@ AV_PIX_FMT_YUV440P10LE
planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian
Definition: pixfmt.h:275
inputs
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
Definition: filter_design.txt:243
AV_PIX_FMT_GRAY8
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
av_image_alloc
int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align)
Allocate an image with size w and h and pixel format pix_fmt, and fill pointers and linesizes accordi...
Definition: imgutils.c:192
interleave
static void interleave(uint8_t *dst, uint8_t *src, int w, int h, int dst_linesize, int src_linesize, enum FilterMode mode, int swap)
Definition: vf_il.c:117
desc
const char * desc
Definition: nvenc.c:68
AV_PIX_FMT_YUV440P12LE
@ AV_PIX_FMT_YUV440P12LE
planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian
Definition: pixfmt.h:277
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:188
FFDrawColor::comp
union FFDrawColor::@215 comp[MAX_PLANES]
AV_PIX_FMT_YUV422P10LE
@ AV_PIX_FMT_YUV422P10LE
planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
Definition: pixfmt.h:161
TINTERLACE_FLAG_CVLPF
#define TINTERLACE_FLAG_CVLPF
Definition: tinterlace.h:37
av_make_q
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition: rational.h:71
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
ff_fill_rectangle
void ff_fill_rectangle(FFDrawContext *draw, FFDrawColor *color, uint8_t *dst[], int dst_linesize[], int dst_x, int dst_y, int w, int h)
Fill a rectangle with an uniform color.
Definition: drawutils.c:318
av_le2ne16
#define av_le2ne16(x)
Definition: bswap.h:95
ff_vf_tinterlace
AVFilter ff_vf_tinterlace
Definition: vf_tinterlace.c:542
AV_PIX_FMT_YUVA444P
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:177
FULL_SCALE_YUVJ_FORMATS
#define FULL_SCALE_YUVJ_FORMATS
Definition: vf_tinterlace.c:76
copy_picture_field
static void copy_picture_field(TInterlaceContext *tinterlace, uint8_t *dst[4], int dst_linesize[4], const uint8_t *src[4], int src_linesize[4], enum AVPixelFormat format, int w, int src_h, int src_field, int interleave, int dst_field, int flags)
Copy picture field from src to dst.
Definition: vf_tinterlace.c:312
AV_PIX_FMT_YUVA420P10LE
@ AV_PIX_FMT_YUVA420P10LE
planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian)
Definition: pixfmt.h:185
internal.h
ff_vf_interlace
AVFilter ff_vf_interlace
Definition: vf_tinterlace.c:554
MODE_NB
@ MODE_NB
Definition: avf_avectorscope.c:41
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
MODE_INTERLEAVE_BOTTOM
@ MODE_INTERLEAVE_BOTTOM
Definition: tinterlace.h:46
FIELD_UPPER
#define FIELD_UPPER
Definition: vf_tinterlace.c:298
MODE_BFF
@ MODE_BFF
Definition: tinterlace.h:54
uint8_t
uint8_t
Definition: audio_convert.c:194
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:60
ff_draw_color
void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4])
Prepare a color.
Definition: drawutils.c:231
av_cmp_q
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
AVFilter
Filter definition.
Definition: avfilter.h:144
ret
ret
Definition: filter_design.txt:187
AVFrame::sample_aspect_ratio
AVRational sample_aspect_ratio
Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
Definition: frame.h:383
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen_template.c:38
tinterlace.h
AVRational::den
int den
Denominator.
Definition: rational.h:60
mode
mode
Definition: ebur128.h:83
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:223
MODE_PAD
@ MODE_PAD
Definition: tinterlace.h:44
avfilter.h
TInterlaceContext::draw
FFDrawContext draw
Definition: tinterlace.h:68
AVPixFmtDescriptor::comp
AVComponentDescriptor comp[4]
Parameters that describe how pixels are packed.
Definition: pixdesc.h:117
av_mul_q
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition: rational.c:80
AV_PIX_FMT_YUV444P
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:71
AVFilterContext
An instance of a filter.
Definition: avfilter.h:338
MODE_INTERLACEX2
@ MODE_INTERLACEX2
Definition: tinterlace.h:47
lowpass_line_c
static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max)
Definition: vf_tinterlace.c:111
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AV_PIX_FMT_YUV422P
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:70
full_scale_yuvj_pix_fmts
static enum AVPixelFormat full_scale_yuvj_pix_fmts[]
Definition: vf_tinterlace.c:79
AV_PIX_FMT_YUVA444P10LE
@ AV_PIX_FMT_YUVA444P10LE
planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian)
Definition: pixfmt.h:189
lowpass_line_complex_c_16
static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8, ptrdiff_t mref, ptrdiff_t pref, int clip_max)
Definition: vf_tinterlace.c:170
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
MODE_TFF
@ MODE_TFF
Definition: tinterlace.h:53
AV_PIX_FMT_YUV411P
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:73
TINTERLACE_FLAG_VLPF
#define TINTERLACE_FLAG_VLPF
Definition: tinterlace.h:36
AV_OPT_TYPE_FLAGS
@ AV_OPT_TYPE_FLAGS
Definition: opt.h:222
imgutils.h
interlace_options
static const AVOption interlace_options[]
Definition: vf_tinterlace.c:62
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:565
lowpass_line_c_16
static void lowpass_line_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8, ptrdiff_t mref, ptrdiff_t pref, int clip_max)
Definition: vf_tinterlace.c:125
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:326
AV_PIX_FMT_YUV410P
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:72
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
h
h
Definition: vp9dsp_template.c:2038
FLAGS
#define FLAGS
Definition: vf_tinterlace.c:37
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:232
AV_PIX_FMT_YUV422P12LE
@ AV_PIX_FMT_YUV422P12LE
planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian
Definition: pixfmt.h:247
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(tinterlace)
AV_PIX_FMT_YUVA422P
@ AV_PIX_FMT_YUVA422P
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition: pixfmt.h:176
MODE_DROP_ODD
@ MODE_DROP_ODD
Definition: tinterlace.h:43
tinterlace_outputs
static const AVFilterPad tinterlace_outputs[]
Definition: vf_tinterlace.c:533