mirror of
https://mirror.skon.top/https://github.com/FFmpeg/FFmpeg
synced 2026-04-20 12:50:49 +08:00
fate: add unit tests for libavutil/timecode functions
This commit is contained in:
committed by
Michael Niedermayer
parent
b462674645
commit
7b49a69f43
@@ -307,6 +307,7 @@ TESTPROGS = adler32 \
|
||||
softfloat \
|
||||
spherical \
|
||||
stereo3d \
|
||||
timecode \
|
||||
tree \
|
||||
twofish \
|
||||
utf8 \
|
||||
|
||||
278
libavutil/tests/timecode.c
Normal file
278
libavutil/tests/timecode.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* Unit tests for libavutil/timecode.c:
|
||||
* av_timecode_init, av_timecode_init_from_components,
|
||||
* av_timecode_init_from_string, av_timecode_make_string,
|
||||
* av_timecode_get_smpte_from_framenum, av_timecode_get_smpte,
|
||||
* av_timecode_make_smpte_tc_string, av_timecode_make_smpte_tc_string2,
|
||||
* av_timecode_make_mpeg_tc_string, av_timecode_adjust_ntsc_framenum2,
|
||||
* av_timecode_check_frame_rate
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libavutil/macros.h"
|
||||
#include "libavutil/rational.h"
|
||||
#include "libavutil/timecode.h"
|
||||
|
||||
static void test_check_frame_rate(void)
|
||||
{
|
||||
static const AVRational rates[] = {
|
||||
{24, 1}, {25, 1}, {30, 1}, {48, 1}, {50, 1}, {60, 1},
|
||||
{100, 1}, {120, 1}, {150, 1},
|
||||
{30000, 1001}, {15, 1}, {12, 1},
|
||||
{0, 0}, {30, 0},
|
||||
};
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(rates); i++)
|
||||
printf("check_frame_rate %d/%d: %d\n",
|
||||
rates[i].num, rates[i].den,
|
||||
av_timecode_check_frame_rate(rates[i]));
|
||||
}
|
||||
|
||||
static void test_init(void)
|
||||
{
|
||||
AVTimecode tc;
|
||||
static const struct {
|
||||
AVRational rate;
|
||||
int flags;
|
||||
int start;
|
||||
} cases[] = {
|
||||
{ {25, 1}, 0, 0 },
|
||||
{ {30, 1}, AV_TIMECODE_FLAG_DROPFRAME, 0 },
|
||||
{ {24, 1}, 0, 100 },
|
||||
{ {0, 1}, 0, 0 },
|
||||
{ {25, 1}, AV_TIMECODE_FLAG_DROPFRAME, 0 },
|
||||
{ {30000, 1001}, AV_TIMECODE_FLAG_DROPFRAME, 0 },
|
||||
{ {25, 1}, AV_TIMECODE_FLAG_ALLOWNEGATIVE, -100 },
|
||||
};
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(cases); i++) {
|
||||
int ret = av_timecode_init(&tc, cases[i].rate, cases[i].flags, cases[i].start, NULL);
|
||||
printf("init %d/%d flags:%d start:%d: ",
|
||||
cases[i].rate.num, cases[i].rate.den, cases[i].flags, cases[i].start);
|
||||
if (ret < 0) {
|
||||
printf("error\n");
|
||||
} else {
|
||||
printf("ok fps=%d start=%d rate=%d/%d\n",
|
||||
tc.fps, tc.start, tc.rate.num, tc.rate.den);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_init_from_components(void)
|
||||
{
|
||||
AVTimecode tc;
|
||||
int ret;
|
||||
|
||||
ret = av_timecode_init_from_components(&tc, (AVRational){25, 1},
|
||||
0, 0, 0, 0, 0, NULL);
|
||||
printf("from_components 25/1 00:00:00:00: %d start=%d\n", ret, tc.start);
|
||||
|
||||
ret = av_timecode_init_from_components(&tc, (AVRational){25, 1},
|
||||
0, 1, 0, 0, 0, NULL);
|
||||
printf("from_components 25/1 01:00:00:00: %d start=%d\n", ret, tc.start);
|
||||
|
||||
ret = av_timecode_init_from_components(&tc, (AVRational){30, 1},
|
||||
0, 1, 2, 3, 4, NULL);
|
||||
printf("from_components 30/1 01:02:03:04: %d start=%d\n", ret, tc.start);
|
||||
|
||||
ret = av_timecode_init_from_components(&tc, (AVRational){30000, 1001},
|
||||
AV_TIMECODE_FLAG_DROPFRAME,
|
||||
1, 0, 0, 0, NULL);
|
||||
printf("from_components 30000/1001 drop 01:00:00;00: %d start=%d\n",
|
||||
ret, tc.start);
|
||||
}
|
||||
|
||||
static void test_init_from_string(void)
|
||||
{
|
||||
AVTimecode tc;
|
||||
int ret;
|
||||
|
||||
ret = av_timecode_init_from_string(&tc, (AVRational){30, 1},
|
||||
"00:01:02:03", NULL);
|
||||
printf("from_string 30/1 00:01:02:03: %d drop=%d start=%d\n",
|
||||
ret, !!(tc.flags & AV_TIMECODE_FLAG_DROPFRAME), tc.start);
|
||||
|
||||
ret = av_timecode_init_from_string(&tc, (AVRational){30000, 1001},
|
||||
"00:01:00;02", NULL);
|
||||
printf("from_string 30000/1001 00:01:00;02: %d drop=%d\n",
|
||||
ret, !!(tc.flags & AV_TIMECODE_FLAG_DROPFRAME));
|
||||
|
||||
ret = av_timecode_init_from_string(&tc, (AVRational){30000, 1001},
|
||||
"01:00:00.00", NULL);
|
||||
printf("from_string 30000/1001 01:00:00.00: %d drop=%d\n",
|
||||
ret, !!(tc.flags & AV_TIMECODE_FLAG_DROPFRAME));
|
||||
|
||||
ret = av_timecode_init_from_string(&tc, (AVRational){25, 1},
|
||||
"notvalid", NULL);
|
||||
printf("from_string 25/1 notvalid: %s\n", ret < 0 ? "error" : "ok");
|
||||
}
|
||||
|
||||
static void test_make_string(void)
|
||||
{
|
||||
AVTimecode tc;
|
||||
char buf[AV_TIMECODE_STR_SIZE];
|
||||
|
||||
av_timecode_init(&tc, (AVRational){25, 1}, 0, 0, NULL);
|
||||
printf("make_string 25/1 35: %s\n", av_timecode_make_string(&tc, buf, 35));
|
||||
printf("make_string 25/1 0: %s\n", av_timecode_make_string(&tc, buf, 0));
|
||||
|
||||
av_timecode_init(&tc, (AVRational){30, 1}, 0, 0, NULL);
|
||||
printf("make_string 30/1 30: %s\n", av_timecode_make_string(&tc, buf, 30));
|
||||
|
||||
av_timecode_init(&tc, (AVRational){25, 1},
|
||||
AV_TIMECODE_FLAG_24HOURSMAX, 0, NULL);
|
||||
printf("make_string 25/1 24hwrap %d: %s\n",
|
||||
25 * 3600 * 25, av_timecode_make_string(&tc, buf, 25 * 3600 * 25));
|
||||
|
||||
av_timecode_init(&tc, (AVRational){30000, 1001},
|
||||
AV_TIMECODE_FLAG_DROPFRAME, 0, NULL);
|
||||
printf("make_string 30000/1001 drop 0: %s\n",
|
||||
av_timecode_make_string(&tc, buf, 0));
|
||||
|
||||
av_timecode_init(&tc, (AVRational){25, 1},
|
||||
AV_TIMECODE_FLAG_ALLOWNEGATIVE, -100, NULL);
|
||||
printf("make_string 25/1 negative start -100 frame 0: %s\n",
|
||||
av_timecode_make_string(&tc, buf, 0));
|
||||
}
|
||||
|
||||
static void test_make_smpte_tc_string(void)
|
||||
{
|
||||
char buf[AV_TIMECODE_STR_SIZE];
|
||||
AVTimecode tc;
|
||||
uint32_t smpte;
|
||||
|
||||
smpte = av_timecode_get_smpte((AVRational){30, 1}, 0, 1, 2, 3, 4);
|
||||
printf("smpte_tc 30/1 01:02:03:04: %s\n",
|
||||
av_timecode_make_smpte_tc_string(buf, smpte, 1));
|
||||
|
||||
av_timecode_init(&tc, (AVRational){25, 1}, 0, 0, NULL);
|
||||
smpte = av_timecode_get_smpte_from_framenum(&tc,
|
||||
25 * 3600 + 25 * 60 + 25 + 5);
|
||||
printf("smpte_from_framenum 25/1 91530: %s\n",
|
||||
av_timecode_make_smpte_tc_string(buf, smpte, 1));
|
||||
}
|
||||
|
||||
static void test_make_smpte_tc_string2(void)
|
||||
{
|
||||
char buf[AV_TIMECODE_STR_SIZE];
|
||||
uint32_t smpte;
|
||||
|
||||
smpte = av_timecode_get_smpte((AVRational){50, 1}, 0, 0, 0, 0, 0);
|
||||
printf("smpte_tc2 50/1 00:00:00:00: %s\n",
|
||||
av_timecode_make_smpte_tc_string2(buf, (AVRational){50, 1},
|
||||
smpte, 1, 0));
|
||||
|
||||
smpte = av_timecode_get_smpte((AVRational){60, 1}, 0, 1, 0, 0, 0);
|
||||
printf("smpte_tc2 60/1 01:00:00:00: %s\n",
|
||||
av_timecode_make_smpte_tc_string2(buf, (AVRational){60, 1},
|
||||
smpte, 1, 0));
|
||||
}
|
||||
|
||||
static void test_make_mpeg_tc_string(void)
|
||||
{
|
||||
char buf[AV_TIMECODE_STR_SIZE];
|
||||
|
||||
uint32_t tc25 = (1u << 19) | (2u << 13) | (3u << 6) | 4u;
|
||||
printf("mpeg_tc 01:02:03:04: %s\n",
|
||||
av_timecode_make_mpeg_tc_string(buf, tc25));
|
||||
|
||||
uint32_t tc25_drop = tc25 | (1u << 24);
|
||||
printf("mpeg_tc drop 01:02:03:04: %s\n",
|
||||
av_timecode_make_mpeg_tc_string(buf, tc25_drop));
|
||||
}
|
||||
|
||||
static void test_adjust_ntsc(void)
|
||||
{
|
||||
static const struct {
|
||||
int framenum;
|
||||
int fps;
|
||||
} cases[] = {
|
||||
{ 0, 30 },
|
||||
{ 1800, 30 },
|
||||
{ 1000, 25 },
|
||||
{ 1000, 0 },
|
||||
{ 3600, 60 },
|
||||
};
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(cases); i++) {
|
||||
printf("adjust_ntsc %d %d: %d\n",
|
||||
cases[i].framenum, cases[i].fps,
|
||||
av_timecode_adjust_ntsc_framenum2(cases[i].framenum,
|
||||
cases[i].fps));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_get_smpte_roundtrip(void)
|
||||
{
|
||||
char buf[AV_TIMECODE_STR_SIZE];
|
||||
char buf2[AV_TIMECODE_STR_SIZE];
|
||||
uint32_t smpte;
|
||||
|
||||
smpte = av_timecode_get_smpte((AVRational){30, 1}, 0, 12, 34, 56, 7);
|
||||
printf("smpte_roundtrip 30/1 12:34:56:07: %s / %s\n",
|
||||
av_timecode_make_smpte_tc_string(buf, smpte, 1),
|
||||
av_timecode_make_smpte_tc_string2(buf2, (AVRational){30, 1},
|
||||
smpte, 1, 0));
|
||||
|
||||
smpte = av_timecode_get_smpte((AVRational){30, 1}, 0, 0, 0, 0, 0);
|
||||
printf("smpte_roundtrip 30/1 00:00:00:00: %s / %s\n",
|
||||
av_timecode_make_smpte_tc_string(buf, smpte, 1),
|
||||
av_timecode_make_smpte_tc_string2(buf2, (AVRational){30, 1},
|
||||
smpte, 1, 0));
|
||||
|
||||
smpte = av_timecode_get_smpte((AVRational){30000, 1001}, 1, 0, 1, 0, 2);
|
||||
printf("smpte_roundtrip 30000/1001 drop bit30=%d: %s / %s\n",
|
||||
!!(smpte & (1u << 30)),
|
||||
av_timecode_make_smpte_tc_string(buf, smpte, 0),
|
||||
av_timecode_make_smpte_tc_string2(buf2, (AVRational){30000, 1001},
|
||||
smpte, 0, 0));
|
||||
|
||||
/* >30 fps SMPTE field bit handling test */
|
||||
smpte = av_timecode_get_smpte((AVRational){50, 1}, 0, 0, 0, 0, 49);
|
||||
printf("smpte_roundtrip 50/1 field bit7=%d: %s / %s\n",
|
||||
!!(smpte & (1u << 7)),
|
||||
av_timecode_make_smpte_tc_string(buf, smpte, 0),
|
||||
av_timecode_make_smpte_tc_string2(buf2, (AVRational){50, 1},
|
||||
smpte, 0, 0));
|
||||
|
||||
smpte = av_timecode_get_smpte((AVRational){60000, 1001}, 0, 0, 0, 0, 59);
|
||||
printf("smpte_roundtrip 60000/1001 field bit23=%d: %s / %s\n",
|
||||
!!(smpte & (1u << 23)),
|
||||
av_timecode_make_smpte_tc_string(buf, smpte, 0),
|
||||
av_timecode_make_smpte_tc_string2(buf2, (AVRational){60000, 1001},
|
||||
smpte, 0, 0));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
test_check_frame_rate();
|
||||
test_init();
|
||||
test_init_from_components();
|
||||
test_init_from_string();
|
||||
test_make_string();
|
||||
test_make_smpte_tc_string();
|
||||
test_make_smpte_tc_string2();
|
||||
test_make_mpeg_tc_string();
|
||||
test_adjust_ntsc();
|
||||
test_get_smpte_roundtrip();
|
||||
return 0;
|
||||
}
|
||||
@@ -216,6 +216,10 @@ fate-file: libavutil/tests/file$(EXESUF)
|
||||
fate-file: CMD = run libavutil/tests/file$(EXESUF) $(SRC_PATH)/libavutil/tests/file.c
|
||||
fate-file: CMP = null
|
||||
|
||||
FATE_LIBAVUTIL += fate-timecode
|
||||
fate-timecode: libavutil/tests/timecode$(EXESUF)
|
||||
fate-timecode: CMD = run libavutil/tests/timecode$(EXESUF)
|
||||
|
||||
FATE_LIBAVUTIL += $(FATE_LIBAVUTIL-yes)
|
||||
FATE-$(CONFIG_AVUTIL) += $(FATE_LIBAVUTIL)
|
||||
fate-libavutil: $(FATE_LIBAVUTIL)
|
||||
|
||||
51
tests/ref/fate/timecode
Normal file
51
tests/ref/fate/timecode
Normal file
@@ -0,0 +1,51 @@
|
||||
check_frame_rate 24/1: 0
|
||||
check_frame_rate 25/1: 0
|
||||
check_frame_rate 30/1: 0
|
||||
check_frame_rate 48/1: 0
|
||||
check_frame_rate 50/1: 0
|
||||
check_frame_rate 60/1: 0
|
||||
check_frame_rate 100/1: 0
|
||||
check_frame_rate 120/1: 0
|
||||
check_frame_rate 150/1: 0
|
||||
check_frame_rate 30000/1001: 0
|
||||
check_frame_rate 15/1: -1
|
||||
check_frame_rate 12/1: -1
|
||||
check_frame_rate 0/0: -1
|
||||
check_frame_rate 30/0: -1
|
||||
init 25/1 flags:0 start:0: ok fps=25 start=0 rate=25/1
|
||||
init 30/1 flags:1 start:0: ok fps=30 start=0 rate=30/1
|
||||
init 24/1 flags:0 start:100: ok fps=24 start=100 rate=24/1
|
||||
init 0/1 flags:0 start:0: error
|
||||
init 25/1 flags:1 start:0: error
|
||||
init 30000/1001 flags:1 start:0: ok fps=30 start=0 rate=30000/1001
|
||||
init 25/1 flags:4 start:-100: ok fps=25 start=-100 rate=25/1
|
||||
from_components 25/1 00:00:00:00: 0 start=0
|
||||
from_components 25/1 01:00:00:00: 0 start=90000
|
||||
from_components 30/1 01:02:03:04: 0 start=111694
|
||||
from_components 30000/1001 drop 01:00:00;00: 0 start=107892
|
||||
from_string 30/1 00:01:02:03: 0 drop=0 start=1863
|
||||
from_string 30000/1001 00:01:00;02: 0 drop=1
|
||||
from_string 30000/1001 01:00:00.00: 0 drop=1
|
||||
from_string 25/1 notvalid: error
|
||||
make_string 25/1 35: 00:00:01:10
|
||||
make_string 25/1 0: 00:00:00:00
|
||||
make_string 30/1 30: 00:00:01:00
|
||||
make_string 25/1 24hwrap 2250000: 01:00:00:00
|
||||
make_string 30000/1001 drop 0: 00:00:00;00
|
||||
make_string 25/1 negative start -100 frame 0: -00:00:04:00
|
||||
smpte_tc 30/1 01:02:03:04: 01:02:03:04
|
||||
smpte_from_framenum 25/1 91530: 01:01:01:05
|
||||
smpte_tc2 50/1 00:00:00:00: 00:00:00:00
|
||||
smpte_tc2 60/1 01:00:00:00: 01:00:00:00
|
||||
mpeg_tc 01:02:03:04: 01:02:03:04
|
||||
mpeg_tc drop 01:02:03:04: 01:02:03;04
|
||||
adjust_ntsc 0 30: 0
|
||||
adjust_ntsc 1800 30: 1802
|
||||
adjust_ntsc 1000 25: 1000
|
||||
adjust_ntsc 1000 0: 1000
|
||||
adjust_ntsc 3600 60: 3604
|
||||
smpte_roundtrip 30/1 12:34:56:07: 12:34:56:07 / 12:34:56:07
|
||||
smpte_roundtrip 30/1 00:00:00:00: 00:00:00:00 / 00:00:00:00
|
||||
smpte_roundtrip 30000/1001 drop bit30=1: 00:01:00;02 / 00:01:00;02
|
||||
smpte_roundtrip 50/1 field bit7=1: 00:00:00:24 / 00:00:00:49
|
||||
smpte_roundtrip 60000/1001 field bit23=1: 00:00:00:29 / 00:00:00:59
|
||||
Reference in New Issue
Block a user