diff --git a/api/openapi.yaml b/api/openapi.yaml index 5342f763..65f455cd 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -65,13 +65,13 @@ components: - H265 - H264 - MPEG-4 Video - - MPEG-1 Video - - MJPEG + - MPEG-1/2 Video + - M-JPEG - Opus - Vorbis - MPEG-4 Audio - MPEG-4 Audio LATM - - MPEG-1 Audio + - MPEG-1/2 Audio - AC3 - Speex - G726 diff --git a/internal/api/api_paths_test.go b/internal/api/api_paths_test.go index 0f1a36c9..a5d4ee74 100644 --- a/internal/api/api_paths_test.go +++ b/internal/api/api_paths_test.go @@ -7,6 +7,7 @@ import ( "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/defs" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/test" "github.com/stretchr/testify/require" ) @@ -41,7 +42,7 @@ func TestPathsList(t *testing.T) { Source: &defs.APIPathSource{Type: defs.APIPathSourceTypeRTSPSession, ID: "pub1"}, Ready: true, ReadyTime: &now, - Tracks: []defs.APIPathTrackCodec{defs.APIPathTrackCodecH264, defs.APIPathTrackCodecOpus}, + Tracks: []defs.APIPathTrackCodec{formatlabel.H264, formatlabel.Opus}, InboundBytes: 1000, OutboundBytes: 2000, InboundFramesInError: 3, @@ -100,7 +101,7 @@ func TestPathsGet(t *testing.T) { Source: &defs.APIPathSource{Type: defs.APIPathSourceTypeRTSPSession, ID: "session123"}, Ready: true, ReadyTime: &now, - Tracks: []defs.APIPathTrackCodec{defs.APIPathTrackCodecH264, defs.APIPathTrackCodecOpus}, + Tracks: []defs.APIPathTrackCodec{formatlabel.H264, formatlabel.Opus}, InboundBytes: 123456, OutboundBytes: 789012, InboundFramesInError: 12, diff --git a/internal/core/api_test.go b/internal/core/api_test.go index 87d717b6..3db5ff08 100644 --- a/internal/core/api_test.go +++ b/internal/core/api_test.go @@ -27,6 +27,7 @@ import ( "github.com/stretchr/testify/require" "github.com/bluenviron/mediamtx/internal/defs" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/protocols/webrtc" "github.com/bluenviron/mediamtx/internal/protocols/whip" "github.com/bluenviron/mediamtx/internal/test" @@ -140,7 +141,7 @@ func TestAPIPathsList(t *testing.T) { Type: "rtspSession", }, Ready: true, - Tracks: []defs.APIPathTrackCodec{defs.APIPathTrackCodecH264, defs.APIPathTrackCodecMPEG4Audio}, + Tracks: []defs.APIPathTrackCodec{formatlabel.H264, formatlabel.MPEG4Audio}, InboundBytes: 17, InboundFramesInError: 0, BytesReceived: 17, @@ -190,7 +191,7 @@ func TestAPIPathsList(t *testing.T) { Type: "rtspsSession", }, Ready: true, - Tracks: []defs.APIPathTrackCodec{defs.APIPathTrackCodecH264, defs.APIPathTrackCodecMPEG4Audio}, + Tracks: []defs.APIPathTrackCodec{formatlabel.H264, formatlabel.MPEG4Audio}, }}, }, out) }) @@ -338,7 +339,7 @@ func TestAPIPathsGet(t *testing.T) { Type: "rtspSession", }, Ready: true, - Tracks: []defs.APIPathTrackCodec{defs.APIPathTrackCodecH264}, + Tracks: []defs.APIPathTrackCodec{formatlabel.H264}, }, out) } else { res, err := hc.Get("http://localhost:9997/v3/paths/get/" + pathName) diff --git a/internal/core/path.go b/internal/core/path.go index 2e0e1296..3bfdbfd3 100644 --- a/internal/core/path.go +++ b/internal/core/path.go @@ -14,6 +14,7 @@ import ( "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/defs" "github.com/bluenviron/mediamtx/internal/externalcmd" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/hooks" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/recorder" @@ -659,7 +660,7 @@ func (pa *path) doAPIPathsGet(req pathAPIPathsGetReq) { if !pa.isAvailable() { return []defs.APIPathTrackCodec{} } - return defs.MediasToCodecs(pa.stream.Desc.Medias) + return formatlabel.MediasToLabels(pa.stream.Desc.Medias) }(), Tracks2: func() []defs.APIPathTrack { if !pa.isAvailable() { diff --git a/internal/defs/api_path_track.go b/internal/defs/api_path_track.go index 3caca9d2..4e893ae2 100644 --- a/internal/defs/api_path_track.go +++ b/internal/defs/api_path_track.go @@ -1,7 +1,56 @@ package defs +import ( + "github.com/bluenviron/gortsplib/v5/pkg/description" + "github.com/bluenviron/gortsplib/v5/pkg/format" + "github.com/bluenviron/mediamtx/internal/formatlabel" +) + // APIPathTrack is a track. type APIPathTrack struct { Codec APIPathTrackCodec `json:"codec"` CodecProps APIPathTrackCodecProps `json:"codecProps"` } + +func formatToTrack(forma format.Format) APIPathTrack { + return APIPathTrack{ + Codec: formatlabel.FormatToLabel(forma), + CodecProps: formatToTrackCodecProps(forma), + } +} + +func gatherFormats(medias []*description.Media) []format.Format { + n := 0 + for _, media := range medias { + n += len(media.Formats) + } + + if n == 0 { + return nil + } + + formats := make([]format.Format, n) + n = 0 + + for _, media := range medias { + n += copy(formats[n:], media.Formats) + } + + return formats +} + +// FormatsToTracks returns tracks of given formats. +func FormatsToTracks(formats []format.Format) []APIPathTrack { + ret := make([]APIPathTrack, len(formats)) + + for i, forma := range formats { + ret[i] = formatToTrack(forma) + } + + return ret +} + +// MediasToTracks returns tracks of given medias. +func MediasToTracks(medias []*description.Media) []APIPathTrack { + return FormatsToTracks(gatherFormats(medias)) +} diff --git a/internal/defs/api_path_track_codec.go b/internal/defs/api_path_track_codec.go index 6934a602..ccfe43bb 100644 --- a/internal/defs/api_path_track_codec.go +++ b/internal/defs/api_path_track_codec.go @@ -1,317 +1,6 @@ package defs -import ( - "fmt" - "strconv" +import "github.com/bluenviron/mediamtx/internal/formatlabel" - "github.com/bluenviron/gortsplib/v5/pkg/description" - "github.com/bluenviron/gortsplib/v5/pkg/format" - codecsh264 "github.com/bluenviron/mediacommon/v2/pkg/codecs/h264" - codecsh265 "github.com/bluenviron/mediacommon/v2/pkg/codecs/h265" -) - -// APIPathTrackCodec is a path track codec. -type APIPathTrackCodec string - -// path track codecs. -const ( - // video - APIPathTrackCodecAV1 APIPathTrackCodec = "AV1" - APIPathTrackCodecVP9 APIPathTrackCodec = "VP9" - APIPathTrackCodecVP8 APIPathTrackCodec = "VP8" - APIPathTrackCodecH265 APIPathTrackCodec = "H265" - APIPathTrackCodecH264 APIPathTrackCodec = "H264" - APIPathTrackCodecMPEG4Video APIPathTrackCodec = "MPEG-4 Video" - APIPathTrackCodecMPEG1Video APIPathTrackCodec = "MPEG-1 Video" - APIPathTrackCodecMJPEG APIPathTrackCodec = "MJPEG" - // audio - APIPathTrackCodecOpus APIPathTrackCodec = "Opus" - APIPathTrackCodecVorbis APIPathTrackCodec = "Vorbis" - APIPathTrackCodecMPEG4Audio APIPathTrackCodec = "MPEG-4 Audio" - APIPathTrackCodecMPEG4AudioLATM APIPathTrackCodec = "MPEG-4 Audio LATM" - APIPathTrackCodecMPEG1Audio APIPathTrackCodec = "MPEG-1 Audio" - APIPathTrackCodecAC3 APIPathTrackCodec = "AC3" - APIPathTrackCodecSpeex APIPathTrackCodec = "Speex" - APIPathTrackCodecG726 APIPathTrackCodec = "G726" - APIPathTrackCodecG722 APIPathTrackCodec = "G722" - APIPathTrackCodecG711 APIPathTrackCodec = "G711" - APIPathTrackCodecLPCM APIPathTrackCodec = "LPCM" - // other - APIPathTrackCodecMPEGTS APIPathTrackCodec = "MPEG-TS" - APIPathTrackCodecKLV APIPathTrackCodec = "KLV" - APIPathTrackCodecGeneric APIPathTrackCodec = "Generic" -) - -func formatToCodec(forma format.Format) APIPathTrackCodec { - switch forma.(type) { - // video - case *format.AV1: - return APIPathTrackCodecAV1 - case *format.VP9: - return APIPathTrackCodecVP9 - case *format.VP8: - return APIPathTrackCodecVP8 - case *format.H265: - return APIPathTrackCodecH265 - case *format.H264: - return APIPathTrackCodecH264 - case *format.MPEG4Video: - return APIPathTrackCodecMPEG4Video - case *format.MPEG1Video: - return APIPathTrackCodecMPEG1Video - case *format.MJPEG: - return APIPathTrackCodecMJPEG - // audio - case *format.Opus: - return APIPathTrackCodecOpus - case *format.Vorbis: - return APIPathTrackCodecVorbis - case *format.MPEG4Audio: - return APIPathTrackCodecMPEG4Audio - case *format.MPEG4AudioLATM: - return APIPathTrackCodecMPEG4AudioLATM - case *format.MPEG1Audio: - return APIPathTrackCodecMPEG1Audio - case *format.AC3: - return APIPathTrackCodecAC3 - case *format.Speex: - return APIPathTrackCodecSpeex - case *format.G726: - return APIPathTrackCodecG726 - case *format.G722: - return APIPathTrackCodecG722 - case *format.G711: - return APIPathTrackCodecG711 - case *format.LPCM: - return APIPathTrackCodecLPCM - // other - case *format.MPEGTS: - return APIPathTrackCodecMPEGTS - case *format.KLV: - return APIPathTrackCodecKLV - default: - return APIPathTrackCodecGeneric - } -} - -func h264ProfileString(profileIdc uint8) string { - switch profileIdc { - case 66: - return "Baseline" - case 77: - return "Main" - case 88: - return "Extended" - case 100: - return "High" - case 110: - return "High 10" - case 122: - return "High 4:2:2" - case 244: - return "High 4:4:4 Predictive" - default: - return strconv.Itoa(int(profileIdc)) - } -} - -func h264LevelString(levelIdc uint8) string { - major := levelIdc / 10 - minor := levelIdc % 10 - if minor == 0 { - return fmt.Sprintf("%d", major) - } - return fmt.Sprintf("%d.%d", major, minor) -} - -func h265ProfileString(profileIdc uint8) string { - switch profileIdc { - case 1: - return "Main" - case 2: - return "Main 10" - case 3: - return "Main Still Picture" - case 4: - return "Range Extensions" - case 5: - return "High Throughput" - case 6: - return "Multiview Main" - case 7: - return "Scalable Main" - case 8: - return "3D Main" - case 9: - return "Screen Content Coding Extensions" - case 10: - return "Scalable Range Extensions" - default: - return strconv.Itoa(int(profileIdc)) - } -} - -func h265LevelString(levelIdc uint8) string { - // H.265 level_idc = 30 * level, so 3.0 = 90, 4.0 = 120, 4.1 = 123 - level := float64(levelIdc) / 30.0 - // Check if it's a clean level like 3.0, 4.0 - if levelIdc%30 == 0 { - return fmt.Sprintf("%.0f", level) - } - return fmt.Sprintf("%.1f", level) -} - -// FormatsToCodecs returns codecs of given formats. -func FormatsToCodecs(formats []format.Format) []APIPathTrackCodec { - ret := make([]APIPathTrackCodec, len(formats)) - for i, forma := range formats { - ret[i] = formatToCodec(forma) - } - return ret -} - -func formatToTrack(forma format.Format) APIPathTrack { - return APIPathTrack{ - Codec: formatToCodec(forma), - CodecProps: formatToTrackCodecProps(forma), - } -} - -func formatToTrackCodecProps(forma format.Format) APIPathTrackCodecProps { - switch forma := forma.(type) { - case *format.AV1: - props := &APIPathTrackCodecPropsAV1{} - - if forma.Profile != nil { - props.Profile = *forma.Profile - } - if forma.LevelIdx != nil { - props.Level = *forma.LevelIdx - } - if forma.Tier != nil { - props.Tier = *forma.Tier - } - - return props - - case *format.VP9: - props := &APIPathTrackCodecPropsVP9{} - - if forma.ProfileID != nil { - props.Profile = *forma.ProfileID - } - - return props - - case *format.H265: - props := &APIPathTrackCodecPropsH265{} - - _, sps, _ := forma.SafeParams() - if sps != nil { - var s codecsh265.SPS - if err := s.Unmarshal(sps); err == nil { - props.Width = s.Width() - props.Height = s.Height() - props.Profile = h265ProfileString(s.ProfileTierLevel.GeneralProfileIdc) - props.Level = h265LevelString(s.ProfileTierLevel.GeneralLevelIdc) - } - } - - return props - - case *format.H264: - props := &APIPathTrackCodecPropsH264{} - - sps, _ := forma.SafeParams() - if sps != nil { - var s codecsh264.SPS - if err := s.Unmarshal(sps); err == nil { - props.Width = s.Width() - props.Height = s.Height() - props.Profile = h264ProfileString(s.ProfileIdc) - props.Level = h264LevelString(s.LevelIdc) - } - } - - return props - - case *format.Opus: - return &APIPathTrackCodecPropsOpus{ - ChannelCount: forma.ChannelCount, - } - - case *format.MPEG4Audio: - props := &APIPathTrackCodecPropsMPEG4Audio{} - - if forma.Config != nil { - props.SampleRate = forma.Config.SampleRate - props.ChannelCount = int(forma.Config.ChannelConfig) - } - - return props - - case *format.AC3: - return &APIPathTrackCodecPropsAC3{ - SampleRate: forma.SampleRate, - ChannelCount: forma.ChannelCount, - } - - case *format.G711: - return &APIPathTrackCodecPropsG711{ - MULaw: forma.MULaw, - SampleRate: forma.SampleRate, - ChannelCount: forma.ChannelCount, - } - - case *format.LPCM: - return &APIPathTrackCodecPropsLPCM{ - BitDepth: forma.BitDepth, - SampleRate: forma.SampleRate, - ChannelCount: forma.ChannelCount, - } - - default: - return nil - } -} - -func gatherFormats(medias []*description.Media) []format.Format { - n := 0 - for _, media := range medias { - n += len(media.Formats) - } - - if n == 0 { - return nil - } - - formats := make([]format.Format, n) - n = 0 - - for _, media := range medias { - n += copy(formats[n:], media.Formats) - } - - return formats -} - -// MediasToCodecs returns codecs of given medias. -func MediasToCodecs(medias []*description.Media) []APIPathTrackCodec { - return FormatsToCodecs(gatherFormats(medias)) -} - -// FormatsToTracks returns tracks of given formats. -func FormatsToTracks(formats []format.Format) []APIPathTrack { - ret := make([]APIPathTrack, len(formats)) - - for i, forma := range formats { - ret[i] = formatToTrack(forma) - } - - return ret -} - -// MediasToTracks returns tracks of given medias. -func MediasToTracks(medias []*description.Media) []APIPathTrack { - return FormatsToTracks(gatherFormats(medias)) -} +// APIPathTrackCodec is a track codec. +type APIPathTrackCodec = formatlabel.Label diff --git a/internal/defs/api_path_track_codec_props.go b/internal/defs/api_path_track_codec_props.go index 5f183e00..0bec31e9 100644 --- a/internal/defs/api_path_track_codec_props.go +++ b/internal/defs/api_path_track_codec_props.go @@ -1,5 +1,14 @@ package defs +import ( + "fmt" + "strconv" + + "github.com/bluenviron/gortsplib/v5/pkg/format" + codecsh264 "github.com/bluenviron/mediacommon/v2/pkg/codecs/h264" + codecsh265 "github.com/bluenviron/mediacommon/v2/pkg/codecs/h265" +) + // APIPathTrackCodecProps contains codec-specific properties. type APIPathTrackCodecProps interface { apiPathTrackCodecProps() @@ -83,3 +92,168 @@ type APIPathTrackCodecPropsLPCM struct { } func (*APIPathTrackCodecPropsLPCM) apiPathTrackCodecProps() {} + +func h264ProfileString(profileIdc uint8) string { + switch profileIdc { + case 66: + return "Baseline" + case 77: + return "Main" + case 88: + return "Extended" + case 100: + return "High" + case 110: + return "High 10" + case 122: + return "High 4:2:2" + case 244: + return "High 4:4:4 Predictive" + default: + return strconv.Itoa(int(profileIdc)) + } +} + +func h264LevelString(levelIdc uint8) string { + major := levelIdc / 10 + minor := levelIdc % 10 + if minor == 0 { + return fmt.Sprintf("%d", major) + } + return fmt.Sprintf("%d.%d", major, minor) +} + +func h265ProfileString(profileIdc uint8) string { + switch profileIdc { + case 1: + return "Main" + case 2: + return "Main 10" + case 3: + return "Main Still Picture" + case 4: + return "Range Extensions" + case 5: + return "High Throughput" + case 6: + return "Multiview Main" + case 7: + return "Scalable Main" + case 8: + return "3D Main" + case 9: + return "Screen Content Coding Extensions" + case 10: + return "Scalable Range Extensions" + default: + return strconv.Itoa(int(profileIdc)) + } +} + +func h265LevelString(levelIdc uint8) string { + // H.265 level_idc = 30 * level, so 3.0 = 90, 4.0 = 120, 4.1 = 123 + level := float64(levelIdc) / 30.0 + // Check if it's a clean level like 3.0, 4.0 + if levelIdc%30 == 0 { + return fmt.Sprintf("%.0f", level) + } + return fmt.Sprintf("%.1f", level) +} + +func formatToTrackCodecProps(forma format.Format) APIPathTrackCodecProps { + switch forma := forma.(type) { + case *format.AV1: + props := &APIPathTrackCodecPropsAV1{} + + if forma.Profile != nil { + props.Profile = *forma.Profile + } + if forma.LevelIdx != nil { + props.Level = *forma.LevelIdx + } + if forma.Tier != nil { + props.Tier = *forma.Tier + } + + return props + + case *format.VP9: + props := &APIPathTrackCodecPropsVP9{} + + if forma.ProfileID != nil { + props.Profile = *forma.ProfileID + } + + return props + + case *format.H265: + props := &APIPathTrackCodecPropsH265{} + + _, sps, _ := forma.SafeParams() + if sps != nil { + var s codecsh265.SPS + if err := s.Unmarshal(sps); err == nil { + props.Width = s.Width() + props.Height = s.Height() + props.Profile = h265ProfileString(s.ProfileTierLevel.GeneralProfileIdc) + props.Level = h265LevelString(s.ProfileTierLevel.GeneralLevelIdc) + } + } + + return props + + case *format.H264: + props := &APIPathTrackCodecPropsH264{} + + sps, _ := forma.SafeParams() + if sps != nil { + var s codecsh264.SPS + if err := s.Unmarshal(sps); err == nil { + props.Width = s.Width() + props.Height = s.Height() + props.Profile = h264ProfileString(s.ProfileIdc) + props.Level = h264LevelString(s.LevelIdc) + } + } + + return props + + case *format.Opus: + return &APIPathTrackCodecPropsOpus{ + ChannelCount: forma.ChannelCount, + } + + case *format.MPEG4Audio: + props := &APIPathTrackCodecPropsMPEG4Audio{} + + if forma.Config != nil { + props.SampleRate = forma.Config.SampleRate + props.ChannelCount = int(forma.Config.ChannelConfig) + } + + return props + + case *format.AC3: + return &APIPathTrackCodecPropsAC3{ + SampleRate: forma.SampleRate, + ChannelCount: forma.ChannelCount, + } + + case *format.G711: + return &APIPathTrackCodecPropsG711{ + MULaw: forma.MULaw, + SampleRate: forma.SampleRate, + ChannelCount: forma.ChannelCount, + } + + case *format.LPCM: + return &APIPathTrackCodecPropsLPCM{ + BitDepth: forma.BitDepth, + SampleRate: forma.SampleRate, + ChannelCount: forma.ChannelCount, + } + + default: + return nil + } +} diff --git a/internal/defs/api_path_track_codec_test.go b/internal/defs/api_path_track_codec_test.go deleted file mode 100644 index 3bf1295e..00000000 --- a/internal/defs/api_path_track_codec_test.go +++ /dev/null @@ -1,206 +0,0 @@ -package defs - -import ( - "testing" - - "github.com/bluenviron/gortsplib/v5/pkg/description" - "github.com/bluenviron/gortsplib/v5/pkg/format" - "github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg4audio" - "github.com/stretchr/testify/require" -) - -func ptr[T any](v T) *T { - return &v -} - -func testFormatH264() *format.H264 { - return &format.H264{ - PayloadTyp: 96, - SPS: []byte{ - 0x67, 0x42, 0xc0, 0x28, 0xd9, 0x00, 0x78, 0x02, - 0x27, 0xe5, 0x84, 0x00, 0x00, 0x03, 0x00, 0x04, - 0x00, 0x00, 0x03, 0x00, 0xf0, 0x3c, 0x60, 0xc9, 0x20, - }, - PPS: []byte{0x08, 0x06, 0x07, 0x08}, - PacketizationMode: 1, - } -} - -func testFormatMPEG4Audio() *format.MPEG4Audio { - return &format.MPEG4Audio{ - PayloadTyp: 96, - Config: &mpeg4audio.AudioSpecificConfig{ - Type: 2, - SampleRate: 44100, - ChannelCount: 2, - ChannelConfig: 2, - }, - SizeLength: 13, - IndexLength: 3, - IndexDeltaLength: 3, - } -} - -func testFormatH265() *format.H265 { - return &format.H265{ - PayloadTyp: 96, - VPS: []byte{ - 0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x02, 0x20, - 0x00, 0x00, 0x03, 0x00, 0xb0, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x03, 0x00, 0x7b, 0x18, 0xb0, 0x24, - }, - SPS: []byte{ - 0x42, 0x01, 0x01, 0x02, 0x20, 0x00, 0x00, 0x03, - 0x00, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, - 0x00, 0x7b, 0xa0, 0x07, 0x82, 0x00, 0x88, 0x7d, - 0xb6, 0x71, 0x8b, 0x92, 0x44, 0x80, 0x53, 0x88, - 0x88, 0x92, 0xcf, 0x24, 0xa6, 0x92, 0x72, 0xc9, - 0x12, 0x49, 0x22, 0xdc, 0x91, 0xaa, 0x48, 0xfc, - 0xa2, 0x23, 0xff, 0x00, 0x01, 0x00, 0x01, 0x6a, - 0x02, 0x02, 0x02, 0x01, - }, - PPS: []byte{ - 0x44, 0x01, 0xc0, 0x25, 0x2f, 0x05, 0x32, 0x40, - }, - } -} - -func TestFormatsToCodecs(t *testing.T) { - codecs := FormatsToCodecs([]format.Format{ - &format.AV1{}, - &format.VP9{}, - &format.VP8{}, - &format.H265{}, - &format.H264{}, - &format.MPEG4Video{}, - &format.MPEG1Video{}, - &format.MJPEG{}, - &format.Opus{}, - &format.Vorbis{}, - &format.MPEG4Audio{}, - &format.MPEG4AudioLATM{}, - &format.MPEG1Audio{}, - &format.AC3{}, - &format.Speex{}, - &format.G726{}, - &format.G722{}, - &format.G711{}, - &format.LPCM{}, - &format.MPEGTS{}, - &format.KLV{}, - &format.Generic{}, - }) - - require.Equal(t, []APIPathTrackCodec{ - APIPathTrackCodecAV1, - APIPathTrackCodecVP9, - APIPathTrackCodecVP8, - APIPathTrackCodecH265, - APIPathTrackCodecH264, - APIPathTrackCodecMPEG4Video, - APIPathTrackCodecMPEG1Video, - APIPathTrackCodecMJPEG, - APIPathTrackCodecOpus, - APIPathTrackCodecVorbis, - APIPathTrackCodecMPEG4Audio, - APIPathTrackCodecMPEG4AudioLATM, - APIPathTrackCodecMPEG1Audio, - APIPathTrackCodecAC3, - APIPathTrackCodecSpeex, - APIPathTrackCodecG726, - APIPathTrackCodecG722, - APIPathTrackCodecG711, - APIPathTrackCodecLPCM, - APIPathTrackCodecMPEGTS, - APIPathTrackCodecKLV, - APIPathTrackCodecGeneric, - }, codecs) -} - -func TestMediasToTracks(t *testing.T) { - tracks := MediasToTracks([]*description.Media{ - {Formats: []format.Format{testFormatH264()}}, - {Formats: []format.Format{testFormatH265()}}, - { - Formats: []format.Format{ - &format.AV1{Profile: ptr(1), LevelIdx: ptr(9), Tier: ptr(0)}, - &format.VP9{ProfileID: ptr(2)}, - &format.MJPEG{}, - &format.Opus{ChannelCount: 2}, - &format.G711{MULaw: true, SampleRate: 8000, ChannelCount: 1}, - &format.LPCM{BitDepth: 16, SampleRate: 48000, ChannelCount: 2}, - }, - }, - { - Formats: []format.Format{testFormatMPEG4Audio()}, - }, - }) - - require.Equal(t, []APIPathTrack{ - { - Codec: APIPathTrackCodecH264, - CodecProps: &APIPathTrackCodecPropsH264{ - Width: 1920, - Height: 1080, - Profile: "Baseline", - Level: "4", - }, - }, - { - Codec: APIPathTrackCodecH265, - CodecProps: &APIPathTrackCodecPropsH265{ - Width: 960, - Height: 540, - Profile: "Main 10", - Level: "4.1", - }, - }, - { - Codec: APIPathTrackCodecAV1, - CodecProps: &APIPathTrackCodecPropsAV1{ - Profile: 1, - Level: 9, - Tier: 0, - }, - }, - { - Codec: APIPathTrackCodecVP9, - CodecProps: &APIPathTrackCodecPropsVP9{ - Profile: 2, - }, - }, - { - Codec: APIPathTrackCodecMJPEG, - CodecProps: nil, - }, - { - Codec: APIPathTrackCodecOpus, - CodecProps: &APIPathTrackCodecPropsOpus{ - ChannelCount: 2, - }, - }, - { - Codec: APIPathTrackCodecG711, - CodecProps: &APIPathTrackCodecPropsG711{ - MULaw: true, - SampleRate: 8000, - ChannelCount: 1, - }, - }, - { - Codec: APIPathTrackCodecLPCM, - CodecProps: &APIPathTrackCodecPropsLPCM{ - BitDepth: 16, - SampleRate: 48000, - ChannelCount: 2, - }, - }, - { - Codec: APIPathTrackCodecMPEG4Audio, - CodecProps: &APIPathTrackCodecPropsMPEG4Audio{ - SampleRate: 44100, - ChannelCount: 2, - }, - }, - }, tracks) -} diff --git a/internal/defs/source.go b/internal/defs/source.go index 673f2830..7471b60c 100644 --- a/internal/defs/source.go +++ b/internal/defs/source.go @@ -7,6 +7,7 @@ import ( "github.com/bluenviron/gortsplib/v5/pkg/description" "github.com/bluenviron/gortsplib/v5/pkg/format" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/logger" ) @@ -22,10 +23,10 @@ type Source interface { // FormatsInfo returns a description of formats. func FormatsInfo(formats []format.Format) string { - codecs := FormatsToCodecs(formats) - codecNames := make([]string, len(codecs)) - for i, codec := range codecs { - codecNames[i] = string(codec) + labels := formatlabel.FormatsToLabels(formats) + codecNames := make([]string, len(labels)) + for i, label := range labels { + codecNames[i] = string(label) } return fmt.Sprintf("%d %s (%s)", diff --git a/internal/formatlabel/label.go b/internal/formatlabel/label.go new file mode 100644 index 00000000..b7c48c2c --- /dev/null +++ b/internal/formatlabel/label.go @@ -0,0 +1,126 @@ +// Package formatlabel contains format label definitions. +package formatlabel + +import ( + "github.com/bluenviron/gortsplib/v5/pkg/description" + "github.com/bluenviron/gortsplib/v5/pkg/format" +) + +// Label is a format label. +type Label string + +// labels. +const ( + // video + AV1 Label = "AV1" + VP9 Label = "VP9" + VP8 Label = "VP8" + H265 Label = "H265" + H264 Label = "H264" + MPEG4Video Label = "MPEG-4 Video" + MPEG1Video Label = "MPEG-1/2 Video" + MJPEG Label = "M-JPEG" + // audio + Opus Label = "Opus" + Vorbis Label = "Vorbis" + MPEG4Audio Label = "MPEG-4 Audio" + MPEG4AudioLATM Label = "MPEG-4 Audio LATM" + MPEG1Audio Label = "MPEG-1/2 Audio" + AC3 Label = "AC3" + Speex Label = "Speex" + G726 Label = "G726" + G722 Label = "G722" + G711 Label = "G711" + LPCM Label = "LPCM" + // other + MPEGTS Label = "MPEG-TS" + KLV Label = "KLV" + Generic Label = "Generic" +) + +// FormatToLabel returns the label associated with a format. +func FormatToLabel(forma format.Format) Label { + switch forma.(type) { + // video + case *format.AV1: + return AV1 + case *format.VP9: + return VP9 + case *format.VP8: + return VP8 + case *format.H265: + return H265 + case *format.H264: + return H264 + case *format.MPEG4Video: + return MPEG4Video + case *format.MPEG1Video: + return MPEG1Video + case *format.MJPEG: + return MJPEG + // audio + case *format.Opus: + return Opus + case *format.Vorbis: + return Vorbis + case *format.MPEG4Audio: + return MPEG4Audio + case *format.MPEG4AudioLATM: + return MPEG4AudioLATM + case *format.MPEG1Audio: + return MPEG1Audio + case *format.AC3: + return AC3 + case *format.Speex: + return Speex + case *format.G726: + return G726 + case *format.G722: + return G722 + case *format.G711: + return G711 + case *format.LPCM: + return LPCM + // other + case *format.MPEGTS: + return MPEGTS + case *format.KLV: + return KLV + default: + return Generic + } +} + +func gatherFormats(medias []*description.Media) []format.Format { + n := 0 + for _, media := range medias { + n += len(media.Formats) + } + + if n == 0 { + return nil + } + + formats := make([]format.Format, n) + n = 0 + + for _, media := range medias { + n += copy(formats[n:], media.Formats) + } + + return formats +} + +// FormatsToLabels returns labels of given formats. +func FormatsToLabels(formats []format.Format) []Label { + ret := make([]Label, len(formats)) + for i, forma := range formats { + ret[i] = FormatToLabel(forma) + } + return ret +} + +// MediasToLabels returns labels of given medias. +func MediasToLabels(medias []*description.Media) []Label { + return FormatsToLabels(gatherFormats(medias)) +} diff --git a/internal/formatlabel/label_test.go b/internal/formatlabel/label_test.go new file mode 100644 index 00000000..b627f9d3 --- /dev/null +++ b/internal/formatlabel/label_test.go @@ -0,0 +1,88 @@ +package formatlabel + +import ( + "testing" + + "github.com/bluenviron/gortsplib/v5/pkg/description" + "github.com/bluenviron/gortsplib/v5/pkg/format" + "github.com/stretchr/testify/require" +) + +func TestFormatToLabel(t *testing.T) { + codecs := []Label{ + FormatToLabel(&format.AV1{}), + FormatToLabel(&format.VP9{}), + FormatToLabel(&format.VP8{}), + FormatToLabel(&format.H265{}), + FormatToLabel(&format.H264{}), + FormatToLabel(&format.MPEG4Video{}), + FormatToLabel(&format.MPEG1Video{}), + FormatToLabel(&format.MJPEG{}), + FormatToLabel(&format.Opus{}), + FormatToLabel(&format.Vorbis{}), + FormatToLabel(&format.MPEG4Audio{}), + FormatToLabel(&format.MPEG4AudioLATM{}), + FormatToLabel(&format.MPEG1Audio{}), + FormatToLabel(&format.AC3{}), + FormatToLabel(&format.Speex{}), + FormatToLabel(&format.G726{}), + FormatToLabel(&format.G722{}), + FormatToLabel(&format.G711{}), + FormatToLabel(&format.LPCM{}), + FormatToLabel(&format.MPEGTS{}), + FormatToLabel(&format.KLV{}), + FormatToLabel(&format.Generic{}), + } + + require.Equal(t, []Label{ + AV1, + VP9, + VP8, + H265, + H264, + MPEG4Video, + MPEG1Video, + MJPEG, + Opus, + Vorbis, + MPEG4Audio, + MPEG4AudioLATM, + MPEG1Audio, + AC3, + Speex, + G726, + G722, + G711, + LPCM, + MPEGTS, + KLV, + Generic, + }, codecs) +} + +func TestFormatsToLabels(t *testing.T) { + require.Equal(t, []Label{ + H264, + Opus, + KLV, + Generic, + }, FormatsToLabels([]format.Format{ + &format.H264{}, + &format.Opus{}, + &format.KLV{}, + &format.Generic{}, + })) +} + +func TestMediasToLabels(t *testing.T) { + require.Equal(t, []Label{ + H264, + Opus, + G711, + KLV, + }, MediasToLabels([]*description.Media{ + {Formats: []format.Format{&format.H264{}}}, + {Formats: []format.Format{&format.Opus{}, &format.G711{}}}, + {Formats: []format.Format{&format.KLV{}}}, + })) +} diff --git a/internal/linters/go2api/go2api_test.go b/internal/linters/go2api/go2api_test.go index bad41e07..7e8ee180 100644 --- a/internal/linters/go2api/go2api_test.go +++ b/internal/linters/go2api/go2api_test.go @@ -46,6 +46,7 @@ func wrapRef(rt reflect.Type, p openAPIProperty) openAPIProperty { type openAPISchema struct { Type string `yaml:"type"` Enum []string `yaml:"enum"` + OneOf []openAPIProperty `yaml:"oneOf"` Properties map[string]openAPIProperty `yaml:"properties"` } @@ -62,6 +63,10 @@ func schemaName(rt reflect.Type) string { return "PathConf" } + if rt == reflect.TypeOf(defs.APIPathTrackCodec("")) { + return "PathTrackCodec" + } + return name } @@ -190,13 +195,13 @@ func goEnumToApi(rt reflect.Type) (openAPISchema, bool) { "H265", "H264", "MPEG-4 Video", - "MPEG-1 Video", - "MJPEG", + "MPEG-1/2 Video", + "M-JPEG", "Opus", "Vorbis", "MPEG-4 Audio", "MPEG-4 Audio LATM", - "MPEG-1 Audio", + "MPEG-1/2 Audio", "AC3", "Speex", "G726", @@ -379,6 +384,42 @@ func TestGo2API(t *testing.T) { "PathTrack", defs.APIPathTrack{}, }, + { + "PathTrackCodecPropsAV1", + defs.APIPathTrackCodecPropsAV1{}, + }, + { + "PathTrackCodecPropsVP9", + defs.APIPathTrackCodecPropsVP9{}, + }, + { + "PathTrackCodecPropsH265", + defs.APIPathTrackCodecPropsH265{}, + }, + { + "PathTrackCodecPropsH264", + defs.APIPathTrackCodecPropsH264{}, + }, + { + "PathTrackCodecPropsOpus", + defs.APIPathTrackCodecPropsOpus{}, + }, + { + "PathTrackCodecPropsMPEG4Audio", + defs.APIPathTrackCodecPropsMPEG4Audio{}, + }, + { + "PathTrackCodecPropsAC3", + defs.APIPathTrackCodecPropsAC3{}, + }, + { + "PathTrackCodecPropsG711", + defs.APIPathTrackCodecPropsG711{}, + }, + { + "PathTrackCodecPropsLPCM", + defs.APIPathTrackCodecPropsLPCM{}, + }, { "Recording", defs.APIRecording{}, @@ -464,6 +505,20 @@ func TestGo2API(t *testing.T) { } }) + t.Run("oneOfs", func(t *testing.T) { + require.Equal(t, openAPISchema{OneOf: []openAPIProperty{ + {Ref: "#/components/schemas/PathTrackCodecPropsAV1"}, + {Ref: "#/components/schemas/PathTrackCodecPropsVP9"}, + {Ref: "#/components/schemas/PathTrackCodecPropsH265"}, + {Ref: "#/components/schemas/PathTrackCodecPropsH264"}, + {Ref: "#/components/schemas/PathTrackCodecPropsOpus"}, + {Ref: "#/components/schemas/PathTrackCodecPropsMPEG4Audio"}, + {Ref: "#/components/schemas/PathTrackCodecPropsAC3"}, + {Ref: "#/components/schemas/PathTrackCodecPropsG711"}, + {Ref: "#/components/schemas/PathTrackCodecPropsLPCM"}, + }}, doc.Components.Schemas["PathTrackCodecProps"]) + }) + t.Run("enums", func(t *testing.T) { for _, rt := range []reflect.Type{ reflect.TypeOf(defs.APIOKStatus("")), diff --git a/internal/metrics/metrics_test.go b/internal/metrics/metrics_test.go index a00ac47f..e1544403 100644 --- a/internal/metrics/metrics_test.go +++ b/internal/metrics/metrics_test.go @@ -11,6 +11,7 @@ import ( "github.com/bluenviron/mediamtx/internal/auth" "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/defs" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/test" "github.com/google/uuid" @@ -50,7 +51,7 @@ func (dummyPathManager) APIPathsList() (*defs.APIPathList, error) { }, Ready: true, ReadyTime: ptrOf(time.Date(2003, 11, 4, 23, 15, 7, 0, time.UTC)), - Tracks: []defs.APIPathTrackCodec{defs.APIPathTrackCodecH264, defs.APIPathTrackCodecH265}, + Tracks: []defs.APIPathTrackCodec{formatlabel.H264, formatlabel.H265}, InboundBytes: 123, OutboundBytes: 456, InboundFramesInError: 7, diff --git a/internal/protocols/hls/from_stream.go b/internal/protocols/hls/from_stream.go index f4509654..f94b3ac4 100644 --- a/internal/protocols/hls/from_stream.go +++ b/internal/protocols/hls/from_stream.go @@ -11,6 +11,7 @@ import ( "github.com/bluenviron/gortsplib/v5/pkg/description" "github.com/bluenviron/gortsplib/v5/pkg/format" "github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg4audio" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/unit" @@ -314,7 +315,7 @@ func FromStream( for _, media := range desc.Medias { for _, forma := range media.Formats { if !slices.Contains(setuppedFormats, forma) { - r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, forma.Codec()) + r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, formatlabel.FormatToLabel(forma)) } n++ } diff --git a/internal/protocols/mpegts/from_stream.go b/internal/protocols/mpegts/from_stream.go index 0355babe..4840d739 100644 --- a/internal/protocols/mpegts/from_stream.go +++ b/internal/protocols/mpegts/from_stream.go @@ -17,6 +17,7 @@ import ( "github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts/substructs" srt "github.com/datarhei/gosrt" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/unit" @@ -185,7 +186,7 @@ func FromStream( if !firstReceived { firstReceived = true } else if u.PTS < lastPTS { - return fmt.Errorf("MPEG-1 Video streams with B-frames are not supported (yet)") + return fmt.Errorf("MPEG-1/2 Video streams with B-frames are not supported (yet)") } lastPTS = u.PTS @@ -402,7 +403,7 @@ func FromStream( for _, medi := range desc.Medias { for _, forma := range medi.Formats { if !slices.Contains(setuppedFormats, forma) { - r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, forma.Codec()) + r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, formatlabel.FormatToLabel(forma)) } n++ } diff --git a/internal/protocols/mpegts/to_stream.go b/internal/protocols/mpegts/to_stream.go index 3fb40fb9..434dd17c 100644 --- a/internal/protocols/mpegts/to_stream.go +++ b/internal/protocols/mpegts/to_stream.go @@ -19,7 +19,7 @@ import ( var errNoSupportedCodecs = errors.New( "the stream doesn't contain any supported codec, which are currently " + - "H265, H264, MPEG-4 Video, MPEG-1/2 Video, Opus, MPEG-4 Audio, MPEG-1 Audio, AC-3") + "H265, H264, MPEG-4 Video, MPEG-1/2 Video, Opus, MPEG-4 Audio, MPEG-1/2 Audio, AC-3") // ToStream maps a MPEG-TS stream to a MediaMTX stream. func ToStream( diff --git a/internal/protocols/rtmp/from_stream.go b/internal/protocols/rtmp/from_stream.go index 74f28bd6..eee7d577 100644 --- a/internal/protocols/rtmp/from_stream.go +++ b/internal/protocols/rtmp/from_stream.go @@ -18,6 +18,7 @@ import ( "github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg1audio" "github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg4audio" "github.com/bluenviron/mediacommon/v2/pkg/codecs/opus" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/unit" @@ -475,7 +476,7 @@ func FromStream( for _, media := range desc.Medias { for _, forma := range media.Formats { if !slices.Contains(setuppedFormats, forma) { - r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, forma.Codec()) + r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, formatlabel.FormatToLabel(forma)) } n++ } diff --git a/internal/protocols/webrtc/from_stream.go b/internal/protocols/webrtc/from_stream.go index d8e4e41e..f0b541f3 100644 --- a/internal/protocols/webrtc/from_stream.go +++ b/internal/protocols/webrtc/from_stream.go @@ -17,6 +17,7 @@ import ( "github.com/bluenviron/gortsplib/v5/pkg/format/rtpvp9" "github.com/bluenviron/mediacommon/v2/pkg/codecs/g711" "github.com/bluenviron/mediacommon/v2/pkg/codecs/opus" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/stream" "github.com/bluenviron/mediamtx/internal/unit" @@ -711,7 +712,7 @@ func FromStream( for _, media := range desc.Medias { for _, forma := range media.Formats { if !slices.Contains(setuppedFormats, forma) { - r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, forma.Codec()) + r.Parent.Log(logger.Warn, "skipping track %d (%s)", n, formatlabel.FormatToLabel(forma)) } n++ } diff --git a/internal/recorder/format_fmp4.go b/internal/recorder/format_fmp4.go index 5aad8f84..f573e859 100644 --- a/internal/recorder/format_fmp4.go +++ b/internal/recorder/format_fmp4.go @@ -22,6 +22,7 @@ import ( mcodecs "github.com/bluenviron/mediacommon/v2/pkg/formats/mp4/codecs" "github.com/bluenviron/mediamtx/internal/defs" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/unit" ) @@ -576,7 +577,7 @@ func (f *formatFMP4) initialize() bool { } firstReceived = true } else if u.PTS < lastPTS { - return fmt.Errorf("MPEG-1 Video streams with B-frames are not supported (yet)") + return fmt.Errorf("MPEG-1/2 Video streams with B-frames are not supported (yet)") } lastPTS = u.PTS @@ -921,7 +922,7 @@ func (f *formatFMP4) initialize() bool { for _, medi := range f.ri.stream.Desc.Medias { for _, forma := range medi.Formats { if !slices.Contains(setuppedFormats, forma) { - f.ri.Log(logger.Warn, "skipping track %d (%s)", n, forma.Codec()) + f.ri.Log(logger.Warn, "skipping track %d (%s)", n, formatlabel.FormatToLabel(forma)) } n++ } diff --git a/internal/recorder/format_mpegts.go b/internal/recorder/format_mpegts.go index 512e8b53..7eaafb92 100644 --- a/internal/recorder/format_mpegts.go +++ b/internal/recorder/format_mpegts.go @@ -18,6 +18,7 @@ import ( tscodecs "github.com/bluenviron/mediacommon/v2/pkg/formats/mpegts/codecs" "github.com/bluenviron/mediamtx/internal/defs" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/unit" ) @@ -221,7 +222,7 @@ func (f *formatMPEGTS) initialize() bool { if !firstReceived { firstReceived = true } else if u.PTS < lastPTS { - return fmt.Errorf("MPEG-1 Video streams with B-frames are not supported (yet)") + return fmt.Errorf("MPEG-1/2 Video streams with B-frames are not supported (yet)") } lastPTS = u.PTS @@ -424,7 +425,7 @@ func (f *formatMPEGTS) initialize() bool { for _, medi := range f.ri.stream.Desc.Medias { for _, forma := range medi.Formats { if !slices.Contains(setuppedFormats, forma) { - f.ri.Log(logger.Warn, "skipping track %d (%s)", n, forma.Codec()) + f.ri.Log(logger.Warn, "skipping track %d (%s)", n, formatlabel.FormatToLabel(forma)) } n++ } diff --git a/internal/stream/sub_stream.go b/internal/stream/sub_stream.go index 079189d6..e1acb224 100644 --- a/internal/stream/sub_stream.go +++ b/internal/stream/sub_stream.go @@ -7,43 +7,11 @@ import ( "github.com/bluenviron/gortsplib/v5/pkg/description" "github.com/bluenviron/gortsplib/v5/pkg/format" "github.com/bluenviron/mediacommon/v2/pkg/codecs/mpeg4audio" + "github.com/bluenviron/mediamtx/internal/formatlabel" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/unit" ) -// FormatsToCodecs returns the name of codecs of given formats. -func FormatsToCodecs(formats []format.Format) []string { - ret := make([]string, len(formats)) - for i, forma := range formats { - ret[i] = forma.Codec() - } - return ret -} - -func gatherFormats(medias []*description.Media) []format.Format { - n := 0 - for _, media := range medias { - n += len(media.Formats) - } - - if n == 0 { - return nil - } - - formats := make([]format.Format, n) - n = 0 - - for _, media := range medias { - n += copy(formats[n:], media.Formats) - } - - return formats -} - -func mediasToCodecs(medias []*description.Media) []string { - return FormatsToCodecs(gatherFormats(medias)) -} - func formatMPEG4AudioConfig(asc *mpeg4audio.AudioSpecificConfig) string { return fmt.Sprintf("type=%d, sampleRate=%d, channelCount=%d", asc.Type, asc.SampleRate, asc.ChannelConfig) @@ -62,19 +30,19 @@ func formatLPCMConfig(f *format.LPCM) string { func mediasAreCompatible(medias1 []*description.Media, medias2 []*description.Media) error { if len(medias1) != len(medias2) { return fmt.Errorf("wants to publish %v, but stream expects %v", - mediasToCodecs(medias2), mediasToCodecs(medias1)) + formatlabel.MediasToLabels(medias2), formatlabel.MediasToLabels(medias1)) } for i := range medias1 { if len(medias1[i].Formats) != len(medias2[i].Formats) { return fmt.Errorf("wants to publish %v, but stream expects %v", - mediasToCodecs(medias2), mediasToCodecs(medias1)) + formatlabel.MediasToLabels(medias2), formatlabel.MediasToLabels(medias1)) } for j := range medias1[i].Formats { if reflect.TypeOf(medias1[i].Formats[j]) != reflect.TypeOf(medias2[i].Formats[j]) { return fmt.Errorf("wants to publish %v, but stream expects %v", - mediasToCodecs(medias2), mediasToCodecs(medias1)) + formatlabel.MediasToLabels(medias2), formatlabel.MediasToLabels(medias1)) } } } diff --git a/internal/unit/payload_mpeg1_audio.go b/internal/unit/payload_mpeg1_audio.go index 4f94d998..f50aca4d 100644 --- a/internal/unit/payload_mpeg1_audio.go +++ b/internal/unit/payload_mpeg1_audio.go @@ -1,6 +1,6 @@ package unit -// PayloadMPEG1Audio is the payload of a MPEG-1 Audio track. +// PayloadMPEG1Audio is the payload of a MPEG-1/2 Audio track. type PayloadMPEG1Audio [][]byte func (PayloadMPEG1Audio) isPayload() {} diff --git a/internal/unit/payload_mpeg1_video.go b/internal/unit/payload_mpeg1_video.go index 48ea3731..c1d0b6cf 100644 --- a/internal/unit/payload_mpeg1_video.go +++ b/internal/unit/payload_mpeg1_video.go @@ -1,6 +1,6 @@ package unit -// PayloadMPEG1Video is the payload of a MPEG-1 Video track. +// PayloadMPEG1Video is the payload of a MPEG-1/2 Video track. type PayloadMPEG1Video []byte func (PayloadMPEG1Video) isPayload() {}