mirror of https://bitbucket.org/ausocean/av.git
148 lines
3.9 KiB
Go
148 lines
3.9 KiB
Go
/*
|
|
DESCRIPTION
|
|
cavlc.go provides utilities for context-adaptive variable-length coding
|
|
for the parsing of H.264 syntax structure fields.
|
|
|
|
AUTHORS
|
|
Saxon A. Nelson-Milton <saxon@ausocean.org>
|
|
|
|
LICENSE
|
|
Copyright (C) 2019 the Australian Ocean Lab (AusOcean).
|
|
|
|
It is free software: you can redistribute it and/or modify them
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation, either version 3 of the License, or (at your
|
|
option) any later version.
|
|
|
|
It is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
in gpl.txt. If not, see http://www.gnu.org/licenses.
|
|
*/
|
|
|
|
package h264dec
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
|
|
)
|
|
|
|
// 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) {
|
|
zeros := -1
|
|
for b := 0; b != 1; zeros++ {
|
|
_b, err := br.ReadBits(1)
|
|
if err != nil {
|
|
return -1, fmt.Errorf("could not read bit, failed with error: %v", err)
|
|
}
|
|
b = int(_b)
|
|
}
|
|
return zeros, nil
|
|
}
|
|
|
|
// parseLevelInformation parses level information and returns the resultant
|
|
// levelVal list using the process defined by section 9.2.2 in the specifications.
|
|
func parseLevelInformation(br *bits.BitReader, totalCoeff, trailingOnes int) ([]int, error) {
|
|
var levelVal []int
|
|
var i int
|
|
for ; i < trailingOnes; i++ {
|
|
b, err := br.ReadBits(1)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not read trailing_ones_sign_flag, failed with error: %v", err)
|
|
}
|
|
levelVal = append(levelVal, 1-int(b)*2)
|
|
}
|
|
|
|
var suffixLen int
|
|
switch {
|
|
case totalCoeff > 10 && trailingOnes < 3:
|
|
suffixLen = 1
|
|
case totalCoeff <= 10 || trailingOnes == 3:
|
|
suffixLen = 0
|
|
default:
|
|
return nil, errors.New("invalid TotalCoeff and TrailingOnes combination")
|
|
}
|
|
|
|
for j := 0; j < totalCoeff-trailingOnes; j++ {
|
|
levelPrefix, err := parseLevelPrefix(br)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not parse level prefix, failed with error: %v", err)
|
|
}
|
|
|
|
var levelSuffixSize int
|
|
switch {
|
|
case levelPrefix == 14 && suffixLen == 0:
|
|
levelSuffixSize = 4
|
|
case levelPrefix >= 15:
|
|
levelSuffixSize = levelPrefix - 3
|
|
default:
|
|
levelSuffixSize = suffixLen
|
|
}
|
|
|
|
var levelSuffix int
|
|
if levelSuffixSize > 0 {
|
|
b, err := br.ReadBits(levelSuffixSize)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not parse levelSuffix, failed with error: %v", err)
|
|
}
|
|
levelSuffix = int(b)
|
|
} else {
|
|
levelSuffix = 0
|
|
}
|
|
|
|
levelCode := (mini(15, levelPrefix) << uint(suffixLen)) + levelSuffix
|
|
|
|
if levelPrefix >= 15 && suffixLen == 0 {
|
|
levelCode += 15
|
|
}
|
|
|
|
if levelPrefix >= 16 {
|
|
levelCode += (1 << uint(levelPrefix-3)) - 4096
|
|
}
|
|
|
|
if i == trailingOnes && trailingOnes < 3 {
|
|
levelCode += 2
|
|
}
|
|
|
|
if levelCode%2 == 0 {
|
|
levelVal = append(levelVal, (levelCode+2)>>1)
|
|
} else {
|
|
levelVal = append(levelVal, (-levelCode-1)>>1)
|
|
}
|
|
|
|
if suffixLen == 0 {
|
|
suffixLen = 1
|
|
}
|
|
|
|
if absi(levelVal[i]) > (3<<uint(suffixLen-1)) && suffixLen < 6 {
|
|
suffixLen++
|
|
}
|
|
i++
|
|
}
|
|
return levelVal, nil
|
|
}
|
|
|
|
// combineLevelRunInfo combines the level and run information obtained prior
|
|
// using the process defined in section 9.2.4 of the specifications and returns
|
|
// the corresponding coeffLevel list.
|
|
func combineLevelRunInfo(levelVal, runVal []int, totalCoeff int) []int {
|
|
coeffNum := -1
|
|
i := totalCoeff - 1
|
|
var coeffLevel []int
|
|
for j := 0; j < totalCoeff; j++ {
|
|
coeffNum += runVal[i] + 1
|
|
if coeffNum >= len(coeffLevel) {
|
|
coeffLevel = append(coeffLevel, make([]int, (coeffNum+1)-len(coeffLevel))...)
|
|
}
|
|
coeffLevel[coeffNum] = levelVal[i]
|
|
i++
|
|
}
|
|
return coeffLevel
|
|
}
|