mirror of https://bitbucket.org/ausocean/av.git
Merged in total-coeff-and-trailing-ones (pull request #243)
codec/h264/h264dec: parsing process for TotalCoeff and TrailingOnes Approved-by: Alan Noble <anoble@gmail.com>
This commit is contained in:
commit
1fba7556dd
|
@ -26,12 +26,289 @@ LICENSE
|
||||||
package h264dec
|
package h264dec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/csv"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
|
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: find where these are defined in the specifications.
|
||||||
|
const (
|
||||||
|
chromaDCLevel = iota
|
||||||
|
intra16x16DCLevel
|
||||||
|
intra16x16ACLevel
|
||||||
|
cbIntra16x16DCLevel
|
||||||
|
cbIntra16x16ACLevel
|
||||||
|
crIntra16x16DCLevel
|
||||||
|
crIntra16x16ACLevel
|
||||||
|
lumaLevel4x4
|
||||||
|
cbLevel4x4
|
||||||
|
crLevel4x4
|
||||||
|
)
|
||||||
|
|
||||||
|
// Initialize the CAVLC coeff_token mapping table.
|
||||||
|
func init() {
|
||||||
|
lines, err := csv.NewReader(strings.NewReader(coeffTokenTable)).ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("could not read lines from coeffTokenTable string, failed with error: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
coeffTokenMaps, err = formCoeffTokenMap(lines)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("could not form coeff_token map, failed with err: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokenMap maps coeff_token to values of TrailingOnes(coeff_token) and
|
||||||
|
// TotalCoeff(coeff_token) given as tokenMap[ number of leading zeros in
|
||||||
|
// coeff_token][ coeff_token val ][ 0 for trailing ones and 1 for totalCoef ]
|
||||||
|
type tokenMap map[int]map[int][2]int
|
||||||
|
|
||||||
|
// The number of columns in the coeffTokenMap defined below. This is
|
||||||
|
// representative of the number of defined nC ranges in table 9-5.
|
||||||
|
const nColumns = 6
|
||||||
|
|
||||||
|
// coeffTokenMaps holds 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 coeffTokenMaps [nColumns]tokenMap
|
||||||
|
|
||||||
|
// formCoeffTokenMap populates the global [nColumns]tokenMap coeffTokenMaps
|
||||||
|
// representation of table 9-5 in the specifications using the coeffTokenTable
|
||||||
|
// const string defined in cavlctab.go.
|
||||||
|
func formCoeffTokenMap(lines [][]string) ([nColumns]tokenMap, error) {
|
||||||
|
var maps [nColumns]tokenMap
|
||||||
|
|
||||||
|
for i := range maps {
|
||||||
|
maps[i] = make(tokenMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
trailingOnes, err := strconv.Atoi(line[0])
|
||||||
|
if err != nil {
|
||||||
|
return maps, fmt.Errorf("could not convert trailingOnes string to int, failed with error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
totalCoeff, err := strconv.Atoi(line[1])
|
||||||
|
if err != nil {
|
||||||
|
return maps, 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 == '1' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if c == '0' {
|
||||||
|
nZeros++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will be the value of the coeff_token (without leading zeros).
|
||||||
|
val, err := binToInt(v[nZeros:])
|
||||||
|
if err != nil {
|
||||||
|
return maps, 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 maps[j][nZeros] == nil {
|
||||||
|
maps[j][nZeros] = make(map[int][2]int)
|
||||||
|
}
|
||||||
|
maps[j][nZeros][val] = [2]int{trailingOnes, totalCoeff}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return maps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: put this somewhere more appropriate once context is understood.
|
||||||
|
type block struct {
|
||||||
|
usingInterMbPredMode bool
|
||||||
|
mbType int
|
||||||
|
totalCoef int
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseTotalCoeffAndTrailingOnes will use logic provided in section 9.2.1 of
|
||||||
|
// the specifications to obtain a value of nC, parse coeff_token from br and
|
||||||
|
// then use table 9-5 to find corresponding values of TrailingOnes(coeff_token)
|
||||||
|
// and TotalCoeff(coeff_token) which are then subsequently returned.
|
||||||
|
func parseTotalCoeffAndTrailingOnes(br *bits.BitReader, vid *VideoStream, ctx *SliceContext, usingMbPredMode bool, level, maxNumCoef, inBlockIdx int) (totalCoeff, trailingOnes, nC, outBlockIdx int, err error) {
|
||||||
|
if level == chromaDCLevel {
|
||||||
|
if ctx.chromaArrayType == 1 {
|
||||||
|
nC = -1
|
||||||
|
} else {
|
||||||
|
nC = -2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Steps 1,2 and 3.
|
||||||
|
if level == intra16x16DCLevel || level == cbIntra16x16DCLevel || level == crIntra16x16DCLevel {
|
||||||
|
outBlockIdx = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4 derive blkA and blkB variables (blockA and blockB here).
|
||||||
|
var mbAddr, blk [2]block
|
||||||
|
switch level {
|
||||||
|
case intra16x16DCLevel, intra16x16ACLevel, lumaLevel4x4:
|
||||||
|
// TODO: clause 6.4.11.4
|
||||||
|
panic("not implemented")
|
||||||
|
case cbIntra16x16DCLevel, cbIntra16x16ACLevel, cbLevel4x4:
|
||||||
|
// TODO: clause 6.4.11.6
|
||||||
|
panic("not implemented")
|
||||||
|
case crIntra16x16DCLevel, crIntra16x16ACLevel, crLevel4x4:
|
||||||
|
// TODO: clause 6.4.11.6
|
||||||
|
panic("not implemented")
|
||||||
|
default:
|
||||||
|
// TODO: clause 6.4.11.5
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
var availableFlag [2]bool
|
||||||
|
var n [2]int
|
||||||
|
for i := range availableFlag {
|
||||||
|
// Step 5.
|
||||||
|
if !(!available(mbAddr[i]) || usingMbPredMode || vid.ConstrainedIntraPred ||
|
||||||
|
mbAddr[i].usingInterMbPredMode || ctx.nalType == 2 || ctx.nalType == 3 || ctx.nalType == 4) {
|
||||||
|
availableFlag[i] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 6.
|
||||||
|
if availableFlag[i] {
|
||||||
|
switch {
|
||||||
|
case mbAddr[i].mbType == pSkip || mbAddr[i].mbType == bSkip || (mbAddr[i].mbType != iPCM && resTransformCoeffLevelsZero(blk[i])):
|
||||||
|
n[i] = 0
|
||||||
|
case mbAddr[i].mbType == iPCM:
|
||||||
|
n[i] = 16
|
||||||
|
default:
|
||||||
|
// TODO: how is this set ?
|
||||||
|
// "Otherwise, nN is set equal to the value TotalCoeff( coeff_token ) of
|
||||||
|
// the neighbouring block blkN."
|
||||||
|
// Do we need to run this same process for this block, or assume it's
|
||||||
|
// already happened?
|
||||||
|
n[i] = blk[i].totalCoef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 7.
|
||||||
|
switch {
|
||||||
|
case availableFlag[0] && availableFlag[1]:
|
||||||
|
nC = (n[0] + n[1] + 1) >> 1
|
||||||
|
case availableFlag[0]:
|
||||||
|
nC = n[0]
|
||||||
|
case availableFlag[1]:
|
||||||
|
nC = n[1]
|
||||||
|
default:
|
||||||
|
nC = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trailingOnes, totalCoeff, _, err = readCoeffToken(br, nC)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("could not get trailingOnes and totalCoeff vars, failed with error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errInvalidNC = errors.New("invalid value of nC")
|
||||||
|
errBadToken = errors.New("could not find coeff_token value in map")
|
||||||
|
)
|
||||||
|
|
||||||
|
// readCoeffToken will read the coeff_token from br and find a match in the
|
||||||
|
// coeff_token mapping table (table 9-5 in the specifications) given also nC.
|
||||||
|
// The resultant TrailingOnes(coeff_token) and TotalCoeff(coeff_token) are
|
||||||
|
// returned as well as the value of coeff_token.
|
||||||
|
func readCoeffToken(br *bits.BitReader, nC int) (trailingOnes, totalCoeff, coeffToken int, err error) {
|
||||||
|
// Get the number of leading zeros.
|
||||||
|
var b uint64
|
||||||
|
nZeros := -1
|
||||||
|
for ; b == 0; nZeros++ {
|
||||||
|
b, err = br.ReadBits(1)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("could not read coeff_token leading zeros, failed with error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the column idx for the map.
|
||||||
|
var nCIdx int
|
||||||
|
switch {
|
||||||
|
case 0 <= nC && nC < 2:
|
||||||
|
nCIdx = 0
|
||||||
|
case 2 <= nC && nC < 4:
|
||||||
|
nCIdx = 1
|
||||||
|
case 4 <= nC && nC < 8:
|
||||||
|
nCIdx = 2
|
||||||
|
case 8 <= nC:
|
||||||
|
nCIdx = 3
|
||||||
|
case nC == -1:
|
||||||
|
nCIdx = 4
|
||||||
|
case nC == -2:
|
||||||
|
nCIdx = 5
|
||||||
|
default:
|
||||||
|
err = errInvalidNC
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the value of coeff_token.
|
||||||
|
val := b
|
||||||
|
nBits := nZeros
|
||||||
|
for {
|
||||||
|
vars, ok := coeffTokenMaps[nCIdx][nZeros][int(val)]
|
||||||
|
if ok {
|
||||||
|
trailingOnes = vars[0]
|
||||||
|
totalCoeff = vars[1]
|
||||||
|
coeffToken = int(val)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxCoeffTokenBits = 16
|
||||||
|
if !ok && nBits == maxCoeffTokenBits {
|
||||||
|
err = errBadToken
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err = br.ReadBits(1)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("could not read next bit of coeff_token, failed with error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nBits++
|
||||||
|
val <<= 1
|
||||||
|
val |= b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement this. From step 6 section 9.2.1. Will return true if "AC
|
||||||
|
// residual transform coefficient levels of the neighbouring block blkN are
|
||||||
|
// equal to 0 due to the corresponding bit of CodedBlockPatternLuma or
|
||||||
|
// CodedBlockPatternChroma being equal to 0"
|
||||||
|
func resTransformCoeffLevelsZero(b block) bool {
|
||||||
|
panic("not implemented")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement this
|
||||||
|
func available(b block) bool {
|
||||||
|
panic("not implemented")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 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]tokenMap
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
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]tokenMap{
|
||||||
|
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]tokenMap{
|
||||||
|
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
|
||||||
|
@ -53,3 +136,55 @@ func TestParseLevelPrefix(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadCoeffToken(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
// Input.
|
||||||
|
nC int
|
||||||
|
tokenBits string
|
||||||
|
|
||||||
|
// Expected.
|
||||||
|
trailingOnes int
|
||||||
|
totalCoeff int
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
nC: 5,
|
||||||
|
tokenBits: "0001001",
|
||||||
|
trailingOnes: 0,
|
||||||
|
totalCoeff: 6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nC: -1,
|
||||||
|
tokenBits: "0000000000111111111",
|
||||||
|
err: errBadToken,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
nC: -3,
|
||||||
|
tokenBits: "0001001",
|
||||||
|
err: errInvalidNC,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
b, err := binToSlice(test.tokenBits)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("converting bin string to slice failed with error: %v for test", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
gotTrailingOnes, gotTotalCoeff, _, gotErr := readCoeffToken(bits.NewBitReader(bytes.NewReader(b)), test.nC)
|
||||||
|
if gotErr != test.err {
|
||||||
|
t.Errorf("did not get expected error for test: %d\nGot: %v\nWant: %v\n", i, gotErr, test.err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotTrailingOnes != test.trailingOnes {
|
||||||
|
t.Errorf("did not get expected TrailingOnes(coeff_token) for test %d\nGot: %v\nWant: %v\n", i, gotTrailingOnes, test.trailingOnes)
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotTotalCoeff != test.totalCoeff {
|
||||||
|
t.Errorf("did not get expected TotalCoeff(coeff_token) for test %d\nGot: %v\nWant: %v\n", i, gotTotalCoeff, test.totalCoeff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package h264dec
|
||||||
|
|
||||||
|
// coefTokenTable is a CSV representation of table 9-5 from the specifications.
|
||||||
|
// This is used to populate a series of maps at initialisation for the
|
||||||
|
// retrieval of TotalCoeff and TrailingOnes values for a given coeff_token.
|
||||||
|
const coeffTokenTable = `0,0,1,11,1111,0000 11,01,1
|
||||||
|
0,1,0001 01,0010 11,0011 11,0000 00,0001 11,0001 111
|
||||||
|
1,1,01,10,1110,0000 01,1,01
|
||||||
|
0,2,0000 0111,0001 11,0010 11,0001 00,0001 00,0001 110
|
||||||
|
1,2,0001 00,0011 1,0111 1,0001 01,0001 10,0001 101
|
||||||
|
2,2,001,011,1101,0001 10,001,001
|
||||||
|
0,3,0000 0011 1,0000 111,0010 00,0010 00,0000 11,0000 0011 1
|
||||||
|
1,3,0000 0110,0010 10,0110 0,0010 01,0000 011,0001 100
|
||||||
|
2,3,0000 101,0010 01,0111 0,0010 10,0000 010,0001 011
|
||||||
|
3,3,0001 1,0101,1100,0010 11,0001 01,0000 1
|
||||||
|
0,4,0000 0001 11,0000 0111,0001 111,0011 00,0000 10,0000 0011 0
|
||||||
|
1,4,0000 0011 0,0001 10,0101 0,0011 01,0000 0011,0000 0010 1
|
||||||
|
2,4,0000 0101,0001 01,0101 1,0011 10,0000 0010,0001 010
|
||||||
|
3,4,0000 11,0100,1011,0011 11,0000 000,0000 01
|
||||||
|
0,5,0000 0000 111,0000 0100,0001 011,0100 00,-,0000 0001 11
|
||||||
|
1,5,0000 0001 10,0000 110,0100 0,0100 01,-,0000 0001 10
|
||||||
|
2,5,0000 0010 1,0000 101,0100 1,0100 10,-,0000 0010 0
|
||||||
|
3,5,0000 100,0011 0,1010,0100 11,-,0001 001
|
||||||
|
0,6,0000 0000 0111 1,0000 0011 1,0001 001,0101 00,-,0000 0000 111
|
||||||
|
1,6,0000 0000 110,0000 0110,0011 10,0101 01,-,0000 0000 110
|
||||||
|
2,6,0000 0001 01,0000 0101,0011 01,0101 10,-,0000 0001 01
|
||||||
|
3,6,0000 0100,0010 00,1001,0101 11,-,0001 000
|
||||||
|
0,7,0000 0000 0101 1,0000 0001 111,0001 000,0110 00,-,0000 0000 0111
|
||||||
|
1,7,0000 0000 0111 0,0000 0011 0,0010 10,0110 01,-,0000 0000 0110
|
||||||
|
2,7,0000 0000 101,0000 0010 1,0010 01,0110 10,-,0000 0000 101
|
||||||
|
3,7,0000 0010 0,0001 00,1000,0110 11,-,0000 0001 00
|
||||||
|
0,8,0000 0000 0100 0,0000 0001 011,0000 1111,0111 00,-,0000 0000 0011 1
|
||||||
|
1,8,0000 0000 0101 0,0000 0001 110,0001 110,0111 01,-,0000 0000 0101
|
||||||
|
2,8,0000 0000 0110 1,0000 0001 101,0001 101,0111 10,-,0000 0000 0100
|
||||||
|
3,8,0000 0001 00,0000 100,0110 1,0111 11,-,0000 0000 100
|
||||||
|
0,9,0000 0000 0011 11,0000 0000 1111,0000 1011,1000 00,-,-
|
||||||
|
1,9,0000 0000 0011 10,0000 0001 010,0000 1110,1000 01,-,-
|
||||||
|
2,9,0000 0000 0100 1,0000 0001 001,0001 010,1000 10,-,-
|
||||||
|
3,9,0000 0000 100,0000 0010 0,0011 00,1000 11,-,-
|
||||||
|
0,10,0000 0000 0010 11,0000 0000 1011,0000 0111 1,1001 00,-,-
|
||||||
|
1,10,0000 0000 0010 10,0000 0000 1110,0000 1010,1001 01,-,-
|
||||||
|
2,10,0000 0000 0011 01,0000 0000 1101,0000 1101,1001 10,-,-
|
||||||
|
3,10,0000 0000 0110 0,0000 0001 100,0001 100,1001 11,-,-
|
||||||
|
0,11,0000 0000 0001 111,0000 0000 1000,0000 0101 1,1010 00,-,-
|
||||||
|
1,11,0000 0000 0001 110,0000 0000 1010,0000 0111 0,1010 01,-,-
|
||||||
|
2,11,0000 0000 0010 01,0000 0000 1001,0000 1001,1010 10,-,-
|
||||||
|
3,11,0000 0000 0011 00,0000 0001 000,0000 1100,1010 11,-,-
|
||||||
|
0,12,0000 0000 0001 011,0000 0000 0111 1,0000 0100 0,1011 00,-,-
|
||||||
|
1,12,0000 0000 0001 010,0000 0000 0111 0,0000 0101 0,1011 01,-,-
|
||||||
|
2,12,0000 0000 0001 101,0000 0000 0110 1,0000 0110 1,1011 10,-,-
|
||||||
|
3,12,0000 0000 0010 00,0000 0000 1100,0000 1000,1011 11,-,-
|
||||||
|
0,13,0000 0000 0000 1111,0000 0000 0101 1,0000 0011 01,1100 00,-,-
|
||||||
|
1,13,0000 0000 0000 001,0000 0000 0101 0,0000 0011 1,1100 01,-,-
|
||||||
|
2,13,0000 0000 0001 001,0000 0000 0100 1,0000 0100 1,1100 10,-,-
|
||||||
|
3,13,0000 0000 0001 100,0000 0000 0110 0,0000 0110 0,1100 11,-,-
|
||||||
|
0,14,0000 0000 0000 1011,0000 0000 0011 1,0000 0010 01,1101 00,-,-
|
||||||
|
1,14,0000 0000 0000 1110,0000 0000 0010 11,0000 0011 00,1101 01,-,-
|
||||||
|
2,14,0000 0000 0000 1101,0000 0000 0011 0,0000 0010 11,1101 10,-,-
|
||||||
|
3,14,0000 0000 0001 000,0000 0000 0100 0,0000 0010 10,1101 11,-,-
|
||||||
|
0,15,0000 0000 0000 0111,0000 0000 0010 01,0000 0001 01,1110 00,-,-
|
||||||
|
1,15,0000 0000 0000 1010,0000 0000 0010 00,0000 0010 00,1110 01,-,-
|
||||||
|
2,15,0000 0000 0000 1001,0000 0000 0010 10,0000 0001 11,1110 10,-,-
|
||||||
|
3,15,0000 0000 0000 1100,0000 0000 0000 1,0000 0001 10,1110 11,-,-
|
||||||
|
0,16,0000 0000 0000 0100,0000 0000 0001 11,0000 0000 01,1111 00,-,-
|
||||||
|
1,16,0000 0000 0000 0110,0000 0000 0001 10,0000 0001 00,1111 01,-,-
|
||||||
|
2,16,0000 0000 0000 0101,0000 0000 0001 01,0000 0000 11,1111 10,-,-
|
||||||
|
3,16,0000 0000 0000 1000,0000 0000 0001 00,0000 0000 10,1111 11,-,-`
|
|
@ -9,6 +9,7 @@ package h264dec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
// binToSlice is a helper function to convert a string of binary into a
|
// binToSlice is a helper function to convert a string of binary into a
|
||||||
|
@ -42,6 +43,21 @@ func binToSlice(s string) ([]byte, error) {
|
||||||
return bytes, nil
|
return bytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// binToInt converts a binary string provided as a string and returns as an int.
|
||||||
|
// White spaces are ignored.
|
||||||
|
func binToInt(s string) (int, error) {
|
||||||
|
var sum int
|
||||||
|
var nSpace int
|
||||||
|
for i := len(s) - 1; i >= 0; i-- {
|
||||||
|
if s[i] == ' ' {
|
||||||
|
nSpace++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sum += int(math.Pow(2, float64(len(s)-1-i-nSpace))) * int(s[i]-'0')
|
||||||
|
}
|
||||||
|
return sum, nil
|
||||||
|
}
|
||||||
|
|
||||||
func maxi(a, b int) int {
|
func maxi(a, b int) int {
|
||||||
if a > b {
|
if a > b {
|
||||||
return a
|
return a
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package h264dec
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestBinToInt(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
in string
|
||||||
|
want int
|
||||||
|
}{
|
||||||
|
{in: "101", want: 5},
|
||||||
|
{in: "1", want: 1},
|
||||||
|
{in: "00000", want: 0},
|
||||||
|
{in: "", want: 0},
|
||||||
|
{in: "1111", want: 15},
|
||||||
|
{in: "1 111", want: 15},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
n, err := binToInt(test.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("did not expect error: %v from binToInt", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n != test.want {
|
||||||
|
t.Errorf("did not get expected result for test %d\nGot: %v\nWant: %v\n", i, n, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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