Skip to content

Commit

Permalink
mpegts: fix compatibility with QuickTime
Browse files Browse the repository at this point in the history
(bluenviron/mediamtx#3206)

always add an AUD to H264 and H265 access units.
  • Loading branch information
aler9 committed May 25, 2024
1 parent 7cd408e commit 34133bc
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 25 deletions.
59 changes: 34 additions & 25 deletions pkg/formats/mpegts/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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},
Expand All @@ -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},
},
},
Expand Down Expand Up @@ -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},
Expand All @@ -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,
Expand All @@ -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,
},
},
},
Expand All @@ -157,6 +162,7 @@ var casesReadWriter = []struct {
30 * 90000,
30 * 90000,
[][]byte{
{byte(h264.NALUTypeAccessUnitDelimiter), 240}, // AUD
testH264SPS, // SPS
{8}, // PPS
{5}, // IDR
Expand All @@ -166,6 +172,7 @@ var casesReadWriter = []struct {
30*90000 + 2*90000,
30*90000 + 1*90000,
[][]byte{
{byte(h264.NALUTypeAccessUnitDelimiter), 240}, // AUD
{1}, // non-IDR
},
},
Expand Down Expand Up @@ -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},
Expand All @@ -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,
Expand All @@ -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,
},
},
},
Expand Down
47 changes: 47 additions & 0 deletions pkg/formats/mpegts/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -89,13 +90,59 @@ func NewWriter(
}

// WriteH26x writes a H26x access unit.
//
// Deprecated: replaced by WriteH264 and WriteH265.
func (w *Writer) WriteH26x(
track *Track,
pts int64,
dts int64,
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...)
}

Check warning on line 121 in pkg/formats/mpegts/writer.go

View check run for this annotation

Codecov / codecov/patch

pkg/formats/mpegts/writer.go#L118-L121

Added lines #L118 - L121 were not covered by tests

enc, err := h264.AnnexBMarshal(au)
if err != nil {
return err
}

Check warning on line 126 in pkg/formats/mpegts/writer.go

View check run for this annotation

Codecov / codecov/patch

pkg/formats/mpegts/writer.go#L125-L126

Added lines #L125 - L126 were not covered by tests

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...)
}

Check warning on line 144 in pkg/formats/mpegts/writer.go

View check run for this annotation

Codecov / codecov/patch

pkg/formats/mpegts/writer.go#L141-L144

Added lines #L141 - L144 were not covered by tests

enc, err := h264.AnnexBMarshal(au)
if err != nil {
return err
Expand Down

0 comments on commit 34133bc

Please sign in to comment.