From ee9281925ec24e22e796f93cf35b3e0ec60e5f51 Mon Sep 17 00:00:00 2001 From: Saxon Date: Fri, 6 Sep 2019 11:49:28 +0930 Subject: [PATCH] codec/h264/h264dec: added functions for loading table 9-5 CSV into [nColumns]map[int]map[int][2]int with testing --- codec/h264/h264dec/cavlc.go | 92 ++++++++++++++++++++++++++++++++ codec/h264/h264dec/cavlc_test.go | 83 ++++++++++++++++++++++++++++ codec/h264/h264dec/mbtype.go | 13 +++++ codec/h264/h264dec/slice.go | 2 + 4 files changed, 190 insertions(+) diff --git a/codec/h264/h264dec/cavlc.go b/codec/h264/h264dec/cavlc.go index e1932548..5b37893c 100644 --- a/codec/h264/h264dec/cavlc.go +++ b/codec/h264/h264dec/cavlc.go @@ -26,12 +26,104 @@ LICENSE package h264dec import ( + "encoding/csv" "errors" "fmt" + "os" + "strconv" "bitbucket.org/ausocean/av/codec/h264/h264dec/bits" ) +// Initialize the CAVLC coeff_token mapping table. +func init() { + const file = "coefftokenmap.csv" + f, err := os.Open(file) + if err != nil { + panic(fmt.Sprintf("could not open coefftokenmap.csv file, failed with error: %v", err)) + } + defer f.Close() + + lines, err := csv.NewReader(f).ReadAll() + if err != nil { + panic(fmt.Sprintf("could not read lines from coeftokenmap.csv file, failed with error: %v", err)) + } + + coeffTokenMap, err = formCoeffTokenMap(lines) + if err != nil { + panic(fmt.Sprintf("could not form coeff_token map, failed with err: %v", err)) + } +} + +// The number of columns in the coeffTokenMap defined below. This is +// representative of the number of defined nC ranges defined in table 9-5. +const nColumns = 6 + +// coeffTokenMap will a representation of table 9-5 from the specifications, and +// is indexed as follows, coeffToken[ nC group ][ number of coeff_token leading +// zeros ][ value of coeff_token ][ 0 for TrailingOnes(coeff_token) and 1 for +// TotalCoef(coeff_token) ]. +var coeffTokenMap [nColumns]map[int]map[int][2]int + +// formCoeffTokenMap populates the global [nColumns]map[int]map[int][2]int, +// coeffTokenMap representation of table 9-5 from the specifications using lines +// read from a corresponding CSV file coefftokenmap.csv. +func formCoeffTokenMap(lines [][]string) ([nColumns]map[int]map[int][2]int, error) { + var tokenMap [nColumns]map[int]map[int][2]int + + for i := range tokenMap { + tokenMap[i] = make(map[int]map[int][2]int) + } + + for _, line := range lines { + trailingOnes, err := strconv.Atoi(line[0]) + if err != nil { + return tokenMap, fmt.Errorf("could not convert trailingOnes string to int, failed with error: %v", err) + } + + totalCoeff, err := strconv.Atoi(line[1]) + if err != nil { + return tokenMap, fmt.Errorf("could not convert totalCoeff string to int, failed with error: %v", err) + } + + // For each column in this row, therefore each nC category, load the + // coeff_token leading zeros and value into the map. + for j, v := range line[2:] { + if v[0] == '-' { + continue + } + + // Count the leading zeros. + var nZeros int + for _, c := range v { + if c == ' ' { + continue + } + + if c == '0' { + nZeros++ + continue + } + break + } + + // This will be the value of the coeff_token (without leading zeros). + val, err := binToInt(v[nZeros:]) + if err != nil { + return tokenMap, fmt.Errorf("could not get value of remaining binary, failed with error: %v", err) + } + + // Add the TrailingOnes(coeff_token) and TotalCoeff(coeff_token) values + // into the map for the coeff_token leading zeros and value. + if tokenMap[j][nZeros] == nil { + tokenMap[j][nZeros] = make(map[int][2]int) + } + tokenMap[j][nZeros][val] = [2]int{trailingOnes, totalCoeff} + } + } + return tokenMap, nil +} + // parseLevelPrefix parses the level_prefix variable as specified by the process // outlined in section 9.2.2.1 in the specifications. func parseLevelPrefix(br *bits.BitReader) (int, error) { diff --git a/codec/h264/h264dec/cavlc_test.go b/codec/h264/h264dec/cavlc_test.go index a6740858..666288c3 100644 --- a/codec/h264/h264dec/cavlc_test.go +++ b/codec/h264/h264dec/cavlc_test.go @@ -26,11 +26,94 @@ package h264dec import ( "bytes" + "reflect" "testing" "bitbucket.org/ausocean/av/codec/h264/h264dec/bits" ) +func TestFormCoeffTokenMap(t *testing.T) { + tests := []struct { + in [][]string + want [nColumns]map[int]map[int][2]int + }{ + { + in: [][]string{ + {"0", "0", "1", "11", "1111", "0000 11", "01", "1"}, + {"0", "1", "0001 01", "0010 11", "0011 11", "0000 00", "0001 11", "0001 111"}, + }, + want: [nColumns]map[int]map[int][2]int{ + 0: { + 0: {1: {0, 0}}, + 3: {5: {0, 1}}, + }, + 1: { + 0: {3: {0, 0}}, + 2: {11: {0, 1}}, + }, + 2: { + 0: {15: {0, 0}}, + 2: {15: {0, 1}}, + }, + 3: { + 4: {3: {0, 0}}, + 6: {0: {0, 1}}, + }, + 4: { + 1: {1: {0, 0}}, + 3: {7: {0, 1}}, + }, + 5: { + 0: {1: {0, 0}}, + 3: {15: {0, 1}}, + }, + }, + }, + { + in: [][]string{ + {"0", "0", "1", "11", "1111", "0000 11", "01", "1"}, + {"0", "1", "0001 01", "0010 11", "0011 11", "-", "0001 11", "0001 111"}, + }, + want: [nColumns]map[int]map[int][2]int{ + 0: { + 0: {1: {0, 0}}, + 3: {5: {0, 1}}, + }, + 1: { + 0: {3: {0, 0}}, + 2: {11: {0, 1}}, + }, + 2: { + 0: {15: {0, 0}}, + 2: {15: {0, 1}}, + }, + 3: { + 4: {3: {0, 0}}, + }, + 4: { + 1: {1: {0, 0}}, + 3: {7: {0, 1}}, + }, + 5: { + 0: {1: {0, 0}}, + 3: {15: {0, 1}}, + }, + }, + }, + } + + for i, test := range tests { + m, err := formCoeffTokenMap(test.in) + if err != nil { + t.Errorf("did not expect error: %v for test: %d", err, i) + } + + if !reflect.DeepEqual(m, test.want) { + t.Errorf("did not get expected result for test: %d\nGot: %v\nWant: %v\n", i, m, test.want) + } + } +} + func TestParseLevelPrefix(t *testing.T) { tests := []struct { in string diff --git a/codec/h264/h264dec/mbtype.go b/codec/h264/h264dec/mbtype.go index eb716c17..2cd124d2 100644 --- a/codec/h264/h264dec/mbtype.go +++ b/codec/h264/h264dec/mbtype.go @@ -40,6 +40,19 @@ const ( maxBSubMbType = 12 ) +// Inferred macroblock types. +// TODO: specification reference. +const ( + pSkip = -1 + bSkip = -1 +) + +// TODO: complete +// I slice mb types. +const ( + iPCM = 25 +) + const MB_TYPE_INFERRED = 1000 var ( diff --git a/codec/h264/h264dec/slice.go b/codec/h264/h264dec/slice.go index 4952cfd9..5ffcf5fd 100644 --- a/codec/h264/h264dec/slice.go +++ b/codec/h264/h264dec/slice.go @@ -46,6 +46,8 @@ type VideoStream struct { type SliceContext struct { *NALUnit *Slice + chromaArrayType int + nalType int } type Slice struct {