{
  "schemaVersion": 1,
  "contentVersion": "ca42e61ede0a24f789d7287a0001244ad22f4abf",
  "id": "docs/tools/filtering/ivtc",
  "collection": "docs",
  "title": "Inverse Telecine",
  "description": "Inverse telecine (IVTC) recovers the original 24p film frames from 3:2 pulldown video, using FFmpeg or VapourSynth's VFM and VDecimate.",
  "canonicalUrl": "https://encode.wiki/tools/filtering/ivtc/",
  "apiUrl": "https://encode.wiki/api/v1/documents/docs/tools/filtering/ivtc.json",
  "markdownUrl": "https://encode.wiki/api/v1/markdown/docs/tools/filtering/ivtc.md",
  "status": "current",
  "tags": [
    "migrated"
  ],
  "license": "CC BY-SA 4.0",
  "dates": {
    "lastVerified": "2026-10-08T00:00:00.000Z"
  },
  "authors": [],
  "sources": [
    {
      "title": "FFmpeg fieldmatch filter documentation",
      "url": "https://ffmpeg.org/ffmpeg-filters.html#fieldmatch",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg decimate filter documentation",
      "url": "https://ffmpeg.org/ffmpeg-filters.html#decimate",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "FFmpeg idet filter documentation",
      "url": "https://ffmpeg.org/ffmpeg-filters.html#idet",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "vs-jetpack v2.2.6",
      "url": "https://github.com/Jaded-Encoding-Thaumaturgy/vs-jetpack/tree/v2.2.6",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "BestSource R22 README",
      "url": "https://github.com/vapoursynth/bestsource/tree/R22",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    },
    {
      "title": "Wobbly v10",
      "url": "https://github.com/Jaded-Encoding-Thaumaturgy/Wobbly/tree/v10",
      "accessedAt": "2026-10-08T00:00:00.000Z"
    }
  ],
  "provenance": {
    "originUrl": "https://github.com/av1-community-contributors/codec-wiki/blob/37c3317fd058b23c71a87679bed5619a98f77752/docs/filtering/ivtc.mdx",
    "originCommit": "37c3317fd058b23c71a87679bed5619a98f77752",
    "migratedAt": "2026-08-21T00:00:00.000Z",
    "modified": true,
    "originPath": "docs/filtering/ivtc.mdx"
  },
  "headings": [
    {
      "depth": 2,
      "text": "Is it telecined?",
      "anchor": "is-it-telecined"
    },
    {
      "depth": 2,
      "text": "FFmpeg",
      "anchor": "ffmpeg"
    },
    {
      "depth": 2,
      "text": "VapourSynth",
      "anchor": "vapoursynth"
    },
    {
      "depth": 2,
      "text": "Check the result",
      "anchor": "check-the-result"
    }
  ],
  "sections": [
    {
      "id": "_preamble",
      "title": "Page introduction",
      "depth": 0,
      "canonicalUrl": "https://encode.wiki/tools/filtering/ivtc/",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/_preamble.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/_preamble.md",
      "checksum": "a620f37901fc843b9b3a98e834337d4dd1c853508c71b88020e1f9f3654d71a2",
      "bytes": 725
    },
    {
      "id": "is-it-telecined",
      "title": "Is it telecined?",
      "depth": 2,
      "anchor": "is-it-telecined",
      "canonicalUrl": "https://encode.wiki/tools/filtering/ivtc/#is-it-telecined",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/is-it-telecined.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/is-it-telecined.md",
      "checksum": "d55c77aa2d5f169be50368ee7b5f5497d7c1a91e5a3ba8c30b5f5eea31c49e73",
      "bytes": 1093
    },
    {
      "id": "ffmpeg",
      "title": "FFmpeg",
      "depth": 2,
      "anchor": "ffmpeg",
      "canonicalUrl": "https://encode.wiki/tools/filtering/ivtc/#ffmpeg",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/ffmpeg.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/ffmpeg.md",
      "checksum": "8cd14bb200b19b66c227a44a301a80c922099dd32c512e454566bfbd1723c102",
      "bytes": 917
    },
    {
      "id": "vapoursynth",
      "title": "VapourSynth",
      "depth": 2,
      "anchor": "vapoursynth",
      "canonicalUrl": "https://encode.wiki/tools/filtering/ivtc/#vapoursynth",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/vapoursynth.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/vapoursynth.md",
      "checksum": "7d26e23696aa28ce659f76d3a2d60db3cbb1fe43a2330aff5bbd69e80dd9b40a",
      "bytes": 1584
    },
    {
      "id": "check-the-result",
      "title": "Check the result",
      "depth": 2,
      "anchor": "check-the-result",
      "canonicalUrl": "https://encode.wiki/tools/filtering/ivtc/#check-the-result",
      "apiUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/check-the-result.json",
      "markdownUrl": "https://encode.wiki/api/v1/sections/docs/tools/filtering/ivtc/check-the-result.md",
      "checksum": "5d1b79493a4709df1c4be5d007c8366043fc6554fcd758accc6489131d602d7f",
      "bytes": 650
    }
  ],
  "outboundReferences": [
    "/tools/filtering/decombing/",
    "/tools/filtering/deinterlace/",
    "https://github.com/Jaded-Encoding-Thaumaturgy/Wobbly"
  ],
  "checksum": "9c9c6615f8b14a8f38c60403b36cdeac32acf72794c9d416107cd9985cdb3bbd",
  "contentFormat": "markdown",
  "markdown": "Film is shot at 24 frames per second, but NTSC video runs at 29.97. Telecine bridges the gap with 3:2 pulldown, which spreads every four film frames (A, B, C, D) over five video frames by repeating fields: AA, BB, BC, CD, DD. Two of every five frames are a mix of two film frames and look combed. Inverse telecine (IVTC) reverses this: it matches fields back into the original progressive frames and then drops the repeated one, giving back 24000/1001 fps with no interpolation and no loss.\n\nThat is why IVTC is the right fix for telecined film and [deinterlacing](/tools/filtering/deinterlace/) is the wrong one. Deinterlacing would interpolate frames that never needed it and leave you at 29.97 fps with an uneven cadence.\n\n## Is it telecined?\n\nRun `idet` over a few thousand frames:\n\n```sh\nffmpeg -t 60 -i input.mkv -vf idet -f null -\n```\n\nTelecine shows up as repeated fields: the \"Repeated Fields\" line reports Top or Bottom repeats in roughly two of every five frames. Stepping through frames in a previewer shows the same thing, three clean frames and two combed ones in a fixed rhythm. True interlaced video combs every moving frame instead.\n\nThere are two kinds of telecine:\n\n- **Hard telecine** has the pulldown baked into the frames. Most NTSC TV recordings and many anime DVDs are like this. This is what IVTC is for.\n- **Soft telecine** stores 24p video with flags that tell the player to repeat fields. NTSC film DVDs are often like this. There is nothing to undo; ignore the flags and you already have clean 24p. Plain `core.bs.VideoSource` ignores them (its `rff` option is off by default, and you may need to set the frame rate to 24000/1001 with `std.AssumeFPS`), but the vs-jetpack `BestSource` wrapper applies them by default (`rff=True`) and hands you hard-telecined 30i that needs the IVTC below.\n\n## FFmpeg\n\n`fieldmatch` pairs fields into frames, `yadif` deinterlaces the few frames that field matching couldn't repair, and `decimate` drops one frame in every five:\n\n```sh\nffmpeg -i input.mkv -vf \"fieldmatch,yadif=deint=interlaced,decimate\" -c:v libx264 -crf 18 output.mkv\n```\n\n`deint=interlaced` makes `yadif` touch only the frames `fieldmatch` still marked as combed, so clean frames pass through untouched. Field order is taken from the stream; set `fieldmatch=order=tff` or `bff` if the stream is flagged wrong. `decimate` only works on constant-frame-rate input, so a source that mixes telecined and genuinely 24p sections needs `dejudder,fps=30000/1001,fieldmatch,decimate` instead (from the FFmpeg documentation); anything more tangled belongs in VapourSynth.\n\nFFmpeg is fine for clean, constant-cadence sources. When the cadence changes partway, or you want to check what each frame did, use VapourSynth.\n\n## VapourSynth\n\nVIVTC's `VFM` (field matcher) and `VDecimate` do the same job with more control. `VFM` only accepts 8-bit input, so field-match before converting to a higher bit depth. `order` is mandatory: 1 for top field first, 0 for bottom field first.\n\n```python\nfrom vssource import BestSource\n\nclip = BestSource.source(\"input.mkv\", bits=None)\nclip = core.vivtc.VFM(clip, order=1)\nclip = core.vivtc.VDecimate(clip)\n```\n\n`VDecimate` removes one frame per cycle of five, whichever is the most nearly duplicate. vs-jetpack's `vsdeinterlace` wraps both and can deinterlace frames VFM could not match, much like the FFmpeg chain:\n\n```python\nfrom vsaa import NNEDI3\nfrom vsdeinterlace import vfm, vdecimate\n\nclip = vfm(clip, tff=True, postprocess=NNEDI3(double_rate=False).deinterlace)\nclip = vdecimate(clip)\n```\n\n`VFM`'s `mode` trades safety against matching. `mode=0` is the safest and never creates duplicate-frame jerkiness, but outputs combed frames where a good match existed in damaged sections (bad edits, blended or orphaned fields); `mode=5` finds a match almost everywhere at the risk of jerky motion. The default is 1. `vsdeinterlace` also has `sivtc`, a minimal fixed-pattern IVTC for sources whose cadence never changes, and `jivtc` for the case where a normal IVTC leaves chroma blends on every fourth frame.\n\nFor difficult hard-telecined sources, especially anime with changing cadence, [Wobbly](https://github.com/Jaded-Encoding-Thaumaturgy/Wobbly) is an assistant for fixing field matching and decimation scene by scene by hand, on top of VFM and VDecimate's output.\n\n## Check the result\n\nYou should get exactly four fifths of the original frame count, at 24000/1001 fps, with the same duration so audio stays in sync. Scrub through motion and look for duplicate frames or sudden jumps. Check the credits and any inserted video too: sections that were not film (credits, titles, commercials, 30i video) don't follow the pattern, and a fixed one-in-five decimation drops real motion from them. Those need separate handling; see [decombing](/tools/filtering/decombing/).\n\nDon't use `-r 24` or `fps=24` as a shortcut. They drop frames on a schedule without matching fields, so you keep combed frames and lose clean ones.\n"
}
