From 5b25bda1a000b61040a10c34b1563106907f937f Mon Sep 17 00:00:00 2001 From: Andrey Semochkin Date: Sun, 23 May 2021 13:37:05 +0300 Subject: [PATCH] test dvrip --- format/dvrip/client.go | 502 +++++++++++++++++++++++++++++++++++++ format/dvrip/struct.go | 185 ++++++++++++++ format/mp4/mp4io/atoms.go | 100 ++++++++ format/mp4m/mp4io/atoms.go | 100 ++++++++ format/rtspv2/client.go | 2 + format/ts/tsio/tsio.go | 17 +- 6 files changed, 895 insertions(+), 11 deletions(-) create mode 100644 format/dvrip/client.go create mode 100644 format/dvrip/struct.go diff --git a/format/dvrip/client.go b/format/dvrip/client.go new file mode 100644 index 0000000..0703942 --- /dev/null +++ b/format/dvrip/client.go @@ -0,0 +1,502 @@ +package dvrip + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "html" + "net" + "net/url" + "strconv" + "strings" + "time" + + "github.com/deepch/vdk/av" + "github.com/deepch/vdk/codec" + "github.com/deepch/vdk/codec/h264parser" +) + +const ( + SignalStreamStop = iota + SignalCodecUpdate +) + +type Client struct { + conn net.Conn + login string + password string + host string + stream string + sequenceNumber int32 + session int32 + aliveInterval time.Duration + CodecData []av.CodecData + OutgoingPacketQueue chan *av.Packet + Signals chan int + options ClientOptions + sps []byte + pps []byte +} + +type ClientOptions struct { + Debug bool + URL string + DialTimeout time.Duration + ReadWriteTimeout time.Duration + DisableAudio bool +} + +//Dial func +func Dial(options ClientOptions) (*Client, error) { + client := &Client{ + Signals: make(chan int, 100), + OutgoingPacketQueue: make(chan *av.Packet, 3000), + options: options, + } + err := client.parseURL(html.UnescapeString(client.options.URL)) + if err != nil { + return nil, err + } + client.conn, err = net.DialTimeout("tcp", client.host, time.Second*2) + if err != nil { + return nil, err + } + err = client.conn.SetDeadline(time.Now().Add(5 * time.Second)) + if err != nil { + return nil, err + } + err = client.Login() + if err != nil { + return nil, err + } + err = client.SetTime() + if err != nil { + return nil, err + } + go client.Monitor() + return client, nil +} + +//Close func +func (client *Client) Close() error { + err := client.conn.Close() + return err +} + +//SetKeepAlive func +func (client *Client) SetKeepAlive() error { + body, err := json.Marshal(map[string]string{ + "Name": "KeepAlive", + "SessionID": fmt.Sprintf("0x%08X", client.session), + }) + if err != nil { + return err + } + err = client.send(codeKeepAlive, body) + if err != nil { + return err + } + return nil +} + +//Monitor func +func (client *Client) Monitor() { + defer func() { + client.Signals <- SignalStreamStop + }() + _, _, err := client.Command(codeOPMonitor, map[string]interface{}{ + "Action": "Claim", + "Parameter": map[string]interface{}{ + "Channel": 0, + "CombinMode": "NONE", + "StreamType": client.stream, + "TransMode": "TCP", + }, + }) + if err != nil { + return + } + payload, err := json.Marshal(map[string]interface{}{ + "Name": "OPMonitor", + "SessionID": fmt.Sprintf("0x%08X", client.session), + "OPMonitor": map[string]interface{}{ + "Action": "Start", + "Parameter": map[string]interface{}{ + "Channel": 0, + "CombinMode": "NONE", + "StreamType": client.stream, + "TransMode": "TCP", + }, + }, + }) + err = client.send(1410, payload) + if err != nil { + return + } + var length uint32 = 0 + var dataType uint32 + timer := time.Now() + var fps int + for { + if time.Now().Sub(timer).Milliseconds() > client.aliveInterval.Milliseconds() { + err = client.SetKeepAlive() + if err != nil { + return + } + timer = time.Now() + } + _, body, err := client.recv(false) + if err != nil { + return + } + buf := bytes.NewReader(body) + err = binary.Read(buf, binary.BigEndian, &dataType) + if err != nil { + return + } + switch dataType { + case 0x1FC, 0x1FE: + frame := struct { + Media byte + FPS byte + Width byte + Height byte + DateTime uint32 + Length uint32 + }{} + err = binary.Read(buf, binary.LittleEndian, &frame) + fps = int(frame.FPS) + if err != nil { + return + } + var packet bytes.Buffer + if frame.Length > uint32(buf.Len()) { + need := frame.Length - uint32(buf.Len()) + _, err = buf.WriteTo(&packet) + if err != nil { + return + } + _, err := client.recvSize(&packet, need) + if err != nil { + return + } + } else { + _, err = buf.WriteTo(&packet) + if err != nil { + return + } + } + if parseMediaType(dataType, frame.Media) == av.H264.String() { + packets, _ := h264parser.SplitNALUs(packet.Bytes()) + for _, i2 := range packets { + naluType := i2[0] & 0x1f + switch { + case naluType >= 1 && naluType <= 5: + client.OutgoingPacketQueue <- &av.Packet{Duration: time.Duration(1000/fps) * time.Millisecond, Idx: 0, IsKeyFrame: naluType == 5, Data: append(binSize(len(i2)), i2...)} + case naluType == 7: + client.CodecUpdateSPS(i2) + case naluType == 8: + client.CodecUpdatePPS(i2) + } + } + } + case 0x1FD: + err = binary.Read(buf, binary.LittleEndian, &length) + if err != nil { + return + } + var packet bytes.Buffer + if length > uint32(buf.Len()) { + need := length - uint32(buf.Len()) + _, err = buf.WriteTo(&packet) + if err != nil { + return + } + _, err := client.recvSize(&packet, need) + if err != nil { + return + } + } else { + _, err = buf.WriteTo(&packet) + if err != nil { + return + } + } + packets, _ := h264parser.SplitNALUs(packet.Bytes()) + for _, i2 := range packets { + naluType := i2[0] & 0x1f + switch { + case naluType >= 1 && naluType <= 5: + if fps != 0 { + client.OutgoingPacketQueue <- &av.Packet{Duration: time.Duration(1000/fps) * time.Millisecond, Idx: 0, IsKeyFrame: naluType == 5, Data: append(binSize(len(i2)), i2...)} + } + case naluType == 7: + client.CodecUpdateSPS(i2) + case naluType == 8: + client.CodecUpdatePPS(i2) + } + } + case 0x1FA, 0x1F9: + if client.options.DisableAudio { + continue + } + frame := struct { + Media byte + SampleRate byte + Length uint16 + }{} + err = binary.Read(buf, binary.LittleEndian, &frame) + if err != nil { + return + } + var packet bytes.Buffer + if uint32(frame.Length) > uint32(buf.Len()) { + need := uint32(frame.Length) - uint32(buf.Len()) + _, err = buf.WriteTo(&packet) + if err != nil { + return + } + _, err := client.recvSize(&packet, need) + if err != nil { + return + } + } else { + _, err = buf.WriteTo(&packet) + if err != nil { + return + } + } + if parseMediaType(dataType, frame.Media) == av.PCM_ALAW.String() { + if client.CodecData != nil { + if len(client.CodecData) == 1 { + client.CodecUpdatePCMAlaw() + } + client.OutgoingPacketQueue <- &av.Packet{Duration: time.Duration(8000/packet.Len()) * time.Millisecond, Idx: 1, Data: packet.Bytes()} + } + } + case 0xFFD8FFE0: + default: + continue + } + } +} + +func (client *Client) SetTime() error { + _, _, err := client.Command(codeOPTimeSetting, time.Now().Format("2006-01-02 15:04:05")) + return err +} +func (client *Client) Login() error { + body, err := json.Marshal(map[string]string{ + "EncryptType": "MD5", + "LoginType": "DVRIP-WEB", + "PassWord": sofiaHash(client.password), + "UserName": client.login, + }) + if err != nil { + return err + } + err = client.send(codeLogin, body) + if err != nil { + return err + } + _, resp, err := client.recv(true) + if err != nil { + return err + } + res := LoginResp{} + err = json.Unmarshal(resp, &res) + if err != nil { + return err + } + if (statusCode(res.Ret) != statusOK) && (statusCode(res.Ret) != statusUpgradeSuccessful) { + return fmt.Errorf("unexpected status code: %v - %v", res.Ret, statusCodes[statusCode(res.Ret)]) + } + client.aliveInterval = time.Duration(res.AliveInterval) * time.Second + session, err := strconv.ParseUint(res.SessionID, 0, 32) + if err != nil { + return err + } + client.session = int32(session) + return nil +} + +//Command func +func (client *Client) Command(command requestCode, data interface{}) (*Payload, []byte, error) { + params, err := json.Marshal(map[string]interface{}{ + "Name": requestCodes[command], + "SessionID": fmt.Sprintf("0x%08X", client.session), + requestCodes[command]: data, + }) + if err != nil { + return nil, nil, err + } + err = client.send(command, params) + if err != nil { + return nil, nil, err + } + resp, body, err := client.recv(true) + return resp, body, err +} + +//send func +func (client *Client) send(msgID requestCode, data []byte) error { + var buf bytes.Buffer + if err := binary.Write(&buf, binary.LittleEndian, Payload{ + Head: 255, + Version: 0, + Session: client.session, + SequenceNumber: client.sequenceNumber, + MsgID: int16(msgID), + BodyLength: int32(len(data)) + 2, + }); err != nil { + return err + } + err := client.conn.SetDeadline(time.Now().Add(5 * time.Second)) + if err != nil { + return err + } + err = binary.Write(&buf, binary.LittleEndian, data) + if err != nil { + return err + } + err = binary.Write(&buf, binary.LittleEndian, magicEnd) + if err != nil { + return err + } + _, err = client.conn.Write(buf.Bytes()) + if err != nil { + return err + } + client.sequenceNumber++ + return nil +} + +//recvSize func +func (client *Client) recvSize(buffer *bytes.Buffer, size uint32) ([]byte, error) { + all := uint32(0) + for { + _, body, err := client.recv(false) + if err != nil { + return nil, err + } + all += uint32(len(body)) + buffer.Write(body) + if all == size { + break + } else if all > size { + return nil, fmt.Errorf("invalid read size") + } + } + return nil, nil +} + +//recv func +func (client *Client) recv(text bool) (*Payload, []byte, error) { + var p Payload + var b = make([]byte, 20) + err := client.conn.SetReadDeadline(time.Now().Add(5 * time.Second)) + if err != nil { + return nil, nil, err + } + _, err = client.conn.Read(b) + if err != nil { + return nil, nil, err + } + err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &p) + if err != nil { + return nil, nil, err + } + client.sequenceNumber += 1 + if p.BodyLength <= 0 || p.BodyLength >= 100000 { + return nil, nil, fmt.Errorf("invalid bodylength: %v", p.BodyLength) + } + body := make([]byte, p.BodyLength) + err = binary.Read(client.conn, binary.LittleEndian, &body) + if err != nil { + return nil, nil, err + } + if text && len(body) > 2 && bytes.Compare(body[len(body)-2:], []byte{10, 0}) == 0 { + body = body[:len(body)-2] + } + return &p, body, nil +} + +//parseURL func +func (client *Client) parseURL(rawURL string) error { + l, err := url.Parse(rawURL) + if err != nil { + return err + } + username := l.User.Username() + password, _ := l.User.Password() + l.User = nil + if l.Port() == "" { + l.Host = fmt.Sprintf("%s:%s", l.Host, "34567") + } + if username == "" { + username = "admin" + } + if password == "" { + password = "admin" + } + client.login = username + client.password = password + client.host = l.Host + client.stream = strings.Trim(l.EscapedPath(), "/") + return nil +} + +func (client *Client) CodecUpdateSPS(val []byte) { + if bytes.Compare(val, client.sps) == 0 { + return + } + client.sps = val + if len(client.pps) == 0 { + return + } + codecData, err := h264parser.NewCodecDataFromSPSAndPPS(val, client.pps) + if err != nil { + return + } + if len(client.CodecData) > 0 { + for i, i2 := range client.CodecData { + if i2.Type().IsVideo() { + client.CodecData[i] = codecData + } + } + } else { + client.CodecData = append(client.CodecData, codecData) + } + client.Signals <- SignalCodecUpdate +} + +func (client *Client) CodecUpdatePPS(val []byte) { + if bytes.Compare(val, client.pps) == 0 { + return + } + client.pps = val + if len(client.sps) == 0 { + return + } + codecData, err := h264parser.NewCodecDataFromSPSAndPPS(client.sps, val) + if err != nil { + return + } + if len(client.CodecData) > 0 { + for i, i2 := range client.CodecData { + if i2.Type().IsVideo() { + client.CodecData[i] = codecData + } + } + } else { + client.CodecData = append(client.CodecData, codecData) + } + client.Signals <- SignalCodecUpdate +} + +func (client *Client) CodecUpdatePCMAlaw() { + CodecData := codec.NewPCMAlawCodecData() + client.CodecData = append(client.CodecData, CodecData) + client.Signals <- SignalCodecUpdate +} diff --git a/format/dvrip/struct.go b/format/dvrip/struct.go new file mode 100644 index 0000000..3af1786 --- /dev/null +++ b/format/dvrip/struct.go @@ -0,0 +1,185 @@ +package dvrip + +import ( + "crypto/md5" + "encoding/binary" + "time" +) + +var magicEnd = [2]byte{0x0A, 0x00} + +const alnum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + +type Payload struct { + Head byte + Version byte + _ byte + _ byte + Session int32 + SequenceNumber int32 + _ byte + _ byte + MsgID int16 + BodyLength int32 +} +type LoginResp struct { + AliveInterval int `json:"AliveInterval"` + ChannelNum int `json:"ChannelNum"` + DeviceType string `json:"DeviceType "` + ExtraChannel int `json:"ExtraChannel"` + Ret int `json:"Ret"` + SessionID string `json:"SessionID"` +} + +type requestCode uint16 + +const ( + codeLogin requestCode = 1000 + codeKeepAlive requestCode = 1006 + codeSystemInfo requestCode = 1020 + codeNetWorkNetCommon requestCode = 1042 + codeGeneral requestCode = 1042 + codeChannelTitle requestCode = 1046 + codeSystemFunction requestCode = 1360 + codeEncodeCapability requestCode = 1360 + codeOPPTZControl requestCode = 1400 + codeOPMonitor requestCode = 1413 + codeOPTalk requestCode = 1434 + codeOPTimeSetting requestCode = 1450 + codeOPMachine requestCode = 1450 + codeOPTimeQuery requestCode = 1452 + codeAuthorityList requestCode = 1470 + codeUsers requestCode = 1472 + codeGroups requestCode = 1474 + codeAddGroup requestCode = 1476 + codeModifyGroup requestCode = 1478 + codeDelGroup requestCode = 1480 + codeAddUser requestCode = 1482 + codeModifyUser requestCode = 1484 + codeDelUser requestCode = 1486 + codeModifyPassword requestCode = 1488 + codeAlarmSet requestCode = 1500 + codeOPNetAlarm requestCode = 1506 + codeAlarmInfo requestCode = 1504 + codeOPSendFile requestCode = 1522 + codeOPSystemUpgrade requestCode = 1525 + codeOPNetKeyboard requestCode = 1550 + codeOPSNAP requestCode = 1560 + codeOPMailTest requestCode = 1636 +) + +type statusCode int + +const ( + statusOK statusCode = 100 + statusUnknownError statusCode = 101 + statusUnsupportedVersion statusCode = 102 + statusRequestNotPermitted statusCode = 103 + statusUserAlreadyLoggedIn statusCode = 104 + statusUserIsNotLoggedIn statusCode = 105 + statusUsernameOrPasswordIsIncorrect statusCode = 106 + statusUserDoesNotHaveNecessaryPermissions statusCode = 107 + statusPasswordIsIncorrect statusCode = 203 + statusStartOfUpgrade statusCode = 511 + statusUpgradeWasNotStarted statusCode = 512 + statusUpgradeDataErrors statusCode = 513 + statusUpgradeError statusCode = 514 + statusUpgradeSuccessful statusCode = 515 +) + +var statusCodes = map[statusCode]string{ + statusOK: "OK", + statusUnknownError: "Unknown error", + statusUnsupportedVersion: "Unsupported version", + statusRequestNotPermitted: "Request not permitted", + statusUserAlreadyLoggedIn: "User already logged in", + statusUserIsNotLoggedIn: "User is not logged in", + statusUsernameOrPasswordIsIncorrect: "Username or password is incorrect", + statusUserDoesNotHaveNecessaryPermissions: "User does not have necessary permissions", + statusPasswordIsIncorrect: "Password is incorrect", + statusStartOfUpgrade: "Start of upgrade", + statusUpgradeWasNotStarted: "Upgrade was not started", + statusUpgradeDataErrors: "Upgrade data errors", + statusUpgradeError: "Upgrade error", + statusUpgradeSuccessful: "Upgrade successful", +} + +var requestCodes = map[requestCode]string{ + codeOPMonitor: "OPMonitor", + codeOPTimeSetting: "OPTimeSetting", +} + +type MetaInfo struct { + Width int + Height int + Datetime time.Time + FPS int + Frame string + Type string +} + +type Frame struct { + Data []byte + Meta MetaInfo +} + +//sofiaHash func +func sofiaHash(password string) string { + digest := md5.Sum([]byte(password)) + hash := make([]byte, 0, 8) + for i := 1; i < len(digest); i += 2 { + sum := int(digest[i-1]) + int(digest[i]) + hash = append(hash, alnum[sum%len(alnum)]) + } + return string(hash) +} + +//parseMediaType func +func parseMediaType(dataType uint32, mediaCode byte) string { + switch dataType { + case 0x1FC, 0x1FD: + switch mediaCode { + case 1: + return "MPEG4" + case 2: + return "H264" + case 3: + return "H265" + } + case 0x1F9: + if mediaCode == 1 || mediaCode == 6 { + return "info" + } + case 0x1FA: + if mediaCode == 0xE { + return "PCM_ALAW" + } + case 0x1FE: + if mediaCode == 0 { + return "JPEG" + } + default: + return "unknown" + } + + return "unexpected" +} + +//parseDatetime func +func parseDatetime(value uint32) time.Time { + second := int(value & 0x3F) + minute := int((value & 0xFC0) >> 6) + hour := int((value & 0x1F000) >> 12) + day := int((value & 0x3E0000) >> 17) + month := int((value & 0x3C00000) >> 22) + year := int(((value & 0xFC000000) >> 26) + 2000) + + return time.Date(year, time.Month(month), day, hour, minute, second, 0, time.UTC) +} + +//binSize func +func binSize(val int) []byte { + buf := make([]byte, 4) + binary.BigEndian.PutUint32(buf, uint32(val)) + return buf +} diff --git a/format/mp4/mp4io/atoms.go b/format/mp4/mp4io/atoms.go index dd3c3fb..3f8c584 100644 --- a/format/mp4/mp4io/atoms.go +++ b/format/mp4/mp4io/atoms.go @@ -3820,3 +3820,103 @@ func (self *TrackFragDecodeTime) Unmarshal(b []byte, offset int) (n int, err err func (self TrackFragDecodeTime) Children() (r []Atom) { return } + +const FTYP = Tag(0x66747970) + +type FileType struct { + MajorBrand uint32 + MinorVersion uint32 + CompatibleBrands []uint32 + AtomPos +} + +func (t FileType) Tag() Tag { + return FTYP +} + +func (f FileType) Marshal(b []byte) (n int) { + l := 16 + 4*len(f.CompatibleBrands) + pio.PutU32BE(b, uint32(l)) + pio.PutU32BE(b[4:], uint32(FTYP)) + pio.PutU32BE(b[8:], f.MajorBrand) + pio.PutU32BE(b[12:], f.MinorVersion) + for i, v := range f.CompatibleBrands { + pio.PutU32BE(b[16+4*i:], v) + } + return l +} + +func (f FileType) Len() int { + return 16 + 4*len(f.CompatibleBrands) +} + +func (f *FileType) Unmarshal(b []byte, offset int) (n int, err error) { + f.AtomPos.setPos(offset, len(b)) + n = 8 + if len(b) < n+8 { + return 0, parseErr("MajorBrand", offset+n, nil) + } + f.MajorBrand = pio.U32BE(b[n:]) + n += 4 + f.MinorVersion = pio.U32BE(b[n:]) + n += 4 + for n < len(b)-3 { + f.CompatibleBrands = append(f.CompatibleBrands, pio.U32BE(b[n:])) + n += 4 + } + return +} + +func (f FileType) Children() []Atom { + return nil +} + +const STYP = Tag(0x73747970) + +type SegmentType struct { + MajorBrand uint32 + MinorVersion uint32 + CompatibleBrands []uint32 + AtomPos +} + +func (t SegmentType) Tag() Tag { + return STYP +} + +func (f SegmentType) Marshal(b []byte) (n int) { + l := 16 + 4*len(f.CompatibleBrands) + pio.PutU32BE(b, uint32(l)) + pio.PutU32BE(b[4:], uint32(STYP)) + pio.PutU32BE(b[8:], f.MajorBrand) + pio.PutU32BE(b[12:], f.MinorVersion) + for i, v := range f.CompatibleBrands { + pio.PutU32BE(b[16+4*i:], v) + } + return l +} + +func (f SegmentType) Len() int { + return 16 + 4*len(f.CompatibleBrands) +} + +func (f *SegmentType) Unmarshal(b []byte, offset int) (n int, err error) { + f.AtomPos.setPos(offset, len(b)) + n = 8 + if len(b) < n+8 { + return 0, parseErr("MajorBrand", offset+n, nil) + } + f.MajorBrand = pio.U32BE(b[n:]) + n += 4 + f.MinorVersion = pio.U32BE(b[n:]) + n += 4 + for n < len(b)-3 { + f.CompatibleBrands = append(f.CompatibleBrands, pio.U32BE(b[n:])) + n += 4 + } + return +} + +func (f SegmentType) Children() []Atom { + return nil +} diff --git a/format/mp4m/mp4io/atoms.go b/format/mp4m/mp4io/atoms.go index dd3c3fb..3f8c584 100644 --- a/format/mp4m/mp4io/atoms.go +++ b/format/mp4m/mp4io/atoms.go @@ -3820,3 +3820,103 @@ func (self *TrackFragDecodeTime) Unmarshal(b []byte, offset int) (n int, err err func (self TrackFragDecodeTime) Children() (r []Atom) { return } + +const FTYP = Tag(0x66747970) + +type FileType struct { + MajorBrand uint32 + MinorVersion uint32 + CompatibleBrands []uint32 + AtomPos +} + +func (t FileType) Tag() Tag { + return FTYP +} + +func (f FileType) Marshal(b []byte) (n int) { + l := 16 + 4*len(f.CompatibleBrands) + pio.PutU32BE(b, uint32(l)) + pio.PutU32BE(b[4:], uint32(FTYP)) + pio.PutU32BE(b[8:], f.MajorBrand) + pio.PutU32BE(b[12:], f.MinorVersion) + for i, v := range f.CompatibleBrands { + pio.PutU32BE(b[16+4*i:], v) + } + return l +} + +func (f FileType) Len() int { + return 16 + 4*len(f.CompatibleBrands) +} + +func (f *FileType) Unmarshal(b []byte, offset int) (n int, err error) { + f.AtomPos.setPos(offset, len(b)) + n = 8 + if len(b) < n+8 { + return 0, parseErr("MajorBrand", offset+n, nil) + } + f.MajorBrand = pio.U32BE(b[n:]) + n += 4 + f.MinorVersion = pio.U32BE(b[n:]) + n += 4 + for n < len(b)-3 { + f.CompatibleBrands = append(f.CompatibleBrands, pio.U32BE(b[n:])) + n += 4 + } + return +} + +func (f FileType) Children() []Atom { + return nil +} + +const STYP = Tag(0x73747970) + +type SegmentType struct { + MajorBrand uint32 + MinorVersion uint32 + CompatibleBrands []uint32 + AtomPos +} + +func (t SegmentType) Tag() Tag { + return STYP +} + +func (f SegmentType) Marshal(b []byte) (n int) { + l := 16 + 4*len(f.CompatibleBrands) + pio.PutU32BE(b, uint32(l)) + pio.PutU32BE(b[4:], uint32(STYP)) + pio.PutU32BE(b[8:], f.MajorBrand) + pio.PutU32BE(b[12:], f.MinorVersion) + for i, v := range f.CompatibleBrands { + pio.PutU32BE(b[16+4*i:], v) + } + return l +} + +func (f SegmentType) Len() int { + return 16 + 4*len(f.CompatibleBrands) +} + +func (f *SegmentType) Unmarshal(b []byte, offset int) (n int, err error) { + f.AtomPos.setPos(offset, len(b)) + n = 8 + if len(b) < n+8 { + return 0, parseErr("MajorBrand", offset+n, nil) + } + f.MajorBrand = pio.U32BE(b[n:]) + n += 4 + f.MinorVersion = pio.U32BE(b[n:]) + n += 4 + for n < len(b)-3 { + f.CompatibleBrands = append(f.CompatibleBrands, pio.U32BE(b[n:])) + n += 4 + } + return +} + +func (f SegmentType) Children() []Atom { + return nil +} diff --git a/format/rtspv2/client.go b/format/rtspv2/client.go index 504a23f..0233172 100644 --- a/format/rtspv2/client.go +++ b/format/rtspv2/client.go @@ -871,6 +871,8 @@ func (client *RTSPClient) Println(v ...interface{}) { log.Println(v) } } + +//binSize func binSize(val int) []byte { buf := make([]byte, 4) binary.BigEndian.PutUint32(buf, uint32(val)) diff --git a/format/ts/tsio/tsio.go b/format/ts/tsio/tsio.go index bd07f90..ba045f6 100644 --- a/format/ts/tsio/tsio.go +++ b/format/ts/tsio/tsio.go @@ -2,9 +2,10 @@ package tsio import ( "fmt" - "github.com/deepch/vdk/utils/bits/pio" "io" "time" + + "github.com/deepch/vdk/utils/bits/pio" ) const ( @@ -513,6 +514,7 @@ func NewTSWriter(pid uint16) *TSWriter { } return w } + //TSHeader func type TSHeader struct { PID uint @@ -524,6 +526,7 @@ type TSHeader struct { RandomAccessIndicator bool HeaderLength uint } + //WriteTSHeader func func WriteTSHeader(w io.Writer, element TSHeader, dataLength int) (written int, err error) { var flags, extFlags uint @@ -614,15 +617,6 @@ func (self *TSWriter) WritePackets(w io.Writer, datav [][]byte, pcr time.Duratio self.tshdr[3] = byte(self.ContinuityCounter)&0xf | 0x30 self.tshdr[5] = 0 // flags hdrlen := 6 - //pid := uint16((self.tshdr[1]&0x1f))<<8 | uint16(self.tshdr[2]) - //if pid != 256 { - //self.tshdr[3] = 0x01 - - //self.tshdr[3] = 0x47 - //self.tshdr[4] - // log.Println(self.tshdr[:5]) - // log.Println("pid", pid,self.tshdr[3] ) - //} self.ContinuityCounter++ if writepos == 0 { @@ -716,9 +710,10 @@ func WriteUInt64(w io.Writer, val uint64, n int) (err error) { func WriteUInt(w io.Writer, val uint, n int) (err error) { return WriteUInt64(w, uint64(val), n) } + //PCRToUInt func func PCRToUInt(pcr uint64) uint64 { base := pcr / 300 ext := pcr % 300 return base<<15 | 0x3f<<9 | ext -} \ No newline at end of file +}