mirror of https://bitbucket.org/ausocean/av.git
codec/h264/h264dec: merged in master, fixed conflicts and problems that that resulted
This commit is contained in:
commit
951d9dd244
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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())
|
||||
|
|
Loading…
Reference in New Issue