fps
This commit is contained in:
		| @@ -3,6 +3,7 @@ package h264parser | |||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"math" | ||||||
|  |  | ||||||
| 	"github.com/deepch/vdk/av" | 	"github.com/deepch/vdk/av" | ||||||
| 	"github.com/deepch/vdk/utils/bits" | 	"github.com/deepch/vdk/utils/bits" | ||||||
| @@ -294,8 +295,10 @@ func SplitNALUs(b []byte) (nalus [][]byte, typ int) { | |||||||
| } | } | ||||||
|  |  | ||||||
| type SPSInfo struct { | type SPSInfo struct { | ||||||
| 	ProfileIdc uint | 	Id                uint | ||||||
| 	LevelIdc   uint | 	ProfileIdc        uint | ||||||
|  | 	LevelIdc          uint | ||||||
|  | 	ConstraintSetFlag uint | ||||||
|  |  | ||||||
| 	MbWidth  uint | 	MbWidth  uint | ||||||
| 	MbHeight uint | 	MbHeight uint | ||||||
| @@ -307,38 +310,59 @@ type SPSInfo struct { | |||||||
|  |  | ||||||
| 	Width  uint | 	Width  uint | ||||||
| 	Height 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)} | 	r := &bits.GolombBitReader{R: bytes.NewReader(data)} | ||||||
|  |  | ||||||
| 	if _, err = r.ReadBits(8); err != nil { | 	if _, err = r.ReadBits(8); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if self.ProfileIdc, err = r.ReadBits(8); err != nil { | 	if s.ProfileIdc, err = r.ReadBits(8); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// constraint_set0_flag-constraint_set6_flag,reserved_zero_2bits | 	// 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 | 		return | ||||||
| 	} | 	} | ||||||
|  | 	s.ConstraintSetFlag = s.ConstraintSetFlag >> 2 | ||||||
|  |  | ||||||
| 	// level_idc | 	// level_idc | ||||||
| 	if self.LevelIdc, err = r.ReadBits(8); err != nil { | 	if s.LevelIdc, err = r.ReadBits(8); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// seq_parameter_set_id | 	// seq_parameter_set_id | ||||||
| 	if _, err = r.ReadExponentialGolombCode(); err != nil { | 	if s.Id, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if self.ProfileIdc == 100 || self.ProfileIdc == 110 || | 	if s.ProfileIdc == 100 || s.ProfileIdc == 110 || | ||||||
| 		self.ProfileIdc == 122 || self.ProfileIdc == 244 || | 		s.ProfileIdc == 122 || s.ProfileIdc == 244 || | ||||||
| 		self.ProfileIdc == 44 || self.ProfileIdc == 83 || | 		s.ProfileIdc == 44 || s.ProfileIdc == 83 || | ||||||
| 		self.ProfileIdc == 86 || self.ProfileIdc == 118 { | 		s.ProfileIdc == 86 || s.ProfileIdc == 118 { | ||||||
|  |  | ||||||
| 		var chroma_format_idc uint | 		var chroma_format_idc uint | ||||||
| 		if chroma_format_idc, err = r.ReadExponentialGolombCode(); err != nil { | 		if chroma_format_idc, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| @@ -450,15 +474,15 @@ func ParseSPS(data []byte) (self SPSInfo, err error) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if self.MbWidth, err = r.ReadExponentialGolombCode(); err != nil { | 	if s.MbWidth, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	self.MbWidth++ | 	s.MbWidth++ | ||||||
|  |  | ||||||
| 	if self.MbHeight, err = r.ReadExponentialGolombCode(); err != nil { | 	if s.MbHeight, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	self.MbHeight++ | 	s.MbHeight++ | ||||||
|  |  | ||||||
| 	var frame_mbs_only_flag uint | 	var frame_mbs_only_flag uint | ||||||
| 	if frame_mbs_only_flag, err = r.ReadBit(); err != nil { | 	if frame_mbs_only_flag, err = r.ReadBit(); err != nil { | ||||||
| @@ -481,23 +505,146 @@ func ParseSPS(data []byte) (self SPSInfo, err error) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if frame_cropping_flag != 0 { | 	if frame_cropping_flag != 0 { | ||||||
| 		if self.CropLeft, err = r.ReadExponentialGolombCode(); err != nil { | 		if s.CropLeft, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		if self.CropRight, err = r.ReadExponentialGolombCode(); err != nil { | 		if s.CropRight, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		if self.CropTop, err = r.ReadExponentialGolombCode(); err != nil { | 		if s.CropTop, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		if self.CropBottom, err = r.ReadExponentialGolombCode(); err != nil { | 		if s.CropBottom, err = r.ReadExponentialGolombCode(); err != nil { | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	self.Width = (self.MbWidth * 16) - self.CropLeft*2 - self.CropRight*2 | 	s.Width = (s.MbWidth * 16) - s.CropLeft*2 - s.CropRight*2 | ||||||
| 	self.Height = ((2 - frame_mbs_only_flag) * self.MbHeight * 16) - self.CropTop*2 - self.CropBottom*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 | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								format/hls/muxer.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								format/hls/muxer.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | package hls | ||||||
| @@ -10,6 +10,7 @@ import ( | |||||||
| 	"github.com/deepch/vdk/codec/aacparser" | 	"github.com/deepch/vdk/codec/aacparser" | ||||||
| 	"github.com/deepch/vdk/codec/h264parser" | 	"github.com/deepch/vdk/codec/h264parser" | ||||||
| 	"github.com/deepch/vdk/codec/h265parser" | 	"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/mp4/mp4io" | ||||||
| 	"github.com/deepch/vdk/format/mp4f/mp4fio" | 	"github.com/deepch/vdk/format/mp4f/mp4fio" | ||||||
| 	"github.com/deepch/vdk/utils/bits/pio" | 	"github.com/deepch/vdk/utils/bits/pio" | ||||||
| @@ -312,6 +313,11 @@ func (element *Muxer) WritePacket4(pkt av.Packet) error { | |||||||
| 	return stream.writePacketV4(pkt) | 	return stream.writePacketV4(pkt) | ||||||
| } | } | ||||||
| func (element *Stream) writePacketV4(pkt av.Packet) error { | 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 | 	trackID := pkt.Idx + 1 | ||||||
| 	if element.sampleIndex == 0 { | 	if element.sampleIndex == 0 { | ||||||
| 		element.moof.Header = &mp4fio.MovieFragHeader{Seqnum: uint32(element.muxer.fragmentIndex + 1)} | 		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{ | 				Run: &mp4fio.TrackFragRun{ | ||||||
| 					Flags:            0x000b05, | 					Flags:            0x000b05, | ||||||
| 					FirstSampleFlags: 0x02000000, | 					FirstSampleFlags: uint32(defaultFlags), | ||||||
| 					DataOffset:       0, | 					DataOffset:       0, | ||||||
| 					Entries:          []mp4io.TrackFragRunEntry{}, | 					Entries:          []mp4io.TrackFragRunEntry{}, | ||||||
| 				}, | 				}, | ||||||
| @@ -339,7 +345,9 @@ func (element *Stream) writePacketV4(pkt av.Packet) error { | |||||||
| 		Duration: uint32(element.timeToTs(pkt.Duration)), | 		Duration: uint32(element.timeToTs(pkt.Duration)), | ||||||
| 		Size:     uint32(len(pkt.Data)), | 		Size:     uint32(len(pkt.Data)), | ||||||
| 		Cts:      uint32(element.timeToTs(pkt.CompositionTime)), | 		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.moof.Tracks[0].Run.Entries = append(element.moof.Tracks[0].Run.Entries, runEnrty) | ||||||
| 	element.buffer = append(element.buffer, pkt.Data...) | 	element.buffer = append(element.buffer, pkt.Data...) | ||||||
| 	element.sampleIndex++ | 	element.sampleIndex++ | ||||||
| @@ -347,6 +355,9 @@ func (element *Stream) writePacketV4(pkt av.Packet) error { | |||||||
|  |  | ||||||
| 	return nil | 	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) { | func (element *Stream) writePacketV3(pkt av.Packet, rawdur time.Duration, maxFrames int) (bool, []byte, error) { | ||||||
| 	trackID := pkt.Idx + 1 | 	trackID := pkt.Idx + 1 | ||||||
| 	var out []byte | 	var out []byte | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ type Session struct { | |||||||
| type Media struct { | type Media struct { | ||||||
| 	AVType             string | 	AVType             string | ||||||
| 	Type               av.CodecType | 	Type               av.CodecType | ||||||
|  | 	FPS                int | ||||||
| 	TimeScale          int | 	TimeScale          int | ||||||
| 	Control            string | 	Control            string | ||||||
| 	Rtpmap             int | 	Rtpmap             int | ||||||
| @@ -37,6 +38,10 @@ func Parse(content string) (sess Session, medias []Media) { | |||||||
|  |  | ||||||
| 	for _, line := range strings.Split(content, "\n") { | 	for _, line := range strings.Split(content, "\n") { | ||||||
| 		line = strings.TrimSpace(line) | 		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) | 		typeval := strings.SplitN(line, "=", 2) | ||||||
| 		if len(typeval) == 2 { | 		if len(typeval) == 2 { | ||||||
| 			fields := strings.SplitN(typeval[1], " ", 2) | 			fields := strings.SplitN(typeval[1], " ", 2) | ||||||
| @@ -78,6 +83,8 @@ func Parse(content string) (sess Session, medias []Media) { | |||||||
| 								media.Control = val | 								media.Control = val | ||||||
| 							case "rtpmap": | 							case "rtpmap": | ||||||
| 								media.Rtpmap, _ = strconv.Atoi(val) | 								media.Rtpmap, _ = strconv.Atoi(val) | ||||||
|  | 							case "x-framerate": | ||||||
|  | 								media.FPS, _ = strconv.Atoi(val) | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 						keyval = strings.Split(field, "/") | 						keyval = strings.Split(field, "/") | ||||||
|   | |||||||
| @@ -85,6 +85,7 @@ type RTSPClient struct { | |||||||
| 	PreAudioTS          int64 | 	PreAudioTS          int64 | ||||||
| 	PreVideoTS          int64 | 	PreVideoTS          int64 | ||||||
| 	PreSequenceNumber   int | 	PreSequenceNumber   int | ||||||
|  | 	FPS                 int | ||||||
| } | } | ||||||
|  |  | ||||||
| type RTSPClientOptions struct { | type RTSPClientOptions struct { | ||||||
| @@ -153,6 +154,7 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) { | |||||||
| 				} else { | 				} else { | ||||||
| 					client.CodecData = append(client.CodecData, h264parser.CodecData{}) | 					client.CodecData = append(client.CodecData, h264parser.CodecData{}) | ||||||
| 				} | 				} | ||||||
|  | 				client.FPS = i2.FPS | ||||||
| 				client.videoCodec = av.H264 | 				client.videoCodec = av.H264 | ||||||
| 			} else if i2.Type == av.H265 { | 			} else if i2.Type == av.H265 { | ||||||
| 				if len(i2.SpropVPS) > 1 && len(i2.SpropSPS) > 1 && len(i2.SpropPPS) > 1 { | 				if len(i2.SpropVPS) > 1 && len(i2.SpropSPS) > 1 && len(i2.SpropPPS) > 1 { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Andrey Semochkin
					Andrey Semochkin