mirror of
https://github.com/bluenviron/mediamtx.git
synced 2026-01-10 04:11:59 -08:00
This commit is contained in:
parent
c314d77596
commit
2d17dff3b5
27 changed files with 727 additions and 487 deletions
|
|
@ -23,7 +23,6 @@ import (
|
|||
|
||||
const (
|
||||
codecH264 = 7
|
||||
codecAAC = 10
|
||||
)
|
||||
|
||||
func resultIsOK1(res *message.MsgCommandAMF0) bool {
|
||||
|
|
@ -617,7 +616,7 @@ func trackFromAACDecoderConfig(data []byte) (*formats.MPEG4Audio, error) {
|
|||
|
||||
var errEmptyMetadata = errors.New("metadata is empty")
|
||||
|
||||
func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, *formats.MPEG4Audio, error) {
|
||||
func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, formats.Format, error) {
|
||||
if len(payload) != 1 {
|
||||
return nil, nil, fmt.Errorf("invalid metadata")
|
||||
}
|
||||
|
|
@ -627,6 +626,9 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, *f
|
|||
return nil, nil, fmt.Errorf("invalid metadata")
|
||||
}
|
||||
|
||||
var videoTrack formats.Format
|
||||
var audioTrack formats.Format
|
||||
|
||||
hasVideo, err := func() (bool, error) {
|
||||
v, ok := md.GetV("videocodecid")
|
||||
if !ok {
|
||||
|
|
@ -667,7 +669,11 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, *f
|
|||
case 0:
|
||||
return false, nil
|
||||
|
||||
case codecAAC:
|
||||
case message.CodecMPEG2Audio:
|
||||
audioTrack = &formats.MPEG2Audio{}
|
||||
return true, nil
|
||||
|
||||
case message.CodecMPEG4Audio:
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
|
@ -687,9 +693,6 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, *f
|
|||
return nil, nil, errEmptyMetadata
|
||||
}
|
||||
|
||||
var videoTrack formats.Format
|
||||
var audioTrack *formats.MPEG4Audio
|
||||
|
||||
for {
|
||||
msg, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
|
|
@ -750,7 +753,7 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, *f
|
|||
}
|
||||
|
||||
if audioTrack == nil {
|
||||
if tmsg.AACType == flvio.AVC_SEQHDR {
|
||||
if tmsg.Codec == message.CodecMPEG4Audio && tmsg.AACType == flvio.AVC_SEQHDR {
|
||||
audioTrack, err = trackFromAACDecoderConfig(tmsg.Payload)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
@ -842,7 +845,7 @@ outer:
|
|||
|
||||
// ReadTracks reads track informations.
|
||||
// It returns the video track and the audio track.
|
||||
func (c *Conn) ReadTracks() (formats.Format, *formats.MPEG4Audio, error) {
|
||||
func (c *Conn) ReadTracks() (formats.Format, formats.Format, error) {
|
||||
msg, err := func() (message.Message, error) {
|
||||
for {
|
||||
msg, err := c.ReadMessage()
|
||||
|
|
@ -901,7 +904,7 @@ func (c *Conn) ReadTracks() (formats.Format, *formats.MPEG4Audio, error) {
|
|||
}
|
||||
|
||||
// WriteTracks writes track informations.
|
||||
func (c *Conn) WriteTracks(videoTrack *formats.H264, audioTrack *formats.MPEG4Audio) error {
|
||||
func (c *Conn) WriteTracks(videoTrack formats.Format, audioTrack formats.Format) error {
|
||||
err := c.WriteMessage(&message.MsgDataAMF0{
|
||||
ChunkStreamID: 4,
|
||||
MessageStreamID: 0x1000000,
|
||||
|
|
@ -916,10 +919,13 @@ func (c *Conn) WriteTracks(videoTrack *formats.H264, audioTrack *formats.MPEG4Au
|
|||
{
|
||||
K: "videocodecid",
|
||||
V: func() float64 {
|
||||
if videoTrack != nil {
|
||||
switch videoTrack.(type) {
|
||||
case *formats.H264:
|
||||
return codecH264
|
||||
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
}(),
|
||||
},
|
||||
{
|
||||
|
|
@ -929,10 +935,16 @@ func (c *Conn) WriteTracks(videoTrack *formats.H264, audioTrack *formats.MPEG4Au
|
|||
{
|
||||
K: "audiocodecid",
|
||||
V: func() float64 {
|
||||
if audioTrack != nil {
|
||||
return codecAAC
|
||||
switch audioTrack.(type) {
|
||||
case *formats.MPEG2Audio:
|
||||
return message.CodecMPEG2Audio
|
||||
|
||||
case *formats.MPEG4Audio:
|
||||
return message.CodecMPEG4Audio
|
||||
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
}(),
|
||||
},
|
||||
},
|
||||
|
|
@ -942,10 +954,11 @@ func (c *Conn) WriteTracks(videoTrack *formats.H264, audioTrack *formats.MPEG4Au
|
|||
return err
|
||||
}
|
||||
|
||||
// write decoder config only if SPS and PPS are available.
|
||||
// if they're not available yet, they're sent later.
|
||||
if videoTrack != nil {
|
||||
sps, pps := videoTrack.SafeParams()
|
||||
if h264Track, ok := videoTrack.(*formats.H264); ok {
|
||||
sps, pps := h264Track.SafeParams()
|
||||
|
||||
// write decoder config only if SPS and PPS are available.
|
||||
// if they're not available yet, they're sent later.
|
||||
if sps != nil && pps != nil {
|
||||
buf, _ := h264conf.Conf{
|
||||
SPS: sps,
|
||||
|
|
@ -965,8 +978,8 @@ func (c *Conn) WriteTracks(videoTrack *formats.H264, audioTrack *formats.MPEG4Au
|
|||
}
|
||||
}
|
||||
|
||||
if audioTrack != nil {
|
||||
enc, err := audioTrack.Config.Marshal()
|
||||
if mpeg4audioTrack, ok := audioTrack.(*formats.MPEG4Audio); ok {
|
||||
enc, err := mpeg4audioTrack.Config.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -974,6 +987,7 @@ func (c *Conn) WriteTracks(videoTrack *formats.H264, audioTrack *formats.MPEG4Au
|
|||
err = c.WriteMessage(&message.MsgAudio{
|
||||
ChunkStreamID: message.MsgAudioChunkStreamID,
|
||||
MessageStreamID: 0x1000000,
|
||||
Codec: message.CodecMPEG4Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
|
|
|
|||
|
|
@ -515,7 +515,7 @@ func TestReadTracks(t *testing.T) {
|
|||
PPS: pps,
|
||||
PacketizationMode: 1,
|
||||
},
|
||||
(*formats.MPEG4Audio)(nil),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"metadata without codec id",
|
||||
|
|
@ -801,7 +801,7 @@ func TestReadTracks(t *testing.T) {
|
|||
},
|
||||
{
|
||||
K: "audiocodecid",
|
||||
V: float64(codecAAC),
|
||||
V: float64(message.CodecMPEG4Audio),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -832,6 +832,7 @@ func TestReadTracks(t *testing.T) {
|
|||
err = mrw.Write(&message.MsgAudio{
|
||||
ChunkStreamID: message.MsgAudioChunkStreamID,
|
||||
MessageStreamID: 0x1000000,
|
||||
Codec: message.CodecMPEG4Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
|
|
@ -932,6 +933,7 @@ func TestReadTracks(t *testing.T) {
|
|||
err = mrw.Write(&message.MsgAudio{
|
||||
ChunkStreamID: message.MsgAudioChunkStreamID,
|
||||
MessageStreamID: 0x1000000,
|
||||
Codec: message.CodecMPEG4Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
|
|
@ -965,6 +967,7 @@ func TestReadTracks(t *testing.T) {
|
|||
err = mrw.Write(&message.MsgAudio{
|
||||
ChunkStreamID: message.MsgAudioChunkStreamID,
|
||||
MessageStreamID: 0x1000000,
|
||||
Codec: message.CodecMPEG4Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
|
|
@ -984,6 +987,7 @@ func TestReadTracks(t *testing.T) {
|
|||
err = mrw.Write(&message.MsgAudio{
|
||||
ChunkStreamID: message.MsgAudioChunkStreamID,
|
||||
MessageStreamID: 0x1000000,
|
||||
Codec: message.CodecMPEG4Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
|
|
@ -995,6 +999,7 @@ func TestReadTracks(t *testing.T) {
|
|||
err = mrw.Write(&message.MsgAudio{
|
||||
ChunkStreamID: message.MsgAudioChunkStreamID,
|
||||
MessageStreamID: 0x1000000,
|
||||
Codec: message.CodecMPEG4Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
|
|
@ -1026,7 +1031,7 @@ func TestReadTracks(t *testing.T) {
|
|||
},
|
||||
{
|
||||
K: "audiocodecid",
|
||||
V: float64(codecAAC),
|
||||
V: float64(message.CodecMPEG4Audio),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -1075,6 +1080,7 @@ func TestReadTracks(t *testing.T) {
|
|||
err = mrw.Write(&message.MsgAudio{
|
||||
ChunkStreamID: message.MsgAudioChunkStreamID,
|
||||
MessageStreamID: 0x1000000,
|
||||
Codec: message.CodecMPEG4Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
|
|
@ -1375,6 +1381,7 @@ func TestWriteTracks(t *testing.T) {
|
|||
require.Equal(t, &message.MsgAudio{
|
||||
ChunkStreamID: message.MsgAudioChunkStreamID,
|
||||
MessageStreamID: 0x1000000,
|
||||
Codec: message.CodecMPEG4Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
|
|
|
|||
|
|
@ -4,15 +4,19 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/notedit/rtmp/format/flv/flvio"
|
||||
|
||||
"github.com/aler9/mediamtx/internal/rtmp/chunk"
|
||||
"github.com/aler9/mediamtx/internal/rtmp/rawmessage"
|
||||
)
|
||||
|
||||
const (
|
||||
// MsgAudioChunkStreamID is the chunk stream ID that is usually used to send MsgAudio{}
|
||||
MsgAudioChunkStreamID = 6
|
||||
MsgAudioChunkStreamID = 4
|
||||
)
|
||||
|
||||
// supported audio codecs
|
||||
const (
|
||||
CodecMPEG2Audio = 2
|
||||
CodecMPEG4Audio = 10
|
||||
)
|
||||
|
||||
// MsgAudio is an audio message.
|
||||
|
|
@ -20,10 +24,11 @@ type MsgAudio struct {
|
|||
ChunkStreamID byte
|
||||
DTS time.Duration
|
||||
MessageStreamID uint32
|
||||
Codec uint8
|
||||
Rate uint8
|
||||
Depth uint8
|
||||
Channels uint8
|
||||
AACType uint8
|
||||
AACType uint8 // only for CodecMPEG4Audio
|
||||
Payload []byte
|
||||
}
|
||||
|
||||
|
|
@ -37,28 +42,45 @@ func (m *MsgAudio) Unmarshal(raw *rawmessage.Message) error {
|
|||
return fmt.Errorf("invalid body size")
|
||||
}
|
||||
|
||||
codec := raw.Body[0] >> 4
|
||||
if codec != flvio.SOUND_AAC {
|
||||
return fmt.Errorf("unsupported audio codec: %d", codec)
|
||||
m.Codec = raw.Body[0] >> 4
|
||||
switch m.Codec {
|
||||
case CodecMPEG2Audio, CodecMPEG4Audio:
|
||||
default:
|
||||
return fmt.Errorf("unsupported audio codec: %d", m.Codec)
|
||||
}
|
||||
|
||||
m.Rate = (raw.Body[0] >> 2) & 0x03
|
||||
m.Depth = (raw.Body[0] >> 1) & 0x01
|
||||
m.Channels = raw.Body[0] & 0x01
|
||||
m.AACType = raw.Body[1]
|
||||
m.Payload = raw.Body[2:]
|
||||
|
||||
if m.Codec == CodecMPEG2Audio {
|
||||
m.Payload = raw.Body[1:]
|
||||
} else {
|
||||
m.AACType = raw.Body[1]
|
||||
m.Payload = raw.Body[2:]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshal implements Message.
|
||||
func (m MsgAudio) Marshal() (*rawmessage.Message, error) {
|
||||
body := make([]byte, 2+len(m.Payload))
|
||||
var l int
|
||||
if m.Codec == CodecMPEG2Audio {
|
||||
l = 1 + len(m.Payload)
|
||||
} else {
|
||||
l = 2 + len(m.Payload)
|
||||
}
|
||||
body := make([]byte, l)
|
||||
|
||||
body[0] = flvio.SOUND_AAC<<4 | m.Rate<<2 | m.Depth<<1 | m.Channels
|
||||
body[1] = m.AACType
|
||||
body[0] = m.Codec<<4 | m.Rate<<2 | m.Depth<<1 | m.Channels
|
||||
|
||||
copy(body[2:], m.Payload)
|
||||
if m.Codec == CodecMPEG2Audio {
|
||||
copy(body[1:], m.Payload)
|
||||
} else {
|
||||
body[1] = m.AACType
|
||||
copy(body[2:], m.Payload)
|
||||
}
|
||||
|
||||
return &rawmessage.Message{
|
||||
ChunkStreamID: m.ChunkStreamID,
|
||||
|
|
|
|||
|
|
@ -27,11 +27,29 @@ var readWriterCases = []struct {
|
|||
},
|
||||
},
|
||||
{
|
||||
"audio",
|
||||
"audio mpeg2",
|
||||
&MsgAudio{
|
||||
ChunkStreamID: 7,
|
||||
DTS: 6013806 * time.Millisecond,
|
||||
MessageStreamID: 4534543,
|
||||
Codec: CodecMPEG2Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
Payload: []byte{0x01, 0x02, 0x03, 0x04},
|
||||
},
|
||||
[]byte{
|
||||
0x7, 0x5b, 0xc3, 0x6e, 0x0, 0x0, 0x5, 0x8, 0x0, 0x45, 0x31, 0xf, 0x2f,
|
||||
0x01, 0x02, 0x03, 0x04,
|
||||
},
|
||||
},
|
||||
{
|
||||
"audio mpeg4",
|
||||
&MsgAudio{
|
||||
ChunkStreamID: 7,
|
||||
DTS: 6013806 * time.Millisecond,
|
||||
MessageStreamID: 4534543,
|
||||
Codec: CodecMPEG4Audio,
|
||||
Rate: flvio.SOUND_44Khz,
|
||||
Depth: flvio.SOUND_16BIT,
|
||||
Channels: flvio.SOUND_STEREO,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue