FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_shuffleplanes.c
Date: 2024-07-17 14:05:47
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 "formats.h"
28 #include "internal.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(AVFilterContext *ctx)
45 {
46 2 AVFilterFormats *formats = NULL;
47 2 ShufflePlanesContext *s = ctx->priv;
48 int fmt, ret, i;
49
50
2/2
✓ Branch 1 taken 456 times.
✓ Branch 2 taken 2 times.
458 for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) {
51 456 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt);
52 456 int planes = av_pix_fmt_count_planes(fmt);
53
54
2/2
✓ Branch 0 taken 454 times.
✓ Branch 1 taken 2 times.
456 if (!(desc->flags & AV_PIX_FMT_FLAG_PAL) &&
55
2/2
✓ Branch 0 taken 426 times.
✓ Branch 1 taken 28 times.
454 !(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) {
56
2/2
✓ Branch 0 taken 1318 times.
✓ Branch 1 taken 233 times.
1551 for (i = 0; i < 4; i++) {
57
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 1199 times.
1318 if (s->map[i] >= planes)
58 119 break;
59
60
4/4
✓ Branch 0 taken 1019 times.
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 189 times.
✓ Branch 3 taken 830 times.
1199 if ((desc->log2_chroma_h || desc->log2_chroma_w) &&
61
10/10
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 123 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 197 times.
✓ Branch 4 taken 320 times.
✓ Branch 5 taken 49 times.
✓ Branch 6 taken 49 times.
✓ Branch 7 taken 271 times.
✓ Branch 8 taken 74 times.
✓ Branch 9 taken 295 times.
369 (i == 1 || i == 2) != (s->map[i] == 1 || s->map[i] == 2))
62 74 break;
63 }
64
65
2/2
✓ Branch 0 taken 193 times.
✓ Branch 1 taken 233 times.
426 if (i != 4)
66 193 continue;
67
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 233 times.
233 if ((ret = ff_add_format(&formats, fmt)) < 0) {
68 return ret;
69 }
70 }
71 }
72
73 2 return ff_set_common_formats(ctx, formats);
74 }
75
76 2 static av_cold int shuffleplanes_config_input(AVFilterLink *inlink)
77 {
78 2 AVFilterContext *ctx = inlink->dst;
79 2 ShufflePlanesContext *s = ctx->priv;
80 2 int used[4] = { 0 };
81 int i;
82
83 2 s->copy = 0;
84 2 s->planes = av_pix_fmt_count_planes(inlink->format);
85
86
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 for (i = 0; i < s->planes; i++) {
87
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 if (used[s->map[i]])
88 3 s->copy = 1;
89 7 used[s->map[i]]++;
90 }
91
92 2 return 0;
93 }
94
95 100 static int shuffleplanes_filter_frame(AVFilterLink *inlink, AVFrame *frame)
96 {
97 100 AVFilterContext *ctx = inlink->dst;
98 100 ShufflePlanesContext *s = ctx->priv;
99 100 uint8_t *shuffled_data[4] = { NULL };
100 100 int shuffled_linesize[4] = { 0 };
101 int i, ret;
102
103
2/2
✓ Branch 0 taken 350 times.
✓ Branch 1 taken 100 times.
450 for (i = 0; i < s->planes; i++) {
104 350 shuffled_data[i] = frame->data[s->map[i]];
105 350 shuffled_linesize[i] = frame->linesize[s->map[i]];
106 }
107 100 memcpy(frame->data, shuffled_data, sizeof(shuffled_data));
108 100 memcpy(frame->linesize, shuffled_linesize, sizeof(shuffled_linesize));
109
110
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 50 times.
100 if (s->copy) {
111 50 AVFrame *copy = ff_get_video_buffer(ctx->outputs[0], frame->width, frame->height);
112
113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!copy) {
114 ret = AVERROR(ENOMEM);
115 goto fail;
116 }
117
118 50 av_frame_copy(copy, frame);
119
120 50 ret = av_frame_copy_props(copy, frame);
121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (ret < 0) {
122 av_frame_free(&copy);
123 goto fail;
124 }
125
126 50 av_frame_free(&frame);
127 50 frame = copy;
128 }
129
130 100 return ff_filter_frame(ctx->outputs[0], frame);
131 fail:
132 av_frame_free(&frame);
133 return ret;
134 }
135
136 #define OFFSET(x) offsetof(ShufflePlanesContext, x)
137 #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
138 static const AVOption shuffleplanes_options[] = {
139 { "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 },
140 { "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 },
141 { "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 },
142 { "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 },
143 { NULL },
144 };
145
146 AVFILTER_DEFINE_CLASS(shuffleplanes);
147
148 static const AVFilterPad shuffleplanes_inputs[] = {
149 {
150 .name = "default",
151 .type = AVMEDIA_TYPE_VIDEO,
152 .config_props = shuffleplanes_config_input,
153 .filter_frame = shuffleplanes_filter_frame,
154 },
155 };
156
157 const AVFilter ff_vf_shuffleplanes = {
158 .name = "shuffleplanes",
159 .description = NULL_IF_CONFIG_SMALL("Shuffle video planes."),
160 .priv_size = sizeof(ShufflePlanesContext),
161 .priv_class = &shuffleplanes_class,
162 FILTER_INPUTS(shuffleplanes_inputs),
163 FILTER_OUTPUTS(ff_video_default_filterpad),
164 FILTER_QUERY_FUNC(query_formats),
165 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
166 };
167