diff --git a/av/codec/h264/sps_test.go b/av/codec/h264/sps_test.go index 1b8fdaa..f6e01ea 100644 --- a/av/codec/h264/sps_test.go +++ b/av/codec/h264/sps_test.go @@ -41,6 +41,14 @@ func TestRawSPS_Parse(t *testing.T) { float64(60000) / float64(1001*2), false, }, + { + "tpl500", + "AAAAAWdkAB6s0gLASaEAAAMAAQAAAwAehA==", + 704, + 576, + 15, + false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/av/codec/hevc/sps_test.go b/av/codec/hevc/sps_test.go index f0e4019..0a57b07 100644 --- a/av/codec/hevc/sps_test.go +++ b/av/codec/hevc/sps_test.go @@ -33,6 +33,14 @@ func TestH265RawSPS_DecodeString(t *testing.T) { 30, false, }, + { + "tpl500-265", + "AAAAAUIBAQFgAAADAAADAAADAAADAJagAWggBln3ja5JMmuWMAgAAAMACAAAAwB4QA==", + 2880, + 1620, + 15, + false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/av/codec/hevc/vps_test.go b/av/codec/hevc/vps_test.go index 802fbf7..a699fc5 100644 --- a/av/codec/hevc/vps_test.go +++ b/av/codec/hevc/vps_test.go @@ -24,6 +24,11 @@ func TestH265RawVPS_DecodeString(t *testing.T) { "QAEMAf//AWAAAAMAkAAAAwAAAwBdlZgJ", false, }, + { + "tpl500-265", + "AAAAAUABDAH//wFgAAADAAADAAADAAADAJasCQ==", + false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/av/format/sdp/parsemeta.go b/av/format/sdp/parsemeta.go index fce74ff..f2e63f9 100644 --- a/av/format/sdp/parsemeta.go +++ b/av/format/sdp/parsemeta.go @@ -13,6 +13,7 @@ import ( "github.com/cnotch/ipchub/av/codec/aac" "github.com/cnotch/ipchub/av/codec/h264" "github.com/cnotch/ipchub/av/codec/hevc" + "github.com/cnotch/ipchub/utils" "github.com/cnotch/ipchub/utils/scan" "github.com/pixelbender/go-sdp/sdp" ) @@ -147,13 +148,13 @@ func parseH264SpsPps(s string, video *codec.VideoMeta) { sps, err := base64.StdEncoding.DecodeString(spsStr) if err == nil { // video.SetParameterSet(h264.ParameterSetSps, sps) - video.Sps = sps + video.Sps = utils.RemoveNaluSeparator(sps) } pps, err := base64.StdEncoding.DecodeString(ppsStr) if err == nil { // video.SetParameterSet(h264.ParameterSetPps, pps) - video.Pps = pps + video.Pps = utils.RemoveNaluSeparator(pps) } _ = h264.MetadataIsReady(video) @@ -167,22 +168,20 @@ func parseH265VpsSpsPps(s string, video *codec.VideoMeta) { advance, token, continueScan = scan.Semicolon.Scan(advance) name, value, ok := scan.EqualPair.Scan(token) if ok { - var ps *[]byte + var ps []byte var err error + if ps, err = base64.StdEncoding.DecodeString(value); err != nil { + return + } + ps = utils.RemoveNaluSeparator(ps) + switch name { case "sprop-vps": - ps = &video.Vps + video.Vps = ps case "sprop-sps": - ps = &video.Sps + video.Sps = ps case "sprop-pps": - ps = &video.Pps - } - if ps == nil { - continue - } - - if *ps, err = base64.StdEncoding.DecodeString(value); err != nil { - return + video.Pps = ps } } } diff --git a/utils/h264or5.go b/utils/h264or5.go index 8930c75..6915a32 100644 --- a/utils/h264or5.go +++ b/utils/h264or5.go @@ -4,9 +4,12 @@ package utils +import "bytes" + // RemoveH264or5EmulationBytes A general routine for making a copy of a (H.264 or H.265) NAL unit, removing 'emulation' bytes from the copy // copy from live555 func RemoveH264or5EmulationBytes(from []byte) []byte { + from = RemoveNaluSeparator(from) to := make([]byte, len(from)) toMaxSize := len(to) fromSize := len(from) @@ -35,3 +38,14 @@ func RemoveH264or5EmulationBytes(from []byte) []byte { return to[:toSize] // return bytes.Replace(from, []byte{0, 0, 3}, []byte{0, 0}, -1) } + +// 移除 NALU 分隔符 0x00000001 或 0x000001 +func RemoveNaluSeparator(nalu []byte) []byte { + if bytes.HasPrefix(nalu, []byte{0x0, 0x0, 0x0, 0x1}) { + return nalu[4:] + } + if bytes.HasPrefix(nalu, []byte{0x0, 0x0, 0x1}) { + return nalu[3:] + } + return nalu +}