From 69dd4d26eccd4daaa68394ee180a12898e19aa05 Mon Sep 17 00:00:00 2001 From: Alexey Khit Date: Fri, 27 Jan 2023 17:11:44 +0300 Subject: [PATCH] Add support OPUS, MP3, PCMU, PCMA for MP4 --- pkg/iso/codecs.go | 72 +++++++++++++++++++++++++++++++-------------- pkg/mp4/consumer.go | 3 +- pkg/mp4/muxer.go | 2 +- 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/pkg/iso/codecs.go b/pkg/iso/codecs.go index 07eeb379..ecb251d0 100644 --- a/pkg/iso/codecs.go +++ b/pkg/iso/codecs.go @@ -2,22 +2,13 @@ package iso import "github.com/AlexxIT/go2rtc/pkg/streamer" -const ( - MoovTrakMdiaMinfStblStsdAvc1 = "avc1" - MoovTrakMdiaMinfStblStsdAvc1AvcC = "avcC" - MoovTrakMdiaMinfStblStsdHev1 = "hev1" - MoovTrakMdiaMinfStblStsdHev1HvcC = "hvcC" - MoovTrakMdiaMinfStblStsdMp4a = "mp4a" - MoovTrakMdiaMinfStblStsdOpus = "Opus" -) - func (m *Movie) WriteVideo(codec string, width, height uint16, conf []byte) { // https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html switch codec { case streamer.CodecH264: - m.StartAtom(MoovTrakMdiaMinfStblStsdAvc1) + m.StartAtom("avc1") case streamer.CodecH265: - m.StartAtom(MoovTrakMdiaMinfStblStsdHev1) + m.StartAtom("hev1") default: panic("unsupported iso video: " + codec) } @@ -40,9 +31,9 @@ func (m *Movie) WriteVideo(codec string, width, height uint16, conf []byte) { switch codec { case streamer.CodecH264: - m.StartAtom(MoovTrakMdiaMinfStblStsdAvc1AvcC) + m.StartAtom("avcC") case streamer.CodecH265: - m.StartAtom(MoovTrakMdiaMinfStblStsdHev1HvcC) + m.StartAtom("hvcC") } m.Write(conf) m.EndAtom() // AVCC @@ -52,10 +43,14 @@ func (m *Movie) WriteVideo(codec string, width, height uint16, conf []byte) { func (m *Movie) WriteAudio(codec string, channels uint16, sampleRate uint32, conf []byte) { switch codec { - case streamer.CodecAAC: - m.StartAtom(MoovTrakMdiaMinfStblStsdMp4a) + case streamer.CodecAAC, streamer.CodecMP3: + m.StartAtom("mp4a") case streamer.CodecOpus: - m.StartAtom(MoovTrakMdiaMinfStblStsdOpus) + m.StartAtom("Opus") + case streamer.CodecPCMU: + m.StartAtom("ulaw") + case streamer.CodecPCMA: + m.StartAtom("alaw") default: panic("unsupported iso audio: " + codec) } @@ -73,8 +68,18 @@ func (m *Movie) WriteAudio(codec string, channels uint16, sampleRate uint32, con switch codec { case streamer.CodecAAC: m.WriteEsdsAAC(conf) + case streamer.CodecMP3: + m.WriteEsdsMP3() case streamer.CodecOpus: - m.WriteDops() + // don't know what means this magic + m.StartAtom("dOps") + m.WriteBytes(0, 0x02, 0x01, 0x38, 0, 0, 0xBB, 0x80, 0, 0, 0) + m.EndAtom() + case streamer.CodecPCMU, streamer.CodecPCMA: + // don't know what means this magic + m.StartAtom("chan") + m.WriteBytes(0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0) + m.EndAtom() } m.EndAtom() // MP4A/OPUS @@ -115,9 +120,32 @@ func (m *Movie) WriteEsdsAAC(conf []byte) { m.EndAtom() // ESDS } -func (m *Movie) WriteDops() { - // don't know what means this magic - m.StartAtom("dOps") - m.WriteBytes(0, 0x02, 0x01, 0x38, 0, 0, 0xBB, 0x80, 0, 0, 0) - m.EndAtom() +func (m *Movie) WriteEsdsMP3() { + m.StartAtom("esds") + m.Skip(1) // version + m.Skip(3) // flags + + // MP4ESDescrTag[3]: + // - MP4DecConfigDescrTag[4]: + // - Other[6] + const header = 5 + const size3 = 3 + const size4 = 13 + const size6 = 1 + + m.WriteBytes(3, 0x80, 0x80, 0x80, size3+header+size4+header+size6) + m.Skip(2) // es id + m.Skip(1) // es flags + + m.WriteBytes(4, 0x80, 0x80, 0x80, size4) + m.WriteBytes(0x6B) // object id + m.WriteBytes(0x15) // stream type + m.Skip(3) // buffer size db + m.Skip(4) // max bitraga + m.Skip(4) // avg bitraga + + m.WriteBytes(6, 0x80, 0x80, 0x80, 1) + m.WriteBytes(2) // ? + + m.EndAtom() // ESDS } diff --git a/pkg/mp4/consumer.go b/pkg/mp4/consumer.go index 9f1f3b50..8d5fbf2d 100644 --- a/pkg/mp4/consumer.go +++ b/pkg/mp4/consumer.go @@ -50,7 +50,6 @@ func (c *Consumer) GetMedias() []*streamer.Media { Direction: streamer.DirectionRecvonly, Codecs: []*streamer.Codec{ {Name: streamer.CodecAAC}, - {Name: streamer.CodecOpus}, }, }, } @@ -143,7 +142,7 @@ func (c *Consumer) AddTrack(media *streamer.Media, track *streamer.Track) *strea return track.Bind(push) - case streamer.CodecOpus: + case streamer.CodecOpus, streamer.CodecMP3, streamer.CodecPCMU, streamer.CodecPCMA: push := func(packet *rtp.Packet) error { if c.wait != waitNone { return nil diff --git a/pkg/mp4/muxer.go b/pkg/mp4/muxer.go index 2d944b0e..83bb33c5 100644 --- a/pkg/mp4/muxer.go +++ b/pkg/mp4/muxer.go @@ -108,7 +108,7 @@ func (m *Muxer) GetInit(codecs []*streamer.Codec) ([]byte, error) { uint32(i+1), codec.Name, codec.ClockRate, codec.Channels, b, ) - case streamer.CodecOpus: + case streamer.CodecOpus, streamer.CodecMP3, streamer.CodecPCMU, streamer.CodecPCMA: mv.WriteAudioTrack( uint32(i+1), codec.Name, codec.ClockRate, codec.Channels, nil, )