diff --git a/codec/h264/h264dec/frame.go b/codec/h264/h264dec/frame.go index 9e240a45..82b32ae5 100644 --- a/codec/h264/h264dec/frame.go +++ b/codec/h264/h264dec/frame.go @@ -19,6 +19,8 @@ const ( naluTypePrefixNALU naluTypeSubsetSPS naluTypeDepthParamSet + naluTypeSliceLayerExtRBSP = 20 + naluTypeSliceLayerExtRBSP2 = 21 ) var ( diff --git a/codec/h264/h264dec/nalunit.go b/codec/h264/h264dec/nalunit.go index 49d34aea..f1535855 100644 --- a/codec/h264/h264dec/nalunit.go +++ b/codec/h264/h264dec/nalunit.go @@ -1,161 +1,291 @@ +/* +DESCRIPTION + nalunit.go provides structures for a NAL unit as well as it's extensions. + +AUTHORS + Saxon Nelson-Milton , The Australian Ocean Laboratory (AusOcean) + mrmod +*/ + package h264dec import ( - "bitbucket.org/ausocean/av/codec/h264/h264dec/bits" + "fmt" + "io" + "github.com/pkg/errors" + + "bitbucket.org/ausocean/av/codec/h264/h264dec/bits" ) -type NalUnit struct { - NumBytes int - ForbiddenZeroBit int - RefIdc int - Type int - SvcExtensionFlag int - Avc3dExtensionFlag int - IdrFlag int - PriorityId int - NoInterLayerPredFlag int - DependencyId int - QualityId int - TemporalId int - UseRefBasePicFlag int - DiscardableFlag int - OutputFlag int - ReservedThree2Bits int - HeaderBytes int - NonIdrFlag int - ViewId int - AnchorPicFlag int - InterViewFlag int - ReservedOneBit int - ViewIdx int - DepthFlag int +// MVCExtension describes a NAL unit header multiview video coding extension, as +// defined in section H.7.3.1.1 of the specifications. +// Semantics of fields are specified in section H.7.4.1.1. +type MVCExtension struct { + // non_idr_flag, if true indicates that access unit is not IDR. + NonIdrFlag bool + + // priority_id, indicates priority of NAL unit. A lower value => higher priority. + PriorityID uint8 + + // view_id, specifies a view identifier for the unit. Units with identical + // view_id are in the same view. + ViewID uint32 + + // temporal_id, temporal identifier for the unit. + TemporalID uint8 + + // anchor_pic_flag, if true access unit is an anchor access unit. + AnchorPicFlag bool + + // inter_view_flag, if false current view component not used for inter-view + // prediction elsewhere in access unit. + InterViewFlag bool + + // reserved_one_bit, always 1 (ignored by decoders) + ReservedOneBit uint8 +} + +// NewMVCExtension parses a NAL unit header multiview video coding extension +// from br following the syntax structure specified in section H.7.3.1.1, and +// returns as a new MVCExtension. +func NewMVCExtension(br *bits.BitReader) (*MVCExtension, error) { + e := &MVCExtension{} + r := newFieldReader(br) + + e.NonIdrFlag = r.readBits(1) == 1 + e.PriorityID = uint8(r.readBits(6)) + e.ViewID = uint32(r.readBits(10)) + e.TemporalID = uint8(r.readBits(3)) + e.AnchorPicFlag = r.readBits(1) == 1 + e.InterViewFlag = r.readBits(1) == 1 + e.ReservedOneBit = uint8(r.readBits(1)) + + if r.err() != nil { + return nil, fmt.Errorf("error from fieldReader: %v", r.err()) + } + return e, nil +} + +// ThreeDAVCExtension describes a NAL unit header 3D advanced video coding +// extension, as defined in section J.7.3.1.1 of the specifications. +// For field semantics see section J.7.4.1.1. +type ThreeDAVCExtension struct { + // view_idx, specifies the order index for the NAL i.e. view_id = view_id[view_idx]. + ViewIdx uint8 + + // dpeth_flag, if true indicates NAL part of a depth view component, otherwise + // a texture view component. + DepthFlag bool + + // non_idr_flag, if true indicates that access unit is not IDR. + NonIdrFlag bool + + // temporal_id, temporal identifier for the unit. + TemporalID uint8 + + // anchor_pic_flag, if true access unit is an anchor access unit. + AnchorPicFlag bool + + // inter_view_flag, if false current view component not used for inter-view + // prediction elsewhere in access unit. + InterViewFlag bool +} + +// NewThreeDAVCExtension parses a NAL unit header 3D advanced video coding +// extension from br following the syntax structure specified in section +// J.7.3.1.1, and returns as a new ThreeDAVCExtension. +func NewThreeDAVCExtension(br *bits.BitReader) (*ThreeDAVCExtension, error) { + e := &ThreeDAVCExtension{} + r := newFieldReader(br) + + e.ViewIdx = uint8(r.readBits(8)) + e.DepthFlag = r.readBits(1) == 1 + e.NonIdrFlag = r.readBits(1) == 1 + e.TemporalID = uint8(r.readBits(3)) + e.AnchorPicFlag = r.readBits(1) == 1 + e.InterViewFlag = r.readBits(1) == 1 + + if r.err() != nil { + return nil, fmt.Errorf("error from fieldReader: %v", r.err()) + } + + return e, nil +} + +// SVCExtension describes a NAL unit header scalable video coding extension, as +// defined in section G.7.3.1.1 of the specifications. +// For field semantics see section G.7.4.1.1. +type SVCExtension struct { + // idr_flag, if true the current coded picture is an IDR picture when + // dependency_id == max(dependency_id) in the coded picture. + IdrFlag bool + + // priority_id, specifies priority identifier for unit. + PriorityID uint8 + + // no_inter_layer_pred_flag, if true inter-layer prediction can't be used for + // decoding slice. + NoInterLayerPredFlag bool + + // dependency_id, specifies a dependency identifier for the NAL. + DependencyID uint8 + + // quality_id, specifies a quality identifier for the NAL. + QualityID uint8 + + // temporal_id, specifiesa temporal identifier for the NAL. + TemporalID uint8 + + // use_ref_base_pic_flag, if true indicates reference base pictures and + // decoded pictures are used as references for inter prediction. + UseRefBasePicFlag bool + + // discardable_flag, if true, indicates current NAL is not used for decoding + // dependency representations that are part of the current coded picture or + // any subsequent coded picture in decoding order and have a greater + // dependency_id value than current NAL. + DiscardableFlag bool + + // output_flag, affects the decoded picture output and removal processes as + // specified in Annex C. + OutputFlag bool + + // reserved_three_2bits, equal to 3. Decoders ignore. + ReservedThree2Bits uint8 +} + +// NewSVCExtension parses a NAL unit header scalable video coding extension from +// br following the syntax structure specified in section G.7.3.1.1, and returns +// as a new SVCExtension. +func NewSVCExtension(br *bits.BitReader) (*SVCExtension, error) { + e := &SVCExtension{} + r := newFieldReader(br) + + e.IdrFlag = r.readBits(1) == 1 + e.PriorityID = uint8(r.readBits(6)) + e.NoInterLayerPredFlag = r.readBits(1) == 1 + e.DependencyID = uint8(r.readBits(3)) + e.QualityID = uint8(r.readBits(4)) + e.TemporalID = uint8(r.readBits(3)) + e.UseRefBasePicFlag = r.readBits(1) == 1 + e.DiscardableFlag = r.readBits(1) == 1 + e.OutputFlag = r.readBits(1) == 1 + e.ReservedThree2Bits = uint8(r.readBits(2)) + + if r.err() != nil { + return nil, fmt.Errorf("error from fieldReader: %v", r.err()) + } + return e, nil +} + +// NALUnit describes a network abstraction layer unit, as defined in section +// 7.3.1 of the specifications. +// Field semantics are defined in section 7.4.1. +type NALUnit struct { + // forbidden_zero_bit, always 0. + ForbiddenZeroBit uint8 + + // nal_ref_idc, if not 0 indicates content of NAL contains a sequence parameter + // set, a sequence parameter set extension, a subset sequence parameter set, + // a picture parameter set, a slice of a reference picture, a slice data + // partition of a reference picture, or a prefix NAL preceding a slice of + // a reference picture. + RefIdc uint8 + + // nal_unit_type, specifies the type of RBSP data contained in the NAL as + // defined in Table 7-1. + Type uint8 + + // svc_extension_flag, indicates whether a nal_unit_header_svc_extension() + // (G.7.3.1.1) or nal_unit_header_mvc_extension() (H.7.3.1.1) will follow next + // in the syntax structure. + SVCExtensionFlag bool + + // avc_3d_extension_flag, for nal_unit_type = 21, indicates that a + // nal_unit_header_mvc_extension() (H.7.3.1.1) or + // nal_unit_header_3davc_extension() (J.7.3.1.1) will follow next in syntax + // structure. + AVC3DExtensionFlag bool + + // nal_unit_header_svc_extension() as defined in section G.7.3.1.1. + SVCExtension *SVCExtension + + // nal_unit_header_3davc_extension() as defined in section J.7.3.1.1 + ThreeDAVCExtension *ThreeDAVCExtension + + // nal_unit_header_mvc_extension() as defined in section H.7.3.1.1). + MVCExtension *MVCExtension + + // emulation_prevention_three_byte, equal to 0x03 and is discarded by decoder. EmulationPreventionThreeByte byte - rbsp []byte + + // rbsp_byte, the raw byte sequence payload data for the NAL. + RBSP []byte } -func NalUnitHeaderSvcExtension(nalUnit *NalUnit, br *bits.BitReader) error { - return readFields(br, []field{ - {&nalUnit.IdrFlag, "IdrFlag", 1}, - {&nalUnit.PriorityId, "PriorityId", 6}, - {&nalUnit.NoInterLayerPredFlag, "NoInterLayerPredFlag", 1}, - {&nalUnit.DependencyId, "DependencyId", 3}, - {&nalUnit.QualityId, "QualityId", 4}, - {&nalUnit.TemporalId, "TemporalId", 3}, - {&nalUnit.UseRefBasePicFlag, "UseRefBasePicFlag", 1}, - {&nalUnit.DiscardableFlag, "DiscardableFlag", 1}, - {&nalUnit.OutputFlag, "OutputFlag", 1}, - {&nalUnit.ReservedThree2Bits, "ReservedThree2Bits", 2}, - }) -} +// NewNALUnit parses a network abstraction layer unit from br following the +// syntax structure specified in section 7.3.1, and returns as a new NALUnit. +func NewNALUnit(br *bits.BitReader) (*NALUnit, error) { + n := &NALUnit{} + r := newFieldReader(br) -func NalUnitHeader3davcExtension(nalUnit *NalUnit, br *bits.BitReader) error { - return readFields(br, []field{ - {&nalUnit.ViewIdx, "ViewIdx", 8}, - {&nalUnit.DepthFlag, "DepthFlag", 1}, - {&nalUnit.NonIdrFlag, "NonIdrFlag", 1}, - {&nalUnit.TemporalId, "TemporalId", 3}, - {&nalUnit.AnchorPicFlag, "AnchorPicFlag", 1}, - {&nalUnit.InterViewFlag, "InterViewFlag", 1}, - }) -} + n.ForbiddenZeroBit = uint8(r.readBits(1)) + n.RefIdc = uint8(r.readBits(2)) + n.Type = uint8(r.readBits(5)) -func NalUnitHeaderMvcExtension(nalUnit *NalUnit, br *bits.BitReader) error { - return readFields(br, []field{ - {&nalUnit.NonIdrFlag, "NonIdrFlag", 1}, - {&nalUnit.PriorityId, "PriorityId", 6}, - {&nalUnit.ViewId, "ViewId", 10}, - {&nalUnit.TemporalId, "TemporalId", 3}, - {&nalUnit.AnchorPicFlag, "AnchorPicFlag", 1}, - {&nalUnit.InterViewFlag, "InterViewFlag", 1}, - {&nalUnit.ReservedOneBit, "ReservedOneBit", 1}, - }) -} - -func (n *NalUnit) RBSP() []byte { - return n.rbsp -} - -func NewNalUnit(frame []byte, numBytesInNal int) (*NalUnit, error) { - logger.Printf("debug: reading %d byte NAL\n", numBytesInNal) - nalUnit := NalUnit{ - NumBytes: numBytesInNal, - HeaderBytes: 1, - } - // TODO: pass in actual io.Reader to NewBitReader - br := bits.NewBitReader(nil) - - err := readFields(br, []field{ - {&nalUnit.ForbiddenZeroBit, "ForbiddenZeroBit", 1}, - {&nalUnit.RefIdc, "NalRefIdc", 2}, - {&nalUnit.Type, "NalUnitType", 5}, - }) - if err != nil { - return nil, err - } - - if nalUnit.Type == 14 || nalUnit.Type == 20 || nalUnit.Type == 21 { - if nalUnit.Type != 21 { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read SvcExtensionFlag") - } - nalUnit.SvcExtensionFlag = int(b) + var err error + if n.Type == naluTypePrefixNALU || n.Type == naluTypeSliceLayerExtRBSP || n.Type == naluTypeSliceLayerExtRBSP2 { + if n.Type != naluTypeSliceLayerExtRBSP2 { + n.SVCExtensionFlag = r.readBits(1) == 1 } else { - b, err := br.ReadBits(1) - if err != nil { - return nil, errors.Wrap(err, "could not read Avc3dExtensionFlag") - } - nalUnit.Avc3dExtensionFlag = int(b) + n.AVC3DExtensionFlag = r.readBits(1) == 1 } - if nalUnit.SvcExtensionFlag == 1 { - NalUnitHeaderSvcExtension(&nalUnit, br) - nalUnit.HeaderBytes += 3 - } else if nalUnit.Avc3dExtensionFlag == 1 { - NalUnitHeader3davcExtension(&nalUnit, br) - nalUnit.HeaderBytes += 2 + if n.SVCExtensionFlag { + n.SVCExtension, err = NewSVCExtension(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse SVCExtension") + } + } else if n.AVC3DExtensionFlag { + n.ThreeDAVCExtension, err = NewThreeDAVCExtension(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse ThreeDAVCExtension") + } } else { - NalUnitHeaderMvcExtension(&nalUnit, br) - nalUnit.HeaderBytes += 3 - + n.MVCExtension, err = NewMVCExtension(br) + if err != nil { + return nil, errors.Wrap(err, "could not parse MVCExtension") + } } } - logger.Printf("debug: found %d byte header. Reading body\n", nalUnit.HeaderBytes) - for i := nalUnit.HeaderBytes; i < nalUnit.NumBytes; i++ { + for moreRBSPData(br) { next3Bytes, err := br.PeekBits(24) - if err != nil { - logger.Printf("error: while reading next 3 NAL bytes: %v\n", err) - break + + // If PeekBits cannot get 3 bytes, but there still might be 2 bytes left in + // the source, we will get an io.EOF; we wish to ignore this and continue. + // The call to moreRBSPData will determine when we have reached the end of + // the NAL unit. + if err != nil && errors.Cause(err) != io.EOF { + return nil, errors.Wrap(err, "could not Peek next 3 bytes") } - // Little odd, the err above and the i+2 check might be synonyms - if i+2 < nalUnit.NumBytes && next3Bytes == 0x000003 { + + if next3Bytes == 0x000003 { for j := 0; j < 2; j++ { - rbspByte, err := br.ReadBits(8) - if err != nil { - return nil, errors.Wrap(err, "could not read rbspByte") - } - nalUnit.rbsp = append(nalUnit.rbsp, byte(rbspByte)) + rbspByte := byte(r.readBits(8)) + n.RBSP = append(n.RBSP, byte(rbspByte)) } - i += 2 // Read Emulation prevention three byte. - eptByte, err := br.ReadBits(8) - if err != nil { - return nil, errors.Wrap(err, "could not read eptByte") - } - nalUnit.EmulationPreventionThreeByte = byte(eptByte) + n.EmulationPreventionThreeByte = byte(r.readBits(8)) } else { - if b, err := br.ReadBits(8); err == nil { - nalUnit.rbsp = append(nalUnit.rbsp, byte(b)) - } else { - logger.Printf("error: while reading byte %d of %d nal bytes: %v\n", i, nalUnit.NumBytes, err) - break - } + n.RBSP = append(n.RBSP, byte(r.readBits(8))) } } - // nalUnit.rbsp = frame[nalUnit.HeaderBytes:] - logger.Printf("info: decoded %s NAL with %d RBSP bytes\n", NALUnitType[nalUnit.Type], len(nalUnit.rbsp)) - return &nalUnit, nil + if r.err() != nil { + return nil, fmt.Errorf("fieldReader error: %v", r.err()) + } + + return n, nil } diff --git a/codec/h264/h264dec/read.go b/codec/h264/h264dec/read.go index 92a12ed9..bf45bd1b 100644 --- a/codec/h264/h264dec/read.go +++ b/codec/h264/h264dec/read.go @@ -63,7 +63,7 @@ func (h *H264Reader) Start() { switch nalUnit.Type { case naluTypeSPS: // TODO: handle this error - sps, _ := NewSPS(nalUnit.rbsp, false) + sps, _ := NewSPS(nalUnit.RBSP, false) h.VideoStreams = append( h.VideoStreams, &VideoStream{SPS: sps}, @@ -71,20 +71,20 @@ 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) + videoStream.PPS, _ = NewPPS(videoStream.SPS, nalUnit.RBSP, false) case naluTypeSliceIDRPicture: fallthrough case naluTypeSliceNonIDRPicture: videoStream := h.VideoStreams[len(h.VideoStreams)-1] logger.Printf("info: frame number %d\n", len(videoStream.Slices)) // TODO: handle this error - sliceContext, _ := NewSliceContext(videoStream, nalUnit, nalUnit.RBSP(), true) + sliceContext, _ := NewSliceContext(videoStream, nalUnit, nalUnit.RBSP, true) videoStream.Slices = append(videoStream.Slices, sliceContext) } } } -func (r *H264Reader) readNalUnit() (*NalUnit, *bits.BitReader, error) { +func (r *H264Reader) readNalUnit() (*NALUnit, *bits.BitReader, error) { // Read to start of NAL logger.Printf("debug: Seeking NAL %d start\n", len(r.NalUnits)) @@ -131,7 +131,7 @@ func (r *H264Reader) readNalUnit() (*NalUnit, *bits.BitReader, error) { r.NalUnits = append(r.NalUnits, nalUnitReader) // TODO: this should really take an io.Reader rather than []byte. Need to fix nil // once this is fixed. - nalUnit, err := NewNalUnit(nil, 0) + nalUnit, err := NewNALUnit(nil) if err != nil { return nil, nil, errors.Wrap(err, "cannot create new nal unit") } diff --git a/codec/h264/h264dec/slice.go b/codec/h264/h264dec/slice.go index b25b4502..93e2a6e4 100644 --- a/codec/h264/h264dec/slice.go +++ b/codec/h264/h264dec/slice.go @@ -23,7 +23,7 @@ type VideoStream struct { Slices []*SliceContext } type SliceContext struct { - *NalUnit + *NALUnit *SPS *PPS *Slice @@ -240,12 +240,12 @@ func CodedBlockPatternChroma(data *SliceData) int { // dependencyId see Annex G.8.8.1 // Also G7.3.1.1 nal_unit_header_svc_extension -func DQId(nalUnit *NalUnit) int { - return (nalUnit.DependencyId << 4) + nalUnit.QualityId +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 { +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" { @@ -381,7 +381,7 @@ func MbPred(sliceContext *SliceContext, br *bits.BitReader, rbsp []byte) error { } } else if mbPartPredMode != direct { - for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NalUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data); mbPartIdx++ { + for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data); mbPartIdx++ { sliceContext.Update(sliceContext.Slice.Header, sliceContext.Slice.Data) m, err := MbPartPredMode(sliceContext.Slice.Data, sliceType, sliceContext.Slice.Data.MbType, mbPartIdx) if err != nil { @@ -417,7 +417,7 @@ func MbPred(sliceContext *SliceContext, br *bits.BitReader, rbsp []byte) error { } } } - for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NalUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data); mbPartIdx++ { + for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data); mbPartIdx++ { m, err := MbPartPredMode(sliceContext.Slice.Data, sliceType, sliceContext.Slice.Data.MbType, mbPartIdx) if err != nil { return errors.Wrap(err, fmt.Sprintf("could not get mbPartPredMode for loop 2 mbPartIdx: %d", mbPartIdx)) @@ -456,7 +456,7 @@ func MbPred(sliceContext *SliceContext, br *bits.BitReader, rbsp []byte) error { } } } - for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NalUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data); mbPartIdx++ { + for mbPartIdx := 0; mbPartIdx < NumMbPart(sliceContext.NALUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data); mbPartIdx++ { sliceContext.Update(sliceContext.Slice.Header, sliceContext.Slice.Data) m, err := MbPartPredMode(sliceContext.Slice.Data, sliceType, sliceContext.Slice.Data.MbType, mbPartIdx) if err != nil { @@ -815,7 +815,7 @@ func NewSliceData(sliceContext *SliceContext, br *bits.BitReader) (*SliceData, e if err != nil { return nil, errors.Wrap(err, "could not get mbPartPredMode") } - if sliceContext.Slice.Data.MbTypeName == "I_NxN" && m != intra16x16 && NumMbPart(sliceContext.NalUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data) == 4 { + if sliceContext.Slice.Data.MbTypeName == "I_NxN" && m != intra16x16 && NumMbPart(sliceContext.NALUnit, sliceContext.SPS, sliceContext.Slice.Header, sliceContext.Slice.Data) == 4 { logger.Printf("\tTODO: subMbPred\n") /* subMbType := SubMbPred(sliceContext.Slice.Data.MbType) @@ -945,11 +945,11 @@ func NewSliceData(sliceContext *SliceContext, br *bits.BitReader) (*SliceData, e func (c *SliceContext) Update(header *SliceHeader, data *SliceData) { c.Slice = &Slice{Header: header, Data: data} } -func NewSliceContext(videoStream *VideoStream, nalUnit *NalUnit, rbsp []byte, showPacket bool) (*SliceContext, error) { +func NewSliceContext(videoStream *VideoStream, nalUnit *NALUnit, rbsp []byte, showPacket bool) (*SliceContext, error) { var err error sps := videoStream.SPS pps := videoStream.PPS - logger.Printf("debug: %s RBSP %d bytes %d bits == \n", NALUnitType[nalUnit.Type], len(rbsp), len(rbsp)*8) + 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 { @@ -974,7 +974,7 @@ func NewSliceContext(videoStream *VideoStream, nalUnit *NalUnit, rbsp []byte, sh } sliceType := sliceTypeMap[header.SliceType] - logger.Printf("debug: %s (%s) slice of %d bytes\n", NALUnitType[nalUnit.Type], sliceType, len(rbsp)) + logger.Printf("debug: %s (%s) slice of %d bytes\n", NALUnitType[int(nalUnit.Type)], sliceType, len(rbsp)) header.PPSID, err = readUe(br) if err != nil { return nil, errors.Wrap(err, "could not parse PPSID") @@ -1350,7 +1350,7 @@ func NewSliceContext(videoStream *VideoStream, nalUnit *NalUnit, rbsp []byte, sh } sliceContext := &SliceContext{ - NalUnit: nalUnit, + NALUnit: nalUnit, SPS: sps, PPS: pps, Slice: &Slice{