av/generator/MPEGTSGenerator.go

182 lines
5.8 KiB
Go

/*
NAME
MPEGTSGenerator.go
DESCRIPTION
See Readme.md
AUTHOR
Saxon Nelson-Milton <saxon@ausocean.org>
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
}