github.com/bluenviron/mediacommon@v1.9.3/pkg/codecs/mpeg1audio/frame_header.go (about)

     1  package mpeg1audio
     2  
     3  import (
     4  	"fmt"
     5  )
     6  
     7  // http://www.mp3-tech.org/programmer/frame_header.html
     8  var bitrates = [][][]int{
     9  	// MPEG-1
    10  	{
    11  		// layer 1
    12  		{},
    13  		// layer 2
    14  		{
    15  			32000,
    16  			48000,
    17  			56000,
    18  			64000,
    19  			80000,
    20  			96000,
    21  			112000,
    22  			128000,
    23  			160000,
    24  			192000,
    25  			224000,
    26  			256000,
    27  			320000,
    28  			384000,
    29  		},
    30  		// layer 3
    31  		{
    32  			32000,
    33  			40000,
    34  			48000,
    35  			56000,
    36  			64000,
    37  			80000,
    38  			96000,
    39  			112000,
    40  			128000,
    41  			160000,
    42  			192000,
    43  			224000,
    44  			256000,
    45  			320000,
    46  		},
    47  	},
    48  	// MPEG-2
    49  	{
    50  		// layer 1
    51  		{},
    52  		// layer 2
    53  		{
    54  			8000,
    55  			16000,
    56  			24000,
    57  			32000,
    58  			40000,
    59  			48000,
    60  			56000,
    61  			64000,
    62  			80000,
    63  			96000,
    64  			112000,
    65  			128000,
    66  			144000,
    67  			160000,
    68  		},
    69  		// layer 3
    70  		{
    71  			8000,
    72  			16000,
    73  			24000,
    74  			32000,
    75  			40000,
    76  			48000,
    77  			56000,
    78  			64000,
    79  			80000,
    80  			96000,
    81  			112000,
    82  			128000,
    83  			144000,
    84  			160000,
    85  		},
    86  	},
    87  }
    88  
    89  var sampleRates = [][]int{
    90  	// MPEG-1
    91  	{
    92  		44100,
    93  		48000,
    94  		32000,
    95  	},
    96  	// MPEG-2
    97  	{
    98  		22050,
    99  		24000,
   100  		16000,
   101  	},
   102  }
   103  
   104  var samplesPerFrame = [][]int{
   105  	// MPEG-1
   106  	{
   107  		384,
   108  		1152,
   109  		1152,
   110  	},
   111  	// MPEG-2
   112  	{
   113  		384,
   114  		1152,
   115  		576,
   116  	},
   117  }
   118  
   119  // ChannelMode is a channel mode of a MPEG-1/2 audio frame.
   120  type ChannelMode int
   121  
   122  // standard channel modes.
   123  const (
   124  	ChannelModeStereo      ChannelMode = 0
   125  	ChannelModeJointStereo ChannelMode = 1
   126  	ChannelModeDualChannel ChannelMode = 2
   127  	ChannelModeMono        ChannelMode = 3
   128  )
   129  
   130  // FrameHeader is the header of a MPEG-1/2 audio frame.
   131  // Specification: ISO 11172-3, 2.4.1.3
   132  type FrameHeader struct {
   133  	MPEG2       bool
   134  	Layer       uint8
   135  	Bitrate     int
   136  	SampleRate  int
   137  	Padding     bool
   138  	ChannelMode ChannelMode
   139  }
   140  
   141  // Unmarshal decodes a FrameHeader.
   142  func (h *FrameHeader) Unmarshal(buf []byte) error {
   143  	if len(buf) < 5 {
   144  		return fmt.Errorf("not enough bytes")
   145  	}
   146  
   147  	syncWord := uint16(buf[0])<<4 | uint16(buf[1])>>4
   148  	if syncWord != 0x0FFF {
   149  		return fmt.Errorf("sync word not found: %x", syncWord)
   150  	}
   151  
   152  	h.MPEG2 = ((buf[1] >> 3) & 0x01) == 0
   153  
   154  	var mpegIndex int
   155  	if h.MPEG2 {
   156  		mpegIndex = 1
   157  	} else {
   158  		mpegIndex = 0
   159  	}
   160  
   161  	h.Layer = 4 - ((buf[1] >> 1) & 0b11)
   162  	if h.Layer <= 1 || h.Layer >= 4 {
   163  		return fmt.Errorf("unsupported MPEG layer: %v", h.Layer)
   164  	}
   165  
   166  	bitrateIndex := (buf[2] >> 4)
   167  	if bitrateIndex == 0 || bitrateIndex >= 15 {
   168  		return fmt.Errorf("invalid bitrate")
   169  	}
   170  	h.Bitrate = bitrates[mpegIndex][h.Layer-1][bitrateIndex-1]
   171  
   172  	sampleRateIndex := (buf[2] >> 2) & 0b11
   173  	if sampleRateIndex >= 3 {
   174  		return fmt.Errorf("invalid sample rate")
   175  	}
   176  	h.SampleRate = sampleRates[mpegIndex][sampleRateIndex]
   177  
   178  	h.Padding = ((buf[2] >> 1) & 0b1) != 0
   179  	h.ChannelMode = ChannelMode(buf[3] >> 6)
   180  
   181  	return nil
   182  }
   183  
   184  // FrameLen returns the length of the frame associated with the header.
   185  func (h FrameHeader) FrameLen() int {
   186  	if h.Padding {
   187  		return (144 * h.Bitrate / h.SampleRate) + 1
   188  	}
   189  	return (144 * h.Bitrate / h.SampleRate)
   190  }
   191  
   192  // SampleCount returns the number of samples contained into the frame.
   193  func (h FrameHeader) SampleCount() int {
   194  	var mpegIndex int
   195  	if h.MPEG2 {
   196  		mpegIndex = 1
   197  	} else {
   198  		mpegIndex = 0
   199  	}
   200  
   201  	return samplesPerFrame[mpegIndex][h.Layer-1]
   202  }