FFmpeg
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_fieldorder.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011 Mark Himsley
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
23  * video field order filter, heavily influenced by vf_pad.c
24  */
25 
26 /* #define DEBUG */
27 
28 #include <stdio.h>
29 #include <string.h>
30 
31 #include "libavutil/imgutils.h"
32 #include "libavutil/internal.h"
33 #include "libavutil/pixdesc.h"
34 #include "avfilter.h"
35 #include "formats.h"
36 #include "internal.h"
37 #include "video.h"
38 
39 typedef struct
40 {
41  unsigned int dst_tff; ///< output bff/tff
42  int line_size[4]; ///< bytes of pixel data per line for each plane
44 
45 static av_cold int init(AVFilterContext *ctx, const char *args)
46 {
47  FieldOrderContext *fieldorder = ctx->priv;
48 
49  const char *tff = "tff";
50  const char *bff = "bff";
51 
52  if (!args) {
53  fieldorder->dst_tff = 1;
54  } else if (sscanf(args, "%u", &fieldorder->dst_tff) == 1) {
55  fieldorder->dst_tff = !!fieldorder->dst_tff;
56  } else if (!strcmp(tff, args)) {
57  fieldorder->dst_tff = 1;
58  } else if (!strcmp(bff, args)) {
59  fieldorder->dst_tff = 0;
60  } else {
61  av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'.\n", args);
62  return AVERROR(EINVAL);
63  }
64 
65  av_log(ctx, AV_LOG_VERBOSE, "output field order: %s\n",
66  fieldorder->dst_tff ? tff : bff);
67 
68  return 0;
69 }
70 
72 {
75  int ret;
76 
77  /** accept any input pixel format that is not hardware accelerated, not
78  * a bitstream format, and does not have vertically sub-sampled chroma */
79  if (ctx->inputs[0]) {
80  formats = NULL;
81  for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) {
82  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
83  if (!(desc->flags & PIX_FMT_HWACCEL ||
84  desc->flags & PIX_FMT_BITSTREAM) &&
85  desc->nb_components && !desc->log2_chroma_h &&
86  (ret = ff_add_format(&formats, pix_fmt)) < 0) {
87  ff_formats_unref(&formats);
88  return ret;
89  }
90  }
91  ff_formats_ref(formats, &ctx->inputs[0]->out_formats);
92  ff_formats_ref(formats, &ctx->outputs[0]->in_formats);
93  }
94 
95  return 0;
96 }
97 
98 static int config_input(AVFilterLink *inlink)
99 {
100  AVFilterContext *ctx = inlink->dst;
101  FieldOrderContext *fieldorder = ctx->priv;
102  int plane;
103 
104  /** full an array with the number of bytes that the video
105  * data occupies per line for each plane of the input video */
106  for (plane = 0; plane < 4; plane++) {
107  fieldorder->line_size[plane] = av_image_get_linesize(
108  inlink->format,
109  inlink->w,
110  plane);
111  }
112 
113  return 0;
114 }
115 
116 static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int w, int h)
117 {
118  AVFilterContext *ctx = inlink->dst;
119  AVFilterLink *outlink = ctx->outputs[0];
120 
121  return ff_get_video_buffer(outlink, perms, w, h);
122 }
123 
125 {
126  AVFilterContext *ctx = inlink->dst;
127  FieldOrderContext *s = ctx->priv;
128  AVFilterLink *outlink = ctx->outputs[0];
129  int h, plane, line_step, line_size, line;
130  uint8_t *data;
131 
132  if (!frame->video->interlaced ||
133  frame->video->top_field_first == s->dst_tff)
134  return ff_filter_frame(outlink, frame);
135 
136  av_dlog(ctx,
137  "picture will move %s one line\n",
138  s->dst_tff ? "up" : "down");
139  h = frame->video->h;
140  for (plane = 0; plane < 4 && frame->data[plane]; plane++) {
141  line_step = frame->linesize[plane];
142  line_size = s->line_size[plane];
143  data = frame->data[plane];
144  if (s->dst_tff) {
145  /** Move every line up one line, working from
146  * the top to the bottom of the frame.
147  * The original top line is lost.
148  * The new last line is created as a copy of the
149  * penultimate line from that field. */
150  for (line = 0; line < h; line++) {
151  if (1 + line < frame->video->h) {
152  memcpy(data, data + line_step, line_size);
153  } else {
154  memcpy(data, data - line_step - line_step, line_size);
155  }
156  data += line_step;
157  }
158  } else {
159  /** Move every line down one line, working from
160  * the bottom to the top of the frame.
161  * The original bottom line is lost.
162  * The new first line is created as a copy of the
163  * second line from that field. */
164  data += (h - 1) * line_step;
165  for (line = h - 1; line >= 0 ; line--) {
166  if (line > 0) {
167  memcpy(data, data - line_step, line_size);
168  } else {
169  memcpy(data, data + line_step + line_step, line_size);
170  }
171  data -= line_step;
172  }
173  }
174  }
175  frame->video->top_field_first = s->dst_tff;
176 
177  return ff_filter_frame(outlink, frame);
178 }
179 
181  {
182  .name = "default",
183  .type = AVMEDIA_TYPE_VIDEO,
184  .config_props = config_input,
185  .get_video_buffer = get_video_buffer,
186  .filter_frame = filter_frame,
187  .min_perms = AV_PERM_READ | AV_PERM_WRITE,
188  },
189  { NULL }
190 };
191 
193  {
194  .name = "default",
195  .type = AVMEDIA_TYPE_VIDEO,
196  },
197  { NULL }
198 };
199 
201  .name = "fieldorder",
202  .description = NULL_IF_CONFIG_SMALL("Set the field order."),
203  .init = init,
204  .priv_size = sizeof(FieldOrderContext),
206  .inputs = avfilter_vf_fieldorder_inputs,
207  .outputs = avfilter_vf_fieldorder_outputs,
208 };