Files
monibuca/plugin/mp4/pkg/box/dops.go
2024-09-12 18:23:36 +08:00

126 lines
3.4 KiB
Go

package box
import (
"encoding/binary"
"io"
"github.com/yapingcat/gomedia/go-codec"
)
// class ChannelMappingTable (unsigned int(8) OutputChannelCount){
// unsigned int(8) StreamCount;
// unsigned int(8) CoupledCount;
// unsigned int(8 * OutputChannelCount) ChannelMapping;
// }
// aligned(8) class OpusSpecificBox extends Box('dOps'){
// unsigned int(8) Version;
// unsigned int(8) OutputChannelCount;
// unsigned int(16) PreSkip;
// unsigned int(32) InputSampleRate;
// signed int(16) OutputGain;
// unsigned int(8) ChannelMappingFamily;
// if (ChannelMappingFamily != 0) {
// ChannelMappingTable(OutputChannelCount);
// }
// }
type ChannelMappingTable struct {
StreamCount uint8
CoupledCount uint8
ChannelMapping []byte
}
type OpusSpecificBox struct {
Box *BasicBox
Version uint8
OutputChannelCount uint8
PreSkip uint16
InputSampleRate uint32
OutputGain int16
ChanMapTable *ChannelMappingTable
}
func NewdOpsBox() *OpusSpecificBox {
return &OpusSpecificBox{
Box: NewBasicBox([4]byte{'d', 'O', 'p', 's'}),
}
}
func (dops *OpusSpecificBox) Size() uint64 {
return uint64(8 + 10 + 2 + dops.OutputChannelCount)
}
func (dops *OpusSpecificBox) Encode() (int, []byte) {
dops.Box.Size = dops.Size()
offset, buf := dops.Box.Encode()
buf[offset] = dops.Version
offset++
buf[offset] = dops.OutputChannelCount
offset++
binary.LittleEndian.PutUint16(buf[offset:], dops.PreSkip)
offset += 2
binary.BigEndian.PutUint32(buf[offset:], dops.InputSampleRate)
offset += 4
binary.LittleEndian.PutUint16(buf[offset:], uint16(dops.OutputGain))
offset += 2
if dops.ChanMapTable != nil {
buf[offset] = dops.ChanMapTable.StreamCount
offset++
buf[offset] = dops.ChanMapTable.CoupledCount
offset++
copy(buf[offset:], dops.ChanMapTable.ChannelMapping)
offset += len(dops.ChanMapTable.ChannelMapping)
}
return offset, buf
}
func (dops *OpusSpecificBox) Decode(r io.Reader, size uint32) (offset int, err error) {
dopsBuf := make([]byte, size-BasicBoxLen)
ChannelMappingFamily := 0
if size-BasicBoxLen-10 > 0 {
ChannelMappingFamily = int(size - BasicBoxLen - 10)
}
if _, err = io.ReadFull(r, dopsBuf); err != nil {
return
}
dops.Version = dopsBuf[0]
dops.OutputChannelCount = dopsBuf[1]
dops.PreSkip = binary.BigEndian.Uint16(dopsBuf[2:])
dops.InputSampleRate = binary.BigEndian.Uint32(dopsBuf[4:])
dops.OutputGain = int16(binary.BigEndian.Uint16(dopsBuf[8:]))
dops.ChanMapTable = nil
if ChannelMappingFamily > 0 {
dops.ChanMapTable = &ChannelMappingTable{}
dops.ChanMapTable.StreamCount = dopsBuf[10]
dops.ChanMapTable.CoupledCount = dopsBuf[11]
dops.ChanMapTable.ChannelMapping = make([]byte, ChannelMappingFamily-2)
copy(dops.ChanMapTable.ChannelMapping, dopsBuf[12:])
}
return int(size - BasicBoxLen), nil
}
func MakeOpusSpecificBox(extraData []byte) []byte {
ctx := &codec.OpusContext{}
ctx.ParseExtranData(extraData)
dops := NewdOpsBox()
dops.Version = 0
dops.OutputChannelCount = uint8(ctx.ChannelCount)
dops.PreSkip = uint16(ctx.Preskip)
dops.InputSampleRate = uint32(ctx.SampleRate)
dops.OutputGain = int16(ctx.OutputGain)
if ctx.MapType > 0 {
dops.ChanMapTable = &ChannelMappingTable{
StreamCount: uint8(ctx.StreamCount),
CoupledCount: uint8(ctx.StereoStreamCount),
ChannelMapping: make([]byte, len(ctx.Channel)),
}
copy(dops.ChanMapTable.ChannelMapping, ctx.Channel)
}
_, dopsbox := dops.Encode()
return dopsbox
}