diff --git a/pkg/formats/mpegts/reader_test.go b/pkg/formats/mpegts/reader_test.go index 373be37..936679d 100644 --- a/pkg/formats/mpegts/reader_test.go +++ b/pkg/formats/mpegts/reader_test.go @@ -10,6 +10,7 @@ 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" ) @@ -59,6 +60,7 @@ 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}, @@ -68,6 +70,7 @@ 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}, }, }, @@ -99,8 +102,8 @@ var casesReadWriter = []struct { }, { // PES AdaptationField: &astits.PacketAdaptationField{ - Length: 88, - StuffingLength: 81, + Length: 81, + StuffingLength: 74, RandomAccessIndicator: true, HasPCR: true, PCR: &astits.ClockReference{Base: 2691000}, @@ -114,22 +117,23 @@ var casesReadWriter = []struct { Payload: []byte{ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x80, 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0x00, 0x00, - 0x00, 0x01, 0x42, 0x01, 0x01, 0x02, 0x20, 0x00, - 0x00, 0x03, 0x00, 0xb0, 0x00, 0x00, 0x03, 0x00, - 0x00, 0x03, 0x00, 0x7b, 0xa0, 0x07, 0x82, 0x00, - 0x88, 0x7d, 0xb6, 0x71, 0x8b, 0x92, 0x44, 0x80, - 0x53, 0x88, 0x88, 0x92, 0xcf, 0x24, 0xa6, 0x92, - 0x72, 0xc9, 0x12, 0x49, 0x22, 0xdc, 0x91, 0xaa, - 0x48, 0xfc, 0xa2, 0x23, 0xff, 0x00, 0x01, 0x00, - 0x01, 0x6a, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x44, 0x01, 0xc0, 0x25, 0x2f, 0x05, - 0x32, 0x40, 0x00, 0x00, 0x00, 0x01, 0x2a, + 0x00, 0x01, 0x46, 0x01, 0x50, 0x00, 0x00, 0x00, + 0x01, 0x42, 0x01, 0x01, 0x02, 0x20, 0x00, 0x00, + 0x03, 0x00, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x03, 0x00, 0x7b, 0xa0, 0x07, 0x82, 0x00, 0x88, + 0x7d, 0xb6, 0x71, 0x8b, 0x92, 0x44, 0x80, 0x53, + 0x88, 0x88, 0x92, 0xcf, 0x24, 0xa6, 0x92, 0x72, + 0xc9, 0x12, 0x49, 0x22, 0xdc, 0x91, 0xaa, 0x48, + 0xfc, 0xa2, 0x23, 0xff, 0x00, 0x01, 0x00, 0x01, + 0x6a, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x44, 0x01, 0xc0, 0x25, 0x2f, 0x05, 0x32, + 0x40, 0x00, 0x00, 0x00, 0x01, 0x2a, }, }, { // PES AdaptationField: &astits.PacketAdaptationField{ - Length: 159, - StuffingLength: 158, + Length: 152, + StuffingLength: 151, }, Header: astits.PacketHeader{ ContinuityCounter: 1, @@ -141,7 +145,8 @@ var casesReadWriter = []struct { Payload: []byte{ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0xc0, 0x0a, 0x31, 0x00, 0xaf, 0xe4, 0x01, 0x11, 0x00, - 0xab, 0x24, 0xe1, 0x00, 0x00, 0x00, 0x01, 0x00, + 0xab, 0x24, 0xe1, 0x00, 0x00, 0x00, 0x01, 0x46, + 0x01, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, }, }, }, @@ -157,6 +162,7 @@ var casesReadWriter = []struct { 30 * 90000, 30 * 90000, [][]byte{ + {byte(h264.NALUTypeAccessUnitDelimiter), 240}, // AUD testH264SPS, // SPS {8}, // PPS {5}, // IDR @@ -166,6 +172,7 @@ var casesReadWriter = []struct { 30*90000 + 2*90000, 30*90000 + 1*90000, [][]byte{ + {byte(h264.NALUTypeAccessUnitDelimiter), 240}, // AUD {1}, // non-IDR }, }, @@ -197,8 +204,8 @@ var casesReadWriter = []struct { }, { // PES AdaptationField: &astits.PacketAdaptationField{ - Length: 130, - StuffingLength: 123, + Length: 124, + StuffingLength: 117, RandomAccessIndicator: true, HasPCR: true, PCR: &astits.ClockReference{Base: 2691000}, @@ -212,17 +219,18 @@ var casesReadWriter = []struct { Payload: []byte{ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x80, 0x05, 0x21, 0x00, 0xa5, 0x65, 0xc1, 0x00, 0x00, - 0x00, 0x01, 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, - 0x78, 0x02, 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, - 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, - 0x60, 0xc9, 0x20, 0x00, 0x00, 0x00, 0x01, 0x08, - 0x00, 0x00, 0x00, 0x01, 0x05, + 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, + 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, + 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, + 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, + 0x20, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, + 0x00, 0x01, 0x05, }, }, { // PES AdaptationField: &astits.PacketAdaptationField{ - Length: 159, - StuffingLength: 158, + Length: 153, + StuffingLength: 152, }, Header: astits.PacketHeader{ ContinuityCounter: 1, @@ -234,7 +242,8 @@ var casesReadWriter = []struct { Payload: []byte{ 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0xc0, 0x0a, 0x31, 0x00, 0xaf, 0xe4, 0x01, 0x11, 0x00, - 0xab, 0x24, 0xe1, 0x00, 0x00, 0x00, 0x01, 0x01, + 0xab, 0x24, 0xe1, 0x00, 0x00, 0x00, 0x01, 0x09, + 0xf0, 0x00, 0x00, 0x00, 0x01, 0x01, }, }, }, diff --git a/pkg/formats/mpegts/writer.go b/pkg/formats/mpegts/writer.go index 7e4a0d9..41db8ed 100644 --- a/pkg/formats/mpegts/writer.go +++ b/pkg/formats/mpegts/writer.go @@ -9,6 +9,7 @@ import ( "github.com/asticode/go-astits" "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" "github.com/bluenviron/mediacommon/pkg/codecs/mpeg4video" @@ -89,6 +90,8 @@ func NewWriter( } // WriteH26x writes a H26x access unit. +// +// Deprecated: replaced by WriteH264 and WriteH265. func (w *Writer) WriteH26x( track *Track, pts int64, @@ -96,6 +99,50 @@ func (w *Writer) WriteH26x( randomAccess bool, au [][]byte, ) error { + if _, ok := track.Codec.(*CodecH265); ok { + return w.WriteH265(track, pts, dts, randomAccess, au) + } + return w.WriteH264(track, pts, dts, randomAccess, au) +} + +// WriteH264 writes a H264 access unit. +func (w *Writer) WriteH264( + track *Track, + pts int64, + dts int64, + randomAccess bool, + au [][]byte, +) error { + // prepend an AUD. This is required by video.js, iOS, QuickTime + if h264.NALUType(au[0][0]&0x1F) != h264.NALUTypeAccessUnitDelimiter { + au = append([][]byte{ + {byte(h264.NALUTypeAccessUnitDelimiter), 240}, + }, au...) + } + + enc, err := h264.AnnexBMarshal(au) + if err != nil { + return err + } + + return w.writeVideo(track, pts, dts, randomAccess, enc) +} + +// WriteH265 writes a H265 access unit. +func (w *Writer) WriteH265( + track *Track, + pts int64, + dts int64, + randomAccess bool, + 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 { + au = append([][]byte{ + {byte(h265.NALUType_AUD_NUT) << 1, 1, 0x50}, + }, au...) + } + enc, err := h264.AnnexBMarshal(au) if err != nil { return err