2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2014-01-29 20:01:30 +11:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
2021-10-06 11:37:50 +11:00
|
|
|
* \ingroup bli
|
2014-01-29 20:01:30 +11:00
|
|
|
*
|
|
|
|
|
* Time-Code string formatting
|
|
|
|
|
*/
|
|
|
|
|
|
2025-02-09 19:05:01 +01:00
|
|
|
#include <cstdio>
|
2014-01-29 20:01:30 +11:00
|
|
|
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_base.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_string.h"
|
2014-01-29 20:01:30 +11:00
|
|
|
|
|
|
|
|
#include "BLI_timecode.h" /* own include */
|
|
|
|
|
|
|
|
|
|
#include "DNA_userdef_types.h" /* for eTimecodeStyles only */
|
|
|
|
|
|
2025-01-26 20:07:57 +01:00
|
|
|
#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
|
2014-01-29 20:01:30 +11:00
|
|
|
|
|
|
|
|
size_t BLI_timecode_string_from_time(char *str,
|
2019-04-16 14:15:49 +02:00
|
|
|
const size_t maxncpy,
|
|
|
|
|
const int brevity_level,
|
|
|
|
|
const float time_seconds,
|
2014-01-29 20:01:30 +11:00
|
|
|
const double fps,
|
|
|
|
|
const short timecode_style)
|
|
|
|
|
{
|
|
|
|
|
int hours = 0, minutes = 0, seconds = 0, frames = 0;
|
|
|
|
|
float time = time_seconds;
|
|
|
|
|
char neg[2] = {'\0'};
|
|
|
|
|
size_t rlen;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-13 13:41:17 +11:00
|
|
|
/* Get frames. */
|
2014-01-29 20:01:30 +11:00
|
|
|
if (time < 0) {
|
2025-03-13 13:41:17 +11:00
|
|
|
/* Correction for negative frames. */
|
2014-01-29 20:01:30 +11:00
|
|
|
neg[0] = '-';
|
|
|
|
|
time = -time;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-10-04 15:53:56 +02:00
|
|
|
if (time >= 3600.0f) {
|
2014-01-29 20:01:30 +11:00
|
|
|
/* hours */
|
|
|
|
|
/* XXX should we only display a single digit for hours since clips are
|
|
|
|
|
* VERY UNLIKELY to be more than 1-2 hours max? However, that would
|
|
|
|
|
* go against conventions...
|
|
|
|
|
*/
|
2025-02-13 13:29:41 +11:00
|
|
|
hours = int(time) / 3600;
|
2015-10-04 15:53:56 +02:00
|
|
|
time = fmodf(time, 3600);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-10-04 15:53:56 +02:00
|
|
|
if (time >= 60.0f) {
|
2014-01-29 20:01:30 +11:00
|
|
|
/* minutes */
|
2025-02-13 13:29:41 +11:00
|
|
|
minutes = int(time) / 60;
|
2015-10-04 15:53:56 +02:00
|
|
|
time = fmodf(time, 60);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-16 14:15:49 +02:00
|
|
|
if (brevity_level <= 0) {
|
2014-01-29 20:01:30 +11:00
|
|
|
/* seconds + frames
|
|
|
|
|
* Frames are derived from 'fraction' of second. We need to perform some additional rounding
|
|
|
|
|
* to cope with 'half' frames, etc., which should be fine in most cases
|
|
|
|
|
*/
|
2025-02-13 13:29:41 +11:00
|
|
|
seconds = int(time);
|
|
|
|
|
frames = round_fl_to_int(float((double(time) - double(seconds)) * fps));
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* seconds (with pixel offset rounding) */
|
2017-09-27 11:13:03 +10:00
|
|
|
seconds = round_fl_to_int(time);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-01-29 20:01:30 +11:00
|
|
|
switch (timecode_style) {
|
|
|
|
|
case USER_TIMECODE_MINIMAL: {
|
|
|
|
|
/* - In general, minutes and seconds should be shown, as most clips will be
|
|
|
|
|
* within this length. Hours will only be included if relevant.
|
|
|
|
|
* - Only show frames when zoomed in enough for them to be relevant
|
|
|
|
|
* (using separator of '+' for frames).
|
2023-05-24 20:27:13 +10:00
|
|
|
* When showing frames, use slightly different display
|
|
|
|
|
* to avoid confusion with `mm:ss` format.
|
2014-01-29 20:01:30 +11:00
|
|
|
*/
|
2019-04-16 14:15:49 +02:00
|
|
|
if (brevity_level <= 0) {
|
2014-01-29 20:01:30 +11:00
|
|
|
/* include "frames" in display */
|
|
|
|
|
if (hours) {
|
2015-04-22 05:37:22 +10:00
|
|
|
rlen = BLI_snprintf_rlen(
|
|
|
|
|
str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
else if (minutes) {
|
2015-04-22 05:37:22 +10:00
|
|
|
rlen = BLI_snprintf_rlen(
|
|
|
|
|
str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2021-07-29 10:24:28 +02:00
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%s00:%02d+%02d", neg, seconds, frames);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-01-29 20:01:30 +11:00
|
|
|
else {
|
|
|
|
|
/* don't include 'frames' in display */
|
|
|
|
|
if (hours) {
|
2015-04-22 05:37:22 +10:00
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2015-04-22 05:37:22 +10:00
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-01-29 20:01:30 +11:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case USER_TIMECODE_SMPTE_MSF: {
|
2019-01-15 23:15:58 +11:00
|
|
|
/* reduced SMPTE format that always shows minutes, seconds, frames.
|
|
|
|
|
* Hours only shown as needed. */
|
2014-01-29 20:01:30 +11:00
|
|
|
if (hours) {
|
2015-04-22 05:37:22 +10:00
|
|
|
rlen = BLI_snprintf_rlen(
|
|
|
|
|
str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2015-04-22 05:37:22 +10:00
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case USER_TIMECODE_MILLISECONDS: {
|
|
|
|
|
/* reduced SMPTE. Instead of frames, milliseconds are shown */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-01-29 20:01:30 +11:00
|
|
|
/* precision of decimal part */
|
2019-04-16 14:15:49 +02:00
|
|
|
const int ms_dp = (brevity_level <= 0) ? (1 - brevity_level) : 1;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-01-29 20:01:30 +11:00
|
|
|
/* to get 2 digit whole-number part for seconds display
|
|
|
|
|
* (i.e. 3 is for 2 digits + radix, on top of full length) */
|
|
|
|
|
const int s_pad = ms_dp + 3;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-01-29 20:01:30 +11:00
|
|
|
if (hours) {
|
2015-04-22 05:37:22 +10:00
|
|
|
rlen = BLI_snprintf_rlen(
|
|
|
|
|
str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2015-04-22 05:37:22 +10:00
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad, ms_dp, time);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-10-04 15:53:56 +02:00
|
|
|
case USER_TIMECODE_SUBRIP: {
|
2019-01-15 23:15:58 +11:00
|
|
|
/* SubRip, like SMPTE milliseconds but seconds and milliseconds
|
|
|
|
|
* are separated by a comma, not a dot... */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-10-04 15:53:56 +02:00
|
|
|
/* precision of decimal part */
|
2019-04-16 14:15:49 +02:00
|
|
|
const int ms_dp = (brevity_level <= 0) ? (1 - brevity_level) : 1;
|
2025-02-13 13:29:41 +11:00
|
|
|
const int ms = round_fl_to_int((time - float(seconds)) * 1000.0f);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-10-04 15:53:56 +02:00
|
|
|
rlen = BLI_snprintf_rlen(
|
|
|
|
|
str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-01-29 20:01:30 +11:00
|
|
|
case USER_TIMECODE_SECONDS_ONLY: {
|
|
|
|
|
/* only show the original seconds display */
|
2019-04-16 14:15:49 +02:00
|
|
|
/* round to whole numbers if brevity_level is >= 1 (i.e. scale is coarse) */
|
|
|
|
|
if (brevity_level <= 0) {
|
|
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - brevity_level, time_seconds);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2017-09-27 11:13:03 +10:00
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case USER_TIMECODE_SMPTE_FULL:
|
|
|
|
|
default: {
|
|
|
|
|
/* full SMPTE format */
|
2015-04-22 05:37:22 +10:00
|
|
|
rlen = BLI_snprintf_rlen(
|
|
|
|
|
str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
|
2014-01-29 20:01:30 +11:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-01-29 20:01:30 +11:00
|
|
|
return rlen;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-30 14:47:31 +10:00
|
|
|
size_t BLI_timecode_string_from_time_simple(char *str,
|
|
|
|
|
const size_t maxncpy,
|
|
|
|
|
const double time_seconds)
|
|
|
|
|
{
|
|
|
|
|
size_t rlen;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-06-30 14:47:31 +10:00
|
|
|
/* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
|
2025-02-13 13:29:41 +11:00
|
|
|
const int hr = int(time_seconds) / (60 * 60);
|
|
|
|
|
const int min = (int(time_seconds) / 60) % 60;
|
|
|
|
|
const int sec = int(time_seconds) % 60;
|
|
|
|
|
const int hun = int(fmod(time_seconds, 1.0) * 100);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-06-30 14:47:31 +10:00
|
|
|
if (hr) {
|
2021-05-27 17:16:08 +10:00
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%.2d:%.2d:%.2d.%.2d", hr, min, sec, hun);
|
2015-06-30 14:47:31 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2021-05-27 17:16:08 +10:00
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%.2d:%.2d.%.2d", min, sec, hun);
|
2015-06-30 14:47:31 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-06-30 14:47:31 +10:00
|
|
|
return rlen;
|
|
|
|
|
}
|
2014-01-29 20:01:30 +11:00
|
|
|
|
2015-06-30 14:47:31 +10:00
|
|
|
size_t BLI_timecode_string_from_time_seconds(char *str,
|
2019-04-16 14:15:49 +02:00
|
|
|
const size_t maxncpy,
|
|
|
|
|
const int brevity_level,
|
|
|
|
|
const float time_seconds)
|
2014-01-29 20:01:30 +11:00
|
|
|
{
|
|
|
|
|
size_t rlen;
|
|
|
|
|
|
2019-04-16 14:15:49 +02:00
|
|
|
/* round to whole numbers if brevity_level is >= 1 (i.e. scale is coarse) */
|
|
|
|
|
if (brevity_level <= 0) {
|
|
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - brevity_level, time_seconds);
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2017-09-27 11:13:03 +10:00
|
|
|
rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
|
2014-01-29 20:01:30 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rlen;
|
|
|
|
|
}
|