FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vf_shuffleplanes.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "libavutil/avstring.h"
20 #include "libavutil/common.h"
21 #include "libavutil/internal.h"
22 #include "libavutil/opt.h"
23 #include "libavutil/pixdesc.h"
24 #include "libavutil/pixfmt.h"
25 
26 #include "avfilter.h"
27 #include "internal.h"
28 #include "video.h"
29 
30 typedef struct ShufflePlanesContext {
31  const AVClass *class;
32 
33  /* number of planes in the selected pixel format */
34  int planes;
35 
36  /* mapping indices */
37  int map[4];
38 
39  /* set to 1 if some plane is used more than once, so we need to make a copy */
40  int copy;
42 
44 {
45  AVFilterContext *ctx = inlink->dst;
46  ShufflePlanesContext *s = ctx->priv;
47  const AVPixFmtDescriptor *desc;
48  int used[4] = { 0 };
49  int i;
50 
51  s->copy = 0;
53  desc = av_pix_fmt_desc_get(inlink->format);
54 
55  for (i = 0; i < s->planes; i++) {
56  if (s->map[i] >= s->planes) {
57  av_log(ctx, AV_LOG_ERROR,
58  "Non-existing input plane #%d mapped to output plane #%d.\n",
59  s->map[i], i);
60  return AVERROR(EINVAL);
61  }
62 
63  if ((desc->log2_chroma_h || desc->log2_chroma_w) &&
64  (i == 1 || i == 2) != (s->map[i] == 1 || s->map[i] == 2)) {
65  av_log(ctx, AV_LOG_ERROR,
66  "Cannot map between a subsampled chroma plane and a luma "
67  "or alpha plane.\n");
68  return AVERROR(EINVAL);
69  }
70 
71  if ((desc->flags & AV_PIX_FMT_FLAG_PAL ||
73  (i == 1) != (s->map[i] == 1)) {
74  av_log(ctx, AV_LOG_ERROR,
75  "Cannot map between a palette plane and a data plane.\n");
76  return AVERROR(EINVAL);
77  }
78  if (used[s->map[i]])
79  s->copy = 1;
80  used[s->map[i]]++;
81  }
82 
83  return 0;
84 }
85 
87 {
88  AVFilterContext *ctx = inlink->dst;
89  ShufflePlanesContext *s = ctx->priv;
90  uint8_t *shuffled_data[4] = { NULL };
91  int shuffled_linesize[4] = { 0 };
92  int i, ret;
93 
94  for (i = 0; i < s->planes; i++) {
95  shuffled_data[i] = frame->data[s->map[i]];
96  shuffled_linesize[i] = frame->linesize[s->map[i]];
97  }
98  memcpy(frame->data, shuffled_data, sizeof(shuffled_data));
99  memcpy(frame->linesize, shuffled_linesize, sizeof(shuffled_linesize));
100 
101  if (s->copy) {
102  AVFrame *copy = ff_get_video_buffer(ctx->outputs[0], frame->width, frame->height);
103 
104  if (!copy) {
105  ret = AVERROR(ENOMEM);
106  goto fail;
107  }
108 
109  av_frame_copy(copy, frame);
110 
111  ret = av_frame_copy_props(copy, frame);
112  if (ret < 0) {
113  av_frame_free(&copy);
114  goto fail;
115  }
116 
117  av_frame_free(&frame);
118  frame = copy;
119  }
120 
121  return ff_filter_frame(ctx->outputs[0], frame);
122 fail:
123  av_frame_free(&frame);
124  return ret;
125 }
126 
127 #define OFFSET(x) offsetof(ShufflePlanesContext, x)
128 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
129 static const AVOption shuffleplanes_options[] = {
130  { "map0", "Index of the input plane to be used as the first output plane ", OFFSET(map[0]), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 4, FLAGS },
131  { "map1", "Index of the input plane to be used as the second output plane ", OFFSET(map[1]), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 4, FLAGS },
132  { "map2", "Index of the input plane to be used as the third output plane ", OFFSET(map[2]), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 4, FLAGS },
133  { "map3", "Index of the input plane to be used as the fourth output plane ", OFFSET(map[3]), AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 4, FLAGS },
134  { NULL },
135 };
136 
137 static const AVClass shuffleplanes_class = {
138  .class_name = "shuffleplanes",
139  .item_name = av_default_item_name,
140  .option = shuffleplanes_options,
141  .version = LIBAVUTIL_VERSION_INT,
142 };
143 
145  {
146  .name = "default",
147  .type = AVMEDIA_TYPE_VIDEO,
148  .config_props = shuffleplanes_config_input,
149  .filter_frame = shuffleplanes_filter_frame,
150  .get_video_buffer = ff_null_get_video_buffer,
151  },
152  { NULL },
153 };
154 
156  {
157  .name = "default",
158  .type = AVMEDIA_TYPE_VIDEO,
159  },
160  { NULL },
161 };
162 
164  .name = "shuffleplanes",
165  .description = NULL_IF_CONFIG_SMALL("Shuffle video planes"),
166 
167  .priv_size = sizeof(ShufflePlanesContext),
168  .priv_class = &shuffleplanes_class,
169 
170  .inputs = shuffleplanes_inputs,
171  .outputs = shuffleplanes_outputs,
172 };