Skip to content

Commit

Permalink
RTMP server enhancement to support OpenIPC cameras
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexxIT committed Dec 29, 2024
1 parent 0d6b8fc commit a3f084d
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 21 deletions.
42 changes: 27 additions & 15 deletions pkg/flv/producer.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,23 +140,29 @@ func (c *Producer) probe() error {
// 1. Empty video/audio flag
// 2. MedaData without stereo key for AAC
// 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()
if err != nil {
return err
}

if i := bytes.IndexByte(waitType, pkt.PayloadType); i < 0 {
continue
} else {
waitType = append(waitType[:i], waitType[i+1:]...)
}
//log.Printf("%d %0.20s", pkt.PayloadType, pkt.Payload)

switch pkt.PayloadType {
case TagAudio:
if !waitAudio {
continue
}

_ = pkt.Payload[1] // bounds

codecID := pkt.Payload[0] >> 4 // SoundFormat
Expand All @@ -179,8 +185,13 @@ func (c *Producer) probe() error {
Codecs: []*core.Codec{codec},
}
c.Medias = append(c.Medias, media)
waitAudio = false

case TagVideo:
if !waitVideo {
continue
}

var codec *core.Codec

if isExHeader(pkt.Payload) {
Expand Down Expand Up @@ -213,19 +224,20 @@ func (c *Producer) probe() error {
Codecs: []*core.Codec{codec},
}
c.Medias = append(c.Medias, media)
waitVideo = false

case TagData:
if !bytes.Contains(pkt.Payload, []byte("onMetaData")) {
waitType = append(waitType, TagData)
continue
}
// Dahua cameras doesn't send videocodecid
if bytes.Contains(pkt.Payload, []byte("videocodecid")) ||
bytes.Contains(pkt.Payload, []byte("width")) ||
bytes.Contains(pkt.Payload, []byte("framerate")) {
waitType = append(waitType, TagVideo)
if !bytes.Contains(pkt.Payload, []byte("videocodecid")) &&
!bytes.Contains(pkt.Payload, []byte("width")) &&
!bytes.Contains(pkt.Payload, []byte("framerate")) {
waitVideo = false
}
if bytes.Contains(pkt.Payload, []byte("audiocodecid")) {
waitType = append(waitType, TagAudio)
if !bytes.Contains(pkt.Payload, []byte("audiocodecid")) {
waitAudio = false
}
}
}
Expand Down
13 changes: 7 additions & 6 deletions pkg/rtmp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
"_result", tID,
map[string]any{"fmsVer": "FMS/3,0,1,123"},
Expand All @@ -129,9 +125,16 @@ func (c *Conn) acceptCommand(b []byte) error {
return c.writeMessage(3, TypeCommand, 0, payload)

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)
return c.writeMessage(3, TypeCommand, 0, payload)

case CommandFCPublish: // no response

case CommandCreateStream:
payload := amf.EncodeItems("_result", tID, nil, 1)
return c.writeMessage(3, TypeCommand, 0, payload)
Expand All @@ -140,8 +143,6 @@ func (c *Conn) acceptCommand(b []byte) error {
c.Intent = cmd
c.streamID = 1

case CommandFCPublish: // no response

default:
println("rtmp: unknown command: " + cmd)
}
Expand Down

0 comments on commit a3f084d

Please sign in to comment.