fps
This commit is contained in:
parent
338966ed52
commit
5adbbcc01f
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user