AlexxIT/go2rtc · error

bitstream: unsupported header:

Error message

bitstream: unsupported header: 

What it means

bitstream.Open is given a raw Annex-B H.264/H.265 elementary stream. After the magic.Open sniffing dispatches on the annexb start code, bitstream peeks 256 bytes and requires the first NAL unit to be an H.264 SPS or an H.265 VPS so it can build codec parameters. If the first NAL is anything else (an IDR/non-IDR slice, AUD, SEI, etc.), it cannot determine the codec and throws this error with the first 8 bytes hex-encoded.

Solutions

  1. Ensure the bitstream begins with the parameter sets: prepend the SPS/PPS (H.264) or VPS/SPS/PPS (H.265) NAL units in Annex-B format before the first slice.
  2. Re-encode or remux the source with parameter sets inline, e.g. `ffmpeg -i in -c copy -bsf:v h264_mp4toannexb out.h264`, which inserts SPS/PPS at each keyframe.
  3. Check that the producer that created the stream was started before the camera/encoder began, so the first bytes captured are the parameter sets rather than a mid-stream slice.
  4. Verify the input is actually H.264/H.265 Annex-B; if it is MP4-format (AVCC, length-prefixed) or another container, use the matching package instead of the bitstream one.

Example fix

// before: feeding a dump that starts with an IDR slice
f, _ := os.Open("gop-dump.h264")
p, err := magic.Open(f) // error: bitstream: unsupported header: 410102...

// after: prepend SPS/PPS captured at stream start
f, _ := os.Open("gop-dump.h264")
r := io.MultiReader(bytes.NewReader(spsppsAnnexB), f)
p, err := magic.Open(r)
Defensive patterns

Strategy: validation

Validate before calling

func isAnnexBParameterStream(data []byte) bool {
	// after start code (00 00 00 01), first NAL must be SPS(7) or VPS(32)
	if !bytes.HasPrefix(data, []byte{0, 0, 0, 1}) {
		return false
	}
	n := data[4] & 0x7E // nal type = (b>>1)&0x3F
	nalType := (data[4] >> 1) & 0x3F
	return nalType == 7 || nalType == 32
}
// call before magic.Open: if !ok, prepend/prepend SPS/PPS or transcode first

Try / catch

p, err := magic.Open(rd)
if err != nil && strings.Contains(err.Error(), "bitstream: unsupported header") {
	// re-open after prepending parameter sets or transcoding
	p, err = magic.Open(io.MultiReader(bytes.NewReader(spsPpsAnnexB), original))
}

Prevention

When it happens

Trigger: Calling magic.Open (or bitstream.Open directly) on a stream whose Annex-B start code is followed by a NAL unit that is not SPS (H.264 type 7) or VPS (H.265 type 32) — e.g. the capture started mid-GOP on an IDR slice, the stream begins with AUD/SEI NALs, or non-Annex-B data was fed in and only coincidentally matched the start code.

Common situations: Dumping an RTP/RTSP track to file and feeding the dump back for consumption; ffmpeg piped output missing SPS because the encoder emits it only periodically; reading a truncated file whose SPS was cut off; piping H.265 streams whose first NAL is VPS in a different order than expected.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/bc170c377f9f7017. Report an issue: GitHub.

Appendix: source

Thrown at pkg/magic/bitstream/producer.go:41

	buf, err := rd.Peek(256)
	if err != nil {
		return nil, err
	}

	buf = annexb.EncodeToAVCC(buf) // won't break original buffer

	var codec *core.Codec
	var format string

	switch {
	case h264.NALUType(buf) == h264.NALUTypeSPS:
		codec = h264.AVCCToCodec(buf)
		format = "h264"
	case h265.NALUType(buf) == h265.NALUTypeVPS:
		codec = h265.AVCCToCodec(buf)
		format = "hevc"
	default:
		return nil, errors.New("bitstream: unsupported header: " + hex.EncodeToString(buf[:8]))
	}

	medias := []*core.Media{
		{
			Kind:      core.KindVideo,
			Direction: core.DirectionRecvonly,
			Codecs:    []*core.Codec{codec},
		},
	}
	return &Producer{
		Connection: core.Connection{
			ID:         core.NewID(),
			FormatName: format,
			Medias:     medias,
			Transport:  r,
		},
		rd: rd,
	}, nil

View on GitHub (pinned to c245815e75)