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

     1  package dvb
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/pkg/errors"
     8  	"github.com/puellanivis/breton/lib/mpeg/ts/psi"
     9  )
    10  
    11  // ServiceDescriptorTable defines a Service Descriptor Table from the DVB standard for MPEG-TS.
    12  // It is a PSI.
    13  type ServiceDescriptorTable struct {
    14  	Syntax *psi.SectionSyntax
    15  
    16  	OriginalNetworkID uint16
    17  
    18  	Services []*Service
    19  
    20  	crc uint32
    21  }
    22  
    23  const (
    24  	tableidSDT = 0x42
    25  )
    26  
    27  func init() {
    28  	psi.Register(tableidSDT, func() psi.PSI { return new(ServiceDescriptorTable) })
    29  }
    30  
    31  // TableID implements mpeg/ts/psi.PSI.
    32  func (sdt *ServiceDescriptorTable) TableID() uint8 {
    33  	return tableidSDT
    34  }
    35  
    36  // SectionSyntax returns the embedded SectionSyntax, and implements mpeg/ts/psi.PSI.
    37  func (sdt *ServiceDescriptorTable) SectionSyntax() *psi.SectionSyntax {
    38  	return sdt.Syntax
    39  }
    40  
    41  func (sdt *ServiceDescriptorTable) String() string {
    42  	out := []string{
    43  		"DVB:SDT",
    44  	}
    45  
    46  	if sdt.Syntax != nil {
    47  		out = append(out, fmt.Sprint(sdt.Syntax))
    48  	}
    49  
    50  	out = append(out, fmt.Sprintf("OrigNetID:%04X", sdt.OriginalNetworkID))
    51  
    52  	for _, s := range sdt.Services {
    53  		out = append(out, s.String())
    54  	}
    55  
    56  	return fmt.Sprintf("{%s}", strings.Join(out, " "))
    57  }
    58  
    59  // Unmarshal decodes a byte slice into the ServiceDescriptorTable.
    60  func (sdt *ServiceDescriptorTable) Unmarshal(b []byte) error {
    61  	if b[0] != tableidSDT {
    62  		return errors.Errorf("table_id mismatch: x%02X != x%02X", b[0], tableidSDT)
    63  	}
    64  
    65  	syn, data, crc, err := psi.CommonUnmarshal(b)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	sdt.Syntax = syn
    71  	sdt.crc = crc
    72  
    73  	sdt.OriginalNetworkID = uint16(data[0])<<8 | uint16(data[1])
    74  
    75  	start := 3 // original_network_id uint16 + reserved_future_use uint8
    76  	for start < len(data) {
    77  		s := new(Service)
    78  
    79  		l, err := s.unmarshal(data[start:])
    80  		if err != nil {
    81  			return err
    82  		}
    83  
    84  		sdt.Services = append(sdt.Services, s)
    85  
    86  		start += l
    87  	}
    88  
    89  	return nil
    90  }
    91  
    92  // Marshal encodes a ServiceDescriptorTable into a byte slice.
    93  func (sdt *ServiceDescriptorTable) Marshal() ([]byte, error) {
    94  	data := make([]byte, 3)
    95  
    96  	data[0] = byte(sdt.OriginalNetworkID >> 8 & 0xFF)
    97  	data[1] = byte(sdt.OriginalNetworkID & 0xFF)
    98  	data[2] = 0xFF // reserved_future_use
    99  
   100  	for _, s := range sdt.Services {
   101  		sb, err := s.marshal()
   102  		if err != nil {
   103  			return nil, err
   104  		}
   105  
   106  		data = append(data, sb...)
   107  	}
   108  
   109  	return psi.CommonMarshal(tableidSDT, true, sdt.Syntax, data)
   110  }