/* NAME MpegTs.go - provides a data structure intended to encapsulate the properties of an MpegTs packet and also functions to allow manipulation of these packets. DESCRIPTION See Readme.md AUTHOR Saxon A. Nelson-Milton LICENSE MpegTs.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean) It is free software: you can redistribute it and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with revid in gpl.txt. If not, see [GNU licenses](http://www.gnu.org/licenses). */ package mpegts import ( "bitbucket.org/ausocean/av/tools" "errors" //"fmt" ) const ( maxMpegTsSize = 188 mpegtsPayloadSize = 176 ) /* The below data struct encapsulates the fields of an MPEG-TS packet. Below is the formatting of an MPEG-TS packet for reference! MPEG-TS Packet Formatting ============================================================================ | octet no | bit 0 | bit 1 | bit 2 | bit 3 | bit 4 | bit 5 | bit 6 | bit 7 | ============================================================================ | octet 0 | sync byte (0x47) | ---------------------------------------------------------------------------- | octet 1 | TEI | PUSI | Prior | PID | ---------------------------------------------------------------------------- | octet 2 | PID cont. | ---------------------------------------------------------------------------- | octet 3 | TSC | AFC | CC | ---------------------------------------------------------------------------- | octet 4 | AFL | ---------------------------------------------------------------------------- | octet 5 | DI | RAI | ESPI | PCRF | OPCRF | SPF | TPDF | AFEF | ---------------------------------------------------------------------------- | optional | PCR (48 bits => 6 bytes) | ---------------------------------------------------------------------------- | - | PCR cont. | ---------------------------------------------------------------------------- | - | PCR cont. | ---------------------------------------------------------------------------- | - | PCR cont. | ---------------------------------------------------------------------------- | - | PCR cont. | ---------------------------------------------------------------------------- | - | PCR cont. | ---------------------------------------------------------------------------- | optional | OPCR (48 bits => 6 bytes) | ---------------------------------------------------------------------------- | - | OPCR cont. | ---------------------------------------------------------------------------- | - | OPCR cont. | ---------------------------------------------------------------------------- | - | OPCR cont. | ---------------------------------------------------------------------------- | - | OPCR cont. | ---------------------------------------------------------------------------- | - | OPCR cont. | ---------------------------------------------------------------------------- | optional | SC | ---------------------------------------------------------------------------- | optional | TPDL | ---------------------------------------------------------------------------- | optional | TPD (variable length) | ---------------------------------------------------------------------------- | - | ... | ---------------------------------------------------------------------------- | optional | Extension (variable length) | ---------------------------------------------------------------------------- | - | ... | ---------------------------------------------------------------------------- | optional | Stuffing (variable length) | ---------------------------------------------------------------------------- | - | ... | ---------------------------------------------------------------------------- | optional | Payload (variable length) | ---------------------------------------------------------------------------- | - | ... | ---------------------------------------------------------------------------- */ type MpegTsPacket struct { TEI bool // Transport Error Indicator PUSI bool // Payload Unit Start Indicator Priority bool // Tranposrt priority indicator PID uint16 // Packet identifier TSC byte // Transport Scrambling Control AFC byte // Adaption Field Control CC byte // Continuity Counter DI bool // Discontinouty indicator RAI bool // random access indicator ESPI bool // Elementary stream priority indicator PCRF bool // PCR flag OPCRF bool // OPCR flag SPF bool // Splicing point flag TPDF bool // Transport private data flag AFEF bool // Adaptation field extension flag PCR uint64 // Program clock reference OPCR uint64 // Original program clock reference SC byte // Splice countdown TPDL byte // Tranposrt private data length TPD []byte // Private data Ext []byte // Adaptation field extension Payload []byte // Mpeg ts payload } // TODO: make payload private considering we now have FillPayload method func (p *MpegTsPacket) FillPayload(channel chan byte){ p.Payload = make([]byte,0,mpegtsPayloadSize) currentPktLength := 6 + int(tools.BoolToByte(p.PCRF))*6+int(tools.BoolToByte(p.OPCRF))*6+ int(tools.BoolToByte(p.SPF))*1+int(tools.BoolToByte(p.TPDF))*1+len(p.TPD) for (currentPktLength+len(p.Payload)) < 188 { //fmt.Printf("len(channel): %v\n", len(channel)) select { case nextByte := <-channel: p.Payload = append(p.Payload,nextByte) default: return } } } func (p *MpegTsPacket) ToByteSlice() (output []byte, err error) { stuffingLength := 182-len(p.Payload)-len(p.TPD)-int(tools.BoolToByte(p.PCRF))*6- int(tools.BoolToByte(p.OPCRF))*6 - int(tools.BoolToByte(p.SPF)) var stuffing []byte if stuffingLength > 0 { stuffing = make([]byte,stuffingLength) } for i := range stuffing { stuffing[i] = 0xFF } afl := 1+int(tools.BoolToByte(p.PCRF))*6+int(tools.BoolToByte(p.OPCRF))* 6+int(tools.BoolToByte(p.SPF))*1+int(tools.BoolToByte(p.TPDF))*1+len(p.TPD)+len(stuffing) output = make([]byte,0,maxMpegTsSize) output = append(output, []byte{ 0x47, (tools.BoolToByte(p.TEI)<<7 | tools.BoolToByte(p.PUSI)<<6 | tools.BoolToByte(p.Priority)<<5 | byte((p.PID&0xFF00)>>8)), byte(p.PID & 0x00FF), (p.TSC<<6 | p.AFC<<4 | p.CC),}...) if p.AFC == 3 || p.AFC == 2 { output = append(output, []byte{ byte(afl), (tools.BoolToByte(p.DI)<<7 | tools.BoolToByte(p.RAI)<<6 | tools.BoolToByte(p.ESPI)<<5 | tools.BoolToByte(p.PCRF)<<4 | tools.BoolToByte(p.OPCRF)<<3 | tools.BoolToByte(p.SPF)<<2 | tools.BoolToByte(p.TPDF)<<1 | tools.BoolToByte(p.AFEF)), }...) for i := 40; p.PCRF && i >= 0; i-=8 { output = append(output, byte((p.PCR<<15)>>uint(i))) } for i := 40; p.OPCRF && i >= 0; i-=8 { output = append(output, byte(p.OPCR>>uint(i))) } if p.SPF { output = append(output, p.SC) } if p.TPDF { output = append(output, append([]byte{p.TPDL}, p.TPD...)...) } output = append(output, p.Ext...) output = append(output, stuffing...) } output = append(output, p.Payload...) if len(output) != 188 { err = errors.New("Length of MPEG-TS packet is not 188! Something is wrong!") } return }