Technical recipe
CJK subtitle burn-in: font coverage, UTF-8 checks and decoded-frame review
Run an original 3.6-second caption exercise with a licensed pinned Noto CJK font, a dependency-free cmap checker, real FFmpeg/libass rendering, four decoded frames and 29 executed checks. Separate missing-glyph checks from readable, regionally correct text.
Before finishing a captioned clip, distinguish four different failures: incorrect subtitle bytes, a font without the requested codepoint, a renderer using another face, and pixels that do not match the intended text. This recipe supplies a real local execution sample, not a MiniMax model test.
Download the full brief01 · Environment and inputs
Download the original SRT, Node scripts, unmodified Noto Sans CJK SC Regular OTF and both OFL/copyright notices into one folder. Keep the font’s separate license when redistributing it.
Use Node.js 24 and an existing FFmpeg 6.0 build with libass/libx264; the bundle does not install or redistribute FFmpeg. The recorded run used Node v24.14.0, libass 0.17.0 and Noto font 2.004.
Choose a fresh local output folder. The sample is silent, 1280×720 and 3.6 seconds long; its script is not a full-length delivery exporter.
Read the intended four cues before rendering. An SC font’s nonzero glyph mappings do not establish preferred Japanese, Korean or Traditional Chinese regional forms.
02 · Run and inspect
01 · Preserve the exact font and verify the subtitle text
Keep NotoSansCJKsc-Regular.otf with OFL.txt and FONT-COPYRIGHT.txt. The unmodified official Sans2.004 font is pinned by SHA-256 and font name. Open sample.srt as UTF-8 and check its four cue texts and time ranges before any renderer is involved. The parser deliberately rejects markup, overlapping cues and variation sequences; it does not guess an unknown encoding or silently rewrite the subtitle. SRT start/end boundaries must align to 10 ms because ASS stores centiseconds; finer values are refused rather than rounded.
node --versionnode run-preflight-tests.mjs02 · Treat codepoint coverage as one preflight result
subtitle-check.mjs reads the font’s Unicode cmap format 4 or 12 and checks nonzero, in-range glyph IDs. This sample contains 43 unique non-whitespace codepoints and none were missing. Twenty-two executed scenarios include a known absent codepoint, missing or modified fonts, invalid UTF-8/UTF-16, overlap, unsafe paths and argument boundaries. Coverage is not a shaping or typography proof: a different regional glyph or unreadable layout can still have a valid mapping.
03 · Run the actual burn-in with safe fixed filter filenames
Pass an absolute FFmpeg binary path and a fresh output directory. The runner creates an original geometric slate, converts supported plaintext SRT into a fixed-style ASS file and uses libass to burn it in. User paths are copied to constant staging filenames instead of being interpolated into a filter expression. Child processes use shell:false, one encoder/filter thread, bounded logs and a one-minute timeout. The recorded macOS font provider was CoreText; the log confirms loading the bundled font and selecting its PostScript face, without claiming general font isolation.
node run-recipe.mjs --ffmpeg /absolute/path/to/ffmpeg --out ./fresh-outputnode run-recipe.mjs --ffmpeg /absolute/path/to/ffmpeg --out ./another-fresh-output --input ./sample-source.mp4 --srt ./sample.srt --font ./NotoSansCJKsc-Regular.otf04 · Decode and read the text, then keep the execution receipt
Compare keyframe-01 through keyframe-04 to the intended bilingual, Simplified/Traditional Chinese and Japanese/Korean cues. The script decodes each PNG and measures subtitle-band pixel changes against the uncaptioned source; those measurements do not prove character identity. Also read the actual font-selection log and coverage report. The execution receipt includes seven media assertions, twenty-two preflight scenarios, file sizes, hashes and the exact tool versions. A limited visual readback was recorded, while regional typography and other subtitle text still need their own review.
03 · Validate the output
- sample.srt decodes strictly as UTF-8 and has valid, ordered, nonoverlapping cue times; the twenty-two preflight tests pass.
- The bundled font remains byte-for-byte matched to its pinned SHA-256, and its OFL license plus copyright notice travel with it.
- All 43 non-whitespace sample codepoints map to valid nonzero glyph IDs; no all-Unicode or regional-form coverage claim is inferred.
- Actual FFmpeg rendering succeeds and its log records the bundled Noto face; missing-glyph diagnostics and unconfirmed font selection fail the run.
- All four selected output frames are decoded at their intended cue times and have measured subtitle-band differences from the clean source.
- The expected text is checked visually for replacement boxes, clipping and punctuation; a nonempty PNG or pixel delta alone is insufficient.
- The receipt identifies actual versions and output hashes, states that production/provider tasks were not run, and preserves the distinction between local rendering and generation-quality evidence.
04 · Boundaries and troubleshooting
- The text contains replacement symbols before rendering.
- Export the source subtitle explicitly as UTF-8 and rerun preflight. Do not change an encoding label while leaving unknown bytes unchanged.
- Coverage finds a missing U+ codepoint.
- Inspect the exact codepoint, obtain a suitably licensed font covering it, and redo the family name, checksum, renderer and visual checks. Do not accept an undocumented system fallback.
- Glyphs exist but look wrong for the target language.
- Separate default codepoint coverage from region-specific CJK forms. Use the appropriate language variant and have the intended language’s typography reviewed; the SC sample does not prove those regional forms.
- The renderer exits successfully but the visible subtitle is absent or clipped.
- Read actual cue times, font-selection diagnostics and decoded frames. Check the 1280×720/3.6-second demonstration limits and placement before adapting the script to a real clip.
- A path, font or output-file check rejects the command.
- Use a fresh controlled directory, the exact bundled font, ordinary local files and an absolute FFmpeg path. The script refuses overwrite, symlinks, traversal and network inputs.
- The fixture works but a full delivery would lose audio or content after 3.6 seconds.
- Do not use this sample runner unchanged for full delivery. Review duration, audio mapping, frame size and caption safe area in a separately verified export command.
- A 201–209 ms cue is refused before conversion.
- Use 10 ms-aligned start/end boundaries with a positive duration. This sample does not round millisecond boundaries, because both values would otherwise collapse to 0.20 seconds in ASS.
Keep the source subtitle, exact font/license, renderer log, four decoded sample frames and execution receipt together. The provided hashes identify this local run; platform/build differences can change output bytes. No model generation, production billing or search-traffic result is claimed.
Files and evidence
- Noto CJK official Sans2.004 license
- Noto CJK official language/font download guide
- FFmpeg official subtitle and ASS filter documentation
- OpenType official cmap specification