BIG core logic rewrite
This commit is contained in:
+86
-97
@@ -3,176 +3,165 @@ package mp4
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/AlexxIT/go2rtc/pkg/aac"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/pion/rtp"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Consumer struct {
|
||||
streamer.Element
|
||||
core.Listener
|
||||
|
||||
Medias []*streamer.Media
|
||||
Medias []*core.Media
|
||||
UserAgent string
|
||||
RemoteAddr string
|
||||
|
||||
muxer *Muxer
|
||||
codecs []*streamer.Codec
|
||||
wait byte
|
||||
senders []*core.Sender
|
||||
|
||||
send uint32
|
||||
muxer *Muxer
|
||||
wait byte
|
||||
|
||||
send int
|
||||
}
|
||||
|
||||
// ParseQuery - like usual parse, but with mp4 param handler
|
||||
func ParseQuery(query map[string][]string) []*streamer.Media {
|
||||
if query["mp4"] != nil {
|
||||
cons := Consumer{}
|
||||
return cons.GetMedias()
|
||||
}
|
||||
|
||||
return streamer.ParseQuery(query)
|
||||
}
|
||||
|
||||
const (
|
||||
waitNone byte = iota
|
||||
waitKeyframe
|
||||
waitInit
|
||||
)
|
||||
|
||||
func (c *Consumer) GetMedias() []*streamer.Media {
|
||||
if c.Medias != nil {
|
||||
return c.Medias
|
||||
}
|
||||
|
||||
// default medias
|
||||
return []*streamer.Media{
|
||||
{
|
||||
Kind: streamer.KindVideo,
|
||||
Direction: streamer.DirectionRecvonly,
|
||||
Codecs: []*streamer.Codec{
|
||||
{Name: streamer.CodecH264},
|
||||
{Name: streamer.CodecH265},
|
||||
func (c *Consumer) GetMedias() []*core.Media {
|
||||
if c.Medias == nil {
|
||||
// default local medias
|
||||
c.Medias = []*core.Media{
|
||||
{
|
||||
Kind: core.KindVideo,
|
||||
Direction: core.DirectionSendonly,
|
||||
Codecs: []*core.Codec{
|
||||
{Name: core.CodecH264},
|
||||
{Name: core.CodecH265},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Kind: streamer.KindAudio,
|
||||
Direction: streamer.DirectionRecvonly,
|
||||
Codecs: []*streamer.Codec{
|
||||
{Name: streamer.CodecAAC},
|
||||
{
|
||||
Kind: core.KindAudio,
|
||||
Direction: core.DirectionSendonly,
|
||||
Codecs: []*core.Codec{
|
||||
{Name: core.CodecAAC},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return c.Medias
|
||||
}
|
||||
|
||||
func (c *Consumer) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.Track {
|
||||
trackID := byte(len(c.codecs))
|
||||
c.codecs = append(c.codecs, track.Codec)
|
||||
func (c *Consumer) AddTrack(media *core.Media, _ *core.Codec, track *core.Receiver) error {
|
||||
trackID := byte(len(c.senders))
|
||||
|
||||
codec := track.Codec
|
||||
switch codec.Name {
|
||||
case streamer.CodecH264:
|
||||
handler := core.NewSender(media, track.Codec)
|
||||
|
||||
switch track.Codec.Name {
|
||||
case core.CodecH264:
|
||||
c.wait = waitInit
|
||||
|
||||
push := func(packet *rtp.Packet) error {
|
||||
handler.Handler = func(packet *rtp.Packet) {
|
||||
if packet.Version != h264.RTPPacketVersionAVC {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
if c.wait != waitNone {
|
||||
if c.wait == waitInit || !h264.IsKeyframe(packet.Payload) {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
c.wait = waitNone
|
||||
}
|
||||
|
||||
buf := c.muxer.Marshal(trackID, packet)
|
||||
atomic.AddUint32(&c.send, uint32(len(buf)))
|
||||
c.Fire(buf)
|
||||
|
||||
return nil
|
||||
c.send += len(buf)
|
||||
}
|
||||
|
||||
var wrapper streamer.WrapperFunc
|
||||
if codec.IsRTP() {
|
||||
wrapper = h264.RTPDepay(track)
|
||||
if track.Codec.IsRTP() {
|
||||
handler.Handler = h264.RTPDepay(track.Codec, handler.Handler)
|
||||
} else {
|
||||
wrapper = h264.RepairAVC(track)
|
||||
handler.Handler = h264.RepairAVC(track.Codec, handler.Handler)
|
||||
}
|
||||
push = wrapper(push)
|
||||
|
||||
return track.Bind(push)
|
||||
|
||||
case streamer.CodecH265:
|
||||
case core.CodecH265:
|
||||
c.wait = waitInit
|
||||
|
||||
push := func(packet *rtp.Packet) error {
|
||||
handler.Handler = func(packet *rtp.Packet) {
|
||||
if packet.Version != h264.RTPPacketVersionAVC {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
if c.wait != waitNone {
|
||||
if c.wait == waitInit || !h265.IsKeyframe(packet.Payload) {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
c.wait = waitNone
|
||||
}
|
||||
|
||||
buf := c.muxer.Marshal(trackID, packet)
|
||||
atomic.AddUint32(&c.send, uint32(len(buf)))
|
||||
c.Fire(buf)
|
||||
|
||||
return nil
|
||||
c.send += len(buf)
|
||||
}
|
||||
|
||||
if codec.IsRTP() {
|
||||
wrapper := h265.RTPDepay(track)
|
||||
push = wrapper(push)
|
||||
if track.Codec.IsRTP() {
|
||||
handler.Handler = h265.RTPDepay(track.Codec, handler.Handler)
|
||||
}
|
||||
|
||||
return track.Bind(push)
|
||||
|
||||
case streamer.CodecAAC:
|
||||
push := func(packet *rtp.Packet) error {
|
||||
case core.CodecAAC:
|
||||
handler.Handler = func(packet *rtp.Packet) {
|
||||
if c.wait != waitNone {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
buf := c.muxer.Marshal(trackID, packet)
|
||||
atomic.AddUint32(&c.send, uint32(len(buf)))
|
||||
c.Fire(buf)
|
||||
|
||||
return nil
|
||||
c.send += len(buf)
|
||||
}
|
||||
|
||||
if codec.IsRTP() {
|
||||
wrapper := aac.RTPDepay(track)
|
||||
push = wrapper(push)
|
||||
if track.Codec.IsRTP() {
|
||||
handler.Handler = aac.RTPDepay(handler.Handler)
|
||||
}
|
||||
|
||||
return track.Bind(push)
|
||||
|
||||
case streamer.CodecOpus, streamer.CodecMP3, streamer.CodecPCMU, streamer.CodecPCMA:
|
||||
push := func(packet *rtp.Packet) error {
|
||||
case core.CodecOpus, core.CodecMP3, core.CodecPCMU, core.CodecPCMA:
|
||||
handler.Handler = func(packet *rtp.Packet) {
|
||||
if c.wait != waitNone {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
buf := c.muxer.Marshal(trackID, packet)
|
||||
atomic.AddUint32(&c.send, uint32(len(buf)))
|
||||
c.Fire(buf)
|
||||
|
||||
return nil
|
||||
c.send += len(buf)
|
||||
}
|
||||
|
||||
return track.Bind(push)
|
||||
default:
|
||||
panic("unsupported codec")
|
||||
}
|
||||
|
||||
panic("unsupported codec")
|
||||
handler.HandleRTP(track)
|
||||
c.senders = append(c.senders, handler)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Consumer) Stop() error {
|
||||
for _, sender := range c.senders {
|
||||
sender.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Consumer) Codecs() []*core.Codec {
|
||||
codecs := make([]*core.Codec, len(c.senders))
|
||||
for i, sender := range c.senders {
|
||||
codecs[i] = sender.Codec
|
||||
}
|
||||
return codecs
|
||||
}
|
||||
|
||||
func (c *Consumer) MimeCodecs() string {
|
||||
return c.muxer.MimeCodecs(c.codecs)
|
||||
return c.muxer.MimeCodecs(c.Codecs())
|
||||
}
|
||||
|
||||
func (c *Consumer) MimeType() string {
|
||||
@@ -181,7 +170,7 @@ func (c *Consumer) MimeType() string {
|
||||
|
||||
func (c *Consumer) Init() ([]byte, error) {
|
||||
c.muxer = &Muxer{}
|
||||
return c.muxer.GetInit(c.codecs)
|
||||
return c.muxer.GetInit(c.Codecs())
|
||||
}
|
||||
|
||||
func (c *Consumer) Start() {
|
||||
@@ -190,14 +179,14 @@ func (c *Consumer) Start() {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
func (c *Consumer) MarshalJSON() ([]byte, error) {
|
||||
info := &streamer.Info{
|
||||
Type: "MP4 client",
|
||||
info := &core.Info{
|
||||
Type: "MP4 passive consumer",
|
||||
RemoteAddr: c.RemoteAddr,
|
||||
UserAgent: c.UserAgent,
|
||||
Send: atomic.LoadUint32(&c.send),
|
||||
Medias: c.Medias,
|
||||
Senders: c.senders,
|
||||
Send: c.send,
|
||||
}
|
||||
return json.Marshal(info)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package mp4
|
||||
|
||||
import "github.com/AlexxIT/go2rtc/pkg/core"
|
||||
|
||||
// ParseQuery - like usual parse, but with mp4 param handler
|
||||
func ParseQuery(query map[string][]string) []*core.Media {
|
||||
if query["mp4"] != nil {
|
||||
cons := Consumer{}
|
||||
return cons.GetMedias()
|
||||
}
|
||||
|
||||
return core.ParseQuery(query)
|
||||
}
|
||||
|
||||
const (
|
||||
waitNone byte = iota
|
||||
waitKeyframe
|
||||
waitInit
|
||||
)
|
||||
+12
-12
@@ -2,10 +2,10 @@ package mp4
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||
"github.com/AlexxIT/go2rtc/pkg/iso"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/codec/h265parser"
|
||||
"github.com/pion/rtp"
|
||||
@@ -24,7 +24,7 @@ const (
|
||||
MimeOpus = "opus"
|
||||
)
|
||||
|
||||
func (m *Muxer) MimeCodecs(codecs []*streamer.Codec) string {
|
||||
func (m *Muxer) MimeCodecs(codecs []*core.Codec) string {
|
||||
var s string
|
||||
|
||||
for i, codec := range codecs {
|
||||
@@ -33,15 +33,15 @@ func (m *Muxer) MimeCodecs(codecs []*streamer.Codec) string {
|
||||
}
|
||||
|
||||
switch codec.Name {
|
||||
case streamer.CodecH264:
|
||||
case core.CodecH264:
|
||||
s += "avc1." + h264.GetProfileLevelID(codec.FmtpLine)
|
||||
case streamer.CodecH265:
|
||||
case core.CodecH265:
|
||||
// H.265 profile=main level=5.1
|
||||
// hvc1 - supported in Safari, hev1 - doesn't, both supported in Chrome
|
||||
s += MimeH265
|
||||
case streamer.CodecAAC:
|
||||
case core.CodecAAC:
|
||||
s += MimeAAC
|
||||
case streamer.CodecOpus:
|
||||
case core.CodecOpus:
|
||||
s += MimeOpus
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func (m *Muxer) MimeCodecs(codecs []*streamer.Codec) string {
|
||||
return s
|
||||
}
|
||||
|
||||
func (m *Muxer) GetInit(codecs []*streamer.Codec) ([]byte, error) {
|
||||
func (m *Muxer) GetInit(codecs []*core.Codec) ([]byte, error) {
|
||||
mv := iso.NewMovie(1024)
|
||||
mv.WriteFileType()
|
||||
|
||||
@@ -58,7 +58,7 @@ func (m *Muxer) GetInit(codecs []*streamer.Codec) ([]byte, error) {
|
||||
|
||||
for i, codec := range codecs {
|
||||
switch codec.Name {
|
||||
case streamer.CodecH264:
|
||||
case core.CodecH264:
|
||||
sps, pps := h264.GetParameterSet(codec.FmtpLine)
|
||||
if sps == nil {
|
||||
// some dummy SPS and PPS not a problem
|
||||
@@ -77,7 +77,7 @@ func (m *Muxer) GetInit(codecs []*streamer.Codec) ([]byte, error) {
|
||||
codecData.AVCDecoderConfRecordBytes(),
|
||||
)
|
||||
|
||||
case streamer.CodecH265:
|
||||
case core.CodecH265:
|
||||
vps, sps, pps := h265.GetParameterSet(codec.FmtpLine)
|
||||
if sps == nil {
|
||||
// some dummy SPS and PPS not a problem
|
||||
@@ -97,8 +97,8 @@ func (m *Muxer) GetInit(codecs []*streamer.Codec) ([]byte, error) {
|
||||
codecData.AVCDecoderConfRecordBytes(),
|
||||
)
|
||||
|
||||
case streamer.CodecAAC:
|
||||
s := streamer.Between(codec.FmtpLine, "config=", ";")
|
||||
case core.CodecAAC:
|
||||
s := core.Between(codec.FmtpLine, "config=", ";")
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -108,7 +108,7 @@ func (m *Muxer) GetInit(codecs []*streamer.Codec) ([]byte, error) {
|
||||
uint32(i+1), codec.Name, codec.ClockRate, codec.Channels, b,
|
||||
)
|
||||
|
||||
case streamer.CodecOpus, streamer.CodecMP3, streamer.CodecPCMU, streamer.CodecPCMA:
|
||||
case core.CodecOpus, core.CodecMP3, core.CodecPCMU, core.CodecPCMA:
|
||||
mv.WriteAudioTrack(
|
||||
uint32(i+1), codec.Name, codec.ClockRate, codec.Channels, nil,
|
||||
)
|
||||
|
||||
+50
-43
@@ -2,48 +2,49 @@ package mp4
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/pion/rtp"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Segment struct {
|
||||
streamer.Element
|
||||
core.Listener
|
||||
|
||||
Medias []*streamer.Media
|
||||
Medias []*core.Media
|
||||
UserAgent string
|
||||
RemoteAddr string
|
||||
|
||||
senders []*core.Sender
|
||||
|
||||
MimeType string
|
||||
OnlyKeyframe bool
|
||||
|
||||
send uint32
|
||||
send int
|
||||
}
|
||||
|
||||
func (c *Segment) GetMedias() []*streamer.Media {
|
||||
func (c *Segment) GetMedias() []*core.Media {
|
||||
if c.Medias != nil {
|
||||
return c.Medias
|
||||
}
|
||||
|
||||
// default medias
|
||||
return []*streamer.Media{
|
||||
// default local medias
|
||||
return []*core.Media{
|
||||
{
|
||||
Kind: streamer.KindVideo,
|
||||
Direction: streamer.DirectionRecvonly,
|
||||
Codecs: []*streamer.Codec{
|
||||
{Name: streamer.CodecH264},
|
||||
{Name: streamer.CodecH265},
|
||||
Kind: core.KindVideo,
|
||||
Direction: core.DirectionSendonly,
|
||||
Codecs: []*core.Codec{
|
||||
{Name: core.CodecH264},
|
||||
{Name: core.CodecH265},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Segment) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.Track {
|
||||
func (c *Segment) AddTrack(media *core.Media, _ *core.Codec, track *core.Receiver) error {
|
||||
muxer := &Muxer{}
|
||||
|
||||
codecs := []*streamer.Codec{track.Codec}
|
||||
codecs := []*core.Codec{track.Codec}
|
||||
|
||||
init, err := muxer.GetInit(codecs)
|
||||
if err != nil {
|
||||
@@ -52,26 +53,26 @@ func (c *Segment) AddTrack(media *streamer.Media, track *streamer.Track) *stream
|
||||
|
||||
c.MimeType = `video/mp4; codecs="` + muxer.MimeCodecs(codecs) + `"`
|
||||
|
||||
handler := core.NewSender(media, track.Codec)
|
||||
|
||||
switch track.Codec.Name {
|
||||
case streamer.CodecH264:
|
||||
var push streamer.WriterFunc
|
||||
case core.CodecH264:
|
||||
|
||||
if c.OnlyKeyframe {
|
||||
push = func(packet *rtp.Packet) error {
|
||||
handler.Handler = func(packet *rtp.Packet) {
|
||||
if !h264.IsKeyframe(packet.Payload) {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
buf := muxer.Marshal(0, packet)
|
||||
atomic.AddUint32(&c.send, uint32(len(buf)))
|
||||
c.Fire(append(init, buf...))
|
||||
|
||||
return nil
|
||||
c.send += len(buf)
|
||||
}
|
||||
} else {
|
||||
var buf []byte
|
||||
|
||||
push = func(packet *rtp.Packet) error {
|
||||
handler.Handler = func(packet *rtp.Packet) {
|
||||
if h264.IsKeyframe(packet.Payload) {
|
||||
// fist frame - send only IFrame
|
||||
// other frames - send IFrame and all PFrames
|
||||
@@ -81,9 +82,10 @@ func (c *Segment) AddTrack(media *streamer.Media, track *streamer.Track) *stream
|
||||
buf = append(buf, b...)
|
||||
}
|
||||
|
||||
atomic.AddUint32(&c.send, uint32(len(buf)))
|
||||
c.Fire(buf)
|
||||
|
||||
c.send += len(buf)
|
||||
|
||||
buf = buf[:0]
|
||||
buf = append(buf, init...)
|
||||
muxer.Reset()
|
||||
@@ -93,51 +95,56 @@ func (c *Segment) AddTrack(media *streamer.Media, track *streamer.Track) *stream
|
||||
b := muxer.Marshal(0, packet)
|
||||
buf = append(buf, b...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var wrapper streamer.WrapperFunc
|
||||
if track.Codec.IsRTP() {
|
||||
wrapper = h264.RTPDepay(track)
|
||||
handler.Handler = h264.RTPDepay(track.Codec, handler.Handler)
|
||||
} else {
|
||||
wrapper = h264.RepairAVC(track)
|
||||
handler.Handler = h264.RepairAVC(track.Codec, handler.Handler)
|
||||
}
|
||||
push = wrapper(push)
|
||||
|
||||
return track.Bind(push)
|
||||
|
||||
case streamer.CodecH265:
|
||||
push := func(packet *rtp.Packet) error {
|
||||
case core.CodecH265:
|
||||
handler.Handler = func(packet *rtp.Packet) {
|
||||
if !h265.IsKeyframe(packet.Payload) {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
buf := muxer.Marshal(0, packet)
|
||||
atomic.AddUint32(&c.send, uint32(len(buf)))
|
||||
c.Fire(append(init, buf...))
|
||||
|
||||
return nil
|
||||
c.send += len(buf)
|
||||
}
|
||||
|
||||
if track.Codec.IsRTP() {
|
||||
wrapper := h265.RTPDepay(track)
|
||||
push = wrapper(push)
|
||||
handler.Handler = h265.RTPDepay(track.Codec, handler.Handler)
|
||||
}
|
||||
|
||||
return track.Bind(push)
|
||||
default:
|
||||
panic(core.UnsupportedCodec)
|
||||
}
|
||||
|
||||
panic("unsupported codec")
|
||||
handler.HandleRTP(track)
|
||||
c.senders = append(c.senders, handler)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Segment) Stop() error {
|
||||
for _, sender := range c.senders {
|
||||
sender.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Segment) MarshalJSON() ([]byte, error) {
|
||||
info := &streamer.Info{
|
||||
Type: "WS/MP4 client",
|
||||
info := &core.Info{
|
||||
Type: "MP4/WebSocket passive consumer",
|
||||
RemoteAddr: c.RemoteAddr,
|
||||
UserAgent: c.UserAgent,
|
||||
Send: atomic.LoadUint32(&c.send),
|
||||
Medias: c.Medias,
|
||||
Senders: c.senders,
|
||||
Send: c.send,
|
||||
}
|
||||
return json.Marshal(info)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package mp4
|
||||
import (
|
||||
"encoding/hex"
|
||||
"github.com/AlexxIT/go2rtc/pkg/aac"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
@@ -14,9 +14,9 @@ import (
|
||||
)
|
||||
|
||||
type Consumer struct {
|
||||
streamer.Element
|
||||
core.Listener
|
||||
|
||||
Medias []*streamer.Media
|
||||
Medias []*core.Media
|
||||
UserAgent string
|
||||
RemoteAddr string
|
||||
|
||||
@@ -28,35 +28,35 @@ type Consumer struct {
|
||||
send int
|
||||
}
|
||||
|
||||
func (c *Consumer) GetMedias() []*streamer.Media {
|
||||
func (c *Consumer) GetMedias() []*core.Media {
|
||||
if c.Medias != nil {
|
||||
return c.Medias
|
||||
}
|
||||
|
||||
return []*streamer.Media{
|
||||
return []*core.Media{
|
||||
{
|
||||
Kind: streamer.KindVideo,
|
||||
Direction: streamer.DirectionRecvonly,
|
||||
Codecs: []*streamer.Codec{
|
||||
{Name: streamer.CodecH264, ClockRate: 90000},
|
||||
Kind: core.KindVideo,
|
||||
Direction: core.DirectionSendonly,
|
||||
Codecs: []*core.Codec{
|
||||
{Name: core.CodecH264, ClockRate: 90000},
|
||||
},
|
||||
},
|
||||
{
|
||||
Kind: streamer.KindAudio,
|
||||
Direction: streamer.DirectionRecvonly,
|
||||
Codecs: []*streamer.Codec{
|
||||
{Name: streamer.CodecAAC, ClockRate: 16000},
|
||||
Kind: core.KindAudio,
|
||||
Direction: core.DirectionSendonly,
|
||||
Codecs: []*core.Codec{
|
||||
{Name: core.CodecAAC, ClockRate: 16000},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Consumer) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.Track {
|
||||
func (c *Consumer) AddTrack(media *core.Media, track *core.Track) *core.Track {
|
||||
codec := track.Codec
|
||||
trackID := int8(len(c.streams))
|
||||
|
||||
switch codec.Name {
|
||||
case streamer.CodecH264:
|
||||
case core.CodecH264:
|
||||
sps, pps := h264.GetParameterSet(codec.FmtpLine)
|
||||
stream, err := h264parser.NewCodecDataFromSPSAndPPS(sps, pps)
|
||||
if err != nil {
|
||||
@@ -102,8 +102,8 @@ func (c *Consumer) AddTrack(media *streamer.Media, track *streamer.Track) *strea
|
||||
|
||||
return track.Bind(push)
|
||||
|
||||
case streamer.CodecAAC:
|
||||
s := streamer.Between(codec.FmtpLine, "config=", ";")
|
||||
case core.CodecAAC:
|
||||
s := core.Between(codec.FmtpLine, "config=", ";")
|
||||
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
@@ -3,6 +3,7 @@ package mp4
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/AlexxIT/go2rtc/pkg/aac"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
@@ -11,14 +12,14 @@ import (
|
||||
)
|
||||
|
||||
type Consumer struct {
|
||||
streamer.Element
|
||||
core.Listener
|
||||
|
||||
Medias []*streamer.Media
|
||||
Medias []*core.Media
|
||||
UserAgent string
|
||||
RemoteAddr string
|
||||
|
||||
muxer *Muxer
|
||||
codecs []*streamer.Codec
|
||||
codecs []*core.Codec
|
||||
wait byte
|
||||
|
||||
send uint32
|
||||
@@ -30,38 +31,38 @@ const (
|
||||
waitInit
|
||||
)
|
||||
|
||||
func (c *Consumer) GetMedias() []*streamer.Media {
|
||||
func (c *Consumer) GetMedias() []*core.Media {
|
||||
if c.Medias != nil {
|
||||
return c.Medias
|
||||
}
|
||||
|
||||
// default medias
|
||||
return []*streamer.Media{
|
||||
return []*core.Media{
|
||||
{
|
||||
Kind: streamer.KindVideo,
|
||||
Direction: streamer.DirectionRecvonly,
|
||||
Codecs: []*streamer.Codec{
|
||||
{Name: streamer.CodecH264},
|
||||
{Name: streamer.CodecH265},
|
||||
Kind: core.KindVideo,
|
||||
Direction: core.DirectionSendonly,
|
||||
Codecs: []*core.Codec{
|
||||
{Name: core.CodecH264},
|
||||
{Name: core.CodecH265},
|
||||
},
|
||||
},
|
||||
{
|
||||
Kind: streamer.KindAudio,
|
||||
Direction: streamer.DirectionRecvonly,
|
||||
Codecs: []*streamer.Codec{
|
||||
{Name: streamer.CodecAAC},
|
||||
Kind: core.KindAudio,
|
||||
Direction: core.DirectionSendonly,
|
||||
Codecs: []*core.Codec{
|
||||
{Name: core.CodecAAC},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Consumer) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.Track {
|
||||
func (c *Consumer) AddTrack(media *core.Media, track *core.Track) *core.Track {
|
||||
trackID := byte(len(c.codecs))
|
||||
c.codecs = append(c.codecs, track.Codec)
|
||||
|
||||
codec := track.Codec
|
||||
switch codec.Name {
|
||||
case streamer.CodecH264:
|
||||
case core.CodecH264:
|
||||
c.wait = waitInit
|
||||
|
||||
push := func(packet *rtp.Packet) error {
|
||||
@@ -93,7 +94,7 @@ func (c *Consumer) AddTrack(media *streamer.Media, track *streamer.Track) *strea
|
||||
|
||||
return track.Bind(push)
|
||||
|
||||
case streamer.CodecH265:
|
||||
case core.CodecH265:
|
||||
c.wait = waitInit
|
||||
|
||||
push := func(packet *rtp.Packet) error {
|
||||
@@ -164,7 +165,7 @@ func (c *Consumer) Start() {
|
||||
//
|
||||
|
||||
func (c *Consumer) MarshalJSON() ([]byte, error) {
|
||||
info := &streamer.Info{
|
||||
info := &core.Info{
|
||||
Type: "MP4 client",
|
||||
RemoteAddr: c.RemoteAddr,
|
||||
UserAgent: c.UserAgent,
|
||||
@@ -2,17 +2,17 @@ package mp4
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/pion/rtp"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Segment struct {
|
||||
streamer.Element
|
||||
core.Listener
|
||||
|
||||
Medias []*streamer.Media
|
||||
Medias []*core.Media
|
||||
UserAgent string
|
||||
RemoteAddr string
|
||||
|
||||
@@ -22,28 +22,28 @@ type Segment struct {
|
||||
send uint32
|
||||
}
|
||||
|
||||
func (c *Segment) GetMedias() []*streamer.Media {
|
||||
func (c *Segment) GetMedias() []*core.Media {
|
||||
if c.Medias != nil {
|
||||
return c.Medias
|
||||
}
|
||||
|
||||
// default medias
|
||||
return []*streamer.Media{
|
||||
return []*core.Media{
|
||||
{
|
||||
Kind: streamer.KindVideo,
|
||||
Direction: streamer.DirectionRecvonly,
|
||||
Codecs: []*streamer.Codec{
|
||||
{Name: streamer.CodecH264},
|
||||
{Name: streamer.CodecH265},
|
||||
Kind: core.KindVideo,
|
||||
Direction: core.DirectionSendonly,
|
||||
Codecs: []*core.Codec{
|
||||
{Name: core.CodecH264},
|
||||
{Name: core.CodecH265},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Segment) AddTrack(media *streamer.Media, track *streamer.Track) *streamer.Track {
|
||||
func (c *Segment) AddTrack(media *core.Media, track *core.Track) *core.Track {
|
||||
muxer := &Muxer{}
|
||||
|
||||
codecs := []*streamer.Codec{track.Codec}
|
||||
codecs := []*core.Codec{track.Codec}
|
||||
|
||||
init, err := muxer.GetInit(codecs)
|
||||
if err != nil {
|
||||
@@ -53,8 +53,8 @@ func (c *Segment) AddTrack(media *streamer.Media, track *streamer.Track) *stream
|
||||
c.MimeType = muxer.MimeType(codecs)
|
||||
|
||||
switch track.Codec.Name {
|
||||
case streamer.CodecH264:
|
||||
var push streamer.WriterFunc
|
||||
case core.CodecH264:
|
||||
var push core.WriterFunc
|
||||
|
||||
if c.OnlyKeyframe {
|
||||
push = func(packet *rtp.Packet) error {
|
||||
@@ -98,7 +98,7 @@ func (c *Segment) AddTrack(media *streamer.Media, track *streamer.Track) *stream
|
||||
}
|
||||
}
|
||||
|
||||
var wrapper streamer.WrapperFunc
|
||||
var wrapper core.WrapperFunc
|
||||
if track.Codec.IsRTP() {
|
||||
wrapper = h264.RTPDepay(track)
|
||||
} else {
|
||||
@@ -108,7 +108,7 @@ func (c *Segment) AddTrack(media *streamer.Media, track *streamer.Track) *stream
|
||||
|
||||
return track.Bind(push)
|
||||
|
||||
case streamer.CodecH265:
|
||||
case core.CodecH265:
|
||||
push := func(packet *rtp.Packet) error {
|
||||
if !h265.IsKeyframe(packet.Payload) {
|
||||
return nil
|
||||
@@ -133,7 +133,7 @@ func (c *Segment) AddTrack(media *streamer.Media, track *streamer.Track) *stream
|
||||
}
|
||||
|
||||
func (c *Segment) MarshalJSON() ([]byte, error) {
|
||||
info := &streamer.Info{
|
||||
info := &core.Info{
|
||||
Type: "WS/MP4 client",
|
||||
RemoteAddr: c.RemoteAddr,
|
||||
UserAgent: c.UserAgent,
|
||||
+10
-10
@@ -3,9 +3,9 @@ package mp4
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h264"
|
||||
"github.com/AlexxIT/go2rtc/pkg/h265"
|
||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/codec/h265parser"
|
||||
@@ -21,7 +21,7 @@ type Muxer struct {
|
||||
pts []uint32
|
||||
}
|
||||
|
||||
func (m *Muxer) MimeType(codecs []*streamer.Codec) string {
|
||||
func (m *Muxer) MimeType(codecs []*core.Codec) string {
|
||||
s := `video/mp4; codecs="`
|
||||
|
||||
for i, codec := range codecs {
|
||||
@@ -30,13 +30,13 @@ func (m *Muxer) MimeType(codecs []*streamer.Codec) string {
|
||||
}
|
||||
|
||||
switch codec.Name {
|
||||
case streamer.CodecH264:
|
||||
case core.CodecH264:
|
||||
s += "avc1." + h264.GetProfileLevelID(codec.FmtpLine)
|
||||
case streamer.CodecH265:
|
||||
case core.CodecH265:
|
||||
// H.265 profile=main level=5.1
|
||||
// hvc1 - supported in Safari, hev1 - doesn't, both supported in Chrome
|
||||
s += "hvc1.1.6.L153.B0"
|
||||
case streamer.CodecAAC:
|
||||
case core.CodecAAC:
|
||||
s += "mp4a.40.2"
|
||||
}
|
||||
}
|
||||
@@ -44,12 +44,12 @@ func (m *Muxer) MimeType(codecs []*streamer.Codec) string {
|
||||
return s + `"`
|
||||
}
|
||||
|
||||
func (m *Muxer) GetInit(codecs []*streamer.Codec) ([]byte, error) {
|
||||
func (m *Muxer) GetInit(codecs []*core.Codec) ([]byte, error) {
|
||||
moov := MOOV()
|
||||
|
||||
for i, codec := range codecs {
|
||||
switch codec.Name {
|
||||
case streamer.CodecH264:
|
||||
case core.CodecH264:
|
||||
sps, pps := h264.GetParameterSet(codec.FmtpLine)
|
||||
if sps == nil {
|
||||
// some dummy SPS and PPS not a problem
|
||||
@@ -92,7 +92,7 @@ func (m *Muxer) GetInit(codecs []*streamer.Codec) ([]byte, error) {
|
||||
|
||||
moov.Tracks = append(moov.Tracks, trak)
|
||||
|
||||
case streamer.CodecH265:
|
||||
case core.CodecH265:
|
||||
vps, sps, pps := h265.GetParameterSet(codec.FmtpLine)
|
||||
if sps == nil {
|
||||
// some dummy SPS and PPS not a problem
|
||||
@@ -136,8 +136,8 @@ func (m *Muxer) GetInit(codecs []*streamer.Codec) ([]byte, error) {
|
||||
|
||||
moov.Tracks = append(moov.Tracks, trak)
|
||||
|
||||
case streamer.CodecAAC:
|
||||
s := streamer.Between(codec.FmtpLine, "config=", ";")
|
||||
case core.CodecAAC:
|
||||
s := core.Between(codec.FmtpLine, "config=", ";")
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user