Drop-frame vs non-drop timecode checker and frame calculator
This drop-frame timecode checker identifies the convention encoded by a timecode separator, verifies that the selected convention is valid for the supplied frame rate, and converts the label into a zero-based absolute frame count.
Run — free
It handles the skipped frame-number labels used by NTSC-derived drop-frame formats instead of treating every labeled minute as identical. The result also reports the nominal counting rate, effective playback rate, number of labels removed before the timecode, and elapsed seconds, making it useful for edit decisions, metadata validation, and automated media pipelines.
Understand what drop-frame timecode actually drops
Drop-frame timecode does not remove video pictures, shorten a clip, or change its playback speed. It removes selected frame numbers from the clock label so that the displayed time stays close to real elapsed time at NTSC-derived fractional rates. At 29.97 fps, counting as if the stream were exactly 30 fps makes the label drift by roughly 3.6 seconds per hour. The drop-frame convention corrects that mismatch by skipping labels 00 and 01 at the start of every minute except each tenth minute. At 59.94 fps it skips four labels, and at 119.88 fps it skips eight. This checker recognizes a semicolon or period before the frame field as drop-frame notation, while a colon means non-drop. It then reports both the selected convention and whether the supplied rate supports drop-frame counting. Nothing is removed from the underlying sequence: the corrected frame count simply subtracts the labels that should never have existed before the requested point. That distinction matters whenever an editor, asset manager, or automation script must translate a human-readable timecode into a precise zero-based frame position.
How the frame-count calculation is made
The calculator first maps the supplied playback rate to its nominal integer counting base. For example, 29.97 uses 30 frame labels per nominal second, while 23.976 uses 24. It validates the minutes, seconds, and frame field against that base. For non-drop notation, the calculation is direct: hours, minutes, and seconds are converted at the nominal rate and the final frame field is added. For drop-frame notation, the checker counts every completed minute before the label, excludes every tenth minute from the correction, and subtracts two, four, or eight skipped labels per corrected minute according to the rate. It also rejects impossible labels such as 00:01:00;00 at 29.97, because the first valid label in that minute is 00:01:00;02. The returned elapsed seconds divide the corrected frame count by the exact fractional playback rate, such as 30000/1001, rather than by the rounded display value. This preserves the practical relationship between frame position and running time while keeping all frame-count arithmetic deterministic and integral.
Choose the convention from the source, not by guesswork
A fractional rate does not automatically prove that a particular timecode is drop-frame. A 29.97 or 59.94 project can carry either drop-frame or non-drop labels, depending on the production requirement and equipment settings. That is why this tool reads the final separator instead of silently forcing one convention: use a semicolon or period when the source specifies drop-frame, and a colon when it specifies non-drop. Rates such as 23.976, 24, and 25 do not use the standard dropped-label correction supported here, so drop-frame punctuation at those rates returns an error instead of a plausible but misleading number. In a media pipeline, preserve the original rate and complete timecode string together; stripping punctuation can erase the convention. Use the reported frame count as a position from a zero origin, then add any separate source start offset only if your workflow requires it. For long-form programs, broadcast logs, caption cues, and conform lists, checking the convention before comparing positions prevents small hourly drift from becoming a visible synchronization or edit-placement error.
What you can do with it
Validate an edit decision list
Reject impossible drop-frame labels and convert valid source timecodes into comparable absolute frame positions.
Check broadcast running time
Confirm that an NTSC-derived program uses the intended convention and calculate elapsed seconds from its corrected count.
Normalize media metadata
Record the convention, nominal rate, exact playback rate, and frame count before assets enter a catalog or transcoding workflow.
FAQ
Does drop-frame timecode delete video frames?
No. It skips selected frame-number labels only; every captured video frame remains present.
How does the checker select drop-frame or non-drop?
A semicolon or period before the frame field selects drop-frame. A colon selects non-drop-frame.
Can 23.976 timecode be drop-frame?
Not under the standard convention implemented here. A drop-frame separator with 23.976 returns an invalid-input error.
Why is 00:01:00;00 invalid at 29.97?
Drop-frame counting skips labels 00 and 01 at the start of that minute. The first valid label is 00:01:00;02.
What does an API request cost?
Each API request costs $0.002. The browser calculator can be used without an API request.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/video2/drop-frame-timecode-check \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"framerate":29.97,"timecode":"01:00:00;00"}'const res = await fetch("https://api.kit.forhosting.com/video2/drop-frame-timecode-check", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"framerate": 29.97,
"timecode": "01:00:00;00"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/video2/drop-frame-timecode-check",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"framerate": 29.97,
"timecode": "01:00:00;00"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/video2/drop-frame-timecode-check", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"framerate":29.97,"timecode":"01:00:00;00"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"framerate":29.97,"timecode":"01:00:00;00"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/video2/drop-frame-timecode-check", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"framerate": 29.97,
"timecode": "01:00:00;00"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "video2.drop_frame_timecode_check",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 500 |
max_minutes | 60 |
max_megapixels | 3.9 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |