lumiera_/tests/basics/time/time-dropframe-test.cpp
2025-06-07 23:59:57 +02:00

196 lines
6.2 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
TimeDropframe(test) - document drop-frame calculation
Copyright (C)
2010 Stefan Kangas <skangas@skangas.se>
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
* *****************************************************************/
/** @file time-dropframe-test.cpp
** unit test \ref TimeDropframe_test to document the
** algorithm to compute the components of drop-frame timecode.
** @see TimeFormats_test
** @see TimeValue_test
** @see timevalue.hpp
*/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/time/dropframe.hpp"
#include "lib/time/timevalue.hpp"
namespace lib {
namespace time{
namespace test{
using time::Time;
using time::TimeVar;
using time::FSecs;
using time::raw_time_64;
namespace {// Test setup
const int FRAMES = 15;
const int MILLIS = 700;
const int SECONDS = 20;
const int MINUTES = 55;
const int HOURS = 3;
/* ====== conversion helpers to verify results ====== */
const auto TIME_SCALE_sec{lib::time::TimeValue::SCALE };
const auto TIME_SCALE_ms {lib::time::TimeValue::SCALE / 1'000};
int
dropframe_frames (raw_time_64 timecode)
{
return calculate_ntsc_drop_frame_number(timecode) % 30;
}
int
dropframe_seconds (raw_time_64 timecode)
{
return calculate_ntsc_drop_frame_number(timecode) / 30 % 60;
}
int
dropframe_minutes (raw_time_64 timecode)
{
return calculate_ntsc_drop_frame_number(timecode) / 30 / 60 % 60;
}
int
dropframe_hours (raw_time_64 timecode)
{
return calculate_ntsc_drop_frame_number(timecode) / 30 / 60 / 60 % 24;
}
int
time_hours (raw_time_64 time)
{
return time / TIME_SCALE_sec / 60 / 60;
}
int
time_minutes (raw_time_64 time)
{
return (time / TIME_SCALE_sec / 60) % 60;
}
int
time_seconds (raw_time_64 time)
{
return (time / TIME_SCALE_sec) % 60;
}
int
time_millis (raw_time_64 time)
{
return (time / TIME_SCALE_ms) % 1000;
}
}
/******************************************************************//**
* @test document the computation of NTSC drop frame timecode mapping.
*/
class TimeDropframe_test : public Test
{
virtual void
run (Arg)
{
verify_DropFrame_conv();
verify_completeMapping();
}
/** @test perform a drop-frame timecode conversion
* and verify the complete round-trip is correct.
*/
void
verify_DropFrame_conv()
{
// Make sure frame 0 begins at 0
raw_time_64 t = build_time_from_ntsc_drop_frame (0, 0, 0, 0);
CHECK (t == 0);
t = build_time_from_ntsc_drop_frame (FRAMES, SECONDS, MINUTES, HOURS);
// Calculate manually what result to expect....
int frames = FRAMES + 30*SECONDS + 30*60*MINUTES + 30*60*60*HOURS; // sum up using nominal 30fps
int minutes_to_drop_frames = (MINUTES - MINUTES/10) + (HOURS * 54); // but every minute, with the exception of every 10 minutes...
frames -= 2*minutes_to_drop_frames; // ...drop 2 frames
int64_t expectedMillis = 1000LL * frames * 1001/30000; // now convert frames to time, using the real framerate
expectedMillis %= 1000; // look at the remainder..
CHECK (time_millis (t) == expectedMillis);
CHECK (time_seconds (t) == SECONDS); // while all other components should come out equal as set
CHECK (time_minutes (t) == MINUTES);
CHECK (time_hours (t) == HOURS);
// Reverse calculate frames for NTSC drop
//CHECK (lumiera_quantise_frames (t, 0, dropFrameDuration) == frames); // the total nominal frames
CHECK (dropframe_frames (t) == FRAMES); // maximum one frame off due to rounding
}
/** @test Cover the whole value range of a day in drop-frame:
* - manually construct a drop-frame timecode
* - make sure our library function returns the same times.
*/
void
verify_completeMapping()
{
for (int hrs = 0; hrs <= 24; hrs += 6)
for (int min = 0; min <= 59; min += 1)
for (int sec = 0; sec <= 59; sec += 10)
for (int frame = 0; frame <= 29; frame++)
{
// Skip dropped frames
if (min % 10 and sec == 0 and frame < 2)
continue;
raw_time_64 t = build_time_from_ntsc_drop_frame(frame, sec, min, hrs);
/*
ECHO ("%02d:%02d:%02d;%02d"
, lumiera_time_ntsc_drop_hours (t)
, lumiera_time_ntsc_drop_minutes (t)
, lumiera_time_ntsc_drop_seconds (t)
, lumiera_time_ntsc_drop_frames (t)
);
*/
CHECK (dropframe_frames (t) == frame);
CHECK (dropframe_seconds (t) == sec);
CHECK (dropframe_minutes (t) == min);
CHECK (dropframe_hours (t) == hrs % 24);
}
// Make sure we do not get non-existent frames
for (int i = 0; i < 59; i++)
{
int frame = (i % 10 == 0) ? 0 : 2;
raw_time_64 t = build_time_from_ntsc_drop_frame (frame, 0, i, 0);
CHECK (dropframe_frames (t) == frame);
}
}
};
/** Register this test class... */
LAUNCHER (TimeDropframe_test, "unit common");
}}} // namespace lib::time::test