Add HEVC support

This commit is contained in:
Ingo Oppermann 2024-01-03 12:59:10 +01:00
parent fde0595744
commit 4ee14576ae
12 changed files with 1054 additions and 83 deletions

View File

@ -116,6 +116,9 @@ type CodecType uint32
var ( var (
H264 = MakeVideoCodecType(avCodecTypeMagic + 1) H264 = MakeVideoCodecType(avCodecTypeMagic + 1)
HEVC = MakeVideoCodecType(avCodecTypeMagic + 2)
VP9 = MakeVideoCodecType(avCodecTypeMagic + 3)
AV1 = MakeVideoCodecType(avCodecTypeMagic + 4)
AAC = MakeAudioCodecType(avCodecTypeMagic + 1) AAC = MakeAudioCodecType(avCodecTypeMagic + 1)
PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 2) PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 2)
PCM_ALAW = MakeAudioCodecType(avCodecTypeMagic + 3) PCM_ALAW = MakeAudioCodecType(avCodecTypeMagic + 3)
@ -126,10 +129,16 @@ var (
const codecTypeAudioBit = 0x1 const codecTypeAudioBit = 0x1
const codecTypeOtherBits = 1 const codecTypeOtherBits = 1
func (self CodecType) String() string { func (c CodecType) String() string {
switch self { switch c {
case H264: case H264:
return "H264" return "H264"
case HEVC:
return "HEVC"
case VP9:
return "VP9"
case AV1:
return "AV1"
case AAC: case AAC:
return "AAC" return "AAC"
case PCM_MULAW: case PCM_MULAW:
@ -144,12 +153,12 @@ func (self CodecType) String() string {
return "" return ""
} }
func (self CodecType) IsAudio() bool { func (c CodecType) IsAudio() bool {
return self&codecTypeAudioBit != 0 return c&codecTypeAudioBit != 0
} }
func (self CodecType) IsVideo() bool { func (c CodecType) IsVideo() bool {
return self&codecTypeAudioBit == 0 return c&codecTypeAudioBit == 0
} }
// Make a new audio codec type. // Make a new audio codec type.
@ -169,7 +178,7 @@ const avCodecTypeMagic = 233333
// CodecData is some important bytes for initializing audio/video decoder, // CodecData is some important bytes for initializing audio/video decoder,
// can be converted to VideoCodecData or AudioCodecData using: // can be converted to VideoCodecData or AudioCodecData using:
// //
// codecdata.(AudioCodecData) or codecdata.(VideoCodecData) // codecdata.(AudioCodecData) or codecdata.(VideoCodecData)
// //
// for H264, CodecData is AVCDecoderConfigure bytes, includes SPS/PPS. // for H264, CodecData is AVCDecoderConfigure bytes, includes SPS/PPS.
type CodecData interface { type CodecData interface {

View File

@ -2,8 +2,9 @@
package pktque package pktque
import ( import (
"github.com/datarhei/joy4/av"
"time" "time"
"github.com/datarhei/joy4/av"
) )
type Filter interface { type Filter interface {

View File

@ -3,10 +3,11 @@ package aacparser
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/datarhei/joy4/av"
"github.com/datarhei/joy4/utils/bits"
"io" "io"
"time" "time"
"github.com/datarhei/joy4/av"
"github.com/datarhei/joy4/utils/bits"
) )
// copied from libavcodec/mpeg4audio.h // copied from libavcodec/mpeg4audio.h

View File

@ -3,6 +3,7 @@ package h264parser
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/datarhei/joy4/av" "github.com/datarhei/joy4/av"
"github.com/datarhei/joy4/utils/bits" "github.com/datarhei/joy4/utils/bits"
"github.com/datarhei/joy4/utils/bits/pio" "github.com/datarhei/joy4/utils/bits/pio"

View File

@ -6,16 +6,16 @@ import (
) )
func TestParser(t *testing.T) { func TestParser(t *testing.T) {
var ok bool var typ int
var nalus [][]byte var nalus [][]byte
annexbFrame, _ := hex.DecodeString("00000001223322330000000122332233223300000133000001000001") annexbFrame, _ := hex.DecodeString("00000001223322330000000122332233223300000133000001000001")
nalus, ok = SplitNALUs(annexbFrame) nalus, typ = SplitNALUs(annexbFrame)
t.Log(ok, len(nalus)) t.Log(typ, len(nalus))
avccFrame, _ := hex.DecodeString( avccFrame, _ := hex.DecodeString(
"00000008aabbccaabbccaabb00000001aa", "00000008aabbccaabbccaabb00000001aa",
) )
nalus, ok = SplitNALUs(avccFrame) nalus, typ = SplitNALUs(avccFrame)
t.Log(ok, len(nalus)) t.Log(typ, len(nalus))
} }

695
codec/hevcparser/parser.go Normal file
View File

@ -0,0 +1,695 @@
package hevcparser
// based on https://github.com/deepch/vdk/blob/v0.0.21/codec/h265parser/parser.go
import (
"bytes"
"errors"
"fmt"
"github.com/datarhei/joy4/av"
"github.com/datarhei/joy4/utils/bits"
"github.com/datarhei/joy4/utils/bits/pio"
)
type SPSInfo struct {
ProfileIdc uint
LevelIdc uint
CropLeft uint
CropRight uint
CropTop uint
CropBottom uint
Width uint
Height uint
PicWidthInLumaSamples uint
PicHeightInLumaSamples uint
generalProfileSpace uint
generalTierFlag uint
generalProfileIDC uint
generalProfileCompatibilityFlags uint32
generalConstraintIndicatorFlags uint64
generalLevelIDC uint
}
const (
NAL_UNIT_CODED_SLICE_TRAIL_N = 0
NAL_UNIT_CODED_SLICE_TRAIL_R = 1
NAL_UNIT_CODED_SLICE_TSA_N = 2
NAL_UNIT_CODED_SLICE_TSA_R = 3
NAL_UNIT_CODED_SLICE_STSA_N = 4
NAL_UNIT_CODED_SLICE_STSA_R = 5
NAL_UNIT_CODED_SLICE_RADL_N = 6
NAL_UNIT_CODED_SLICE_RADL_R = 7
NAL_UNIT_CODED_SLICE_RASL_N = 8
NAL_UNIT_CODED_SLICE_RASL_R = 9
NAL_UNIT_RESERVED_VCL_N10 = 10
NAL_UNIT_RESERVED_VCL_R11 = 11
NAL_UNIT_RESERVED_VCL_N12 = 12
NAL_UNIT_RESERVED_VCL_R13 = 13
NAL_UNIT_RESERVED_VCL_N14 = 14
NAL_UNIT_RESERVED_VCL_R15 = 15
NAL_UNIT_CODED_SLICE_BLA_W_LP = 16
NAL_UNIT_CODED_SLICE_BLA_W_RADL = 17
NAL_UNIT_CODED_SLICE_BLA_N_LP = 18
NAL_UNIT_CODED_SLICE_IDR_W_RADL = 19
NAL_UNIT_CODED_SLICE_IDR_N_LP = 20
NAL_UNIT_CODED_SLICE_CRA = 21
NAL_UNIT_RESERVED_IRAP_VCL22 = 22
NAL_UNIT_RESERVED_IRAP_VCL23 = 23
NAL_UNIT_RESERVED_VCL24 = 24
NAL_UNIT_RESERVED_VCL25 = 25
NAL_UNIT_RESERVED_VCL26 = 26
NAL_UNIT_RESERVED_VCL27 = 27
NAL_UNIT_RESERVED_VCL28 = 28
NAL_UNIT_RESERVED_VCL29 = 29
NAL_UNIT_RESERVED_VCL30 = 30
NAL_UNIT_RESERVED_VCL31 = 31
NAL_UNIT_VPS = 32
NAL_UNIT_SPS = 33
NAL_UNIT_PPS = 34
NAL_UNIT_ACCESS_UNIT_DELIMITER = 35
NAL_UNIT_EOS = 36
NAL_UNIT_EOB = 37
NAL_UNIT_FILLER_DATA = 38
NAL_UNIT_PREFIX_SEI = 39
NAL_UNIT_SUFFIX_SEI = 40
NAL_UNIT_RESERVED_NVCL41 = 41
NAL_UNIT_RESERVED_NVCL42 = 42
NAL_UNIT_RESERVED_NVCL43 = 43
NAL_UNIT_RESERVED_NVCL44 = 44
NAL_UNIT_RESERVED_NVCL45 = 45
NAL_UNIT_RESERVED_NVCL46 = 46
NAL_UNIT_RESERVED_NVCL47 = 47
NAL_UNIT_UNSPECIFIED_48 = 48
NAL_UNIT_UNSPECIFIED_49 = 49
NAL_UNIT_UNSPECIFIED_50 = 50
NAL_UNIT_UNSPECIFIED_51 = 51
NAL_UNIT_UNSPECIFIED_52 = 52
NAL_UNIT_UNSPECIFIED_53 = 53
NAL_UNIT_UNSPECIFIED_54 = 54
NAL_UNIT_UNSPECIFIED_55 = 55
NAL_UNIT_UNSPECIFIED_56 = 56
NAL_UNIT_UNSPECIFIED_57 = 57
NAL_UNIT_UNSPECIFIED_58 = 58
NAL_UNIT_UNSPECIFIED_59 = 59
NAL_UNIT_UNSPECIFIED_60 = 60
NAL_UNIT_UNSPECIFIED_61 = 61
NAL_UNIT_UNSPECIFIED_62 = 62
NAL_UNIT_UNSPECIFIED_63 = 63
NAL_UNIT_INVALID = 64
)
const (
MAX_VPS_COUNT = 16
MAX_SUB_LAYERS = 7
MAX_SPS_COUNT = 32
)
var (
ErrorHEVCIncorectUnitSize = errors.New("incorrect unit size")
ErrorHECVIncorectUnitType = errors.New("incorrect unit type")
)
var StartCodeBytes = []byte{0, 0, 1}
var AUDBytes = []byte{0, 0, 0, 1, 0x9, 0xf0, 0, 0, 0, 1} // AUD
const (
NALU_RAW = iota
NALU_AVCC
NALU_ANNEXB
)
func SplitNALUs(b []byte) (nalus [][]byte, typ int) {
if len(b) < 4 {
return [][]byte{b}, NALU_RAW
}
val3 := pio.U24BE(b)
val4 := pio.U32BE(b)
if val4 <= uint32(len(b)) {
_val4 := val4
_b := b[4:]
nalus := [][]byte{}
for {
nalus = append(nalus, _b[:_val4])
_b = _b[_val4:]
if len(_b) < 4 {
break
}
_val4 = pio.U32BE(_b)
_b = _b[4:]
if _val4 > uint32(len(_b)) {
break
}
}
if len(_b) == 0 {
return nalus, NALU_AVCC
}
}
if val3 == 1 || val4 == 1 {
_val3 := val3
_val4 := val4
start := 0
pos := 0
for {
if start != pos {
nalus = append(nalus, b[start:pos])
}
if _val3 == 1 {
pos += 3
} else if _val4 == 1 {
pos += 4
}
start = pos
if start == len(b) {
break
}
_val3 = 0
_val4 = 0
for pos < len(b) {
if pos+2 < len(b) && b[pos] == 0 {
_val3 = pio.U24BE(b[pos:])
if _val3 == 0 {
if pos+3 < len(b) {
_val4 = uint32(b[pos+3])
if _val4 == 1 {
break
}
}
} else if _val3 == 1 {
break
}
pos++
} else {
pos++
}
}
}
typ = NALU_ANNEXB
return
}
return [][]byte{b}, NALU_RAW
}
func ParseSPS(sps []byte) (ctx SPSInfo, err error) {
if len(sps) < 2 {
err = ErrorHEVCIncorectUnitSize
return
}
rbsp := nal2rbsp(sps[2:])
br := &bits.GolombBitReader{R: bytes.NewReader(rbsp)}
// sps_video_parameter_set_id
if _, err = br.ReadBits(4); err != nil {
return
}
// sps_max_sub_layers_minus1
spsMaxSubLayersMinus1, err := br.ReadBits(3)
if err != nil {
return
}
// sps_temporal_id_nesting_flag
if _, err = br.ReadBit(); err != nil {
return
}
// profile_tier_level( 1, sps_max_sub_layers_minus1 )
if err = parsePTL(br, &ctx, spsMaxSubLayersMinus1); err != nil {
return
}
// sps_seq_parameter_set_id
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// chroma_format_idc
var chroma_format_idc uint
if chroma_format_idc, err = br.ReadExponentialGolombCode(); err != nil {
return
}
if chroma_format_idc == 3 {
// separate_colour_plane_flag
if _, err = br.ReadBit(); err != nil {
return
}
}
// Table 6-1, Section 6.2
var subWidthC uint
var subHeightC uint
switch chroma_format_idc {
case 0:
subWidthC, subHeightC = 1, 1
case 1:
subWidthC, subHeightC = 2, 2
case 2:
subWidthC, subHeightC = 2, 1
case 3:
subWidthC, subHeightC = 1, 1
}
// pic_width_in_luma_samples
if ctx.PicWidthInLumaSamples, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// pic_height_in_luma_samples
if ctx.PicHeightInLumaSamples, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// conformance_window_flag
conformanceWindowFlag, err := br.ReadBit()
if err != nil {
return
}
var conf_win_left_offset uint
var conf_win_right_offset uint
var conf_win_top_offset uint
var conf_win_bottom_offset uint
if conformanceWindowFlag != 0 {
// conf_win_left_offset
conf_win_left_offset, err = br.ReadExponentialGolombCode()
if err != nil {
return
}
ctx.CropLeft = subWidthC * conf_win_left_offset
// conf_win_right_offset
conf_win_right_offset, err = br.ReadExponentialGolombCode()
if err != nil {
return
}
ctx.CropRight = subWidthC * conf_win_right_offset
// conf_win_top_offset
conf_win_top_offset, err = br.ReadExponentialGolombCode()
if err != nil {
return
}
ctx.CropTop = subHeightC * conf_win_top_offset
// conf_win_bottom_offset
conf_win_bottom_offset, err = br.ReadExponentialGolombCode()
if err != nil {
return
}
ctx.CropBottom = subHeightC * conf_win_bottom_offset
}
ctx.Width = ctx.PicWidthInLumaSamples - ctx.CropLeft - ctx.CropRight
ctx.Height = ctx.PicHeightInLumaSamples - ctx.CropTop - ctx.CropBottom
// bit_depth_luma_minus8
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// bit_depth_chroma_minus8
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// log2_max_pic_order_cnt_lsb_minus4
_, err = br.ReadExponentialGolombCode()
if err != nil {
return
}
// sps_sub_layer_ordering_info_present_flag
spsSubLayerOrderingInfoPresentFlag, err := br.ReadBit()
if err != nil {
return
}
var i uint
if spsSubLayerOrderingInfoPresentFlag != 0 {
i = 0
} else {
i = spsMaxSubLayersMinus1
}
for ; i <= spsMaxSubLayersMinus1; i++ {
// sps_max_dec_pic_buffering_minus1[ i ]
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// sps_max_num_reorder_pics[ i ]
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// sps_max_latency_increase_plus1[ i ]
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
}
// log2_min_luma_coding_block_size_minus3
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// log2_diff_max_min_luma_coding_block_size
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// log2_min_luma_transform_block_size_minus2
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// log2_diff_max_min_luma_transform_block_size
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// max_transform_hierarchy_depth_inter
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
// max_transform_hierarchy_depth_intra
if _, err = br.ReadExponentialGolombCode(); err != nil {
return
}
return
}
func parsePTL(br *bits.GolombBitReader, ctx *SPSInfo, maxSubLayersMinus1 uint) error {
var err error
var ptl SPSInfo
if ptl.generalProfileSpace, err = br.ReadBits(2); err != nil {
return err
}
if ptl.generalTierFlag, err = br.ReadBit(); err != nil {
return err
}
if ptl.generalProfileIDC, err = br.ReadBits(5); err != nil {
return err
}
if ptl.generalProfileCompatibilityFlags, err = br.ReadBits32(32); err != nil {
return err
}
if ptl.generalConstraintIndicatorFlags, err = br.ReadBits64(48); err != nil {
return err
}
if ptl.generalLevelIDC, err = br.ReadBits(8); err != nil {
return err
}
updatePTL(ctx, &ptl)
if maxSubLayersMinus1 == 0 {
return nil
}
subLayerProfilePresentFlag := make([]uint, maxSubLayersMinus1)
subLayerLevelPresentFlag := make([]uint, maxSubLayersMinus1)
for i := uint(0); i < maxSubLayersMinus1; i++ {
if subLayerProfilePresentFlag[i], err = br.ReadBit(); err != nil {
return err
}
if subLayerLevelPresentFlag[i], err = br.ReadBit(); err != nil {
return err
}
}
if maxSubLayersMinus1 > 0 {
for i := maxSubLayersMinus1; i < 8; i++ {
if _, err = br.ReadBits(2); err != nil {
return err
}
}
}
for i := uint(0); i < maxSubLayersMinus1; i++ {
if subLayerProfilePresentFlag[i] != 0 {
if _, err = br.ReadBits32(32); err != nil {
return err
}
if _, err = br.ReadBits32(32); err != nil {
return err
}
if _, err = br.ReadBits32(24); err != nil {
return err
}
}
if subLayerLevelPresentFlag[i] != 0 {
if _, err = br.ReadBits(8); err != nil {
return err
}
}
}
return nil
}
func updatePTL(ctx, ptl *SPSInfo) {
ctx.generalProfileSpace = ptl.generalProfileSpace
if ptl.generalTierFlag > ctx.generalTierFlag {
ctx.generalLevelIDC = ptl.generalLevelIDC
ctx.generalTierFlag = ptl.generalTierFlag
} else {
if ptl.generalLevelIDC > ctx.generalLevelIDC {
ctx.generalLevelIDC = ptl.generalLevelIDC
}
}
if ptl.generalProfileIDC > ctx.generalProfileIDC {
ctx.generalProfileIDC = ptl.generalProfileIDC
}
ctx.generalProfileCompatibilityFlags &= ptl.generalProfileCompatibilityFlags
ctx.generalConstraintIndicatorFlags &= ptl.generalConstraintIndicatorFlags
}
func nal2rbsp(nal []byte) []byte {
return bytes.Replace(nal, []byte{0x0, 0x0, 0x3}, []byte{0x0, 0x0}, -1)
}
type CodecData struct {
Record []byte
RecordInfo HEVCDecoderConfRecord
SPSInfo SPSInfo
}
func (codec CodecData) Type() av.CodecType {
return av.HEVC
}
func (codec CodecData) HEVCDecoderConfRecordBytes() []byte {
return codec.Record
}
func (codec CodecData) SPS() []byte {
return codec.RecordInfo.SPS[0]
}
func (codec CodecData) PPS() []byte {
return codec.RecordInfo.PPS[0]
}
func (codec CodecData) VPS() []byte {
return codec.RecordInfo.VPS[0]
}
func (codec CodecData) Width() int {
return int(codec.SPSInfo.Width)
}
func (codec CodecData) Height() int {
return int(codec.SPSInfo.Height)
}
func NewCodecDataFromHEVCDecoderConfRecord(record []byte) (self CodecData, err error) {
self.Record = record
if _, err = (&self.RecordInfo).Unmarshal(record); err != nil {
return
}
if len(self.RecordInfo.SPS) == 0 {
err = fmt.Errorf("hevcparser: no SPS found in HEVCDecoderConfRecord")
return
}
if len(self.RecordInfo.PPS) == 0 {
err = fmt.Errorf("hevcparser: no PPS found in HEVCDecoderConfRecord")
return
}
if len(self.RecordInfo.VPS) == 0 {
err = fmt.Errorf("hevcparser: no VPS found in HEVCDecoderConfRecord")
return
}
if self.SPSInfo, err = ParseSPS(self.RecordInfo.SPS[0]); err != nil {
err = fmt.Errorf("hevcparser: parse SPS failed(%s)", err)
return
}
return
}
func NewCodecDataFromVPSAndSPSAndPPS(vps, sps, pps []byte) (self CodecData, err error) {
recordinfo := HEVCDecoderConfRecord{}
recordinfo.HEVCProfileIndication = sps[3]
recordinfo.ProfileCompatibility = sps[4]
recordinfo.HEVCLevelIndication = sps[5]
recordinfo.SPS = [][]byte{sps}
recordinfo.PPS = [][]byte{pps}
recordinfo.VPS = [][]byte{vps}
recordinfo.LengthSizeMinusOne = 3
if self.SPSInfo, err = ParseSPS(sps); err != nil {
return
}
buf := make([]byte, recordinfo.Len())
recordinfo.Marshal(buf, self.SPSInfo)
self.RecordInfo = recordinfo
self.Record = buf
return
}
type HEVCDecoderConfRecord struct {
HEVCProfileIndication uint8
ProfileCompatibility uint8
HEVCLevelIndication uint8
LengthSizeMinusOne uint8
VPS [][]byte
SPS [][]byte
PPS [][]byte
}
var ErrDecconfInvalid = fmt.Errorf("hevcparser: HEVCDecoderConfRecord invalid")
func (record *HEVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
if len(b) < 30 {
err = ErrDecconfInvalid
return
}
record.HEVCProfileIndication = b[1]
record.ProfileCompatibility = b[2]
record.HEVCLevelIndication = b[3]
record.LengthSizeMinusOne = b[4] & 0x03
vpscount := int(b[25] & 0x1f)
n += 26
for i := 0; i < vpscount; i++ {
if len(b) < n+2 {
err = ErrDecconfInvalid
return
}
vpslen := int(pio.U16BE(b[n:]))
n += 2
if len(b) < n+vpslen {
err = ErrDecconfInvalid
return
}
record.VPS = append(record.VPS, b[n:n+vpslen])
n += vpslen
}
if len(b) < n+1 {
err = ErrDecconfInvalid
return
}
n++
n++
spscount := int(b[n])
n++
for i := 0; i < spscount; i++ {
if len(b) < n+2 {
err = ErrDecconfInvalid
return
}
spslen := int(pio.U16BE(b[n:]))
n += 2
if len(b) < n+spslen {
err = ErrDecconfInvalid
return
}
record.SPS = append(record.SPS, b[n:n+spslen])
n += spslen
}
n++
n++
ppscount := int(b[n])
n++
for i := 0; i < ppscount; i++ {
if len(b) < n+2 {
err = ErrDecconfInvalid
return
}
ppslen := int(pio.U16BE(b[n:]))
n += 2
if len(b) < n+ppslen {
err = ErrDecconfInvalid
return
}
record.PPS = append(record.PPS, b[n:n+ppslen])
n += ppslen
}
return
}
func (record HEVCDecoderConfRecord) Len() (n int) {
n = 23
for _, sps := range record.SPS {
n += 5 + len(sps)
}
for _, pps := range record.PPS {
n += 5 + len(pps)
}
for _, vps := range record.VPS {
n += 5 + len(vps)
}
return
}
func (record HEVCDecoderConfRecord) Marshal(b []byte, si SPSInfo) (n int) {
b[0] = 1
b[1] = record.HEVCProfileIndication
b[2] = record.ProfileCompatibility
b[3] = record.HEVCLevelIndication
b[21] = 3
b[22] = 3
n += 23
b[n] = (record.VPS[0][0] >> 1) & 0x3f
n++
b[n] = byte(len(record.VPS) >> 8)
n++
b[n] = byte(len(record.VPS))
n++
for _, vps := range record.VPS {
pio.PutU16BE(b[n:], uint16(len(vps)))
n += 2
copy(b[n:], vps)
n += len(vps)
}
b[n] = (record.SPS[0][0] >> 1) & 0x3f
n++
b[n] = byte(len(record.SPS) >> 8)
n++
b[n] = byte(len(record.SPS))
n++
for _, sps := range record.SPS {
pio.PutU16BE(b[n:], uint16(len(sps)))
n += 2
copy(b[n:], sps)
n += len(sps)
}
b[n] = (record.PPS[0][0] >> 1) & 0x3f
n++
b[n] = byte(len(record.PPS) >> 8)
n++
b[n] = byte(len(record.PPS))
n++
for _, pps := range record.PPS {
pio.PutU16BE(b[n:], uint16(len(pps)))
n += 2
copy(b[n:], pps)
n += len(pps)
}
return
}

View File

@ -0,0 +1,58 @@
package main
import (
"fmt"
"log"
"os"
"github.com/datarhei/joy4/av"
"github.com/datarhei/joy4/av/avutil"
"github.com/datarhei/joy4/codec/h264parser"
"github.com/datarhei/joy4/format"
)
func init() {
format.RegisterAll()
}
func main() {
if len(os.Args) < 2 {
log.Fatalf("%s [url]", os.Args[0])
}
src, err := avutil.Open(os.Args[1])
if err != nil {
log.Fatalf("error connecting: %s", err.Error())
}
defer src.Close()
var streams []av.CodecData
if streams, err = src.Streams(); err != nil {
log.Fatalf("error streams: %s", err.Error())
}
idx := int8(-1)
for i, s := range streams {
if s.Type().IsVideo() {
fmt.Printf("video: %s\n", s.Type().String())
v := s.(h264parser.CodecData)
os.Stdout.Write(v.AVCDecoderConfRecordBytes())
idx = int8(i)
}
}
for {
p, err := src.ReadPacket()
if err != nil {
log.Fatalf("error reading: %s", err.Error())
}
if p.Idx != idx {
continue
}
os.Stdout.Write(p.Data)
}
}

View File

@ -116,7 +116,7 @@ func (s *server) handlePlay(conn *rtmp.Conn) {
s.lock.RUnlock() s.lock.RUnlock()
if ch != nil { if ch != nil {
conn.SetMetaData(ch.metadata) //conn.SetMetaData(ch.metadata)
s.log("PLAY", "START", conn.URL.Path, "", client) s.log("PLAY", "START", conn.URL.Path, "", client)
cursor := ch.que.Oldest() cursor := ch.que.Oldest()
@ -139,8 +139,6 @@ func (s *server) handlePlay(conn *rtmp.Conn) {
} else { } else {
s.log("PLAY", "NOTFOUND", conn.URL.Path, "", client) s.log("PLAY", "NOTFOUND", conn.URL.Path, "", client)
} }
return
} }
func (s *server) handlePublish(conn *rtmp.Conn) { func (s *server) handlePublish(conn *rtmp.Conn) {
@ -169,14 +167,14 @@ func (s *server) handlePublish(conn *rtmp.Conn) {
return return
} }
metadata := conn.GetMetaData() //metadata := conn.GetMetaData()
s.lock.Lock() s.lock.Lock()
ch := s.channels[conn.URL.Path] ch := s.channels[conn.URL.Path]
if ch == nil { if ch == nil {
ch = &channel{} ch = &channel{}
ch.metadata = metadata //ch.metadata = metadata
ch.que = pubsub.NewQueue() ch.que = pubsub.NewQueue()
ch.que.WriteHeader(streams) ch.que.WriteHeader(streams)
for _, stream := range streams { for _, stream := range streams {
@ -221,8 +219,6 @@ func (s *server) handlePublish(conn *rtmp.Conn) {
ch.que.Close() ch.que.Close()
s.log("PUBLISH", "STOP", conn.URL.Path, "", client) s.log("PUBLISH", "STOP", conn.URL.Path, "", client)
return
} }
func main() { func main() {

View File

@ -2,16 +2,19 @@ package flv
import ( import (
"bufio" "bufio"
"encoding/hex"
"fmt" "fmt"
"io"
"github.com/datarhei/joy4/av" "github.com/datarhei/joy4/av"
"github.com/datarhei/joy4/av/avutil" "github.com/datarhei/joy4/av/avutil"
"github.com/datarhei/joy4/codec" "github.com/datarhei/joy4/codec"
"github.com/datarhei/joy4/codec/aacparser" "github.com/datarhei/joy4/codec/aacparser"
"github.com/datarhei/joy4/codec/fake" "github.com/datarhei/joy4/codec/fake"
"github.com/datarhei/joy4/codec/h264parser" "github.com/datarhei/joy4/codec/h264parser"
"github.com/datarhei/joy4/codec/hevcparser"
"github.com/datarhei/joy4/format/flv/flvio" "github.com/datarhei/joy4/format/flv/flvio"
"github.com/datarhei/joy4/utils/bits/pio" "github.com/datarhei/joy4/utils/bits/pio"
"io"
) )
var MaxProbePacketCount = 20 var MaxProbePacketCount = 20
@ -27,6 +30,8 @@ func NewMetadataByStreams(streams []av.CodecData) (metadata flvio.AMFMap, err er
switch typ { switch typ {
case av.H264: case av.H264:
metadata["videocodecid"] = flvio.VIDEO_H264 metadata["videocodecid"] = flvio.VIDEO_H264
case av.HEVC:
metadata["videocodecid"] = flvio.FourCCToFloat(flvio.FOURCC_HEVC)
default: default:
err = fmt.Errorf("flv: metadata: unsupported video codecType=%v", stream.Type()) err = fmt.Errorf("flv: metadata: unsupported video codecType=%v", stream.Type())
@ -83,21 +88,42 @@ func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) {
switch tag.Type { switch tag.Type {
case flvio.TAG_VIDEO: case flvio.TAG_VIDEO:
switch tag.AVCPacketType { if tag.IsExHeader {
case flvio.AVC_SEQHDR: if tag.FourCC == flvio.FOURCC_HEVC {
if !self.GotVideo { if tag.PacketType == flvio.PKTTYPE_SEQUENCE_START {
var stream h264parser.CodecData if !self.GotVideo {
if stream, err = h264parser.NewCodecDataFromAVCDecoderConfRecord(tag.Data); err != nil { var stream hevcparser.CodecData
err = fmt.Errorf("flv: h264 seqhdr invalid: %s", err.Error()) fmt.Printf("got HEVC sequence start:\n%s\n", hex.Dump(tag.Data))
return if stream, err = hevcparser.NewCodecDataFromHEVCDecoderConfRecord(tag.Data); err != nil {
err = fmt.Errorf("flv: hevc seqhdr invalid: %s", err.Error())
return
}
self.VideoStreamIdx = len(self.Streams)
self.Streams = append(self.Streams, stream)
self.GotVideo = true
}
} else if tag.PacketType == flvio.PKTTYPE_CODED_FRAMES || tag.PacketType == flvio.PKTTYPE_CODED_FRAMESX {
self.CacheTag(tag, timestamp)
} }
self.VideoStreamIdx = len(self.Streams)
self.Streams = append(self.Streams, stream)
self.GotVideo = true
} }
} else {
switch tag.AVCPacketType {
case flvio.AVC_SEQHDR:
if !self.GotVideo {
var stream h264parser.CodecData
fmt.Printf("got H264 sequence start:\n%s\n", hex.Dump(tag.Data))
if stream, err = h264parser.NewCodecDataFromAVCDecoderConfRecord(tag.Data); err != nil {
err = fmt.Errorf("flv: h264 seqhdr invalid: %s", err.Error())
return
}
self.VideoStreamIdx = len(self.Streams)
self.Streams = append(self.Streams, stream)
self.GotVideo = true
}
case flvio.AVC_NALU: case flvio.AVC_NALU:
self.CacheTag(tag, timestamp) self.CacheTag(tag, timestamp)
}
} }
case flvio.TAG_AUDIO: case flvio.TAG_AUDIO:
@ -166,8 +192,8 @@ func (self *Prober) TagToPacket(tag flvio.Tag, timestamp int32) (pkt av.Packet,
switch tag.Type { switch tag.Type {
case flvio.TAG_VIDEO: case flvio.TAG_VIDEO:
pkt.Idx = int8(self.VideoStreamIdx) pkt.Idx = int8(self.VideoStreamIdx)
switch tag.AVCPacketType { switch tag.PacketType {
case flvio.AVC_NALU: case flvio.PKTTYPE_CODED_FRAMES, flvio.PKTTYPE_CODED_FRAMESX:
ok = true ok = true
pkt.Data = tag.Data pkt.Data = tag.Data
pkt.CompositionTime = flvio.TsToTime(tag.CompositionTime) pkt.CompositionTime = flvio.TsToTime(tag.CompositionTime)
@ -219,6 +245,22 @@ func CodecDataToTag(stream av.CodecData) (_tag flvio.Tag, ok bool, err error) {
Data: h264.AVCDecoderConfRecordBytes(), Data: h264.AVCDecoderConfRecordBytes(),
FrameType: flvio.FRAME_KEY, FrameType: flvio.FRAME_KEY,
} }
fmt.Printf("set H264 sequence start:\n%v\n", hex.Dump(h264.AVCDecoderConfRecordBytes()))
ok = true
_tag = tag
case av.HEVC:
fmt.Printf("CodecDataToTag for HEVC\n")
hevc := stream.(hevcparser.CodecData)
tag := flvio.Tag{
Type: flvio.TAG_VIDEO,
IsExHeader: true,
PacketType: flvio.PKTTYPE_SEQUENCE_START,
FourCC: flvio.FOURCC_HEVC,
Data: hevc.HEVCDecoderConfRecordBytes(),
FrameType: flvio.FRAME_KEY,
}
fmt.Printf("set HEVC sequence start:\n%v\n", hex.Dump(hevc.HEVCDecoderConfRecordBytes()))
ok = true ok = true
_tag = tag _tag = tag
@ -272,6 +314,27 @@ func PacketToTag(pkt av.Packet, stream av.CodecData) (tag flvio.Tag, timestamp i
tag.FrameType = flvio.FRAME_INTER tag.FrameType = flvio.FRAME_INTER
} }
case av.HEVC:
//fmt.Printf("PacketToTag for HEVC\n")
tag = flvio.Tag{
Type: flvio.TAG_VIDEO,
IsExHeader: true,
PacketType: flvio.PKTTYPE_CODED_FRAMES,
CompositionTime: flvio.TimeToTs(pkt.CompositionTime),
FourCC: flvio.FOURCC_HEVC,
Data: pkt.Data,
}
if pkt.CompositionTime == 0 {
tag.PacketType = flvio.PKTTYPE_CODED_FRAMESX
}
if pkt.IsKeyFrame {
tag.FrameType = flvio.FRAME_KEY
} else {
tag.FrameType = flvio.FRAME_INTER
}
case av.AAC: case av.AAC:
tag = flvio.Tag{ tag = flvio.Tag{
Type: flvio.TAG_AUDIO, Type: flvio.TAG_AUDIO,

View File

@ -2,10 +2,11 @@ package flvio
import ( import (
"fmt" "fmt"
"github.com/datarhei/joy4/av"
"github.com/datarhei/joy4/utils/bits/pio"
"io" "io"
"time" "time"
"github.com/datarhei/joy4/av"
"github.com/datarhei/joy4/utils/bits/pio"
) )
func TsToTime(ts int32) time.Duration { func TsToTime(ts int32) time.Duration {
@ -60,6 +61,27 @@ const (
VIDEO_H264 = 7 VIDEO_H264 = 7
) )
const (
PKTTYPE_SEQUENCE_START = 0
PKTTYPE_CODED_FRAMES = 1
PKTTYPE_SEQUENCE_END = 2
PKTTYPE_CODED_FRAMESX = 3
PKTTYPE_METADATA = 4
PKTTYPE_MPEG2TS_SEQUENCE_START = 5
)
var (
FOURCC_AV1 = [4]byte{'a', 'v', '0', '1'}
FOURCC_VP9 = [4]byte{'v', 'p', '0', '9'}
FOURCC_HEVC = [4]byte{'h', 'v', 'c', '1'}
)
func FourCCToFloat(fourcc [4]byte) float64 {
i := int(fourcc[0])<<24 | int(fourcc[1])<<16 | int(fourcc[2])<<8 | int(fourcc[3])
return float64(i)
}
type Tag struct { type Tag struct {
/* /*
8 = Audio 8 = Audio
@ -126,14 +148,22 @@ type Tag struct {
AACPacketType uint8 AACPacketType uint8
/* /*
0: reserved
1: keyframe (for AVC, a seekable frame) 1: keyframe (for AVC, a seekable frame)
2: inter frame (for AVC, a non- seekable frame) 2: inter frame (for AVC, a non- seekable frame)
3: disposable inter frame (H.263 only) 3: disposable inter frame (H.263 only)
4: generated keyframe (reserved for server use only) 4: generated keyframe (reserved for server use only)
5: video info/command frame 5: video info/command frame
6: reserved
7: reserved
*/ */
FrameType uint8 FrameType uint8
/*
FrameType & 0b1000 != 0
*/
IsExHeader bool
/* /*
1: JPEG (currently unused) 1: JPEG (currently unused)
2: Sorenson H.263 2: Sorenson H.263
@ -145,6 +175,16 @@ type Tag struct {
*/ */
CodecID uint8 CodecID uint8
/*
0: PacketTypeSequenceStart
1: PacketTypeCodedFrames
2: PacketTypeSequenceEnd
3: PacketTypeCodedFramesX
4: PacketTypeMetadata
5: PacketTypeMPEG2TSSequenceStart
*/
PacketType uint8
/* /*
0: AVC sequence header 0: AVC sequence header
1: AVC NALU 1: AVC NALU
@ -154,18 +194,20 @@ type Tag struct {
CompositionTime int32 CompositionTime int32
FourCC [4]byte
Data []byte Data []byte
} }
func (self Tag) ChannelLayout() av.ChannelLayout { func (t Tag) ChannelLayout() av.ChannelLayout {
if self.SoundType == SOUND_MONO { if t.SoundType == SOUND_MONO {
return av.CH_MONO return av.CH_MONO
} else { } else {
return av.CH_STEREO return av.CH_STEREO
} }
} }
func (self *Tag) audioParseHeader(b []byte) (n int, err error) { func (t *Tag) audioParseHeader(b []byte) (n int, err error) {
if len(b) < n+1 { if len(b) < n+1 {
err = fmt.Errorf("audiodata: parse invalid") err = fmt.Errorf("audiodata: parse invalid")
return return
@ -173,97 +215,163 @@ func (self *Tag) audioParseHeader(b []byte) (n int, err error) {
flags := b[n] flags := b[n]
n++ n++
self.SoundFormat = flags >> 4 t.SoundFormat = flags >> 4
self.SoundRate = (flags >> 2) & 0x3 t.SoundRate = (flags >> 2) & 0x3
self.SoundSize = (flags >> 1) & 0x1 t.SoundSize = (flags >> 1) & 0x1
self.SoundType = flags & 0x1 t.SoundType = flags & 0x1
switch self.SoundFormat { switch t.SoundFormat {
case SOUND_AAC: case SOUND_AAC:
if len(b) < n+1 { if len(b) < n+1 {
err = fmt.Errorf("audiodata: parse invalid") err = fmt.Errorf("audiodata: parse invalid")
return return
} }
self.AACPacketType = b[n] t.AACPacketType = b[n]
n++ n++
} }
return return
} }
func (self Tag) audioFillHeader(b []byte) (n int) { func (t Tag) audioFillHeader(b []byte) (n int) {
var flags uint8 var flags uint8
flags |= self.SoundFormat << 4 flags |= t.SoundFormat << 4
flags |= self.SoundRate << 2 flags |= t.SoundRate << 2
flags |= self.SoundSize << 1 flags |= t.SoundSize << 1
flags |= self.SoundType flags |= t.SoundType
b[n] = flags b[n] = flags
n++ n++
switch self.SoundFormat { switch t.SoundFormat {
case SOUND_AAC: case SOUND_AAC:
b[n] = self.AACPacketType b[n] = t.AACPacketType
n++ n++
} }
return return
} }
func (self *Tag) videoParseHeader(b []byte) (n int, err error) { func (t *Tag) videoParseHeader(b []byte) (n int, err error) {
if len(b) < n+1 { if len(b) < n+1 {
err = fmt.Errorf("videodata: parse invalid") err = fmt.Errorf("videodata: parse invalid")
return return
} }
flags := b[n] flags := b[n]
self.FrameType = flags >> 4 t.FrameType = flags >> 4
self.CodecID = flags & 0xf t.CodecID = flags & 0b1111
//fmt.Printf("%#8b\n", flags)
n++ n++
if self.FrameType == FRAME_INTER || self.FrameType == FRAME_KEY { if (t.FrameType & 0b1000) != 0 {
t.IsExHeader = true
t.PacketType = t.CodecID
t.CodecID = 0
if t.PacketType != PKTTYPE_METADATA {
t.FrameType = t.FrameType & 0b0111
}
}
if !t.IsExHeader {
if t.FrameType == FRAME_INTER || t.FrameType == FRAME_KEY {
if len(b) < n+4 {
err = fmt.Errorf("videodata: parse invalid: neither interframe nor keyframe")
return
}
t.AVCPacketType = b[n]
switch t.AVCPacketType {
case AVC_SEQHDR:
t.PacketType = PKTTYPE_SEQUENCE_START
case AVC_NALU:
t.PacketType = PKTTYPE_CODED_FRAMES
case AVC_EOS:
t.PacketType = PKTTYPE_SEQUENCE_END
}
n++
t.CompositionTime = pio.I24BE(b[n:])
n += 3
}
} else {
if len(b) < n+4 { if len(b) < n+4 {
err = fmt.Errorf("videodata: parse invalid") err = fmt.Errorf("videodata: parse invalid: not enough bytes for the fourCC value")
return return
} }
self.AVCPacketType = b[n]
n++
self.CompositionTime = pio.I24BE(b[n:]) t.FourCC[0] = b[n]
t.FourCC[1] = b[n+1]
t.FourCC[2] = b[n+2]
t.FourCC[3] = b[n+3]
n += 4
t.CompositionTime = 0
if t.FourCC == FOURCC_HEVC {
if t.PacketType == PKTTYPE_CODED_FRAMES {
t.CompositionTime = pio.I24BE(b[n:])
n += 3
}
}
}
//fmt.Printf("parseVideoHeader: PacketType: %d\n%s\n", t.PacketType, hex.Dump(b[:n]))
return
}
func (t Tag) videoFillHeader(b []byte) (n int) {
if t.IsExHeader {
flags := t.FrameType<<4 | t.PacketType | 0b10000000
b[n] = flags
n++
b[n] = t.FourCC[0]
b[n+1] = t.FourCC[1]
b[n+2] = t.FourCC[2]
b[n+3] = t.FourCC[3]
n += 4
if t.FourCC == FOURCC_HEVC {
if t.PacketType == PKTTYPE_CODED_FRAMES {
pio.PutI24BE(b[n:], t.CompositionTime)
n += 3
}
}
} else {
flags := t.FrameType<<4 | t.CodecID
b[n] = flags
n++
b[n] = t.AVCPacketType
n++
pio.PutI24BE(b[n:], t.CompositionTime)
n += 3 n += 3
} }
//fmt.Printf("videoFillHeader: PacketType: %d\n%s\n", t.PacketType, hex.Dump(b[:n]))
return return
} }
func (self Tag) videoFillHeader(b []byte) (n int) { func (t Tag) FillHeader(b []byte) (n int) {
flags := self.FrameType<<4 | self.CodecID switch t.Type {
b[n] = flags
n++
b[n] = self.AVCPacketType
n++
pio.PutI24BE(b[n:], self.CompositionTime)
n += 3
return
}
func (self Tag) FillHeader(b []byte) (n int) {
switch self.Type {
case TAG_AUDIO: case TAG_AUDIO:
return self.audioFillHeader(b) return t.audioFillHeader(b)
case TAG_VIDEO: case TAG_VIDEO:
return self.videoFillHeader(b) return t.videoFillHeader(b)
} }
return return
} }
func (self *Tag) ParseHeader(b []byte) (n int, err error) { func (t *Tag) ParseHeader(b []byte) (n int, err error) {
switch self.Type { switch t.Type {
case TAG_AUDIO: case TAG_AUDIO:
return self.audioParseHeader(b) return t.audioParseHeader(b)
case TAG_VIDEO: case TAG_VIDEO:
return self.videoParseHeader(b) return t.videoParseHeader(b)
} }
return return

View File

@ -78,6 +78,7 @@ func (self *Server) handleConn(conn *Conn) (err error) {
} }
if conn.playing { if conn.playing {
fmt.Printf("play\n")
if self.HandlePlay != nil { if self.HandlePlay != nil {
self.HandlePlay(conn) self.HandlePlay(conn)
} }
@ -463,6 +464,8 @@ func (self *Conn) readConnect() (err error) {
return return
} }
fmt.Printf("readConnect: %+v\n", self.commandobj)
var ok bool var ok bool
var _app, _tcurl interface{} var _app, _tcurl interface{}
if _app, ok = self.commandobj["app"]; !ok { if _app, ok = self.commandobj["app"]; !ok {
@ -691,6 +694,8 @@ func (self *Conn) writeConnect(path string) (err error) {
return return
} }
fmt.Printf("writeConnect: app: %s\n", path)
// > connect("app") // > connect("app")
if Debug { if Debug {
fmt.Printf("rtmp: > connect('%s') host=%s\n", path, self.URL.Host) fmt.Printf("rtmp: > connect('%s') host=%s\n", path, self.URL.Host)
@ -705,6 +710,7 @@ func (self *Conn) writeConnect(path string) (err error) {
"audioCodecs": 4071, "audioCodecs": 4071,
"videoCodecs": 252, "videoCodecs": 252,
"videoFunction": 1, "videoFunction": 1,
"fourCcList": flvio.AMFArray{"av01", "vp09", "hvc1"},
}, },
); err != nil { ); err != nil {
return return
@ -984,14 +990,19 @@ func (self *Conn) WriteHeader(streams []av.CodecData) (err error) {
var metadata flvio.AMFMap = nil var metadata flvio.AMFMap = nil
metadata = self.GetMetaData() //metadata = self.GetMetaData()
fmt.Printf("WriteHeader\n")
if metadata == nil { if metadata == nil {
if metadata, err = flv.NewMetadataByStreams(streams); err != nil { if metadata, err = flv.NewMetadataByStreams(streams); err != nil {
fmt.Printf("WriteHeader error: %s\n", err.Error())
return return
} }
} }
fmt.Printf("WriteHeader: %#v\n", metadata)
// > onMetaData() // > onMetaData()
if err = self.writeDataMsg(5, self.avmsgsid, "onMetaData", metadata); err != nil { if err = self.writeDataMsg(5, self.avmsgsid, "onMetaData", metadata); err != nil {
return return
@ -1547,17 +1558,21 @@ func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid uint8, ms
if metaindex != -1 && metaindex < len(self.datamsgvals) { if metaindex != -1 && metaindex < len(self.datamsgvals) {
self.metadata = self.datamsgvals[metaindex].(flvio.AMFMap) self.metadata = self.datamsgvals[metaindex].(flvio.AMFMap)
fmt.Printf("onMetadata: %+v\n", self.metadata)
fmt.Printf("videocodecid: %#08x (%f)\n", int64(self.metadata["videocodecid"].(float64)), self.metadata["videocodecid"].(float64))
} }
case msgtypeidVideoMsg: case msgtypeidVideoMsg:
if len(msgdata) == 0 { if len(msgdata) == 0 {
return return
} }
//fmt.Printf("msgdata: %#08x\n", msgdata[:5])
tag := flvio.Tag{Type: flvio.TAG_VIDEO} tag := flvio.Tag{Type: flvio.TAG_VIDEO}
var n int var n int
if n, err = (&tag).ParseHeader(msgdata); err != nil { if n, err = (&tag).ParseHeader(msgdata); err != nil {
return return
} }
//fmt.Printf("tag: %+v\n", tag)
if !(tag.FrameType == flvio.FRAME_INTER || tag.FrameType == flvio.FRAME_KEY) { if !(tag.FrameType == flvio.FRAME_INTER || tag.FrameType == flvio.FRAME_KEY) {
return return
} }

View File

@ -33,6 +33,30 @@ func (self *GolombBitReader) ReadBits(n int) (res uint, err error) {
return return
} }
func (self *GolombBitReader) ReadBits32(n uint) (r uint32, err error) {
var t uint
for i := uint(0); i < n; i++ {
t, err = self.ReadBit()
if err != nil {
return
}
r = (r << 1) | uint32(t)
}
return
}
func (self *GolombBitReader) ReadBits64(n uint) (r uint64, err error) {
var t uint
for i := uint(0); i < n; i++ {
t, err = self.ReadBit()
if err != nil {
return
}
r = (r << 1) | uint64(t)
}
return
}
func (self *GolombBitReader) ReadExponentialGolombCode() (res uint, err error) { func (self *GolombBitReader) ReadExponentialGolombCode() (res uint, err error) {
i := 0 i := 0
for { for {