FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_detelecine.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Himangi Saraogi <himangi774@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file detelecine filter.
23  */
24 
25 
26 #include "libavutil/avstring.h"
27 #include "libavutil/imgutils.h"
28 #include "libavutil/opt.h"
29 #include "libavutil/pixdesc.h"
30 #include "avfilter.h"
31 #include "formats.h"
32 #include "internal.h"
33 #include "video.h"
34 
35 typedef struct DetelecineContext {
36  const AVClass *class;
38  char *pattern;
40  int init_len;
41  unsigned int pattern_pos;
42  unsigned int nskip_fields;
43  int64_t start_time;
44 
47  int occupied;
48 
49  int nb_planes;
50  int planeheight[4];
51  int stride[4];
52 
56 
57 #define OFFSET(x) offsetof(DetelecineContext, x)
58 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
59 
60 static const AVOption detelecine_options[] = {
61  {"first_field", "select first field", OFFSET(first_field), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "field"},
62  {"top", "select top field first", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "field"},
63  {"t", "select top field first", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "field"},
64  {"bottom", "select bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "field"},
65  {"b", "select bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "field"},
66  {"pattern", "pattern that describe for how many fields a frame is to be displayed", OFFSET(pattern), AV_OPT_TYPE_STRING, {.str="23"}, 0, 0, FLAGS},
67  {"start_frame", "position of first frame with respect to the pattern if stream is cut", OFFSET(start_frame), AV_OPT_TYPE_INT, {.i64=0}, 0, 13, FLAGS},
68  {NULL}
69 };
70 
71 AVFILTER_DEFINE_CLASS(detelecine);
72 
74 {
75  DetelecineContext *s = ctx->priv;
76  const char *p;
77  int max = 0;
78  int sum = 0;
79 
80  if (!strlen(s->pattern)) {
81  av_log(ctx, AV_LOG_ERROR, "No pattern provided.\n");
82  return AVERROR_INVALIDDATA;
83  }
84 
85  for (p = s->pattern; *p; p++) {
86  if (!av_isdigit(*p)) {
87  av_log(ctx, AV_LOG_ERROR, "Provided pattern includes non-numeric characters.\n");
88  return AVERROR_INVALIDDATA;
89  }
90 
91  sum += *p - '0';
92  max = FFMAX(*p - '0', max);
93  s->pts.num += *p - '0';
94  s->pts.den += 2;
95  }
96 
97  if (s->start_frame >= sum) {
98  av_log(ctx, AV_LOG_ERROR, "Provided start_frame is too big.\n");
99  return AVERROR_INVALIDDATA;
100  }
101 
102  s->nskip_fields = 0;
103  s->pattern_pos = 0;
105  s->init_len = 0;
106 
107  if (s->start_frame != 0) {
108  int nfields = 0;
109  for (p = s->pattern; *p; p++) {
110  nfields += *p - '0';
111  s->pattern_pos++;
112  if (nfields >= 2*s->start_frame) {
113  s->init_len = nfields - 2*s->start_frame;
114  break;
115  }
116  }
117  }
118 
119  av_log(ctx, AV_LOG_INFO, "Detelecine pattern %s removes up to %d frames per frame, pts advance factor: %d/%d\n",
120  s->pattern, (max + 1) / 2, s->pts.num, s->pts.den);
121 
122  return 0;
123 }
124 
126 {
128  int fmt, ret;
129 
130  for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
132  if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL ||
133  desc->flags & AV_PIX_FMT_FLAG_PAL ||
134  desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) &&
135  (ret = ff_add_format(&pix_fmts, fmt)) < 0)
136  return ret;
137  }
138 
139  return ff_set_common_formats(ctx, pix_fmts);
140 }
141 
142 static int config_input(AVFilterLink *inlink)
143 {
144  DetelecineContext *s = inlink->dst->priv;
146  int ret;
147 
148  s->temp = ff_get_video_buffer(inlink, inlink->w, inlink->h);
149  if (!s->temp)
150  return AVERROR(ENOMEM);
151 
152  s->frame[0] = ff_get_video_buffer(inlink, inlink->w, inlink->h);
153  if (!s->frame[0])
154  return AVERROR(ENOMEM);
155 
156  s->frame[1] = ff_get_video_buffer(inlink, inlink->w, inlink->h);
157  if (!s->frame[1])
158  return AVERROR(ENOMEM);
159 
160  if ((ret = av_image_fill_linesizes(s->stride, inlink->format, inlink->w)) < 0)
161  return ret;
162 
163  s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
164  s->planeheight[0] = s->planeheight[3] = inlink->h;
165 
167 
168  return 0;
169 }
170 
171 static int config_output(AVFilterLink *outlink)
172 {
173  AVFilterContext *ctx = outlink->src;
174  DetelecineContext *s = ctx->priv;
175  const AVFilterLink *inlink = ctx->inputs[0];
176  AVRational fps = inlink->frame_rate;
177 
178  if (!fps.num || !fps.den) {
179  av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; "
180  "current rate of %d/%d is invalid\n", fps.num, fps.den);
181  return AVERROR(EINVAL);
182  }
183  fps = av_mul_q(fps, av_inv_q(s->pts));
184  av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n",
185  inlink->frame_rate.num, inlink->frame_rate.den, fps.num, fps.den);
186 
187  outlink->frame_rate = fps;
188  outlink->time_base = av_mul_q(inlink->time_base, s->pts);
189  av_log(ctx, AV_LOG_VERBOSE, "TB: %d/%d -> %d/%d\n",
190  inlink->time_base.num, inlink->time_base.den, outlink->time_base.num, outlink->time_base.den);
191 
192  s->ts_unit = av_inv_q(av_mul_q(fps, outlink->time_base));
193 
194  return 0;
195 }
196 
197 static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
198 {
199  AVFilterContext *ctx = inlink->dst;
200  AVFilterLink *outlink = ctx->outputs[0];
201  DetelecineContext *s = ctx->priv;
202  int i, len = 0, ret = 0, out = 0;
203 
204  if (s->start_time == AV_NOPTS_VALUE)
205  s->start_time = inpicref->pts;
206 
207  if (s->nskip_fields >= 2) {
208  s->nskip_fields -= 2;
209  return 0;
210  } else if (s->nskip_fields >= 1) {
211  for (i = 0; i < s->nb_planes; i++) {
212  av_image_copy_plane(s->temp->data[i], s->temp->linesize[i],
213  inpicref->data[i], inpicref->linesize[i],
214  s->stride[i],
215  s->planeheight[i]);
216  }
217  s->occupied = 1;
218  s->nskip_fields--;
219  return 0;
220  }
221 
222  if (s->nskip_fields == 0) {
223  len = s->init_len;
224  s->init_len = 0;
225  while(!len && s->pattern[s->pattern_pos]) {
226  len = s->pattern[s->pattern_pos] - '0';
227  s->pattern_pos++;
228  }
229 
230  if (!s->pattern[s->pattern_pos])
231  s->pattern_pos = 0;
232 
233  if(!len) { // do not output any field as the entire pattern is zero
234  av_frame_free(&inpicref);
235  return 0;
236  }
237 
238  if (len == 1 && s->occupied) {
239  s->occupied = 0;
240  // output THIS image as-is
241  for (i = 0; i < s->nb_planes; i++)
243  s->temp->data[i], s->temp->linesize[i],
244  s->stride[i],
245  s->planeheight[i]);
246  len = 0;
247  while(!len && s->pattern[s->pattern_pos]) {
248  len = s->pattern[s->pattern_pos] - '0';
249  s->pattern_pos++;
250  }
251 
252  if (!s->pattern[s->pattern_pos])
253  s->pattern_pos = 0;
254 
255  s->occupied = 0;
256  ++out;
257  }
258 
259  if (s->occupied) {
260  for (i = 0; i < s->nb_planes; i++) {
261  // fill in the EARLIER field from the new pic
263  s->frame[out]->linesize[i] * 2,
264  inpicref->data[i] + inpicref->linesize[i] * s->first_field,
265  inpicref->linesize[i] * 2,
266  s->stride[i],
267  (s->planeheight[i] - s->first_field + 1) / 2);
268  // fill in the LATER field from the buffered pic
269  av_image_copy_plane(s->frame[out]->data[i] + s->frame[out]->linesize[i] * !s->first_field,
270  s->frame[out]->linesize[i] * 2,
271  s->temp->data[i] + s->temp->linesize[i] * !s->first_field,
272  s->temp->linesize[i] * 2,
273  s->stride[i],
274  (s->planeheight[i] - !s->first_field + 1) / 2);
275  }
276 
277  s->occupied = 0;
278  if (len <= 2) {
279  for (i = 0; i < s->nb_planes; i++) {
280  av_image_copy_plane(s->temp->data[i], s->temp->linesize[i],
281  inpicref->data[i], inpicref->linesize[i],
282  s->stride[i],
283  s->planeheight[i]);
284  }
285  s->occupied = 1;
286  }
287  ++out;
288  len = (len >= 3) ? len - 3 : 0;
289  } else {
290  if (len >= 2) {
291  // output THIS image as-is
292  for (i = 0; i < s->nb_planes; i++)
294  inpicref->data[i], inpicref->linesize[i],
295  s->stride[i],
296  s->planeheight[i]);
297  len -= 2;
298  ++out;
299  } else if (len == 1) {
300  // output THIS image as-is
301  for (i = 0; i < s->nb_planes; i++)
303  inpicref->data[i], inpicref->linesize[i],
304  s->stride[i],
305  s->planeheight[i]);
306 
307  for (i = 0; i < s->nb_planes; i++) {
308  av_image_copy_plane(s->temp->data[i], s->temp->linesize[i],
309  inpicref->data[i], inpicref->linesize[i],
310  s->stride[i],
311  s->planeheight[i]);
312  }
313  s->occupied = 1;
314 
315  len--;
316  ++out;
317  }
318  }
319 
320  if (len == 1 && s->occupied)
321  {
322  len--;
323  s->occupied = 0;
324  }
325  }
326  s->nskip_fields = len;
327 
328  for (i = 0; i < out; ++i) {
329  AVFrame *frame = av_frame_clone(s->frame[i]);
330 
331  if (!frame) {
332  av_frame_free(&inpicref);
333  return AVERROR(ENOMEM);
334  }
335 
336  av_frame_copy_props(frame, inpicref);
337  frame->pts = ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time) +
338  av_rescale(outlink->frame_count_in, s->ts_unit.num,
339  s->ts_unit.den);
340  ret = ff_filter_frame(outlink, frame);
341  }
342 
343  av_frame_free(&inpicref);
344 
345  return ret;
346 }
347 
349 {
350  DetelecineContext *s = ctx->priv;
351 
352  av_frame_free(&s->temp);
353  av_frame_free(&s->frame[0]);
354  av_frame_free(&s->frame[1]);
355 }
356 
357 static const AVFilterPad detelecine_inputs[] = {
358  {
359  .name = "default",
360  .type = AVMEDIA_TYPE_VIDEO,
361  .filter_frame = filter_frame,
362  .config_props = config_input,
363  },
364  { NULL }
365 };
366 
367 static const AVFilterPad detelecine_outputs[] = {
368  {
369  .name = "default",
370  .type = AVMEDIA_TYPE_VIDEO,
371  .config_props = config_output,
372  },
373  { NULL }
374 };
375 
377  .name = "detelecine",
378  .description = NULL_IF_CONFIG_SMALL("Apply an inverse telecine pattern."),
379  .priv_size = sizeof(DetelecineContext),
380  .priv_class = &detelecine_class,
381  .init = init,
382  .uninit = uninit,
384  .inputs = detelecine_inputs,
385  .outputs = detelecine_outputs,
386 };
#define AV_PIX_FMT_FLAG_PAL
Pixel format has a palette in data[1], values are indexes in this palette.
Definition: pixdesc.h:132
#define NULL
Definition: coverity.c:32
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
static av_const int av_isdigit(int c)
Locale-independent conversion of ASCII isdigit.
Definition: avstring.h:206
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2446
This structure describes decoded (raw) audio or video data.
Definition: frame.h:226
AVOption.
Definition: opt.h:246
const char * fmt
Definition: avisynth_c.h:769
misc image utilities
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2486
Main libavfilter public API header.
const char * desc
Definition: nvenc.c:65
int num
Numerator.
Definition: rational.h:59
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
const char * name
Pad name.
Definition: internal.h:60
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1080
#define av_cold
Definition: attributes.h:82
AVOptions.
static int config_input(AVFilterLink *inlink)
static av_cold void uninit(AVFilterContext *ctx)
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:319
AVFILTER_DEFINE_CLASS(detelecine)
static AVFrame * frame
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
#define av_log(a,...)
#define FLAGS
Definition: vf_detelecine.c:58
static int first_field(const struct video_data *s)
Definition: v4l2.c:230
static const AVOption detelecine_options[]
Definition: vf_detelecine.c:60
A filter pad used for either input or output.
Definition: internal.h:54
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
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
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:101
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
void * priv
private data for use by the filter
Definition: avfilter.h:353
#define AV_PIX_FMT_FLAG_HWACCEL
Pixel format is an HW accelerated format.
Definition: pixdesc.h:140
int ff_add_format(AVFilterFormats **avff, int64_t fmt)
Add fmt to the list of media formats contained in *avff.
Definition: formats.c:337
#define FFMAX(a, b)
Definition: common.h:94
uint64_t flags
Combination of AV_PIX_FMT_FLAG_...
Definition: pixdesc.h:106
static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:129
AVFormatContext * ctx
Definition: movenc.c:48
static av_cold int init(AVFilterContext *ctx)
Definition: vf_detelecine.c:73
#define s(width, name)
Definition: cbs_vp9.c:257
static int config_output(AVFilterLink *outlink)
static const AVFilterPad inputs[]
Definition: af_acontrast.c:193
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:540
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:257
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:81
AVFilter ff_vf_detelecine
AVRational ts_unit
Definition: vf_detelecine.c:46
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width)
Fill plane linesizes for an image with pixel format pix_fmt and width width.
Definition: imgutils.c:89
Rational number (pair of numerator and denominator).
Definition: rational.h:58
const char * name
Filter name.
Definition: avfilter.h:148
AVFrame * frame[2]
Definition: vf_detelecine.c:53
#define AV_PIX_FMT_FLAG_BITSTREAM
All values of a component are bit-wise packed end to end.
Definition: pixdesc.h:136
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:266
static const AVFilterPad detelecine_inputs[]
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:240
unsigned int nskip_fields
Definition: vf_detelecine.c:42
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition: rational.h:159
GLint GLenum GLboolean GLsizei stride
Definition: opengl_enc.c:105
unsigned int pattern_pos
Definition: vf_detelecine.c:41
int den
Denominator.
Definition: rational.h:60
static const AVFilterPad detelecine_outputs[]
int len
static int query_formats(AVFilterContext *ctx)
A list of supported formats for one end of a filter link.
Definition: formats.h:64
An instance of a filter.
Definition: avfilter.h:338
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition: rational.c:80
FILE * out
Definition: movenc.c:54
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
internal API functions
#define OFFSET(x)
Definition: vf_detelecine.c:57
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:654
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:58