From db8f2790f8a11d651c88d51469522599bb7144d7 Mon Sep 17 00:00:00 2001 From: notch Date: Sat, 9 Jan 2021 07:09:48 +0800 Subject: [PATCH] update h264 --- av/codec/h264/bitsutil.go | 126 ----------- av/codec/h264/{h264.go => const.go} | 53 +++-- av/codec/h264/shortcut.go | 54 +++++ av/codec/h264/sps.go | 338 +++++++++------------------- av/codec/metadata.go | 46 ++++ go.mod | 1 - go.sum | 2 - 7 files changed, 230 insertions(+), 390 deletions(-) delete mode 100644 av/codec/h264/bitsutil.go rename av/codec/h264/{h264.go => const.go} (80%) create mode 100644 av/codec/h264/shortcut.go diff --git a/av/codec/h264/bitsutil.go b/av/codec/h264/bitsutil.go deleted file mode 100644 index bcf2150..0000000 --- a/av/codec/h264/bitsutil.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2019,CAOHONGJU All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package h264 - -import ( - bits "github.com/cnotch/bitutil" -) - -func u8(r *bits.Reader, w int, target *uint8) (err error) { - *target, err = r.ReadUint8(w) - return -} - -func u16(r *bits.Reader, w int, target *uint16) (err error) { - *target, err = r.ReadUint16(w) - return -} - -func u32(r *bits.Reader, w int, target *uint32) (err error) { - *target, err = r.ReadUint32(w) - return -} - -func flag(r *bits.Reader, target *uint8) (err error) { - *target, err = r.ReadBit() - return -} - -func ue(r *bits.Reader) (res uint32, err error) { - i := 0 - for { - var bit uint8 - if bit, err = r.ReadBit(); err != nil { - return - } - if !(bit == 0 && i < 32) { - break - } - i++ - } - - if res, err = r.ReadUint32(i); err != nil { - return - } - res += (1 << uint(i)) - 1 - return -} -func ue8(r *bits.Reader, target *uint8) error { - temp, err := ue(r) - *target = uint8(temp) - return err -} - -func ue16(r *bits.Reader, target *uint16) error { - temp, err := ue(r) - *target = uint16(temp) - return err -} - -func ue32(r *bits.Reader, target *uint32) (err error) { - *target, err = ue(r) - return -} - -func se(r *bits.Reader) (res int32, err error) { - var ui32 uint32 - if ui32, err = ue(r); err != nil { - return - } - res = int32(ui32) - - if res&0x01 != 0 { - res = (res + 1) / 2 - } else { - res = -res / 2 - } - return -} -func se8(r *bits.Reader, target *int8) error { - temp, err := se(r) - *target = int8(temp) - return err -} -func se16(r *bits.Reader, target *int16) error { - temp, err := se(r) - *target = int16(temp) - return err -} -func se32(r *bits.Reader, target *int32) (err error) { - *target, err = se(r) - return -} - -// copy from live555 -// A general routine for making a copy of a (H.264 or H.265) NAL unit, removing 'emulation' bytes from the copy -func removeH264or5EmulationBytes(from []byte) []byte { - to := make([]byte, len(from)) - toMaxSize := len(to) - fromSize := len(from) - toSize := 0 - i := 0 - for i < fromSize && toSize+1 < toMaxSize { - if i+2 < fromSize && from[i] == 0 && from[i+1] == 0 && from[i+2] == 3 { - to[toSize] = 0 - to[toSize+1] = 0 - toSize += 2 - i += 3 - } else { - to[toSize] = from[i] - toSize++ - i++ - } - } - - // 如果剩余最后一个字节,拷贝它 - if i < fromSize && toSize < toMaxSize { - to[toSize] = from[i] - toSize++ - i++ - } - - return to[:toSize] - // return bytes.Replace(from, []byte{0, 0, 3}, []byte{0, 0}, -1) -} diff --git a/av/codec/h264/h264.go b/av/codec/h264/const.go similarity index 80% rename from av/codec/h264/h264.go rename to av/codec/h264/const.go index 521554f..c8ca948 100755 --- a/av/codec/h264/h264.go +++ b/av/codec/h264/const.go @@ -54,6 +54,34 @@ const ( NalTypeBitmask = 0x1F ) +// Profile +const ( + ProfileConstrained = (1 << 9) // 8+1; constraint_set1_flag + ProfileIntra = (1 << 11) // 8+3; constraint_set3_flag + + ProfileBaseline = 66 + ProfileConstrainedBaseline = (66 | ProfileConstrained) + ProfileMain = 77 + ProfileExtended = 88 + ProfileHigh = 100 + ProfileHigh10 = 110 + ProfileHigh10Intra = (110 | ProfileIntra) + ProfileMultiViewHigh = 118 + ProfileHigh422 = 122 + ProfileHigh422Intra = (122 | ProfileIntra) + ProfileStereoHigh = 128 + ProfileHigh444 = 144 + ProfileHigh444Predictive = 244 + ProfileHigh444Intra = (244 | ProfileIntra) + ProfileCAVLC444 = 44 +) + +// 参数集索引 +const ( + ParameterSetSps = iota + ParameterSetPps +) + // 其他常量 const ( // 7.4.2.1.1: seq_parameter_set_id is in [0, 31]. @@ -97,28 +125,3 @@ const ( MaxWidth = MaxMbWidth * 16 MaxHeight = MaxMbHeight * 16 ) - -// NulType . -func NulType(b byte) byte { - return b & NalTypeBitmask -} - -// IsSps . -func IsSps(b byte) bool { - return b&NalTypeBitmask == NalSps -} - -// IsPps . -func IsPps(b byte) bool { - return b&NalTypeBitmask == NalPps -} - -// IsIdrSlice . -func IsIdrSlice(b byte) bool { - return b&NalTypeBitmask == NalIdrSlice -} - -// IsFillerData . -func IsFillerData(b byte) bool { - return b&NalTypeBitmask == NalFillerData -} diff --git a/av/codec/h264/shortcut.go b/av/codec/h264/shortcut.go new file mode 100644 index 0000000..8950832 --- /dev/null +++ b/av/codec/h264/shortcut.go @@ -0,0 +1,54 @@ +// Copyright (c) 2019,CAOHONGJU All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package h264 + +import "github.com/cnotch/ipchub/av/codec" + +// MetadataIsReady . +func MetadataIsReady(vm *codec.VideoMeta) bool { + sps := vm.Sps //ParameterSet(ParameterSetSps) + pps := vm.Pps //ParameterSet(ParameterSetPps) + if len(sps) == 0 || len(pps) == 0 { + return false + } + + if vm.Width == 0 { + // decode + var rawsps RawSPS + if err := rawsps.Decode(sps); err != nil { + return false + } + vm.Width = rawsps.Width() + vm.Height = rawsps.Height() + vm.FixedFrameRate = rawsps.IsFixedFrameRate() + vm.FrameRate = rawsps.FrameRate() + } + return true +} + +// NulType . +func NulType(nt byte) byte { + return nt & NalTypeBitmask +} + +// IsSps . +func IsSps(nt byte) bool { + return nt&NalTypeBitmask == NalSps +} + +// IsPps . +func IsPps(nt byte) bool { + return nt&NalTypeBitmask == NalPps +} + +// IsIdrSlice . +func IsIdrSlice(nt byte) bool { + return nt&NalTypeBitmask == NalIdrSlice +} + +// IsFillerData . +func IsFillerData(nt byte) bool { + return nt&NalTypeBitmask == NalFillerData +} diff --git a/av/codec/h264/sps.go b/av/codec/h264/sps.go index b6ee377..98bbe6c 100644 --- a/av/codec/h264/sps.go +++ b/av/codec/h264/sps.go @@ -1,15 +1,19 @@ // Copyright (c) 2019,CAOHONGJU All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. - +// +// Translate from FFmpeg cbs_h264.h cbs_h264_syntax_template.c +// package h264 import ( "encoding/base64" "errors" "fmt" + "runtime/debug" - bits "github.com/cnotch/bitutil" + "github.com/cnotch/ipchub/utils" + "github.com/cnotch/ipchub/utils/bits" ) // RawNALUnitHeader 原始 h264 Nal单元头 @@ -220,13 +224,13 @@ type RawSPS struct { Vui RawVUI } -// Width Video Width +// Width 视频宽度(像素) func (sps *RawSPS) Width() int { w := (sps.PicWidthInMbsMinus1+1)*16 - sps.FrameCropLeftOffset*2 - sps.FrameCropRightOffset*2 return int(w) } -// Height Video Height +// Height 视频高度(像素) func (sps *RawSPS) Height() int { h := (2-uint16(sps.FrameMbsOnlyFlag))*(sps.PicHeightInMapUnitsMinus1+1)*16 - sps.FrameCropTopOffset*2 - sps.FrameCropBottomOffset*2 return int(h) @@ -256,7 +260,13 @@ func (sps *RawSPS) DecodeString(b64 string) error { // Decode 从字节序列中解码 sps NAL func (sps *RawSPS) Decode(data []byte) (err error) { - spsWEB := removeH264or5EmulationBytes(data) + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("RawSPS decode panic;r = %v \n %s", r, debug.Stack()) + } + }() + + spsWEB := utils.RemoveH264or5EmulationBytes(data) if len(spsWEB) < 4 { return errors.New("The data is not enough") } @@ -271,56 +281,41 @@ func (sps *RawSPS) Decode(data []byte) (err error) { } // 前三个字节 - sps.ProfileIdc, _ = r.ReadUint8(8) + sps.ProfileIdc = r.ReadUint8(8) - sps.ConstraintSet0Flag, _ = r.ReadBit() - sps.ConstraintSet1Flag, _ = r.ReadBit() - sps.ConstraintSet2Flag, _ = r.ReadBit() - sps.ConstraintSet3Flag, _ = r.ReadBit() - sps.ConstraintSet4Flag, _ = r.ReadBit() - sps.ConstraintSet5Flag, _ = r.ReadBit() - sps.ReservedZero2Bits, _ = r.ReadUint8(2) + sps.ConstraintSet0Flag = r.ReadBit() + sps.ConstraintSet1Flag = r.ReadBit() + sps.ConstraintSet2Flag = r.ReadBit() + sps.ConstraintSet3Flag = r.ReadBit() + sps.ConstraintSet4Flag = r.ReadBit() + sps.ConstraintSet5Flag = r.ReadBit() + sps.ReservedZero2Bits = r.ReadUint8(2) - sps.LevelIdc, _ = r.ReadUint8(8) + sps.LevelIdc = r.ReadUint8(8) // seq_parameter_set_id - if err = ue8(r, &sps.SeqParameterSetID); err != nil { - return - } + sps.SeqParameterSetID = r.ReadUe8() if sps.ProfileIdc == 100 || sps.ProfileIdc == 110 || sps.ProfileIdc == 122 || sps.ProfileIdc == 244 || sps.ProfileIdc == 44 || sps.ProfileIdc == 83 || sps.ProfileIdc == 86 || sps.ProfileIdc == 118 { - - if err = ue8(r, &sps.ChromaFormatIdc); err != nil { - return - } + sps.ChromaFormatIdc = r.ReadUe8() if sps.ChromaFormatIdc == 3 { // separate_colour_plane_flag - if sps.SeparateColourPlaneFlag, err = r.ReadBit(); err != nil { - return - } + sps.SeparateColourPlaneFlag = r.ReadBit() } else { sps.SeparateColourPlaneFlag = 0 } - if err = ue8(r, &sps.BitDepthLumaMinus8); err != nil { - return - } - if err = ue8(r, &sps.BitDepthChromaMinus8); err != nil { - return - } + sps.BitDepthLumaMinus8 = r.ReadUe8() + sps.BitDepthChromaMinus8 = r.ReadUe8() // qpprime_y_zero_transform_bypass_flag - if sps.QpprimeYZeroTransformBypassFlag, err = r.ReadBit(); err != nil { - return - } + sps.QpprimeYZeroTransformBypassFlag = r.ReadBit() - if sps.SeqScalingMatrixPresentFlag, err = r.ReadBit(); err != nil { - return - } + sps.SeqScalingMatrixPresentFlag = r.ReadBit() if sps.SeqScalingMatrixPresentFlag != 0 { maxI := 8 @@ -329,9 +324,7 @@ func (sps *RawSPS) Decode(data []byte) (err error) { } for i := 0; i < maxI; i++ { - if sps.SeqScalingListPresentFlag[i], err = r.ReadBit(); err != nil { - return - } + sps.SeqScalingListPresentFlag[i] = r.ReadBit() if sps.SeqScalingListPresentFlag[i] != 0 { sps.scanList(r, i) } @@ -350,109 +343,70 @@ func (sps *RawSPS) Decode(data []byte) (err error) { } // log2_max_frame_num_minus4 - if err = ue8(r, &sps.Log2MaxFrameNumMinus4); err != nil { - return - } + sps.Log2MaxFrameNumMinus4 = r.ReadUe8() // pic_order_cnt_type - if err = ue8(r, &sps.PicOrderCntType); err != nil { - return - } + sps.PicOrderCntType = r.ReadUe8() if sps.PicOrderCntType == 0 { // log2_max_pic_order_cnt_lsb_minus4 - if err = ue8(r, &sps.Log2MaxPicOrderCntLsbMinus4); err != nil { - return - } + sps.Log2MaxPicOrderCntLsbMinus4 = r.ReadUe8() } else if sps.PicOrderCntType == 1 { // delta_pic_order_always_zero_flag - if sps.DeltaPicOrderAlwaysZeroFlag, err = r.ReadBit(); err != nil { - return - } + sps.DeltaPicOrderAlwaysZeroFlag = r.ReadBit() // offset_for_non_ref_pic - if err = se32(r, &sps.OffsetForNonRefPic); err != nil { - return - } + sps.OffsetForNonRefPic = r.ReadSe() // offset_for_top_to_bottom_field - if err = se32(r, &sps.OffsetForTopToBottomField); err != nil { - return - } + sps.OffsetForTopToBottomField = r.ReadSe() // num_ref_frames_in_pic_order_cnt_cycle - if err = ue8(r, &sps.NumRefFramesInPicOrderCntCycle); err != nil { - return - } + sps.NumRefFramesInPicOrderCntCycle = r.ReadUe8() for i := uint8(0); i < sps.NumRefFramesInPicOrderCntCycle; i++ { // offset_for_ref_frame - if err = se32(r, &sps.OffsetForRefFrame[i]); err != nil { - return - } + sps.OffsetForRefFrame[i] = r.ReadSe() } } // max_num_ref_frames - if err = ue8(r, &sps.MaxNumRefFrames); err != nil { - return - } + sps.MaxNumRefFrames = r.ReadUe8() // gaps_in_frame_num_allowed_flag - if sps.GapsInFrameNumAllowedFlag, err = r.ReadBit(); err != nil { - return - } + sps.GapsInFrameNumAllowedFlag = r.ReadBit() // pic_width_in_mbs_minus1 - if err = ue16(r, &sps.PicWidthInMbsMinus1); err != nil { - return - } + sps.PicWidthInMbsMinus1 = r.ReadUe16() // pic_height_in_map_units_minus1 - if err = ue16(r, &sps.PicHeightInMapUnitsMinus1); err != nil { - return - } + sps.PicHeightInMapUnitsMinus1 = r.ReadUe16() // frame_mbs_only_flag - if sps.FrameMbsOnlyFlag, err = r.ReadBit(); err != nil { - return - } + sps.FrameMbsOnlyFlag = r.ReadBit() + if sps.FrameMbsOnlyFlag == 0 { // mb_adaptive_frame_field_flag - if sps.MbAdaptiveFrameFieldFlag, err = r.ReadBit(); err != nil { - return - } + sps.MbAdaptiveFrameFieldFlag = r.ReadBit() } // direct_8x8_inference_flag - if sps.Direct8x8InferenceFlag, err = r.ReadBit(); err != nil { - return - } + sps.Direct8x8InferenceFlag = r.ReadBit() // frame_cropping_flag - if sps.FrameCroppingFlag, err = r.ReadBit(); err != nil { - return - } + sps.FrameCroppingFlag = r.ReadBit() + if sps.FrameCroppingFlag == 1 { // frame_crop_left_offset - if err = ue16(r, &sps.FrameCropLeftOffset); err != nil { - return - } + sps.FrameCropLeftOffset = r.ReadUe16() // frame_crop_right_offset - if err = ue16(r, &sps.FrameCropRightOffset); err != nil { - return - } + sps.FrameCropRightOffset = r.ReadUe16() // frame_crop_top_offset - if err = ue16(r, &sps.FrameCropTopOffset); err != nil { - return - } // frame_crop_bottom_offset - if err = ue16(r, &sps.FrameCropBottomOffset); err != nil { - return - } + sps.FrameCropTopOffset = r.ReadUe16() + // frame_crop_bottom_offset + sps.FrameCropBottomOffset = r.ReadUe16() } // vui_parameters_present_flag - if sps.VuiParametersPresentFlag, err = r.ReadBit(); err != nil { - return - } + sps.VuiParametersPresentFlag = r.ReadBit() // vui parameters if sps.VuiParametersPresentFlag == 1 { @@ -479,9 +433,7 @@ func (sps *RawSPS) scanList(r *bits.Reader, i int) (err error) { scale := 8 for i = 0; i < sizeOfScan; i++ { - if err = se8(r, ¤t[i]); err != nil { - return - } + current[i] = r.ReadSe8() scale = (scale + int(current[i]) + 256) % 256 if scale == 0 { break @@ -492,9 +444,9 @@ func (sps *RawSPS) scanList(r *bits.Reader, i int) (err error) { } func (h *RawNALUnitHeader) decode(r *bits.Reader) (err error) { - h.ForbiddenZeroBit, _ = r.ReadBit() - h.NalRefIdc, _ = r.ReadUint8(2) - h.NalUnitType, _ = r.ReadUint8(5) + h.ForbiddenZeroBit = r.ReadBit() + h.NalRefIdc = r.ReadUint8(2) + h.NalUnitType = r.ReadUint8(5) if h.NalUnitType == NalPrefix || h.NalUnitType == NalExtenSlice || @@ -505,58 +457,31 @@ func (h *RawNALUnitHeader) decode(r *bits.Reader) (err error) { } func (vui *RawVUI) decode(r *bits.Reader, sps *RawSPS) (err error) { - if err = flag(r, &vui.AspectRatioInfoPresentFlag); err != nil { - return - } + vui.AspectRatioInfoPresentFlag = r.ReadBit() if vui.AspectRatioInfoPresentFlag == 1 { - if err = u8(r, 8, &vui.AspectRatioIdc); err != nil { - return - } + vui.AspectRatioIdc = r.ReadUint8(8) if vui.AspectRatioIdc == 255 { - if err = u16(r, 16, &vui.SarWidth); err != nil { - return - } - if err = u16(r, 16, &vui.SarHeight); err != nil { - return - } + vui.SarWidth = r.ReadUint16(16) + vui.SarHeight = r.ReadUint16(16) } } else { vui.AspectRatioIdc = 0 } - if err = flag(r, &vui.OverscanInfoPresentFlag); err != nil { - return - } + vui.OverscanInfoPresentFlag = r.ReadBit() if vui.OverscanInfoPresentFlag == 1 { - if err = flag(r, &vui.OverscanAppropriateFlag); err != nil { - return - } + vui.OverscanAppropriateFlag = r.ReadBit() } - if err = flag(r, &vui.VideoSignalTypePresentFlag); err != nil { - return - } + vui.VideoSignalTypePresentFlag = r.ReadBit() if vui.VideoSignalTypePresentFlag == 1 { - if err = u8(r, 3, &vui.VideoFormat); err != nil { - return - } - if err = flag(r, &vui.VideoFullRangeFlag); err != nil { - return - } - - if err = flag(r, &vui.ColourDescriptionPresentFlag); err != nil { - return - } + vui.VideoFormat = r.ReadUint8(3) + vui.VideoFullRangeFlag = r.ReadBit() + vui.ColourDescriptionPresentFlag = r.ReadBit() if vui.ColourDescriptionPresentFlag == 1 { - if err = u8(r, 8, &vui.ColourPrimaries); err != nil { - return - } - if err = u8(r, 8, &vui.TransferCharacteristics); err != nil { - return - } - if err = u8(r, 8, &vui.MatrixCoefficients); err != nil { - return - } + vui.ColourPrimaries = r.ReadUint8(8) + vui.TransferCharacteristics = r.ReadUint8(8) + vui.MatrixCoefficients = r.ReadUint8(8) } } else { vui.VideoFormat = 5 @@ -566,50 +491,32 @@ func (vui *RawVUI) decode(r *bits.Reader, sps *RawSPS) (err error) { vui.MatrixCoefficients = 2 } - if err = flag(r, &vui.ChromaLocInfoPresentFlag); err != nil { - return - } + vui.ChromaLocInfoPresentFlag = r.ReadBit() if vui.ChromaLocInfoPresentFlag == 1 { - if err = ue8(r, &vui.ChromaSampleLocTypeTopField); err != nil { - return - } - if err = ue8(r, &vui.ChromaSampleLocTypeBottomField); err != nil { - return - } + vui.ChromaSampleLocTypeTopField = r.ReadUe8() + vui.ChromaSampleLocTypeBottomField = r.ReadUe8() } else { vui.ChromaSampleLocTypeTopField = 0 vui.ChromaSampleLocTypeBottomField = 0 } - if err = flag(r, &vui.TimingInfoPresentFlag); err != nil { - return - } + vui.TimingInfoPresentFlag = r.ReadBit() if vui.TimingInfoPresentFlag == 1 { - if err = u32(r, 32, &vui.NumUnitsInTick); err != nil { - return - } - if err = u32(r, 32, &vui.TimeScale); err != nil { - return - } - if err = flag(r, &vui.FixedFrameRateFlag); err != nil { - return - } + vui.NumUnitsInTick = r.ReadUint32(32) + vui.TimeScale = r.ReadUint32(32) + vui.FixedFrameRateFlag = r.ReadBit() } else { vui.FixedFrameRateFlag = 0 } - if err = flag(r, &vui.NalHrdParametersPresentFlag); err != nil { - return - } + vui.NalHrdParametersPresentFlag = r.ReadBit() if vui.NalHrdParametersPresentFlag == 1 { if err = vui.NalHrdParameters.decode(r); err != nil { return } } - if err = flag(r, &vui.VclHrdParametersPresentFlag); err != nil { - return - } + vui.VclHrdParametersPresentFlag = r.ReadBit() if vui.VclHrdParametersPresentFlag == 1 { if err = vui.VclHrdParameters.decode(r); err != nil { return @@ -618,44 +525,24 @@ func (vui *RawVUI) decode(r *bits.Reader, sps *RawSPS) (err error) { if vui.NalHrdParametersPresentFlag == 1 || vui.VclHrdParametersPresentFlag == 1 { - if err = flag(r, &vui.LowDelayHrdFlag); err != nil { - return - } + vui.LowDelayHrdFlag = r.ReadBit() } else { vui.LowDelayHrdFlag = 1 - vui.FixedFrameRateFlag } - if err = flag(r, &vui.PicStructPresentFlag); err != nil { - return - } + vui.PicStructPresentFlag = r.ReadBit() - if err = flag(r, &vui.BitstreamRestrictionFlag); err != nil { - return - } + vui.BitstreamRestrictionFlag = r.ReadBit() if vui.BitstreamRestrictionFlag == 1 { - if err = flag(r, &vui.MotionVectorsOverPicBoundariesFlag); err != nil { - return - } - if err = ue8(r, &vui.MaxBytesPerPicDenom); err != nil { - return - } - if err = ue8(r, &vui.MaxBitsPerMbDenom); err != nil { - return - } + vui.MotionVectorsOverPicBoundariesFlag = r.ReadBit() + vui.MaxBytesPerPicDenom = r.ReadUe8() + vui.MaxBitsPerMbDenom = r.ReadUe8() // The current version of the standard constrains this to be in // [0,15], but older versions allow 16. - if err = ue8(r, &vui.Log2MaxMvLengthHorizontal); err != nil { - return - } - if err = ue8(r, &vui.Log2MaxMvLengthVertical); err != nil { - return - } - if err = ue8(r, &vui.MaxNumReorderFrames); err != nil { - return - } - if err = ue8(r, &vui.MaxDecFrameBuffering); err != nil { - return - } + vui.Log2MaxMvLengthHorizontal = r.ReadUe8() + vui.Log2MaxMvLengthVertical = r.ReadUe8() + vui.MaxNumReorderFrames = r.ReadUe8() + vui.MaxDecFrameBuffering = r.ReadUe8() } else { vui.MotionVectorsOverPicBoundariesFlag = 1 vui.MaxBytesPerPicDenom = 2 @@ -716,40 +603,19 @@ func (vui *RawVUI) parametersDefault(sps *RawSPS) (err error) { } func (hrd *RawHRD) decode(r *bits.Reader) (err error) { - if err = ue8(r, &hrd.CpbCntMinus1); err != nil { - return - } - if err = u8(r, 4, &hrd.BitRateScale); err != nil { - return - } - if err = u8(r, 4, &hrd.CpbSizeScale); err != nil { - return - } + hrd.CpbCntMinus1 = r.ReadUe8() + hrd.BitRateScale = r.ReadUint8(4) + hrd.CpbSizeScale = r.ReadUint8(4) for i := 0; i <= int(hrd.CpbCntMinus1); i++ { - if err = ue32(r, &hrd.BitRateValueMinus1[i]); err != nil { - return - } - if err = ue32(r, &hrd.CpbSizeValueMinus1[i]); err != nil { - return - } - if err = flag(r, &hrd.CbrFlag[i]); err != nil { - return - } - } - - if err = u8(r, 5, &hrd.InitialCpbRemovalDelayLengthMinus1); err != nil { - return - } - if err = u8(r, 5, &hrd.CpbRemovalDelayLengthMinus1); err != nil { - return - } - if err = u8(r, 5, &hrd.DpbOutputDelayLengthMinus1); err != nil { - return - } - if err = u8(r, 5, &hrd.TimeOffsetLength); err != nil { - return + hrd.BitRateValueMinus1[i] = r.ReadUe() + hrd.CpbSizeValueMinus1[i] = r.ReadUe() + hrd.CbrFlag[i] = r.ReadBit() } + hrd.InitialCpbRemovalDelayLengthMinus1 = r.ReadUint8(5) + hrd.CpbRemovalDelayLengthMinus1 = r.ReadUint8(5) + hrd.DpbOutputDelayLengthMinus1 = r.ReadUint8(5) + hrd.TimeOffsetLength = r.ReadUint8(5) return } diff --git a/av/codec/metadata.go b/av/codec/metadata.go index d9e3f6b..8c5ae43 100644 --- a/av/codec/metadata.go +++ b/av/codec/metadata.go @@ -16,6 +16,12 @@ type VideoMeta struct { Sps []byte `json:"-"` Pps []byte `json:"-"` Vps []byte `json:"-"` + + // // 媒体的参数集,如 sdp中的 sprop_xxx + // parameterSets `json:"-"` + // // 不同封装和传输方式的特别参数 + // // 比如 RTP 封装: streamid, packetization-mode, profile-level-id 等 + // specificParams `json:"-"` } // AudioMeta 音频元数据 @@ -26,4 +32,44 @@ type AudioMeta struct { Channels int `json:"channels,omitempty"` DataRate float64 `json:"datarate,omitempty"` Sps []byte `json:"-"` // sps + + // // 媒体的参数集,如 sdp中的 sprop_xxx + // parameterSets `json:"-"` + // // 不同封装和传输方式的特别参数 + // // 比如 RTP 封装: streamid, mode, profile-level-id,sizelength, indexlength,indexdeltalength 等 + // specificParams `json:"-"` +} + +type parameterSets [][]byte + +func (pss *parameterSets) ParameterSet(idx int) []byte { + if len(*pss) <= idx { + return nil + } + return (*pss)[idx] +} +func (pss *parameterSets) SetParameterSet(idx int, paramSet []byte) { + if len(*pss) <= idx { + temp := make(parameterSets, idx+1) + copy(temp, *pss) + *pss = temp + } + (*pss)[idx] = paramSet +} + +type specificParams map[string]string + +func (params *specificParams) SpecificParam(name string) (value string, ok bool) { + if params == nil { + return + } + value, ok = (*params)[name] + return +} + +func (params *specificParams) SetSpecificParam(name, value string) { + if params == nil { + *params = make(specificParams) + } + (*params)[name] = value } diff --git a/go.mod b/go.mod index c20a4f0..cd506a8 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.14 require ( github.com/BurntSushi/toml v0.3.1 // indirect github.com/cnotch/apirouter v0.0.0-20200731232942-89e243a791f3 - github.com/cnotch/bitutil v0.0.0-20200512012328-08db448fb960 github.com/cnotch/loader v0.0.0-20200405015128-d9d964d09439 github.com/cnotch/queue v0.0.0-20201224060551-4191569ce8f6 github.com/cnotch/scheduler v0.0.0-20200522024700-1d2da93eefc5 diff --git a/go.sum b/go.sum index 05751df..22293df 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/cnotch/apirouter v0.0.0-20200731232942-89e243a791f3 h1:Y8fe6nOk/UMsVZOPPLEVd9axxbIuBBjhZ+g6RpMz6vI= github.com/cnotch/apirouter v0.0.0-20200731232942-89e243a791f3/go.mod h1:5deJPLON/x/s2dLOQfuKS0lenhOIT4xX0pvtN/OEIuY= -github.com/cnotch/bitutil v0.0.0-20200512012328-08db448fb960 h1:mZGYgYjlZOh+oMLvv3uxT61J0y8SWStIoOaqWU9S3Lk= -github.com/cnotch/bitutil v0.0.0-20200512012328-08db448fb960/go.mod h1:ivZKsbAhsndNi8A5NFiDkBUY3+lVINm+IXNUnQNn6JM= github.com/cnotch/loader v0.0.0-20200405015128-d9d964d09439 h1:iNWyllf6zuby+nDNC6zKEkM7aUFbp4RccfWVdQ3HFfQ= github.com/cnotch/loader v0.0.0-20200405015128-d9d964d09439/go.mod h1:oWpDagHB6p+Kqqq7RoRZKyC4XAXft50hR8pbTxdbYYs= github.com/cnotch/queue v0.0.0-20200326024423-6e88bdbf2ad4 h1:bU2h1mvmsh6V1gQDGKgA9lHfBMLCmaVs1t2xyloDYHY=