FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_shuffleplanes.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 48 56 85.7%
Functions: 3 3 100.0%
Branches: 37 40 92.5%

Line Branch Exec Source
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 "filters.h"
28 #include "formats.h"
29 #include "video.h"
30
31 typedef struct ShufflePlanesContext {
32 const AVClass *class;
33
34 /* number of planes in the selected pixel format */
35 int planes;
36
37 /* mapping indices */
38 int map[4];
39
40 /* set to 1 if some plane is used more than once, so we need to make a copy */
41 int copy;
42 } ShufflePlanesContext;
43
44 2 static int query_formats(const AVFilterContext *ctx,
45 AVFilterFormatsConfig **cfg_in,
46 AVFilterFormatsConfig **cfg_out)
47 {
48 2 AVFilterFormats *formats = NULL;
49 2 const ShufflePlanesContext *s = ctx->priv;
50 int fmt, ret, i;
51
52
2/2
✓ Branch 1 taken 486 times.
✓ Branch 2 taken 2 times.
488 for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
53 486 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
54 486 int planes = av_pix_fmt_count_planes(fmt);
55
56
2/2
✓ Branch 0 taken 484 times.
✓ Branch 1 taken 2 times.
486 if (!(desc->flags & AV_PIX_FMT_FLAG_PAL) &&
57
2/2
✓ Branch 0 taken 456 times.
✓ Branch 1 taken 28 times.
484 !(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
58
2/2
✓ Branch 0 taken 1404 times.
✓ Branch 1 taken 246 times.
1650 for (i = 0; i < 4; i++) {
59
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 1270 times.
1404 if (s->map[i] >= planes)
60 134 break;
61
62
4/4
✓ Branch 0 taken 1090 times.
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 195 times.
✓ Branch 3 taken 895 times.
1270 if ((desc->log2_chroma_h || desc->log2_chroma_w) &&
63
10/10
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 201 times.
✓ Branch 4 taken 326 times.
✓ Branch 5 taken 49 times.
✓ Branch 6 taken 49 times.
✓ Branch 7 taken 277 times.
✓ Branch 8 taken 76 times.
✓ Branch 9 taken 299 times.
375 (i == 1 || i == 2) != (s->map[i] == 1 || s->map[i] == 2))
64 76 break;
65 }
66
67
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 246 times.
456 if (i != 4)
68 210 continue;
69
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 246 times.
246 if ((ret = ff_add_format(&formats, fmt)) < 0) {
70 return ret;
71 }
72 }
73 }
74
75 2 return ff_set_common_formats2(ctx, cfg_in, cfg_out, formats);
76 }
77
78 2 static av_cold int shuffleplanes_config_input(AVFilterLink *inlink)
79 {
80 2 AVFilterContext *ctx = inlink->dst;
81 2 ShufflePlanesContext *s = ctx->priv;
82 2 int used[4] = { 0 };
83 int i;
84
85 2 s->copy = 0;
86 2 s->planes = av_pix_fmt_count_planes(inlink->format);
87
88
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 for (i = 0; i < s->planes; i++) {
89
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (used[s->map[i]])
90 3 s->copy = 1;
91 7 used[s->map[i]]++;
92 }
93
94 2 return 0;
95 }
96
97 100 static int shuffleplanes_filter_frame(AVFilterLink *inlink, AVFrame *frame)
98 {
99 100 AVFilterContext *ctx = inlink->dst;
100 100 ShufflePlanesContext *s = ctx->priv;
101 100 uint8_t *shuffled_data[4] = { NULL };
102 100 int shuffled_linesize[4] = { 0 };
103 int i, ret;
104
105
2/2
✓ Branch 0 taken 350 times.
✓ Branch 1 taken 100 times.
450 for (i = 0; i < s->planes; i++) {
106 350 shuffled_data[i] = frame->data[s->map[i]];
107 350 shuffled_linesize[i] = frame->linesize[s->map[i]];
108 }
109 100 memcpy(frame->data, shuffled_data, sizeof(shuffled_data));
110 100 memcpy(frame->linesize, shuffled_linesize, sizeof(shuffled_linesize));
111
112
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 50 times.
100 if (s->copy) {
113 50 AVFrame *copy = ff_get_video_buffer(ctx->outputs[0], frame->width, frame->height);
114
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!copy) {
116 ret = AVERROR(ENOMEM);
117 goto fail;
118 }
119
120 50 av_frame_copy(copy, frame);
121
122 50 ret = av_frame_copy_props(copy, frame);
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (ret < 0) {
124 av_frame_free(&copy);
125 goto fail;
126 }
127
128 50 av_frame_free(&frame);
129 50 frame = copy;
130 }
131
132 100 return ff_filter_frame(ctx->outputs[0], frame);
133 fail:
134 av_frame_free(&frame);
135 return ret;
136 }
137
138 #define OFFSET(x) offsetof(ShufflePlanesContext, x)
139 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
140 static const AVOption shuffleplanes_options[] = {
141 { "map0", "Index of the input plane to be used as the first output plane ", OFFSET(map[0]), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, FLAGS },
142 { "map1", "Index of the input plane to be used as the second output plane ", OFFSET(map[1]), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 3, FLAGS },
143 { "map2", "Index of the input plane to be used as the third output plane ", OFFSET(map[2]), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 3, FLAGS },
144 { "map3", "Index of the input plane to be used as the fourth output plane ", OFFSET(map[3]), AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 3, FLAGS },
145 { NULL },
146 };
147
148 AVFILTER_DEFINE_CLASS(shuffleplanes);
149
150 static const AVFilterPad shuffleplanes_inputs[] = {
151 {
152 .name = "default",
153 .type = AVMEDIA_TYPE_VIDEO,
154 .config_props = shuffleplanes_config_input,
155 .filter_frame = shuffleplanes_filter_frame,
156 },
157 };
158
159 const AVFilter ff_vf_shuffleplanes = {
160 .name = "shuffleplanes",
161 .description = NULL_IF_CONFIG_SMALL("Shuffle video planes."),
162 .priv_size = sizeof(ShufflePlanesContext),
163 .priv_class = &shuffleplanes_class,
164 FILTER_INPUTS(shuffleplanes_inputs),
165 FILTER_OUTPUTS(ff_video_default_filterpad),
166 FILTER_QUERY_FUNC2(query_formats),
167 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
168 };
169