diff --git a/pkg/formats/mpegts/reader.go b/pkg/formats/mpegts/reader.go index 4b5e836..2c70a21 100644 --- a/pkg/formats/mpegts/reader.go +++ b/pkg/formats/mpegts/reader.go @@ -11,6 +11,7 @@ import ( "github.com/bluenviron/mediacommon/pkg/codecs/ac3" "github.com/bluenviron/mediacommon/pkg/codecs/h264" + "github.com/bluenviron/mediacommon/pkg/codecs/h265" "github.com/bluenviron/mediacommon/pkg/codecs/mpeg1audio" "github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio" ) @@ -114,8 +115,36 @@ func (r *Reader) OnDecodeError(cb ReaderOnDecodeErrorFunc) { r.onDecodeError = cb } -// OnDataH26x sets a callback that is called when data from an H26x track is received. +// OnDataH26x sets a callback that is called when data from an H265 or H264 track is received. +// +// Deprecated: replaced by OnDataH264, OnDataH265 func (r *Reader) OnDataH26x(track *Track, cb ReaderOnDataH26xFunc) { + if _, ok := track.Codec.(*CodecH265); ok { + r.OnDataH265(track, cb) + } else { + r.OnDataH264(track, cb) + } +} + +// OnDataH265 sets a callback that is called when data from an H265 track is received. +func (r *Reader) OnDataH265(track *Track, cb ReaderOnDataH26xFunc) { + r.onData[track.PID] = func(pts int64, dts int64, data []byte) error { + au, err := h264.AnnexBUnmarshal(data) + if err != nil { + r.onDecodeError(err) + return nil + } + + if au[0][0] == byte(h265.NALUType_AUD_NUT<<1) { + au = au[1:] + } + + return cb(pts, dts, au) + } +} + +// OnDataH264 sets a callback that is called when data from an H264 track is received. +func (r *Reader) OnDataH264(track *Track, cb ReaderOnDataH26xFunc) { r.onData[track.PID] = func(pts int64, dts int64, data []byte) error { au, err := h264.AnnexBUnmarshal(data) if err != nil { @@ -123,6 +152,10 @@ func (r *Reader) OnDataH26x(track *Track, cb ReaderOnDataH26xFunc) { return nil } + if au[0][0] == byte(h264.NALUTypeAccessUnitDelimiter) { + au = au[1:] + } + return cb(pts, dts, au) } } diff --git a/pkg/formats/mpegts/reader_test.go b/pkg/formats/mpegts/reader_test.go index 936679d..e6f63b8 100644 --- a/pkg/formats/mpegts/reader_test.go +++ b/pkg/formats/mpegts/reader_test.go @@ -10,7 +10,6 @@ import ( "github.com/asticode/go-astits" "github.com/stretchr/testify/require" - "github.com/bluenviron/mediacommon/pkg/codecs/h264" "github.com/bluenviron/mediacommon/pkg/codecs/h265" "github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio" ) @@ -60,7 +59,6 @@ var casesReadWriter = []struct { 30 * 90000, 30 * 90000, [][]byte{ - {byte(h265.NALUType_AUD_NUT) << 1, 1, 0x50}, // AUD testH265SPS, // SPS testH265PPS, // PPS {byte(h265.NALUType_CRA_NUT) << 1}, @@ -70,7 +68,6 @@ var casesReadWriter = []struct { 30*90000 + 2*90000, 30*90000 + 1*90000, [][]byte{ - {byte(h265.NALUType_AUD_NUT) << 1, 1, 0x50}, // AUD {byte(h265.NALUType_TRAIL_N) << 1}, }, }, @@ -162,7 +159,6 @@ var casesReadWriter = []struct { 30 * 90000, 30 * 90000, [][]byte{ - {byte(h264.NALUTypeAccessUnitDelimiter), 240}, // AUD testH264SPS, // SPS {8}, // PPS {5}, // IDR @@ -172,7 +168,6 @@ var casesReadWriter = []struct { 30*90000 + 2*90000, 30*90000 + 1*90000, [][]byte{ - {byte(h264.NALUTypeAccessUnitDelimiter), 240}, // AUD {1}, // non-IDR }, }, @@ -879,8 +874,17 @@ func TestReader(t *testing.T) { i := 0 switch ca.track.Codec.(type) { - case *CodecH265, *CodecH264: - r.OnDataH26x(ca.track, func(pts int64, dts int64, au [][]byte) error { + case *CodecH265: + r.OnDataH265(ca.track, func(pts int64, dts int64, au [][]byte) error { + require.Equal(t, ca.samples[i].pts, pts) + require.Equal(t, ca.samples[i].dts, dts) + require.Equal(t, ca.samples[i].data, au) + i++ + return nil + }) + + case *CodecH264: + r.OnDataH264(ca.track, func(pts int64, dts int64, au [][]byte) error { require.Equal(t, ca.samples[i].pts, pts) require.Equal(t, ca.samples[i].dts, dts) require.Equal(t, ca.samples[i].data, au) @@ -1243,7 +1247,7 @@ func TestReaderDecodeErrors(t *testing.T) { switch ca { case "missing pts", "h26x invalid avcc": - r.OnDataH26x(r.Tracks()[0], func(_, _ int64, _ [][]byte) error { + r.OnDataH264(r.Tracks()[0], func(_, _ int64, _ [][]byte) error { return nil }) @@ -1269,7 +1273,7 @@ func TestReaderDecodeErrors(t *testing.T) { case "garbage": counter := 0 - r.OnDataH26x(r.Tracks()[0], func(_, _ int64, _ [][]byte) error { + r.OnDataH264(r.Tracks()[0], func(_, _ int64, _ [][]byte) error { counter++ if counter == 2 { dataRecv = true diff --git a/pkg/formats/mpegts/writer.go b/pkg/formats/mpegts/writer.go index 41db8ed..466dc22 100644 --- a/pkg/formats/mpegts/writer.go +++ b/pkg/formats/mpegts/writer.go @@ -105,8 +105,8 @@ func (w *Writer) WriteH26x( return w.WriteH264(track, pts, dts, randomAccess, au) } -// WriteH264 writes a H264 access unit. -func (w *Writer) WriteH264( +// WriteH265 writes a H265 access unit. +func (w *Writer) WriteH265( track *Track, pts int64, dts int64, @@ -114,9 +114,9 @@ func (w *Writer) WriteH264( au [][]byte, ) error { // prepend an AUD. This is required by video.js, iOS, QuickTime - if h264.NALUType(au[0][0]&0x1F) != h264.NALUTypeAccessUnitDelimiter { + if au[0][0] != byte(h265.NALUType_AUD_NUT<<1) { au = append([][]byte{ - {byte(h264.NALUTypeAccessUnitDelimiter), 240}, + {byte(h265.NALUType_AUD_NUT) << 1, 1, 0x50}, }, au...) } @@ -128,8 +128,8 @@ func (w *Writer) WriteH264( return w.writeVideo(track, pts, dts, randomAccess, enc) } -// WriteH265 writes a H265 access unit. -func (w *Writer) WriteH265( +// WriteH264 writes a H264 access unit. +func (w *Writer) WriteH264( track *Track, pts int64, dts int64, @@ -137,9 +137,9 @@ func (w *Writer) WriteH265( au [][]byte, ) error { // prepend an AUD. This is required by video.js, iOS, QuickTime - if h265.NALUType(au[0][0]>>1) != h265.NALUType_AUD_NUT { + if au[0][0] != byte(h264.NALUTypeAccessUnitDelimiter) { au = append([][]byte{ - {byte(h265.NALUType_AUD_NUT) << 1, 1, 0x50}, + {byte(h264.NALUTypeAccessUnitDelimiter), 240}, }, au...) }