github.com/bluenviron/mediacommon@v1.9.3/pkg/codecs/h264/avcc.go (about) 1 package h264 2 3 import ( 4 "errors" 5 "fmt" 6 ) 7 8 // ErrAVCCNoNALUs is returned by AVCCUnmarshal when no NALUs have been decoded. 9 var ErrAVCCNoNALUs = errors.New("AVCC unit doesn't contain any NALU") 10 11 // AVCCUnmarshal decodes an access unit from the AVCC stream format. 12 // Specification: ISO 14496-15, section 5.3.4.2.1 13 func AVCCUnmarshal(buf []byte) ([][]byte, error) { 14 bl := len(buf) 15 pos := 0 16 var ret [][]byte 17 naluCount := 0 18 auSize := 0 19 20 for { 21 if (bl - pos) < 4 { 22 return nil, fmt.Errorf("invalid length") 23 } 24 25 l := int(uint32(buf[pos])<<24 | uint32(buf[pos+1])<<16 | uint32(buf[pos+2])<<8 | uint32(buf[pos+3])) 26 pos += 4 27 28 if l != 0 { 29 if (auSize + l) > MaxAccessUnitSize { 30 return nil, fmt.Errorf("access unit size (%d) is too big, maximum is %d", auSize+l, MaxAccessUnitSize) 31 } 32 33 if (naluCount + 1) > MaxNALUsPerAccessUnit { 34 return nil, fmt.Errorf("NALU count (%d) exceeds maximum allowed (%d)", 35 len(ret)+1, MaxNALUsPerAccessUnit) 36 } 37 38 if (bl - pos) < l { 39 return nil, fmt.Errorf("invalid length") 40 } 41 42 ret = append(ret, buf[pos:pos+l]) 43 auSize += l 44 naluCount++ 45 pos += l 46 } 47 48 if (bl - pos) == 0 { 49 break 50 } 51 } 52 53 if ret == nil { 54 return nil, ErrAVCCNoNALUs 55 } 56 57 return ret, nil 58 } 59 60 func avccMarshalSize(au [][]byte) int { 61 n := 0 62 for _, nalu := range au { 63 n += 4 + len(nalu) 64 } 65 return n 66 } 67 68 // AVCCMarshal encodes an access unit into the AVCC stream format. 69 // Specification: ISO 14496-15, section 5.3.4.2.1 70 func AVCCMarshal(au [][]byte) ([]byte, error) { 71 buf := make([]byte, avccMarshalSize(au)) 72 pos := 0 73 74 for _, nalu := range au { 75 naluLen := len(nalu) 76 buf[pos] = byte(naluLen >> 24) 77 buf[pos+1] = byte(naluLen >> 16) 78 buf[pos+2] = byte(naluLen >> 8) 79 buf[pos+3] = byte(naluLen) 80 pos += 4 81 82 pos += copy(buf[pos:], nalu) 83 } 84 85 return buf, nil 86 }