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

     1  package dvb
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	desc "github.com/puellanivis/breton/lib/mpeg/ts/descriptor"
     8  )
     9  
    10  // RunningStatus is an enum defining running state from the DVB standard for MPEG-TS.
    11  type RunningStatus uint8
    12  
    13  // RunningStatus enum values.
    14  const (
    15  	NotRunning RunningStatus = iota + 1
    16  	Starting
    17  	Pausing
    18  	Running
    19  	OffAir
    20  )
    21  
    22  var runningStatusNames = map[RunningStatus]string{
    23  	NotRunning: "NOT_RUN",
    24  	Starting:   "START",
    25  	Pausing:    "PAUSE",
    26  	Running:    "RUN",
    27  	OffAir:     "OFF_AIR",
    28  }
    29  
    30  func (rs RunningStatus) String() string {
    31  	if s, ok := runningStatusNames[rs]; ok {
    32  		return s
    33  	}
    34  
    35  	return fmt.Sprintf("x%X", uint8(rs))
    36  }
    37  
    38  // Service defines a single Service from the Service Description Table from the DVB standard for MPEG-TS.
    39  type Service struct {
    40  	ID            uint16
    41  	EITSchedule   bool
    42  	EITPresent    bool
    43  	RunningStatus RunningStatus
    44  	FreeCA        bool
    45  
    46  	Descriptors []desc.Descriptor
    47  }
    48  
    49  func (s *Service) String() string {
    50  	out := []string{
    51  		"DVB:Service",
    52  		fmt.Sprintf("ID:x%04X", s.ID),
    53  	}
    54  
    55  	if s.EITSchedule {
    56  		out = append(out, "EIT_SCHED")
    57  	}
    58  
    59  	if s.EITPresent {
    60  		out = append(out, "EIT_PRES")
    61  	}
    62  
    63  	out = append(out, fmt.Sprint(s.RunningStatus))
    64  
    65  	if s.FreeCA {
    66  		out = append(out, "FreeCA")
    67  	}
    68  
    69  	for _, d := range s.Descriptors {
    70  		out = append(out, fmt.Sprintf("Desc:%v", d))
    71  	}
    72  
    73  	return fmt.Sprintf("{%s}", strings.Join(out, " "))
    74  }
    75  
    76  const (
    77  	flagEITSchedule = 0x02
    78  	flagEITPresent  = 0x01
    79  
    80  	shiftRunningStatus = 5
    81  	maskRunningStatus  = 0x07
    82  
    83  	flagFreeCA = 0x10
    84  )
    85  
    86  func (s *Service) marshal() ([]byte, error) {
    87  	b := make([]byte, 5)
    88  
    89  	b[0] = byte((s.ID >> 8) & 0xff)
    90  	b[1] = byte(s.ID & 0xff)
    91  	b[2] = 0xFC
    92  
    93  	if s.EITSchedule {
    94  		b[2] |= flagEITSchedule
    95  	}
    96  
    97  	if s.EITPresent {
    98  		b[2] |= flagEITPresent
    99  	}
   100  
   101  	b[3] = byte((s.RunningStatus & maskRunningStatus) << shiftRunningStatus)
   102  	if s.FreeCA {
   103  		b[3] |= flagFreeCA
   104  	}
   105  
   106  	loopLen := 0
   107  	for _, d := range s.Descriptors {
   108  		db, err := d.Marshal()
   109  		if err != nil {
   110  			return nil, err
   111  		}
   112  
   113  		loopLen += len(db)
   114  		b = append(b, db...)
   115  	}
   116  
   117  	b[3] |= byte((loopLen >> 8) & 0x0F)
   118  	b[4] = byte(loopLen & 0xFF)
   119  
   120  	return b, nil
   121  }
   122  
   123  func (s *Service) unmarshal(b []byte) (int, error) {
   124  	s.ID = uint16(b[0])<<8 | uint16(b[1])
   125  	s.EITSchedule = b[2]&flagEITSchedule != 0
   126  	s.EITPresent = b[2]&flagEITPresent != 0
   127  	s.RunningStatus = RunningStatus((b[3] >> shiftRunningStatus) & maskRunningStatus)
   128  	s.FreeCA = b[3]&flagFreeCA != 0
   129  
   130  	loopLen := int(b[3]&0x0F)<<8 | int(b[4])
   131  
   132  	start := 0
   133  	b = b[5:]
   134  
   135  	for start < loopLen {
   136  		pd, err := desc.Unmarshal(b[start:])
   137  		if err != nil {
   138  			return start, err
   139  		}
   140  
   141  		start += pd.Len()
   142  		s.Descriptors = append(s.Descriptors, pd)
   143  	}
   144  
   145  	return start + 5, nil
   146  }