/* 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" "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 picture struct { *SliceContext isIDR bool isBottomField bool isTopField bool } type VideoStream struct { *SPS *PPS Slices []*SliceContext ChromaArrayType int priorPic *picture currPic *picture maxPicOrderCntLsb int picOrderCntMsb int idrPicFlag bool frameNumOffset int expectedDeltaPerPicOrderCntCycle int topFieldOrderCnt int bottomFieldOrderCnt int } type SliceContext struct { *SPS *PPS *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 }