Skip to main content

Automatic QC Tests

Automatic QC is configured as a list of tests in the qc object of a Job Description. Each test is one rule (for example, Max Characters Per Line) with its own parameters, a failure level, and a threshold. QC never changes your captions. It produces a report and an overall qc_status for the job.

{
"qc": {
"stage": "pre",
"tests": [
{ "id": "maxCharsPerLine", "max": 42, "level": "critical", "threshold": 0 },
{ "id": "maxLinesPerEvent", "max": 2, "level": "critical", "threshold": 0 },
{ "id": "frameGap", "min": 2, "minTolerance": 0, "maxTolerance": 6, "level": "info", "threshold": 0 },
{ "id": "sequentialTiming", "level": "critical", "threshold": 0 },
{ "id": "xmlEntities", "level": "critical", "threshold": 0 }
]
}
}

Test properties​

PropertyRequiredDescription
idYes*The test to run (see the catalog). *You can use name instead: the display name (for example "Max Characters Per Line") is matched case-insensitively.
levelNocritical, warn, or info. warning is also accepted. Defaults to the test's default level.
thresholdNoNumber of errors needed before the test changes the job status. 0 and 1 both mean the first error counts; 3 means three or more errors. Default 0.
enabledNoSet to false to keep a test in the config without running it. Default true.
parametersNoTest-specific settings such as max, min, unit, or values. Missing parameters use the defaults listed below.

You can list a test more than once with different settings. For example, add maxCps at 17 as warn and again at 20 as critical. The job is rejected when it is submitted if a test ID is unknown, a level is invalid, or a threshold is negative. The API returns HTTP 400 and the CLI exits with a non-zero code.

QC status​

A test is triggered when its error count reaches max(threshold, 1). The job's qc_status is then:

qc_statusWhen
failAt least one triggered critical test
warnNo triggered critical tests, and at least one triggered warn test
passAnything else. info tests are reported but never change the status.

qc_errors is the total number of errors from every test, including info tests. A QC failure never stops a Convert job from producing its output file. The CLI can optionally exit with code 2 on fail; see --qc_exit_code.

Stages​

qc.stage controls when content tests run:

  • pre (the default) checks the captions as decoded from the source.
  • post checks them after all filters, right before encoding, at the target frame rate.

Technical tests (the XML checks) and source-order tests (sequentialTiming) always check the source file, whatever the stage.

QC report​

The API response, the job record, and the webhook all include qc_status and qc_errors. The full report is returned as qcReport:

{
"version": 2,
"info": { "stage": "pre", "source_profile": "dfxp", "tc_start": "00:00:01:00" },
"summary": { "qc_status": "fail", "qc_errors": 3, "critical": 1, "warn": 1, "info": 0 },
"tests": [
{ "index": 0, "id": "maxCharsPerLine", "name": "Max Characters Per Line", "level": "critical", "threshold": 0, "scope": "content", "ran": true, "errorCount": 2, "triggered": true }
],
"results": {
"content": [
{ "testId": "maxCharsPerLine", "testName": "Max Characters Per Line", "name": "Character Length Error", "level": "critical", "details": "Event 4 has a line with a character length of 47.", "timecodeStart": "00:00:12:05", "timecodeEnd": "00:00:14:00", "start": 12.2, "end": 14, "eventId": 4, "text": "This line is longer than the..." }
],
"technical": [
{ "testId": "xmlEntities", "name": "XML Entity Error", "level": "critical", "details": "Line 12: unescaped \"&\" must be written as &.", "line": 12, "eventId": null }
]
}
}
  • Summary counts: summary.critical, summary.warn, and summary.info count triggered tests at each level, not errors.
  • Skipped tests: in tests[], skipped explains why a test did not apply, for example an XML test on an SRT source.
  • Test errors: error is set on a test that could not run. A test that errors counts as triggered.
  • Event groups: in post-processing jobs with more than one event group, each content error also has an eventGroup index.

Test catalog​

Text​

IDNameParameters (default)Default levelDescription
minCharsPerLineMin Characters Per Linemin (1)criticalFlags events that contain a line shorter than the minimum number of characters.
maxCharsPerLineMax Characters Per Linemax (42)criticalFlags events that contain a line longer than the maximum number of characters.
minLinesPerEventMin Lines Per Eventmin (1)criticalFlags events with fewer text lines than the minimum.
maxLinesPerEventMax Lines Per Eventmax (2)criticalFlags events with more text lines than the maximum.
minWordsPerLineMin Words Per Linemin (1)warnFlags events that contain a line with fewer words than the minimum.
maxWordsPerLineMax Words Per Linemax (12)warnFlags events that contain a line with more words than the maximum.
illegalChars608Illegal 608 Characters—criticalFlags characters that cannot be encoded as CEA-608 closed captions.
illegalCharsNetflixIllegal Netflix Characters—criticalFlags characters outside the Netflix supported glyph list.
whiteSpaceLeading, Trailing or Double Spaces—warnFlags lines that start or end with a space, or contain two or more spaces in a row.
emptyEventEmpty Event—warnFlags timed events that contain no text. Note: formats that use blank events as clears (e.g. SCC) will report those clears.

Timing​

IDNameParameters (default)Default levelDescription
minDurationMin Event Durationmin (0.833)
unit ("seconds"; frames / seconds)
criticalFlags events shorter than the minimum duration.
maxDurationMax Event Durationmax (7)
unit ("seconds"; frames / seconds)
criticalFlags events longer than the maximum duration.
minCpsMin Characters Per Secondmin (1)
countSpaces (true)
infoFlags events whose reading speed is below the minimum characters per second.
maxCpsMax Characters Per Secondmax (20)
countSpaces (true)
criticalFlags events whose reading speed is above the maximum characters per second.
minWpmMin Words Per Minutemin (1)infoFlags events whose reading speed is below the minimum words per minute.
maxWpmMax Words Per Minutemax (200)warnFlags events whose reading speed is above the maximum words per minute.
frameGapFrame Gapmin (2 frames)
minTolerance (0 frames)
maxTolerance (11 frames)
warnWhen the gap between two events falls between the min and max tolerance (in frames), it must be exactly the required gap. Gaps outside the tolerance window are ignored.
minGapMin Gap Between Eventsmin (2 frames)criticalFlags consecutive events separated by fewer frames than the minimum.
maxGapMax Gap Between Eventsmax (100 frames)infoFlags consecutive events separated by more frames than the maximum.
overlapOverlapping Events—criticalFlags events that start before the previous event ends.
sequentialTimingSequential Timing—criticalFlags events that start earlier than the event before them in the source file (captions out of order). Always checks the source file order, whatever the QC stage.
zeroOrNegativeDurationZero or Negative Duration—criticalFlags events whose end time is equal to or earlier than their start time.
startTimeRangeStart Time Rangemin ("00:00:00:00")
max ("01:00:00:00")
warnFlags events that start before the min timecode or after the max timecode.

Formatting​

IDNameParameters (default)Default levelDescription
boldFormattingBold Formatting—infoFlags events that contain bolded text.
italicsFormattingItalics Formatting—infoFlags events that contain italics text.
underlineFormattingUnderline Formatting—infoFlags events that contain underlined text.

Technical (XML)​

IDNameParameters (default)Default levelDescription
xmlWellFormedXML Well-Formed—criticalValidates that an XML-based source file (TTML, DFXP, IMSC, etc.) is well-formed.
xmlEntitiesXML Entity Escaping—criticalFlags unescaped ampersands and less-than signs, and entities that are not defined in XML (e.g.  ).
frameRateFrame RateframeRate ("23.976"; 24 / 25 / 30 / 50 / 60 / 23.976 / 23.98 / 29.97 / 59.94)criticalChecks ttp:frameRate and ttp:frameRateMultiplier against the expected media frame rate.
timeBaseTime Basevalues (["media"])criticalChecks ttp:timeBase against the allowed values.
tcFormatTimecode Formatvalues (["smpte"])criticalChecks that every begin/end value uses an allowed time expression format (smpte, tcMs, seconds, milliseconds, frames, ticks).
fontSizeUnitFont Size Unitvalues (["%"])criticalChecks that every font size unit in the file is one of the allowed values.
fontSizeRangeFont Size Rangemin (80)
max (100)
criticalChecks that every font size is within the min and max values.
fontWeightFont Weightvalues (["normal"])criticalChecks that every font weight in the file is one of the allowed values.
fontStyleFont Stylevalues (["normal"])criticalChecks that every font style in the file is one of the allowed values.
fontFamilyFont Familyvalues (["proportionalSansSerif"])criticalChecks that every font family in the file is one of the allowed values.
textOutlineColorText Outline Colorvalues (["#101010"])criticalChecks that every text outline color in the file is one of the allowed values.
textOutlineSizeText Outline Sizevalues ([3])criticalChecks that every text outline size in the file is one of the allowed values.
textOutlineSizeUnitText Outline Size Unitvalues (["%"])criticalChecks that every text outline unit in the file is one of the allowed values.
textColorText Colorvalues (["#ebebeb"])criticalChecks that every font color in the file is one of the allowed values.
backgroundColorBackground Colorvalues (["transparent"])criticalChecks that every background color in the file is one of the allowed values.
luminanceGainLuminance Gainvalues ([1.5])criticalChecks that every luminance gain in the file is one of the allowed values.

Technical tests apply to XML-based sources such as TTML, DFXP, IMSC and SMPTE-TT, and are skipped for other formats. list parameters accept an array or a comma-separated string. minDuration and maxDuration use seconds by default; set unit to frames to use frames at the stage's frame rate.

Presets​

Presets are ready-made test lists. You'll find them in the Automatic QC panel of the Job Form. Apply one as a starting point, then edit any of its tests. The Netflix presets use values from the Netflix English Timed Text Style Guide and Subtitle Timing Guidelines.

Netflix English (Adult) (netflixEnglishAdult)​

Netflix English subtitle and timing guidelines for adult programs (20 CPS).

TestSettingsLevel
maxCharsPerLinemax: 42critical
maxLinesPerEventmax: 2critical
minDurationmin: 0.833, unit: "seconds"critical
maxDurationmax: 7, unit: "seconds"critical
minGapmin: 2critical
frameGapmin: 2, minTolerance: 3, maxTolerance: 11warn
overlap—critical
sequentialTiming—critical
zeroOrNegativeDuration—critical
illegalCharsNetflix—critical
whiteSpace—warn
emptyEvent—warn
xmlWellFormed—critical
xmlEntities—critical
maxCpsmax: 20, countSpaces: truecritical

Netflix English (Children) (netflixEnglishChildren)​

Netflix English subtitle and timing guidelines for children's programs (17 CPS).

TestSettingsLevel
maxCharsPerLinemax: 42critical
maxLinesPerEventmax: 2critical
minDurationmin: 0.833, unit: "seconds"critical
maxDurationmax: 7, unit: "seconds"critical
minGapmin: 2critical
frameGapmin: 2, minTolerance: 3, maxTolerance: 11warn
overlap—critical
sequentialTiming—critical
zeroOrNegativeDuration—critical
illegalCharsNetflix—critical
whiteSpace—warn
emptyEvent—warn
xmlWellFormed—critical
xmlEntities—critical
maxCpsmax: 17, countSpaces: truecritical

Broadcast 608 Captions (broadcast608)​

Common CEA-608 closed caption limits: 32 characters, 4 lines, legal 608 characters and sequential timing.

TestSettingsLevel
maxCharsPerLinemax: 32critical
maxLinesPerEventmax: 4critical
illegalChars608—critical
overlap—critical
sequentialTiming—critical
zeroOrNegativeDuration—critical

Legacy configuration​

The original qc.content / qc.technical configuration is still accepted and is converted to tests automatically. Every converted test is critical with a threshold of 0, so any error sets qc_status to fail.

Legacy settingTest
content.minChars / maxCharsminCharsPerLine / maxCharsPerLine
content.minLines / maxLinesminLinesPerEvent / maxLinesPerEvent
content.minWords / maxWordsminWordsPerLine / maxWordsPerLine
content.overlap (unless false)overlap
content.illegalChars608 / illegalCharsNetflixillegalChars608 / illegalCharsNetflix
content.minEventDurationFrames / maxEventDurationFramesminDuration / maxDuration with unit: "seconds" (the legacy values were always compared in seconds)
content.minCps / maxCps, minWpm / maxWpmminCps / maxCps, minWpm / maxWpm
content.minEventGapFrames / maxEventGapFramesminGap / maxGap
content.whiteSpacewhiteSpace
content.minStartSmpte / maxStartSmptestartTimeRange
content.formatBold / formatItalics / formatUnderlineboldFormatting / italicsFormatting / underlineFormatting
technical.frameRate, timeBase, tcFormat, fontSizeUnit, fontWeight, fontStyle, fontFamilyThe test with the same name
technical.fontSizeMin / fontSizeMaxfontSizeRange
technical.textOutlineColor / textOutlineSize / textOutlineSizeUnitThe test with the same name
technical.color / bgColor / luminanceGaintextColor / backgroundColor / luminanceGain

Content settings are converted only when content.enabled is true. Technical settings are converted only when technical.enabled is true and technical.profile is "xml".

The conversion also corrects some legacy behavior:

  • Italics and underline checks now run.
  • The overlap flag is respected.
  • Frame gaps are rounded to the nearest frame.
  • A 29.97 frame-rate check expects a 1000 1001 multiplier.