|
|
|
@ -9,11 +9,11 @@
|
|
|
|
|
package hevc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/hex"
|
|
|
|
|
"errors"
|
|
|
|
|
|
|
|
|
|
"github.com/q191201771/naza/pkg/nazabits"
|
|
|
|
|
|
|
|
|
|
"github.com/q191201771/naza/pkg/bele"
|
|
|
|
|
"github.com/q191201771/naza/pkg/nazalog"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// AnnexB
|
|
|
|
@ -44,6 +44,28 @@ var (
|
|
|
|
|
NALUTypeSEISuffix uint8 = 40 // 0x28
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Context struct {
|
|
|
|
|
// unsigned int(8) configurationVersion = 1;
|
|
|
|
|
configurationVersion uint8
|
|
|
|
|
// unsigned int(2) general_profile_space;
|
|
|
|
|
// unsigned int(1) general_tier_flag;
|
|
|
|
|
// unsigned int(5) general_profile_idc;
|
|
|
|
|
generalProfileSpace uint8
|
|
|
|
|
generalTierFlag uint8
|
|
|
|
|
generalProfileIDC uint8
|
|
|
|
|
// unsigned int(32) general_profile_compatibility_flags;
|
|
|
|
|
generalProfileCompatibilityFlags uint32
|
|
|
|
|
// unsigned int(48) general_constraint_indicator_flags;
|
|
|
|
|
generalConstraintIndicatorFlags uint64
|
|
|
|
|
generalLevelIDC uint8
|
|
|
|
|
|
|
|
|
|
numTemporalLayers uint8
|
|
|
|
|
|
|
|
|
|
chromaFormat uint32
|
|
|
|
|
bitDepthLumaMinus8 uint32
|
|
|
|
|
bitDepthChromaMinus8 uint32
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ParseNALUTypeReadable(v uint8) string {
|
|
|
|
|
b, ok := NALUTypeMapping[ParseNALUType(v)]
|
|
|
|
|
if !ok {
|
|
|
|
@ -92,14 +114,14 @@ func ParseVPSSPSPPSFromSeqHeader(payload []byte) (vps, sps, pps []byte, err erro
|
|
|
|
|
if payload[0] != 0x1c || payload[1] != 0x00 || payload[2] != 0 || payload[3] != 0 || payload[4] != 0 {
|
|
|
|
|
return nil, nil, nil, ErrHEVC
|
|
|
|
|
}
|
|
|
|
|
nazalog.Debugf("%s", hex.Dump(payload))
|
|
|
|
|
//nazalog.Debugf("%s", hex.Dump(payload))
|
|
|
|
|
|
|
|
|
|
if len(payload) < 33 {
|
|
|
|
|
return nil, nil, nil, ErrHEVC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
index := 27
|
|
|
|
|
if numOfArrays := payload[index]; numOfArrays != 3 {
|
|
|
|
|
if numOfArrays := payload[index]; numOfArrays != 3 && numOfArrays != 4 {
|
|
|
|
|
return nil, nil, nil, ErrHEVC
|
|
|
|
|
}
|
|
|
|
|
index++
|
|
|
|
@ -152,3 +174,330 @@ func ParseVPSSPSPPSFromSeqHeader(payload []byte) (vps, sps, pps []byte, err erro
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BuildSeqHeaderFromVPSSPSPPS(vps, sps, pps []byte) ([]byte, error) {
|
|
|
|
|
var sh []byte
|
|
|
|
|
sh = make([]byte, 1024)
|
|
|
|
|
sh[0] = 0x1c
|
|
|
|
|
sh[1] = 0x0
|
|
|
|
|
sh[2] = 0x0
|
|
|
|
|
sh[3] = 0x0
|
|
|
|
|
sh[4] = 0x0
|
|
|
|
|
|
|
|
|
|
// unsigned int(8) configurationVersion = 1;
|
|
|
|
|
sh[5] = 0x1
|
|
|
|
|
|
|
|
|
|
ctx := newContext()
|
|
|
|
|
if err := ParseVPS(vps, ctx); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if err := ParseSPS(sps, ctx); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// unsigned int(2) general_profile_space;
|
|
|
|
|
// unsigned int(1) general_tier_flag;
|
|
|
|
|
// unsigned int(5) general_profile_idc;
|
|
|
|
|
sh[6] = ctx.generalProfileSpace<<6 | ctx.generalTierFlag<<5 | ctx.generalProfileIDC
|
|
|
|
|
// unsigned int(32) general_profile_compatibility_flags
|
|
|
|
|
bele.BEPutUint32(sh[7:], ctx.generalProfileCompatibilityFlags)
|
|
|
|
|
// unsigned int(48) general_constraint_indicator_flags
|
|
|
|
|
bele.BEPutUint32(sh[11:], uint32(ctx.generalConstraintIndicatorFlags>>16))
|
|
|
|
|
bele.BEPutUint16(sh[15:], uint16(ctx.generalConstraintIndicatorFlags))
|
|
|
|
|
sh[17] = ctx.generalLevelIDC
|
|
|
|
|
|
|
|
|
|
return sh, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ParseVPS(vps []byte, ctx *Context) error {
|
|
|
|
|
br := nazabits.NewBitReader(vps)
|
|
|
|
|
|
|
|
|
|
// type
|
|
|
|
|
if _, err := br.ReadBits8(8); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// skip
|
|
|
|
|
// vps_video_parameter_set_id u(4)
|
|
|
|
|
// vps_reserved_three_2bits u(2)
|
|
|
|
|
// vps_max_layers_minus1 u(6)
|
|
|
|
|
if _, err := br.ReadBits16(12); err != nil {
|
|
|
|
|
return ErrHEVC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vpsMaxSubLayersMinus1, err := br.ReadBits8(3)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return ErrHEVC
|
|
|
|
|
}
|
|
|
|
|
if vpsMaxSubLayersMinus1+1 > ctx.numTemporalLayers {
|
|
|
|
|
ctx.numTemporalLayers = vpsMaxSubLayersMinus1 + 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// skip
|
|
|
|
|
// vps_temporal_id_nesting_flag u(1)
|
|
|
|
|
// vps_reserved_0xffff_16bits u(16)
|
|
|
|
|
if _, err := br.ReadBits32(17); err != nil {
|
|
|
|
|
return ErrHEVC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return parsePTL(br, ctx, vpsMaxSubLayersMinus1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ParseSPS(sps []byte, ctx *Context) error {
|
|
|
|
|
var err error
|
|
|
|
|
br := nazabits.NewBitReader(sps)
|
|
|
|
|
|
|
|
|
|
// type
|
|
|
|
|
if _, err = br.ReadBits8(8); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sps_video_parameter_set_id
|
|
|
|
|
if _, err = br.ReadBits8(4); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spsMaxSubLayersMinus1, err := br.ReadBits8(3)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err := br.ReadBit(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = parsePTL(br, ctx, spsMaxSubLayersMinus1); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ctx.chromaFormat, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if ctx.chromaFormat == 3 {
|
|
|
|
|
if _, err = br.ReadBit(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conformanceWindowFlag, err := br.ReadBit()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if conformanceWindowFlag != 0 {
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ctx.bitDepthLumaMinus8, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if ctx.bitDepthChromaMinus8, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
_, err = br.ReadGolomb()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
spsSubLayerOrderingInfoPresentFlag, err := br.ReadBit()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
var i uint8
|
|
|
|
|
if spsSubLayerOrderingInfoPresentFlag != 0 {
|
|
|
|
|
i = 0
|
|
|
|
|
} else {
|
|
|
|
|
i = spsMaxSubLayersMinus1
|
|
|
|
|
}
|
|
|
|
|
for ; i <= spsMaxSubLayersMinus1; i++ {
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if _, err = br.ReadGolomb(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parsePTL(br nazabits.BitReader, ctx *Context, maxSubLayersMinus1 uint8) error {
|
|
|
|
|
var err error
|
|
|
|
|
var ptl Context
|
|
|
|
|
if ptl.generalProfileSpace, err = br.ReadBits8(2); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if ptl.generalTierFlag, err = br.ReadBit(); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if ptl.generalProfileIDC, err = br.ReadBits8(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.ReadBits8(8); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
updatePTL(ctx, &ptl)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
subLayerProfilePresentFlag := make([]uint8, maxSubLayersMinus1)
|
|
|
|
|
subLayerLevelPresentFlag := make([]uint8, maxSubLayersMinus1)
|
|
|
|
|
for i := uint8(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.ReadBits8(2); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := uint8(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.ReadBits8(8); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func updatePTL(ctx, ptl *Context) {
|
|
|
|
|
ctx.generalProfileSpace = ptl.generalProfileSpace
|
|
|
|
|
|
|
|
|
|
if ctx.generalTierFlag < ptl.generalTierFlag {
|
|
|
|
|
ctx.generalLevelIDC = ptl.generalLevelIDC
|
|
|
|
|
} else {
|
|
|
|
|
if ptl.generalLevelIDC > ctx.generalLevelIDC {
|
|
|
|
|
ctx.generalLevelIDC = ptl.generalLevelIDC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.generalTierFlag = ptl.generalTierFlag
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ptl.generalProfileIDC > ctx.generalProfileIDC {
|
|
|
|
|
ctx.generalProfileIDC = ptl.generalProfileIDC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.generalProfileCompatibilityFlags &= ptl.generalProfileCompatibilityFlags
|
|
|
|
|
|
|
|
|
|
ctx.generalConstraintIndicatorFlags &= ptl.generalConstraintIndicatorFlags
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newContext() *Context {
|
|
|
|
|
return &Context{
|
|
|
|
|
configurationVersion: 1,
|
|
|
|
|
//hvcc->lengthSizeMinusOne = 3; // 4 bytes
|
|
|
|
|
generalProfileCompatibilityFlags: 0xffffffff,
|
|
|
|
|
generalConstraintIndicatorFlags: 0xffffffffffff,
|
|
|
|
|
//hvcc->min_spatial_segmentation_idc = MAX_SPATIAL_SEGMENTATION + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//func skipScalingListData(br nazabits.BitReader) error {
|
|
|
|
|
// var numCoeffs int
|
|
|
|
|
// var i int
|
|
|
|
|
//
|
|
|
|
|
// for i = 0; i < 4; i++ {
|
|
|
|
|
// k := 6
|
|
|
|
|
// if i == 3 {
|
|
|
|
|
// k = 2
|
|
|
|
|
// }
|
|
|
|
|
// for j := 0; j < k; j++ {
|
|
|
|
|
// f, err := br.ReadBit()
|
|
|
|
|
// if err != nil {
|
|
|
|
|
// return err
|
|
|
|
|
// }
|
|
|
|
|
// if f != 0 {
|
|
|
|
|
// if _, err := br.ReadGolomb(); err != nil {
|
|
|
|
|
// return err
|
|
|
|
|
// }
|
|
|
|
|
// } else {
|
|
|
|
|
// numCoeffs = 1 << (4+(uint32(i)<<1))
|
|
|
|
|
// if numCoeffs > 64 {
|
|
|
|
|
// numCoeffs = 64
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// if i > 1 {
|
|
|
|
|
// if _, err := br.ReadGolomb(); err != nil {
|
|
|
|
|
// return err
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// for i := 0; i < numCoeffs; i++ {
|
|
|
|
|
// if _, err := br.ReadGolomb(); err != nil {
|
|
|
|
|
// return err
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// return nil
|
|
|
|
|
//}
|
|
|
|
|