Browse Source

fix compatibility with RTMP Dahua cameras (#2289) (#769) (#2298)

pull/2299/head
Alessandro Ros 2 years ago committed by GitHub
parent
commit
5b92bd5699
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      go.sum
  2. 130
      internal/rtmp/reader.go
  3. 702
      internal/rtmp/reader_test.go

2
go.sum

@ -254,6 +254,7 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -254,6 +254,7 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -265,6 +266,7 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= @@ -265,6 +266,7 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

130
internal/rtmp/reader.go

@ -2,7 +2,6 @@ package rtmp @@ -2,7 +2,6 @@ package rtmp
import (
"bytes"
"errors"
"fmt"
"time"
@ -33,6 +32,67 @@ type OnDataMPEG4AudioFunc func(pts time.Duration, au []byte) @@ -33,6 +32,67 @@ type OnDataMPEG4AudioFunc func(pts time.Duration, au []byte)
// OnDataMPEG1AudioFunc is the prototype of the callback passed to OnDataMPEG1Audio().
type OnDataMPEG1AudioFunc func(pts time.Duration, frame []byte)
func hasVideo(md flvio.AMFMap) (bool, error) {
v, ok := md.GetV("videocodecid")
if !ok {
// some Dahua cameras send width and height without videocodecid
if v, ok := md.GetV("width"); ok {
if vf, ok := v.(float64); ok && vf != 0 {
return true, nil
}
}
return false, nil
}
switch vt := v.(type) {
case float64:
switch vt {
case 0:
return false, nil
case message.CodecH264, float64(message.FourCCAV1),
float64(message.FourCCVP9), float64(message.FourCCHEVC):
return true, nil
}
case string:
if vt == "avc1" || vt == "hvc1" || vt == "av01" {
return true, nil
}
}
return false, fmt.Errorf("unsupported video codec: %v", v)
}
func hasAudio(md flvio.AMFMap, audioTrack *format.Format) (bool, error) {
v, ok := md.GetV("audiocodecid")
if !ok {
return false, nil
}
switch vt := v.(type) {
case float64:
switch vt {
case 0:
return false, nil
case message.CodecMPEG1Audio:
*audioTrack = &format.MPEG1Audio{}
return true, nil
case message.CodecMPEG4Audio:
return true, nil
}
case string:
if vt == "mp4a" {
return true, nil
}
}
return false, fmt.Errorf("unsupported audio codec %v", v)
}
func h265FindNALU(array []mp4.HEVCNaluArray, typ h265.NALUType) []byte {
for _, entry := range array {
if entry.NaluType == byte(typ) && entry.NumNalus == 1 &&
@ -74,8 +134,6 @@ func trackFromAACDecoderConfig(data []byte) (format.Format, error) { @@ -74,8 +134,6 @@ func trackFromAACDecoderConfig(data []byte) (format.Format, error) {
}, nil
}
var errEmptyMetadata = errors.New("metadata is empty")
func tracksFromMetadata(conn *Conn, payload []interface{}) (format.Format, format.Format, error) {
if len(payload) != 1 {
return nil, nil, fmt.Errorf("invalid metadata")
@ -89,69 +147,18 @@ func tracksFromMetadata(conn *Conn, payload []interface{}) (format.Format, forma @@ -89,69 +147,18 @@ func tracksFromMetadata(conn *Conn, payload []interface{}) (format.Format, forma
var videoTrack format.Format
var audioTrack format.Format
hasVideo, err := func() (bool, error) {
v, ok := md.GetV("videocodecid")
if !ok {
return false, nil
}
switch vt := v.(type) {
case float64:
switch vt {
case 0:
return false, nil
case message.CodecH264, float64(message.FourCCAV1),
float64(message.FourCCVP9), float64(message.FourCCHEVC):
return true, nil
}
case string:
if vt == "avc1" || vt == "hvc1" || vt == "av01" {
return true, nil
}
}
return false, fmt.Errorf("unsupported video codec: %v", v)
}()
hasVideo, err := hasVideo(md)
if err != nil {
return nil, nil, err
}
hasAudio, err := func() (bool, error) {
v, ok := md.GetV("audiocodecid")
if !ok {
return false, nil
}
switch vt := v.(type) {
case float64:
switch vt {
case 0:
return false, nil
case message.CodecMPEG1Audio:
audioTrack = &format.MPEG1Audio{}
return true, nil
case message.CodecMPEG4Audio:
return true, nil
}
case string:
if vt == "mp4a" {
return true, nil
}
}
return false, fmt.Errorf("unsupported audio codec %v", v)
}()
hasAudio, err := hasAudio(md, &audioTrack)
if err != nil {
return nil, nil, err
}
if !hasVideo && !hasAudio {
return nil, nil, errEmptyMetadata
return nil, nil, fmt.Errorf("metadata doesn't contain any track")
}
for {
@ -422,15 +429,6 @@ func (r *Reader) readTracks() (format.Format, format.Format, error) { @@ -422,15 +429,6 @@ func (r *Reader) readTracks() (format.Format, format.Format, error) {
if s, ok := payload[0].(string); ok && s == "onMetaData" {
videoTrack, audioTrack, err := tracksFromMetadata(r.conn, payload[1:])
if err != nil {
if err == errEmptyMetadata {
msg, err := r.conn.Read()
if err != nil {
return nil, nil, err
}
return tracksFromMessages(r.conn, msg)
}
return nil, nil, err
}

702
internal/rtmp/reader_test.go

@ -106,6 +106,7 @@ func TestReadTracks(t *testing.T) { @@ -106,6 +106,7 @@ func TestReadTracks(t *testing.T) {
name string
videoTrack format.Format
audioTrack format.Format
messages []message.Message
}{
{
"video+audio",
@ -126,138 +127,8 @@ func TestReadTracks(t *testing.T) { @@ -126,138 +127,8 @@ func TestReadTracks(t *testing.T) {
IndexLength: 3,
IndexDeltaLength: 3,
},
},
{
"video",
&format.H264{
PayloadTyp: 96,
SPS: h264SPS,
PPS: h264PPS,
PacketizationMode: 1,
},
nil,
},
{
"metadata without codec id, video+audio",
&format.H264{
PayloadTyp: 96,
SPS: h264SPS,
PPS: h264PPS,
PacketizationMode: 1,
},
&format.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
},
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
},
},
{
"metadata without codec id, video only",
&format.H264{
PayloadTyp: 96,
SPS: h264SPS,
PPS: h264PPS,
PacketizationMode: 1,
},
nil,
},
{
"missing metadata, video+audio",
&format.H264{
PayloadTyp: 96,
SPS: h264SPS,
PPS: h264PPS,
PacketizationMode: 1,
},
&format.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
},
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
},
},
{
"missing metadata, audio",
nil,
&format.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
},
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
},
},
{
"obs studio pre 29.1 h265",
&format.H265{
PayloadTyp: 96,
VPS: h265VPS,
SPS: h265SPS,
PPS: h265PPS,
},
&format.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
},
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
},
},
{
"xplit broadcaster",
&format.H265{
PayloadTyp: 96,
VPS: h265VPS,
SPS: h265SPS,
PPS: h265PPS,
},
nil,
},
{
"obs 30",
&format.H265{
PayloadTyp: 96,
VPS: h265VPS,
SPS: h265SPS,
PPS: h265PPS,
},
nil,
},
{
"ffmpeg av1",
&format.AV1{
PayloadTyp: 96,
},
nil,
},
} {
t.Run(ca.name, func(t *testing.T) {
var buf bytes.Buffer
bc := bytecounter.NewReadWriter(&buf)
mrw := message.NewReadWriter(bc, bc, true)
switch ca.name {
case "video+audio":
err := mrw.Write(&message.DataAMF0{
[]message.Message{
&message.DataAMF0{
ChunkStreamID: 4,
MessageStreamID: 1,
Payload: []interface{}{
@ -282,32 +153,22 @@ func TestReadTracks(t *testing.T) { @@ -282,32 +153,22 @@ func TestReadTracks(t *testing.T) {
},
},
},
})
require.NoError(t, err)
buf, _ := h264conf.Conf{
SPS: h264SPS,
PPS: h264PPS,
}.Marshal()
err = mrw.Write(&message.Video{
},
&message.Video{
ChunkStreamID: message.VideoChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecH264,
IsKeyFrame: true,
Type: message.VideoTypeConfig,
Payload: buf,
})
require.NoError(t, err)
enc, err := mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
err = mrw.Write(&message.Audio{
Payload: func() []byte {
buf, _ := h264conf.Conf{
SPS: h264SPS,
PPS: h264PPS,
}.Marshal()
return buf
}(),
},
&message.Audio{
ChunkStreamID: message.AudioChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecMPEG4Audio,
@ -315,12 +176,29 @@ func TestReadTracks(t *testing.T) { @@ -315,12 +176,29 @@ func TestReadTracks(t *testing.T) {
Depth: flvio.SOUND_16BIT,
Channels: flvio.SOUND_STEREO,
AACType: message.AudioAACTypeConfig,
Payload: enc,
})
require.NoError(t, err)
case "video":
err := mrw.Write(&message.DataAMF0{
Payload: func() []byte {
enc, err := mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
return enc
}(),
},
},
},
{
"video",
&format.H264{
PayloadTyp: 96,
SPS: h264SPS,
PPS: h264PPS,
PacketizationMode: 1,
},
nil,
[]message.Message{
&message.DataAMF0{
ChunkStreamID: 4,
MessageStreamID: 1,
Payload: []interface{}{
@ -345,158 +223,72 @@ func TestReadTracks(t *testing.T) { @@ -345,158 +223,72 @@ func TestReadTracks(t *testing.T) {
},
},
},
})
require.NoError(t, err)
buf, _ := h264conf.Conf{
SPS: h264SPS,
PPS: h264PPS,
}.Marshal()
err = mrw.Write(&message.Video{
ChunkStreamID: message.VideoChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecH264,
IsKeyFrame: true,
Type: message.VideoTypeConfig,
Payload: buf,
})
require.NoError(t, err)
case "metadata without codec id, video+audio":
err := mrw.Write(&message.DataAMF0{
ChunkStreamID: 4,
MessageStreamID: 1,
Payload: []interface{}{
"@setDataFrame",
"onMetaData",
flvio.AMFMap{
{
K: "width",
V: float64(2688),
},
{
K: "height",
V: float64(1520),
},
{
K: "framerate",
V: float64(0o25),
},
},
},
})
require.NoError(t, err)
buf, _ := h264conf.Conf{
SPS: h264SPS,
PPS: h264PPS,
}.Marshal()
err = mrw.Write(&message.Video{
},
&message.Video{
ChunkStreamID: message.VideoChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecH264,
IsKeyFrame: true,
Type: message.VideoTypeConfig,
Payload: buf,
})
require.NoError(t, err)
enc, err := mpeg4audio.Config{
Payload: func() []byte {
buf, _ := h264conf.Conf{
SPS: h264SPS,
PPS: h264PPS,
}.Marshal()
return buf
}(),
},
},
},
{
"issue mediamtx/386 (missing metadata), video+audio",
&format.H264{
PayloadTyp: 96,
SPS: h264SPS,
PPS: h264PPS,
PacketizationMode: 1,
},
&format.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
err = mrw.Write(&message.Audio{
ChunkStreamID: message.AudioChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecMPEG4Audio,
Rate: flvio.SOUND_44Khz,
Depth: flvio.SOUND_16BIT,
Channels: flvio.SOUND_STEREO,
AACType: message.AudioAACTypeConfig,
Payload: enc,
})
require.NoError(t, err)
case "metadata without codec id, video only":
err := mrw.Write(&message.DataAMF0{
ChunkStreamID: 4,
MessageStreamID: 1,
Payload: []interface{}{
"@setDataFrame",
"onMetaData",
flvio.AMFMap{
{
K: "width",
V: float64(2688),
},
{
K: "height",
V: float64(1520),
},
{
K: "framerate",
V: float64(0o25),
},
},
},
})
require.NoError(t, err)
buf, _ := h264conf.Conf{
SPS: h264SPS,
PPS: h264PPS,
}.Marshal()
err = mrw.Write(&message.Video{
},
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
},
[]message.Message{
&message.Video{
ChunkStreamID: message.VideoChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecH264,
IsKeyFrame: true,
Type: message.VideoTypeConfig,
Payload: buf,
})
require.NoError(t, err)
err = mrw.Write(&message.Video{
ChunkStreamID: message.VideoChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecH264,
IsKeyFrame: true,
Type: message.VideoTypeAU,
Payload: []byte{0x01, 0x02, 0x03, 0x04},
DTS: 1 * time.Second,
})
require.NoError(t, err)
case "missing metadata, video+audio":
buf, _ := h264conf.Conf{
SPS: h264SPS,
PPS: h264PPS,
}.Marshal()
err := mrw.Write(&message.Video{
Payload: func() []byte {
buf, _ := h264conf.Conf{
SPS: h264SPS,
PPS: h264PPS,
}.Marshal()
return buf
}(),
},
&message.Video{
ChunkStreamID: message.VideoChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecH264,
IsKeyFrame: true,
Type: message.VideoTypeConfig,
Payload: buf,
})
require.NoError(t, err)
enc, err := mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
err = mrw.Write(&message.Audio{
Payload: func() []byte {
buf, _ := h264conf.Conf{
SPS: h264SPS,
PPS: h264PPS,
}.Marshal()
return buf
}(),
},
&message.Audio{
ChunkStreamID: message.AudioChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecMPEG4Audio,
@ -504,19 +296,34 @@ func TestReadTracks(t *testing.T) { @@ -504,19 +296,34 @@ func TestReadTracks(t *testing.T) {
Depth: flvio.SOUND_16BIT,
Channels: flvio.SOUND_STEREO,
AACType: message.AudioAACTypeConfig,
Payload: enc,
})
require.NoError(t, err)
case "missing metadata, audio":
enc, err := mpeg4audio.Config{
Payload: func() []byte {
enc, err := mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
return enc
}(),
},
},
},
{
"issue mediamtx/386 (missing metadata), audio",
nil,
&format.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
err = mrw.Write(&message.Audio{
},
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
},
[]message.Message{
&message.Audio{
ChunkStreamID: message.AudioChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecMPEG4Audio,
@ -524,11 +331,17 @@ func TestReadTracks(t *testing.T) { @@ -524,11 +331,17 @@ func TestReadTracks(t *testing.T) {
Depth: flvio.SOUND_16BIT,
Channels: flvio.SOUND_STEREO,
AACType: message.AudioAACTypeConfig,
Payload: enc,
})
require.NoError(t, err)
err = mrw.Write(&message.Audio{
Payload: func() []byte {
enc, err := mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
return enc
}(),
},
&message.Audio{
ChunkStreamID: message.AudioChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecMPEG4Audio,
@ -536,13 +349,40 @@ func TestReadTracks(t *testing.T) { @@ -536,13 +349,40 @@ func TestReadTracks(t *testing.T) {
Depth: flvio.SOUND_16BIT,
Channels: flvio.SOUND_STEREO,
AACType: message.AudioAACTypeConfig,
Payload: enc,
DTS: 1 * time.Second,
})
require.NoError(t, err)
case "obs studio pre 29.1 h265":
err := mrw.Write(&message.DataAMF0{
Payload: func() []byte {
enc, err := mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
return enc
}(),
DTS: 1 * time.Second,
},
},
},
{
"obs studio pre 29.1 h265",
&format.H265{
PayloadTyp: 96,
VPS: h265VPS,
SPS: h265SPS,
PPS: h265PPS,
},
&format.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
},
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
},
[]message.Message{
&message.DataAMF0{
ChunkStreamID: 4,
MessageStreamID: 1,
Payload: []interface{}{
@ -567,34 +407,24 @@ func TestReadTracks(t *testing.T) { @@ -567,34 +407,24 @@ func TestReadTracks(t *testing.T) {
},
},
},
})
require.NoError(t, err)
avcc, err := h264.AVCCMarshal([][]byte{
h265VPS,
h265SPS,
h265PPS,
})
require.NoError(t, err)
err = mrw.Write(&message.Video{
},
&message.Video{
ChunkStreamID: message.VideoChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecH264,
IsKeyFrame: true,
Type: message.VideoTypeAU,
Payload: avcc,
})
require.NoError(t, err)
enc, err := mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
err = mrw.Write(&message.Audio{
Payload: func() []byte {
avcc, err := h264.AVCCMarshal([][]byte{
h265VPS,
h265SPS,
h265PPS,
})
require.NoError(t, err)
return avcc
}(),
},
&message.Audio{
ChunkStreamID: message.AudioChunkStreamID,
MessageStreamID: 0x1000000,
Codec: message.CodecMPEG4Audio,
@ -602,12 +432,29 @@ func TestReadTracks(t *testing.T) { @@ -602,12 +432,29 @@ func TestReadTracks(t *testing.T) {
Depth: flvio.SOUND_16BIT,
Channels: flvio.SOUND_STEREO,
AACType: message.AudioAACTypeConfig,
Payload: enc,
})
require.NoError(t, err)
case "xplit broadcaster":
err := mrw.Write(&message.DataAMF0{
Payload: func() []byte {
enc, err := mpeg4audio.Config{
Type: 2,
SampleRate: 44100,
ChannelCount: 2,
}.Marshal()
require.NoError(t, err)
return enc
}(),
},
},
},
{
"issue mediamtx/2232 (xsplit broadcaster)",
&format.H265{
PayloadTyp: 96,
VPS: h265VPS,
SPS: h265SPS,
PPS: h265PPS,
},
nil,
[]message.Message{
&message.DataAMF0{
ChunkStreamID: 4,
MessageStreamID: 1,
Payload: []interface{}{
@ -632,23 +479,31 @@ func TestReadTracks(t *testing.T) { @@ -632,23 +479,31 @@ func TestReadTracks(t *testing.T) {
},
},
},
})
require.NoError(t, err)
var buf bytes.Buffer
_, err = mp4.Marshal(&buf, hvcc, mp4.Context{})
require.NoError(t, err)
err = mrw.Write(&message.ExtendedSequenceStart{
},
&message.ExtendedSequenceStart{
ChunkStreamID: 4,
MessageStreamID: 0x1000000,
FourCC: message.FourCCHEVC,
Config: buf.Bytes(),
})
require.NoError(t, err)
case "obs 30":
err := mrw.Write(&message.DataAMF0{
Config: func() []byte {
var buf bytes.Buffer
_, err = mp4.Marshal(&buf, hvcc, mp4.Context{})
require.NoError(t, err)
return buf.Bytes()
}(),
},
},
},
{
"obs 30",
&format.H265{
PayloadTyp: 96,
VPS: h265VPS,
SPS: h265SPS,
PPS: h265PPS,
},
nil,
[]message.Message{
&message.DataAMF0{
ChunkStreamID: 4,
MessageStreamID: 1,
Payload: []interface{}{
@ -673,23 +528,28 @@ func TestReadTracks(t *testing.T) { @@ -673,23 +528,28 @@ func TestReadTracks(t *testing.T) {
},
},
},
})
require.NoError(t, err)
var buf bytes.Buffer
_, err = mp4.Marshal(&buf, hvcc, mp4.Context{})
require.NoError(t, err)
err = mrw.Write(&message.ExtendedSequenceStart{
},
&message.ExtendedSequenceStart{
ChunkStreamID: 4,
MessageStreamID: 0x1000000,
FourCC: message.FourCCHEVC,
Config: buf.Bytes(),
})
require.NoError(t, err)
case "ffmpeg av1":
err := mrw.Write(&message.DataAMF0{
Config: func() []byte {
var buf bytes.Buffer
_, err = mp4.Marshal(&buf, hvcc, mp4.Context{})
require.NoError(t, err)
return buf.Bytes()
}(),
},
},
},
{
"ffmpeg av1",
&format.AV1{
PayloadTyp: 96,
},
nil,
[]message.Message{
&message.DataAMF0{
ChunkStreamID: 4,
MessageStreamID: 1,
Payload: []interface{}{
@ -730,14 +590,8 @@ func TestReadTracks(t *testing.T) { @@ -730,14 +590,8 @@ func TestReadTracks(t *testing.T) {
},
},
},
})
require.NoError(t, err)
var buf bytes.Buffer
_, err = mp4.Marshal(&buf, hvcc, mp4.Context{})
require.NoError(t, err)
err = mrw.Write(&message.ExtendedSequenceStart{
},
&message.ExtendedSequenceStart{
ChunkStreamID: 6,
MessageStreamID: 0x1000000,
FourCC: message.FourCCAV1,
@ -746,7 +600,93 @@ func TestReadTracks(t *testing.T) { @@ -746,7 +600,93 @@ func TestReadTracks(t *testing.T) {
0x00, 0x42, 0xab, 0xbf, 0xc3, 0x70, 0x0b, 0xe0,
0x01,
},
})
},
},
},
{
"issue mediamtx/2289 (missing videocodecid)",
&format.H264{
PayloadTyp: 96,
SPS: []byte{
0x67, 0x64, 0x00, 0x1f, 0xac, 0x2c, 0x6a, 0x81,
0x40, 0x16, 0xe9, 0xb8, 0x28, 0x08, 0x2a, 0x00,
0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00,
0xc9, 0x08,
},
PPS: []byte{0x68, 0xee, 0x31, 0xb2, 0x1b},
PacketizationMode: 1,
},
&format.MPEG4Audio{
PayloadTyp: 96,
Config: &mpeg4audio.Config{
Type: 2,
SampleRate: 48000,
ChannelCount: 1,
},
SizeLength: 13,
IndexLength: 3,
IndexDeltaLength: 3,
},
[]message.Message{
&message.DataAMF0{
ChunkStreamID: 4,
MessageStreamID: 1,
Payload: []interface{}{
"@setDataFrame",
"onMetaData",
flvio.AMFMap{
{
K: "width",
V: float64(1280),
},
{
K: "height",
V: float64(720),
},
{
K: "framerate",
V: float64(30),
},
{
K: "audiocodecid",
V: float64(10),
},
},
},
},
&message.Video{
ChunkStreamID: 0x15,
MessageStreamID: 0x1000000,
Codec: 0x7,
IsKeyFrame: true,
Payload: []uint8{
0x01, 0x64, 0x00, 0x1f, 0xff, 0xe1, 0x00, 0x1a,
0x67, 0x64, 0x00, 0x1f, 0xac, 0x2c, 0x6a, 0x81,
0x40, 0x16, 0xe9, 0xb8, 0x28, 0x08, 0x2a, 0x00,
0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00,
0xc9, 0x08, 0x01, 0x00, 0x05, 0x68, 0xee, 0x31,
0xb2, 0x1b,
},
},
&message.Audio{
ChunkStreamID: 0x14,
MessageStreamID: 0x1000000,
Codec: 0xa,
Rate: 0x3,
Depth: 0x1,
Channels: 0x1,
Payload: []uint8{0x11, 0x88},
},
},
},
} {
t.Run(ca.name, func(t *testing.T) {
var buf bytes.Buffer
bc := bytecounter.NewReadWriter(&buf)
mrw := message.NewReadWriter(bc, bc, true)
for _, msg := range ca.messages {
err := mrw.Write(msg)
require.NoError(t, err)
}

Loading…
Cancel
Save