av/codec/h264/h264dec/slice.go

1377 lines
44 KiB
Go
Raw Normal View History

/*
DESCRIPTION
slice.go provides parsing functionality for slice raw byte sequence data.
AUTHORS
Saxon Nelson-Milton <saxon@ausocean.org>, The Australian Ocean Laboratory (AusOcean)
Bruce McMoran <mcmoranbjr@gmail.com>
*/
package h264dec
import (
"bytes"
"fmt"
"math"
2019-07-19 09:14:45 +03:00
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
"github.com/pkg/errors"
)
// Slice types as defined by table 7-6 in specifications.
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
chroma420
chroma422
chroma444
)
type VideoStream struct {
*SPS
*PPS
Slices []*SliceContext
ChromaArrayType int
}
type SliceContext struct {
*NALUnit
*Slice
chromaArrayType int
nalType int
}
type Slice struct {
*SliceHeader
*SliceData
}
// RefPicListModification provides elements of a ref_pic_list_modification syntax
// (defined in 7.3.3.1 of specifications) and a ref_pic_list_mvc_modification
// (defined in H.7.3.3.1.1 of specifications).
type RefPicListModification struct {
RefPicListModificationFlag [2]bool
ModificationOfPicNums [2][]int
AbsDiffPicNumMinus1 [2][]int
LongTermPicNum [2][]int
}
// TODO: need to complete this.
// NewRefPicListMVCModification parses elements of a ref_pic_list_mvc_modification
// following the syntax structure defined in section H.7.3.3.1.1, and returns as
// a new RefPicListModification.
func NewRefPicListMVCModifiation(br *bits.BitReader) (*RefPicListModification, error) {
return nil, nil
}
// NewRefPicListModification parses elements of a ref_pic_list_modification
// following the syntax structure defined in section 7.3.3.1, and returns as
// a new RefPicListModification.
func NewRefPicListModification(br *bits.BitReader, p *PPS, s *SliceHeader) (*RefPicListModification, error) {
r := &RefPicListModification{}
r.ModificationOfPicNums[0] = make([]int, p.NumRefIdxL0DefaultActiveMinus1+2)
r.ModificationOfPicNums[1] = make([]int, p.NumRefIdxL1DefaultActiveMinus1+2)
r.AbsDiffPicNumMinus1[0] = make([]int, p.NumRefIdxL0DefaultActiveMinus1+2)
r.AbsDiffPicNumMinus1[1] = make([]int, p.NumRefIdxL1DefaultActiveMinus1+2)
r.LongTermPicNum[0] = make([]int, p.NumRefIdxL0DefaultActiveMinus1+2)
r.LongTermPicNum[1] = make([]int, p.NumRefIdxL1DefaultActiveMinus1+2)
fr := newFieldReader(br)
// 7.3.3.1
if s.SliceType%5 != 2 && s.SliceType%5 != 4 {
r.RefPicListModificationFlag[0] = fr.readBits(1) == 1
if r.RefPicListModificationFlag[0] {
for i := 0; ; i++ {
r.ModificationOfPicNums[0][i] = int(fr.readUe())
if r.ModificationOfPicNums[0][i] == 0 || r.ModificationOfPicNums[0][i] == 1 {
r.AbsDiffPicNumMinus1[0][i] = int(fr.readUe())
} else if r.ModificationOfPicNums[0][i] == 2 {
r.LongTermPicNum[0][i] = int(fr.readUe())
}
if r.ModificationOfPicNums[0][i] == 3 {
break
}
}
}
}
if s.SliceType%5 == 1 {
r.RefPicListModificationFlag[1] = fr.readBits(1) == 1
if r.RefPicListModificationFlag[1] {
for i := 0; ; i++ {
r.ModificationOfPicNums[1][i] = int(fr.readUe())
if r.ModificationOfPicNums[1][i] == 0 || r.ModificationOfPicNums[1][i] == 1 {
r.AbsDiffPicNumMinus1[1][i] = int(fr.readUe())
} else if r.ModificationOfPicNums[1][i] == 2 {
r.LongTermPicNum[1][i] = int(fr.readUe())
}
if r.ModificationOfPicNums[1][i] == 3 {
break
}
}
}
}
return r, nil
}
// PredWeightTable provides elements of a pred_weight_table syntax structure
// as defined in section 7.3.3.2 of the specifications.
type PredWeightTable struct {
LumaLog2WeightDenom int
ChromaLog2WeightDenom int
LumaWeightL0Flag bool
LumaWeightL0 []int
LumaOffsetL0 []int
ChromaWeightL0Flag bool
ChromaWeightL0 [][]int
ChromaOffsetL0 [][]int
LumaWeightL1Flag bool
LumaWeightL1 []int
LumaOffsetL1 []int
ChromaWeightL1Flag bool
ChromaWeightL1 [][]int
ChromaOffsetL1 [][]int
}
// NewPredWeightTable parses elements of a pred_weight_table following the
// syntax structure defined in section 7.3.3.2, and returns as a new
// PredWeightTable.
func NewPredWeightTable(br *bits.BitReader, h *SliceHeader, chromaArrayType int) (*PredWeightTable, error) {
p := &PredWeightTable{}
r := newFieldReader(br)
p.LumaLog2WeightDenom = int(r.readUe())
if chromaArrayType != 0 {
p.ChromaLog2WeightDenom = int(r.readUe())
}
for i := 0; i <= h.NumRefIdxL0ActiveMinus1; i++ {
p.LumaWeightL0Flag = r.readBits(1) == 1
if p.LumaWeightL0Flag {
se, err := readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse LumaWeightL0")
}
p.LumaWeightL0 = append(p.LumaWeightL0, se)
se, err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse LumaOffsetL0")
}
p.LumaOffsetL0 = append(p.LumaOffsetL0, se)
}
if chromaArrayType != 0 {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read ChromaWeightL0Flag")
}
p.ChromaWeightL0Flag = b == 1
if p.ChromaWeightL0Flag {
p.ChromaWeightL0 = append(p.ChromaWeightL0, []int{})
p.ChromaOffsetL0 = append(p.ChromaOffsetL0, []int{})
for j := 0; j < 2; j++ {
se, err := readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse ChromaWeightL0")
}
p.ChromaWeightL0[i] = append(p.ChromaWeightL0[i], se)
se, err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse ChromaOffsetL0")
}
p.ChromaOffsetL0[i] = append(p.ChromaOffsetL0[i], se)
}
}
}
}
if h.SliceType%5 == 1 {
for i := 0; i <= h.NumRefIdxL1ActiveMinus1; i++ {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read LumaWeightL1Flag")
}
p.LumaWeightL1Flag = b == 1
if p.LumaWeightL1Flag {
se, err := readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse LumaWeightL1")
}
p.LumaWeightL1 = append(p.LumaWeightL1, se)
se, err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse LumaOffsetL1")
}
p.LumaOffsetL1 = append(p.LumaOffsetL1, se)
}
if chromaArrayType != 0 {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read ChromaWeightL1Flag")
}
p.ChromaWeightL1Flag = b == 1
if p.ChromaWeightL1Flag {
p.ChromaWeightL1 = append(p.ChromaWeightL1, []int{})
p.ChromaOffsetL1 = append(p.ChromaOffsetL1, []int{})
for j := 0; j < 2; j++ {
se, err := readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse ChromaWeightL1")
}
p.ChromaWeightL1[i] = append(p.ChromaWeightL1[i], se)
se, err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse ChromaOffsetL1")
}
p.ChromaOffsetL1[i] = append(p.ChromaOffsetL1[i], se)
}
}
}
}
}
return p, nil
}
// DecRefPicMarking provides elements of a dec_ref_pic_marking syntax structure
// as defined in section 7.3.3.3 of the specifications.
type DecRefPicMarking struct {
NoOutputOfPriorPicsFlag bool
LongTermReferenceFlag bool
AdaptiveRefPicMarkingModeFlag bool
elements []drpmElement
}
type drpmElement struct {
MemoryManagementControlOperation int
DifferenceOfPicNumsMinus1 int
LongTermPicNum int
LongTermFrameIdx int
MaxLongTermFrameIdxPlus1 int
}
// NewDecRefPicMarking parses elements of a dec_ref_pic_marking following the
// syntax structure defined in section 7.3.3.3, and returns as a new
// DecRefPicMarking.
func NewDecRefPicMarking(br *bits.BitReader, idrPic bool) (*DecRefPicMarking, error) {
d := &DecRefPicMarking{}
r := newFieldReader(br)
if idrPic {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read NoOutputOfPriorPicsFlag")
}
d.NoOutputOfPriorPicsFlag = b == 1
b, err = br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read LongTermReferenceFlag")
}
d.LongTermReferenceFlag = b == 1
} else {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read AdaptiveRefPicMarkingModeFlag")
}
d.AdaptiveRefPicMarkingModeFlag = b == 1
if d.AdaptiveRefPicMarkingModeFlag {
for i := 0; ; i++ {
d.elements = append(d.elements, drpmElement{})
d.elements[i].MemoryManagementControlOperation = int(r.readUe())
if d.elements[i].MemoryManagementControlOperation == 1 || d.elements[i].MemoryManagementControlOperation == 3 {
d.elements[i].DifferenceOfPicNumsMinus1 = int(r.readUe())
}
if d.elements[i].MemoryManagementControlOperation == 2 {
d.elements[i].LongTermPicNum = int(r.readUe())
}
if d.elements[i].MemoryManagementControlOperation == 3 || d.elements[i].MemoryManagementControlOperation == 6 {
d.elements[i].LongTermFrameIdx = int(r.readUe())
}
if d.elements[i].MemoryManagementControlOperation == 4 {
d.elements[i].MaxLongTermFrameIdxPlus1 = int(r.readUe())
}
if d.elements[i].MemoryManagementControlOperation == 0 {
break
}
}
}
}
return d, nil
}
type SliceHeader struct {
FirstMbInSlice int
SliceType int
PPSID int
ColorPlaneID int
FrameNum int
FieldPic bool
BottomField bool
IDRPicID int
PicOrderCntLsb int
DeltaPicOrderCntBottom int
DeltaPicOrderCnt []int
RedundantPicCnt int
DirectSpatialMvPred bool
NumRefIdxActiveOverride bool
NumRefIdxL0ActiveMinus1 int
NumRefIdxL1ActiveMinus1 int
*RefPicListModification
*PredWeightTable
*DecRefPicMarking
CabacInit int
SliceQpDelta int
SpForSwitch bool
SliceQsDelta int
DisableDeblockingFilter int
SliceAlphaC0OffsetDiv2 int
SliceBetaOffsetDiv2 int
SliceGroupChangeCycle int
}
type SliceData struct {
BitReader *bits.BitReader
CabacAlignmentOneBit int
MbSkipRun int
MbSkipFlag bool
MbFieldDecodingFlag bool
EndOfSliceFlag bool
MbType int
MbTypeName string
SliceTypeName string
PcmAlignmentZeroBit int
PcmSampleLuma []int
PcmSampleChroma []int
TransformSize8x8Flag bool
CodedBlockPattern int
MbQpDelta int
PrevIntra4x4PredModeFlag []int
RemIntra4x4PredMode []int
PrevIntra8x8PredModeFlag []int
RemIntra8x8PredMode []int
IntraChromaPredMode int
RefIdxL0 []int
RefIdxL1 []int
MvdL0 [][][]int
MvdL1 [][][]int
}
// Table 7-6
var sliceTypeMap = map[int]string{
0: "P",
1: "B",
2: "I",
3: "SP",
4: "SI",
5: "P",
6: "B",
7: "I",
8: "SP",
9: "SI",
}
func flagVal(b bool) int {
if b {
return 1
}
return 0
}
// context-adaptive arithmetic entropy-coded element (CABAC)
// 9.3
// When parsing the slice date of a slice (7.3.4) the initialization is 9.3.1
func (d SliceData) ae(v int) int {
// 9.3.1.1 : CABAC context initialization ctxIdx
return 0
}
// 8.2.2
func MbToSliceGroupMap(sps *SPS, pps *PPS, header *SliceHeader) []int {
mbaffFrameFlag := 0
if sps.MBAdaptiveFrameFieldFlag && !header.FieldPic {
mbaffFrameFlag = 1
}
mapUnitToSliceGroupMap := MapUnitToSliceGroupMap(sps, pps, header)
mbToSliceGroupMap := []int{}
for i := 0; i <= PicSizeInMbs(sps, header)-1; i++ {
if sps.FrameMBSOnlyFlag || header.FieldPic {
mbToSliceGroupMap = append(mbToSliceGroupMap, mapUnitToSliceGroupMap[i])
continue
}
if mbaffFrameFlag == 1 {
mbToSliceGroupMap = append(mbToSliceGroupMap, mapUnitToSliceGroupMap[i/2])
continue
}
if !sps.FrameMBSOnlyFlag && !sps.MBAdaptiveFrameFieldFlag && !header.FieldPic {
mbToSliceGroupMap = append(
mbToSliceGroupMap,
mapUnitToSliceGroupMap[(i/(2*PicWidthInMbs(sps)))*PicWidthInMbs(sps)+(i%PicWidthInMbs(sps))])
}
}
return mbToSliceGroupMap
}
func PicWidthInMbs(sps *SPS) int {
return int(sps.PicWidthInMBSMinus1 + 1)
}
func PicHeightInMapUnits(sps *SPS) int {
return int(sps.PicHeightInMapUnitsMinus1 + 1)
}
func PicSizeInMapUnits(sps *SPS) int {
return int(PicWidthInMbs(sps) * PicHeightInMapUnits(sps))
}
func FrameHeightInMbs(sps *SPS) int {
return int((2 - flagVal(sps.FrameMBSOnlyFlag)) * PicHeightInMapUnits(sps))
}
func PicHeightInMbs(sps *SPS, header *SliceHeader) int {
return int(FrameHeightInMbs(sps) / (1 + flagVal(header.FieldPic)))
}
func PicSizeInMbs(sps *SPS, header *SliceHeader) int {
return int(PicWidthInMbs(sps) * PicHeightInMbs(sps, header))
}
// table 6-1
func SubWidthC(sps *SPS) int {
n := 17
if sps.SeparateColorPlaneFlag {
if sps.ChromaFormatIDC == chroma444 {
return n
}
}
switch sps.ChromaFormatIDC {
case chromaMonochrome:
return n
case chroma420:
n = 2
case chroma422:
n = 2
case chroma444:
n = 1
}
return n
}
func SubHeightC(sps *SPS) int {
n := 17
if sps.SeparateColorPlaneFlag {
if sps.ChromaFormatIDC == chroma444 {
return n
}
}
switch sps.ChromaFormatIDC {
case chromaMonochrome:
return n
case chroma420:
n = 2
case chroma422:
n = 1
case chroma444:
n = 1
}
return n
}
// 7-36
func CodedBlockPatternLuma(data *SliceData) int {
return data.CodedBlockPattern % 16
}
func CodedBlockPatternChroma(data *SliceData) int {
return data.CodedBlockPattern / 16
}
// dependencyId see Annex G.8.8.1
// Also G7.3.1.1 nal_unit_header_svc_extension
func DQId(nalUnit *NALUnit) int {
return int((nalUnit.SVCExtension.DependencyID << 4)) + int(nalUnit.SVCExtension.QualityID)
}
// Annex G p527
func NumMbPart(nalUnit *NALUnit, sps *SPS, header *SliceHeader, data *SliceData) int {
sliceType := sliceTypeMap[header.SliceType]
numMbPart := 0
if MbTypeName(sliceType, CurrMbAddr(sps, header)) == "B_SKIP" || MbTypeName(sliceType, CurrMbAddr(sps, header)) == "B_Direct_16x16" {
if DQId(nalUnit) == 0 && nalUnit.Type != 20 {
numMbPart = 4
} else if DQId(nalUnit) > 0 && nalUnit.Type == 20 {
numMbPart = 1
}
} else if MbTypeName(sliceType, CurrMbAddr(sps, header)) != "B_SKIP" && MbTypeName(sliceType, CurrMbAddr(sps, header)) != "B_Direct_16x16" {
numMbPart = CurrMbAddr(sps, header)
}
return numMbPart
}
func MbPred(chromaArrayType int, vid *VideoStream, sliceContext *SliceContext, br *bits.BitReader, rbsp []byte) error {
var cabac *CABAC
r := newFieldReader(br)
sliceType := sliceTypeMap[sliceContext.Slice.SliceHeader.SliceType]
mbPartPredMode, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceType, sliceContext.Slice.SliceData.MbType, 0)
if err != nil {
return errors.Wrap(err, "could not get mbPartPredMode")
}
if mbPartPredMode == intra4x4 || mbPartPredMode == intra8x8 || mbPartPredMode == intra16x16 {
if mbPartPredMode == intra4x4 {
for luma4x4BlkIdx := 0; luma4x4BlkIdx < 16; luma4x4BlkIdx++ {
var v int
if vid.PPS.EntropyCodingMode == 1 {
// TODO: 1 bit or ae(v)
binarization := NewBinarization(
"PrevIntra4x4PredModeFlag",
sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
// TODO: fix videostream should be nil.
cabac = initCabac(binarization, nil, sliceContext)
_ = cabac
logger.Printf("TODO: ae for PevIntra4x4PredModeFlag[%d]\n", luma4x4BlkIdx)
} else {
b, err := br.ReadBits(1)
if err != nil {
return errors.Wrap(err, "could not read PrevIntra4x4PredModeFlag")
}
v = int(b)
}
sliceContext.Slice.SliceData.PrevIntra4x4PredModeFlag = append(
sliceContext.Slice.SliceData.PrevIntra4x4PredModeFlag,
v)
if sliceContext.Slice.SliceData.PrevIntra4x4PredModeFlag[luma4x4BlkIdx] == 0 {
if vid.PPS.EntropyCodingMode == 1 {
// TODO: 3 bits or ae(v)
binarization := NewBinarization(
"RemIntra4x4PredMode",
sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
logger.Printf("TODO: ae for RemIntra4x4PredMode[%d]\n", luma4x4BlkIdx)
} else {
b, err := br.ReadBits(3)
if err != nil {
return errors.Wrap(err, "could not read RemIntra4x4PredMode")
}
v = int(b)
}
if len(sliceContext.Slice.SliceData.RemIntra4x4PredMode) < luma4x4BlkIdx {
sliceContext.Slice.SliceData.RemIntra4x4PredMode = append(
sliceContext.Slice.SliceData.RemIntra4x4PredMode,
make([]int, luma4x4BlkIdx-len(sliceContext.Slice.SliceData.RemIntra4x4PredMode)+1)...)
}
sliceContext.Slice.SliceData.RemIntra4x4PredMode[luma4x4BlkIdx] = v
}
}
}
if mbPartPredMode == intra8x8 {
for luma8x8BlkIdx := 0; luma8x8BlkIdx < 4; luma8x8BlkIdx++ {
sliceContext.Update(sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData)
var v int
if vid.PPS.EntropyCodingMode == 1 {
// TODO: 1 bit or ae(v)
binarization := NewBinarization("PrevIntra8x8PredModeFlag", sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
logger.Printf("TODO: ae for PrevIntra8x8PredModeFlag[%d]\n", luma8x8BlkIdx)
} else {
b, err := br.ReadBits(1)
if err != nil {
return errors.Wrap(err, "could not read PrevIntra8x8PredModeFlag")
}
v = int(b)
}
sliceContext.Slice.SliceData.PrevIntra8x8PredModeFlag = append(
sliceContext.Slice.SliceData.PrevIntra8x8PredModeFlag, v)
if sliceContext.Slice.SliceData.PrevIntra8x8PredModeFlag[luma8x8BlkIdx] == 0 {
if vid.PPS.EntropyCodingMode == 1 {
// TODO: 3 bits or ae(v)
binarization := NewBinarization(
"RemIntra8x8PredMode",
sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
logger.Printf("TODO: ae for RemIntra8x8PredMode[%d]\n", luma8x8BlkIdx)
} else {
b, err := br.ReadBits(3)
if err != nil {
return errors.Wrap(err, "could not read RemIntra8x8PredMode")
}
v = int(b)
}
if len(sliceContext.Slice.SliceData.RemIntra8x8PredMode) < luma8x8BlkIdx {
sliceContext.Slice.SliceData.RemIntra8x8PredMode = append(
sliceContext.Slice.SliceData.RemIntra8x8PredMode,
make([]int, luma8x8BlkIdx-len(sliceContext.Slice.SliceData.RemIntra8x8PredMode)+1)...)
}
sliceContext.Slice.SliceData.RemIntra8x8PredMode[luma8x8BlkIdx] = v
}
}
}
if chromaArrayType == 1 || chromaArrayType == 2 {
if vid.PPS.EntropyCodingMode == 1 {
// TODO: ue(v) or ae(v)
binarization := NewBinarization(
"IntraChromaPredMode",
sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
logger.Printf("TODO: ae for IntraChromaPredMode\n")
} else {
sliceContext.Slice.SliceData.IntraChromaPredMode = int(r.readUe())
}
}
} else if mbPartPredMode != direct {
for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, vid.SPS, sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData); mbPartIdx++ {
sliceContext.Update(sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData)
m, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceType, sliceContext.Slice.SliceData.MbType, mbPartIdx)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("could not get mbPartPredMode for loop 1 mbPartIdx: %d", mbPartIdx))
}
if (sliceContext.Slice.SliceHeader.NumRefIdxL0ActiveMinus1 > 0 || sliceContext.Slice.SliceData.MbFieldDecodingFlag != sliceContext.Slice.SliceHeader.FieldPic) && m != predL1 {
logger.Printf("\tTODO: refIdxL0[%d] te or ae(v)\n", mbPartIdx)
if len(sliceContext.Slice.SliceData.RefIdxL0) < mbPartIdx {
sliceContext.Slice.SliceData.RefIdxL0 = append(
sliceContext.Slice.SliceData.RefIdxL0, make([]int, mbPartIdx-len(sliceContext.Slice.SliceData.RefIdxL0)+1)...)
}
if vid.PPS.EntropyCodingMode == 1 {
// TODO: te(v) or ae(v)
binarization := NewBinarization(
"RefIdxL0",
sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
logger.Printf("TODO: ae for RefIdxL0[%d]\n", mbPartIdx)
} else {
// TODO: Only one reference picture is used for inter-prediction,
// then the value should be 0
if MbaffFrameFlag(vid.SPS, sliceContext.Slice.SliceHeader) == 0 || !sliceContext.Slice.SliceData.MbFieldDecodingFlag {
sliceContext.Slice.SliceData.RefIdxL0[mbPartIdx] = int(r.readTe(uint(sliceContext.Slice.SliceHeader.NumRefIdxL0ActiveMinus1)))
} else {
rangeMax := 2*sliceContext.Slice.SliceHeader.NumRefIdxL0ActiveMinus1 + 1
sliceContext.Slice.SliceData.RefIdxL0[mbPartIdx] = int(r.readTe(uint(rangeMax)))
}
}
}
}
for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, vid.SPS, sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData); mbPartIdx++ {
m, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceType, sliceContext.Slice.SliceData.MbType, mbPartIdx)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("could not get mbPartPredMode for loop 2 mbPartIdx: %d", mbPartIdx))
}
if m != predL1 {
for compIdx := 0; compIdx < 2; compIdx++ {
if len(sliceContext.Slice.SliceData.MvdL0) < mbPartIdx {
sliceContext.Slice.SliceData.MvdL0 = append(
sliceContext.Slice.SliceData.MvdL0,
make([][][]int, mbPartIdx-len(sliceContext.Slice.SliceData.MvdL0)+1)...)
}
if len(sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0]) < compIdx {
sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0] = append(
sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0],
make([]int, compIdx-len(sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0])+1)...)
}
if vid.PPS.EntropyCodingMode == 1 {
// TODO: se(v) or ae(v)
if compIdx == 0 {
binarization := NewBinarization(
"MvdLnEnd0",
sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
} else if compIdx == 1 {
binarization := NewBinarization(
"MvdLnEnd1",
sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
}
logger.Printf("TODO: ae for MvdL0[%d][0][%d]\n", mbPartIdx, compIdx)
} else {
sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0][compIdx], _ = readSe(br)
}
}
}
}
for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, vid.SPS, sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData); mbPartIdx++ {
sliceContext.Update(sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData)
m, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceType, sliceContext.Slice.SliceData.MbType, mbPartIdx)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("could not get mbPartPredMode for loop 3 mbPartIdx: %d", mbPartIdx))
}
if m != predL0 {
for compIdx := 0; compIdx < 2; compIdx++ {
if len(sliceContext.Slice.SliceData.MvdL1) < mbPartIdx {
sliceContext.Slice.SliceData.MvdL1 = append(
sliceContext.Slice.SliceData.MvdL1,
make([][][]int, mbPartIdx-len(sliceContext.Slice.SliceData.MvdL1)+1)...)
}
if len(sliceContext.Slice.SliceData.MvdL1[mbPartIdx][0]) < compIdx {
sliceContext.Slice.SliceData.MvdL1[mbPartIdx][0] = append(
sliceContext.Slice.SliceData.MvdL0[mbPartIdx][0],
make([]int, compIdx-len(sliceContext.Slice.SliceData.MvdL1[mbPartIdx][0])+1)...)
}
if vid.PPS.EntropyCodingMode == 1 {
if compIdx == 0 {
binarization := NewBinarization(
"MvdLnEnd0",
sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
} else if compIdx == 1 {
binarization := NewBinarization(
"MvdLnEnd1",
sliceContext.Slice.SliceData)
binarization.Decode(sliceContext, br, rbsp)
}
// TODO: se(v) or ae(v)
logger.Printf("TODO: ae for MvdL1[%d][0][%d]\n", mbPartIdx, compIdx)
} else {
sliceContext.Slice.SliceData.MvdL1[mbPartIdx][0][compIdx], _ = readSe(br)
}
}
}
}
}
return nil
}
// 8.2.2.1
func MapUnitToSliceGroupMap(sps *SPS, pps *PPS, header *SliceHeader) []int {
mapUnitToSliceGroupMap := []int{}
picSizeInMapUnits := PicSizeInMapUnits(sps)
if pps.NumSliceGroupsMinus1 == 0 {
// 0 to PicSizeInMapUnits -1 inclusive
for i := 0; i <= picSizeInMapUnits-1; i++ {
mapUnitToSliceGroupMap = append(mapUnitToSliceGroupMap, 0)
}
} else {
switch pps.SliceGroupMapType {
case 0:
// 8.2.2.1
i := 0
for i < picSizeInMapUnits {
// iGroup should be incremented in the pps.RunLengthMinus1 index operation. There may be a bug here
for iGroup := 0; iGroup <= pps.NumSliceGroupsMinus1 && i < picSizeInMapUnits; i += pps.RunLengthMinus1[iGroup+1] + 1 {
for j := 0; j < pps.RunLengthMinus1[iGroup] && i+j < picSizeInMapUnits; j++ {
if len(mapUnitToSliceGroupMap) < i+j {
mapUnitToSliceGroupMap = append(
mapUnitToSliceGroupMap,
make([]int, (i+j)-len(mapUnitToSliceGroupMap)+1)...)
}
mapUnitToSliceGroupMap[i+j] = iGroup
}
}
}
case 1:
// 8.2.2.2
for i := 0; i < picSizeInMapUnits; i++ {
v := ((i % PicWidthInMbs(sps)) + (((i / PicWidthInMbs(sps)) * (pps.NumSliceGroupsMinus1 + 1)) / 2)) % (pps.NumSliceGroupsMinus1 + 1)
mapUnitToSliceGroupMap = append(mapUnitToSliceGroupMap, v)
}
case 2:
// 8.2.2.3
for i := 0; i < picSizeInMapUnits; i++ {
mapUnitToSliceGroupMap = append(mapUnitToSliceGroupMap, pps.NumSliceGroupsMinus1)
}
for iGroup := pps.NumSliceGroupsMinus1 - 1; iGroup >= 0; iGroup-- {
yTopLeft := pps.TopLeft[iGroup] / PicWidthInMbs(sps)
xTopLeft := pps.TopLeft[iGroup] % PicWidthInMbs(sps)
yBottomRight := pps.BottomRight[iGroup] / PicWidthInMbs(sps)
xBottomRight := pps.BottomRight[iGroup] % PicWidthInMbs(sps)
for y := yTopLeft; y <= yBottomRight; y++ {
for x := xTopLeft; x <= xBottomRight; x++ {
idx := y*PicWidthInMbs(sps) + x
if len(mapUnitToSliceGroupMap) < idx {
mapUnitToSliceGroupMap = append(
mapUnitToSliceGroupMap,
make([]int, idx-len(mapUnitToSliceGroupMap)+1)...)
mapUnitToSliceGroupMap[idx] = iGroup
}
}
}
}
case 3:
// 8.2.2.4
// TODO
case 4:
// 8.2.2.5
// TODO
case 5:
// 8.2.2.6
// TODO
case 6:
// 8.2.2.7
// TODO
}
}
// 8.2.2.8
// Convert mapUnitToSliceGroupMap to MbToSliceGroupMap
return mapUnitToSliceGroupMap
}
func nextMbAddress(n int, sps *SPS, pps *PPS, header *SliceHeader) int {
i := n + 1
// picSizeInMbs is the number of macroblocks in picture 0
// 7-13
// PicWidthInMbs = sps.PicWidthInMBSMinus1 + 1
// PicHeightInMapUnits = sps.PicHeightInMapUnitsMinus1 + 1
// 7-29
// picSizeInMbs = PicWidthInMbs * PicHeightInMbs
// 7-26
// PicHeightInMbs = FrameHeightInMbs / (1 + header.fieldPicFlag)
// 7-18
// FrameHeightInMbs = (2 - ps.FrameMBSOnlyFlag) * PicHeightInMapUnits
picWidthInMbs := sps.PicWidthInMBSMinus1 + 1
picHeightInMapUnits := sps.PicHeightInMapUnitsMinus1 + 1
frameHeightInMbs := (2 - flagVal(sps.FrameMBSOnlyFlag)) * int(picHeightInMapUnits)
picHeightInMbs := frameHeightInMbs / (1 + flagVal(header.FieldPic))
picSizeInMbs := int(picWidthInMbs) * picHeightInMbs
mbToSliceGroupMap := MbToSliceGroupMap(sps, pps, header)
for i < picSizeInMbs && mbToSliceGroupMap[i] != mbToSliceGroupMap[i] {
i++
}
return i
}
func CurrMbAddr(sps *SPS, header *SliceHeader) int {
mbaffFrameFlag := 0
if sps.MBAdaptiveFrameFieldFlag && !header.FieldPic {
mbaffFrameFlag = 1
}
return header.FirstMbInSlice * (1 * mbaffFrameFlag)
}
func MbaffFrameFlag(sps *SPS, header *SliceHeader) int {
if sps.MBAdaptiveFrameFieldFlag && !header.FieldPic {
return 1
}
return 0
}
func NewSliceData(chromaArrayType int, vid *VideoStream, sliceContext *SliceContext, br *bits.BitReader) (*SliceData, error) {
r := newFieldReader(br)
var cabac *CABAC
sliceContext.Slice.SliceData = &SliceData{BitReader: br}
// TODO: Why is this being initialized here?
// initCabac(sliceContext)
if vid.PPS.EntropyCodingMode == 1 {
for !br.ByteAligned() {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read CabacAlignmentOneBit")
}
sliceContext.Slice.SliceData.CabacAlignmentOneBit = int(b)
}
}
mbaffFrameFlag := 0
if vid.SPS.MBAdaptiveFrameFieldFlag && !sliceContext.Slice.SliceHeader.FieldPic {
mbaffFrameFlag = 1
}
currMbAddr := sliceContext.Slice.SliceHeader.FirstMbInSlice * (1 * mbaffFrameFlag)
moreDataFlag := true
prevMbSkipped := 0
sliceContext.Slice.SliceData.SliceTypeName = sliceTypeMap[sliceContext.Slice.SliceHeader.SliceType]
sliceContext.Slice.SliceData.MbTypeName = MbTypeName(sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType)
logger.Printf("debug: \tSliceData: Processing moreData: %v\n", moreDataFlag)
for moreDataFlag {
logger.Printf("debug: \tLooking for more sliceContext.Slice.SliceData in slice type %s\n", sliceContext.Slice.SliceData.SliceTypeName)
if sliceContext.Slice.SliceData.SliceTypeName != "I" && sliceContext.Slice.SliceData.SliceTypeName != "SI" {
logger.Printf("debug: \tNonI/SI slice, processing moreData\n")
if vid.PPS.EntropyCodingMode == 0 {
sliceContext.Slice.SliceData.MbSkipRun = int(r.readUe())
if sliceContext.Slice.SliceData.MbSkipRun > 0 {
prevMbSkipped = 1
}
for i := 0; i < sliceContext.Slice.SliceData.MbSkipRun; i++ {
// nextMbAddress(currMbAdd
currMbAddr = nextMbAddress(currMbAddr, vid.SPS, vid.PPS, sliceContext.Slice.SliceHeader)
}
if sliceContext.Slice.SliceData.MbSkipRun > 0 {
moreDataFlag = moreRBSPData(br)
}
} else {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read MbSkipFlag")
}
sliceContext.Slice.SliceData.MbSkipFlag = b == 1
moreDataFlag = !sliceContext.Slice.SliceData.MbSkipFlag
}
}
if moreDataFlag {
if mbaffFrameFlag == 1 && (currMbAddr%2 == 0 || (currMbAddr%2 == 1 && prevMbSkipped == 1)) {
if vid.PPS.EntropyCodingMode == 1 {
// TODO: ae implementation
binarization := NewBinarization("MbFieldDecodingFlag", sliceContext.Slice.SliceData)
// TODO: this should take a BitReader where the nil is.
binarization.Decode(sliceContext, br, nil)
logger.Printf("TODO: ae for MbFieldDecodingFlag\n")
} else {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read MbFieldDecodingFlag")
}
sliceContext.Slice.SliceData.MbFieldDecodingFlag = b == 1
}
}
// BEGIN: macroblockLayer()
if vid.PPS.EntropyCodingMode == 1 {
// TODO: ae implementation
binarization := NewBinarization("MbType", sliceContext.Slice.SliceData)
cabac = initCabac(binarization, nil, sliceContext)
_ = cabac
// TODO: remove bytes parameter from this function.
binarization.Decode(sliceContext, br, nil)
if binarization.PrefixSuffix {
logger.Printf("debug: MBType binarization has prefix and suffix\n")
}
bits := []int{}
for binIdx := 0; binarization.IsBinStringMatch(bits); binIdx++ {
newBit, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read bit")
}
if binarization.UseDecodeBypass == 1 {
// DecodeBypass
logger.Printf("TODO: decodeBypass is set: 9.3.3.2.3")
codIRange, codIOffset, err := initDecodingEngine(sliceContext.Slice.SliceData.BitReader)
if err != nil {
return nil, errors.Wrap(err, "could not initialise decoding engine")
}
// Initialize the decoder
// TODO: When should the suffix of MaxBinIdxCtx be used and when just the prefix?
// TODO: When should the suffix of CtxIdxOffset be used?
arithmeticDecoder, err := NewArithmeticDecoding(
sliceContext,
binarization,
CtxIdx(
binarization.binIdx,
binarization.MaxBinIdxCtx.Prefix,
binarization.CtxIdxOffset.Prefix,
),
codIRange,
codIOffset,
)
if err != nil {
return nil, errors.Wrap(err, "error from NewArithmeticDecoding")
}
// Bypass decoding
codIOffset, _, err = arithmeticDecoder.DecodeBypass(
sliceContext.Slice.SliceData,
codIRange,
codIOffset,
)
if err != nil {
return nil, errors.Wrap(err, "could not DecodeBypass")
}
// End DecodeBypass
} else {
// DO 9.3.3.1
ctxIdx := CtxIdx(
binIdx,
binarization.MaxBinIdxCtx.Prefix,
binarization.CtxIdxOffset.Prefix)
if binarization.MaxBinIdxCtx.IsPrefixSuffix {
logger.Printf("TODO: Handle PrefixSuffix binarization\n")
}
logger.Printf("debug: MBType ctxIdx for %d is %d\n", binIdx, ctxIdx)
// Then 9.3.3.2
codIRange, codIOffset, err := initDecodingEngine(br)
if err != nil {
return nil, errors.Wrap(err, "error from initDecodingEngine")
}
logger.Printf("debug: coding engine initialized: %d/%d\n", codIRange, codIOffset)
}
bits = append(bits, int(newBit))
}
logger.Printf("TODO: ae for MBType\n")
} else {
sliceContext.Slice.SliceData.MbType = int(r.readUe())
}
if sliceContext.Slice.SliceData.MbTypeName == "I_PCM" {
for !br.ByteAligned() {
_, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read PCMAlignmentZeroBit")
}
}
// 7-3 p95
bitDepthY := 8 + vid.SPS.BitDepthLumaMinus8
for i := 0; i < 256; i++ {
s, err := br.ReadBits(int(bitDepthY))
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("could not read PcmSampleLuma[%d]", i))
}
sliceContext.Slice.SliceData.PcmSampleLuma = append(
sliceContext.Slice.SliceData.PcmSampleLuma,
int(s))
}
// 9.3.1 p 246
// cabac = initCabac(binarization, sliceContext)
// 6-1 p 47
mbWidthC := 16 / SubWidthC(vid.SPS)
mbHeightC := 16 / SubHeightC(vid.SPS)
// if monochrome
if vid.SPS.ChromaFormatIDC == chromaMonochrome || vid.SPS.SeparateColorPlaneFlag {
mbWidthC = 0
mbHeightC = 0
}
bitDepthC := 8 + vid.SPS.BitDepthChromaMinus8
for i := 0; i < 2*mbWidthC*mbHeightC; i++ {
s, err := br.ReadBits(int(bitDepthC))
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("could not read PcmSampleChroma[%d]", i))
}
sliceContext.Slice.SliceData.PcmSampleChroma = append(
sliceContext.Slice.SliceData.PcmSampleChroma,
int(s))
}
// 9.3.1 p 246
// cabac = initCabac(binarization, sliceContext)
} else {
noSubMbPartSizeLessThan8x8Flag := 1
m, err := MbPartPredMode(sliceContext.Slice.SliceData, sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType, 0)
if err != nil {
return nil, errors.Wrap(err, "could not get mbPartPredMode")
}
if sliceContext.Slice.SliceData.MbTypeName == "I_NxN" && m != intra16x16 && NumMbPart(sliceContext.NALUnit, vid.SPS, sliceContext.Slice.SliceHeader, sliceContext.Slice.SliceData) == 4 {
logger.Printf("\tTODO: subMbPred\n")
/*
subMbType := SubMbPred(sliceContext.Slice.SliceData.MbType)
for mbPartIdx := 0; mbPartIdx < 4; mbPartIdx++ {
if subMbType[mbPartIdx] != "B_Direct_8x8" {
if NumbSubMbPart(subMbType[mbPartIdx]) > 1 {
noSubMbPartSizeLessThan8x8Flag = 0
}
} else if !vid.SPS.Direct8x8InferenceFlag {
noSubMbPartSizeLessThan8x8Flag = 0
}
}
*/
} else {
if vid.PPS.Transform8x8Mode == 1 && sliceContext.Slice.SliceData.MbTypeName == "I_NxN" {
// TODO
// 1 bit or ae(v)
// If vid.PPS.EntropyCodingMode == 1, use ae(v)
if vid.PPS.EntropyCodingMode == 1 {
binarization := NewBinarization("TransformSize8x8Flag", sliceContext.Slice.SliceData)
cabac = initCabac(binarization, nil, sliceContext)
binarization.Decode(sliceContext, br, nil)
logger.Println("TODO: ae(v) for TransformSize8x8Flag")
} else {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read TransformSize8x8Flag")
}
sliceContext.Slice.SliceData.TransformSize8x8Flag = b == 1
}
}
// TODO: fix nil argument for.
MbPred(chromaArrayType, nil, sliceContext, br, nil)
}
m, err = MbPartPredMode(sliceContext.Slice.SliceData, sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType, 0)
if err != nil {
return nil, errors.Wrap(err, "could not get mbPartPredMode")
}
if m != intra16x16 {
// TODO: me, ae
logger.Printf("TODO: CodedBlockPattern pending me/ae implementation\n")
if vid.PPS.EntropyCodingMode == 1 {
binarization := NewBinarization("CodedBlockPattern", sliceContext.Slice.SliceData)
cabac = initCabac(binarization, nil, sliceContext)
// TODO: fix nil argument.
binarization.Decode(sliceContext, br, nil)
logger.Printf("TODO: ae for CodedBlockPattern\n")
} else {
me, _ := readMe(
br,
uint(chromaArrayType),
// TODO: fix this
//MbPartPredMode(sliceContext.Slice.SliceData, sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType, 0)))
0)
sliceContext.Slice.SliceData.CodedBlockPattern = int(me)
}
// sliceContext.Slice.SliceData.CodedBlockPattern = me(v) | ae(v)
if CodedBlockPatternLuma(sliceContext.Slice.SliceData) > 0 && vid.PPS.Transform8x8Mode == 1 && sliceContext.Slice.SliceData.MbTypeName != "I_NxN" && noSubMbPartSizeLessThan8x8Flag == 1 && (sliceContext.Slice.SliceData.MbTypeName != "B_Direct_16x16" || vid.SPS.Direct8x8InferenceFlag) {
// TODO: 1 bit or ae(v)
if vid.PPS.EntropyCodingMode == 1 {
binarization := NewBinarization("Transform8x8Flag", sliceContext.Slice.SliceData)
cabac = initCabac(binarization, nil, sliceContext)
// TODO: fix nil argument.
binarization.Decode(sliceContext, br, nil)
logger.Printf("TODO: ae for TranformSize8x8Flag\n")
} else {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "coult not read TransformSize8x8Flag")
}
sliceContext.Slice.SliceData.TransformSize8x8Flag = b == 1
}
}
}
m, err = MbPartPredMode(sliceContext.Slice.SliceData, sliceContext.Slice.SliceData.SliceTypeName, sliceContext.Slice.SliceData.MbType, 0)
if err != nil {
return nil, errors.Wrap(err, "could not get mbPartPredMode")
}
if CodedBlockPatternLuma(sliceContext.Slice.SliceData) > 0 || CodedBlockPatternChroma(sliceContext.Slice.SliceData) > 0 || m == intra16x16 {
// TODO: se or ae(v)
if vid.PPS.EntropyCodingMode == 1 {
binarization := NewBinarization("MbQpDelta", sliceContext.Slice.SliceData)
cabac = initCabac(binarization, nil, sliceContext)
// TODO; fix nil argument
binarization.Decode(sliceContext, br, nil)
logger.Printf("TODO: ae for MbQpDelta\n")
} else {
sliceContext.Slice.SliceData.MbQpDelta, _ = readSe(br)
}
}
}
} // END MacroblockLayer
if vid.PPS.EntropyCodingMode == 0 {
moreDataFlag = moreRBSPData(br)
} else {
if sliceContext.Slice.SliceData.SliceTypeName != "I" && sliceContext.Slice.SliceData.SliceTypeName != "SI" {
if sliceContext.Slice.SliceData.MbSkipFlag {
prevMbSkipped = 1
} else {
prevMbSkipped = 0
}
}
if mbaffFrameFlag == 1 && currMbAddr%2 == 0 {
moreDataFlag = true
} else {
// TODO: ae implementation
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read EndOfSliceFlag")
}
sliceContext.Slice.SliceData.EndOfSliceFlag = b == 1
moreDataFlag = !sliceContext.Slice.SliceData.EndOfSliceFlag
}
}
currMbAddr = nextMbAddress(currMbAddr, vid.SPS, vid.PPS, sliceContext.Slice.SliceHeader)
} // END while moreDataFlag
return sliceContext.Slice.SliceData, nil
}
func (c *SliceContext) Update(header *SliceHeader, data *SliceData) {
c.Slice = &Slice{SliceHeader: header, SliceData: data}
}
func NewSliceContext(vid *VideoStream, nalUnit *NALUnit, rbsp []byte, showPacket bool) (*SliceContext, error) {
var err error
sps := vid.SPS
pps := vid.PPS
logger.Printf("debug: %s RBSP %d bytes %d bits == \n", NALUnitType[int(nalUnit.Type)], len(rbsp), len(rbsp)*8)
logger.Printf("debug: \t%#v\n", rbsp[0:8])
var idrPic bool
if nalUnit.Type == 5 {
idrPic = true
}
header := SliceHeader{}
if sps.SeparateColorPlaneFlag {
vid.ChromaArrayType = 0
} else {
vid.ChromaArrayType = int(sps.ChromaFormatIDC)
}
br := bits.NewBitReader(bytes.NewReader(rbsp))
r := newFieldReader(br)
header.FirstMbInSlice = int(r.readUe())
header.SliceType = int(r.readUe())
sliceType := sliceTypeMap[header.SliceType]
logger.Printf("debug: %s (%s) slice of %d bytes\n", NALUnitType[int(nalUnit.Type)], sliceType, len(rbsp))
header.PPSID = int(r.readUe())
if sps.SeparateColorPlaneFlag {
b, err := br.ReadBits(2)
if err != nil {
return nil, errors.Wrap(err, "could not read ColorPlaneID")
}
header.ColorPlaneID = int(b)
}
// TODO: See 7.4.3
// header.FrameNum = b.NextField("FrameNum", 0)
if !sps.FrameMBSOnlyFlag {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read FieldPic")
}
header.FieldPic = b == 1
if header.FieldPic {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read BottomField")
}
header.BottomField = b == 1
}
}
if idrPic {
header.IDRPicID = int(r.readUe())
}
if sps.PicOrderCountType == 0 {
b, err := br.ReadBits(int(sps.Log2MaxPicOrderCntLSBMin4 + 4))
if err != nil {
return nil, errors.Wrap(err, "could not read PicOrderCntLsb")
}
header.PicOrderCntLsb = int(b)
if pps.BottomFieldPicOrderInFramePresent && !header.FieldPic {
header.DeltaPicOrderCntBottom, err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse DeltaPicOrderCntBottom")
}
}
}
if sps.PicOrderCountType == 1 && !sps.DeltaPicOrderAlwaysZeroFlag {
header.DeltaPicOrderCnt[0], err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse DeltaPicOrderCnt")
}
if pps.BottomFieldPicOrderInFramePresent && !header.FieldPic {
header.DeltaPicOrderCnt[1], err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse DeltaPicOrderCnt")
}
}
}
if pps.RedundantPicCntPresent {
header.RedundantPicCnt = int(r.readUe())
}
if sliceType == "B" {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read DirectSpatialMvPred")
}
header.DirectSpatialMvPred = b == 1
}
if sliceType == "B" || sliceType == "SP" {
b, err := br.ReadBits(1)
if err != nil {
return nil, errors.Wrap(err, "could not read NumRefIdxActiveOverride")
}
header.NumRefIdxActiveOverride = b == 1
if header.NumRefIdxActiveOverride {
header.NumRefIdxL0ActiveMinus1 = int(r.readUe())
if sliceType == "B" {
header.NumRefIdxL1ActiveMinus1 = int(r.readUe())
}
}
}
if nalUnit.Type == 20 || nalUnit.Type == 21 {
// Annex H
// H.7.3.3.1.1
// refPicListMvcModifications()
} else {
header.RefPicListModification, err = NewRefPicListModification(br, pps, &header)
if err != nil {
return nil, errors.Wrap(err, "could not parse RefPicListModification")
}
}
if (pps.WeightedPred && (sliceType == "P" || sliceType == "SP")) || (pps.WeightedBipred == 1 && sliceType == "B") {
header.PredWeightTable, err = NewPredWeightTable(br, &header, vid.ChromaArrayType)
if err != nil {
return nil, errors.Wrap(err, "could not parse PredWeightTable")
}
}
if nalUnit.RefIdc != 0 {
// devRefPicMarking()
header.DecRefPicMarking, err = NewDecRefPicMarking(br, idrPic)
if err != nil {
return nil, errors.Wrap(err, "could not parse DecRefPicMarking")
}
}
if pps.EntropyCodingMode == 1 && sliceType != "I" && sliceType != "SI" {
header.CabacInit = int(r.readUe())
}
header.SliceQpDelta = int(r.readSe())
if sliceType == "SP" || sliceType == "SI" {
if sliceType == "SP" {
header.SpForSwitch = r.readBits(1) == 1
}
header.SliceQsDelta = int(r.readSe())
}
if pps.DeblockingFilterControlPresent {
header.DisableDeblockingFilter = int(r.readUe())
if header.DisableDeblockingFilter != 1 {
header.SliceAlphaC0OffsetDiv2, err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse SliceAlphaC0OffsetDiv2")
}
header.SliceBetaOffsetDiv2, err = readSe(br)
if err != nil {
return nil, errors.Wrap(err, "could not parse SliceBetaOffsetDiv2")
}
}
}
if pps.NumSliceGroupsMinus1 > 0 && pps.SliceGroupMapType >= 3 && pps.SliceGroupMapType <= 5 {
b, err := br.ReadBits(int(math.Ceil(math.Log2(float64(pps.PicSizeInMapUnitsMinus1/pps.SliceGroupChangeRateMinus1 + 1)))))
if err != nil {
return nil, errors.Wrap(err, "could not read SliceGruopChangeCycle")
}
header.SliceGroupChangeCycle = int(b)
}
sliceContext := &SliceContext{
NALUnit: nalUnit,
Slice: &Slice{
SliceHeader: &header,
},
}
sliceContext.Slice.SliceData, err = NewSliceData(vid.ChromaArrayType, nil, sliceContext, br)
if err != nil {
return nil, errors.Wrap(err, "could not create slice data")
}
return sliceContext, nil
}