Skip to main content

Media Analyzer

The media analyzer is the first decision-making stage after a file is discovered. It runs FFprobe once, normalizes the raw stream metadata, and returns a typed analysis object for the planner and future intelligence features.

The analyzer does not decide whether to transcode. It records facts. The planner remains responsible for skip, remux, and transcode decisions.

What the analyzer extracts

For the selected video stream and container, Alchemist records:

  • codec, container, resolution, frame rate, duration, and file size
  • video bitrate and container bitrate when FFprobe reports them
  • bit depth and pixel-format warnings
  • HDR/color metadata such as transfer, primaries, color space, and range
  • audio stream metadata, channel counts, default/forced flags, and heavy/lossless audio facts
  • subtitle stream metadata, including image-based and styled subtitle facts
  • cheap structure metadata such as interlacing flags and Dolby Vision side data
  • source chapter count for non-fatal preservation checks after finalization

This is intentionally limited to metadata already available from the normal probe path. Alchemist does not run expensive sampled probes such as cropdetect, VMAF pre-flight, OCR, decode spot checks, or grain/complexity analysis during this pass.

Analyzer report

Each MediaAnalysis includes an analysis_report alongside the existing metadata, warnings, and confidence fields. The report has two parts:

analysis_report:
labels: factual classifications
metrics: measured optional values

Labels

Labels are factual and deterministic. They are not product-policy conclusions. Examples include:

LabelMeaning
high_bpp_densityThe measured normalized video bits-per-pixel is high.
low_bpp_densityThe measured normalized video bits-per-pixel is low.
remux_like_densityContainer bitrate is very close to video bitrate, suggesting low mux overhead.
heavy_audioAt least one audio stream uses a codec Alchemist treats as heavy/lossless for optimization evidence.
lossless_audioAt least one audio stream is a lossless codec such as TrueHD, FLAC, ALAC, or PCM.
image_subtitleAt least one subtitle stream is image-based, such as PGS/DVD subtitles.
styled_subtitleAt least one subtitle stream uses styled text, such as ASS/SSA.
hdr_metadataHDR metadata is present.
bt2020_without_transferBT.2020 primaries are present but transfer metadata is missing.
dolby_vision_metadataDolby Vision side-data metadata is present.
interlaced_metadataFFprobe reports an interlaced field order.
variable_frame_rate_hintAverage-rate and frame-count-derived FPS disagree enough to suggest VFR.

Warnings such as missing_video_bitrate, missing_duration, and unrecognized_pixel_format are mirrored as labels so future UI surfaces can show the same evidence without reverse-engineering warning enums.

Metrics

Metrics are optional because FFprobe does not report every field for every file. Current metrics include:

  • raw_bpp and normalized_bpp
  • estimated_container_bitrate_bps
  • aggregate audio_bitrate_share
  • video/audio/subtitle stream counts
  • image/text subtitle counts
  • HDR and BT.2020 booleans
  • FPS values derived from average rate and frame count

If video bitrate is missing, Alchemist may still estimate container bitrate from file size and duration, but BPP density labels remain absent because they require a measured video bitrate.

Cache behavior

Analyzer output is cached in the media probe cache keyed by path, mtime, size, file identity when available, and FFprobe/cache schema version. The analyzer report bumps the probe cache schema marker so older cached probe payloads are refreshed before these new facts are used.

Legacy cached MediaAnalysis JSON without analysis_report still decodes safely; the report defaults to an empty label set and empty metrics.

Relationship to the planner

The planner still uses the stable MediaMetadata fields and existing confidence/warning behavior. Analyzer labels and metrics are stored for later Library Intelligence and explanation work, but this pass does not change job queueing, skip/remux/transcode decisions, output promotion, or replacement policy.

See Planner and Skip Decisions for the current policy layer.