Merge Stefan's work on timeconversion and SMPTE drop-frame
This commit is contained in:
commit
9df0df6145
4 changed files with 284 additions and 28 deletions
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
time.c - Utilities for handling time
|
||||
Time - Utilities for handling time
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Christian Thaeter <ct@pipapo.org>
|
||||
2011, Christian Thaeter <ct@pipapo.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -137,26 +137,105 @@ lumiera_build_time(long millis, uint secs, uint mins, uint hours)
|
|||
return time;
|
||||
}
|
||||
|
||||
gavl_time_t
|
||||
lumiera_build_time_fps (float fps, uint frames, uint secs, uint mins, uint hours)
|
||||
{
|
||||
gavl_time_t time = frames * (1000.0 / fps)
|
||||
+ 1000 * secs
|
||||
+ 1000 * 60 * mins
|
||||
+ 1000 * 60 * 60 * hours;
|
||||
time *= GAVL_TIME_SCALE_MS;
|
||||
return time;
|
||||
}
|
||||
|
||||
gavl_time_t
|
||||
lumiera_build_time_ntsc_drop (uint frames, uint secs, uint mins, uint hours)
|
||||
{
|
||||
int total_mins = 60 * hours + mins;
|
||||
int total_frames = 108000 * hours
|
||||
+ 1800 * mins
|
||||
+ 30 * secs
|
||||
+ frames
|
||||
- 2 * (total_mins - total_mins / 10);
|
||||
|
||||
return (total_frames / 29.97f) * 1000 * GAVL_TIME_SCALE_MS;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_hours(gavl_time_t time)
|
||||
lumiera_time_hours (gavl_time_t time)
|
||||
{
|
||||
return time / GAVL_TIME_SCALE_MS / 1000 / 60 / 60;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_minutes(gavl_time_t time)
|
||||
lumiera_time_minutes (gavl_time_t time)
|
||||
{
|
||||
return (time / GAVL_TIME_SCALE_MS / 1000 / 60) % 60;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_seconds(gavl_time_t time)
|
||||
lumiera_time_seconds (gavl_time_t time)
|
||||
{
|
||||
return (time / GAVL_TIME_SCALE_MS / 1000) % 60;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_millis(gavl_time_t time)
|
||||
lumiera_time_millis (gavl_time_t time)
|
||||
{
|
||||
return (time / GAVL_TIME_SCALE_MS) % 1000;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_frames (gavl_time_t time, float fps)
|
||||
{
|
||||
return (fps * (lumiera_time_millis(time))) / 1000;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_frame_count (gavl_time_t time, float fps)
|
||||
{
|
||||
REQUIRE (fps > 0);
|
||||
|
||||
return roundf((time / GAVL_TIME_SCALE_MS / 1000.0f) * fps);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used in the NTSC drop-frame functions to avoid code
|
||||
* repetition.
|
||||
* @return the frame number for given time
|
||||
*/
|
||||
static int
|
||||
ntsc_drop_get_frame_number (gavl_time_t time)
|
||||
{
|
||||
int frame = lumiera_time_frame_count (time, NTSC_DROP_FRAME_FPS);
|
||||
|
||||
int d = frame / 17982; // 17982 = 600 * 29.97
|
||||
int m = frame % 17982; // 17982 = 600 * 29.97
|
||||
|
||||
return frame + 18*d + 2*((m - 2) / 1798); // 1798 = 60 * 29.97
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_ntsc_drop_frames (gavl_time_t time)
|
||||
{
|
||||
return ntsc_drop_get_frame_number(time) % 30;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_ntsc_drop_seconds (gavl_time_t time)
|
||||
{
|
||||
return ntsc_drop_get_frame_number(time) / 30 % 60;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_ntsc_drop_minutes (gavl_time_t time)
|
||||
{
|
||||
return ntsc_drop_get_frame_number(time) / 30 / 60 % 60;
|
||||
}
|
||||
|
||||
int
|
||||
lumiera_time_ntsc_drop_hours (gavl_time_t time)
|
||||
{
|
||||
return ntsc_drop_get_frame_number(time) / 30 / 60 / 60 % 24;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@ lumiera_frame_duration (lib::time::FrameRate const& fps);
|
|||
extern "C" { /* ===================== C interface ======================== */
|
||||
#endif
|
||||
|
||||
#define NTSC_DROP_FRAME_FPS 29.97
|
||||
/* TODO: replace this by lib/time/FrameRate::NTSC */
|
||||
|
||||
/**
|
||||
* Formats a time value in H:MM:SS.mmm format into a temporary buffer.
|
||||
|
|
@ -127,29 +129,87 @@ lumiera_time_of_gridpoint (long nr, gavl_time_t origin, gavl_time_t grid);
|
|||
|
||||
/**
|
||||
* Builds a time value by summing up the given components.
|
||||
* @param millis number of milliseconds
|
||||
* @param secs number of seconds
|
||||
* @param mins number of minutes
|
||||
* @param hours number of hours
|
||||
*/
|
||||
gavl_time_t
|
||||
lumiera_build_time (long millis, uint secs, uint mins, uint hours);
|
||||
|
||||
/**
|
||||
* Extract the hour part of given time.
|
||||
* Builds a time value by summing up the given components.
|
||||
* @todo replace float framerates by lib::time::FrameRate
|
||||
*/
|
||||
int lumiera_time_hours(gavl_time_t time);
|
||||
gavl_time_t
|
||||
lumiera_build_time_fps (float fps, uint frames, uint secs, uint mins, uint hours);
|
||||
|
||||
/**
|
||||
* Extract the minute part of given time.
|
||||
* Builds a time value by summing up the given components.
|
||||
* The components are interpreted as a NTSC drop-frame timecode.
|
||||
* @warning take care not to specify time codes that are illegal NTSC drop-frame times.
|
||||
*/
|
||||
int lumiera_time_minutes(gavl_time_t time);
|
||||
gavl_time_t
|
||||
lumiera_build_time_ntsc_drop (uint frames, uint secs, uint mins, uint hours);
|
||||
|
||||
|
||||
/** Extract the hour part of given time. */
|
||||
int
|
||||
lumiera_time_hours (gavl_time_t time);
|
||||
|
||||
|
||||
/** Extract the minute part of given time. */
|
||||
int
|
||||
lumiera_time_minutes (gavl_time_t time);
|
||||
|
||||
|
||||
/** Extract the seconds part of given time. */
|
||||
int
|
||||
lumiera_time_seconds (gavl_time_t time);
|
||||
|
||||
|
||||
/** Extract the milliseconds part of given time. */
|
||||
int
|
||||
lumiera_time_millis (gavl_time_t time);
|
||||
|
||||
/**
|
||||
* Extract the seconds part of given time.
|
||||
* Extract the frame part of given time, using the given fps.
|
||||
* @param fps frame rate
|
||||
* @todo use the rational lib::time::FrameRate instead of a float
|
||||
*/
|
||||
int lumiera_time_seconds(gavl_time_t time);
|
||||
int
|
||||
lumiera_time_frames (gavl_time_t time, float fps);
|
||||
|
||||
/**
|
||||
* Extract the milliseconds part of given time.
|
||||
* Extract the frame count for the given time, using the given fps.
|
||||
* @todo use the rational lib::time::FrameRate instead of a float
|
||||
*/
|
||||
int lumiera_time_millis(gavl_time_t time);
|
||||
int
|
||||
lumiera_time_frame_count (gavl_time_t time, float fps);
|
||||
|
||||
/**
|
||||
* Extract the frame part of given time, using NTSC drop-frame timecode.
|
||||
*/
|
||||
int
|
||||
lumiera_time_ntsc_drop_frames (gavl_time_t time);
|
||||
|
||||
/**
|
||||
* Extract the second part of given time, using NTSC drop-frame timecode.
|
||||
*/
|
||||
int
|
||||
lumiera_time_ntsc_drop_seconds (gavl_time_t time);
|
||||
|
||||
/**
|
||||
* Extract the minute part of given time, using NTSC drop-frame timecode.
|
||||
*/
|
||||
int
|
||||
lumiera_time_ntsc_drop_minutes (gavl_time_t time);
|
||||
|
||||
/**
|
||||
* Extract the hour part of given time, using NTSC drop-frame timecode.
|
||||
*/
|
||||
int
|
||||
lumiera_time_ntsc_drop_hours (gavl_time_t time);
|
||||
|
||||
|
||||
|
||||
|
|
@ -157,3 +217,4 @@ int lumiera_time_millis(gavl_time_t time);
|
|||
}//extern "C"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -4,3 +4,9 @@ TEST "basic functionality" basic <<END
|
|||
err: ECHO: .*: 00:00:00.000
|
||||
err: ECHO: .*: 03:55:20.700
|
||||
END
|
||||
|
||||
TEST "frame rate dependent calculations" fps <<END
|
||||
END
|
||||
|
||||
TEST "ntsc drop-frame calculations" ntsc_drop_frame << END
|
||||
END
|
||||
|
|
|
|||
|
|
@ -28,36 +28,146 @@ typedef unsigned int uint;
|
|||
|
||||
TESTS_BEGIN
|
||||
|
||||
const int FRAMES = 15;
|
||||
const int MILLIS = 700;
|
||||
const int SECONDS = 20;
|
||||
const int MINUTES = 55;
|
||||
const int HOURS = 3;
|
||||
const float FPS = 24.0;
|
||||
|
||||
/*
|
||||
* 1. Basic functionality
|
||||
*/
|
||||
|
||||
TEST (basic) {
|
||||
TEST (basic)
|
||||
{
|
||||
// Zero
|
||||
gavl_time_t t = lumiera_build_time(0,0,0,0);
|
||||
gavl_time_t t = lumiera_build_time (0,0,0,0);
|
||||
|
||||
CHECK ((gavl_time_t) t == 0);
|
||||
CHECK (lumiera_time_millis(t) == 0);
|
||||
CHECK (lumiera_time_seconds(t) == 0);
|
||||
CHECK (lumiera_time_minutes(t) == 0);
|
||||
CHECK (lumiera_time_hours(t) == 0);
|
||||
CHECK ((gavl_time_t) t == 0);
|
||||
CHECK (lumiera_time_millis (t) == 0);
|
||||
CHECK (lumiera_time_seconds (t) == 0);
|
||||
CHECK (lumiera_time_minutes (t) == 0);
|
||||
CHECK (lumiera_time_hours (t) == 0);
|
||||
CHECK (lumiera_time_frames (t, FPS) == 0);
|
||||
CHECK (lumiera_time_frames (t, FPS+5) == 0);
|
||||
CHECK (lumiera_time_frame_count (t, FPS) == 0);
|
||||
CHECK (lumiera_time_frame_count (t, FPS+5) == 0);
|
||||
|
||||
ECHO ("%s", lumiera_tmpbuf_print_time(t));
|
||||
ECHO ("%s", lumiera_tmpbuf_print_time (t));
|
||||
|
||||
// Non-zero
|
||||
t = lumiera_build_time(MILLIS, SECONDS, MINUTES, HOURS);
|
||||
t = lumiera_build_time (MILLIS, SECONDS, MINUTES, HOURS);
|
||||
|
||||
CHECK (lumiera_time_millis(t) == MILLIS);
|
||||
CHECK (lumiera_time_seconds(t) == SECONDS);
|
||||
CHECK (lumiera_time_minutes(t) == MINUTES);
|
||||
CHECK (lumiera_time_hours(t) == HOURS);
|
||||
CHECK (lumiera_time_millis (t) == MILLIS);
|
||||
CHECK (lumiera_time_seconds (t) == SECONDS);
|
||||
CHECK (lumiera_time_minutes (t) == MINUTES);
|
||||
CHECK (lumiera_time_hours (t) == HOURS);
|
||||
CHECK (lumiera_time_frames (t, FPS) == (int)((FPS * MILLIS) / 1000));
|
||||
CHECK (lumiera_time_frames (t, FPS+5) == (int)(((FPS+5) * MILLIS) / 1000));
|
||||
CHECK (lumiera_time_frame_count (t, FPS) == 338897);
|
||||
CHECK (lumiera_time_frame_count (t, FPS+5) == 409500);
|
||||
|
||||
ECHO ("%s", lumiera_tmpbuf_print_time(t));
|
||||
ECHO ("%s", lumiera_tmpbuf_print_time (t));
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. Frame rate dependent calculations.
|
||||
*/
|
||||
|
||||
TEST (fps)
|
||||
{
|
||||
gavl_time_t t = lumiera_build_time_fps (FPS, FRAMES, SECONDS, MINUTES, HOURS);
|
||||
|
||||
CHECK (lumiera_time_millis (t) == (int)(FRAMES * (1000.0 / FPS)));
|
||||
CHECK (lumiera_time_seconds (t) == SECONDS);
|
||||
CHECK (lumiera_time_minutes (t) == MINUTES);
|
||||
CHECK (lumiera_time_hours (t) == HOURS);
|
||||
CHECK (lumiera_time_frames (t, FPS) == FRAMES);
|
||||
CHECK (lumiera_time_frames (t, FPS+5) == (int)(((FPS+5) * 625) / 1000));
|
||||
CHECK (lumiera_time_frame_count (t, FPS) == 338895);
|
||||
CHECK (lumiera_time_frame_count (t, FPS+5) == 409498);
|
||||
}
|
||||
|
||||
/*
|
||||
* 3. NTSC drop-frame calculations.
|
||||
*/
|
||||
|
||||
TEST (ntsc_drop_frame)
|
||||
{
|
||||
// Make sure frame 0 begins at 0
|
||||
gavl_time_t t = lumiera_build_time_ntsc_drop (0, 0, 0, 0);
|
||||
|
||||
CHECK ((gavl_time_t) t == 0);
|
||||
CHECK (lumiera_time_millis (t) == 0);
|
||||
CHECK (lumiera_time_seconds (t) == 0);
|
||||
CHECK (lumiera_time_minutes (t) == 0);
|
||||
CHECK (lumiera_time_hours (t) == 0);
|
||||
CHECK (lumiera_time_frames (t, FPS) == 0);
|
||||
CHECK (lumiera_time_frames (t, FPS+5) == 0);
|
||||
CHECK (lumiera_time_frame_count (t, FPS) == 0);
|
||||
CHECK (lumiera_time_frame_count (t, FPS+5) == 0);
|
||||
|
||||
// Use some arbitrary value to test with
|
||||
const int FRAMES = 15;
|
||||
const int SECONDS = 20;
|
||||
const int MINUTES = 55;
|
||||
const int HOURS = 3;
|
||||
const float FPS = 24.0;
|
||||
|
||||
t = lumiera_build_time_ntsc_drop (FRAMES, SECONDS, MINUTES, HOURS);
|
||||
|
||||
CHECK (lumiera_time_millis (t) == 487);
|
||||
CHECK (lumiera_time_seconds (t) == SECONDS);
|
||||
CHECK (lumiera_time_minutes (t) == MINUTES);
|
||||
CHECK (lumiera_time_hours (t) == HOURS);
|
||||
|
||||
// Check standard frame calculations to verify build_time_ntsc_drop
|
||||
CHECK (lumiera_time_frames (t, FPS) == 11);
|
||||
CHECK (lumiera_time_frames (t, FPS+5) == 14);
|
||||
CHECK (lumiera_time_frame_count (t, FPS) == 338892);
|
||||
CHECK (lumiera_time_frame_count (t, FPS+5) == 409494);
|
||||
|
||||
// Frames for NTSC drop
|
||||
CHECK (lumiera_time_ntsc_drop_frames (t) == 15);
|
||||
CHECK (lumiera_time_frame_count (t, NTSC_DROP_FRAME_FPS) == 423191);
|
||||
|
||||
// Make sure we get back the same times. These tests are perhaps overly exhaustive.
|
||||
int min;
|
||||
int sec;
|
||||
int frame;
|
||||
int hrs;
|
||||
for (hrs = 0; hrs <= 24; hrs += 6)
|
||||
for (min = 0; min <= 59; min += 8)
|
||||
for (sec = 0; sec <= 59; sec += 8)
|
||||
for (frame = 0; frame <= 29; frame++)
|
||||
{
|
||||
// Skip dropped frames
|
||||
if (min % 10 && sec == 0 && frame < 2)
|
||||
continue;
|
||||
|
||||
t = lumiera_build_time_ntsc_drop(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 (lumiera_time_ntsc_drop_frames (t) == frame);
|
||||
CHECK (lumiera_time_ntsc_drop_seconds (t) == sec);
|
||||
CHECK (lumiera_time_ntsc_drop_minutes (t) == min);
|
||||
CHECK (lumiera_time_ntsc_drop_hours (t) == hrs % 24);
|
||||
}
|
||||
|
||||
// Make sure we do not get non-existent frames
|
||||
int i;
|
||||
for (i = 0; i < 59; i++)
|
||||
{
|
||||
int frame = (i % 10 == 0) ? 0 : 2;
|
||||
t = lumiera_build_time_ntsc_drop (frame, 0, i, 0);
|
||||
CHECK (lumiera_time_ntsc_drop_frames (t) == frame);
|
||||
}
|
||||
}
|
||||
|
||||
TESTS_END
|
||||
|
|
|
|||
Loading…
Reference in a new issue