Files
go2rtc/pkg/iso/codecs.go
2023-07-23 22:19:35 +03:00

182 lines
4.7 KiB
Go

package iso
import (
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/pcm"
)
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 core.CodecH264:
m.StartAtom("avc1")
case core.CodecH265:
m.StartAtom("hev1")
default:
panic("unsupported iso video: " + codec)
}
m.Skip(6)
m.WriteUint16(1) // data_reference_index
m.Skip(2) // version
m.Skip(2) // revision
m.Skip(4) // vendor
m.Skip(4) // temporal quality
m.Skip(4) // spatial quality
m.WriteUint16(width) // width
m.WriteUint16(height) // height
m.WriteFloat32(72) // horizontal resolution
m.WriteFloat32(72) // vertical resolution
m.Skip(4) // reserved
m.WriteUint16(1) // frame count
m.Skip(32) // compressor name
m.WriteUint16(24) // depth
m.WriteUint16(0xFFFF) // color table id (-1)
switch codec {
case core.CodecH264:
m.StartAtom("avcC")
case core.CodecH265:
m.StartAtom("hvcC")
}
m.Write(conf)
m.EndAtom() // AVCC
m.StartAtom("pasp") // Pixel Aspect Ratio
m.WriteUint32(1) // hSpacing
m.WriteUint32(1) // vSpacing
m.EndAtom()
m.EndAtom() // AVC1
}
func (m *Movie) WriteAudio(codec string, channels uint16, sampleRate uint32, conf []byte) {
switch codec {
case core.CodecAAC, core.CodecMP3:
m.StartAtom("mp4a") // supported in all players and browsers
case core.CodecFLAC:
m.StartAtom("fLaC") // supported in all players and browsers
case core.CodecOpus:
m.StartAtom("Opus") // supported in Chrome and Firefox
case core.CodecPCMU:
m.StartAtom("ulaw")
case core.CodecPCMA:
m.StartAtom("alaw")
default:
panic("unsupported iso audio: " + codec)
}
if channels == 0 {
channels = 1
}
m.Skip(6)
m.WriteUint16(1) // data_reference_index
m.Skip(2) // version
m.Skip(2) // revision
m.Skip(4) // vendor
m.WriteUint16(channels) // channel_count
m.WriteUint16(16) // sample_size
m.Skip(2) // compression id
m.Skip(2) // reserved
m.WriteFloat32(float64(sampleRate)) // sample_rate
switch codec {
case core.CodecAAC:
m.WriteEsdsAAC(conf)
case core.CodecMP3:
m.WriteEsdsMP3()
case core.CodecFLAC:
m.StartAtom("dfLa")
m.Write(pcm.FLACHeader(false, sampleRate))
m.EndAtom()
case core.CodecOpus:
m.WriteOpus(channels, sampleRate)
case core.CodecPCMU, core.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
}
func (m *Movie) WriteEsdsAAC(conf []byte) {
m.StartAtom("esds")
m.Skip(1) // version
m.Skip(3) // flags
// MP4ESDescrTag[3]:
// - MP4DecConfigDescrTag[4]:
// - MP4DecSpecificDescrTag[5]: conf
// - Other[6]
const header = 5
const size3 = 3
const size4 = 13
size5 := byte(len(conf))
const size6 = 1
m.WriteBytes(3, 0x80, 0x80, 0x80, size3+header+size4+header+size5+header+size6)
m.Skip(2) // es id
m.Skip(1) // es flags
// https://learn.microsoft.com/en-us/windows/win32/medfound/mpeg-4-file-sink#aac-audio
m.WriteBytes(4, 0x80, 0x80, 0x80, size4+header+size5)
m.WriteBytes(0x40) // 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(5, 0x80, 0x80, 0x80, size5)
m.Write(conf)
m.WriteBytes(6, 0x80, 0x80, 0x80, 1)
m.WriteBytes(2) // ?
m.EndAtom() // ESDS
}
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
// https://learn.microsoft.com/en-us/windows/win32/medfound/mpeg-4-file-sink#mp3-audio
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
}
func (m *Movie) WriteOpus(channels uint16, sampleRate uint32) {
// https://www.opus-codec.org/docs/opus_in_isobmff.html
m.StartAtom("dOps")
m.Skip(1) // version
m.WriteBytes(byte(channels))
m.WriteUint16(0) // PreSkip ???
m.WriteUint32(sampleRate)
m.Skip(2) // OutputGain
m.Skip(1) // signed int(16) OutputGain;
m.EndAtom()
}