From 5adbbcc01f89bc75144b16dd7e163708b755eeba Mon Sep 17 00:00:00 2001 From: Andrey Semochkin Date: Sat, 8 May 2021 23:07:59 +0300 Subject: [PATCH] fps --- codec/h264parser/parser.go | 189 ++++++++++++++++++++++++++++++++----- format/hls/muxer.go | 1 + format/mp4f/muxer.go | 13 ++- format/rtsp/sdp/parser.go | 7 ++ format/rtspv2/client.go | 2 + 5 files changed, 190 insertions(+), 22 deletions(-) create mode 100644 format/hls/muxer.go diff --git a/codec/h264parser/parser.go b/codec/h264parser/parser.go index b015f9e..042164f 100644 --- a/codec/h264parser/parser.go +++ b/codec/h264parser/parser.go @@ -3,6 +3,7 @@ package h264parser import ( "bytes" "fmt" + "math" "github.com/deepch/vdk/av" "github.com/deepch/vdk/utils/bits" @@ -294,8 +295,10 @@ func SplitNALUs(b []byte) (nalus [][]byte, typ int) { } type SPSInfo struct { - ProfileIdc uint - LevelIdc uint + Id uint + ProfileIdc uint + LevelIdc uint + ConstraintSetFlag uint MbWidth uint MbHeight uint @@ -307,38 +310,59 @@ type SPSInfo struct { Width uint Height uint + FPS uint } -func ParseSPS(data []byte) (self SPSInfo, err error) { +func RemoveH264orH265EmulationBytes(b []byte) []byte { + j := 0 + r := make([]byte, len(b)) + for i := 0; (i < len(b)) && (j < len(b)); { + if i+2 < len(b) && + b[i] == 0 && b[i+1] == 0 && b[i+2] == 3 { + r[j] = 0 + r[j+1] = 0 + j = j + 2 + i = i + 3 + } else { + r[j] = b[i] + j = j + 1 + i = i + 1 + } + } + return r[:j] +} +func ParseSPS(data []byte) (s SPSInfo, err error) { + data = RemoveH264orH265EmulationBytes(data) r := &bits.GolombBitReader{R: bytes.NewReader(data)} if _, err = r.ReadBits(8); err != nil { return } - if self.ProfileIdc, err = r.ReadBits(8); err != nil { + if s.ProfileIdc, err = r.ReadBits(8); err != nil { return } // constraint_set0_flag-constraint_set6_flag,reserved_zero_2bits - if _, err = r.ReadBits(8); err != nil { + if s.ConstraintSetFlag, err = r.ReadBits(8); err != nil { return } + s.ConstraintSetFlag = s.ConstraintSetFlag >> 2 // level_idc - if self.LevelIdc, err = r.ReadBits(8); err != nil { + if s.LevelIdc, err = r.ReadBits(8); err != nil { return } // seq_parameter_set_id - if _, err = r.ReadExponentialGolombCode(); err != nil { + if s.Id, err = r.ReadExponentialGolombCode(); err != nil { return } - if self.ProfileIdc == 100 || self.ProfileIdc == 110 || - self.ProfileIdc == 122 || self.ProfileIdc == 244 || - self.ProfileIdc == 44 || self.ProfileIdc == 83 || - self.ProfileIdc == 86 || self.ProfileIdc == 118 { + if s.ProfileIdc == 100 || s.ProfileIdc == 110 || + s.ProfileIdc == 122 || s.ProfileIdc == 244 || + s.ProfileIdc == 44 || s.ProfileIdc == 83 || + s.ProfileIdc == 86 || s.ProfileIdc == 118 { var chroma_format_idc uint if chroma_format_idc, err = r.ReadExponentialGolombCode(); err != nil { @@ -450,15 +474,15 @@ func ParseSPS(data []byte) (self SPSInfo, err error) { return } - if self.MbWidth, err = r.ReadExponentialGolombCode(); err != nil { + if s.MbWidth, err = r.ReadExponentialGolombCode(); err != nil { return } - self.MbWidth++ + s.MbWidth++ - if self.MbHeight, err = r.ReadExponentialGolombCode(); err != nil { + if s.MbHeight, err = r.ReadExponentialGolombCode(); err != nil { return } - self.MbHeight++ + s.MbHeight++ var frame_mbs_only_flag uint if frame_mbs_only_flag, err = r.ReadBit(); err != nil { @@ -481,23 +505,146 @@ func ParseSPS(data []byte) (self SPSInfo, err error) { return } if frame_cropping_flag != 0 { - if self.CropLeft, err = r.ReadExponentialGolombCode(); err != nil { + if s.CropLeft, err = r.ReadExponentialGolombCode(); err != nil { return } - if self.CropRight, err = r.ReadExponentialGolombCode(); err != nil { + if s.CropRight, err = r.ReadExponentialGolombCode(); err != nil { return } - if self.CropTop, err = r.ReadExponentialGolombCode(); err != nil { + if s.CropTop, err = r.ReadExponentialGolombCode(); err != nil { return } - if self.CropBottom, err = r.ReadExponentialGolombCode(); err != nil { + if s.CropBottom, err = r.ReadExponentialGolombCode(); err != nil { return } } - self.Width = (self.MbWidth * 16) - self.CropLeft*2 - self.CropRight*2 - self.Height = ((2 - frame_mbs_only_flag) * self.MbHeight * 16) - self.CropTop*2 - self.CropBottom*2 + s.Width = (s.MbWidth * 16) - s.CropLeft*2 - s.CropRight*2 + s.Height = ((2 - frame_mbs_only_flag) * s.MbHeight * 16) - s.CropTop*2 - s.CropBottom*2 + vui_parameter_present_flag, err := r.ReadBit() + if err != nil { + return + } + + if vui_parameter_present_flag != 0 { + aspect_ratio_info_present_flag, err := r.ReadBit() + if err != nil { + return s, err + } + + if aspect_ratio_info_present_flag != 0 { + aspect_ratio_idc, err := r.ReadBits(8) + if err != nil { + return s, err + } + + if aspect_ratio_idc == 255 { + sar_width, err := r.ReadBits(16) + if err != nil { + return s, err + } + sar_height, err := r.ReadBits(16) + if err != nil { + return s, err + } + + _, _ = sar_width, sar_height + } + } + + overscan_info_present_flag, err := r.ReadBit() + if err != nil { + return s, err + } + + if overscan_info_present_flag != 0 { + overscan_appropriate_flagu, err := r.ReadBit() + if err != nil { + return s, err + } + + _ = overscan_appropriate_flagu + } + video_signal_type_present_flag, err := r.ReadBit() + if video_signal_type_present_flag != 0 { + video_format, err := r.ReadBits(3) + if err != nil { + return s, err + } + _ = video_format + video_full_range_flag, err := r.ReadBit() + if err != nil { + return s, err + } + _ = video_full_range_flag + colour_description_present_flag, err := r.ReadBit() + if err != nil { + return s, err + } + if colour_description_present_flag != 0 { + colour_primaries, err := r.ReadBits(8) + if err != nil { + return s, err + } + _ = colour_primaries + transfer_characteristics, err := r.ReadBits(8) + if err != nil { + return s, err + } + _ = transfer_characteristics + matrix_coefficients, err := r.ReadBits(8) + if err != nil { + return s, err + } + _ = matrix_coefficients + } + } + chroma_loc_info_present_flag, err := r.ReadBit() + if err != nil { + return s, err + } + if chroma_loc_info_present_flag != 0 { + chroma_sample_loc_type_top_field, err := r.ReadSE() + if err != nil { + return s, err + } + _ = chroma_sample_loc_type_top_field + + chroma_sample_loc_type_bottom_field, err := r.ReadSE() + if err != nil { + return s, err + } + + _ = chroma_sample_loc_type_bottom_field + } + + timing_info_present_flag, err := r.ReadBit() + if err != nil { + return s, err + } + + if timing_info_present_flag != 0 { + num_units_in_tick, err := r.ReadBits(32) + if err != nil { + return s, err + } + time_scale, err := r.ReadBits(32) + if err != nil { + return s, err + } + s.FPS = uint(math.Floor(float64(time_scale) / float64(num_units_in_tick) / 2.0)) + fixed_frame_rate_flag, err := r.ReadBit() + if err != nil { + return s, err + } + if fixed_frame_rate_flag != 0 { + //utils.L.InfoLn("fixed_frame_rate_flag", fixed_frame_rate_flag) + //have been devide 2 + //self.FPS = self.FPS / 2 + } + } + } return } diff --git a/format/hls/muxer.go b/format/hls/muxer.go new file mode 100644 index 0000000..92ea362 --- /dev/null +++ b/format/hls/muxer.go @@ -0,0 +1 @@ +package hls diff --git a/format/mp4f/muxer.go b/format/mp4f/muxer.go index d9d3dd2..1e0630b 100644 --- a/format/mp4f/muxer.go +++ b/format/mp4f/muxer.go @@ -10,6 +10,7 @@ import ( "github.com/deepch/vdk/codec/aacparser" "github.com/deepch/vdk/codec/h264parser" "github.com/deepch/vdk/codec/h265parser" + "github.com/deepch/vdk/format/fmp4/fmp4io" "github.com/deepch/vdk/format/mp4/mp4io" "github.com/deepch/vdk/format/mp4f/mp4fio" "github.com/deepch/vdk/utils/bits/pio" @@ -312,6 +313,11 @@ func (element *Muxer) WritePacket4(pkt av.Packet) error { return stream.writePacketV4(pkt) } func (element *Stream) writePacketV4(pkt av.Packet) error { + //pkt.Data = pkt.Data[4:] + defaultFlags := fmp4io.SampleNonKeyframe + if pkt.IsKeyFrame { + defaultFlags = fmp4io.SampleNoDependencies + } trackID := pkt.Idx + 1 if element.sampleIndex == 0 { element.moof.Header = &mp4fio.MovieFragHeader{Seqnum: uint32(element.muxer.fragmentIndex + 1)} @@ -327,7 +333,7 @@ func (element *Stream) writePacketV4(pkt av.Packet) error { }, Run: &mp4fio.TrackFragRun{ Flags: 0x000b05, - FirstSampleFlags: 0x02000000, + FirstSampleFlags: uint32(defaultFlags), DataOffset: 0, Entries: []mp4io.TrackFragRunEntry{}, }, @@ -339,7 +345,9 @@ func (element *Stream) writePacketV4(pkt av.Packet) error { Duration: uint32(element.timeToTs(pkt.Duration)), Size: uint32(len(pkt.Data)), Cts: uint32(element.timeToTs(pkt.CompositionTime)), + Flags: uint32(defaultFlags), } + //log.Println("packet", defaultFlags,pkt.Duration, pkt.CompositionTime) element.moof.Tracks[0].Run.Entries = append(element.moof.Tracks[0].Run.Entries, runEnrty) element.buffer = append(element.buffer, pkt.Data...) element.sampleIndex++ @@ -347,6 +355,9 @@ func (element *Stream) writePacketV4(pkt av.Packet) error { return nil } +func (element *Muxer) SetIndex(val int) { + element.fragmentIndex = val +} func (element *Stream) writePacketV3(pkt av.Packet, rawdur time.Duration, maxFrames int) (bool, []byte, error) { trackID := pkt.Idx + 1 var out []byte diff --git a/format/rtsp/sdp/parser.go b/format/rtsp/sdp/parser.go index c5d7ca2..5c8f8e1 100644 --- a/format/rtsp/sdp/parser.go +++ b/format/rtsp/sdp/parser.go @@ -18,6 +18,7 @@ type Session struct { type Media struct { AVType string Type av.CodecType + FPS int TimeScale int Control string Rtpmap int @@ -37,6 +38,10 @@ func Parse(content string) (sess Session, medias []Media) { for _, line := range strings.Split(content, "\n") { line = strings.TrimSpace(line) + ////Camera [BUG] a=x-framerate: 25 + if strings.Contains(line, "x-framerate") { + line = strings.Replace(line, " ", "", -1) + } typeval := strings.SplitN(line, "=", 2) if len(typeval) == 2 { fields := strings.SplitN(typeval[1], " ", 2) @@ -78,6 +83,8 @@ func Parse(content string) (sess Session, medias []Media) { media.Control = val case "rtpmap": media.Rtpmap, _ = strconv.Atoi(val) + case "x-framerate": + media.FPS, _ = strconv.Atoi(val) } } keyval = strings.Split(field, "/") diff --git a/format/rtspv2/client.go b/format/rtspv2/client.go index 50bd8c8..504a23f 100644 --- a/format/rtspv2/client.go +++ b/format/rtspv2/client.go @@ -85,6 +85,7 @@ type RTSPClient struct { PreAudioTS int64 PreVideoTS int64 PreSequenceNumber int + FPS int } type RTSPClientOptions struct { @@ -153,6 +154,7 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) { } else { client.CodecData = append(client.CodecData, h264parser.CodecData{}) } + client.FPS = i2.FPS client.videoCodec = av.H264 } else if i2.Type == av.H265 { if len(i2.SpropVPS) > 1 && len(i2.SpropSPS) > 1 && len(i2.SpropPPS) > 1 {