VIDEO TIMING · EXPLAINER

Drop Frame vs Non-Drop Frame Timecode: Why Your Captions Drift

Your subtitles start perfectly in sync and are seconds off by the end of the hour. The cause is usually a 70-year-old engineering decision. Here is how drop frame timecode works and how to convert it correctly.

Updated October 23, 2026 · 7 min read

Quick answer

Video at 29.97 frames per second doesn't fit neatly into a clock that counts 30 frames per second. Non-drop frame (NDF) timecode counts 30 labels per second anyway, so after an hour of video the timecode reads 01:00:00:00 when roughly 1 hour and 3.6 seconds has actually passed. Drop frame (DF) timecode fixes this by skipping certain frame numbers (never actual frames) so the label stays in step with real time.

If you convert timecode to subtitle timestamps and pick the wrong one, your captions drift: perfect at the start, noticeably late by the end.

DimensionDrop frame (DF)Non-drop frame (NDF)
Frame rates29.97 and 59.94 fpsAny rate, including 24, 25, 30, 23.976, 29.97
Frames actually removedNoneNone
Frame numbers skippedYes, at most minute boundariesNo
Matches wall-clock timeYes, very closelyOnly at integer frame rates
Drift at 29.97 fpsNegligibleAbout 3.6 seconds per hour
Typical notation01:00:00;00 (semicolon)01:00:00:00 (colons)
Common inUS broadcast, program-length timingFilm, 24/25 fps work, many edit sessions
Math to convertMore complexSimple counting

What SMPTE timecode is

SMPTE timecode (named after the Society of Motion Picture and Television Engineers) gives every frame of video a unique address in the form hours:minutes:seconds:frames. At 25 fps the frame field runs 00 to 24; at 30 fps (or 29.97) it runs 00 to 29.

Timecode is a label, not a measurement. That distinction is the whole story. As long as the frame rate is a whole number, labels and real time agree. When the frame rate is 29.97, they can't, and you have to choose which one to keep honest.

Why 29.97 fps exists

Original black-and-white US television ran at 30 frames per second. When color was added to the NTSC standard in the early 1950s, the color information was carried on a subcarrier, and engineers needed it to avoid interfering with the audio carrier while staying compatible with existing black-and-white sets. The solution was to lower the frame rate very slightly, by a factor of 1000/1001.

So "30 fps" became 30000/1001, about 29.97 fps. The same factor gives the other "odd" rates you'll see:

Nominal rateActual rateExact valueWhere you see it
2423.97624000/1001Film-style content for NTSC regions, a lot of web video
3029.9730000/1001US broadcast, many cameras and phones in NTSC regions
6059.9460000/1001Sports, high-frame-rate broadcast
252525PAL regions (Europe and others); no drift issue

Rates like 25, 50, 24 and 30 are whole numbers, so their timecode never drifts. The headache is specific to the 1000/1001 family.

Where the drift comes from

Non-drop frame timecode counts 30 labels per "second." But only about 29.97 frames arrive per real second. So each timecode second is slightly longer than a real second.

  • Per real hour, 29.97 fps video produces about 107,892 frames.
  • NDF timecode needs 108,000 frames to reach 01:00:00:00.
  • The difference is 108 frames, about 3.6 seconds.

Run a two-hour film at 29.97 NDF and the timecode is roughly 7 seconds behind the clock by the end. For edit decisions that doesn't matter. For broadcast schedules, program durations and captions synchronized to real time, it does.

How drop frame timecode works

Drop frame skips 108 frame numbers per hour to cancel the drift exactly (well, almost exactly; the leftover error is a tiny fraction of a frame per day). It does it with a fixed rule:

  • At the start of every minute, skip frame numbers 00 and 01.
  • Except every tenth minute (00, 10, 20, 30, 40, 50), where nothing is skipped.

That is 2 numbers skipped in 9 out of every 10 minutes: 18 per 10 minutes, 108 per hour. In practice, the counter jumps like this:

01:00:59;28
01:00:59;29
01:01:00;02   <- ;00 and ;01 do not exist in this minute
01:01:00;03

01:09:59;29
01:10:00;00   <- tenth minute, no skip
01:10:00;01

So a DF timecode like 01:01:00;00 is invalid. It never exists. If your software ever produces it, something has mislabeled NDF as DF.

At 59.94 fps, drop frame works the same way but skips four frame numbers (00 to 03) at each non-tenth minute.

Notation: semicolon vs colon

The usual convention:

  • Drop frame: semicolon before the frames, 01:00:00;00. Some tools use a semicolon or period throughout, such as 01;00;00;00 or 01.00.00.00.
  • Non-drop frame: all colons, 01:00:00:00.

Treat the separator as a strong hint, not a guarantee. Files exported from scripts, spreadsheets or caption tools often lose the semicolon. When the stakes are high, check the project's frame rate and timecode mode in the editing or caption software directly.

Which one should you use?

  • US broadcast deliverables at 29.97: usually drop frame, because program lengths and schedules are in real time. Follow the delivery spec you were given.
  • Film, 24, 25 or 50 fps projects: non-drop frame; there is nothing to drop.
  • 23.976 projects: non-drop frame. There is no standard drop frame mode at this rate, so conversions must use the exact 24000/1001 rate.
  • Internal editing at 29.97: either works, as long as everyone on the project uses the same mode. Mixing modes between editor, caption vendor and delivery is where problems start.

How timecode affects subtitles and captions

Subtitle formats like SRT and WebVTT don't use frames at all. They use real time in hours, minutes, seconds and milliseconds, such as 00:01:00,060 in SRT or 00:01:00.060 in WebVTT (see our SRT vs VTT guide). Any time you move between a frame-based timeline and a subtitle file, you are converting labels to real time, and you have to know which kind of label you started with.

The classic failure: a caption list exported with 29.97 NDF timecode is converted to SRT as though each timecode second were a real second. The first caption is fine. Every later caption is slightly early compared to the video, and the error grows by about 3.6 seconds per hour. On a long lecture or webinar, viewers notice well before the end.

Converting timecode to SRT time in Python

The safe approach is always: timecode to frame count, then frame count to seconds using the exact rate.

from fractions import Fraction

def timecode_to_frames(tc, nominal_fps=30, drop_frame=False):
    """Convert 'HH:MM:SS:FF' or 'HH:MM:SS;FF' to a frame count."""
    hh, mm, ss, ff = [int(p) for p in tc.replace(";", ":").split(":")]
    frames = ((hh * 3600) + (mm * 60) + ss) * nominal_fps + ff
    if drop_frame:
        # 2 numbers dropped per minute at 30 fps, 4 at 60 fps
        dropped_per_min = 2 if nominal_fps == 30 else 4
        total_minutes = hh * 60 + mm
        frames -= dropped_per_min * (total_minutes - total_minutes // 10)
    return frames

def frames_to_srt(frames, nominal_fps=30, pulldown=True):
    """Frame count to an SRT timestamp. pulldown=True means a 1000/1001 rate."""
    rate = Fraction(nominal_fps * 1000, 1001) if pulldown else Fraction(nominal_fps)
    total_ms = round(Fraction(frames) / rate * 1000)
    h, rem = divmod(total_ms, 3_600_000)
    m, rem = divmod(rem, 60_000)
    s, ms = divmod(rem, 1000)
    return f"{h:02}:{m:02}:{s:02},{ms:03}"

# One hour of 29.97 DF timecode is (almost exactly) one real hour
print(frames_to_srt(timecode_to_frames("01:00:00;00", drop_frame=True)))
# 00:59:59,996

# The same label read as NDF is about 3.6 seconds longer
print(frames_to_srt(timecode_to_frames("01:00:00:00")))
# 01:00:03,600

# 23.976 fps material (NDF, 24 frame labels per second)
print(frames_to_srt(timecode_to_frames("00:10:00:00", nominal_fps=24), nominal_fps=24))
# 00:10:00,600

Two details worth noting. First, Fraction avoids floating point rounding building up over long files. Second, many programs start timecode at 01:00:00:00 rather than zero, so subtract the program's start timecode before converting, or every subtitle will be an hour late.

Common sync bugs and how to spot them

SymptomLikely causeFix
Captions in sync at start, drift laterDF or NDF timecode converted as if 30 fps were exactly 30Convert with the 1000/1001 rate
Drift of about 3.6 s per hourNDF treated as real time at 29.97Use the exact rate when converting
Drift of about 0.1 percent on 23.976 contentRate treated as 24 instead of 24000/1001Use 24000/1001
Every caption off by exactly one hourProgram starts at 01:00:00:00Subtract the start timecode
Invalid timecodes like ;00 at minute 1NDF values labeled as DFCheck the source mode
Captions off by a fixed amountDifferent start points or an intro edited inShift all cues by a constant offset
PAL and NTSC versions disagree25 fps vs 23.976 or 29.97 conversion with speed changeRe-time per version, don't reuse files blindly

A quick diagnostic: compare the error at the first and last cue. If the error is constant, you have an offset problem. If it grows steadily, you have a rate problem.

Common myths

  • "Drop frame drops frames." It drops numbers. Every frame of picture is still there.
  • "Drop frame is more accurate." Both count every frame correctly. Drop frame only makes the labels match the wall clock.
  • "You need drop frame for 23.976." There is no standard drop frame mode at that rate; use NDF and convert with the exact rate.
  • "Web video doesn't have this problem." Plenty of phone and web video is 29.97 or 23.976. It shows up the moment you convert between frames and milliseconds.

Getting caption files that already use real time

If you only need subtitles for a video that lives on YouTube, you can sidestep frame math entirely. YouTubeTranscript.dev exports a video's captions, or AI-generated ones when none exist, as SRT or VTT with millisecond timestamps in real time, so there is no timecode mode to get wrong. If you need to shift or clean those files afterward, the SRT to text and remove timestamps tools help, and our video accessibility guide covers what synchronized captions need to meet WCAG.

Frequently asked questions

What is the difference between drop frame and non-drop frame timecode?+

Both count every frame of 29.97 fps video. Non-drop frame numbers frames continuously at 30 per second, so its labels slowly fall behind real time. Drop frame skips certain frame numbers (not actual frames) so the timecode label stays aligned with the wall clock.

Does drop frame timecode actually drop frames?+

No. No picture is removed. Drop frame only skips frame numbers: labels ;00 and ;01 at the start of every minute, except every tenth minute. The video itself is unchanged.

How do you tell drop frame from non-drop frame timecode?+

By convention, drop frame uses a semicolon before the frame field, as in 01:00:00;00, and non-drop frame uses colons throughout, as in 01:00:00:00. Some software uses a period or other marker, so check the project or file settings when in doubt.

How much does non-drop frame timecode drift?+

At 29.97 fps, non-drop frame timecode falls behind real time by about 3.6 seconds per hour, which is 108 frames.

Is there drop frame timecode for 23.976 fps?+

Not in standard SMPTE timecode. 23.976 fps material is normally counted with non-drop frame timecode, so it drifts against real time in the same way, and conversions must account for the 1000/1001 factor.

Why is NTSC video 29.97 frames per second instead of 30?+

When color was added to the US broadcast standard in the early 1950s, engineers lowered the frame rate by a factor of 1000/1001 to reduce interference between the new color signal and the sound carrier while keeping compatibility with black-and-white TVs. 30 fps became about 29.97 fps.

Keep reading

मुफ़्त में ट्रांसक्रिप्ट निकालना शुरू करें

किसी भी YouTube वीडियो को सेकंडों में टेक्स्ट में बदलें। क्रेडिट कार्ड की ज़रूरत नहीं।

YOUTUBETRANSCRIPT.DEV आज़माएँ →
Drop Frame vs Non-Drop Frame Timecode Explained