123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- package codec
- import (
- "encoding/binary"
- "errors"
- )
- // rfc6716 https://datatracker.ietf.org/doc/html/rfc6716
- //
- // TOC byte
- // 0
- // 0 1 2 3 4 5 6 7
- // +-+-+-+-+-+-+-+-+
- // | config |s| c |
- // +-+-+-+-+-+-+-+-+
- // +-----------------------+-----------+-----------+-------------------+
- // | Configuration | Mode | Bandwidth | Frame Sizes |
- // | Number(s) | | | |
- // +-----------------------+-----------+-----------+-------------------+
- // | 0...3 | SILK-only | NB | 10, 20, 40, 60 ms |
- // | | | | |
- // | 4...7 | SILK-only | MB | 10, 20, 40, 60 ms |
- // | | | | |
- // | 8...11 | SILK-only | WB | 10, 20, 40, 60 ms |
- // | | | | |
- // | 12...13 | Hybrid | SWB | 10, 20 ms |
- // | | | | |
- // | 14...15 | Hybrid | FB | 10, 20 ms |
- // | | | | |
- // | 16...19 | CELT-only | NB | 2.5, 5, 10, 20 ms |
- // | | | | |
- // | 20...23 | CELT-only | WB | 2.5, 5, 10, 20 ms |
- // | | | | |
- // | 24...27 | CELT-only | SWB | 2.5, 5, 10, 20 ms |
- // | | | | |
- // | 28...31 | CELT-only | FB | 2.5, 5, 10, 20 ms |
- // +-----------------------+-----------+-----------+-------------------+
- // s: with 0 indicating mono and 1 indicating stereo.
- //
- // c : codes 0 to 3
- // 0: 1 frame in the packet
- // 1: 2 frames in the packet, each with equal compressed size
- // 2: 2 frames in the packet, with different compressed sizes
- // 3: an arbitrary number of frames in the packet
- // Frame Length Coding
- // 0: No frame (Discontinuous Transmission (DTX) or lost packet)
- // 1...251: Length of the frame in bytes
- // 252...255: A second byte is needed. The total length is (second_byte*4)+first_byte
- // Code 0:
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | config |s|0|0| |
- // +-+-+-+-+-+-+-+-+ |
- // | Compressed frame 1 (N-1 bytes)... :
- // : |
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // Code 1:
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | config |s|0|1| |
- // +-+-+-+-+-+-+-+-+ :
- // | Compressed frame 1 ((N-1)/2 bytes)... |
- // : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ :
- // | Compressed frame 2 ((N-1)/2 bytes)... |
- // : +-+-+-+-+-+-+-+-+
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // Code 2:
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | config |s|1|0| N1 (1-2 bytes): |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ :
- // | Compressed frame 1 (N1 bytes)... |
- // : +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
- // | Compressed frame 2... :
- // : |
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- //Code 3:
- // Frame Count Byte
- // 0
- // 0 1 2 3 4 5 6 7
- // +-+-+-+-+-+-+-+-+
- // |v|p| M |
- // +-+-+-+-+-+-+-+-+
- // v: 0 - CBR 1 - VBR
- // p: 0 - no padding 1 - padding after frame
- // M: frame count
- // A CBR Code 3 Packet
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | config |s|1|1|0|p| M | Padding length (Optional) :
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // : Compressed frame 1 (R/M bytes)... :
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // : Compressed frame 2 (R/M bytes)... :
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // : ... :
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // : Compressed frame M (R/M bytes)... :
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // : Opus Padding (Optional)... |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- //
- //
- // A VBR Code 3 Packet
- // 0 1 2 3
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | config |s|1|1|1|p| M | Padding length (Optional) :
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // : N1 (1-2 bytes): N2 (1-2 bytes): ... : N[M-1] |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // : Compressed frame 1 (N1 bytes)... :
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // : Compressed frame 2 (N2 bytes)... :
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // : ... :
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | |
- // : Compressed frame M... :
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // : Opus Padding (Optional)... |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- var (
- /// 10ms,20ms,40ms,60ms, samplerate 48000
- // sample num per millisecond
- // 48000 / 1000ms * 10 = 480 ...
- SLKOpusSampleSize [4]int = [4]int{480, 960, 1920, 2880}
- HybridOpusSampleSize [4]int = [4]int{480, 960}
- CELTOpusSampleSize [4]int = [4]int{120, 210, 480, 960}
- )
- func OpusPacketDuration(packet []byte) uint64 {
- config := int(packet[0] >> 3)
- code := packet[0] & 0x03
- frameCount := 0
- var duration uint64
- if code == 0 {
- frameCount = 1
- } else if code == 1 || code == 2 {
- frameCount = 2
- } else if code == 3 {
- frameCount = int(packet[1] & 0x1F)
- } else {
- panic("code must <= 3")
- }
- switch {
- case config >= 0 && config < 12:
- duration = uint64(frameCount * SLKOpusSampleSize[config%4])
- case config >= 12 && config < 16:
- duration = uint64(frameCount * HybridOpusSampleSize[config%2])
- case config >= 16 && config < 32:
- duration = uint64(frameCount * CELTOpusSampleSize[config%4])
- default:
- panic("unkown opus config")
- }
- return duration
- }
- //ffmpeg opus.h OpusPacket
- type OpusPacket struct {
- Code int
- Config int
- Stereo int
- Vbr int
- FrameCount int
- FrameLen []uint16
- Frame []byte
- Duration uint64
- }
- func DecodeOpusPacket(packet []byte) *OpusPacket {
- pkt := &OpusPacket{}
- pkt.Code = int(packet[0] & 0x03)
- pkt.Stereo = int((packet[0] >> 2) & 0x01)
- pkt.Config = int(packet[0] >> 3)
- switch pkt.Code {
- case 0:
- pkt.FrameCount = 1
- pkt.FrameLen = make([]uint16, 1)
- pkt.FrameLen[0] = uint16(len(packet) - 1)
- pkt.Frame = packet[1:]
- case 1:
- pkt.FrameCount = 2
- pkt.FrameLen = make([]uint16, 1)
- pkt.FrameLen[0] = uint16(len(packet)-1) / 2
- pkt.Frame = packet[1:]
- case 2:
- pkt.FrameCount = 2
- hdr := 1
- N1 := int(packet[1])
- if N1 >= 252 {
- N1 = N1 + int(packet[2]*4)
- hdr = 2
- }
- pkt.FrameLen = make([]uint16, 2)
- pkt.FrameLen[0] = uint16(N1)
- pkt.FrameLen[1] = uint16(len(packet)-hdr) - uint16(N1)
- case 3:
- hdr := 2
- pkt.Vbr = int(packet[1] >> 7)
- padding := packet[1] >> 6
- pkt.FrameCount = int(packet[1] & 0x1F)
- paddingLen := 0
- if padding == 1 {
- for packet[hdr] == 255 {
- paddingLen += 254
- hdr++
- }
- paddingLen += int(packet[hdr])
- }
- if pkt.Vbr == 0 {
- pkt.FrameLen = make([]uint16, 1)
- pkt.FrameLen[0] = uint16(len(packet)-hdr-paddingLen) / uint16(pkt.FrameCount)
- pkt.Frame = packet[hdr : hdr+int(pkt.FrameLen[0]*uint16(pkt.FrameCount))]
- } else {
- n := 0
- for i := 0; i < int(pkt.FrameCount)-1; i++ {
- N1 := int(packet[hdr])
- hdr += 1
- if N1 >= 252 {
- N1 = N1 + int(packet[hdr]*4)
- hdr += 1
- }
- n += N1
- pkt.FrameLen = append(pkt.FrameLen, uint16(N1))
- }
- lastFrameLen := len(packet) - hdr - paddingLen - n
- pkt.FrameLen = append(pkt.FrameLen, uint16(lastFrameLen))
- pkt.Frame = packet[hdr : hdr+n+lastFrameLen]
- }
- default:
- panic("Error C must <= 3")
- }
- OpusPacketDuration(packet)
- return pkt
- }
- const (
- LEFT_CHANNEL = 0
- RIGHT_CHANNEL = 1
- )
- var (
- vorbisChanLayoutOffset [8][8]byte = [8][8]byte{
- {0},
- {0, 1},
- {0, 2, 1},
- {0, 1, 2, 3},
- {0, 2, 1, 3, 4},
- {0, 2, 1, 5, 3, 4},
- {0, 2, 1, 6, 5, 3, 4},
- {0, 2, 1, 7, 5, 6, 3, 4},
- }
- )
- type ChannelOrder func(channels int, idx int) int
- func defalutOrder(channels int, idx int) int {
- return idx
- }
- func vorbisOrder(channels int, idx int) int {
- return int(vorbisChanLayoutOffset[channels-1][idx])
- }
- type ChannelMap struct {
- StreamIdx int
- ChannelIdx int
- Silence bool
- Copy bool
- CopyFrom int
- }
- type OpusContext struct {
- Preskip int
- SampleRate int
- ChannelCount int
- StreamCount int
- StereoStreamCount int
- OutputGain uint16
- MapType uint8
- ChannelMaps []ChannelMap
- }
- // opus ID Head
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | 'O' | 'p' | 'u' | 's' |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | 'H' | 'e' | 'a' | 'd' |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Version = 1 | Channel Count | Pre-skip |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Input Sample Rate (Hz) |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Output Gain (Q7.8 in dB) | Mapping Family| |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ :
- // | |
- // : Optional Channel Mapping Table... :
- // | |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- // +-+-+-+-+-+-+-+-+
- // | Stream Count |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Coupled Count | Channel Mapping... :
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- //
- func (ctx *OpusContext) ParseExtranData(extraData []byte) error {
- if string(extraData[0:8]) != "OpusHead" {
- return errors.New("magic signature must equal OpusHead")
- }
- _ = extraData[8] // version
- ctx.ChannelCount = int(extraData[9])
- ctx.Preskip = int(binary.LittleEndian.Uint16(extraData[10:]))
- ctx.SampleRate = int(binary.LittleEndian.Uint32(extraData[12:]))
- ctx.OutputGain = binary.LittleEndian.Uint16(extraData[16:])
- ctx.MapType = extraData[18]
- var channel []byte
- var order ChannelOrder
- if ctx.MapType == 0 {
- ctx.StreamCount = 1
- ctx.StereoStreamCount = ctx.ChannelCount - 1
- channel = []byte{0, 1}
- order = defalutOrder
- } else if ctx.MapType == 1 || ctx.MapType == 2 || ctx.MapType == 255 {
- ctx.StreamCount = int(extraData[19])
- ctx.StereoStreamCount = int(extraData[20])
- if ctx.MapType == 1 {
- channel = extraData[21 : 21+ctx.ChannelCount]
- order = vorbisOrder
- }
- } else {
- return errors.New("unsupport map type 255")
- }
- for i := 0; i < ctx.ChannelCount; i++ {
- cm := ChannelMap{}
- index := channel[order(ctx.ChannelCount, i)]
- if index == 255 {
- cm.Silence = true
- continue
- } else if index > byte(ctx.StereoStreamCount)+byte(ctx.StreamCount) {
- return errors.New("index must < (streamcount + stereo streamcount)")
- }
- for j := 0; j < i; j++ {
- if channel[order(ctx.ChannelCount, i)] == index {
- cm.Copy = true
- cm.CopyFrom = j
- break
- }
- }
- if int(index) < 2*ctx.StereoStreamCount {
- cm.StreamIdx = int(index) / 2
- if index&1 == 0 {
- cm.ChannelIdx = LEFT_CHANNEL
- } else {
- cm.ChannelIdx = RIGHT_CHANNEL
- }
- } else {
- cm.StreamIdx = int(index) - ctx.StereoStreamCount
- cm.ChannelIdx = 0
- }
- ctx.ChannelMaps = append(ctx.ChannelMaps, cm)
- }
- return nil
- }
- func (ctx *OpusContext) WriteOpusExtraData() []byte {
- extraData := make([]byte, 19)
- copy(extraData, string("OpusHead"))
- extraData[8] = 0x01
- extraData[9] = byte(ctx.ChannelCount)
- binary.LittleEndian.PutUint16(extraData[10:], uint16(ctx.Preskip))
- binary.LittleEndian.PutUint32(extraData[12:], uint32(ctx.SampleRate))
- return extraData
- }
- func WriteDefaultOpusExtraData() []byte {
- return []byte{
- 'O', 'p', 'u', 's', 'H', 'e', 'a', 'd',
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- }
- }
|