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

     1  package psi
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/pkg/errors"
     8  )
     9  
    10  // ProgramMap defines an MPEG-TS Program Map entry.
    11  type ProgramMap struct {
    12  	ProgramNumber uint16
    13  	PID           uint16
    14  }
    15  
    16  // Set assigns a given program number and pid into the ProgramMap.
    17  func (pm *ProgramMap) Set(pnum, pid uint16) {
    18  	pm.ProgramNumber = pnum
    19  	if pid > 0x1FFF {
    20  		panic("PAT pids cannot exceed 0x1FFF")
    21  	}
    22  	pm.PID = pid
    23  }
    24  
    25  // PAT defines an MPEG-TS Program Allocation Table.
    26  type PAT struct {
    27  	Syntax *SectionSyntax
    28  
    29  	Map []ProgramMap
    30  
    31  	crc uint32
    32  }
    33  
    34  func (pat *PAT) String() string {
    35  	out := []string{
    36  		"PAT",
    37  	}
    38  
    39  	if pat.Syntax != nil {
    40  		out = append(out, fmt.Sprint(pat.Syntax))
    41  	}
    42  
    43  	for _, m := range pat.Map {
    44  		out = append(out, fmt.Sprintf("x%X:x%X", m.ProgramNumber, m.PID))
    45  	}
    46  
    47  	out = append(out, fmt.Sprintf("crc:x%08X", pat.crc))
    48  
    49  	return fmt.Sprintf("{%s}", strings.Join(out, " "))
    50  }
    51  
    52  const (
    53  	tableidPAT = 0x00
    54  )
    55  
    56  func init() {
    57  	Register(tableidPAT, func() PSI { return new(PAT) })
    58  }
    59  
    60  // TableID implements mpeg/ts/psi.PSI.
    61  func (pat *PAT) TableID() uint8 {
    62  	return tableidPAT
    63  }
    64  
    65  // SectionSyntax returns the embedded SectionSyntax, and implements mpeg/ts/psi.PSI.
    66  func (pat *PAT) SectionSyntax() *SectionSyntax {
    67  	return pat.Syntax
    68  }
    69  
    70  // Unmarshal decodes a byte slice into the PAT.
    71  func (pat *PAT) Unmarshal(b []byte) error {
    72  	if b[0] != tableidPAT {
    73  		return errors.Errorf("table_id mismatch: x%02X != x%02X", b[0], tableidPAT)
    74  	}
    75  
    76  	syn, data, crc, err := CommonUnmarshal(b)
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	pat.Syntax = syn
    82  	pat.crc = crc
    83  
    84  	pat.Map = make([]ProgramMap, len(data)/4)
    85  	for i := range pat.Map {
    86  		b := data[i*4:]
    87  
    88  		pat.Map[i].ProgramNumber = (uint16(b[0]) << 8) | uint16(b[1])
    89  		pat.Map[i].PID = (uint16(b[2]&0x1F) << 8) | uint16(b[3])
    90  	}
    91  
    92  	return nil
    93  }
    94  
    95  // Marshal encodes the PAT into a byte slice.
    96  func (pat *PAT) Marshal() ([]byte, error) {
    97  	data := make([]byte, len(pat.Map)*4)
    98  
    99  	for i := range pat.Map {
   100  		b := data[i*4:]
   101  
   102  		b[0] = byte((pat.Map[i].ProgramNumber >> 8) & 0xFF)
   103  		b[1] = byte(pat.Map[i].ProgramNumber & 0xFF)
   104  
   105  		b[2] = byte((pat.Map[i].PID>>8)&0x1F) | 0xE0
   106  		b[3] = byte(pat.Map[i].PID & 0xFF)
   107  	}
   108  
   109  	return CommonMarshal(tableidPAT, false, pat.Syntax, data)
   110  }