package h264dec import ( "math" "bitbucket.org/ausocean/av/codec/h264/h264dec/bits" "github.com/pkg/errors" ) const ( NaCtxId = 10000 NA_SUFFIX = -1 MbAddrNotAvailable = 10000 ) // G.7.4.3.4 via G.7.3.3.4 via 7.3.2.13 for NalUnitType 20 or 21 // refLayerMbWidthC is equal to MbWidthC for the reference layer representation func RefMbW(chromaFlag, refLayerMbWidthC int) int { if chromaFlag == 0 { return 16 } return refLayerMbWidthC } // refLayerMbHeightC is equal to MbHeightC for the reference layer representation func RefMbH(chromaFlag, refLayerMbHeightC int) int { if chromaFlag == 0 { return 16 } return refLayerMbHeightC } func XOffset(xRefMin16, refMbW int) int { return (((xRefMin16 - 64) >> 8) << 4) - (refMbW >> 1) } func YOffset(yRefMin16, refMbH int) int { return (((yRefMin16 - 64) >> 8) << 4) - (refMbH >> 1) } func MbWidthC(sps *SPS) int { mbWidthC := 16 / SubWidthC(sps) if sps.ChromaFormatIDC == chromaMonochrome || sps.SeparateColorPlaneFlag { mbWidthC = 0 } return mbWidthC } func MbHeightC(sps *SPS) int { mbHeightC := 16 / SubHeightC(sps) if sps.ChromaFormatIDC == chromaMonochrome || sps.SeparateColorPlaneFlag { mbHeightC = 0 } return mbHeightC } // G.8.6.2.2.2 func Xr(x, xOffset, refMbW int) int { return (x + xOffset) % refMbW } func Yr(y, yOffset, refMbH int) int { return (y + yOffset) % refMbH } // G.8.6.2.2.2 func Xd(xr, refMbW int) int { if xr >= refMbW/2 { return xr - refMbW } return xr + 1 } func Yd(yr, refMbH int) int { if yr >= refMbH/2 { return yr - refMbH } return yr + 1 } func Ya(yd, refMbH, signYd int) int { return yd - (refMbH/2+1)*signYd } // 6.4.11.1 func MbAddr(xd, yd, predPartWidth int) { // TODO: Unfinished var n string if xd == -1 && yd == 0 { n = "A" } if xd == 0 && yd == -1 { n = "B" } if xd == predPartWidth && yd == -1 { n = "C" } if xd == -1 && yd == -1 { n = "D" } _ = n } func CondTermFlag(mbAddr, mbSkipFlag int) int { if mbAddr == MbAddrNotAvailable || mbSkipFlag == 1 { return 0 } return 1 } // s9.3.3 p 278: Returns the value of the syntax element func (bin *Binarization) Decode(sliceContext *SliceContext, b *bits.BitReader, rbsp []byte) {} // 9.3.3.1.1 : returns ctxIdxInc func Decoder9_3_3_1_1_1(condTermFlagA, condTermFlagB int) int { return condTermFlagA + condTermFlagB } // 9-5 // 7-30 p 112 func SliceQPy(pps *PPS, header *SliceHeader) int { return 26 + pps.PicInitQpMinus26 + header.SliceQpDelta } // 9-5 func PreCtxState(m, n, sliceQPy int) int { // slicQPy-subY return Clip3(1, 126, ((m*Clip3(0, 51, sliceQPy))>>4)+n) } func Clip1y(x, bitDepthY int) int { return Clip3(0, (1< y { return y } return z } type CABAC struct { PStateIdx int ValMPS int Context *SliceContext } // table 9-1 func initCabac(binarization *Binarization, context *SliceContext) *CABAC { var valMPS, pStateIdx int // TODO: When to use prefix, when to use suffix? ctxIdx := CtxIdx( binarization.binIdx, binarization.MaxBinIdxCtx.Prefix, binarization.CtxIdxOffset.Prefix) mn := MNVars[ctxIdx] preCtxState := PreCtxState(mn[0].M, mn[0].N, SliceQPy(context.PPS, context.Header)) if preCtxState <= 63 { pStateIdx = 63 - preCtxState valMPS = 0 } else { pStateIdx = preCtxState - 64 valMPS = 1 } _ = pStateIdx _ = valMPS // Initialization of context variables // Initialization of decoding engine return &CABAC{ PStateIdx: pStateIdx, ValMPS: valMPS, Context: context, } } // Binarizations for macroblock types in slice types. var ( // binOfIMBTypes provides binarization strings for values of macroblock // type in I slices as defined in table 9-36 of the specifications. binOfIMBTypes = [numOfIMBTypes][]int{ 0: {0}, 1: {1, 0, 0, 0, 0, 0}, 2: {1, 0, 0, 0, 0, 1}, 3: {1, 0, 0, 0, 1, 0}, 4: {1, 0, 0, 0, 1, 1}, 5: {1, 0, 0, 1, 0, 0, 0}, 6: {1, 0, 0, 1, 0, 0, 1}, 7: {1, 0, 0, 1, 0, 1, 0}, 8: {1, 0, 0, 1, 0, 1, 1}, 9: {1, 0, 0, 1, 1, 0, 0}, 10: {1, 0, 0, 1, 1, 0, 1}, 11: {1, 0, 0, 1, 1, 1, 0}, 12: {1, 0, 0, 1, 1, 1, 1}, 13: {1, 0, 1, 0, 0, 0}, 14: {1, 0, 1, 0, 0, 1}, 15: {1, 0, 1, 0, 1, 0}, 16: {1, 0, 1, 0, 1, 1}, 17: {1, 0, 1, 1, 0, 0, 0}, 18: {1, 0, 1, 1, 0, 0, 1}, 19: {1, 0, 1, 1, 0, 1, 0}, 20: {1, 0, 1, 1, 0, 1, 1}, 21: {1, 0, 1, 1, 1, 0, 0}, 22: {1, 0, 1, 1, 1, 0, 1}, 23: {1, 0, 1, 1, 1, 1, 0}, 24: {1, 0, 1, 1, 1, 1, 1}, 25: {1, 1}, } // binOfPOrSPMBTypes provides binarization strings for values of macroblock // type in P or SP slices as defined in table 9-37 of the specifications. // NB: binarization of macroblock types 5 to 30 is 1 and not included here. binOfPOrSPMBTypes = [5][]int{ 0: {0, 0, 0}, 1: {0, 1, 1}, 2: {0, 1, 0}, 3: {0, 0, 1}, 4: {}, } // binOfBMBTypes provides binarization strings for values of macroblock // type in B slice as defined in table 9-37 of the specifications. // NB: binarization of macroblock types 23 to 48 is 111101 and is not // included here. binOfBMBTypes = [23][]int{ 0: {0}, 1: {1, 0, 0}, 2: {1, 0, 1}, 3: {1, 1, 0, 0, 0, 0}, 4: {1, 1, 0, 0, 0, 1}, 5: {1, 1, 0, 0, 1, 0}, 6: {1, 1, 0, 0, 1, 1}, 7: {1, 1, 0, 1, 0, 0}, 8: {1, 1, 0, 1, 0, 1}, 9: {1, 1, 0, 1, 1, 0}, 10: {1, 1, 0, 1, 1, 1}, 11: {1, 1, 1, 1, 1, 0}, 12: {1, 1, 1, 0, 0, 0, 0}, 13: {1, 1, 1, 0, 0, 0, 1}, 14: {1, 1, 1, 0, 0, 1, 0}, 15: {1, 1, 1, 0, 0, 1, 1}, 16: {1, 1, 1, 0, 1, 0, 0}, 17: {1, 1, 1, 0, 1, 0, 1}, 18: {1, 1, 1, 0, 1, 1, 0}, 19: {1, 1, 1, 0, 1, 1, 1}, 20: {1, 1, 1, 1, 0, 0, 0}, 21: {1, 1, 1, 1, 0, 0, 1}, 22: {1, 1, 1, 1, 1, 1}, } ) // Binarizations for sub-macroblock types in slice types. var ( // binOfPorSPSubMBTypes provides binarization strings for values of sub-macroblock // type in P or SP slices as defined in table 9-38 of the specifications. binOfPOrSPSubMBTypes = [4][]int{ 0: {1}, 1: {0, 0}, 2: {0, 1, 1}, 3: {0, 1, 0}, } // binOfBSubMBTypes provides binarization strings for values of sub-macroblock // type in B slices as defined in table 9-38 of the specifications. binOfBSubMBTypes = [numOfBSubMBTypes][]int{ 0: {1}, 1: {1, 0, 0}, 2: {1, 0, 1}, 3: {1, 1, 0, 0, 0}, 4: {1, 1, 0, 0, 1}, 5: {1, 1, 0, 1, 0}, 6: {1, 1, 0, 1, 1}, 7: {1, 1, 1, 0, 0, 0}, 8: {1, 1, 1, 0, 0, 1}, 9: {1, 1, 1, 0, 1, 0}, 10: {1, 1, 1, 0, 1, 1}, 11: {1, 1, 1, 1, 0}, 12: {1, 1, 1, 1, 1}, } ) // Errors used by mbTypeBinarization. var ( errBadMbType = errors.New("macroblock type outside of valid range") errBadMbSliceType = errors.New("bad slice type for macroblock") ) // mbTypeBinarization returns the macroblock type binarization for the given // macroblock type value and slice type using the process defined in section // 9.3.2.5 of the specifications. func mbTypeBinarization(v, slice int) ([]int, error) { switch slice { case sliceTypeI: if v < minIMbType || v > maxIMbType { return nil, errBadMbType } return binOfIMBTypes[v], nil case sliceTypeSI: if v < minSIMbType || v > maxSIMbType { return nil, errBadMbType } if v == sliceTypeSI { return []int{0}, nil } return append([]int{1}, binOfIMBTypes[v-1]...), nil case sliceTypeP, sliceTypeSP: if v < minPOrSPMbType || v > maxPOrSPMbType || v == P8x8ref0 { return nil, errBadMbType } if v < 5 { return binOfPOrSPMBTypes[v], nil } return append([]int{1}, binOfIMBTypes[v-5]...), nil case sliceTypeB: if v < minBMbType || v > maxBMbType { return nil, errBadMbType } if v < 23 { return binOfBMBTypes[v], nil } return append([]int{1, 1, 1, 1, 0, 1}, binOfIMBTypes[v-23]...), nil default: return nil, errBadMbSliceType } } // Error used by subMbTypeBinarization. var errBadSubMbSliceType = errors.New("bad slice type for sub-macroblock") // subMbTypeBinarization returns the binarization of a sub-macroblock type // given the slice in which it is in using the process defined in section // 9.3.2.5 of the specifications. func subMbTypeBinarization(v, slice int) ([]int, error) { switch slice { case sliceTypeP, sliceTypeSP: if v < minPOrSPSubMbType || v > maxPOrSPSubMbType { return nil, errBadMbType } return binOfPOrSPSubMBTypes[v], nil case sliceTypeB: if v < minBSubMbType || v > maxBSubMbType { return nil, errBadMbType } return binOfBSubMBTypes[v], nil default: return nil, errBadSubMbSliceType } } // Table 9-34 type MaxBinIdxCtx struct { // When false, Prefix is the MaxBinIdxCtx IsPrefixSuffix bool Prefix, Suffix int } type CtxIdxOffset struct { // When false, Prefix is the MaxBinIdxCtx IsPrefixSuffix bool Prefix, Suffix int } // Table 9-34 type Binarization struct { SyntaxElement string BinarizationType MaxBinIdxCtx CtxIdxOffset UseDecodeBypass int // TODO: Why are these private but others aren't? binIdx int binString []int } type BinarizationType struct { PrefixSuffix bool FixedLength bool Unary bool TruncatedUnary bool CMax bool // 9.3.2.3 UEGk bool CMaxValue int } // 9.3.2.5 func NewBinarization(syntaxElement string, data *SliceData) *Binarization { sliceTypeName := data.SliceTypeName logger.Printf("debug: binarization of %s in sliceType %s\n", syntaxElement, sliceTypeName) binarization := &Binarization{SyntaxElement: syntaxElement} switch syntaxElement { case "CodedBlockPattern": binarization.BinarizationType = BinarizationType{PrefixSuffix: true} binarization.MaxBinIdxCtx = MaxBinIdxCtx{IsPrefixSuffix: true, Prefix: 3, Suffix: 1} binarization.CtxIdxOffset = CtxIdxOffset{IsPrefixSuffix: true, Prefix: 73, Suffix: 77} case "IntraChromaPredMode": binarization.BinarizationType = BinarizationType{ TruncatedUnary: true, CMax: true, CMaxValue: 3} binarization.MaxBinIdxCtx = MaxBinIdxCtx{Prefix: 1} binarization.CtxIdxOffset = CtxIdxOffset{Prefix: 64} case "MbQpDelta": binarization.BinarizationType = BinarizationType{} binarization.MaxBinIdxCtx = MaxBinIdxCtx{Prefix: 2} binarization.CtxIdxOffset = CtxIdxOffset{Prefix: 60} case "MvdLnEnd0": binarization.UseDecodeBypass = 1 binarization.BinarizationType = BinarizationType{UEGk: true} binarization.MaxBinIdxCtx = MaxBinIdxCtx{IsPrefixSuffix: true, Prefix: 4, Suffix: NA_SUFFIX} binarization.CtxIdxOffset = CtxIdxOffset{ IsPrefixSuffix: true, Prefix: 40, Suffix: NA_SUFFIX, } case "MvdLnEnd1": binarization.UseDecodeBypass = 1 binarization.BinarizationType = BinarizationType{UEGk: true} binarization.MaxBinIdxCtx = MaxBinIdxCtx{ IsPrefixSuffix: true, Prefix: 4, Suffix: NA_SUFFIX, } binarization.CtxIdxOffset = CtxIdxOffset{ IsPrefixSuffix: true, Prefix: 47, Suffix: NA_SUFFIX, } // 9.3.2.5 case "MbType": logger.Printf("debug: \tMbType is %s\n", data.MbTypeName) switch sliceTypeName { case "SI": binarization.BinarizationType = BinarizationType{PrefixSuffix: true} binarization.MaxBinIdxCtx = MaxBinIdxCtx{IsPrefixSuffix: true, Prefix: 0, Suffix: 6} binarization.CtxIdxOffset = CtxIdxOffset{IsPrefixSuffix: true, Prefix: 0, Suffix: 3} case "I": binarization.BinarizationType = BinarizationType{} binarization.MaxBinIdxCtx = MaxBinIdxCtx{Prefix: 6} binarization.CtxIdxOffset = CtxIdxOffset{Prefix: 3} case "SP": fallthrough case "P": binarization.BinarizationType = BinarizationType{PrefixSuffix: true} binarization.MaxBinIdxCtx = MaxBinIdxCtx{IsPrefixSuffix: true, Prefix: 2, Suffix: 5} binarization.CtxIdxOffset = CtxIdxOffset{IsPrefixSuffix: true, Prefix: 14, Suffix: 17} } case "MbFieldDecodingFlag": binarization.BinarizationType = BinarizationType{ FixedLength: true, CMax: true, CMaxValue: 1} binarization.MaxBinIdxCtx = MaxBinIdxCtx{Prefix: 0} binarization.CtxIdxOffset = CtxIdxOffset{Prefix: 70} case "PrevIntra4x4PredModeFlag": fallthrough case "PrevIntra8x8PredModeFlag": binarization.BinarizationType = BinarizationType{FixedLength: true, CMax: true, CMaxValue: 1} binarization.MaxBinIdxCtx = MaxBinIdxCtx{Prefix: 0} binarization.CtxIdxOffset = CtxIdxOffset{Prefix: 68} case "RefIdxL0": fallthrough case "RefIdxL1": binarization.BinarizationType = BinarizationType{Unary: true} binarization.MaxBinIdxCtx = MaxBinIdxCtx{Prefix: 2} binarization.CtxIdxOffset = CtxIdxOffset{Prefix: 54} case "RemIntra4x4PredMode": fallthrough case "RemIntra8x8PredMode": binarization.BinarizationType = BinarizationType{FixedLength: true, CMax: true, CMaxValue: 7} binarization.MaxBinIdxCtx = MaxBinIdxCtx{Prefix: 0} binarization.CtxIdxOffset = CtxIdxOffset{Prefix: 69} case "TransformSize8x8Flag": binarization.BinarizationType = BinarizationType{FixedLength: true, CMax: true, CMaxValue: 1} binarization.MaxBinIdxCtx = MaxBinIdxCtx{Prefix: 0} binarization.CtxIdxOffset = CtxIdxOffset{Prefix: 399} } return binarization } func (b *Binarization) IsBinStringMatch(bits []int) bool { for i, _b := range bits { if b.binString[i] != _b { return false } } return len(b.binString) == len(bits) } // 9.3.1.2: output is codIRange and codIOffset func initDecodingEngine(bitReader *bits.BitReader) (int, int, error) { logger.Printf("debug: initializing arithmetic decoding engine\n") codIRange := 510 codIOffset, err := bitReader.ReadBits(9) if err != nil { return 0, 0, errors.Wrap(err, "could not read codIOffset") } logger.Printf("debug: codIRange: %d :: codIOffsset: %d\n", codIRange, codIOffset) return codIRange, int(codIOffset), nil } // 9.3.3.2: output is value of the bin func NewArithmeticDecoding(context *SliceContext, binarization *Binarization, ctxIdx, codIRange, codIOffset int) (ArithmeticDecoding, error) { a := ArithmeticDecoding{Context: context, Binarization: binarization} logger.Printf("debug: decoding bypass %d, for ctx %d\n", binarization.UseDecodeBypass, ctxIdx) // TODO: Implement if binarization.UseDecodeBypass == 1 { // TODO: 9.3.3.2.3 : DecodeBypass() var err error codIOffset, a.BinVal, err = a.DecodeBypass(context.Slice.Data, codIRange, codIOffset) if err != nil { return ArithmeticDecoding{}, errors.Wrap(err, "error from DecodeBypass getting codIOffset and BinVal") } } else if binarization.UseDecodeBypass == 0 && ctxIdx == 276 { // TODO: 9.3.3.2.4 : DecodeTerminate() } else { // TODO: 9.3.3.2.1 : DecodeDecision() } a.BinVal = -1 return a, nil } // 9.3.3.2.3 // Invoked when bypassFlag is equal to 1 func (a ArithmeticDecoding) DecodeBypass(sliceData *SliceData, codIRange, codIOffset int) (int, int, error) { // Decoded value binVal codIOffset = codIOffset << uint(1) // TODO: Concurrency check // TODO: Possibly should be codIOffset | ReadOneBit shift, err := sliceData.BitReader.ReadBits(1) if err != nil { return 0, 0, errors.Wrap(err, "coult not read shift bit from sliceData.") } codIOffset = codIOffset << uint(shift) if codIOffset >= codIRange { a.BinVal = 1 codIOffset -= codIRange } else { a.BinVal = 0 } return codIOffset, a.BinVal, nil } // 9.3.3.2.4 // Decodes endOfSliceFlag and I_PCM // Returns codIRange, codIOffSet, decoded value of binVal func (a ArithmeticDecoding) DecodeTerminate(sliceData *SliceData, codIRange, codIOffset int) (int, int, int, error) { codIRange -= 2 if codIOffset >= codIRange { a.BinVal = 1 // Terminate CABAC decoding, last bit inserted into codIOffset is = 1 // this is now also the rbspStopOneBit // TODO: How is this denoting termination? return codIRange, codIOffset, a.BinVal, nil } a.BinVal = 0 var err error codIRange, codIOffset, err = a.RenormD(sliceData, codIRange, codIOffset) if err != nil { return 0, 0, 0, errors.Wrap(err, "error from RenormD") } return codIRange, codIOffset, a.BinVal, nil } // 9.3.3.2.2 Renormalization process of ADecEngine // Returns codIRange, codIOffset func (a ArithmeticDecoding) RenormD(sliceData *SliceData, codIRange, codIOffset int) (int, int, error) { if codIRange >= 256 { return codIRange, codIOffset, nil } codIRange = codIRange << uint(1) codIOffset = codIOffset << uint(1) bit, err := sliceData.BitReader.ReadBits(1) if err != nil { return 0, 0, errors.Wrap(err, "could not read bit from sliceData") } codIOffset = codIOffset | int(bit) return a.RenormD(sliceData, codIRange, codIOffset) } type ArithmeticDecoding struct { Context *SliceContext Binarization *Binarization BinVal int } // 9.3.3.2.1 // returns: binVal, updated codIRange, updated codIOffset func (a ArithmeticDecoding) BinaryDecision(ctxIdx, codIRange, codIOffset int) (int, int, int, error) { var binVal int cabac := initCabac(a.Binarization, a.Context) // Derivce codIRangeLPS qCodIRangeIdx := (codIRange >> 6) & 3 pStateIdx := cabac.PStateIdx codIRangeLPS, err := retCodIRangeLPS(pStateIdx, qCodIRangeIdx) if err != nil { return 0, 0, 0, errors.Wrap(err, "could not get codIRangeLPS from retCodIRangeLPS") } codIRange = codIRange - codIRangeLPS if codIOffset >= codIRange { binVal = 1 - cabac.ValMPS codIOffset -= codIRange codIRange = codIRangeLPS } else { binVal = cabac.ValMPS } // TODO: Do StateTransition and then RenormD happen here? See: 9.3.3.2.1 return binVal, codIRange, codIOffset, nil } // 9.3.3.2.1.1 // Returns: pStateIdx, valMPS func (c *CABAC) StateTransitionProcess(binVal int) { if binVal == c.ValMPS { c.PStateIdx = stateTransxTab[c.PStateIdx].TransIdxMPS } else { if c.PStateIdx == 0 { c.ValMPS = 1 - c.ValMPS } c.PStateIdx = stateTransxTab[c.PStateIdx].TransIdxLPS } } var ctxIdxLookup = map[int]map[int]int{ 3: {0: NaCtxId, 1: 276, 2: 3, 3: 4, 4: NaCtxId, 5: NaCtxId}, 14: {0: 0, 1: 1, 2: NaCtxId}, 17: {0: 0, 1: 276, 2: 1, 3: 2, 4: NaCtxId}, 27: {0: NaCtxId, 1: 3, 2: NaCtxId}, 32: {0: 0, 1: 276, 2: 1, 3: 2, 4: NaCtxId}, 36: {2: NaCtxId, 3: 3, 4: 3, 5: 3}, 40: {0: NaCtxId}, 47: {0: NaCtxId, 1: 3, 2: 4, 3: 5}, 54: {0: NaCtxId, 1: 4}, 64: {0: NaCtxId, 1: 3, 2: 3}, 69: {0: 0, 1: 0, 2: 0}, 77: {0: NaCtxId, 1: NaCtxId}, } // 9.3.3.1 // Returns ctxIdx func CtxIdx(binIdx, maxBinIdxCtx, ctxIdxOffset int) int { ctxIdx := NaCtxId // table 9-39 c, ok := ctxIdxLookup[ctxIdxOffset] if ok { v, ok := c[binIdx] if ok { return v } } switch ctxIdxOffset { case 0: if binIdx != 0 { return NaCtxId } // 9.3.3.1.1.3 case 3: return 7 case 11: if binIdx != 0 { return NaCtxId } // 9.3.3.1.1.3 case 14: if binIdx > 2 { return NaCtxId } case 17: return 3 case 21: if binIdx < 3 { ctxIdx = binIdx } else { return NaCtxId } case 24: // 9.3.3.1.1.1 case 27: return 5 case 32: return 3 case 36: if binIdx == 0 || binIdx == 1 { ctxIdx = binIdx } case 40: fallthrough case 47: return 6 case 54: if binIdx > 1 { ctxIdx = 5 } case 60: if binIdx == 0 { // 9.3.3.1.1.5 } if binIdx == 1 { ctxIdx = 2 } if binIdx > 1 { ctxIdx = 3 } case 64: return NaCtxId case 68: if binIdx != 0 { return NaCtxId } ctxIdx = 0 case 69: return NaCtxId case 70: if binIdx != 0 { return NaCtxId } // 9.3.3.1.1.2 case 77: return NaCtxId case 276: if binIdx != 0 { return NaCtxId } ctxIdx = 0 case 399: if binIdx != 0 { return NaCtxId } // 9.3.3.1.1.10 } return ctxIdx } // Error used by unaryBinarization. var errNegativeSyntaxVal = errors.New("cannot get unary binarization of negative value") // unaryBinarization returns the unary binarization of a syntax element having // value v, as specified by setion 9.3.2.1 in the specifications. func unaryBinarization(v int) ([]int, error) { if v < 0 { return nil, errNegativeSyntaxVal } r := make([]int, v+1) for i := 0; i <= v; i++ { if i < v { r[i] = 1 } } return r, nil } // Error used by truncUnaryBinarization. var errInvalidSyntaxVal = errors.New("syntax value cannot be greater than cMax") // truncUnaryBinarization returns the truncated unary binarization of a syntax // element v given a cMax as specified in section 9.3.2.2 of the specifications. func truncUnaryBinarization(v, cMax int) ([]int, error) { if v < 0 { return nil, errNegativeSyntaxVal } if v > cMax { return nil, errInvalidSyntaxVal } if v == cMax { b, _ := unaryBinarization(v) return b[:len(b)-1], nil } return unaryBinarization(v) } // Error used by unaryExpGolombBinarization. var errInvalidUCoff = errors.New("uCoff cannot be less than or equal to zero") // unaryExpGolombBinarization returns the concatendated unary/k-th order // Exp-Golomb (UEGk) binarization of a syntax element using the process defined // in section 9.3.2.3 of the specifications. func unaryExpGolombBinarization(v, uCoff, k int, signedValFlag bool) ([]int, error) { if uCoff <= 0 { return nil, errInvalidUCoff } prefix, err := truncUnaryBinarization(mini(uCoff, absi(v)), uCoff) if err != nil { return nil, err } return append(prefix, suffix(v, uCoff, k, signedValFlag)...), nil } // suffix returns the suffix part of a unary k-th Exp-Golomb Binarization // using the the algorithm as described by pseudo code 9-6 in section 9.3.2.3. // TODO: could probably reduce allocations. func suffix(v, uCoff, k int, signedValFlag bool) []int { var s []int if absi(v) >= uCoff { sufS := absi(v) - uCoff var stop bool for { if sufS >= (1 << uint(k)) { s = append(s, 1) sufS = sufS - (1 << uint(k)) k++ } else { s = append(s, 0) for k = k - 1; k >= 0; k-- { s = append(s, (sufS>>uint(k))&1) } stop = true } if stop { break } } } if signedValFlag && v != 0 { if v > 0 { s = append(s, 0) } else { s = append(s, 1) } } return s } // Error used by fixedLenBinariztion. var errNegativeValue = errors.New("cannot get fixed length binarization of negative value") // fixedLenBinarization returns the fixed-length (FL) binarization of the syntax // element v, given cMax to determine bin length, as specified by section 9.3.2.4 // of the specifications. func fixedLenBinarization(v, cMax int) ([]int, error) { if v < 0 { return nil, errNegativeValue } l := int(math.Ceil(math.Log2(float64(cMax + 1)))) r := make([]int, l) for i := l - 1; i >= 0; i-- { r[i] = v % 2 v = v / 2 } return r, nil }