/* NAME MPEGTSGenerator.go DESCRIPTION See Readme.md AUTHOR Saxon Nelson-Milton LICENSE MPEGTSGenerator.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 generator import ( _ "fmt" _ "os" //"bitbucket.org/ausocean/av/mpegts" //"bitbucket.org/ausocean/av/pes" //"bitbucket.org/ausocean/av/tools" //"bitbucket.org/ausocean/av/rtp" "../mpegts" "../pes" "../rtp" "../tools" ) var ( patTable= []byte{0, 0, 176, 13, 0, 1, 193, 0, 0, 0, 1, 240, 0, 42, 177, 4, 178, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255} pmtTable = []byte{0, 2, 176, 18, 0, 1, 193, 0, 0, 0xE1, 0x00, 0xF0, 0, 0x1B, 0xE1, 0, 0xF0, 0, 0x15, 0xBD, 0x4D, 0x56, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255} ) const ( SdtPid = 17 PatPid = 0 pmtPid = 4096 videoPid = 256 streamID = 0xE0 ) type tsGenerator struct { rtpInputChan chan rtp.RtpPacket outputChan chan []byte nalInputChan chan []byte currentTsPacket *mpegts.MpegTsPacket payloadByteChan chan byte currentCC byte currentPtsTime float64 currentPcrTime float64 fps uint pesPktChan chan []byte ccMap map[int]int } func (g *tsGenerator) GetInputChan() chan []byte { return g.nalInputChan } func (g *tsGenerator) GetOutputChan() chan []byte { return g.outputChan } func NewTsGenerator(fps uint) (g *tsGenerator) { g = new(tsGenerator) g.outputChan = make(chan []byte, 100) g.rtpInputChan = make(chan rtp.RtpPacket, 100) g.nalInputChan = make(chan []byte, 10000) g.currentCC = 0 g.fps = fps g.currentPcrTime = .0 g.currentPtsTime = .7 g.pesPktChan = make(chan []byte, 1000) g.payloadByteChan = make(chan byte, 100000) g.ccMap = make(map[int]int, 4) g.ccMap[SdtPid] = 0 g.ccMap[PatPid] = 0 g.ccMap[pmtPid] = 0 g.ccMap[videoPid] = 0 return } func (g *tsGenerator) genPts() (pts uint64) { pts = uint64(g.currentPtsTime * float64(90000)) g.currentPtsTime += 1.0 / float64(g.fps) return } func (g *tsGenerator) genPcr() (pcr uint64) { pcr = uint64(g.currentPcrTime * float64(90000)) g.currentPcrTime += 1.0 / float64(g.fps) return } func (g *tsGenerator) Start() { go g.generate() } func (g *tsGenerator) generate() { var rtpBuffer [](*rtp.RtpPacket) for { select { case nalUnit := <-g.nalInputChan: g.pesPktChan <- pes.PESPacket{ StreamID: streamID, PDI: byte(2), PTS: g.genPts(), Data: nalUnit, HeaderLength: 5, }.ToByteSlice() case pesPkt := <-g.pesPktChan: for ii := range pesPkt { g.payloadByteChan <- pesPkt[ii] } pusi := true for len(g.payloadByteChan) > 0 { pkt := mpegts.MpegTsPacket{ PUSI: pusi, PID: videoPid, RAI: pusi, CC: byte(g.getCC(videoPid)), AFC: byte(3), PCRF: pusi, } pkt.FillPayload(g.payloadByteChan) if pusi { // Create pat table and send off patPkt := mpegts.MpegTsPacket{ PUSI: pusi, PID: PatPid, CC: byte(g.getCC(PatPid)), AFC: 1, Payload: PatTable, } patPktAsByteSlice, _ := patPkt.ToByteSlice() g.outputChan <- patPktAsByteSlice // Create pmt table and send off pmtPkt := mpegts.MpegTsPacket{ PUSI: pusi, PID: pmtPid, CC: byte(g.getCC(pmtPid)), AFC: 1, Payload: pmtTable, } pmtPktAsByteSlice, _ := pmtPkt.ToByteSlice() g.outputChan <- pmtPktAsByteSlice pkt.PCR = g.genPcr() pusi = false } pktAsBytelice, _ := pkt.ToByteSlice() g.outputChan <- pktAsBytelice } } } } func (g *tsGenerator) getCC(pid int) int { temp := g.ccMap[pid] if g.ccMap[pid]++; g.ccMap[pid] > 15 { g.ccMap[pid] = 0 } return temp }