github.com/puellanivis/breton@v0.2.16/lib/mpeg/ts/psi/utils.go (about)

     1  package psi
     2  
     3  import (
     4  	"github.com/pkg/errors"
     5  )
     6  
     7  // CommonMarshal takes care of the common elements of encoding a PSI table.
     8  func CommonMarshal(id uint8, private bool, syn *SectionSyntax, data []byte) ([]byte, error) {
     9  	// len(common_header) + len(data) + len(crc)
    10  	l := 4 + len(data) + 4
    11  
    12  	var sb []byte
    13  	if syn != nil {
    14  		var err error
    15  
    16  		sb, err = syn.Marshal()
    17  		if err != nil {
    18  			return nil, err
    19  		}
    20  
    21  		l += len(sb)
    22  	}
    23  
    24  	b := make([]byte, l)
    25  
    26  	b[1] = id
    27  	if private {
    28  		b[2] |= flagPrivate
    29  	}
    30  
    31  	start := 4
    32  	secLen := l - start
    33  	if secLen > 1021 {
    34  		return nil, errors.New("section_length may not exceed 1021")
    35  	}
    36  	b[2] |= byte((secLen>>8)&0x0F) | 0x30
    37  	b[3] = byte(secLen & 0xFF)
    38  
    39  	if syn != nil {
    40  		b[2] |= flagSectionSyntax
    41  
    42  		copy(b[start:], sb)
    43  		start += len(sb)
    44  	}
    45  
    46  	// copy in the SectionSyntax
    47  	copy(b[start:], data)
    48  
    49  	// TODO(puellanivis): calculate CRC32
    50  	copy(b[l-4:], []byte{0xde, 0xad, 0xbe, 0xef})
    51  
    52  	return b, nil
    53  }
    54  
    55  // CommonUnmarshal takes care of the common elements of decoding a PSI table.
    56  func CommonUnmarshal(b []byte) (syn *SectionSyntax, data []byte, crc uint32, err error) {
    57  	secLen := int(b[1]&0x0F)<<8 | int(b[2])
    58  	if secLen > 1021 {
    59  		return nil, nil, 0, errors.New("section_length may not exceed 1021")
    60  	}
    61  
    62  	start := 3
    63  
    64  	if b[1]&flagSectionSyntax != 0 {
    65  		syn = new(SectionSyntax)
    66  
    67  		if err := syn.Unmarshal(b[3:]); err != nil {
    68  			return nil, nil, 0, err
    69  		}
    70  
    71  		start += 5
    72  		secLen -= 5
    73  	}
    74  
    75  	end := start + secLen - 4
    76  	if start >= len(b) {
    77  		return nil, nil, 0, errors.New("buffer too short")
    78  	}
    79  	if end+4 > len(b) {
    80  		return nil, nil, 0, errors.New("section_length overruns buffer")
    81  	}
    82  	if end < 0 {
    83  		return nil, nil, 0, errors.New("section_length is too short")
    84  	}
    85  	data = b[start:end]
    86  
    87  	for _, b := range b[end : end+4] {
    88  		crc = (crc << 8) | uint32(b)
    89  	}
    90  
    91  	return syn, data, crc, nil
    92  }