github.com/pion/webrtc/v4@v4.0.1/pkg/media/h264reader/h264reader.go (about) 1 // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly> 2 // SPDX-License-Identifier: MIT 3 4 // Package h264reader implements a H264 Annex-B Reader 5 package h264reader 6 7 import ( 8 "bytes" 9 "errors" 10 "io" 11 ) 12 13 // H264Reader reads data from stream and constructs h264 nal units 14 type H264Reader struct { 15 stream io.Reader 16 nalBuffer []byte 17 countOfConsecutiveZeroBytes int 18 nalPrefixParsed bool 19 readBuffer []byte 20 tmpReadBuf []byte 21 } 22 23 var ( 24 errNilReader = errors.New("stream is nil") 25 errDataIsNotH264Stream = errors.New("data is not a H264 bitstream") 26 ) 27 28 // NewReader creates new H264Reader 29 func NewReader(in io.Reader) (*H264Reader, error) { 30 if in == nil { 31 return nil, errNilReader 32 } 33 34 reader := &H264Reader{ 35 stream: in, 36 nalBuffer: make([]byte, 0), 37 nalPrefixParsed: false, 38 readBuffer: make([]byte, 0), 39 tmpReadBuf: make([]byte, 4096), 40 } 41 42 return reader, nil 43 } 44 45 // NAL H.264 Network Abstraction Layer 46 type NAL struct { 47 PictureOrderCount uint32 48 49 // NAL header 50 ForbiddenZeroBit bool 51 RefIdc uint8 52 UnitType NalUnitType 53 54 Data []byte // header byte + rbsp 55 } 56 57 func (reader *H264Reader) read(numToRead int) (data []byte, e error) { 58 for len(reader.readBuffer) < numToRead { 59 n, err := reader.stream.Read(reader.tmpReadBuf) 60 if err != nil { 61 return nil, err 62 } 63 if n == 0 { 64 break 65 } 66 reader.readBuffer = append(reader.readBuffer, reader.tmpReadBuf[0:n]...) 67 } 68 var numShouldRead int 69 if numToRead <= len(reader.readBuffer) { 70 numShouldRead = numToRead 71 } else { 72 numShouldRead = len(reader.readBuffer) 73 } 74 data = reader.readBuffer[0:numShouldRead] 75 reader.readBuffer = reader.readBuffer[numShouldRead:] 76 return data, nil 77 } 78 79 func (reader *H264Reader) bitStreamStartsWithH264Prefix() (prefixLength int, e error) { 80 nalPrefix3Bytes := []byte{0, 0, 1} 81 nalPrefix4Bytes := []byte{0, 0, 0, 1} 82 83 prefixBuffer, e := reader.read(4) 84 if e != nil { 85 return 86 } 87 88 n := len(prefixBuffer) 89 90 if n == 0 { 91 return 0, io.EOF 92 } 93 94 if n < 3 { 95 return 0, errDataIsNotH264Stream 96 } 97 98 nalPrefix3BytesFound := bytes.Equal(nalPrefix3Bytes, prefixBuffer[:3]) 99 if n == 3 { 100 if nalPrefix3BytesFound { 101 return 0, io.EOF 102 } 103 return 0, errDataIsNotH264Stream 104 } 105 106 // n == 4 107 if nalPrefix3BytesFound { 108 reader.nalBuffer = append(reader.nalBuffer, prefixBuffer[3]) 109 return 3, nil 110 } 111 112 nalPrefix4BytesFound := bytes.Equal(nalPrefix4Bytes, prefixBuffer) 113 if nalPrefix4BytesFound { 114 return 4, nil 115 } 116 return 0, errDataIsNotH264Stream 117 } 118 119 // NextNAL reads from stream and returns then next NAL, 120 // and an error if there is incomplete frame data. 121 // Returns all nil values when no more NALs are available. 122 func (reader *H264Reader) NextNAL() (*NAL, error) { 123 if !reader.nalPrefixParsed { 124 _, err := reader.bitStreamStartsWithH264Prefix() 125 if err != nil { 126 return nil, err 127 } 128 129 reader.nalPrefixParsed = true 130 } 131 132 for { 133 buffer, err := reader.read(1) 134 if err != nil { 135 break 136 } 137 138 n := len(buffer) 139 140 if n != 1 { 141 break 142 } 143 readByte := buffer[0] 144 nalFound := reader.processByte(readByte) 145 if nalFound { 146 nal := newNal(reader.nalBuffer) 147 nal.parseHeader() 148 if nal.UnitType == NalUnitTypeSEI { 149 reader.nalBuffer = nil 150 continue 151 } 152 break 153 } 154 155 reader.nalBuffer = append(reader.nalBuffer, readByte) 156 } 157 158 if len(reader.nalBuffer) == 0 { 159 return nil, io.EOF 160 } 161 162 nal := newNal(reader.nalBuffer) 163 reader.nalBuffer = nil 164 nal.parseHeader() 165 166 return nal, nil 167 } 168 169 func (reader *H264Reader) processByte(readByte byte) (nalFound bool) { 170 nalFound = false 171 172 switch readByte { 173 case 0: 174 reader.countOfConsecutiveZeroBytes++ 175 case 1: 176 if reader.countOfConsecutiveZeroBytes >= 2 { 177 countOfConsecutiveZeroBytesInPrefix := 2 178 if reader.countOfConsecutiveZeroBytes > 2 { 179 countOfConsecutiveZeroBytesInPrefix = 3 180 } 181 182 if nalUnitLength := len(reader.nalBuffer) - countOfConsecutiveZeroBytesInPrefix; nalUnitLength > 0 { 183 reader.nalBuffer = reader.nalBuffer[0:nalUnitLength] 184 nalFound = true 185 } 186 } 187 188 reader.countOfConsecutiveZeroBytes = 0 189 default: 190 reader.countOfConsecutiveZeroBytes = 0 191 } 192 193 return nalFound 194 } 195 196 func newNal(data []byte) *NAL { 197 return &NAL{PictureOrderCount: 0, ForbiddenZeroBit: false, RefIdc: 0, UnitType: NalUnitTypeUnspecified, Data: data} 198 } 199 200 func (h *NAL) parseHeader() { 201 firstByte := h.Data[0] 202 h.ForbiddenZeroBit = (((firstByte & 0x80) >> 7) == 1) // 0x80 = 0b10000000 203 h.RefIdc = (firstByte & 0x60) >> 5 // 0x60 = 0b01100000 204 h.UnitType = NalUnitType((firstByte & 0x1F) >> 0) // 0x1F = 0b00011111 205 }