AlexxIT/go2rtc · error

unsupported iso video

Error message

unsupported iso video: ${codec}

What it means

WriteVideo in the ISO BMFF (MP4) muxer panics when asked to write a video sample entry for a codec it does not support. Only H264 (avc1) and H265 (hev1) sample entries are implemented; any other core.Codec value hits the default branch and panics.

Solutions

  1. Transcode or repack the stream to H264/H265 before feeding WriteVideo.
  2. Add a pre-call guard that checks the codec and rejects unsupported values gracefully instead of reaching the panic.
  3. If the codec should be supported, extend the switch in pkg/iso/codecs.go with the appropriate sample entry atom.
  4. Recover from the panic at a muxer boundary and convert it to a returned error.

Example fix

// before
m.WriteVideo(trackID, core.CodecVP9, ...) // panics: unsupported iso video: VP9
// after
switch codec {
case core.CodecH264, core.CodecH265:
    m.WriteVideo(trackID, codec, ...)
default:
    return fmt.Errorf("mp4 muxer supports only H264/H265 video, got %s", codec)
}
Defensive patterns

Strategy: validation

Validate before calling

var supportedVideo = map[core.Codec]bool{core.CodecH264: true, core.CodecH265: true}
if !supportedVideo[codec] {
    return fmt.Errorf("unsupported iso video codec: %s", codec)
}
m.WriteVideo(trackID, codec, w, timescale)

Type guard

func isSupportedISOVideo(c core.Codec) bool {
    return c == core.CodecH264 || c == core.CodecH265
}

Try / catch

// Go: convert panic to error at the muxer boundary
func safeWriteVideo(m *iso.Muxer, args...) (err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("iso muxer panic: %v", r)
        }
    }()
    m.WriteVideo(args...)
    return nil
}

Prevention

When it happens

Trigger: Calling WriteVideo with a codec argument other than core.CodecH264 or core.CodecH265 (e.g. H263, MJPEG, VP9) while building an MP4/ISOBMFF track.

Common situations: Feeding a camera stream that publishes a non-H264/H265 codec into the MP4 muxer; upstream remuxing logic that passes the source codec through unvalidated; adding a new codec to core without extending pkg/iso.

Related errors


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

Appendix: source

Thrown at pkg/iso/codecs.go:16

package iso

import (
	"github.com/AlexxIT/go2rtc/pkg/core"
	"github.com/AlexxIT/go2rtc/pkg/pcm"
)

func (m *Movie) WriteVideo(codec string, width, height uint16, conf []byte) {
	// https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
	switch codec {
	case core.CodecH264:
		m.StartAtom("avc1")
	case core.CodecH265:
		m.StartAtom("hev1")
	default:
		panic("unsupported iso video: " + codec)
	}
	m.Skip(6)
	m.WriteUint16(1)      // data_reference_index
	m.Skip(2)             // version
	m.Skip(2)             // revision
	m.Skip(4)             // vendor
	m.Skip(4)             // temporal quality
	m.Skip(4)             // spatial quality
	m.WriteUint16(width)  // width
	m.WriteUint16(height) // height
	m.WriteFloat32(72)    // horizontal resolution
	m.WriteFloat32(72)    // vertical resolution
	m.Skip(4)             // reserved
	m.WriteUint16(1)      // frame count
	m.Skip(32)            // compressor name
	m.WriteUint16(24)     // depth
	m.WriteUint16(0xFFFF) // color table id (-1)

View on GitHub (pinned to c245815e75)