Merge pull request #2 from aginetwork7/feature/playback
Skip pyload type not in SDP Add PAUSE API
This commit is contained in:
commit
c0fd928d5e
@ -46,6 +46,7 @@ const (
|
|||||||
DESCRIBE = "DESCRIBE"
|
DESCRIBE = "DESCRIBE"
|
||||||
OPTIONS = "OPTIONS"
|
OPTIONS = "OPTIONS"
|
||||||
PLAY = "PLAY"
|
PLAY = "PLAY"
|
||||||
|
PAUSE = "PAUSE"
|
||||||
SETUP = "SETUP"
|
SETUP = "SETUP"
|
||||||
TEARDOWN = "TEARDOWN"
|
TEARDOWN = "TEARDOWN"
|
||||||
)
|
)
|
||||||
@ -96,6 +97,7 @@ type RTSPClient struct {
|
|||||||
sequenceNumber int
|
sequenceNumber int
|
||||||
end int
|
end int
|
||||||
offset int
|
offset int
|
||||||
|
status string
|
||||||
}
|
}
|
||||||
|
|
||||||
type RTSPClientOptions struct {
|
type RTSPClientOptions struct {
|
||||||
@ -271,7 +273,7 @@ func (client *RTSPClient) startStream() {
|
|||||||
client.Println("RTSP Client RTP SetDeadline", err)
|
client.Println("RTSP Client RTP SetDeadline", err)
|
||||||
return
|
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)
|
err := client.request(OPTIONS, map[string]string{"Require": "implicit-play"}, client.control, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
client.Println("RTSP Client RTP keep-alive", err)
|
client.Println("RTSP Client RTP keep-alive", err)
|
||||||
@ -279,6 +281,10 @@ func (client *RTSPClient) startStream() {
|
|||||||
}
|
}
|
||||||
timer = time.Now()
|
timer = time.Now()
|
||||||
}
|
}
|
||||||
|
if client.status == PAUSE {
|
||||||
|
// client.Println("RTSP Client PAUSE")
|
||||||
|
continue
|
||||||
|
}
|
||||||
if !fixed {
|
if !fixed {
|
||||||
nb, err := io.ReadFull(client.connRW, header)
|
nb, err := io.ReadFull(client.connRW, header)
|
||||||
if err != nil || nb != 4 {
|
if err != nil || nb != 4 {
|
||||||
@ -335,7 +341,7 @@ func (client *RTSPClient) startStream() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
responseTmp = append(responseTmp, oneb...)
|
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:") {
|
if strings.Contains(string(responseTmp), "Content-Length:") {
|
||||||
si, err := strconv.Atoi(stringInBetween(string(responseTmp), "Content-Length: ", "\r\n"))
|
si, err := strconv.Atoi(stringInBetween(string(responseTmp), "Content-Length: ", "\r\n"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -371,15 +377,13 @@ func (client *RTSPClient) request(method string, customHeaders map[string]string
|
|||||||
if client.clientDigest {
|
if client.clientDigest {
|
||||||
builder.WriteString(fmt.Sprintf("Authorization: %s\r\n", client.createDigest(method, uri)))
|
builder.WriteString(fmt.Sprintf("Authorization: %s\r\n", client.createDigest(method, uri)))
|
||||||
}
|
}
|
||||||
if customHeaders != nil {
|
for k, v := range customHeaders {
|
||||||
for k, v := range customHeaders {
|
builder.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
|
||||||
builder.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for k, v := range client.headers {
|
for k, v := range client.headers {
|
||||||
builder.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
|
builder.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
|
||||||
}
|
}
|
||||||
builder.WriteString(fmt.Sprintf("\r\n"))
|
builder.WriteString("\r\n")
|
||||||
client.Println(builder.String())
|
client.Println(builder.String())
|
||||||
s := builder.String()
|
s := builder.String()
|
||||||
_, err = client.connRW.WriteString(s)
|
_, err = client.connRW.WriteString(s)
|
||||||
@ -505,6 +509,31 @@ func (client *RTSPClient) request(method string, customHeaders map[string]string
|
|||||||
return
|
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() {
|
func (client *RTSPClient) Close() {
|
||||||
if client.conn != nil {
|
if client.conn != nil {
|
||||||
client.conn.SetDeadline(time.Now().Add(time.Second))
|
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 {
|
if client.videoCodec != av.H264 && client.videoCodec != av.H265 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if bytes.Compare(val, client.sps) == 0 {
|
if bytes.Equal(val, client.sps) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
client.sps = val
|
client.sps = val
|
||||||
@ -601,7 +630,7 @@ func (client *RTSPClient) CodecUpdatePPS(val []byte) {
|
|||||||
if client.videoCodec != av.H264 && client.videoCodec != av.H265 {
|
if client.videoCodec != av.H264 && client.videoCodec != av.H265 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if bytes.Compare(val, client.pps) == 0 {
|
if bytes.Equal(val, client.pps) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
client.pps = val
|
client.pps = val
|
||||||
@ -641,7 +670,7 @@ func (client *RTSPClient) CodecUpdateVPS(val []byte) {
|
|||||||
if client.videoCodec != av.H265 {
|
if client.videoCodec != av.H265 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if bytes.Compare(val, client.vps) == 0 {
|
if bytes.Equal(val, client.vps) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
client.vps = val
|
client.vps = val
|
||||||
|
@ -2,12 +2,14 @@ package rtspv2
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/deepch/vdk/av"
|
"github.com/deepch/vdk/av"
|
||||||
"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"
|
||||||
"math"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -15,22 +17,40 @@ const (
|
|||||||
TimeDelay = 1
|
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) {
|
func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) {
|
||||||
content := *payloadRAW
|
content := *payloadRAW
|
||||||
firstByte := content[4]
|
firstByte := content[4]
|
||||||
padding := (firstByte>>5)&1 == 1
|
padding := (firstByte>>5)&1 == 1
|
||||||
extension := (firstByte>>4)&1 == 1
|
extension := (firstByte>>4)&1 == 1
|
||||||
CSRCCnt := int(firstByte & 0x0f)
|
CSRCCnt := int(firstByte & 0x0f)
|
||||||
client.sequenceNumber = int(binary.BigEndian.Uint16(content[6:8]))
|
payloadType := int(content[5] & 0x7f)
|
||||||
client.timestamp = int64(binary.BigEndian.Uint32(content[8:16]))
|
sequenceNumber := int(binary.BigEndian.Uint16(content[6:8]))
|
||||||
|
timestamp := int64(binary.BigEndian.Uint32(content[8:12]))
|
||||||
if isRTCPPacket(content) {
|
if isRTCPPacket(content) {
|
||||||
client.Println("skipping RTCP packet")
|
client.Println("skipping RTCP packet")
|
||||||
return nil, false
|
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)
|
client.end = len(content)
|
||||||
if client.end-client.offset >= 4*CSRCCnt {
|
if client.end-client.offset >= 4*CSRCCnt {
|
||||||
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])
|
nalRaw, _ := h264parser.SplitNALUs(content[client.offset:client.end])
|
||||||
if len(nalRaw) == 0 || len(nalRaw[0]) == 0 {
|
if len(nalRaw) == 0 || len(nalRaw[0]) == 0 {
|
||||||
|
client.Println("nal Raw 0", nalRaw)
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
var retmap []*av.Packet
|
var retmap []*av.Packet
|
||||||
|
Loading…
Reference in New Issue
Block a user