Help us shape the future of Go! Take the 2026 Go Developer Survey

dashcheck

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2026 License: MIT Imports: 21 Imported by: 0

README

Test Coverage Status Go Reference license

dashcheck checks MPEG-DASH streams: the MPD, its segments, and for live streams the timing against a synchronized clock. The same Go code runs as a command-line tool and in the browser as WebAssembly.

Try it in the browser: https://tobbee.github.io/dashcheck/

It checks:

  • MPD syntax: well-formed XML and the MPEG-DASH 6th edition XML schema, with line and column for each error.
  • MPD rules: a growing set of semantic rules on the dash-mpd model, such as unique ids, SegmentTemplate consistency, SegmentTimeline gaps and overlaps, and UTCTiming.
  • Segments: init and media segments parsed with mp4ff, and cross-checked against the MPD: @codecs against the decoder configuration, size, sample rate, handler, earliest presentation time and duration against the MPD timeline, continuity between segments, and sync samples at segment start. -sequence-numbers adds a check of a convention that no spec requires: one mfhd sequence number per segment, shared by its chunks and increasing.
  • Live timing: the clock is synchronized to the MPD's UTCTiming source, as a player would do, and compared with a reference clock. The newest segments in the availability window must be available, the next one must not be available too early, and a SegmentTimeline must reach the live edge.
  • MPD updates: a live MPD is fetched again after about one segment (-updates N sets how many times) and compared with the version before: @publishTime, ids, Representation attributes and the timing of segments that both versions describe, plus the DVB-DASH update constraints.
  • Profiles: DASH-IF IOP, CMAF, low latency, DVB-DASH 2014 and 2017, HbbTV and CTA WAVE, selected by the MPD's @profiles. -profiles chooses them instead: -profiles auto,dvb adds DVB-DASH to the profiles the MPD signals, and -profiles dvb,hbbtv checks only DVB-DASH and HbbTV, as if MPD@profiles listed them. The DASH-HLS interoperability rules of CTA-5005, which MPDs do not signal, are added with -hls-interop.

All findings carry a stable rule ID; dashcheck -rules lists them, and docs/rules.md documents them with the DASH-IF checks that each covers, marking the rules that the DASH-IF Conformance tool does not have.

Command line

go install github.com/tobbee/dashcheck/cmd/dashcheck@latest
dashcheck https://livesim2.dashif.org/livesim2/segtimeline_1/testpic_2s/Manifest.mpd
dashcheck -n 10 -level warning path/to/local/Manifest.mpd
dashcheck -json https://example.com/stream.mpd
dashcheck -profiles auto,hbbtv https://example.com/stream.mpd
dashcheck -short streams/*.mpd
dashcheck -short -json $(cat urls.txt) > results.json

The exit code is 1 if any error was found, which makes it usable in CI.

-short prints one line per MPD instead of the report, and takes several MPDs, which it checks -parallel at a time. -level adds the findings below each line.

$ dashcheck -short testdata/*.mpd testdata/*/*.mpd
FAIL  testdata/malformed.mpd  (3 errors, 0 warnings, 0 info)
OK    testdata/testpic_2s/Manifest.mpd  (0 errors, 0 warnings, 0 info)

2 MPDs: 1 with errors, 0 with warnings, 1 OK

With -json, -short writes an array of reports, each with its counts. dashcheck -version prints the version, which Go takes from the git tag and commit at build time.

Browser

The latest release runs at https://tobbee.github.io/dashcheck/. To run the browser tool locally:

make serve   # builds web/dashcheck.wasm and serves web/ on http://localhost:8080 (localhost only)

The page runs the checker in a Web Worker. It can check a URL, or a local folder with packager output, which is read in the browser and never uploaded. A URL can be passed as ?url=... to share a check. The latest 20 checks are kept with their results in the browser's localStorage, to show them again or to check a URL again with the same options.

Browser limits: the stream must send CORS headers (almost all DASH CDNs do, since players need them), and an https page cannot fetch http:// URLs. Use the command-line tool for such streams.

Each release is published on GitHub Pages by .github/workflows/pages.yml (it can also be run by hand). The published page counts visits and checks with GoatCounter, without cookies: it sends the page path and title, the screen width, the referrer without its query string, and for a check whether it was a URL or a folder, never an MPD URL.

Design

cmd/dashcheck        CLI (net/http, local files)
cmd/dashcheck-wasm   wasm entry point for the browser
web/                 static page and Web Worker
dashcheck            runner: fetch MPD, check it, sync clock, check segments
mpdcheck             MPD rules (schema/ for XSD validation)
addressing           MPD to segment lists, availability times
segcheck             init and media segment checks with mp4ff
clock                UTCTiming measurement and synchronized clock
fetch                Fetcher interface: native and browser fetch
report               rules, findings, report
spec                 profiles to check, chosen or from @profiles

No check does I/O or reads the clock directly. Everything goes through fetch.Fetcher and clock.Clock, so the checks are identical in all hosts and can be tested with fixed clocks and test servers.

XSD validation uses jacoelho/xsd, a pure Go validator. The schema files in schema/xsd come from MPEGGroup/DASHSchema, with the internal DTD entities expanded. One type is changed: ContentSteering@defaultServiceLocation is a space-separated list, as in Table K.6 of ISO/IEC 23009-1:2026 and in ETSI TS 103 998, not the single token of the schema. The schema maintainers agreed in MPEGGroup/DASHSchema#171 that it is a list, but DASHSchema has not been changed yet.

Status and next steps

This is an early version. docs/dashif-coverage.md lists all 408 checks of the DASH-IF Conformance tool and which dashcheck rules cover them. It is generated from docs/dashif-checks.json; after changing that file, run go test ./internal/coverage -update, which also regenerates docs/rules.md. To refresh the list from a newer version of the DASH-IF tool, run tools/dashif-inventory.py <clone> docs/dashif-checks.json. Bugs found in the DASH-IF tool while porting its checks are listed in docs/dashif-upstream-bugs.md, ready to be reported.

Planned next steps:

  • Port the remaining DASH-IF checks (DVB AVS3, which needs AVS3 support in mp4ff).
  • Bandwidth checks.
  • Chunk arrival timing for low-latency streams.
  • A long-running monitor mode.

Development

make             # golangci-lint, build, wasm and tests
make coverage    # coverage.html and coverage.txt
make codespell
make pre-commit-install   # gofmt, golangci-lint and tests before each commit

Changes are listed in CHANGELOG.md.

License

MIT, see LICENSE. The XSD files in schema/xsd come from MPEGGroup/DASHSchema under its own license.

The gopher in the logo and favicon is adapted from the Go gopher, created by Renée French and licensed under CC BY 4.0.

Documentation

Overview

Package dashcheck checks MPEG-DASH streams: the MPD, its segments, and for dynamic MPDs the timing against a synchronized wall clock.

All network access goes through a fetch.Fetcher and all time through a clock.Clock, so the same code runs natively and in the browser (wasm).

Index

Constants

View Source
const (
	DefaultMaxSegments = 4
	DefaultConcurrency = 4
	DefaultLiveMargin  = time.Second
	DefaultMPDUpdates  = 1
)

Variables

View Source
var (
	RuleHTTPMPD = report.Register(report.Rule{
		ID: "HTTP-MPD", Severity: report.Error,
		Desc: "The MPD must be fetchable",
	})
	RuleHTTPInit = report.Register(report.Rule{
		ID: "HTTP-INIT", Severity: report.Error,
		Desc: "The initialization segment must be fetchable",
	})
	RuleHTTPSegment = report.Register(report.Rule{
		ID: "HTTP-SEGMENT", Severity: report.Error,
		Desc: "Media segments must be fetchable while they are in the availability window",
	})
	RuleHTTPRange = report.Register(report.Rule{
		ID: "HTTP-RANGE", Severity: report.Warning,
		Desc:    "HTTP servers should answer byte range requests with the requested range",
		SpecRef: "DASH-IF IOP v4.3 3.4.2",
	})
	RuleHTTPIOPRange = report.Register(report.Rule{
		ID: "HTTP-IOP-RANGE", Severity: report.Error,
		Desc:    "HTTP servers must answer byte range requests for IOP on-demand Representations with the requested range",
		SpecRef: "DASH-IF IOP v4.3 3.4.2",
	})
	RuleUnsupported = report.Register(report.Rule{
		ID: "SEG-UNSUPPORTED", Severity: report.Info,
		Desc: "Segments in formats other than ISOBMFF are not checked",
	})
	RuleSegmentSequences = report.Register(report.Rule{
		ID: "ADDR-UNSUPPORTED", Severity: report.Info,
		Desc: "SegmentTimeline duration patterns (S@p, S@ssp) and URL parameters (Annex I) are not supported yet, so their segments are not checked",
	})
	RuleSegmentList = report.Register(report.Rule{
		ID: "ADDR-SEGMENTS", Severity: report.Error,
		Desc: "The segment list of a Representation must be derivable",
	})
)
View Source
var (
	RuleNotStarted = report.Register(report.Rule{
		ID: "LIVE-NOT-STARTED", Severity: report.Warning,
		Desc: "The presentation has not started yet, so no segments can be checked",
	})
	RulePublishFuture = report.Register(report.Rule{
		ID: "LIVE-PUBLISHTIME", Severity: report.Warning,
		Desc: "MPD@publishTime should not be in the future",
	})
	RuleNoSegments = report.Register(report.Rule{
		ID: "LIVE-NO-SEGMENTS", Severity: report.Error,
		Desc:    "A live Representation must have segments in the availability window",
		SpecRef: refTimingModel + " 13.3",
	})
	RuleStaleTimeline = report.Register(report.Rule{
		ID: "LIVE-STALE", Severity: report.Error,
		Desc:    "The MPD must describe segments up to the live edge",
		SpecRef: refTimingModel + " 9.2.2",
	})
	RuleEarly = report.Register(report.Rule{
		ID: "LIVE-EARLY", Severity: report.Warning,
		Desc:    "Segments should not be available before their availability start time",
		SpecRef: refTimingModel + " 13.3",
	})
)

Functions

func Check

func Check(ctx context.Context, mpdURL string, opts Options) *report.Report

Check fetches and checks the MPD at mpdURL and its segments.

func CheckData

func CheckData(ctx context.Context, data []byte, mpdURL string, opts Options) *report.Report

CheckData checks an MPD given as data, e.g. a local file opened in a browser. Segments are fetched relative to mpdURL.

Types

type Options

type Options struct {
	Fetcher fetch.Fetcher
	// Clock overrides clock synchronization. If nil, dynamic MPDs use a clock
	// synced to their UTCTiming sources, and static MPDs the local clock.
	Clock clock.Clock
	// Reference is the reference clock URL (http-iso). Empty means
	// clock.DefaultReference; "none" disables it.
	Reference string
	// MaxSegments is the number of media segments checked per Representation.
	// Zero means DefaultMaxSegments; negative means all (static MPDs only).
	MaxSegments int
	// Concurrency is the number of Representations checked in parallel.
	Concurrency int
	// LiveMargin keeps live checks away from the edges of the availability
	// window, to allow for clock inaccuracy. Zero means DefaultLiveMargin.
	LiveMargin time.Duration
	// MPDUpdates is the number of times a dynamic MPD is fetched again to
	// check its updates. Zero means DefaultMPDUpdates; negative disables it.
	MPDUpdates int
	// Profiles chooses the profiles whose rules apply. The zero value is the
	// profiles that the MPD signals in @profiles.
	Profiles spec.Selection
	// HLSInterop adds the checks of the DASH-HLS Interoperability
	// Specification CTA-5005-B, which MPDs do not signal.
	HLSInterop bool
	// SequenceNumbers adds the check of a sequence number convention: one
	// mfhd sequence_number per segment, increasing (SEG-SEQUENCE-NUMBER).
	SequenceNumbers bool
	// UpdateInterval is the time between MPD fetches. Zero means about one
	// segment duration, between 2 and 10 seconds.
	UpdateInterval time.Duration
	// Progress, if set, receives progress updates. It may be called from several goroutines.
	Progress func(Progress)
}

Options control a check.

type Progress

type Progress struct {
	Phase   string `json:"phase"`
	Done    int    `json:"done"`
	Total   int    `json:"total"`
	Message string `json:"message,omitempty"`
}

Progress describes how far a check has come.

Directories

Path Synopsis
Package addressing turns an MPD into a list of Representations with their segment addresses and times.
Package addressing turns an MPD into a list of Representations with their segment addresses and times.
Package clock provides a wall clock synchronized to the UTCTiming sources signaled in an MPD, the reference that players use.
Package clock provides a wall clock synchronized to the UTCTiming sources signaled in an MPD, the reference that players use.
cmd
dashcheck command
Command dashcheck checks an MPEG-DASH stream: the MPD, its segments and, for live streams, the timing against a synchronized clock.
Command dashcheck checks an MPEG-DASH stream: the MPD, its segments and, for live streams, the timing against a synchronized clock.
dashcheck-wasm command
Command dashcheck-wasm exposes dashcheck to JavaScript.
Command dashcheck-wasm exposes dashcheck to JavaScript.
Package fetch abstracts HTTP access so that the checks run unchanged natively (net/http, local files) and in the browser (fetch API via wasm).
Package fetch abstracts HTTP access so that the checks run unchanged natively (net/http, local files) and in the browser (fetch API via wasm).
coverage
Package coverage tracks which checks of the DASH-IF Conformance tool have been ported to dashcheck.
Package coverage tracks which checks of the DASH-IF Conformance tool have been ported to dashcheck.
Package mpdcheck validates an MPD: XML well-formedness and schema, followed by semantic rules on the typed MPD model from dash-mpd.
Package mpdcheck validates an MPD: XML well-formedness and schema, followed by semantic rules on the typed MPD model from dash-mpd.
Package report defines the findings produced by all checks.
Package report defines the findings produced by all checks.
Package schema validates MPDs against the MPEG-DASH XML schema.
Package schema validates MPDs against the MPEG-DASH XML schema.
Package segcheck checks initialization and media segments with mp4ff, and cross-checks them against the MPD.
Package segcheck checks initialization and media segments with mp4ff, and cross-checks them against the MPD.
Package spec lists the profiles that turn on profile-specific rules, and lets the user choose which of them an MPD is checked against.
Package spec lists the profiles that turn on profile-specific rules, and lets the user choose which of them an MPD is checked against.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL