Skip to content

Output Format

All results of the toolkit are records in one format, shared by all commands. This page describes the records and the files they are written to. For the individual metrics, see Metrics.

Files

With -o <directory>, the toolkit writes these files:

  • records.ndjson: all records of the run, one JSON object per line (format ndjson)
  • summary.json: one JSON document with the most important results per input (format json)
  • <record_type>.csv: one CSV file per record type, with nested fields flattened into columns (format csv)

--format selects the formats. The default is ndjson,json. Without -o, the NDJSON records are written to standard output.

Records

Every record has a type field and a schema_version field. The record types are:

  • run_info: information about the run: tool version, command line, inputs with their IDs, start and end time, versions of the components, host, options, and the final status and errors
  • stream_info: stream information of one input (container, programs, streams)
  • frame_bitstream: bitstream statistics of one video frame
  • frame_pixels: pixel metrics of one video frame
  • model_score: a quality model score for a second, a GOP, or a whole stream
  • alignment: the alignment of one encode with the reference (compare only)
  • frame_fullref: VMAF, PSNR and SSIM of one frame against the reference (compare only)
  • summary: statistics of one metric of one stream
  • comparison: the difference of one metric's statistics between an encode and the reference (compare only)

The run_info record is written twice: at the start of the run with status set to running, and at the end with the final status. When you read records.ndjson, use the last run_info record.

Common fields

Records that refer to an input have these fields:

  • input: the ID of the input, as listed in run_info.inputs. Inputs are numbered from "0" in the order of the command line. In compare, "0" is the reference.
  • stream: the index of the stream within the input, as numbered by FFmpeg
  • program, pid: the program number and PID, for transport streams

Frame records also have:

  • n: the frame index in presentation order, starting at 0
  • pts: the presentation timestamp in seconds
  • pts_raw and time_base: the original timestamp and its time base, so that no precision is lost

All timestamps are the original timestamps of the file, including the start offset of transport streams. This lets you locate a frame with other tools, such as ffprobe. The terminal view shows times from the start of each input instead.

Optional fields are left out of a record when they have no value, rather than written as null.

Example

A frame_bitstream record of an H.264 frame (shortened):

{
  "schema_version": "0.1.6",
  "type": "frame_bitstream",
  "input": "0",
  "stream": 0,
  "program": 1,
  "pid": 256,
  "n": 42,
  "pts": 3.16,
  "pts_raw": 284400,
  "time_base": {"num": 1, "den": 90000},
  "frame_type": "P",
  "is_idr": false,
  "size": 18734,
  "qp_avg": 28.4,
  "qp_stdev": 2.1,
  "qp_min": 24,
  "qp_max": 35,
  "motion_avg": 3.2
}

A model_score record with the overall P.1204.3 score:

{
  "schema_version": "0.1.6",
  "type": "model_score",
  "input": "0",
  "stream": 0,
  "model": "p1204.3",
  "scope": "overall",
  "start": 1.48,
  "end": 7.48,
  "device": "pc",
  "display": {"width": 3840, "height": 2160},
  "score": 3.87
}

summary.json

summary.json groups the results by input. It holds the run_info of the run and one entry per input:

{
  "schema_version": "0.1.6",
  "run_info": { "...": "..." },
  "inputs": [
    {
      "id": "0",
      "uri": "channel1.ts",
      "label": "channel1.ts",
      "stream_info": [ { "...": "..." } ],
      "alignments": [ { "...": "..." } ],
      "model_scores": [ { "model": "p1204.3", "scope": "overall", "...": "..." } ],
      "summaries": [ { "record_type": "frame_bitstream", "metric": "qp_avg", "...": "..." } ],
      "comparisons": [ { "...": "..." } ]
    }
  ]
}

The entries are the records of the NDJSON output, without their type and schema_version fields. model_scores holds only the overall scores; the scores per second and per GOP are only in records.ndjson and model_score.csv. comparisons are listed under the encode they belong to. Empty lists are left out.

summary.json is written at the end of the run. When you use the terminal view and compute additional metrics on demand, it is written when you close the view.

CSV files

The CSV files contain the same records as records.ndjson, one file per record type, for example frame_bitstream.csv or summary.csv. Nested fields are flattened into columns with dotted names (for example vmaf.score in frame_fullref.csv). run_info is not written to CSV. stream_info.csv has one row per stream.

JSON Schema

surfmeter-media schema prints the JSON Schema of all record types:

surfmeter-media schema > surfmeter-media-records.schema.json

Use it to validate the output, or to generate types for your own code, for example with quicktype or datamodel-code-generator for Python.

The schema_version field of each record tells you which version of the format it follows. New fields may be added in later versions; your code should ignore fields it does not know.

Records of on-demand jobs

When you compute additional metrics in the terminal view (see Basic Usage), their records are added to the output files with a job field (a job column in CSV). The final run_info lists these jobs under jobs.