From cd83cf9e8e631818af6ccf0530074e8df07607a0 Mon Sep 17 00:00:00 2001 From: Saxon Date: Wed, 14 Aug 2019 14:08:24 +0930 Subject: [PATCH] codec/h264/h2646dec: fixed up binarization tables and added mbTypeBinarization function along with test TestMbTypeBinarization. --- codec/h264/h264dec/cabac.go | 277 +++++++++++++++++-------------- codec/h264/h264dec/cabac_test.go | 42 ++++- codec/h264/h264dec/mbtype.go | 32 ++++ codec/h264/h264dec/slice.go | 9 + 4 files changed, 230 insertions(+), 130 deletions(-) diff --git a/codec/h264/h264dec/cabac.go b/codec/h264/h264dec/cabac.go index 8b3a6e4c..12a07ddc 100644 --- a/codec/h264/h264dec/cabac.go +++ b/codec/h264/h264dec/cabac.go @@ -100,13 +100,7 @@ func CondTermFlag(mbAddr, mbSkipFlag int) int { } // s9.3.3 p 278: Returns the value of the syntax element -func (bin *Binarization) Decode(sliceContext *SliceContext, b *bits.BitReader, rbsp []byte) { - if bin.SyntaxElement == "MbType" { - bin.binString = binIdxMbMap[sliceContext.Slice.Data.SliceTypeName][sliceContext.Slice.Data.MbType] - } else { - logger.Printf("TODO: no means to find binString for %s\n", bin.SyntaxElement) - } -} +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 { @@ -178,135 +172,160 @@ func initCabac(binarization *Binarization, context *SliceContext) *CABAC { } } -// Table 9-36, 9-37 -// func BinIdx(mbType int, sliceTypeName string) []int { -// Map of SliceTypeName[MbType][]int{binString} -// {"SliceTypeName": {MbTypeCode: []BinString}} +// Binarizations for macroblock types in slice types. var ( - binIdxMbMap = map[string]map[int][]int{ - "I": { - 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}, - }, - // Table 9-37 - "P": { - 0: {0, 0, 0}, - 1: {0, 1, 1}, - 2: {0, 1, 0}, - 3: {0, 0, 1}, - 4: {}, - 5: {1}, - 6: {1}, - 7: {1}, - 8: {1}, - 9: {1}, - 10: {1}, - 11: {1}, - 12: {1}, - 13: {1}, - 14: {1}, - 15: {1}, - 16: {1}, - 17: {1}, - 18: {1}, - 19: {1}, - 20: {1}, - 21: {1}, - 22: {1}, - 23: {1}, - 24: {1}, - 25: {1}, - 26: {1}, - 27: {1}, - 28: {1}, - 29: {1}, - 30: {1}, - }, - // Table 9-37 - "SP": { - 0: {0, 0, 0}, - 1: {0, 1, 1}, - 2: {0, 1, 0}, - 3: {0, 0, 1}, - 4: {}, - 5: {1}, - 6: {1}, - 7: {1}, - 8: {1}, - 9: {1}, - 10: {1}, - 11: {1}, - 12: {1}, - 13: {1}, - 14: {1}, - 15: {1}, - 16: {1}, - 17: {1}, - 18: {1}, - 19: {1}, - 20: {1}, - 21: {1}, - 22: {1}, - 23: {1}, - 24: {1}, - 25: {1}, - 26: {1}, - 27: {1}, - 28: {1}, - 29: {1}, - 30: {1}, - }, - // TODO: B Slice table 9-37 + // 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}, } - // Map of SliceTypeName[SubMbType][]int{binString} - binIdxSubMbMap = map[string]map[int][]int{ - "P": { - 0: {1}, - 1: {0, 0}, - 2: {0, 1, 1}, - 3: {0, 1, 0}, - }, - "SP": { - 0: {1}, - 1: {0, 0}, - 2: {0, 1, 1}, - 3: {0, 1, 0}, - }, - // TODO: B slice table 9-38 + // 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: {}, } - // Table 9-36, 9-37 - MbBinIdx = []int{1, 2, 3, 4, 5, 6} - - // Table 9-38 - SubMbBinIdx = []int{0, 1, 2, 3, 4, 5} + // 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") + errInvalidSliceType = errors.New("slice type does not exist") +) + +// 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, errInvalidSliceType + } +} + // Table 9-34 type MaxBinIdxCtx struct { // When false, Prefix is the MaxBinIdxCtx diff --git a/codec/h264/h264dec/cabac_test.go b/codec/h264/h264dec/cabac_test.go index 66d82a93..26350f18 100644 --- a/codec/h264/h264dec/cabac_test.go +++ b/codec/h264/h264dec/cabac_test.go @@ -1,6 +1,46 @@ package h264dec -import "testing" +import ( + "reflect" + "testing" +) + +func TestMbTypeBinarization(t *testing.T) { + tests := []struct { + v, slice int + want []int + err error + }{ + {v: 6, slice: sliceTypeI, want: []int{1, 0, 0, 1, 0, 0, 1}}, + {v: 26, slice: sliceTypeI, err: errBadMbType}, + {v: -1, slice: sliceTypeI, err: errBadMbType}, + {v: 4, slice: sliceTypeSI, want: []int{0}}, + {v: 6, slice: sliceTypeSI, want: []int{1, 1, 0, 0, 1, 0, 0, 0}}, + {v: 0, slice: sliceTypeSI, err: errBadMbType}, + {v: 27, slice: sliceTypeSI, err: errBadMbType}, + {v: 2, slice: sliceTypeP, want: []int{0, 1, 0}}, + {v: 3, slice: sliceTypeSP, want: []int{0, 0, 1}}, + {v: 7, slice: sliceTypeP, want: []int{1, 1, 0, 0, 0, 0, 1}}, + {v: 7, slice: sliceTypeSP, want: []int{1, 1, 0, 0, 0, 0, 1}}, + {v: -1, slice: sliceTypeP, err: errBadMbType}, + {v: 31, slice: sliceTypeP, err: errBadMbType}, + {v: 8, slice: sliceTypeB, want: []int{1, 1, 0, 1, 0, 1}}, + {v: 30, slice: sliceTypeB, want: []int{1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0}}, + {v: -1, slice: sliceTypeB, err: errBadMbType}, + {v: 49, slice: sliceTypeB, err: errBadMbType}, + } + + for i, test := range tests { + got, err := mbTypeBinarization(test.v, test.slice) + if err != test.err { + t.Errorf("did not get expected error for test %d\nGot: %v\nWant: %v", i, err, test.err) + } + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("did not get expected result for test %d\nGot: %v\nWant: %v", i, got, test.want) + } + } +} var ctxIdxTests = []struct { binIdx int diff --git a/codec/h264/h264dec/mbtype.go b/codec/h264/h264dec/mbtype.go index e335e756..02466d45 100644 --- a/codec/h264/h264dec/mbtype.go +++ b/codec/h264/h264dec/mbtype.go @@ -4,6 +4,38 @@ import ( "errors" ) +// P slice macroblock types. +const ( + P8x8ref0 = 4 +) + +// Number of macroblock types for each slice type. +const ( + numOfIMBTypes = 26 + numOfPMBTypes = 31 + numOfSPMBTypes = 31 + numOfBMBTypes = 49 +) + +// Number of sub macroblock types for each slice type. +const ( + numOfPSubMBTypes = 4 + numOfSPSubMBTypes = 4 + numOfBSubMBTypes = 13 +) + +// Min and max macroblock types for slice types. +const ( + minIMbType = 0 + maxIMbType = 25 + minPOrSPMbType = 0 + maxPOrSPMbType = 30 + minBMbType = 0 + maxBMbType = 48 + minSIMbType = 1 + maxSIMbType = 26 +) + const MB_TYPE_INFERRED = 1000 var ( diff --git a/codec/h264/h264dec/slice.go b/codec/h264/h264dec/slice.go index 77c6091b..ee8ed35e 100644 --- a/codec/h264/h264dec/slice.go +++ b/codec/h264/h264dec/slice.go @@ -9,6 +9,15 @@ import ( "github.com/pkg/errors" ) +// Slice types. +const ( + sliceTypeP = 0 + sliceTypeB = 1 + sliceTypeI = 2 + sliceTypeSP = 3 + sliceTypeSI = 4 +) + // Chroma formats as defined in section 6.2, tab 6-1. const ( chromaMonochrome = iota