mirror of https://bitbucket.org/ausocean/av.git
codec/h264/h264dec: added functions for loading table 9-5 CSV into [nColumns]map[int]map[int][2]int with testing
This commit is contained in:
parent
e614633cbd
commit
ee9281925e
|
@ -26,12 +26,104 @@ LICENSE
|
||||||
package h264dec
|
package h264dec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/csv"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
|
"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
|
// parseLevelPrefix parses the level_prefix variable as specified by the process
|
||||||
// outlined in section 9.2.2.1 in the specifications.
|
// outlined in section 9.2.2.1 in the specifications.
|
||||||
func parseLevelPrefix(br *bits.BitReader) (int, error) {
|
func parseLevelPrefix(br *bits.BitReader) (int, error) {
|
||||||
|
|
|
@ -26,11 +26,94 @@ package h264dec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
|
"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) {
|
func TestParseLevelPrefix(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
in string
|
in string
|
||||||
|
|
|
@ -40,6 +40,19 @@ const (
|
||||||
maxBSubMbType = 12
|
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
|
const MB_TYPE_INFERRED = 1000
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -46,6 +46,8 @@ type VideoStream struct {
|
||||||
type SliceContext struct {
|
type SliceContext struct {
|
||||||
*NALUnit
|
*NALUnit
|
||||||
*Slice
|
*Slice
|
||||||
|
chromaArrayType int
|
||||||
|
nalType int
|
||||||
}
|
}
|
||||||
|
|
||||||
type Slice struct {
|
type Slice struct {
|
||||||
|
|
Loading…
Reference in New Issue