github.com/puellanivis/breton@v0.2.16/lib/mpeg/framer/framer.go (about)

     1  package framer
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"io"
     7  	"net/http"
     8  
     9  	"github.com/pkg/errors"
    10  )
    11  
    12  // Various MIME-Types for Audo/Video types.
    13  const (
    14  	AAC  = "audio/x-aac"
    15  	MP3  = "audio/mp3"
    16  	H264 = "video/h264"
    17  )
    18  
    19  // Scanner implemnets bufio.Scanner breaking up certain Audio/Video types into packet frames.
    20  type Scanner struct {
    21  	mediaType   string
    22  	frameDetect []byte
    23  
    24  	*bufio.Scanner
    25  }
    26  
    27  // MediaType returns what MIME-Type was detected by the Scanner.
    28  func (s *Scanner) MediaType() string {
    29  	if len(s.frameDetect) <= 0 {
    30  		return "unknown/unknown"
    31  	}
    32  
    33  	return s.mediaType
    34  }
    35  
    36  // GetPCR returns the current PCR from the Scanner, extracting the information from the MPEG frame header.
    37  //
    38  // TODO: currently unimplemented.
    39  func (s *Scanner) GetPCR() int64 {
    40  	return 0
    41  }
    42  
    43  var (
    44  	syncWordMP3nocrc = []byte{0xFF, 0xFA}
    45  	syncWordMP3      = []byte{0xFF, 0xFB}
    46  
    47  	syncWordAACnocrc = []byte{0xFF, 0xF0}
    48  	syncWordAAC      = []byte{0xFF, 0xF1}
    49  
    50  	syncWordNAL = []byte{0x00, 0x00, 0x00, 0x01}
    51  )
    52  
    53  // DetectContentType is a dropin replacement and wrapper for http.DetectContentType,
    54  // which additionally detects certain Audio/Video types.
    55  //
    56  // Before defering to http.DetectContentType, it looks for certain MPEG sync words supported by this library.
    57  func DetectContentType(data []byte) string {
    58  	switch {
    59  	// MPEG ADTS wrapped MP3
    60  	case bytes.Equal(data[:2], syncWordMP3):
    61  		return MP3
    62  
    63  	// MPEG ADTS wrapped AAC
    64  	case bytes.Equal(data[:2], syncWordAAC):
    65  		return AAC
    66  
    67  	// H264 byte stream.
    68  	case bytes.Equal(data[:4], syncWordNAL):
    69  		return H264
    70  	}
    71  
    72  	return http.DetectContentType(data)
    73  }
    74  
    75  func (s *Scanner) splitter(data []byte, atEOF bool) (advance int, token []byte, err error) {
    76  	if len(s.frameDetect) <= 0 {
    77  		if len(data) < 4 {
    78  			return 0, nil, nil
    79  		}
    80  
    81  		switch {
    82  		// MPEG ADTS wrapped MP3
    83  		case bytes.Equal(data[:2], syncWordMP3), bytes.Equal(data[:2], syncWordMP3nocrc):
    84  			s.mediaType = MP3
    85  			s.frameDetect = append([]byte{}, data[:2]...)
    86  
    87  		// MPEG ADTS wrapped AAC
    88  		case bytes.Equal(data[:2], syncWordAAC), bytes.Equal(data[:2], syncWordAACnocrc):
    89  			s.mediaType = AAC
    90  			s.frameDetect = append([]byte{}, data[:2]...)
    91  
    92  		// H264 byte stream.
    93  		case bytes.Equal(data[:4], syncWordNAL):
    94  			s.mediaType = H264
    95  			s.frameDetect = append([]byte{}, data[:4]...)
    96  
    97  		default:
    98  			return 0, nil, errors.New("unable to detect type")
    99  		}
   100  	}
   101  
   102  	advance = 1
   103  
   104  	if len(data) < 1 && atEOF {
   105  		return 0, nil, io.EOF
   106  	}
   107  
   108  	j := bytes.Index(data[advance:], s.frameDetect)
   109  	if j < 0 {
   110  		if atEOF {
   111  			return len(data), data, nil
   112  		}
   113  
   114  		// need more data
   115  		return 0, nil, nil
   116  	}
   117  
   118  	advance += j
   119  	return advance, data[:advance], nil
   120  }
   121  
   122  // NewScanner returns a new Scanner, which implements bufio.Scanner.
   123  // The Scanner reads from the given io.Reader, and chunks the data into packet frames.
   124  func NewScanner(r io.Reader) *Scanner {
   125  	s := &Scanner{
   126  		Scanner: bufio.NewScanner(r),
   127  	}
   128  	s.Split(s.splitter)
   129  	return s
   130  }