Blender  V3.3
timecode.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. All rights reserved. */
3 
10 #include <stdio.h>
11 
12 #include "BLI_math.h"
13 #include "BLI_string.h"
14 #include "BLI_utildefines.h"
15 
16 #include "BLI_timecode.h" /* own include */
17 
18 #include "DNA_userdef_types.h" /* for eTimecodeStyles only */
19 
20 #include "BLI_strict_flags.h"
21 
23  const size_t maxncpy,
24  const int brevity_level,
25  const float time_seconds,
26  const double fps,
27  const short timecode_style)
28 {
29  int hours = 0, minutes = 0, seconds = 0, frames = 0;
30  float time = time_seconds;
31  char neg[2] = {'\0'};
32  size_t rlen;
33 
34  /* get cframes */
35  if (time < 0) {
36  /* Correction for negative cframes. */
37  neg[0] = '-';
38  time = -time;
39  }
40 
41  if (time >= 3600.0f) {
42  /* hours */
43  /* XXX should we only display a single digit for hours since clips are
44  * VERY UNLIKELY to be more than 1-2 hours max? However, that would
45  * go against conventions...
46  */
47  hours = (int)time / 3600;
48  time = fmodf(time, 3600);
49  }
50 
51  if (time >= 60.0f) {
52  /* minutes */
53  minutes = (int)time / 60;
54  time = fmodf(time, 60);
55  }
56 
57  if (brevity_level <= 0) {
58  /* seconds + frames
59  * Frames are derived from 'fraction' of second. We need to perform some additional rounding
60  * to cope with 'half' frames, etc., which should be fine in most cases
61  */
62  seconds = (int)time;
63  frames = round_fl_to_int((float)(((double)time - (double)seconds) * fps));
64  }
65  else {
66  /* seconds (with pixel offset rounding) */
67  seconds = round_fl_to_int(time);
68  }
69 
70  switch (timecode_style) {
71  case USER_TIMECODE_MINIMAL: {
72  /* - In general, minutes and seconds should be shown, as most clips will be
73  * within this length. Hours will only be included if relevant.
74  * - Only show frames when zoomed in enough for them to be relevant
75  * (using separator of '+' for frames).
76  * When showing frames, use slightly different display to avoid confusion with mm:ss format
77  */
78  if (brevity_level <= 0) {
79  /* include "frames" in display */
80  if (hours) {
81  rlen = BLI_snprintf_rlen(
82  str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
83  }
84  else if (minutes) {
85  rlen = BLI_snprintf_rlen(
86  str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
87  }
88  else {
89  rlen = BLI_snprintf_rlen(str, maxncpy, "%s00:%02d+%02d", neg, seconds, frames);
90  }
91  }
92  else {
93  /* don't include 'frames' in display */
94  if (hours) {
95  rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
96  }
97  else {
98  rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds);
99  }
100  }
101  break;
102  }
104  /* reduced SMPTE format that always shows minutes, seconds, frames.
105  * Hours only shown as needed. */
106  if (hours) {
107  rlen = BLI_snprintf_rlen(
108  str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
109  }
110  else {
111  rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
112  }
113  break;
114  }
116  /* reduced SMPTE. Instead of frames, milliseconds are shown */
117 
118  /* precision of decimal part */
119  const int ms_dp = (brevity_level <= 0) ? (1 - brevity_level) : 1;
120 
121  /* to get 2 digit whole-number part for seconds display
122  * (i.e. 3 is for 2 digits + radix, on top of full length) */
123  const int s_pad = ms_dp + 3;
124 
125  if (hours) {
126  rlen = BLI_snprintf_rlen(
127  str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time);
128  }
129  else {
130  rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad, ms_dp, time);
131  }
132  break;
133  }
134  case USER_TIMECODE_SUBRIP: {
135  /* SubRip, like SMPTE milliseconds but seconds and milliseconds
136  * are separated by a comma, not a dot... */
137 
138  /* precision of decimal part */
139  const int ms_dp = (brevity_level <= 0) ? (1 - brevity_level) : 1;
140  const int ms = round_fl_to_int((time - (float)seconds) * 1000.0f);
141 
142  rlen = BLI_snprintf_rlen(
143  str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms);
144  break;
145  }
147  /* only show the original seconds display */
148  /* round to whole numbers if brevity_level is >= 1 (i.e. scale is coarse) */
149  if (brevity_level <= 0) {
150  rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - brevity_level, time_seconds);
151  }
152  else {
153  rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
154  }
155  break;
156  }
158  default: {
159  /* full SMPTE format */
160  rlen = BLI_snprintf_rlen(
161  str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
162  break;
163  }
164  }
165 
166  return rlen;
167 }
168 
170  const size_t maxncpy,
171  const double time_seconds)
172 {
173  size_t rlen;
174 
175  /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
176  const int hr = ((int)time_seconds) / (60 * 60);
177  const int min = (((int)time_seconds) / 60) % 60;
178  const int sec = ((int)time_seconds) % 60;
179  const int hun = ((int)(fmod(time_seconds, 1.0) * 100));
180 
181  if (hr) {
182  rlen = BLI_snprintf_rlen(str, maxncpy, "%.2d:%.2d:%.2d.%.2d", hr, min, sec, hun);
183  }
184  else {
185  rlen = BLI_snprintf_rlen(str, maxncpy, "%.2d:%.2d.%.2d", min, sec, hun);
186  }
187 
188  return rlen;
189 }
190 
192  const size_t maxncpy,
193  const int brevity_level,
194  const float time_seconds)
195 {
196  size_t rlen;
197 
198  /* round to whole numbers if brevity_level is >= 1 (i.e. scale is coarse) */
199  if (brevity_level <= 0) {
200  rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - brevity_level, time_seconds);
201  }
202  else {
203  rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
204  }
205 
206  return rlen;
207 }
MINLINE int round_fl_to_int(float a)
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
@ USER_TIMECODE_SMPTE_FULL
@ USER_TIMECODE_SECONDS_ONLY
@ USER_TIMECODE_MINIMAL
@ USER_TIMECODE_SUBRIP
@ USER_TIMECODE_MILLISECONDS
@ USER_TIMECODE_SMPTE_MSF
double time
#define str(s)
#define fmodf(x, y)
Definition: metal/compat.h:230
#define min(a, b)
Definition: sort.c:35
size_t BLI_timecode_string_from_time_simple(char *str, const size_t maxncpy, const double time_seconds)
Definition: timecode.c:169
size_t BLI_timecode_string_from_time_seconds(char *str, const size_t maxncpy, const int brevity_level, const float time_seconds)
Definition: timecode.c:191
size_t BLI_timecode_string_from_time(char *str, const size_t maxncpy, const int brevity_level, const float time_seconds, const double fps, const short timecode_style)
Definition: timecode.c:22