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

     1  package packet
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  // TransportScrambleControl is an enum of what kind of MPEG Transport Scramble Control is to be used.
    12  type TransportScrambleControl byte
    13  
    14  // TransportScrambleControl enum values.
    15  const (
    16  	ScrambleNone TransportScrambleControl = iota
    17  	scrambleReserve
    18  	ScrambleEven
    19  	ScrambleOdd
    20  )
    21  
    22  // Packet defines a single MPEG-TS packet.
    23  type Packet struct {
    24  	PID      uint16
    25  	TEI      bool
    26  	PUSI     bool
    27  	Priority bool
    28  
    29  	ScrambleControl TransportScrambleControl
    30  	*AdaptationField
    31  	Continuity byte
    32  
    33  	Payload []byte
    34  }
    35  
    36  func (p *Packet) String() string {
    37  	var out []string
    38  
    39  	out = append(out, fmt.Sprintf("PID:x%04X", p.PID), fmt.Sprintf("[%X]", p.Continuity))
    40  	if p.TEI {
    41  		out = append(out, "TEI")
    42  	}
    43  	if p.PUSI {
    44  		out = append(out, "PUSI")
    45  	}
    46  	if p.Priority {
    47  		out = append(out, "PRI")
    48  	}
    49  
    50  	switch p.ScrambleControl {
    51  	case ScrambleNone:
    52  	case ScrambleEven:
    53  		out = append(out, "EVEN")
    54  	case ScrambleOdd:
    55  		out = append(out, "ODD")
    56  	}
    57  
    58  	if p.AdaptationField != nil {
    59  		out = append(out, fmt.Sprintf("AF:%+v", p.AdaptationField))
    60  	}
    61  
    62  	if len(p.Payload) > 0 {
    63  		pl := fmt.Sprintf("Payload[%d]", len(p.Payload))
    64  
    65  		if len(p.Payload) > 16 {
    66  			pl = fmt.Sprintf("%s{ % 2X… }", pl, p.Payload[:16])
    67  		} else {
    68  			pl = fmt.Sprintf("%s{ % 2X }", pl, p.Payload)
    69  		}
    70  
    71  		out = append(out, pl)
    72  	}
    73  
    74  	return fmt.Sprintf("{%s}", strings.Join(out, " "))
    75  }
    76  
    77  const (
    78  	flagTEI      = 0x80
    79  	flagPUSI     = 0x40
    80  	flagPriority = 0x20
    81  
    82  	flagPayload         = 0x10
    83  	flagAdaptationField = 0x20
    84  
    85  	// Length is how long an MPEG-TS packet is.
    86  	Length = 188
    87  
    88  	// HeaderLength is the length of an MPEG-TS packet.
    89  	HeaderLength = 4
    90  
    91  	// MaxPayload is the maximum length of payload that may be put into a packet.
    92  	MaxPayload = Length - HeaderLength
    93  )
    94  
    95  // Bytes returns the payload of the Packet as a byte slice.
    96  func (p *Packet) Bytes() []byte {
    97  	return p.Payload
    98  }
    99  
   100  // Unmarshal decodes a byte slice into the Packet.
   101  func (p *Packet) Unmarshal(b []byte) error {
   102  	if len(b) != Length || b[0] != 'G' {
   103  		return errors.Errorf("invalid packet %v", b[:4])
   104  	}
   105  
   106  	p.TEI = (b[1] & flagTEI) != 0
   107  	p.PUSI = (b[1] & flagPUSI) != 0
   108  	p.Priority = (b[1] & flagPriority) != 0
   109  
   110  	p.PID = (uint16(b[1]&0x1f) << 8) | uint16(b[2])
   111  
   112  	p.ScrambleControl = TransportScrambleControl((b[3] >> 6) & 0x03)
   113  	p.Continuity = b[3] & 0x0f
   114  
   115  	start := 4
   116  
   117  	if b[3]&flagAdaptationField != 0 {
   118  		af := new(AdaptationField)
   119  
   120  		l, err := af.unmarshal(b[start:])
   121  		if err != nil {
   122  			return err
   123  		}
   124  
   125  		p.AdaptationField = af
   126  
   127  		start += l
   128  	}
   129  
   130  	if b[3]&flagPayload != 0 {
   131  		p.Payload = append([]byte{}, b[start:]...)
   132  	}
   133  
   134  	return nil
   135  }
   136  
   137  var fullPadding = bytes.Repeat([]byte{0xFF}, Length)
   138  
   139  // Marshal encodes a Packet into a byte slice.
   140  func (p *Packet) Marshal() ([]byte, error) {
   141  	if p.PID > 0x1fff {
   142  		return nil, errors.Errorf("PID %d is greater than maximum 0x1fff", p.PID)
   143  	}
   144  
   145  	packet := make([]byte, Length)
   146  
   147  	packet[0] = 'G'
   148  
   149  	if p.TEI {
   150  		packet[1] |= flagTEI
   151  	}
   152  
   153  	if p.PUSI {
   154  		packet[1] |= flagPUSI
   155  	}
   156  
   157  	if p.Priority {
   158  		packet[1] |= flagPriority
   159  	}
   160  
   161  	packet[1] |= byte((p.PID >> 8) & 0x1f)
   162  	packet[2] = byte(p.PID & 0xff)
   163  
   164  	packet[3] = byte((p.ScrambleControl&0x03)<<6) | byte(p.Continuity&0x0f)
   165  
   166  	start := 4
   167  	if p.AdaptationField != nil {
   168  		packet[3] |= flagAdaptationField
   169  
   170  		b, err := p.AdaptationField.marshal()
   171  		if err != nil {
   172  			return nil, err
   173  		}
   174  
   175  		n := copy(packet[start:], b)
   176  		start += n
   177  	}
   178  
   179  	if len(p.Payload) > 0 {
   180  		packet[3] |= flagPayload
   181  
   182  		n := copy(packet[start:], p.Payload)
   183  		start += n
   184  
   185  		if n < len(p.Payload) {
   186  			return nil, errors.Errorf("short packet: %d < %d", n, len(p.Payload))
   187  		}
   188  	}
   189  
   190  	copy(packet[start:], fullPadding)
   191  
   192  	return packet, nil
   193  }