FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/tests/unscaled_threaded.c
Date: 2026-10-20 22:17:59
Exec Total Coverage
Lines: 68 76 89.5%
Functions: 4 4 100.0%
Branches: 39 50 78.0%

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 <stdio.h>
20 #include <string.h>
21
22 #include "libavutil/frame.h"
23 #include "libavutil/imgutils.h"
24 #include "libavutil/log.h"
25 #include "libavutil/opt.h"
26 #include "libavutil/pixdesc.h"
27 #include "libswscale/swscale.h"
28
29 2250 static AVFrame *alloc_frame(enum AVPixelFormat format, int height)
30 {
31 2250 AVFrame *frame = av_frame_alloc();
32
33
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2250 times.
2250 if (!frame)
34 ✗ return NULL;
35 2250 frame->format = format;
36 2250 frame->width = 64;
37 2250 frame->height = height;
38
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2250 times.
2250 if (av_frame_get_buffer(frame, 32) < 0)
39 ✗ av_frame_free(&frame);
40 2250 return frame;
41 }
42
43 3750 static int convert(AVFrame *dst, const AVFrame *src, int threads, int legacy)
44 {
45 3750 struct SwsContext *sws = sws_alloc_context();
46 int ret;
47
48
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3750 times.
3750 if (!sws)
49 ✗ return AVERROR(ENOMEM);
50 3750 av_opt_set_int(sws, "threads", threads, 0);
51 3750 av_opt_set_int(sws, "sws_flags", SWS_BILINEAR, 0);
52 3750 av_opt_set(sws, "sws_dither", "none", 0);
53
2/2
✓ Branch 0 taken 1875 times.
✓ Branch 1 taken 1875 times.
3750 if (legacy) {
54 1875 av_opt_set_int(sws, "srcw", src->width, 0);
55 1875 av_opt_set_int(sws, "srch", src->height, 0);
56 1875 av_opt_set_int(sws, "src_format", src->format, 0);
57 1875 av_opt_set_int(sws, "dstw", dst->width, 0);
58 1875 av_opt_set_int(sws, "dsth", dst->height, 0);
59 1875 av_opt_set_int(sws, "dst_format", dst->format, 0);
60 1875 ret = sws_init_context(sws, NULL, NULL);
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1875 times.
1875 if (ret < 0)
62 ✗ goto end;
63 }
64 3750 ret = sws_scale_frame(sws, dst, src);
65 3750 end:
66 3750 sws_freeContext(sws);
67 3750 return ret;
68 }
69
70 750 static int compare(enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
71 int height, int legacy, unsigned *mismatches)
72 {
73 static const int threads[] = { 2, 3, 7, 16 };
74 750 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(src_fmt);
75 750 AVFrame *src = alloc_frame(src_fmt, height);
76 750 AVFrame *ref = alloc_frame(dst_fmt, height);
77 750 AVFrame *dst = alloc_frame(dst_fmt, height);
78 750 int ret = AVERROR(ENOMEM);
79
80
3/6
✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 750 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 750 times.
750 if (!src || !ref || !dst)
81 ✗ goto end;
82
4/4
✓ Branch 0 taken 2700 times.
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 2100 times.
✓ Branch 3 taken 600 times.
2850 for (int p = 0; p < 4 && src->data[p]; p++) {
83
4/4
✓ Branch 0 taken 1350 times.
✓ Branch 1 taken 750 times.
✓ Branch 2 taken 450 times.
✓ Branch 3 taken 900 times.
2100 const int h = AV_CEIL_RSHIFT(height, p == 1 || p == 2 ? desc->log2_chroma_h : 0);
84 2100 const int w = av_image_get_linesize(src_fmt, src->width, p);
85
2/2
✓ Branch 0 taken 39600 times.
✓ Branch 1 taken 2100 times.
41700 for (int y = 0; y < h; y++)
86
2/2
✓ Branch 0 taken 2073600 times.
✓ Branch 1 taken 39600 times.
2113200 for (int x = 0; x < w; x++)
87 2073600 src->data[p][y * src->linesize[p] + x] =
88 2073600 (x * 37 + y * 73 + x * y * 11 + p * 59) & 255;
89 }
90 750 ret = convert(ref, src, 1, legacy);
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 750 times.
750 if (ret < 0)
92 ✗ goto end;
93
2/2
✓ Branch 0 taken 3000 times.
✓ Branch 1 taken 750 times.
3750 for (int t = 0; t < FF_ARRAY_ELEMS(threads); t++) {
94 3000 ret = convert(dst, src, threads[t], legacy);
95
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3000 times.
3000 if (ret < 0)
96 ✗ goto end;
97
3/4
✓ Branch 0 taken 6400 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3400 times.
✓ Branch 3 taken 3000 times.
6400 for (int p = 0; p < 4 && dst->data[p]; p++) {
98 3400 const int w = av_image_get_linesize(dst_fmt, dst->width, p);
99
2/2
✓ Branch 0 taken 81600 times.
✓ Branch 1 taken 3400 times.
85000 for (int y = 0; y < height; y++)
100 81600 *mismatches += !!memcmp(ref->data[p] + y * ref->linesize[p],
101 81600 dst->data[p] + y * dst->linesize[p], w);
102 }
103 }
104 750 end:
105 750 av_frame_free(&src);
106 750 av_frame_free(&ref);
107 750 av_frame_free(&dst);
108 750 return ret;
109 }
110
111 1 int main(void)
112 {
113 static const enum AVPixelFormat inputs[] = {
114 AV_PIX_FMT_NV12, AV_PIX_FMT_NV21, AV_PIX_FMT_YUV420P,
115 AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV422P,
116 };
117 static const enum AVPixelFormat outputs[] = {
118 AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
119 AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, AV_PIX_FMT_GBRP,
120 AV_PIX_FMT_RGB565LE, AV_PIX_FMT_BGR565LE,
121 AV_PIX_FMT_RGB555LE, AV_PIX_FMT_BGR555LE,
122 AV_PIX_FMT_RGB565BE, AV_PIX_FMT_BGR565BE,
123 AV_PIX_FMT_RGB555BE, AV_PIX_FMT_BGR555BE,
124 };
125 static const int heights[] = { 2, 6, 14, 48, 50 };
126
127 1 av_log_set_level(AV_LOG_ERROR);
128
129 /* Compare against the same implementation with one thread, since different
130 * architectures need not produce identical rounding. Include both the
131 * dynamic graph and the initialized legacy context APIs. */
132
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 for (int s = 0; s < FF_ARRAY_ELEMS(inputs); s++) {
133
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 5 times.
80 for (int d = 0; d < FF_ARRAY_ELEMS(outputs); d++) {
134 75 unsigned mismatches = 0;
135
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 75 times.
225 for (int legacy = 0; legacy <= 1; legacy++) {
136
2/2
✓ Branch 0 taken 750 times.
✓ Branch 1 taken 150 times.
900 for (int h = 0; h < FF_ARRAY_ELEMS(heights); h++) {
137 750 int ret = compare(inputs[s], outputs[d], heights[h], legacy, &mismatches);
138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 750 times.
750 if (ret < 0)
139 ✗ return 1;
140 }
141 }
142 75 printf("%s -> %s: %u mismatching rows\n",
143 75 av_get_pix_fmt_name(inputs[s]), av_get_pix_fmt_name(outputs[d]),
144 mismatches);
145 }
146 }
147 1 return 0;
148 }
149