Blender  V2.93
timecode.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #include <stdio.h>
27 
28 #include "BLI_math.h"
29 #include "BLI_string.h"
30 #include "BLI_utildefines.h"
31 
32 #include "BLI_timecode.h" /* own include */
33 
34 #include "DNA_userdef_types.h" /* for eTimecodeStyles only */
35 
36 #include "BLI_strict_flags.h"
37 
52  const size_t maxncpy,
53  const int brevity_level,
54  const float time_seconds,
55  const double fps,
56  const short timecode_style)
57 {
58  int hours = 0, minutes = 0, seconds = 0, frames = 0;
59  float time = time_seconds;
60  char neg[2] = {'\0'};
61  size_t rlen;
62 
63  /* get cframes */
64  if (time < 0) {
65  /* correction for negative cfraues */
66  neg[0] = '-';
67  time = -time;
68  }
69 
70  if (time >= 3600.0f) {
71  /* hours */
72  /* XXX should we only display a single digit for hours since clips are
73  * VERY UNLIKELY to be more than 1-2 hours max? However, that would
74  * go against conventions...
75  */
76  hours = (int)time / 3600;
77  time = fmodf(time, 3600);
78  }
79 
80  if (time >= 60.0f) {
81  /* minutes */
82  minutes = (int)time / 60;
83  time = fmodf(time, 60);
84  }
85 
86  if (brevity_level <= 0) {
87  /* seconds + frames
88  * Frames are derived from 'fraction' of second. We need to perform some additional rounding
89  * to cope with 'half' frames, etc., which should be fine in most cases
90  */
91  seconds = (int)time;
92  frames = round_fl_to_int((float)(((double)time - (double)seconds) * fps));
93  }
94  else {
95  /* seconds (with pixel offset rounding) */
96  seconds = round_fl_to_int(time);
97  }
98 
99  switch (timecode_style) {
100  case USER_TIMECODE_MINIMAL: {
101  /* - In general, minutes and seconds should be shown, as most clips will be
102  * within this length. Hours will only be included if relevant.
103  * - Only show frames when zoomed in enough for them to be relevant
104  * (using separator of '+' for frames).
105  * When showing frames, use slightly different display to avoid confusion with mm:ss format
106  */
107  if (brevity_level <= 0) {
108  /* include "frames" in display */
109  if (hours) {
110  rlen = BLI_snprintf_rlen(
111  str, maxncpy, "%s%02d:%02d:%02d+%02d", neg, hours, minutes, seconds, frames);
112  }
113  else if (minutes) {
114  rlen = BLI_snprintf_rlen(
115  str, maxncpy, "%s%02d:%02d+%02d", neg, minutes, seconds, frames);
116  }
117  else {
118  rlen = BLI_snprintf_rlen(str, maxncpy, "%s%d+%02d", neg, seconds, frames);
119  }
120  }
121  else {
122  /* don't include 'frames' in display */
123  if (hours) {
124  rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, hours, minutes, seconds);
125  }
126  else {
127  rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d", neg, minutes, seconds);
128  }
129  }
130  break;
131  }
133  /* reduced SMPTE format that always shows minutes, seconds, frames.
134  * Hours only shown as needed. */
135  if (hours) {
136  rlen = BLI_snprintf_rlen(
137  str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
138  }
139  else {
140  rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%02d:%02d", neg, minutes, seconds, frames);
141  }
142  break;
143  }
145  /* reduced SMPTE. Instead of frames, milliseconds are shown */
146 
147  /* precision of decimal part */
148  const int ms_dp = (brevity_level <= 0) ? (1 - brevity_level) : 1;
149 
150  /* to get 2 digit whole-number part for seconds display
151  * (i.e. 3 is for 2 digits + radix, on top of full length) */
152  const int s_pad = ms_dp + 3;
153 
154  if (hours) {
155  rlen = BLI_snprintf_rlen(
156  str, maxncpy, "%s%02d:%02d:%0*.*f", neg, hours, minutes, s_pad, ms_dp, time);
157  }
158  else {
159  rlen = BLI_snprintf_rlen(str, maxncpy, "%s%02d:%0*.*f", neg, minutes, s_pad, ms_dp, time);
160  }
161  break;
162  }
163  case USER_TIMECODE_SUBRIP: {
164  /* SubRip, like SMPTE milliseconds but seconds and milliseconds
165  * are separated by a comma, not a dot... */
166 
167  /* precision of decimal part */
168  const int ms_dp = (brevity_level <= 0) ? (1 - brevity_level) : 1;
169  const int ms = round_fl_to_int((time - (float)seconds) * 1000.0f);
170 
171  rlen = BLI_snprintf_rlen(
172  str, maxncpy, "%s%02d:%02d:%02d,%0*d", neg, hours, minutes, seconds, ms_dp, ms);
173  break;
174  }
176  /* only show the original seconds display */
177  /* round to whole numbers if brevity_level is >= 1 (i.e. scale is coarse) */
178  if (brevity_level <= 0) {
179  rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - brevity_level, time_seconds);
180  }
181  else {
182  rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
183  }
184  break;
185  }
187  default: {
188  /* full SMPTE format */
189  rlen = BLI_snprintf_rlen(
190  str, maxncpy, "%s%02d:%02d:%02d:%02d", neg, hours, minutes, seconds, frames);
191  break;
192  }
193  }
194 
195  return rlen;
196 }
197 
207  const size_t maxncpy,
208  const double time_seconds)
209 {
210  size_t rlen;
211 
212  /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
213  const int hr = ((int)time_seconds) / (60 * 60);
214  const int min = (((int)time_seconds) / 60) % 60;
215  const int sec = ((int)time_seconds) % 60;
216  const int hun = ((int)(fmod(time_seconds, 1.0) * 100));
217 
218  if (hr) {
219  rlen = BLI_snprintf(str, maxncpy, "%.2d:%.2d:%.2d.%.2d", hr, min, sec, hun);
220  }
221  else {
222  rlen = BLI_snprintf(str, maxncpy, "%.2d:%.2d.%.2d", min, sec, hun);
223  }
224 
225  return rlen;
226 }
227 
241  const size_t maxncpy,
242  const int brevity_level,
243  const float time_seconds)
244 {
245  size_t rlen;
246 
247  /* round to whole numbers if brevity_level is >= 1 (i.e. scale is coarse) */
248  if (brevity_level <= 0) {
249  rlen = BLI_snprintf_rlen(str, maxncpy, "%.*f", 1 - brevity_level, time_seconds);
250  }
251  else {
252  rlen = BLI_snprintf_rlen(str, maxncpy, "%d", round_fl_to_int(time_seconds));
253  }
254 
255  return rlen;
256 }
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
size_t BLI_snprintf(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)
#define min(a, b)
Definition: sort.c:51
size_t BLI_timecode_string_from_time_simple(char *str, const size_t maxncpy, const double time_seconds)
Definition: timecode.c:206
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:240
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:51