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 {
36  const AVClass *class;
38  char *pattern;
40  unsigned int pattern_pos;
41  unsigned int nskip_fields;
42  int64_t start_time;
43 
46  int occupied;
47 
48  int nb_planes;
49  int planeheight[4];
50  int stride[4];
51 
55 
56 #define OFFSET(x) offsetof(DetelecineContext, x)
57 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
58 
59 static const AVOption detelecine_options[] = {
60  {"first_field", "select first field", OFFSET(first_field), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "field"},
61  {"top", "select top field first", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "field"},
62  {"t", "select top field first", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "field"},
63  {"bottom", "select bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "field"},
64  {"b", "select bottom field first", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "field"},
65  {"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},
66  {"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},
67  {NULL}
68 };
69 
70 AVFILTER_DEFINE_CLASS(detelecine);
71 
72 static av_cold int init(AVFilterContext *ctx)
73 {
74  DetelecineContext *s = ctx->priv;
75  const char *p;
76  int max = 0;
77 
78  if (!strlen(s->pattern)) {
79  av_log(ctx, AV_LOG_ERROR, "No pattern provided.\n");
80  return AVERROR_INVALIDDATA;
81  }
82 
83  for (p = s->pattern; *p; p++) {
84  if (!av_isdigit(*p)) {
85  av_log(ctx, AV_LOG_ERROR, "Provided pattern includes non-numeric characters.\n");
86  return AVERROR_INVALIDDATA;
87  }
88 
89  max = FFMAX(*p - '0', max);
90  s->pts.num += *p - '0';
91  s->pts.den += 2;
92  }
93 
94  s->nskip_fields = 0;
95  s->pattern_pos = 0;
97 
98  if (s->start_frame != 0) {
99  int nfields = 0;
100  for (p = s->pattern; *p; p++) {
101  nfields += *p - '0';
102  s->pattern_pos++;
103  if (nfields >= 2*s->start_frame) {
104  s->nskip_fields = nfields - 2*s->start_frame;
105  break;
106  }
107  }
108  }
109 
110  av_log(ctx, AV_LOG_INFO, "Detelecine pattern %s removes up to %d frames per frame, pts advance factor: %d/%d\n",
111  s->pattern, (max + 1) / 2, s->pts.num, s->pts.den);
112 
113  return 0;
114 }
115 
117 {
118  AVFilterFormats *pix_fmts = NULL;
119  int fmt;
120 
121  for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
122  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
123  if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL ||
124  desc->flags & AV_PIX_FMT_FLAG_PAL ||
126  ff_add_format(&pix_fmts, fmt);
127  }
128 
129  return ff_set_common_formats(ctx, pix_fmts);
130 }
131 
132 static int config_input(AVFilterLink *inlink)
133 {
134  DetelecineContext *s = inlink->dst->priv;
135  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
136  int ret;
137 
138  s->temp = ff_get_video_buffer(inlink, inlink->w, inlink->h);
139  if (!s->temp)
140  return AVERROR(ENOMEM);
141 
142  s->frame = ff_get_video_buffer(inlink, inlink->w, inlink->h);
143  if (!s->frame)
144  return AVERROR(ENOMEM);
145 
146  if ((ret = av_image_fill_linesizes(s->stride, inlink->format, inlink->w)) < 0)
147  return ret;
148 
149  s->planeheight[1] = s->planeheight[2] = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
150  s->planeheight[0] = s->planeheight[3] = inlink->h;
151 
153 
154  return 0;
155 }
156 
157 static int config_output(AVFilterLink *outlink)
158 {
159  AVFilterContext *ctx = outlink->src;
160  DetelecineContext *s = ctx->priv;
161  const AVFilterLink *inlink = ctx->inputs[0];
162  AVRational fps = inlink->frame_rate;
163 
164  if (!fps.num || !fps.den) {
165  av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; "
166  "current rate of %d/%d is invalid\n", fps.num, fps.den);
167  return AVERROR(EINVAL);
168  }
169  fps = av_mul_q(fps, av_inv_q(s->pts));
170  av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n",
171  inlink->frame_rate.num, inlink->frame_rate.den, fps.num, fps.den);
172 
173  outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
174  outlink->frame_rate = fps;
175  outlink->time_base = av_mul_q(inlink->time_base, s->pts);
176  av_log(ctx, AV_LOG_VERBOSE, "TB: %d/%d -> %d/%d\n",
177  inlink->time_base.num, inlink->time_base.den, outlink->time_base.num, outlink->time_base.den);
178 
179  s->ts_unit = av_inv_q(av_mul_q(fps, outlink->time_base));
180 
181  return 0;
182 }
183 
184 static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref)
185 {
186  AVFilterContext *ctx = inlink->dst;
187  AVFilterLink *outlink = ctx->outputs[0];
188  DetelecineContext *s = ctx->priv;
189  int i, len = 0, ret = 0, out = 0;
190 
191  if (s->start_time == AV_NOPTS_VALUE)
192  s->start_time = inpicref->pts;
193 
194  if (s->nskip_fields >= 2) {
195  s->nskip_fields -= 2;
196  return 0;
197  } else if (s->nskip_fields >= 1) {
198  if (s->occupied) {
199  s->occupied = 0;
200  s->nskip_fields--;
201  }
202  else {
203  for (i = 0; i < s->nb_planes; i++) {
204  av_image_copy_plane(s->temp->data[i], s->temp->linesize[i],
205  inpicref->data[i], inpicref->linesize[i],
206  s->stride[i],
207  s->planeheight[i]);
208  }
209  s->occupied = 1;
210  s->nskip_fields--;
211  return 0;
212  }
213  }
214 
215  if (s->nskip_fields == 0) {
216  while(!len && s->pattern[s->pattern_pos]) {
217  len = s->pattern[s->pattern_pos] - '0';
218  s->pattern_pos++;
219  }
220 
221  if (!s->pattern[s->pattern_pos])
222  s->pattern_pos = 0;
223 
224  if(!len) { // do not output any field as the entire pattern is zero
225  av_frame_free(&inpicref);
226  return 0;
227  }
228 
229  if (s->occupied) {
230  for (i = 0; i < s->nb_planes; i++) {
231  // fill in the EARLIER field from the new pic
233  s->frame->linesize[i] * 2,
234  inpicref->data[i] + inpicref->linesize[i] * s->first_field,
235  inpicref->linesize[i] * 2,
236  s->stride[i],
237  (s->planeheight[i] - s->first_field + 1) / 2);
238  // fill in the LATER field from the buffered pic
239  av_image_copy_plane(s->frame->data[i] + s->frame->linesize[i] * !s->first_field,
240  s->frame->linesize[i] * 2,
241  s->temp->data[i] + s->temp->linesize[i] * !s->first_field,
242  s->temp->linesize[i] * 2,
243  s->stride[i],
244  (s->planeheight[i] - !s->first_field + 1) / 2);
245  }
246  len -= 2;
247  for (i = 0; i < s->nb_planes; i++) {
248  av_image_copy_plane(s->temp->data[i], s->temp->linesize[i],
249  inpicref->data[i], inpicref->linesize[i],
250  s->stride[i],
251  s->planeheight[i]);
252  }
253  s->occupied = 1;
254  out = 1;
255  } else {
256  if (len >= 2) {
257  // output THIS image as-is
258  for (i = 0; i < s->nb_planes; i++)
260  inpicref->data[i], inpicref->linesize[i],
261  s->stride[i],
262  s->planeheight[i]);
263  len -= 2;
264  out = 1;
265  } else if (len == 1) {
266  // fill in the EARLIER field from the new pic
267  for (i = 0; i < s->nb_planes; i++) {
269  s->frame->linesize[i] * s->first_field,
270  s->frame->linesize[i] * 2,
271  inpicref->data[i] +
272  inpicref->linesize[i] * s->first_field,
273  inpicref->linesize[i] * 2, s->stride[i],
274  (s->planeheight[i] - s->first_field + 1) / 2);
275  }
276 
277  // TODO: not sure about the other field
278 
279  len--;
280  out = 1;
281  }
282  }
283 
284  if (len == 1 && s->occupied)
285  {
286  len--;
287  s->occupied = 0;
288  }
289  }
290  s->nskip_fields = len;
291 
292  if (out) {
294 
295  if (!frame) {
296  av_frame_free(&inpicref);
297  return AVERROR(ENOMEM);
298  }
299 
300  av_frame_copy_props(frame, inpicref);
301  frame->pts = ((s->start_time == AV_NOPTS_VALUE) ? 0 : s->start_time) +
302  av_rescale(outlink->frame_count, s->ts_unit.num,
303  s->ts_unit.den);
304  ret = ff_filter_frame(outlink, frame);
305  }
306 
307  av_frame_free(&inpicref);
308 
309  return ret;
310 }
311 
312 static av_cold void uninit(AVFilterContext *ctx)
313 {
314  DetelecineContext *s = ctx->priv;
315 
316  av_frame_free(&s->temp);
317  av_frame_free(&s->frame);
318 }
319 
320 static const AVFilterPad detelecine_inputs[] = {
321  {
322  .name = "default",
323  .type = AVMEDIA_TYPE_VIDEO,
324  .filter_frame = filter_frame,
325  .config_props = config_input,
326  },
327  { NULL }
328 };
329 
330 static const AVFilterPad detelecine_outputs[] = {
331  {
332  .name = "default",
333  .type = AVMEDIA_TYPE_VIDEO,
334  .config_props = config_output,
335  },
336  { NULL }
337 };
338 
340  .name = "detelecine",
341  .description = NULL_IF_CONFIG_SMALL("Apply an inverse telecine pattern."),
342  .priv_size = sizeof(DetelecineContext),
343  .priv_class = &detelecine_class,
344  .init = init,
345  .uninit = uninit,
347  .inputs = detelecine_inputs,
348  .outputs = detelecine_outputs,
349 };
#define AV_PIX_FMT_FLAG_PAL
Pixel format has a palette in data[1], values are indexes in this palette.
Definition: pixdesc.h:115
#define NULL
Definition: coverity.c:32
int av_isdigit(int c)
Locale-independent conversion of ASCII isdigit.
Definition: avstring.c:320
const char * s
Definition: avisynth_c.h:631
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2090
This structure describes decoded (raw) audio or video data.
Definition: frame.h:171
AVOption.
Definition: opt.h:255
const char * fmt
Definition: avisynth_c.h:632
misc image utilities
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:248
int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2130
Main libavfilter public API header.
int num
numerator
Definition: rational.h:44
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:109
const char * name
Pad name.
Definition: internal.h:67
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:641
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1145
#define av_cold
Definition: attributes.h:74
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:257
AVFILTER_DEFINE_CLASS(detelecine)
static AVFrame * frame
AVRational av_mul_q(AVRational b, AVRational c)
Multiply two rationals.
Definition: rational.c:80
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:192
#define av_log(a,...)
#define FLAGS
Definition: vf_detelecine.c:57
static int first_field(const struct video_data *s)
Definition: v4l2.c:228
static const AVOption detelecine_options[]
Definition: vf_detelecine.c:59
A filter pad used for either input or output.
Definition: internal.h:61
#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:542
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:89
#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:148
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:175
void * priv
private data for use by the filter
Definition: avfilter.h:654
#define AV_PIX_FMT_FLAG_HWACCEL
Pixel format is an HW accelerated format.
Definition: pixdesc.h:123
int ff_add_format(AVFilterFormats **avff, int64_t fmt)
Add fmt to the list of media formats contained in *avff.
Definition: formats.c:323
#define FFMAX(a, b)
Definition: common.h:64
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:127
ret
Definition: avfilter.c:974
#define FF_CEIL_RSHIFT(a, b)
Definition: common.h:57
static av_cold int init(AVFilterContext *ctx)
Definition: vf_detelecine.c:72
static int config_output(AVFilterLink *outlink)
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:449
#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:199
uint8_t flags
Definition: pixdesc.h:90
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
AVFilter ff_vf_detelecine
AVRational ts_unit
Definition: vf_detelecine.c:45
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:470
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:88
static const AVFilterPad inputs[]
Definition: af_ashowinfo.c:239
rational number numerator/denominator
Definition: rational.h:43
const char * name
Filter name.
Definition: avfilter.h:474
#define AV_PIX_FMT_FLAG_BITSTREAM
All values of a component are bit-wise packed end to end.
Definition: pixdesc.h:119
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:648
static const AVFilterPad detelecine_inputs[]
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition: rational.h:133
Frame requests may need to loop in order to be fulfilled.
Definition: internal.h:359
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:182
unsigned int nskip_fields
Definition: vf_detelecine.c:41
GLint GLenum GLboolean GLsizei stride
Definition: opengl_enc.c:105
unsigned int pattern_pos
Definition: vf_detelecine.c:40
int den
denominator
Definition: rational.h:45
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
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(constuint8_t *) pi-0x80)*(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(constint16_t *) pi >>8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t,*(constint16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(constint32_t *) pi >>24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t,*(constint32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(constfloat *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(constfloat *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(constfloat *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(constdouble *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(constdouble *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(constdouble *) pi *(1U<< 31))))#defineSET_CONV_FUNC_GROUP(ofmt, ifmt) staticvoidset_generic_function(AudioConvert *ac){}voidff_audio_convert_free(AudioConvert **ac){if(!*ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);}AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enumAVSampleFormatout_fmt, enumAVSampleFormatin_fmt, intchannels, intsample_rate, intapply_map){AudioConvert *ac;intin_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) returnNULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method!=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt)>2){ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc){av_free(ac);returnNULL;}returnac;}in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar){ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar?ac->channels:1;}elseif(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;elseac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);returnac;}intff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in){intuse_generic=1;intlen=in->nb_samples;intp;if(ac->dc){av_log(ac->avr, AV_LOG_TRACE,"%dsamples-audio_convert:%sto%s(dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));returnff_convert_dither(ac-> out
An instance of a filter.
Definition: avfilter.h:633
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:273
internal API functions
#define OFFSET(x)
Definition: vf_detelecine.c:56
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:548
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:241