codec/h264/h264dec: merged in master, fixed conflicts and problems that that resulted

This commit is contained in:
Saxon 2019-08-05 13:46:02 +09:30
commit 951d9dd244
8 changed files with 572 additions and 251 deletions

View File

@ -164,6 +164,11 @@ func (br *BitReader) ByteAligned() bool {
return br.bits == 0
}
// Off returns the current offset from the starting bit of the current byte.
func (br *BitReader) Off() int {
return br.bits
}
// BytesRead returns the number of bytes that have been read by the BitReader.
func (br *BitReader) BytesRead() int {
return br.nRead

View File

@ -0,0 +1,41 @@
/*
DESCRIPTION
helpers.go provides general helper utilities.
AUTHORS
Saxon Nelson-Milton <saxon@ausocean.org>, The Australian Ocean Laboratory (AusOcean)
*/
package h264dec
import "errors"
// binToSlice is a helper function to convert a string of binary into a
// corresponding byte slice, e.g. "0100 0001 1000 1100" => {0x41,0x8c}.
// Spaces in the string are ignored.
func binToSlice(s string) ([]byte, error) {
var (
a byte = 0x80
cur byte
bytes []byte
)
for _, c := range s {
switch c {
case ' ':
continue
case '1':
cur |= a
case '0':
default:
return nil, errors.New("invalid binary string")
}
a >>= 1
if a == 0 {
bytes = append(bytes, cur)
cur = 0
a = 0x80
}
}
return bytes, nil
}

View File

@ -89,13 +89,13 @@ func TestReadSe(t *testing.T) {
in []byte // Bitstring to read.
want int // Expected value from se(v) parsing process.
}{
{[]byte{0x80}, 0},
{[]byte{0x40}, 1},
{[]byte{0x60}, -1},
{[]byte{0x20}, 2},
{[]byte{0x28}, -2},
{[]byte{0x30}, 3},
{[]byte{0x38}, -3},
{[]byte{0x80}, 0}, // Bit string: 1, codeNum: 0, syntax element val: 0
{[]byte{0x40}, 1}, // Bit string: 010, codeNum: 1, syntax element val: 1
{[]byte{0x60}, -1}, // Bit string: 011, codeNum: 2, syntax element val: -1
{[]byte{0x20}, 2}, // Bit string: 00100, codeNum: 3, syntax element val: 2
{[]byte{0x28}, -2}, // Bit string: 00101, codeNum: 4, syntax element val: -2
{[]byte{0x30}, 3}, // Bit string: 00110, codeNum: 5, syntax element val: 3
{[]byte{0x38}, -3}, // Bit string: 00111, codeNum: 6, syntax element val: -3
}
for i, test := range tests {

View File

@ -13,9 +13,8 @@ import (
type PPS struct {
ID, SPSID int
EntropyCodingMode int
NumSliceGroupsMinus1 int
BottomFieldPicOrderInFramePresent bool
NumSlicGroupsMinus1 int
NumSliceGroupsMinus1 int
SliceGroupMapType int
RunLengthMinus1 []int
TopLeft []int
@ -40,12 +39,8 @@ type PPS struct {
SecondChromaQpIndexOffset int
}
func NewPPS(sps *SPS, rbsp []byte, showPacket bool) (*PPS, error) {
logger.Printf("debug: PPS RBSP %d bytes %d bits == \n", len(rbsp), len(rbsp)*8)
logger.Printf("debug: \t%#v\n", rbsp[0:8])
func NewPPS(br *bits.BitReader, chromaFormat int) (*PPS, error) {
pps := PPS{}
// TODO: give this io.Reader
br := bits.NewBitReader(nil)
r := newFieldReader(br)
pps.ID = int(r.readUe())
@ -97,7 +92,7 @@ func NewPPS(sps *SPS, rbsp []byte, showPacket bool) (*PPS, error) {
if pps.PicScalingMatrixPresent {
v := 6
if sps.ChromaFormatIDC != chroma444 {
if chromaFormat != chroma444 {
v = 2
}
for i := 0; i < 6+(v*pps.Transform8x8Mode); i++ {
@ -125,7 +120,5 @@ func NewPPS(sps *SPS, rbsp []byte, showPacket bool) (*PPS, error) {
moreRBSPData(br)
// rbspTrailingBits()
}
return &pps, nil
}

View File

@ -0,0 +1,123 @@
/*
DESCRIPTION
pps_test.go provides testing for parsing functionality found in pps.go.
AUTHORS
Saxon Nelson-Milton <saxon@ausocean.org>, The Australian Ocean Laboratory (AusOcean)
*/
package h264dec
import (
"bytes"
"reflect"
"testing"
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
)
func TestNewPPS(t *testing.T) {
// TODO: add test with scaling list once we have a test for scalingList func.
tests := []struct {
in string
chromaFormat int
want PPS
}{
{
in: "1" + // ue(v) pic_parameter_set_id = 0
"1" + // ue(v) seq_parameter_set_id = 0
"1" + // u(1) entropy_coding_mode_flag = 1
"0" + // u(1) pic_order_present_flag = 0
"1" + // ue(v) num_slice_groups_minus1 = 0
"1" + // ue(v) num_ref_idx_L0_active_minus1 = 0
"1" + // ue(v) num_ref_idx_L1_active_minus1 = 0
"1" + // u(1) weighted_pred_flag = 1
"00" + // u(2) weighted_bipred_idc = 0
"1" + // se(v) pic_init_qp_minus26 = 0
"1" + // se(v) pic_init_qs_minus26 = 0
"1" + // se(v) chroma_qp_index_offset = 0
"1" + // u(1) deblocking_filter_control_present_flag = 1
"0" + // u(1) constrained_intra_pred_flag = 0
"0" + // u(1) redundant_pic_cnt_present_flag = 0
"10000000", // rbspTrailingBits
want: PPS{
ID: 0,
SPSID: 0,
EntropyCodingMode: 1,
BottomFieldPicOrderInFramePresent: false,
NumSliceGroupsMinus1: 0,
NumRefIdxL0DefaultActiveMinus1: 0,
NumRefIdxL1DefaultActiveMinus1: 0,
WeightedPred: true,
WeightedBipred: 0,
PicInitQpMinus26: 0,
PicInitQsMinus26: 0,
ChromaQpIndexOffset: 0,
DeblockingFilterControlPresent: true,
ConstrainedIntraPred: false,
RedundantPicCntPresent: false,
},
},
{
in: "1" + // ue(v) pic_parameter_set_id = 0
"1" + // ue(v) seq_parameter_set_id = 0
"1" + // u(1) entropy_coding_mode_flag = 1
"1" + // u(1) bottom_field_pic_order_in_frame_present_flag = 1
"010" + // ue(v) num_slice_groups_minus1 = 1
"1" + // ue(v) slice_group_map_type = 0
"1" + // ue(v) run_length_minus1[0] = 0
"1" + // ue(v) run_length_minus1[1] = 0
"1" + // ue(v) num_ref_idx_L0_active_minus1 = 0
"1" + // ue(v) num_ref_idx_L1_active_minus1 = 0
"1" + // u(1) weighted_pred_flag = 0
"00" + // u(2) weighted_bipred_idc = 0
"011" + // se(v) pic_init_qp_minus26 = -1
"010" + // se(v) pic_init_qs_minus26 = 1
"00100" + // se(v) chroma_qp_index_offset = 2
"0" + // u(1) deblocking_filter_control_present_flag =0
"0" + // u(1) constrained_intra_pred_flag=0
"0" + // u(1) redundant_pic_cnt_present_flag=0
"0" + // u(1) transform_8x8_mode_flag=0
"0" + // u(1) pic_scaling_matrix_present_flag=0
"00100" + // se(v) second_chroma_qp_index_offset=2
"10000", // stop bit and trailing bits
want: PPS{
ID: 0,
SPSID: 0,
EntropyCodingMode: 1,
BottomFieldPicOrderInFramePresent: true,
NumSliceGroupsMinus1: 1,
RunLengthMinus1: []int{0, 0},
NumRefIdxL0DefaultActiveMinus1: 0,
NumRefIdxL1DefaultActiveMinus1: 0,
WeightedPred: true,
WeightedBipred: 0,
PicInitQpMinus26: -1,
PicInitQsMinus26: 1,
ChromaQpIndexOffset: 2,
DeblockingFilterControlPresent: false,
ConstrainedIntraPred: false,
RedundantPicCntPresent: false,
Transform8x8Mode: 0,
PicScalingMatrixPresent: false,
SecondChromaQpIndexOffset: 2,
},
},
}
for i, test := range tests {
bin, err := binToSlice(test.in)
if err != nil {
t.Fatalf("error: %v converting binary string to slice for test: %d", err, i)
}
pps, err := NewPPS(bits.NewBitReader(bytes.NewReader(bin)), test.chromaFormat)
if err != nil {
t.Fatalf("did not expect error: %v for test: %d", err, i)
}
if !reflect.DeepEqual(test.want, *pps) {
t.Errorf("did not get expected result for test: %d.\nGot: %+v\nWant: %+v\n", i, *pps, test.want)
}
}
}

View File

@ -71,7 +71,8 @@ func (h *H264Reader) Start() {
case naluTypePPS:
videoStream := h.VideoStreams[len(h.VideoStreams)-1]
// TODO: handle this error
videoStream.PPS, _ = NewPPS(videoStream.SPS, nalUnit.RBSP, false)
// TODO: fix chromaFormat
videoStream.PPS, _ = NewPPS(nil, 0)
case naluTypeSliceIDRPicture:
fallthrough
case naluTypeSliceNonIDRPicture:
@ -177,23 +178,63 @@ func isEmpty3Byte(buf []byte) bool {
return true
}
// TODO: complete this.
func moreRBSPData(br *bits.BitReader) bool {
// Read until the least significant bit of any remaining bytes
// If the least significant bit is 1, that marks the first bit
// of the rbspTrailingBits() struct. If the bits read is more
// than 0, then there is more RBSP data
var bits uint64
cnt := 0
for bits != 1 {
if _, err := br.ReadBits(8); err != nil {
logger.Printf("moreRBSPData error: %v\n", err)
return false
}
cnt++
// If we get an error then we must at end of NAL unit or end of stream, so
// return false.
b, err := br.PeekBits(1)
if err != nil {
return false
}
logger.Printf("moreRBSPData: read %d additional bits\n", cnt)
return cnt > 0
// If b is not 1, then we don't have a stop bit and therefore there is more
// data so return true.
if b == 0 {
return true
}
// If we have a stop bit and trailing zeros then we're okay, otherwise return
// now, we haven't found the end.
b, err = br.PeekBits(8 - br.Off())
if err != nil {
return false
}
rem := 0x01 << uint(7-br.Off())
if int(b) != rem {
return true
}
// If we try to read another bit but get EOF then we must be at the end of the
// NAL or stream.
_, err = br.PeekBits(9 - br.Off())
if err != nil {
return false
}
// Do we have some trailing 0 bits, and then a 24-bit start code ? If so, it
// there must not be any more RBSP data left.
// If we get an error from the Peek, then there must not be another NAL, and
// there must be some more RBSP, because trailing bits do not extend past the
// byte in which the stop bit is found.
b, err = br.PeekBits(8 - br.Off() + 24)
if err != nil {
return true
}
rem = (0x01 << uint((7-br.Off())+24)) | 0x01
if int(b) == rem {
return false
}
// Similar check to above, but this time checking for 32-bit start code.
b, err = br.PeekBits(8 - br.Off() + 32)
if err != nil {
return true
}
rem = (0x01 << uint((7-br.Off())+32)) | 0x01
if int(b) == rem {
return false
}
return true
}
type field struct {

View File

@ -0,0 +1,59 @@
/*
DESCRIPTION
read_test.go provides testing for utilities in read.go.
AUTHORS
Saxon Nelson-Milton <saxon@ausocean.org>, The Australian Ocean Laboratory (AusOcean)
*/
package h264dec
import (
"bytes"
"testing"
"bitbucket.org/ausocean/av/codec/h264/h264dec/bits"
)
func TestMoreRBSPData(t *testing.T) {
tests := []struct {
in string
want bool
}{
{
in: "00000100",
want: true,
},
{
in: "10000100",
want: true,
},
{
in: "10000000",
want: false,
},
{
in: "10000000 00000000 00000000 00000001",
want: false,
},
{
in: "10000000 00000000 00000000 00000000 00000001",
want: false,
},
{
in: "10000000 00000000",
want: true,
},
}
for i, test := range tests {
b, err := binToSlice(test.in)
if err != nil {
t.Fatalf("unexpected binToSlice error: %v for test: %d", err, i)
}
got := moreRBSPData(bits.NewBitReader(bytes.NewReader(b)))
if got != test.want {
t.Errorf("unexpected result for test: %d\nGot: %v\nWant: %v\n", i, got, test.want)
}
}
}

View File

@ -32,51 +32,196 @@ 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) {
ref := &RefPicListModification{}
r := newFieldReader(br)
// 7.3.3.1
if h.SliceType%5 != 2 && h.SliceType%5 != 4 {
ref.RefPicListModificationFlagL0 = r.readBits(1) == 1
if ref.RefPicListModificationFlagL0 {
for ref.ModificationOfPicNums != 3 {
ref.ModificationOfPicNums = int(r.readUe())
if ref.ModificationOfPicNums == 0 || ref.ModificationOfPicNums == 1 {
ref.AbsDiffPicNumMinus1 = int(r.readUe())
} else if ref.ModificationOfPicNums == 2 {
ref.LongTermPicNum = int(r.readUe())
}
}
}
}
if h.SliceType%5 == 1 {
ref.RefPicListModificationFlagL1 = r.readBits(1) == 1
if ref.RefPicListModificationFlagL1 {
for ref.ModificationOfPicNums != 3 {
ref.ModificationOfPicNums = int(r.readUe())
if ref.ModificationOfPicNums == 0 || ref.ModificationOfPicNums == 1 {
ref.AbsDiffPicNumMinus1 = int(r.readUe())
} else if ref.ModificationOfPicNums == 2 {
ref.LongTermPicNum = int(r.readUe())
}
}
}
}
// 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{}
r := newFieldReader(br)
p.LumaLog2WeightDenom = int(r.readUe())
if p.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 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 +231,82 @@ 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{}
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 {
d.MemoryManagementControlOperation = int(r.readUe())
for d.MemoryManagementControlOperation != 0 {
if d.MemoryManagementControlOperation == 1 || d.MemoryManagementControlOperation == 3 {
d.DifferenceOfPicNumsMinus1 = int(r.readUe())
}
if d.MemoryManagementControlOperation == 2 {
h.RefPicListModification.LongTermPicNum = int(r.readUe())
}
if d.MemoryManagementControlOperation == 3 || d.MemoryManagementControlOperation == 6 {
d.LongTermFrameIdx = int(r.readUe())
}
if d.MemoryManagementControlOperation == 4 {
d.MaxLongTermFrameIdxPlus1 = int(r.readUe())
}
}
}
}
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
@ -1040,186 +1261,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 = int(r.readUe())
if header.ModificationOfPicNums == 0 || header.ModificationOfPicNums == 1 {
header.AbsDiffPicNumMinus1 = int(r.readUe())
} else if header.ModificationOfPicNums == 2 {
header.LongTermPicNum = int(r.readUe())
}
}
}
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 = int(r.readUe())
if header.ModificationOfPicNums == 0 || header.ModificationOfPicNums == 1 {
header.AbsDiffPicNumMinus1 = int(r.readUe())
} else if header.ModificationOfPicNums == 2 {
header.LongTermPicNum = int(r.readUe())
}
}
}
}
// refPicListModification()
}
if (pps.WeightedPred && (sliceType == "P" || sliceType == "SP")) || (pps.WeightedBipred == 1 && sliceType == "B") {
// predWeightTable()
header.LumaLog2WeightDenom = int(r.readUe())
if header.ChromaArrayType != 0 {
header.ChromaLog2WeightDenom = int(r.readUe())
header.PredWeightTable, err = NewPredWeightTable(br, &header)
if err != nil {
return nil, errors.Wrap(err, "could not parse PredWeightTable")
}
for i := 0; i <= header.NumRefIdxL0ActiveMinus1; i++ {
header.LumaWeightL0Flag = r.readBits(1) == 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 = int(r.readUe())
for header.MemoryManagementControlOperation != 0 {
if header.MemoryManagementControlOperation == 1 || header.MemoryManagementControlOperation == 3 {
header.DifferenceOfPicNumsMinus1 = int(r.readUe())
}
if header.MemoryManagementControlOperation == 2 {
header.LongTermPicNum = int(r.readUe())
}
if header.MemoryManagementControlOperation == 3 || header.MemoryManagementControlOperation == 6 {
header.LongTermFrameIdx = int(r.readUe())
}
if header.MemoryManagementControlOperation == 4 {
header.MaxLongTermFrameIdxPlus1 = int(r.readUe())
}
}
}
} // 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 = int(r.readUe())