*This was originally posted on my old blog in 2010. In redesigning and updating my site, I’ve been able to revise the post and clear up a few issues, particularly around 23.976 drop-frame timecode.*

### About Drop-Frame Timecode

In order to do math with timecode, which is in an hours:minutes:seconds:frames format, it must be converted into a number representing the total number of frames. You then do your math with frame numbers, and convert back to the timecode format. For non-drop-frame timecode, this is trivial (I’ve included that code below as well for completeness). It gets complicated when you’re dealing with drop-frame timecode. If you’re new to drop-frame, it’s a way of accurately measuring the running time of video that doesn’t run at an even frame rate. In the United States and several other countries, video runs at 29.97 frames per second, but we usually count it at 30 fps. This means that, after a while, the timecode does not accurately reflect the running time of the video. For an hour-long program, the timecode gets to be about 3.6 seconds off. The solution to this problem is drop-frame timecode, which is sort of like leap year for timecode. At 29.97 fps, every minute (except minutes divisible by ten), you skip counting the first two frames. You know you’re looking at drop frame timecode because the colon between minutes and frames is usually replaced by a semicolon. For example, you go:

- 12:38:59;27
- 12:38:59;28
- 12:38:59;29
- and then you skip to…
- 12:39:00;02
- 12:39:00;03

### Symbols

- I’m using the \ symbol to represent integer division. In (positive) integer division, we divide two numbers and discard the decimal part. So 3 \ 2 would just be equal to 1. Different languages represent integer division in different ways. Java and C will do it automatically as long as you’re dividing integer types. Javascript requires taking Math.floor() of regular division. Python 2.x will also do it automatically with integer types, but it can be forced to do it with a / / symbol, which is required in Python 3.x. Ruby will also do it automatically with integers and it can be forced with Numeric#div. It looks like \ the operator comes from the BASIC world. Different languages do different things when doing integer division with negative numbers. Some round towards zero, others round down. That’s beyond the scope of this tutorial, though.
- I’m using the symbol % to represent the modulo operator. Modulo refers to the remainder that’s left after division. 30 / 7 is 4 with a remainder of 2, so 30 % 7 would be 2. Most languages use the same % notation for modulo. As with integer division, modulo behaviors vary among programming languages when negative numbers are involved. Again, we’re not going to worry about those distinctions here.

### Finally, the Code!

So, without further ado, here’s some pseudocode in a vaguely Java style. First, we’ll convert a frame number into hours, minutes, seconds, and frames.

[This code has been updated on 8/8/2010 to correct a bug on line 27 caught by Jean-Baptiste Mardelle of Kdenlive. It was updated again on 1/4/2012 to fix a minor syntax error and correct a display issue with < and > symbols. Thanks to Martin Baker for catching those. I updated it in October, 2019 to remove 24p and to address an issue related to negative values]

#### Frame Number to Drop-Frame Timecode

#### Drop-Frame Timecode to Frame Number

### Non-Drop-Frame Timecode

For the sake of completeness, here’s the code for the relatively trivial task of converting between frame numbers and non-drop-frame timecode. This code is general and will work for any frame rate including 23.976p.

#### Frame Number to NDF

#### NDF to Frame Number

### A Note About 24p

In NTSC countries, 24p footage actually runs at 23.976 fps. 23.976 drop-frame timecode is not part of the SMPTE timecode spec and most editing programs don’t have a 24p drop-frame option. There are good reasons for this. Let’s think about how drop-frame timecode works for 29.97. Television programs commonly run in 30 minute increments, so drop-frame timecode should work in such a way that it is guaranteed to be a correct representation of the running time at least every 30 minutes. In fact, drop-frame is cyclical every ten minutes and, therefore, is guaranteed to accurately represent run-time every ten minutes.

At 30 frames per second, to convert ten minutes of programming to a frame count, you multiply:

30 (frames per second) * 60 (seconds per minute) * 10 (minutes) = 18,000

However, since NTSC video operates at 29.97, not 30 frames per second, the actual number of frames in ten minutes of NTSC video is:

29.97 (frames per second) * 60 (seconds per minute) * 10 (minutes) = 17,982

That means that every ten minutes, drop-frame timecode needs to make up for the discrepancy between 18,000 frames and 17,982 frames, which is 18 frames. And that’s exactly what drop-frame timecode does. By skipping two frames every minute, except for minutes divisible by ten, the timecode skips exactly 18 frames every ten minutes and therefore, even if drop-frame timecode may deviate from actual running time by a frame or two within a ten minute cycle, at the end of that cycle, it is guaranteed to be consistent.

Now let’s run those same numbers for 23.976:

24 (frames per second) * 60 (seconds per minute) * 10 (minutes) = 14,400

23.976 (frames per second) * 60 (seconds per minute) * 10 (minutes) = 14,385.6

Already, we can see that we might be in trouble here. The discrepancy over ten minutes is 14.4 frames, which has a decimal component. Even at 30 minutes or 60 minutes, the discrepancy between 24 and 23.976 has a decimal. That means that no matter what rules you set for dropping frames, there’s no way to make it come out evenly over a 60 minute period. There’s actually no way to make it come out evenly even over a 24 hour period. There’s simply no way to devise a formula to accurately do drop-frame for 23.976 footage.

The issue here is that 23.976 has more significant digits than 29.97.* Over a ten minute period, you’re multiplying your frame rate by 600 (60 seconds per minute * 10 minutes). That’s enough to multiply the 0.97 part of 29.97 into an integer, but at 23.976, you’re still stuck with that pesky 0.6.

So what should you do if you have 23.976 footage? Well, below is some code to get accurate timings, at least. We’ll call it pseudo-drop-frame for 24p. This is not part of the SMPTE spec, but it will give you a good estimate of the actual running time of your program.

Basically, what we’re doing here is calculating the true runtime in seconds and then using the remaining fractions of a second to calculate frames.

Practically, this means that a 30 minute 24p program should be (about) 43,157 frames long and a 60 minute program should be (about) 86,314. That translates to 24p non drop-frame timecode of 00:29:58:05 and 00:59:56:10 respectively.

#### Frame Number to Pseudo-Drop-Frame 24p

#### Pseudo-Drop-Frame 24p to Frame Number

Master sync / timecode generators like our Evertz 5601MSC use a GPS reference, so not only is the video reference spot on for frequency, the time code is extremely stable. Nevertheless, at any given moment there will be some amount of error between the (drop frame) time code versus real time. The solution to this is called “jam sync,” which essentially resets the time code, forcing it to match the real time once again. Some systems perform the jam when the error exceeds a set threshold; as you can imagine, this creates a fairly large jump and can be disruptive. Our equipment automatically performs the jam daily (ours takes place at 2am, when the automation doesn’t care). Not only does this correct for the relatively small mathematical imprecision you notice, it also makes provision for events like leap seconds that occur from time to time.

Naturally, this is only significant for operations that use time code to reflect real time — to control automation, or to index continuous recordings like air check systems. For time code within the context of specific program content, even shows that run several hours, uncorrected drop-frame code is accurate enough to run cleanly.

I’ve had to jam sync devices on a film set before, this is a way to be sure that all your equipment (cameras, audio, slate, etc.) have matching timecode. Since different internal timecode generators can drift slightly over time, you periodically re-sync everything to one master timecode generator. I didn’t know that similar equipment is used by broadcast engineers, but it makes sense. Another user, dcwar, pointed out that the manual for the Evertz Master Clock System that Jeff uses is available online. Page 54 has more detail about the jam sync process as well as a couple very cool graphs showing how drop-frame timecode can drift over the course of a day.

So there you have it, that’s why the very slight error in rounding frame rates to 29.97 doesn’t cause all television programming to slip by a few frames each day.

## Leave A Comment