diff --git a/README.md b/README.md index ab784ab1..4644ec43 100644 --- a/README.md +++ b/README.md @@ -10,10 +10,10 @@ Live streams can be published to the server with: |protocol|variants|codecs| |--------|--------|------| -|RTSP clients (FFmpeg, GStreamer, etc)|UDP, TCP, RTSPS|H264, H265, VP8, VP9, AV1, MPEG-2 video, M-JPEG, MPEG-4 video, MPEG-2 audio (MP3), MPEG-4 Audio (AAC), Opus, G711, G722, LPCM and any RTP-compatible codec| -|RTSP servers and cameras|UDP, UDP-Multicast, TCP, RTSPS|H264, H265, VP8, VP9, AV1, MPEG-2 video, M-JPEG, MPEG-4 video, MPEG-2 audio (MP3), MPEG-4 Audio (AAC), Opus, G711, G722, LPCM and any RTP-compatible codec| -|RTMP clients (OBS Studio)|RTMP, RTMPS|H264, H265, MPEG-2 audio (MP3), MPEG-4 Audio (AAC)| -|RTMP servers and cameras|RTMP, RTMPS|H264, MPEG-2 audio (MP3), MPEG-4 Audio (AAC)| +|RTSP clients (FFmpeg, GStreamer, etc)|UDP, TCP, RTSPS|H264, H265, VP8, VP9, AV1, MPEG-2 Video, M-JPEG, MPEG-4 Video (H263, Xvid), MPEG-2 Audio (MP3), MPEG-4 Audio (AAC), Opus, G711, G722, LPCM and any RTP-compatible codec| +|RTSP servers and cameras|UDP, UDP-Multicast, TCP, RTSPS|H264, H265, VP8, VP9, AV1, MPEG-2 Video, M-JPEG, MPEG-4 Video (H263, Xvid), MPEG-2 Audio (MP3), MPEG-4 Audio (AAC), Opus, G711, G722, LPCM and any RTP-compatible codec| +|RTMP clients (OBS Studio)|RTMP, RTMPS|H264, H265, MPEG-2 Audio (MP3), MPEG-4 Audio (AAC)| +|RTMP servers and cameras|RTMP, RTMPS|H264, MPEG-2 Audio (MP3), MPEG-4 Audio (AAC)| |HLS servers and cameras|Low-Latency HLS, MP4-based HLS, legacy HLS|H264, H265, MPEG-4 Audio (AAC), Opus| |UDP/MPEG-TS streams|Unicast, broadcast, multicast|H264, H265, MPEG-4 Audio (AAC), Opus| |Raspberry Pi Cameras||H264| @@ -22,8 +22,8 @@ And can be read from the server with: |protocol|variants|codecs| |--------|--------|------| -|RTSP|UDP, UDP-Multicast, TCP, RTSPS|H264, H265, VP8, VP9, AV1, MPEG-2 video, M-JPEG, MPEG-4 video, MPEG-2 audio (MP3), MPEG-4 Audio (AAC), Opus, G711, G722, LPCM and any RTP-compatible codec| -|RTMP|RTMP, RTMPS|H264, MPEG-2 audio (MP3), MPEG-4 Audio (AAC)| +|RTSP|UDP, UDP-Multicast, TCP, RTSPS|H264, H265, VP8, VP9, AV1, MPEG-2 Video, M-JPEG, MPEG-4 Video (H263, Xvid), MPEG-2 Audio (MP3), MPEG-4 Audio (AAC), Opus, G711, G722, LPCM and any RTP-compatible codec| +|RTMP|RTMP, RTMPS|H264, MPEG-2 Audio (MP3), MPEG-4 Audio (AAC)| |HLS|Low-Latency HLS, MP4-based HLS, legacy HLS|H264, H265, MPEG-4 Audio (AAC), Opus| |WebRTC||H264, VP8, VP9, Opus, G711, G722| diff --git a/internal/core/rtmp_conn.go b/internal/core/rtmp_conn.go index 63ef3c50..b3dac6e2 100644 --- a/internal/core/rtmp_conn.go +++ b/internal/core/rtmp_conn.go @@ -48,7 +48,8 @@ func getRTMPWriteFunc(medi *media.Media, format formats.Format, stream *stream) return func(msg interface{}) error { tmsg := msg.(*message.MsgVideo) - if tmsg.H264Type == flvio.AVC_SEQHDR { + switch tmsg.Type { + case message.MsgVideoTypeConfig: var conf h264conf.Conf err := conf.Unmarshal(tmsg.Payload) if err != nil { @@ -65,9 +66,8 @@ func getRTMPWriteFunc(medi *media.Media, format formats.Format, stream *stream) AU: au, NTP: time.Now(), }) - } - if tmsg.H264Type == flvio.AVC_NALU { + case message.MsgVideoTypeAU: au, err := h264.AVCCUnmarshal(tmsg.Payload) if err != nil { return fmt.Errorf("unable to decode AVCC: %v", err) @@ -114,15 +114,15 @@ func getRTMPWriteFunc(medi *media.Media, format formats.Format, stream *stream) return func(msg interface{}) error { tmsg := msg.(*message.MsgAudio) - if tmsg.AACType != flvio.AAC_RAW { - return nil + if tmsg.AACType == message.MsgAudioAACTypeAU { + return stream.writeUnit(medi, format, &formatprocessor.UnitMPEG4Audio{ + PTS: tmsg.DTS, + AUs: [][]byte{tmsg.Payload}, + NTP: time.Now(), + }) } - return stream.writeUnit(medi, format, &formatprocessor.UnitMPEG4Audio{ - PTS: tmsg.DTS, - AUs: [][]byte{tmsg.Payload}, - NTP: time.Now(), - }) + return nil } default: @@ -366,7 +366,7 @@ func (c *rtmpConn) runRead(ctx context.Context, u *url.URL) error { if videoFormat == nil && audioFormat == nil { return fmt.Errorf( - "the stream doesn't contain any supported codec, which are currently H264, MPEG2-Audio, MPEG4-Audio") + "the stream doesn't contain any supported codec, which are currently H264, MPEG-2 Audio, MPEG-4 Audio") } defer res.stream.readerRemove(c) @@ -496,8 +496,9 @@ func (c *rtmpConn) findVideoFormat(stream *stream, ringBuffer *ringbuffer.RingBu err = c.conn.WriteMessage(&message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: idrPresent, - H264Type: flvio.AVC_NALU, + Type: message.MsgVideoTypeAU, Payload: avcc, DTS: dts, PTSDelta: pts - dts, @@ -560,7 +561,7 @@ func (c *rtmpConn) findAudioFormat(stream *stream, ringBuffer *ringbuffer.RingBu Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_RAW, + AACType: message.MsgAudioAACTypeAU, Payload: au, DTS: pts + time.Duration(i)*mpeg4audio.SamplesPerAccessUnit* time.Second/time.Duration(audioFormatMPEG4.ClockRate()), @@ -621,11 +622,21 @@ func (c *rtmpConn) findAudioFormat(stream *stream, ringBuffer *ringbuffer.RingBu channels = flvio.SOUND_MONO } + rate := uint8(flvio.SOUND_44Khz) + switch h.SampleRate { + case 5500: + rate = flvio.SOUND_5_5Khz + case 11025: + rate = flvio.SOUND_11Khz + case 22050: + rate = flvio.SOUND_22Khz + } + msg := &message.MsgAudio{ ChunkStreamID: message.MsgAudioChunkStreamID, MessageStreamID: 0x1000000, Codec: message.CodecMPEG2Audio, - Rate: flvio.SOUND_44Khz, + Rate: rate, Depth: flvio.SOUND_16BIT, Channels: channels, Payload: frame, diff --git a/internal/core/rtmp_server_test.go b/internal/core/rtmp_server_test.go index 8f70e226..41986263 100644 --- a/internal/core/rtmp_server_test.go +++ b/internal/core/rtmp_server_test.go @@ -10,7 +10,6 @@ import ( "github.com/bluenviron/gortsplib/v3/pkg/formats" "github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio" - "github.com/notedit/rtmp/format/flv/flvio" "github.com/stretchr/testify/require" "github.com/aler9/mediamtx/internal/rtmp" @@ -149,8 +148,9 @@ func TestRTMPServerPublishRead(t *testing.T) { err = conn1.WriteMessage(&message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_NALU, + Type: message.MsgVideoTypeAU, Payload: []byte{ 0x00, 0x00, 0x00, 0x04, 0x05, 0x02, 0x03, 0x04, // IDR 1 0x00, 0x00, 0x00, 0x04, 0x05, 0x02, 0x03, 0x04, // IDR 2 @@ -163,8 +163,9 @@ func TestRTMPServerPublishRead(t *testing.T) { require.Equal(t, &message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_NALU, + Type: message.MsgVideoTypeAU, Payload: []byte{ 0x00, 0x00, 0x00, 0x19, // SPS 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, diff --git a/internal/core/rtmp_source_test.go b/internal/core/rtmp_source_test.go index 0c7f627f..6f0b5513 100644 --- a/internal/core/rtmp_source_test.go +++ b/internal/core/rtmp_source_test.go @@ -10,7 +10,6 @@ import ( "github.com/bluenviron/gortsplib/v3/pkg/formats" "github.com/bluenviron/gortsplib/v3/pkg/url" "github.com/bluenviron/mediacommon/pkg/codecs/mpeg4audio" - "github.com/notedit/rtmp/format/flv/flvio" "github.com/pion/rtp" "github.com/stretchr/testify/require" @@ -90,8 +89,9 @@ func TestRTMPSource(t *testing.T) { err = conn.WriteMessage(&message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_NALU, + Type: message.MsgVideoTypeAU, Payload: []byte{0x00, 0x00, 0x00, 0x04, 0x05, 0x02, 0x03, 0x04}, }) require.NoError(t, err) diff --git a/internal/formatprocessor/mpeg2audio.go b/internal/formatprocessor/mpeg2audio.go index 453b749e..035f8497 100644 --- a/internal/formatprocessor/mpeg2audio.go +++ b/internal/formatprocessor/mpeg2audio.go @@ -9,7 +9,7 @@ import ( "github.com/pion/rtp" ) -// UnitMPEG2Audio is a MPEG2-audio data unit. +// UnitMPEG2Audio is a MPEG-2 Audio data unit. type UnitMPEG2Audio struct { RTPPackets []*rtp.Packet NTP time.Time diff --git a/internal/formatprocessor/mpeg4audio.go b/internal/formatprocessor/mpeg4audio.go index 1fd0d584..72693c67 100644 --- a/internal/formatprocessor/mpeg4audio.go +++ b/internal/formatprocessor/mpeg4audio.go @@ -9,7 +9,7 @@ import ( "github.com/pion/rtp" ) -// UnitMPEG4Audio is a MPEG4-audio data unit. +// UnitMPEG4Audio is a MPEG-4 Audio data unit. type UnitMPEG4Audio struct { RTPPackets []*rtp.Packet NTP time.Time diff --git a/internal/rtmp/conn.go b/internal/rtmp/conn.go index 5920f1b6..f33fb1a9 100644 --- a/internal/rtmp/conn.go +++ b/internal/rtmp/conn.go @@ -21,10 +21,6 @@ import ( "github.com/aler9/mediamtx/internal/rtmp/message" ) -const ( - codecH264 = 7 -) - func resultIsOK1(res *message.MsgCommandAMF0) bool { if len(res.Arguments) < 2 { return false @@ -641,7 +637,7 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, fo case 0: return false, nil - case codecH264: + case message.CodecH264: return true, nil } @@ -651,7 +647,7 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, fo } } - return false, fmt.Errorf("unsupported video codec %v", v) + return false, fmt.Errorf("unsupported video codec: %v", v) }() if err != nil { return nil, nil, err @@ -694,6 +690,11 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, fo } for { + if (!hasVideo || videoTrack != nil) && + (!hasAudio || audioTrack != nil) { + return videoTrack, audioTrack, nil + } + msg, err := c.ReadMessage() if err != nil { return nil, nil, err @@ -706,12 +707,12 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, fo } if videoTrack == nil { - if tmsg.H264Type == flvio.AVC_SEQHDR { + if tmsg.Type == message.MsgVideoTypeConfig { videoTrack, err = trackFromH264DecoderConfig(tmsg.Payload) if err != nil { return nil, nil, err } - } else if tmsg.H264Type == 1 && tmsg.IsKeyFrame { + } else if tmsg.Type == message.MsgVideoTypeAU && tmsg.IsKeyFrame { nalus, err := h264.AVCCUnmarshal(tmsg.Payload) if err != nil { return nil, nil, err @@ -753,7 +754,7 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, fo } if audioTrack == nil { - if tmsg.Codec == message.CodecMPEG4Audio && tmsg.AACType == flvio.AVC_SEQHDR { + if tmsg.Codec == message.CodecMPEG4Audio && tmsg.AACType == message.MsgAudioAACTypeConfig { audioTrack, err = trackFromAACDecoderConfig(tmsg.Payload) if err != nil { return nil, nil, err @@ -761,11 +762,6 @@ func (c *Conn) readTracksFromMetadata(payload []interface{}) (formats.Format, fo } } } - - if (!hasVideo || videoTrack != nil) && - (!hasAudio || audioTrack != nil) { - return videoTrack, audioTrack, nil - } } } @@ -784,7 +780,7 @@ outer: startTime = &v } - if tmsg.H264Type == flvio.AVC_SEQHDR { + if tmsg.Type == message.MsgVideoTypeConfig { if videoTrack == nil { var err error videoTrack, err = trackFromH264DecoderConfig(tmsg.Payload) @@ -809,7 +805,7 @@ outer: startTime = &v } - if tmsg.AACType == flvio.AVC_SEQHDR { + if tmsg.AACType == message.MsgAudioAACTypeConfig { if audioTrack == nil { var err error audioTrack, err = trackFromAACDecoderConfig(tmsg.Payload) @@ -921,7 +917,7 @@ func (c *Conn) WriteTracks(videoTrack formats.Format, audioTrack formats.Format) V: func() float64 { switch videoTrack.(type) { case *formats.H264: - return codecH264 + return message.CodecH264 default: return 0 @@ -954,12 +950,10 @@ func (c *Conn) WriteTracks(videoTrack formats.Format, audioTrack formats.Format) return err } - if h264Track, ok := videoTrack.(*formats.H264); ok { - sps, pps := h264Track.SafeParams() - + if videoTrack, ok := videoTrack.(*formats.H264); ok { // 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 { + if sps, pps := videoTrack.SafeParams(); sps != nil && pps != nil { buf, _ := h264conf.Conf{ SPS: sps, PPS: pps, @@ -968,8 +962,9 @@ func (c *Conn) WriteTracks(videoTrack formats.Format, audioTrack formats.Format) err = c.WriteMessage(&message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_SEQHDR, + Type: message.MsgVideoTypeConfig, Payload: buf, }) if err != nil { @@ -991,7 +986,7 @@ func (c *Conn) WriteTracks(videoTrack formats.Format, audioTrack formats.Format) Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_SEQHDR, + AACType: message.MsgAudioAACTypeConfig, Payload: enc, }) if err != nil { diff --git a/internal/rtmp/conn_test.go b/internal/rtmp/conn_test.go index 60ec26b7..7e0cd00d 100644 --- a/internal/rtmp/conn_test.go +++ b/internal/rtmp/conn_test.go @@ -793,7 +793,7 @@ func TestReadTracks(t *testing.T) { }, { K: "videocodecid", - V: float64(codecH264), + V: float64(message.CodecH264), }, { K: "audiodatarate", @@ -816,8 +816,9 @@ func TestReadTracks(t *testing.T) { err = mrw.Write(&message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_SEQHDR, + Type: message.MsgVideoTypeConfig, Payload: buf, }) require.NoError(t, err) @@ -836,7 +837,7 @@ func TestReadTracks(t *testing.T) { Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_SEQHDR, + AACType: message.MsgAudioAACTypeConfig, Payload: enc, }) require.NoError(t, err) @@ -855,7 +856,7 @@ func TestReadTracks(t *testing.T) { }, { K: "videocodecid", - V: float64(codecH264), + V: float64(message.CodecH264), }, { K: "audiodatarate", @@ -878,8 +879,9 @@ func TestReadTracks(t *testing.T) { err = mrw.Write(&message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_SEQHDR, + Type: message.MsgVideoTypeConfig, Payload: buf, }) require.NoError(t, err) @@ -917,8 +919,9 @@ func TestReadTracks(t *testing.T) { err = mrw.Write(&message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_SEQHDR, + Type: message.MsgVideoTypeConfig, Payload: buf, }) require.NoError(t, err) @@ -937,7 +940,7 @@ func TestReadTracks(t *testing.T) { Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_SEQHDR, + AACType: message.MsgAudioAACTypeConfig, Payload: enc, }) require.NoError(t, err) @@ -951,8 +954,9 @@ func TestReadTracks(t *testing.T) { err = mrw.Write(&message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_SEQHDR, + Type: message.MsgVideoTypeConfig, Payload: buf, }) require.NoError(t, err) @@ -971,7 +975,7 @@ func TestReadTracks(t *testing.T) { Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_SEQHDR, + AACType: message.MsgAudioAACTypeConfig, Payload: enc, }) require.NoError(t, err) @@ -991,7 +995,7 @@ func TestReadTracks(t *testing.T) { Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_SEQHDR, + AACType: message.MsgAudioAACTypeConfig, Payload: enc, }) require.NoError(t, err) @@ -1003,7 +1007,7 @@ func TestReadTracks(t *testing.T) { Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_SEQHDR, + AACType: message.MsgAudioAACTypeConfig, Payload: enc, DTS: 1 * time.Second, }) @@ -1023,7 +1027,7 @@ func TestReadTracks(t *testing.T) { }, { K: "videocodecid", - V: float64(codecH264), + V: float64(message.CodecH264), }, { K: "audiodatarate", @@ -1064,8 +1068,9 @@ func TestReadTracks(t *testing.T) { err = mrw.Write(&message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: 1, + Type: message.MsgVideoTypeAU, Payload: avcc, }) require.NoError(t, err) @@ -1084,7 +1089,7 @@ func TestReadTracks(t *testing.T) { Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_SEQHDR, + AACType: message.MsgAudioAACTypeConfig, Payload: enc, }) require.NoError(t, err) @@ -1364,8 +1369,9 @@ func TestWriteTracks(t *testing.T) { require.Equal(t, &message.MsgVideo{ ChunkStreamID: message.MsgVideoChunkStreamID, MessageStreamID: 0x1000000, + Codec: message.CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_SEQHDR, + Type: message.MsgVideoTypeConfig, Payload: []byte{ 0x1, 0x64, 0x0, 0xc, 0xff, 0xe1, 0x0, 0x15, 0x67, 0x64, 0x0, @@ -1385,7 +1391,7 @@ func TestWriteTracks(t *testing.T) { Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_SEQHDR, + AACType: message.MsgAudioAACTypeConfig, Payload: []byte{0x12, 0x10}, }, msg) } diff --git a/internal/rtmp/message/msg_audio.go b/internal/rtmp/message/msg_audio.go index 5a80b3e8..b5c8bc45 100644 --- a/internal/rtmp/message/msg_audio.go +++ b/internal/rtmp/message/msg_audio.go @@ -19,6 +19,15 @@ const ( CodecMPEG4Audio = 10 ) +// MsgAudioAACType is the AAC type of a MsgAudio. +type MsgAudioAACType uint8 + +// MsgAudioAACType values. +const ( + MsgAudioAACTypeConfig MsgAudioAACType = 0 + MsgAudioAACTypeAU MsgAudioAACType = 1 +) + // MsgAudio is an audio message. type MsgAudio struct { ChunkStreamID byte @@ -28,7 +37,7 @@ type MsgAudio struct { Rate uint8 Depth uint8 Channels uint8 - AACType uint8 // only for CodecMPEG4Audio + AACType MsgAudioAACType // only for CodecMPEG4Audio Payload []byte } @@ -56,7 +65,13 @@ func (m *MsgAudio) Unmarshal(raw *rawmessage.Message) error { if m.Codec == CodecMPEG2Audio { m.Payload = raw.Body[1:] } else { - m.AACType = raw.Body[1] + m.AACType = MsgAudioAACType(raw.Body[1]) + switch m.AACType { + case MsgAudioAACTypeConfig, MsgAudioAACTypeAU: + default: + return fmt.Errorf("unsupported audio message type: %d", m.AACType) + } + m.Payload = raw.Body[2:] } @@ -78,7 +93,7 @@ func (m MsgAudio) Marshal() (*rawmessage.Message, error) { if m.Codec == CodecMPEG2Audio { copy(body[1:], m.Payload) } else { - body[1] = m.AACType + body[1] = uint8(m.AACType) copy(body[2:], m.Payload) } diff --git a/internal/rtmp/message/msg_video.go b/internal/rtmp/message/msg_video.go index 963aeb95..c08447a5 100644 --- a/internal/rtmp/message/msg_video.go +++ b/internal/rtmp/message/msg_video.go @@ -15,13 +15,29 @@ const ( MsgVideoChunkStreamID = 6 ) +// supported video codecs +const ( + CodecH264 = 7 +) + +// MsgVideoType is the type of a video message. +type MsgVideoType uint8 + +// MsgVideoType values. +const ( + MsgVideoTypeConfig MsgVideoType = 0 + MsgVideoTypeAU MsgVideoType = 1 + MsgVideoTypeEOS MsgVideoType = 2 +) + // MsgVideo is a video message. type MsgVideo struct { ChunkStreamID byte DTS time.Duration MessageStreamID uint32 + Codec uint8 IsKeyFrame bool - H264Type uint8 + Type MsgVideoType PTSDelta time.Duration Payload []byte } @@ -38,12 +54,19 @@ func (m *MsgVideo) Unmarshal(raw *rawmessage.Message) error { m.IsKeyFrame = (raw.Body[0] >> 4) == flvio.FRAME_KEY - codec := raw.Body[0] & 0x0F - if codec != flvio.VIDEO_H264 { - return fmt.Errorf("unsupported video codec: %d", codec) + m.Codec = raw.Body[0] & 0x0F + switch m.Codec { + case CodecH264: + default: + return fmt.Errorf("unsupported video codec: %d", m.Codec) } - m.H264Type = raw.Body[1] + m.Type = MsgVideoType(raw.Body[1]) + switch m.Type { + case MsgVideoTypeConfig, MsgVideoTypeAU, MsgVideoTypeEOS: + default: + return fmt.Errorf("unsupported video message type: %d", m.Type) + } tmp := uint32(raw.Body[2])<<16 | uint32(raw.Body[3])<<8 | uint32(raw.Body[4]) m.PTSDelta = time.Duration(tmp) * time.Millisecond @@ -62,8 +85,8 @@ func (m MsgVideo) Marshal() (*rawmessage.Message, error) { } else { body[0] = flvio.FRAME_INTER << 4 } - body[0] |= flvio.VIDEO_H264 - body[1] = m.H264Type + body[0] |= m.Codec + body[1] = uint8(m.Type) tmp := uint32(m.PTSDelta / time.Millisecond) body[2] = uint8(tmp >> 16) diff --git a/internal/rtmp/message/reader_test.go b/internal/rtmp/message/reader_test.go index 2b5c3bc1..b067552f 100644 --- a/internal/rtmp/message/reader_test.go +++ b/internal/rtmp/message/reader_test.go @@ -53,7 +53,7 @@ var readWriterCases = []struct { Rate: flvio.SOUND_44Khz, Depth: flvio.SOUND_16BIT, Channels: flvio.SOUND_STEREO, - AACType: flvio.AAC_RAW, + AACType: MsgAudioAACTypeAU, Payload: []byte{0x5A, 0xC0, 0x77, 0x40}, }, []byte{ @@ -220,8 +220,9 @@ var readWriterCases = []struct { ChunkStreamID: 6, DTS: 2543534 * time.Millisecond, MessageStreamID: 0x1000000, + Codec: CodecH264, IsKeyFrame: true, - H264Type: flvio.AVC_SEQHDR, + Type: MsgVideoTypeConfig, PTSDelta: 10 * time.Millisecond, Payload: []byte{0x01, 0x02, 0x03}, },