diff --git a/format/rtspv2/client.go b/format/rtspv2/client.go index c020122..87246aa 100644 --- a/format/rtspv2/client.go +++ b/format/rtspv2/client.go @@ -46,6 +46,7 @@ const ( DESCRIBE = "DESCRIBE" OPTIONS = "OPTIONS" PLAY = "PLAY" + PAUSE = "PAUSE" SETUP = "SETUP" TEARDOWN = "TEARDOWN" ) @@ -96,6 +97,7 @@ type RTSPClient struct { sequenceNumber int end int offset int + status string } type RTSPClientOptions struct { @@ -271,7 +273,7 @@ func (client *RTSPClient) startStream() { client.Println("RTSP Client RTP SetDeadline", err) return } - if int(time.Now().Sub(timer).Seconds()) > 25 { + if int(time.Since(timer).Seconds()) > 25 { err := client.request(OPTIONS, map[string]string{"Require": "implicit-play"}, client.control, false, true) if err != nil { client.Println("RTSP Client RTP keep-alive", err) @@ -279,6 +281,10 @@ func (client *RTSPClient) startStream() { } timer = time.Now() } + if client.status == PAUSE { + // client.Println("RTSP Client PAUSE") + continue + } if !fixed { nb, err := io.ReadFull(client.connRW, header) if err != nil || nb != 4 { @@ -335,7 +341,7 @@ func (client *RTSPClient) startStream() { return } responseTmp = append(responseTmp, oneb...) - if (len(responseTmp) > 4 && bytes.Compare(responseTmp[len(responseTmp)-4:], []byte("\r\n\r\n")) == 0) || len(responseTmp) > 768 { + if (len(responseTmp) > 4 && bytes.Equal(responseTmp[len(responseTmp)-4:], []byte("\r\n\r\n"))) || len(responseTmp) > 768 { if strings.Contains(string(responseTmp), "Content-Length:") { si, err := strconv.Atoi(stringInBetween(string(responseTmp), "Content-Length: ", "\r\n")) if err != nil { @@ -371,15 +377,13 @@ func (client *RTSPClient) request(method string, customHeaders map[string]string if client.clientDigest { builder.WriteString(fmt.Sprintf("Authorization: %s\r\n", client.createDigest(method, uri))) } - if customHeaders != nil { - for k, v := range customHeaders { - builder.WriteString(fmt.Sprintf("%s: %s\r\n", k, v)) - } + for k, v := range customHeaders { + builder.WriteString(fmt.Sprintf("%s: %s\r\n", k, v)) } for k, v := range client.headers { builder.WriteString(fmt.Sprintf("%s: %s\r\n", k, v)) } - builder.WriteString(fmt.Sprintf("\r\n")) + builder.WriteString("\r\n") client.Println(builder.String()) s := builder.String() _, err = client.connRW.WriteString(s) @@ -505,6 +509,31 @@ func (client *RTSPClient) request(method string, customHeaders map[string]string return } +func (client *RTSPClient) Pause() error { + if err := client.request(PAUSE, nil, client.pURL.String(), false, true); err != nil { + return err + } + client.status = PAUSE + return nil +} + +func (client *RTSPClient) Play(customHeaders map[string]string) error { + if err := client.request(PLAY, customHeaders, client.pURL.String(), false, true); err != nil { + return err + } + client.status = PLAY + return nil +} + +func (client *RTSPClient) Seek(customHeaders map[string]string, target int64) error { + customHeaders["Range"] = fmt.Sprintf("npt=%d.00-", target) + if err := client.request(PLAY, customHeaders, client.pURL.String(), false, true); err != nil { + return err + } + client.status = PLAY + return nil +} + func (client *RTSPClient) Close() { if client.conn != nil { client.conn.SetDeadline(time.Now().Add(time.Second)) @@ -561,7 +590,7 @@ func (client *RTSPClient) CodecUpdateSPS(val []byte) { if client.videoCodec != av.H264 && client.videoCodec != av.H265 { return } - if bytes.Compare(val, client.sps) == 0 { + if bytes.Equal(val, client.sps) { return } client.sps = val @@ -601,7 +630,7 @@ func (client *RTSPClient) CodecUpdatePPS(val []byte) { if client.videoCodec != av.H264 && client.videoCodec != av.H265 { return } - if bytes.Compare(val, client.pps) == 0 { + if bytes.Equal(val, client.pps) { return } client.pps = val @@ -641,7 +670,7 @@ func (client *RTSPClient) CodecUpdateVPS(val []byte) { if client.videoCodec != av.H265 { return } - if bytes.Compare(val, client.vps) == 0 { + if bytes.Equal(val, client.vps) { return } client.vps = val diff --git a/format/rtspv2/demuxer.go b/format/rtspv2/demuxer.go index 396ca41..ac61184 100644 --- a/format/rtspv2/demuxer.go +++ b/format/rtspv2/demuxer.go @@ -2,12 +2,14 @@ package rtspv2 import ( "encoding/binary" + "fmt" + "math" + "time" + "github.com/deepch/vdk/av" "github.com/deepch/vdk/codec/aacparser" "github.com/deepch/vdk/codec/h264parser" "github.com/deepch/vdk/codec/h265parser" - "math" - "time" ) const ( @@ -15,22 +17,40 @@ const ( TimeDelay = 1 ) +func (client *RTSPClient) containsPayloadType(pt int) bool { + var exist bool + for _, sdp := range client.mediaSDP { + if sdp.Rtpmap == pt { + exist = true + } + } + return exist +} + func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) { content := *payloadRAW firstByte := content[4] padding := (firstByte>>5)&1 == 1 extension := (firstByte>>4)&1 == 1 CSRCCnt := int(firstByte & 0x0f) - client.sequenceNumber = int(binary.BigEndian.Uint16(content[6:8])) - client.timestamp = int64(binary.BigEndian.Uint32(content[8:16])) - + payloadType := int(content[5] & 0x7f) + sequenceNumber := int(binary.BigEndian.Uint16(content[6:8])) + timestamp := int64(binary.BigEndian.Uint32(content[8:12])) if isRTCPPacket(content) { client.Println("skipping RTCP packet") return nil, false } - client.offset = RTPHeaderSize + if !client.containsPayloadType(payloadType) { + client.Println(fmt.Sprintf("skipping RTP packet, paytload type: %v", payloadType)) + return nil, false + } + // client.Println(fmt.Sprintf("padding: %v, extension: %v, csrccnt: %d, sequence number: %d.payload type: %d, timestamp: %d", + // padding, extension, CSRCCnt, sequenceNumber, payloadType, timestamp)) + client.offset = RTPHeaderSize + client.sequenceNumber = sequenceNumber + client.timestamp = timestamp client.end = len(content) if client.end-client.offset >= 4*CSRCCnt { client.offset += 4 * CSRCCnt @@ -88,6 +108,7 @@ func (client *RTSPClient) handleVideo(content []byte) ([]*av.Packet, bool) { } nalRaw, _ := h264parser.SplitNALUs(content[client.offset:client.end]) if len(nalRaw) == 0 || len(nalRaw[0]) == 0 { + client.Println("nal Raw 0", nalRaw) return nil, false } var retmap []*av.Packet