diff --git a/codec/h264/h264dec/slice.go b/codec/h264/h264dec/slice.go index 93e2a6e4..18fb7a69 100644 --- a/codec/h264/h264dec/slice.go +++ b/codec/h264/h264dec/slice.go @@ -32,51 +32,231 @@ type Slice struct { Header *SliceHeader Data *SliceData } -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 - CabacInit int - SliceQpDelta int - SpForSwitch bool - SliceQsDelta int - DisableDeblockingFilter int - SliceAlphaC0OffsetDiv2 int - SliceBetaOffsetDiv2 int - SliceGroupChangeCycle int - RefPicListModificationFlagL0 bool - ModificationOfPicNums int - AbsDiffPicNumMinus1 int - LongTermPicNum int - RefPicListModificationFlagL1 bool - LumaLog2WeightDenom int - ChromaLog2WeightDenom int - ChromaArrayType 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 + +// 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 { + RefPicListModificationFlagL0 bool + ModificationOfPicNums int + AbsDiffPicNumMinus1 int + LongTermPicNum int + RefPicListModificationFlagL1 bool +} + +// 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, h *SliceHeader) (*RefPicListModification, error) { + r := &RefPicListModification{} + // 7.3.3.1 + if h.SliceType%5 != 2 && h.SliceType%5 != 4 { + b, err := br.ReadBits(1) + if err != nil { + return nil, errors.Wrap(err, "could not read RefPicListModificationFlagL0") + } + r.RefPicListModificationFlagL0 = b == 1 + + if r.RefPicListModificationFlagL0 { + for r.ModificationOfPicNums != 3 { + r.ModificationOfPicNums, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse ModificationOfPicNums") + } + + if r.ModificationOfPicNums == 0 || r.ModificationOfPicNums == 1 { + r.AbsDiffPicNumMinus1, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse AbsDiffPicNumMinus1") + } + } else if r.ModificationOfPicNums == 2 { + r.LongTermPicNum, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse LongTermPicNum") + } + } + } + } + + } + if h.SliceType%5 == 1 { + b, err := br.ReadBits(1) + if err != nil { + return nil, errors.Wrap(err, "could not read RefPicListModificationFlagL1") + } + r.RefPicListModificationFlagL1 = b == 1 + + if r.RefPicListModificationFlagL1 { + for r.ModificationOfPicNums != 3 { + r.ModificationOfPicNums, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse ModificationOfPicNums") + } + + if r.ModificationOfPicNums == 0 || r.ModificationOfPicNums == 1 { + r.AbsDiffPicNumMinus1, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse AbsDiffPicNumMinus1") + } + } else if r.ModificationOfPicNums == 2 { + r.LongTermPicNum, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse LongTermPicNum") + } + } + } + } + } + // refPicListModification() + return nil, 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 + ChromaArrayType 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) (*PredWeightTable, error) { + p := &PredWeightTable{} + var err error + + p.LumaLog2WeightDenom, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse LumaLog2WeightDenom") + } + + if p.ChromaArrayType != 0 { + p.ChromaLog2WeightDenom, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse ChromaLog2WeightDenom") + } + } + for i := 0; i <= h.NumRefIdxL0ActiveMinus1; i++ { + b, err := br.ReadBits(1) + if err != nil { + return nil, errors.Wrap(err, "could not read LumaWeightL0Flag") + } + p.LumaWeightL0Flag = b == 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 p.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 p.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 @@ -86,6 +266,96 @@ type SliceHeader struct { 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, h *SliceHeader) (*DecRefPicMarking, error) { + d := &DecRefPicMarking{} + 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 { + d.MemoryManagementControlOperation, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse MemoryManagementControlOperation") + } + for d.MemoryManagementControlOperation != 0 { + if d.MemoryManagementControlOperation == 1 || d.MemoryManagementControlOperation == 3 { + d.DifferenceOfPicNumsMinus1, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse MemoryManagementControlOperation") + } + } + if d.MemoryManagementControlOperation == 2 { + h.RefPicListModification.LongTermPicNum, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse LongTermPicNum") + } + } + if d.MemoryManagementControlOperation == 3 || d.MemoryManagementControlOperation == 6 { + d.LongTermFrameIdx, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse LongTermFrameIdx") + } + } + if d.MemoryManagementControlOperation == 4 { + d.MaxLongTermFrameIdxPlus1, err = readUe(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse MaxLongTermFrameIdxPlus1") + } + } + } + } + } + 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 @@ -1075,229 +1345,24 @@ func NewSliceContext(videoStream *VideoStream, nalUnit *NALUnit, rbsp []byte, sh // H.7.3.3.1.1 // refPicListMvcModifications() } else { - // 7.3.3.1 - if header.SliceType%5 != 2 && header.SliceType%5 != 4 { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read RefPicListModificationFlagL0") - } - header.RefPicListModificationFlagL0 = b == 1 - - if header.RefPicListModificationFlagL0 { - for header.ModificationOfPicNums != 3 { - header.ModificationOfPicNums, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse ModificationOfPicNums") - } - - if header.ModificationOfPicNums == 0 || header.ModificationOfPicNums == 1 { - header.AbsDiffPicNumMinus1, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse AbsDiffPicNumMinus1") - } - } else if header.ModificationOfPicNums == 2 { - header.LongTermPicNum, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse LongTermPicNum") - } - } - } - } - + header.RefPicListModification, err = NewRefPicListModification(br, &header) + if err != nil { + return nil, errors.Wrap(err, "could not parse RefPicListModification") } - if header.SliceType%5 == 1 { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read RefPicListModificationFlagL1") - } - header.RefPicListModificationFlagL1 = b == 1 - - if header.RefPicListModificationFlagL1 { - for header.ModificationOfPicNums != 3 { - header.ModificationOfPicNums, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse ModificationOfPicNums") - } - - if header.ModificationOfPicNums == 0 || header.ModificationOfPicNums == 1 { - header.AbsDiffPicNumMinus1, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse AbsDiffPicNumMinus1") - } - } else if header.ModificationOfPicNums == 2 { - header.LongTermPicNum, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse LongTermPicNum") - } - } - } - } - } - // refPicListModification() } if (pps.WeightedPred && (sliceType == "P" || sliceType == "SP")) || (pps.WeightedBipred == 1 && sliceType == "B") { - // predWeightTable() - header.LumaLog2WeightDenom, err = readUe(br) + header.PredWeightTable, err = NewPredWeightTable(br, &header) if err != nil { - return nil, errors.Wrap(err, "could not parse LumaLog2WeightDenom") + return nil, errors.Wrap(err, "could not parse PredWeightTable") } - - if header.ChromaArrayType != 0 { - header.ChromaLog2WeightDenom, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse ChromaLog2WeightDenom") - } - } - for i := 0; i <= header.NumRefIdxL0ActiveMinus1; i++ { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read LumaWeightL0Flag") - } - header.LumaWeightL0Flag = b == 1 - - if header.LumaWeightL0Flag { - se, err := readSe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse LumaWeightL0") - } - header.LumaWeightL0 = append(header.LumaWeightL0, se) - - se, err = readSe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse LumaOffsetL0") - } - header.LumaOffsetL0 = append(header.LumaOffsetL0, se) - } - if header.ChromaArrayType != 0 { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read ChromaWeightL0Flag") - } - header.ChromaWeightL0Flag = b == 1 - - if header.ChromaWeightL0Flag { - header.ChromaWeightL0 = append(header.ChromaWeightL0, []int{}) - header.ChromaOffsetL0 = append(header.ChromaOffsetL0, []int{}) - for j := 0; j < 2; j++ { - se, err := readSe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse ChromaWeightL0") - } - header.ChromaWeightL0[i] = append(header.ChromaWeightL0[i], se) - - se, err = readSe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse ChromaOffsetL0") - } - header.ChromaOffsetL0[i] = append(header.ChromaOffsetL0[i], se) - } - } - } - } - if header.SliceType%5 == 1 { - for i := 0; i <= header.NumRefIdxL1ActiveMinus1; i++ { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read LumaWeightL1Flag") - } - header.LumaWeightL1Flag = b == 1 - - if header.LumaWeightL1Flag { - se, err := readSe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse LumaWeightL1") - } - header.LumaWeightL1 = append(header.LumaWeightL1, se) - - se, err = readSe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse LumaOffsetL1") - } - header.LumaOffsetL1 = append(header.LumaOffsetL1, se) - } - if header.ChromaArrayType != 0 { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read ChromaWeightL1Flag") - } - header.ChromaWeightL1Flag = b == 1 - - if header.ChromaWeightL1Flag { - header.ChromaWeightL1 = append(header.ChromaWeightL1, []int{}) - header.ChromaOffsetL1 = append(header.ChromaOffsetL1, []int{}) - for j := 0; j < 2; j++ { - se, err := readSe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse ChromaWeightL1") - } - header.ChromaWeightL1[i] = append(header.ChromaWeightL1[i], se) - - se, err = readSe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse ChromaOffsetL1") - } - header.ChromaOffsetL1[i] = append(header.ChromaOffsetL1[i], se) - } - } - } - } - } - } // end predWeightTable + } if nalUnit.RefIdc != 0 { // devRefPicMarking() - if idrPic { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read NoOutputOfPriorPicsFlag") - } - header.NoOutputOfPriorPicsFlag = b == 1 - - b, err = br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read LongTermReferenceFlag") - } - header.LongTermReferenceFlag = b == 1 - } else { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read AdaptiveRefPicMarkingModeFlag") - } - header.AdaptiveRefPicMarkingModeFlag = b == 1 - - if header.AdaptiveRefPicMarkingModeFlag { - header.MemoryManagementControlOperation, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse MemoryManagementControlOperation") - } - for header.MemoryManagementControlOperation != 0 { - if header.MemoryManagementControlOperation == 1 || header.MemoryManagementControlOperation == 3 { - header.DifferenceOfPicNumsMinus1, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse MemoryManagementControlOperation") - } - } - if header.MemoryManagementControlOperation == 2 { - header.LongTermPicNum, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse LongTermPicNum") - } - } - if header.MemoryManagementControlOperation == 3 || header.MemoryManagementControlOperation == 6 { - header.LongTermFrameIdx, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse LongTermFrameIdx") - } - } - if header.MemoryManagementControlOperation == 4 { - header.MaxLongTermFrameIdxPlus1, err = readUe(br) - if err != nil { - return nil, errors.Wrap(err, "could not parse MaxLongTermFrameIdxPlus1") - } - } - } - } - } // end decRefPicMarking + header.DecRefPicMarking, err = NewDecRefPicMarking(br, idrPic, &header) + if err != nil { + return nil, errors.Wrap(err, "could not parse DecRefPicMarking") + } } if pps.EntropyCodingMode == 1 && sliceType != "I" && sliceType != "SI" { header.CabacInit, err = readUe(br)