FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/tests/timecode.c
Date: 2026-04-10 12:18:52
Exec Total Coverage
Lines: 110 110 100.0%
Functions: 11 11 100.0%
Branches: 9 10 90.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 /**
20 * Unit tests for libavutil/timecode.c:
21 * av_timecode_init, av_timecode_init_from_components,
22 * av_timecode_init_from_string, av_timecode_make_string,
23 * av_timecode_get_smpte_from_framenum, av_timecode_get_smpte,
24 * av_timecode_make_smpte_tc_string, av_timecode_make_smpte_tc_string2,
25 * av_timecode_make_mpeg_tc_string, av_timecode_adjust_ntsc_framenum2,
26 * av_timecode_check_frame_rate
27 */
28
29 #include <stdio.h>
30 #include <string.h>
31
32 #include "libavutil/macros.h"
33 #include "libavutil/rational.h"
34 #include "libavutil/timecode.h"
35
36 1 static void test_check_frame_rate(void)
37 {
38 static const AVRational rates[] = {
39 {24, 1}, {25, 1}, {30, 1}, {48, 1}, {50, 1}, {60, 1},
40 {100, 1}, {120, 1}, {150, 1},
41 {30000, 1001}, {15, 1}, {12, 1},
42 {0, 0}, {30, 0},
43 };
44
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1 times.
15 for (int i = 0; i < FF_ARRAY_ELEMS(rates); i++)
45 14 printf("check_frame_rate %d/%d: %d\n",
46 14 rates[i].num, rates[i].den,
47 av_timecode_check_frame_rate(rates[i]));
48 1 }
49
50 1 static void test_init(void)
51 {
52 AVTimecode tc;
53 static const struct {
54 AVRational rate;
55 int flags;
56 int start;
57 } cases[] = {
58 { {25, 1}, 0, 0 },
59 { {30, 1}, AV_TIMECODE_FLAG_DROPFRAME, 0 },
60 { {24, 1}, 0, 100 },
61 { {0, 1}, 0, 0 },
62 { {25, 1}, AV_TIMECODE_FLAG_DROPFRAME, 0 },
63 { {30000, 1001}, AV_TIMECODE_FLAG_DROPFRAME, 0 },
64 { {25, 1}, AV_TIMECODE_FLAG_ALLOWNEGATIVE, -100 },
65 };
66
67
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 for (int i = 0; i < FF_ARRAY_ELEMS(cases); i++) {
68 7 int ret = av_timecode_init(&tc, cases[i].rate, cases[i].flags, cases[i].start, NULL);
69 7 printf("init %d/%d flags:%d start:%d: ",
70 7 cases[i].rate.num, cases[i].rate.den, cases[i].flags, cases[i].start);
71
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 if (ret < 0) {
72 2 printf("error\n");
73 } else {
74 5 printf("ok fps=%d start=%d rate=%d/%d\n",
75 tc.fps, tc.start, tc.rate.num, tc.rate.den);
76 }
77 }
78 1 }
79
80 1 static void test_init_from_components(void)
81 {
82 AVTimecode tc;
83 int ret;
84
85 1 ret = av_timecode_init_from_components(&tc, (AVRational){25, 1},
86 0, 0, 0, 0, 0, NULL);
87 1 printf("from_components 25/1 00:00:00:00: %d start=%d\n", ret, tc.start);
88
89 1 ret = av_timecode_init_from_components(&tc, (AVRational){25, 1},
90 0, 1, 0, 0, 0, NULL);
91 1 printf("from_components 25/1 01:00:00:00: %d start=%d\n", ret, tc.start);
92
93 1 ret = av_timecode_init_from_components(&tc, (AVRational){30, 1},
94 0, 1, 2, 3, 4, NULL);
95 1 printf("from_components 30/1 01:02:03:04: %d start=%d\n", ret, tc.start);
96
97 1 ret = av_timecode_init_from_components(&tc, (AVRational){30000, 1001},
98 AV_TIMECODE_FLAG_DROPFRAME,
99 1, 0, 0, 0, NULL);
100 1 printf("from_components 30000/1001 drop 01:00:00;00: %d start=%d\n",
101 ret, tc.start);
102 1 }
103
104 1 static void test_init_from_string(void)
105 {
106 AVTimecode tc;
107 int ret;
108
109 1 ret = av_timecode_init_from_string(&tc, (AVRational){30, 1},
110 "00:01:02:03", NULL);
111 1 printf("from_string 30/1 00:01:02:03: %d drop=%d start=%d\n",
112 1 ret, !!(tc.flags & AV_TIMECODE_FLAG_DROPFRAME), tc.start);
113
114 1 ret = av_timecode_init_from_string(&tc, (AVRational){30000, 1001},
115 "00:01:00;02", NULL);
116 1 printf("from_string 30000/1001 00:01:00;02: %d drop=%d\n",
117 1 ret, !!(tc.flags & AV_TIMECODE_FLAG_DROPFRAME));
118
119 1 ret = av_timecode_init_from_string(&tc, (AVRational){30000, 1001},
120 "01:00:00.00", NULL);
121 1 printf("from_string 30000/1001 01:00:00.00: %d drop=%d\n",
122 1 ret, !!(tc.flags & AV_TIMECODE_FLAG_DROPFRAME));
123
124 1 ret = av_timecode_init_from_string(&tc, (AVRational){25, 1},
125 "notvalid", NULL);
126
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 printf("from_string 25/1 notvalid: %s\n", ret < 0 ? "error" : "ok");
127 1 }
128
129 1 static void test_make_string(void)
130 {
131 AVTimecode tc;
132 char buf[AV_TIMECODE_STR_SIZE];
133
134 1 av_timecode_init(&tc, (AVRational){25, 1}, 0, 0, NULL);
135 1 printf("make_string 25/1 35: %s\n", av_timecode_make_string(&tc, buf, 35));
136 1 printf("make_string 25/1 0: %s\n", av_timecode_make_string(&tc, buf, 0));
137
138 1 av_timecode_init(&tc, (AVRational){30, 1}, 0, 0, NULL);
139 1 printf("make_string 30/1 30: %s\n", av_timecode_make_string(&tc, buf, 30));
140
141 1 av_timecode_init(&tc, (AVRational){25, 1},
142 AV_TIMECODE_FLAG_24HOURSMAX, 0, NULL);
143 1 printf("make_string 25/1 24hwrap %d: %s\n",
144 25 * 3600 * 25, av_timecode_make_string(&tc, buf, 25 * 3600 * 25));
145
146 1 av_timecode_init(&tc, (AVRational){30000, 1001},
147 AV_TIMECODE_FLAG_DROPFRAME, 0, NULL);
148 1 printf("make_string 30000/1001 drop 0: %s\n",
149 av_timecode_make_string(&tc, buf, 0));
150
151 1 av_timecode_init(&tc, (AVRational){25, 1},
152 AV_TIMECODE_FLAG_ALLOWNEGATIVE, -100, NULL);
153 1 printf("make_string 25/1 negative start -100 frame 0: %s\n",
154 av_timecode_make_string(&tc, buf, 0));
155 1 }
156
157 1 static void test_make_smpte_tc_string(void)
158 {
159 char buf[AV_TIMECODE_STR_SIZE];
160 AVTimecode tc;
161 uint32_t smpte;
162
163 1 smpte = av_timecode_get_smpte((AVRational){30, 1}, 0, 1, 2, 3, 4);
164 1 printf("smpte_tc 30/1 01:02:03:04: %s\n",
165 av_timecode_make_smpte_tc_string(buf, smpte, 1));
166
167 1 av_timecode_init(&tc, (AVRational){25, 1}, 0, 0, NULL);
168 1 smpte = av_timecode_get_smpte_from_framenum(&tc,
169 25 * 3600 + 25 * 60 + 25 + 5);
170 1 printf("smpte_from_framenum 25/1 91530: %s\n",
171 av_timecode_make_smpte_tc_string(buf, smpte, 1));
172 1 }
173
174 1 static void test_make_smpte_tc_string2(void)
175 {
176 char buf[AV_TIMECODE_STR_SIZE];
177 uint32_t smpte;
178
179 1 smpte = av_timecode_get_smpte((AVRational){50, 1}, 0, 0, 0, 0, 0);
180 1 printf("smpte_tc2 50/1 00:00:00:00: %s\n",
181 1 av_timecode_make_smpte_tc_string2(buf, (AVRational){50, 1},
182 smpte, 1, 0));
183
184 1 smpte = av_timecode_get_smpte((AVRational){60, 1}, 0, 1, 0, 0, 0);
185 1 printf("smpte_tc2 60/1 01:00:00:00: %s\n",
186 1 av_timecode_make_smpte_tc_string2(buf, (AVRational){60, 1},
187 smpte, 1, 0));
188 1 }
189
190 1 static void test_make_mpeg_tc_string(void)
191 {
192 char buf[AV_TIMECODE_STR_SIZE];
193
194 1 uint32_t tc25 = (1u << 19) | (2u << 13) | (3u << 6) | 4u;
195 1 printf("mpeg_tc 01:02:03:04: %s\n",
196 av_timecode_make_mpeg_tc_string(buf, tc25));
197
198 1 uint32_t tc25_drop = tc25 | (1u << 24);
199 1 printf("mpeg_tc drop 01:02:03:04: %s\n",
200 av_timecode_make_mpeg_tc_string(buf, tc25_drop));
201 1 }
202
203 1 static void test_adjust_ntsc(void)
204 {
205 static const struct {
206 int framenum;
207 int fps;
208 } cases[] = {
209 { 0, 30 },
210 { 1800, 30 },
211 { 1000, 25 },
212 { 1000, 0 },
213 { 3600, 60 },
214 };
215
216
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 for (int i = 0; i < FF_ARRAY_ELEMS(cases); i++) {
217 10 printf("adjust_ntsc %d %d: %d\n",
218 5 cases[i].framenum, cases[i].fps,
219 5 av_timecode_adjust_ntsc_framenum2(cases[i].framenum,
220 5 cases[i].fps));
221 }
222 1 }
223
224 1 static void test_get_smpte_roundtrip(void)
225 {
226 char buf[AV_TIMECODE_STR_SIZE];
227 char buf2[AV_TIMECODE_STR_SIZE];
228 uint32_t smpte;
229
230 1 smpte = av_timecode_get_smpte((AVRational){30, 1}, 0, 12, 34, 56, 7);
231 1 printf("smpte_roundtrip 30/1 12:34:56:07: %s / %s\n",
232 av_timecode_make_smpte_tc_string(buf, smpte, 1),
233 1 av_timecode_make_smpte_tc_string2(buf2, (AVRational){30, 1},
234 smpte, 1, 0));
235
236 1 smpte = av_timecode_get_smpte((AVRational){30, 1}, 0, 0, 0, 0, 0);
237 1 printf("smpte_roundtrip 30/1 00:00:00:00: %s / %s\n",
238 av_timecode_make_smpte_tc_string(buf, smpte, 1),
239 1 av_timecode_make_smpte_tc_string2(buf2, (AVRational){30, 1},
240 smpte, 1, 0));
241
242 1 smpte = av_timecode_get_smpte((AVRational){30000, 1001}, 1, 0, 1, 0, 2);
243 1 printf("smpte_roundtrip 30000/1001 drop bit30=%d: %s / %s\n",
244 1 !!(smpte & (1u << 30)),
245 av_timecode_make_smpte_tc_string(buf, smpte, 0),
246 1 av_timecode_make_smpte_tc_string2(buf2, (AVRational){30000, 1001},
247 smpte, 0, 0));
248
249 /* >30 fps SMPTE field bit handling test */
250 1 smpte = av_timecode_get_smpte((AVRational){50, 1}, 0, 0, 0, 0, 49);
251 1 printf("smpte_roundtrip 50/1 field bit7=%d: %s / %s\n",
252 1 !!(smpte & (1u << 7)),
253 av_timecode_make_smpte_tc_string(buf, smpte, 0),
254 1 av_timecode_make_smpte_tc_string2(buf2, (AVRational){50, 1},
255 smpte, 0, 0));
256
257 1 smpte = av_timecode_get_smpte((AVRational){60000, 1001}, 0, 0, 0, 0, 59);
258 1 printf("smpte_roundtrip 60000/1001 field bit23=%d: %s / %s\n",
259 1 !!(smpte & (1u << 23)),
260 av_timecode_make_smpte_tc_string(buf, smpte, 0),
261 1 av_timecode_make_smpte_tc_string2(buf2, (AVRational){60000, 1001},
262 smpte, 0, 0));
263 1 }
264
265 1 int main(void)
266 {
267 1 test_check_frame_rate();
268 1 test_init();
269 1 test_init_from_components();
270 1 test_init_from_string();
271 1 test_make_string();
272 1 test_make_smpte_tc_string();
273 1 test_make_smpte_tc_string2();
274 1 test_make_mpeg_tc_string();
275 1 test_adjust_ntsc();
276 1 test_get_smpte_roundtrip();
277 1 return 0;
278 }
279