Added a blank payloader for MJPEG RTSP
This commit is contained in:
+8
-3
@@ -11,6 +11,7 @@ import (
|
|||||||
"net/textproto"
|
"net/textproto"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
@@ -73,7 +74,7 @@ func (c *Client) startJPEG() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
packet := &rtp.Packet{Payload: buf}
|
packet := &rtp.Packet{Header: rtp.Header{Timestamp: now()}, Payload: buf}
|
||||||
_ = c.track.WriteRTP(packet)
|
_ = c.track.WriteRTP(packet)
|
||||||
|
|
||||||
req := c.res.Request
|
req := c.res.Request
|
||||||
@@ -93,7 +94,7 @@ func (c *Client) startJPEG() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
packet = &rtp.Packet{Payload: buf}
|
packet = &rtp.Packet{Header: rtp.Header{Timestamp: now()}, Payload: buf}
|
||||||
_ = c.track.WriteRTP(packet)
|
_ = c.track.WriteRTP(packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ func (c *Client) startMJPEG(boundary string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
packet := &rtp.Packet{Payload: buf}
|
packet := &rtp.Packet{Header: rtp.Header{Timestamp: now()}, Payload: buf}
|
||||||
_ = c.track.WriteRTP(packet)
|
_ = c.track.WriteRTP(packet)
|
||||||
|
|
||||||
if _, err = r.Discard(2); err != nil {
|
if _, err = r.Discard(2); err != nil {
|
||||||
@@ -145,3 +146,7 @@ func (c *Client) startMJPEG(boundary string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func now() uint32 {
|
||||||
|
return uint32(time.Now().UnixMilli() * 90)
|
||||||
|
}
|
||||||
|
|||||||
+139
-5
@@ -10,11 +10,7 @@ func RTPDepay(track *streamer.Track) streamer.WrapperFunc {
|
|||||||
|
|
||||||
return func(push streamer.WriterFunc) streamer.WriterFunc {
|
return func(push streamer.WriterFunc) streamer.WriterFunc {
|
||||||
return func(packet *rtp.Packet) error {
|
return func(packet *rtp.Packet) error {
|
||||||
//fmt.Printf(
|
//log.Printf("[RTP] codec: %s, size: %6d, ts: %10d, pt: %2d, ssrc: %d, seq: %d, mark: %v", track.Codec.Name, len(packet.Payload), packet.Timestamp, packet.PayloadType, packet.SSRC, packet.SequenceNumber, packet.Marker)
|
||||||
// "[RTP] codec: %s, size: %6d, ts: %10d, pt: %2d, ssrc: %d, seq: %d, mark: %v\n",
|
|
||||||
// track.Codec.Name, len(packet.Payload), packet.Timestamp,
|
|
||||||
// packet.PayloadType, packet.SSRC, packet.SequenceNumber, packet.Marker,
|
|
||||||
//)
|
|
||||||
|
|
||||||
// https://www.rfc-editor.org/rfc/rfc2435#section-3.1
|
// https://www.rfc-editor.org/rfc/rfc2435#section-3.1
|
||||||
b := packet.Payload
|
b := packet.Payload
|
||||||
@@ -76,3 +72,141 @@ func RTPDepay(track *streamer.Track) streamer.WrapperFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RTPPay() streamer.WrapperFunc {
|
||||||
|
return func(push streamer.WriterFunc) streamer.WriterFunc {
|
||||||
|
return func(packet *rtp.Packet) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//func RTPPay() streamer.WrapperFunc {
|
||||||
|
// const packetSize = 1436
|
||||||
|
//
|
||||||
|
// sequencer := rtp.NewRandomSequencer()
|
||||||
|
//
|
||||||
|
// return func(push streamer.WriterFunc) streamer.WriterFunc {
|
||||||
|
// return func(packet *rtp.Packet) error {
|
||||||
|
// // reincode image to more common form
|
||||||
|
// img, err := jpeg.Decode(bytes.NewReader(packet.Payload))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// wh := img.Bounds().Size()
|
||||||
|
// w := wh.X
|
||||||
|
// h := wh.Y
|
||||||
|
//
|
||||||
|
// if w > 2040 {
|
||||||
|
// w = 2040
|
||||||
|
// } else if w&3 > 0 {
|
||||||
|
// w &= 3
|
||||||
|
// }
|
||||||
|
// if h > 2040 {
|
||||||
|
// h = 2040
|
||||||
|
// } else if h&3 > 0 {
|
||||||
|
// h &= 3
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if w != wh.X || h != wh.Y {
|
||||||
|
// x0 := (wh.X - w) / 2
|
||||||
|
// y0 := (wh.Y - h) / 2
|
||||||
|
// rect := image.Rect(x0, y0, x0+w, y0+h)
|
||||||
|
// img = img.(*image.YCbCr).SubImage(rect)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// buf := bytes.NewBuffer(nil)
|
||||||
|
// if err = jpeg.Encode(buf, img, nil); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// h1 := make([]byte, 8)
|
||||||
|
// h1[4] = 1 // Type
|
||||||
|
// h1[5] = 255 // Q
|
||||||
|
//
|
||||||
|
// // MBZ=0, Precision=0, Length=128
|
||||||
|
// h2 := make([]byte, 4, 132)
|
||||||
|
// h2[3] = 128
|
||||||
|
//
|
||||||
|
// var jpgData []byte
|
||||||
|
//
|
||||||
|
// p := buf.Bytes()
|
||||||
|
//
|
||||||
|
// for jpgData == nil {
|
||||||
|
// // 2 bytes h1
|
||||||
|
// if p[0] != 0xFF {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// size := binary.BigEndian.Uint16(p[2:]) + 2
|
||||||
|
//
|
||||||
|
// // 2 bytes payload size (include 2 bytes)
|
||||||
|
// switch p[1] {
|
||||||
|
// case 0xD8: // 0. Start Of Image (size=0)
|
||||||
|
// p = p[2:]
|
||||||
|
// continue
|
||||||
|
// case 0xDB: // 1. Define Quantization Table (size=130)
|
||||||
|
// for i := uint16(4 + 1); i < size; i += 1 + 64 {
|
||||||
|
// h2 = append(h2, p[i:i+64]...)
|
||||||
|
// }
|
||||||
|
// case 0xC0: // 2. Start Of Frame (size=15)
|
||||||
|
// if p[4] != 8 {
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// h := binary.BigEndian.Uint16(p[5:])
|
||||||
|
// w := binary.BigEndian.Uint16(p[7:])
|
||||||
|
// h1[6] = uint8(w >> 3)
|
||||||
|
// h1[7] = uint8(h >> 3)
|
||||||
|
// case 0xC4: // 3. Define Huffman Table (size=416)
|
||||||
|
// case 0xDA: // 4. Start Of Scan (size=10)
|
||||||
|
// jpgData = p[size:]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// p = p[size:]
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// offset := 0
|
||||||
|
// p = make([]byte, 0)
|
||||||
|
//
|
||||||
|
// for jpgData != nil {
|
||||||
|
// p = p[:0]
|
||||||
|
//
|
||||||
|
// if offset > 0 {
|
||||||
|
// h1[1] = byte(offset >> 16)
|
||||||
|
// h1[2] = byte(offset >> 8)
|
||||||
|
// h1[3] = byte(offset)
|
||||||
|
// p = append(p, h1...)
|
||||||
|
// } else {
|
||||||
|
// p = append(p, h1...)
|
||||||
|
// p = append(p, h2...)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// dataLen := packetSize - len(p)
|
||||||
|
// if dataLen < len(jpgData) {
|
||||||
|
// p = append(p, jpgData[:dataLen]...)
|
||||||
|
// jpgData = jpgData[dataLen:]
|
||||||
|
// offset += dataLen
|
||||||
|
// } else {
|
||||||
|
// p = append(p, jpgData...)
|
||||||
|
// jpgData = nil
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// clone := rtp.Packet{
|
||||||
|
// Header: rtp.Header{
|
||||||
|
// Version: 2,
|
||||||
|
// Marker: jpgData == nil,
|
||||||
|
// SequenceNumber: sequencer.NextSequenceNumber(),
|
||||||
|
// Timestamp: packet.Timestamp,
|
||||||
|
// },
|
||||||
|
// Payload: p,
|
||||||
|
// }
|
||||||
|
// if err := push(&clone); err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/aac"
|
"github.com/AlexxIT/go2rtc/pkg/aac"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||||
|
"github.com/AlexxIT/go2rtc/pkg/mjpeg"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/tcp"
|
"github.com/AlexxIT/go2rtc/pkg/tcp"
|
||||||
"github.com/pion/rtcp"
|
"github.com/pion/rtcp"
|
||||||
@@ -776,6 +777,8 @@ func (c *Conn) bindTrack(
|
|||||||
|
|
||||||
size := packet.MarshalSize()
|
size := packet.MarshalSize()
|
||||||
|
|
||||||
|
//log.Printf("[RTP] codec: %s, size: %6d, ts: %10d, pt: %2d, ssrc: %d, seq: %d, mark: %v", track.Codec.Name, len(packet.Payload), packet.Timestamp, packet.PayloadType, packet.SSRC, packet.SequenceNumber, packet.Marker)
|
||||||
|
|
||||||
data := make([]byte, 4+size)
|
data := make([]byte, 4+size)
|
||||||
data[0] = '$'
|
data[0] = '$'
|
||||||
data[1] = channel
|
data[1] = channel
|
||||||
@@ -802,6 +805,9 @@ func (c *Conn) bindTrack(
|
|||||||
case streamer.CodecAAC:
|
case streamer.CodecAAC:
|
||||||
wrapper := aac.RTPPay(1500)
|
wrapper := aac.RTPPay(1500)
|
||||||
push = wrapper(push)
|
push = wrapper(push)
|
||||||
|
case streamer.CodecJPEG:
|
||||||
|
wrapper := mjpeg.RTPPay()
|
||||||
|
push = wrapper(push)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user