mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-10-04 16:02:43 +08:00
RTMP server enhancement to support OpenIPC cameras
This commit is contained in:
@@ -140,23 +140,29 @@ func (c *Producer) probe() error {
|
|||||||
// 1. Empty video/audio flag
|
// 1. Empty video/audio flag
|
||||||
// 2. MedaData without stereo key for AAC
|
// 2. MedaData without stereo key for AAC
|
||||||
// 3. Audio header after Video keyframe tag
|
// 3. Audio header after Video keyframe tag
|
||||||
waitType := []byte{TagData}
|
|
||||||
timeout := time.Now().Add(core.ProbeTimeout)
|
|
||||||
|
|
||||||
for len(waitType) != 0 && time.Now().Before(timeout) {
|
// OpenIPC camera sends:
|
||||||
|
// 1. Empty video/audio flag
|
||||||
|
// 2. No MetaData packet
|
||||||
|
// 3. Sends a video packet in more than 3 seconds
|
||||||
|
waitVideo := true
|
||||||
|
waitAudio := true
|
||||||
|
timeout := time.Now().Add(time.Second * 5)
|
||||||
|
|
||||||
|
for (waitVideo || waitAudio) && time.Now().Before(timeout) {
|
||||||
pkt, err := c.readPacket()
|
pkt, err := c.readPacket()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if i := bytes.IndexByte(waitType, pkt.PayloadType); i < 0 {
|
//log.Printf("%d %0.20s", pkt.PayloadType, pkt.Payload)
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
waitType = append(waitType[:i], waitType[i+1:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch pkt.PayloadType {
|
switch pkt.PayloadType {
|
||||||
case TagAudio:
|
case TagAudio:
|
||||||
|
if !waitAudio {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
_ = pkt.Payload[1] // bounds
|
_ = pkt.Payload[1] // bounds
|
||||||
|
|
||||||
codecID := pkt.Payload[0] >> 4 // SoundFormat
|
codecID := pkt.Payload[0] >> 4 // SoundFormat
|
||||||
@@ -179,8 +185,13 @@ func (c *Producer) probe() error {
|
|||||||
Codecs: []*core.Codec{codec},
|
Codecs: []*core.Codec{codec},
|
||||||
}
|
}
|
||||||
c.Medias = append(c.Medias, media)
|
c.Medias = append(c.Medias, media)
|
||||||
|
waitAudio = false
|
||||||
|
|
||||||
case TagVideo:
|
case TagVideo:
|
||||||
|
if !waitVideo {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
var codec *core.Codec
|
var codec *core.Codec
|
||||||
|
|
||||||
if isExHeader(pkt.Payload) {
|
if isExHeader(pkt.Payload) {
|
||||||
@@ -213,19 +224,20 @@ func (c *Producer) probe() error {
|
|||||||
Codecs: []*core.Codec{codec},
|
Codecs: []*core.Codec{codec},
|
||||||
}
|
}
|
||||||
c.Medias = append(c.Medias, media)
|
c.Medias = append(c.Medias, media)
|
||||||
|
waitVideo = false
|
||||||
|
|
||||||
case TagData:
|
case TagData:
|
||||||
if !bytes.Contains(pkt.Payload, []byte("onMetaData")) {
|
if !bytes.Contains(pkt.Payload, []byte("onMetaData")) {
|
||||||
waitType = append(waitType, TagData)
|
continue
|
||||||
}
|
}
|
||||||
// Dahua cameras doesn't send videocodecid
|
// Dahua cameras doesn't send videocodecid
|
||||||
if bytes.Contains(pkt.Payload, []byte("videocodecid")) ||
|
if !bytes.Contains(pkt.Payload, []byte("videocodecid")) &&
|
||||||
bytes.Contains(pkt.Payload, []byte("width")) ||
|
!bytes.Contains(pkt.Payload, []byte("width")) &&
|
||||||
bytes.Contains(pkt.Payload, []byte("framerate")) {
|
!bytes.Contains(pkt.Payload, []byte("framerate")) {
|
||||||
waitType = append(waitType, TagVideo)
|
waitVideo = false
|
||||||
}
|
}
|
||||||
if bytes.Contains(pkt.Payload, []byte("audiocodecid")) {
|
if !bytes.Contains(pkt.Payload, []byte("audiocodecid")) {
|
||||||
waitType = append(waitType, TagAudio)
|
waitAudio = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -117,10 +117,6 @@ func (c *Conn) acceptCommand(b []byte) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.App == "" {
|
|
||||||
return fmt.Errorf("rtmp: read command %x", b)
|
|
||||||
}
|
|
||||||
|
|
||||||
payload := amf.EncodeItems(
|
payload := amf.EncodeItems(
|
||||||
"_result", tID,
|
"_result", tID,
|
||||||
map[string]any{"fmsVer": "FMS/3,0,1,123"},
|
map[string]any{"fmsVer": "FMS/3,0,1,123"},
|
||||||
@@ -129,9 +125,16 @@ func (c *Conn) acceptCommand(b []byte) error {
|
|||||||
return c.writeMessage(3, TypeCommand, 0, payload)
|
return c.writeMessage(3, TypeCommand, 0, payload)
|
||||||
|
|
||||||
case CommandReleaseStream:
|
case CommandReleaseStream:
|
||||||
|
// if app is empty - will use key as app
|
||||||
|
if c.App == "" && len(items) == 4 {
|
||||||
|
c.App, _ = items[3].(string)
|
||||||
|
}
|
||||||
|
|
||||||
payload := amf.EncodeItems("_result", tID, nil)
|
payload := amf.EncodeItems("_result", tID, nil)
|
||||||
return c.writeMessage(3, TypeCommand, 0, payload)
|
return c.writeMessage(3, TypeCommand, 0, payload)
|
||||||
|
|
||||||
|
case CommandFCPublish: // no response
|
||||||
|
|
||||||
case CommandCreateStream:
|
case CommandCreateStream:
|
||||||
payload := amf.EncodeItems("_result", tID, nil, 1)
|
payload := amf.EncodeItems("_result", tID, nil, 1)
|
||||||
return c.writeMessage(3, TypeCommand, 0, payload)
|
return c.writeMessage(3, TypeCommand, 0, payload)
|
||||||
@@ -140,8 +143,6 @@ func (c *Conn) acceptCommand(b []byte) error {
|
|||||||
c.Intent = cmd
|
c.Intent = cmd
|
||||||
c.streamID = 1
|
c.streamID = 1
|
||||||
|
|
||||||
case CommandFCPublish: // no response
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
println("rtmp: unknown command: " + cmd)
|
println("rtmp: unknown command: " + cmd)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user