package ts import ( "github.com/ziutek/dvb" "io" "os" "syscall" ) var ( // ErrSync means a lost of MPEG-TS synchronization. ErrSync = dvb.TemporaryError("MPEG-TS synchronization error") ) // PktReader is an interface that wraps the ReadPkt method. type PktReader interface { // ReadPkt reads one MPEG-TS packet. // If it returns ErrSync or dvb.ErrOverflow you can try to read next // packet. ReadPkt(Pkt) error } // PktStreamReader wraps any io.Reader interface and returns PktReader and // PktReplacer implementation for read MPEG-TS packets from stream of bytes. // Internally it doesn't allocate any memory so is friendly for real-time // applications (it doesn't cause GC to run). // // Using PktStreamReader you can start read at any point in stream. If the start point // doesn't match a beginning of a packet, PktReader returns ErrSync and // tries to synchronize during next read. type PktStreamReader struct {
func (nit NIT) Current() bool { return Table(nit).Current() } func (nit NIT) NetId() uint16 { return Table(nit).TableIdExt() } func (nit NIT) s() Section { if len(nit) == 0 { panic("NIT doesn't contain valid data") } return nit[0] } var ErrNITSectionLen = dvb.TemporaryError("incorrect NIT section length") // Update reads next NIT from r func (nit *NIT) Update(r SectionReader, actualMux bool, current bool) error { tableId := byte(0x41) if actualMux { tableId = 0x40 } return (*Table)(nit).Update(r, tableId, true, current, ISOSectionMaxLen) } // Descriptors returns network descriptors list func (nit NIT) Descriptors() TableDescriptors { // BUG: Network descriptros can be in more than one (first) section. They // should be located in the first sections of table and they should end // before first not empty transport stream looop.
type SDT Table func (sdt SDT) Version() int8 { return Table(sdt).Version() } func (sdt SDT) Current() bool { return Table(sdt).Current() } func (sdt SDT) MuxId() uint16 { return Table(sdt).TableIdExt() } var ErrSDTSectionLen = dvb.TemporaryError("incorrect SDT section length") // Update reads next SDT from r func (sdt *SDT) Update(r SectionReader, actualMux bool, current bool) error { tableId := byte(0x46) if actualMux { tableId = 0x42 } t := (*Table)(sdt) err := t.Update(r, tableId, true, current, ISOSectionMaxLen) if err != nil { return err } for _, s := range *t { if len(s.Data()) < 2 { t.Reset()
package psi import ( "github.com/ziutek/dvb" "time" ) const TDTSectionLen = 3 + 5 var ErrTDTSectionSyntax = dvb.TemporaryError("incorrect TDT section syntax") func ParseTDT(s Section) (time.Time, error) { if s.TableId() != 0x70 || s.GenericSyntax() || !s.PrivateSyntax() || s.Len() != TDTSectionLen { return time.Time{}, ErrTDTSectionSyntax } return decodeMJDUTC(s[3:8]) } type TDT Section func MakeTDT() TDT { s := MakeEmptySection(TDTSectionLen, false) s.SetTableId(0x70) s.SetPrivateSyntax(true) s.Alloc(5, 0) return TDT(s) } // SetTime converts UTC time t to MJD and stores it in tdt. TDT has no // CRC sum so modified TDT is valid. func (tdt TDT) SetTime(t time.Time) {
package psi import ( "github.com/ziutek/dvb" ) var ( ErrTableSectionNumber = dvb.TemporaryError("Table: incorrect section number") ErrTableSyntax = dvb.TemporaryError("Table: incorrect section syntax") ) type Table []Section func (t Table) check() { if len(t) == 0 { panic("table doesn't contain valid data") } } func (t *Table) Reset() { *t = (*t)[:0] } func (t Table) TableId() byte { t.check() return t[0].TableId() } func (t Table) SetTableId(id byte) { t.check() for _, s := range t {
} func (p PMT) progInfoLen() int { return int(decodeU16(Section(p).Data()[2:4]) & 0x0fff) } func (p PMT) ProgramDescriptors() DescriptorList { return DescriptorList(Section(p).Data()[4 : 4+p.progInfoLen()]) } func (p PMT) ESInfo() ESInfoList { return ESInfoList(Section(p).Data()[4+p.progInfoLen():]) } var ( ErrPMTSectionSyntax = dvb.TemporaryError("incorrect PMT section syntax") ErrPMTProgInfoLen = dvb.TemporaryError("incorrect PMT program info length") ) // AsPMT returns s as PMT or error if s isn't PMT section. This works because // PMT should fit in one section (other tables occupy multiple sections. func AsPMT(s Section) (PMT, error) { if s.TableId() != 2 || !s.GenericSyntax() || s.Number() != 0 || s.LastNumber() != 0 { return nil, ErrPMTSectionSyntax } p := PMT(s) if p.progInfoLen()+4 > len(s.Data()) { return nil, ErrPMTProgInfoLen } return p, nil
package psi import ( "github.com/ziutek/dvb" "github.com/ziutek/dvb/ts" ) var ( ErrSectionLength = dvb.TemporaryError("incorrect value of section_length field") ErrSectionPointer = dvb.TemporaryError("incorrect pointer_field") ErrSectionSpace = dvb.TemporaryError("no free space for section decoding") ErrSectionSyntax = dvb.TemporaryError("section syntax indicator not set") ErrSectionCRC = dvb.TemporaryError("section has incorrect CRC") ErrSectionReserved = dvb.TemporaryError("section has wrong value of header reserved bits") ErrSectionData = dvb.TemporaryError("too few data to decode section") ) // SectionDecoder can decode section from stream of packets type SectionDecoder struct { r ts.PktReplacer pkt *ts.ArrayPkt buffered bool // Not processed data in pkt check bool } // NewSectionDecoder creates section decoder. You can use r == nil and // set source of packets lather using SetPktReplacer or SetPktReader method. // If check is true decoder checks value of reserved header bits and CRC. func NewSectionDecoder(r ts.PktReplacer, check bool) *SectionDecoder { return &SectionDecoder{r: r, pkt: new(ts.ArrayPkt), check: check} }