UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Timecode.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
7#include "HAL/Platform.h"
9#include "Misc/FrameNumber.h"
10#include "Misc/FrameRate.h"
11#include "Misc/FrameTime.h"
12#include "Misc/Timespan.h"
13
19{
24 : Hours(0)
25 , Minutes(0)
26 , Seconds(0)
27 , Frames(0)
28 , Subframe(0)
30 {}
31
47
64
74 {
75 if (InbRollover)
76 {
77 const int32 NumberOfSecondsPerDay = 60 * 60 * 24;
78 double IntegralPart = 0.0;
79 double Fractional = FMath::Modf(InSeconds, &IntegralPart);
82 }
83
84 const int32 NumberOfFrames = (int32)FMath::RoundToDouble(InSeconds * InFrameRate.AsDecimal());
85 *this = FromFrameNumber(FFrameNumber(NumberOfFrames), InFrameRate, InbDropFrame);
86 }
87
97
98
99
100 friend bool operator==(const FFrameRate& A, const FFrameRate& B);
101 friend bool operator!=(const FFrameRate& A, const FFrameRate& B);
102
103public:
104
109 {
110 const int32 NumberOfFramesInSecond = FMath::CeilToInt((float)InFrameRate.AsDecimal());
113
114 if (NumberOfFramesInSecond <= 0)
115 {
116 return FFrameNumber();
117 }
118
119 // Do a quick pre-pass to take any overflow values and move them into bigger time units.
122
125
128
130 {
132
133 // Calculate how many minutes there are total so we can know how many times we've skipped timecodes.
135
136 // We skip timecodes 9 times out of every 10.
140
141 return FFrameNumber(TotalFrames);
142 }
143 else
144 {
146 return FFrameNumber(TotalFrames);
147 }
148 }
149
162 {
163 const int32 NumberOfFramesInSecond = FMath::CeilToInt((float)InFrameRate.AsDecimal());
166
167 if (NumberOfFramesInSecond <= 0)
168 {
169 return FTimecode();
170 }
171
172 if (InbDropFrame)
173 {
174 // Drop Frame Timecode (DFT) was created to address the issue with playing back whole frames at fractional framerates.
175 // DFT is confusingly named though, as no frame numbers are actually dropped, only the display of them. At an ideal 30fps,
176 // there are 108,000 frames in an hour. When played back at 29.97 however, there are only 107,892 frames per hour. This
177 // leaves us a difference of 108 frames per hour (roughly ~3.6s!). DFT works by accumulating error until the error is significant
178 // enough to catch up by a frame. This is accomplished by dropping two (or four) timecode numbers every minute which gives us a
179 // total difference of 2*60 = 120 frames per hour. Unfortunately 120 puts us out of sync again as the difference is only 108 frames,
180 // so we need to get 12 frames back. By not dropping frames every 10th minute, that gives us 2 frames * 6 (00, 10, 20, 30, 40, 50)
181 // which gets us the 12 frame difference we need. In short, we drop frames (skip timecode numbers) every minute, on the minute, except
182 // when (Minute % 10 == 0)
183
184 // 29.97 drops two timecode values (frames 0 and 1) while 59.94 drops four values (frames 0, 1, 2 and 3)
186
187 // At an ideal 30fps there would be 18,000 frames every 10 minutes, but at 29.97 there's only 17,982 frames.
188 const int32 NumTrueFramesPerTenMinutes = FMath::FloorToInt((float)((60 * 10) * InFrameRate.AsDecimal()));
189
190 // Calculate out how many times we've skipped dropping frames (ie: Minute 15 gives us a value of 1, as we've only didn't drop frames on the 10th minute)
192
193 // Now we can figure out how many frame (displays) have been skipped total; 9 times out of every 10 minutes
195
196 int32 OffsetFrame = FMath::Abs(InFrameNumber.Value);
198
199 // If we end up with a value of 0 or 1 (or 2 or 3 for 59.94) then we're not skipping timecode numbers this time.
201 {
203 }
204 else
205 {
206 // Each minute we slip a little bit more out of sync by a small amount, we just wait until we've accumulated enough error
207 // to skip a whole frame and can catch up.
208 const uint32 NumTrueFramesPerMinute = (uint32)FMath::FloorToInt(60 * (float)InFrameRate.AsDecimal());
209
210 // Figure out which minute we are (0-9) to see how many to skip
214 }
215
216 // Convert to negative timecode at the end if the original was negative.
217 OffsetFrame *= FMath::Sign(InFrameNumber.Value);
218
219 // Now that we've fudged what frames it thinks we're converting, we can do a standard Frame -> Timecode conversion.
224
225 return FTimecode(Hours, Minutes, Seconds, Frames, true);
226 }
227 else
228 {
229 // If we're in non-drop-frame we just convert straight through without fudging the frame numbers to skip certain timecodes.
234
235 return FTimecode(Hours, Minutes, Seconds, Frames, false);
236 }
237 }
238
250
266
276
290 {
291 return FTimecode(InTimespan.GetTotalSeconds(), InFrameRate, InbDropFrame, InbRollover);
292 }
293
306
308 static bool IsDropFormatTimecodeSupported(const double InRate)
309 {
310 return FMath::IsNearlyEqual(InRate, 30.0/1.001)
311 || FMath::IsNearlyEqual(InRate, 60.0/1.001);
312 }
313
316 {
317 const double InRate = InFrameRate.AsDecimal();
318
319 return IsDropFormatTimecodeSupported(InRate);
320 }
321
327
330
336 static bool IsValidDropFormatTimecodeRate(const FString& InRateString)
337 {
338 const FString NTSC_30_DF = "29.97df";
339 const FString NTSC_60_DF = "59.94df";
340
342 }
343
350 CORE_API FString ToString(bool bForceSignDisplay = false, bool bDisplaySubframe = false) const;
351
372
382 bool IsValid() const
383 {
385 {
386 return FMath::Abs(Val) >= MinVal && FMath::Abs(Val) <= MaxVal;
387 };
388 return InAbsRange(Minutes, 0, 59) && InAbsRange(Seconds, 0, 59) && Subframe >= 0;
389 }
390public:
391
396
399
402
405
407 float Subframe = 0;
408
411
412 friend inline bool operator==(const FTimecode& A, const FTimecode& B)
413 {
414 return A.Hours == B.Hours && A.Minutes == B.Minutes && A.Seconds == B.Seconds && A.Frames == B.Frames && A.Subframe == B.Subframe;
415 }
416
417 friend inline bool operator!=(const FTimecode& A, const FTimecode& B)
418 {
419 return !(A == B);
420 }
421
422};
#define checkSlow(expr)
Definition AssertionMacros.h:332
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
float Val(const FString &Value)
Definition UnrealMath.cpp:3163
uint32_t uint32
Definition binka_ue_file_header.h:6
@ false
Definition radaudio_common.h:23
Definition FrameNumber.h:18
Definition FrameRate.h:21
Definition FrameTime.h:16
static UE_FORCEINLINE_HINT bool IsNearlyEqual(float A, float B, float ErrorTolerance=UE_SMALL_NUMBER)
Definition UnrealMathUtility.h:388
static UE_FORCEINLINE_HINT float RoundToZero(float F)
Definition UnrealMathUtility.h:2209
Definition Timecode.h:19
static FTimecode FromTimespan(const FTimespan &InTimespan, const FFrameRate &InFrameRate, bool InbRollover)
Definition Timecode.h:302
FTimecode(double InSeconds, const FFrameRate &InFrameRate, bool InbRollover)
Definition Timecode.h:93
static CORE_API TOptional< FTimecode > ParseTimecode(const FStringView InTimecodeString)
Definition Timecode.cpp:212
static FTimecode FromFrameNumber(const FFrameNumber &InFrameNumber, const FFrameRate &InFrameRate)
Definition Timecode.h:246
friend bool operator!=(const FFrameRate &A, const FFrameRate &B)
static bool IsDropFormatTimecodeSupported(const FFrameRate &InFrameRate)
Definition Timecode.h:315
friend bool operator==(const FFrameRate &A, const FFrameRate &B)
static FTimecode FromFrameTime(const FFrameTime &InFrameTime, const FFrameRate &InFrameRate, TOptional< bool > bDropFrame={})
Definition Timecode.h:259
static CORE_API bool UseDropFormatTimecodeByDefaultWhenSupported()
Definition Timecode.cpp:22
FFrameNumber ToFrameNumber(const FFrameRate &InFrameRate) const
Definition Timecode.h:108
bool IsValid() const
Definition Timecode.h:382
float Subframe
Definition Timecode.h:407
static bool UseDropFormatTimecode(const FFrameRate &InFrameRate)
Definition Timecode.h:323
friend bool operator!=(const FTimecode &A, const FTimecode &B)
Definition Timecode.h:417
friend bool operator==(const FTimecode &A, const FTimecode &B)
Definition Timecode.h:412
int32 Frames
Definition Timecode.h:404
static bool IsDropFormatTimecodeSupported(const double InRate)
Definition Timecode.h:308
FTimecode()
Definition Timecode.h:23
FTimecode(int32 InHours, int32 InMinutes, int32 InSeconds, int32 InFrames, bool InbDropFrame)
Definition Timecode.h:38
static FTimecode FromTimespan(const FTimespan &InTimespan, const FFrameRate &InFrameRate, bool InbDropFrame, bool InbRollover)
Definition Timecode.h:289
static FTimecode FromFrameNumber(const FFrameNumber &InFrameNumber, const FFrameRate &InFrameRate, bool InbDropFrame)
Definition Timecode.h:161
int32 Minutes
Definition Timecode.h:398
FTimecode(double InSeconds, const FFrameRate &InFrameRate, bool InbDropFrame, bool InbRollover)
Definition Timecode.h:73
FTimecode(int32 InHours, int32 InMinutes, int32 InSeconds, int32 InFrames, float InSubframe, bool InbDropFrame)
Definition Timecode.h:54
int32 Hours
Definition Timecode.h:395
FTimespan ToTimespan(const FFrameRate &InFrameRate) const
Definition Timecode.h:270
bool bDropFrameFormat
Definition Timecode.h:410
static bool IsValidDropFormatTimecodeRate(const FString &InRateString)
Definition Timecode.h:336
int32 Seconds
Definition Timecode.h:401
Definition Timespan.h:76
static FTimespan FromSeconds(double Seconds)
Definition Timespan.h:673
Definition Optional.h:131