github.com/bluenviron/mediacommon@v1.9.3/pkg/codecs/mpeg4audio/stream_mux_config.go (about)

     1  package mpeg4audio
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/bluenviron/mediacommon/pkg/bits"
     7  )
     8  
     9  // StreamMuxConfigLayer is a layer of a StreamMuxConfig.
    10  type StreamMuxConfigLayer struct {
    11  	AudioSpecificConfig       *AudioSpecificConfig
    12  	FrameLengthType           uint
    13  	LatmBufferFullness        uint
    14  	FrameLength               uint
    15  	CELPframeLengthTableIndex uint
    16  	HVXCframeLengthTableIndex bool
    17  }
    18  
    19  // StreamMuxConfigProgram is a program of a StreamMuxConfig.
    20  type StreamMuxConfigProgram struct {
    21  	Layers []*StreamMuxConfigLayer
    22  }
    23  
    24  // StreamMuxConfig is a StreamMuxConfig.
    25  // Specification: ISO 14496-3, Table 1.42
    26  type StreamMuxConfig struct {
    27  	NumSubFrames     uint
    28  	Programs         []*StreamMuxConfigProgram
    29  	OtherDataPresent bool
    30  	OtherDataLenBits uint32
    31  	CRCCheckPresent  bool
    32  	CRCCheckSum      uint8
    33  }
    34  
    35  // Unmarshal decodes a StreamMuxConfig.
    36  func (c *StreamMuxConfig) Unmarshal(buf []byte) error {
    37  	pos := 0
    38  
    39  	err := bits.HasSpace(buf, pos, 12)
    40  	if err != nil {
    41  		return err
    42  	}
    43  
    44  	audioMuxVersion := bits.ReadFlagUnsafe(buf, &pos)
    45  	if audioMuxVersion {
    46  		return fmt.Errorf("audioMuxVersion = 1 is not supported")
    47  	}
    48  
    49  	allStreamsSameTimeFraming := bits.ReadFlagUnsafe(buf, &pos)
    50  	if !allStreamsSameTimeFraming {
    51  		return fmt.Errorf("allStreamsSameTimeFraming = 0 is not supported")
    52  	}
    53  
    54  	c.NumSubFrames = uint(bits.ReadBitsUnsafe(buf, &pos, 6))
    55  	numProgram := uint(bits.ReadBitsUnsafe(buf, &pos, 4))
    56  
    57  	c.Programs = make([]*StreamMuxConfigProgram, numProgram+1)
    58  
    59  	for prog := uint(0); prog <= numProgram; prog++ {
    60  		p := &StreamMuxConfigProgram{}
    61  		c.Programs[prog] = p
    62  
    63  		numLayer, err := bits.ReadBits(buf, &pos, 3)
    64  		if err != nil {
    65  			return err
    66  		}
    67  
    68  		p.Layers = make([]*StreamMuxConfigLayer, numLayer+1)
    69  
    70  		for lay := uint(0); lay <= uint(numLayer); lay++ {
    71  			l := &StreamMuxConfigLayer{}
    72  			p.Layers[lay] = l
    73  
    74  			var useSameConfig bool
    75  
    76  			if prog == 0 && lay == 0 {
    77  				useSameConfig = false
    78  			} else {
    79  				var err error
    80  				useSameConfig, err = bits.ReadFlag(buf, &pos)
    81  				if err != nil {
    82  					return err
    83  				}
    84  			}
    85  
    86  			if !useSameConfig {
    87  				l.AudioSpecificConfig = &AudioSpecificConfig{}
    88  				err := l.AudioSpecificConfig.UnmarshalFromPos(buf, &pos)
    89  				if err != nil {
    90  					return err
    91  				}
    92  			}
    93  
    94  			tmp, err := bits.ReadBits(buf, &pos, 3)
    95  			if err != nil {
    96  				// support truncated configs
    97  				l.LatmBufferFullness = 255
    98  				return nil //nolint:nilerr
    99  			}
   100  			l.FrameLengthType = uint(tmp)
   101  
   102  			switch l.FrameLengthType {
   103  			case 0:
   104  				tmp, err := bits.ReadBits(buf, &pos, 8)
   105  				if err != nil {
   106  					return err
   107  				}
   108  				l.LatmBufferFullness = uint(tmp)
   109  
   110  			case 1:
   111  				tmp, err := bits.ReadBits(buf, &pos, 9)
   112  				if err != nil {
   113  					return err
   114  				}
   115  				l.FrameLength = uint(tmp)
   116  
   117  			case 4, 5, 3:
   118  				tmp, err := bits.ReadBits(buf, &pos, 6)
   119  				if err != nil {
   120  					return err
   121  				}
   122  				l.CELPframeLengthTableIndex = uint(tmp)
   123  
   124  			case 6, 7:
   125  				var err error
   126  				l.HVXCframeLengthTableIndex, err = bits.ReadFlag(buf, &pos)
   127  				if err != nil {
   128  					return err
   129  				}
   130  			}
   131  		}
   132  	}
   133  
   134  	c.OtherDataPresent, err = bits.ReadFlag(buf, &pos)
   135  	if err != nil {
   136  		return err
   137  	}
   138  
   139  	if c.OtherDataPresent {
   140  		for {
   141  			c.OtherDataLenBits *= 256
   142  
   143  			err := bits.HasSpace(buf, pos, 9)
   144  			if err != nil {
   145  				return err
   146  			}
   147  
   148  			otherDataLenEsc := bits.ReadFlagUnsafe(buf, &pos)
   149  			otherDataLenTmp := uint32(bits.ReadBitsUnsafe(buf, &pos, 8))
   150  			c.OtherDataLenBits += otherDataLenTmp
   151  
   152  			if !otherDataLenEsc {
   153  				break
   154  			}
   155  		}
   156  	}
   157  
   158  	c.CRCCheckPresent, err = bits.ReadFlag(buf, &pos)
   159  	if err != nil {
   160  		return err
   161  	}
   162  
   163  	if c.CRCCheckPresent {
   164  		tmp, err := bits.ReadBits(buf, &pos, 8)
   165  		if err != nil {
   166  			return err
   167  		}
   168  		c.CRCCheckSum = uint8(tmp)
   169  	}
   170  
   171  	return nil
   172  }
   173  
   174  func (c StreamMuxConfig) marshalSize() int {
   175  	n := 12
   176  
   177  	for prog, p := range c.Programs {
   178  		n += 3
   179  
   180  		for lay, l := range p.Layers {
   181  			if prog != 0 || lay != 0 {
   182  				n++
   183  			}
   184  
   185  			if l.AudioSpecificConfig != nil {
   186  				n += l.AudioSpecificConfig.marshalSizeBits()
   187  			}
   188  
   189  			n += 3
   190  
   191  			switch l.FrameLengthType {
   192  			case 0:
   193  				n += 8
   194  
   195  			case 1:
   196  				n += 9
   197  
   198  			case 4, 5, 3:
   199  				n += 6
   200  
   201  			case 6, 7:
   202  				n++
   203  			}
   204  		}
   205  	}
   206  
   207  	n++ // otherDataPresent
   208  
   209  	if c.OtherDataPresent {
   210  		tmp := c.OtherDataLenBits
   211  		for {
   212  			tmp /= 256
   213  			n += 9
   214  
   215  			if tmp == 0 {
   216  				break
   217  			}
   218  		}
   219  	}
   220  
   221  	n++ // crcCheckPresent
   222  
   223  	if c.CRCCheckPresent {
   224  		n += 8
   225  	}
   226  
   227  	ret := n / 8
   228  	if (n % 8) != 0 {
   229  		ret++
   230  	}
   231  
   232  	return ret
   233  }
   234  
   235  // Marshal encodes a StreamMuxConfig.
   236  func (c StreamMuxConfig) Marshal() ([]byte, error) {
   237  	buf := make([]byte, c.marshalSize())
   238  	pos := 0
   239  
   240  	bits.WriteBits(buf, &pos, 0, 1) // audioMuxVersion
   241  	bits.WriteBits(buf, &pos, 1, 1) // allStreamsSameTimeFraming
   242  	bits.WriteBits(buf, &pos, uint64(c.NumSubFrames), 6)
   243  	bits.WriteBits(buf, &pos, uint64(len(c.Programs)-1), 4)
   244  
   245  	for prog, p := range c.Programs {
   246  		bits.WriteBits(buf, &pos, uint64(len(p.Layers)-1), 3)
   247  
   248  		for lay, l := range p.Layers {
   249  			if prog != 0 || lay != 0 {
   250  				if l.AudioSpecificConfig != nil {
   251  					bits.WriteBits(buf, &pos, 0, 1)
   252  				} else {
   253  					bits.WriteBits(buf, &pos, 1, 1)
   254  				}
   255  			}
   256  
   257  			if l.AudioSpecificConfig != nil {
   258  				err := l.AudioSpecificConfig.marshalTo(buf, &pos)
   259  				if err != nil {
   260  					return nil, err
   261  				}
   262  			}
   263  
   264  			bits.WriteBits(buf, &pos, uint64(l.FrameLengthType), 3)
   265  
   266  			switch l.FrameLengthType {
   267  			case 0:
   268  				bits.WriteBits(buf, &pos, uint64(l.LatmBufferFullness), 8)
   269  
   270  			case 1:
   271  				bits.WriteBits(buf, &pos, uint64(l.FrameLength), 9)
   272  
   273  			case 4, 5, 3:
   274  				bits.WriteBits(buf, &pos, uint64(l.CELPframeLengthTableIndex), 6)
   275  
   276  			case 6, 7:
   277  				if l.HVXCframeLengthTableIndex {
   278  					bits.WriteBits(buf, &pos, 1, 1)
   279  				} else {
   280  					bits.WriteBits(buf, &pos, 0, 1)
   281  				}
   282  			}
   283  		}
   284  	}
   285  
   286  	if c.OtherDataPresent {
   287  		bits.WriteBits(buf, &pos, 1, 1)
   288  
   289  		var lenBytes []byte
   290  		tmp := c.OtherDataLenBits
   291  
   292  		for {
   293  			mod := tmp % 256
   294  			tmp -= mod
   295  			tmp /= 256
   296  			lenBytes = append(lenBytes, uint8(mod))
   297  
   298  			if tmp == 0 {
   299  				break
   300  			}
   301  		}
   302  
   303  		for i := len(lenBytes) - 1; i > 0; i-- {
   304  			bits.WriteBits(buf, &pos, 1, 1)
   305  			bits.WriteBits(buf, &pos, uint64(lenBytes[i]), 8)
   306  		}
   307  
   308  		bits.WriteBits(buf, &pos, 0, 1)
   309  		bits.WriteBits(buf, &pos, uint64(lenBytes[0]), 8)
   310  	} else {
   311  		bits.WriteBits(buf, &pos, 0, 1)
   312  	}
   313  
   314  	if c.CRCCheckPresent {
   315  		bits.WriteBits(buf, &pos, 1, 1)
   316  		bits.WriteBits(buf, &pos, uint64(c.CRCCheckSum), 8)
   317  	} else {
   318  		bits.WriteBits(buf, &pos, 0, 1)
   319  	}
   320  
   321  	return buf, nil
   322  }