2018-02-13 11:39:26 +03:00
|
|
|
/*
|
|
|
|
NAME
|
2018-02-28 16:46:59 +03:00
|
|
|
MPEGTSGenerator.go
|
2018-02-13 11:39:26 +03:00
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
See Readme.md
|
|
|
|
|
|
|
|
AUTHOR
|
2018-02-28 16:46:59 +03:00
|
|
|
Saxon Nelson-Milton <saxon@ausocean.org>
|
2018-02-13 11:39:26 +03:00
|
|
|
|
|
|
|
LICENSE
|
2018-02-28 16:46:59 +03:00
|
|
|
MPEGTSGenerator.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)
|
2018-02-13 11:39:26 +03:00
|
|
|
|
|
|
|
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).
|
|
|
|
*/
|
2018-02-10 09:59:56 +03:00
|
|
|
package generator
|
2017-12-30 11:31:50 +03:00
|
|
|
|
2018-02-12 10:58:29 +03:00
|
|
|
import (
|
2018-02-28 16:46:59 +03:00
|
|
|
_ "fmt"
|
|
|
|
_ "os"
|
2018-02-12 10:58:29 +03:00
|
|
|
//"bitbucket.org/ausocean/av/mpegts"
|
|
|
|
//"bitbucket.org/ausocean/av/pes"
|
|
|
|
//"bitbucket.org/ausocean/av/tools"
|
|
|
|
//"bitbucket.org/ausocean/av/rtp"
|
|
|
|
"../mpegts"
|
|
|
|
"../pes"
|
|
|
|
"../rtp"
|
2018-02-28 16:46:59 +03:00
|
|
|
"../tools"
|
2018-02-12 10:58:29 +03:00
|
|
|
)
|
|
|
|
|
2018-01-16 08:49:18 +03:00
|
|
|
var (
|
2018-02-28 16:46:59 +03:00
|
|
|
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}
|
2018-01-16 08:49:18 +03:00
|
|
|
|
2018-02-28 16:46:59 +03:00
|
|
|
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}
|
2018-01-16 08:49:18 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2018-02-28 16:46:59 +03:00
|
|
|
SdtPid = 17
|
|
|
|
PatPid = 0
|
|
|
|
pmtPid = 4096
|
|
|
|
videoPid = 256
|
|
|
|
streamID = 0xE0
|
2018-01-16 08:49:18 +03:00
|
|
|
)
|
|
|
|
|
2018-01-10 04:32:16 +03:00
|
|
|
type tsGenerator struct {
|
2018-02-28 16:46:59 +03:00
|
|
|
rtpInputChan chan rtp.RtpPacket
|
|
|
|
outputChan chan []byte
|
2018-01-30 09:24:39 +03:00
|
|
|
nalInputChan chan []byte
|
2018-01-08 04:12:26 +03:00
|
|
|
currentTsPacket *mpegts.MpegTsPacket
|
2018-01-04 10:04:33 +03:00
|
|
|
payloadByteChan chan byte
|
|
|
|
currentCC byte
|
2018-02-28 16:46:59 +03:00
|
|
|
currentPtsTime float64
|
|
|
|
currentPcrTime float64
|
|
|
|
fps uint
|
|
|
|
pesPktChan chan []byte
|
|
|
|
ccMap map[int]int
|
2018-01-16 08:06:51 +03:00
|
|
|
}
|
|
|
|
|
2018-02-28 16:46:59 +03:00
|
|
|
func (g *tsGenerator) GetInputChan() chan []byte {
|
2018-01-30 09:24:39 +03:00
|
|
|
return g.nalInputChan
|
2018-01-16 08:06:51 +03:00
|
|
|
}
|
|
|
|
|
2018-02-28 16:46:59 +03:00
|
|
|
func (g *tsGenerator) GetOutputChan() chan []byte {
|
2018-02-12 10:58:29 +03:00
|
|
|
return g.outputChan
|
2017-12-13 09:52:18 +03:00
|
|
|
}
|
|
|
|
|
2018-01-10 06:57:56 +03:00
|
|
|
func NewTsGenerator(fps uint) (g *tsGenerator) {
|
|
|
|
g = new(tsGenerator)
|
2018-02-12 10:58:29 +03:00
|
|
|
g.outputChan = make(chan []byte, 100)
|
|
|
|
g.rtpInputChan = make(chan rtp.RtpPacket, 100)
|
2018-01-30 09:24:39 +03:00
|
|
|
g.nalInputChan = make(chan []byte, 10000)
|
2018-01-10 06:57:56 +03:00
|
|
|
g.currentCC = 0
|
|
|
|
g.fps = fps
|
|
|
|
g.currentPcrTime = .0
|
|
|
|
g.currentPtsTime = .7
|
2018-01-16 08:06:51 +03:00
|
|
|
g.pesPktChan = make(chan []byte, 1000)
|
|
|
|
g.payloadByteChan = make(chan byte, 100000)
|
2018-01-16 10:17:38 +03:00
|
|
|
g.ccMap = make(map[int]int, 4)
|
2018-01-16 08:49:18 +03:00
|
|
|
g.ccMap[SdtPid] = 0
|
|
|
|
g.ccMap[PatPid] = 0
|
2018-02-28 16:46:59 +03:00
|
|
|
g.ccMap[pmtPid] = 0
|
|
|
|
g.ccMap[videoPid] = 0
|
2018-01-04 10:04:33 +03:00
|
|
|
return
|
2017-12-13 09:52:18 +03:00
|
|
|
}
|
|
|
|
|
2018-02-28 16:46:59 +03:00
|
|
|
func (g *tsGenerator) genPts() (pts uint64) {
|
2018-01-10 06:57:56 +03:00
|
|
|
pts = uint64(g.currentPtsTime * float64(90000))
|
2018-02-28 16:46:59 +03:00
|
|
|
g.currentPtsTime += 1.0 / float64(g.fps)
|
2018-01-08 04:12:26 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-02-28 16:46:59 +03:00
|
|
|
func (g *tsGenerator) genPcr() (pcr uint64) {
|
2018-01-10 06:57:56 +03:00
|
|
|
pcr = uint64(g.currentPcrTime * float64(90000))
|
2018-02-28 16:46:59 +03:00
|
|
|
g.currentPcrTime += 1.0 / float64(g.fps)
|
2018-01-08 04:12:26 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-02-28 16:46:59 +03:00
|
|
|
func (g *tsGenerator) Start() {
|
2018-01-24 07:12:22 +03:00
|
|
|
go g.generate()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *tsGenerator) generate() {
|
2018-01-08 04:12:26 +03:00
|
|
|
var rtpBuffer [](*rtp.RtpPacket)
|
2018-01-17 06:48:47 +03:00
|
|
|
for {
|
2018-01-04 10:04:33 +03:00
|
|
|
select {
|
2018-01-10 06:57:56 +03:00
|
|
|
case nalUnit := <-g.nalInputChan:
|
2018-02-28 16:46:59 +03:00
|
|
|
g.pesPktChan <- pes.PESPacket{
|
|
|
|
StreamID: streamID,
|
|
|
|
PDI: byte(2),
|
|
|
|
PTS: g.genPts(),
|
|
|
|
Data: nalUnit,
|
2018-01-08 04:12:26 +03:00
|
|
|
HeaderLength: 5,
|
2018-02-28 16:46:59 +03:00
|
|
|
}.ToByteSlice()
|
2018-01-16 08:06:51 +03:00
|
|
|
case pesPkt := <-g.pesPktChan:
|
2018-01-04 10:04:33 +03:00
|
|
|
for ii := range pesPkt {
|
2018-01-16 08:06:51 +03:00
|
|
|
g.payloadByteChan <- pesPkt[ii]
|
2018-01-04 10:04:33 +03:00
|
|
|
}
|
2018-01-08 04:12:26 +03:00
|
|
|
pusi := true
|
2018-01-16 08:06:51 +03:00
|
|
|
for len(g.payloadByteChan) > 0 {
|
2018-01-08 04:12:26 +03:00
|
|
|
pkt := mpegts.MpegTsPacket{
|
|
|
|
PUSI: pusi,
|
2018-02-28 16:46:59 +03:00
|
|
|
PID: videoPid,
|
|
|
|
RAI: pusi,
|
|
|
|
CC: byte(g.getCC(videoPid)),
|
|
|
|
AFC: byte(3),
|
2018-01-08 04:12:26 +03:00
|
|
|
PCRF: pusi,
|
|
|
|
}
|
2018-01-16 08:06:51 +03:00
|
|
|
pkt.FillPayload(g.payloadByteChan)
|
2018-01-24 07:12:22 +03:00
|
|
|
|
2018-01-08 04:12:26 +03:00
|
|
|
if pusi {
|
2018-01-16 08:49:18 +03:00
|
|
|
// Create pat table and send off
|
|
|
|
patPkt := mpegts.MpegTsPacket{
|
2018-02-28 16:46:59 +03:00
|
|
|
PUSI: pusi,
|
|
|
|
PID: PatPid,
|
|
|
|
CC: byte(g.getCC(PatPid)),
|
|
|
|
AFC: 1,
|
2018-01-16 10:17:38 +03:00
|
|
|
Payload: PatTable,
|
2018-01-16 08:49:18 +03:00
|
|
|
}
|
2018-02-12 10:58:29 +03:00
|
|
|
|
|
|
|
patPktAsByteSlice, _ := patPkt.ToByteSlice()
|
|
|
|
g.outputChan <- patPktAsByteSlice
|
2018-01-16 08:49:18 +03:00
|
|
|
|
|
|
|
// Create pmt table and send off
|
|
|
|
pmtPkt := mpegts.MpegTsPacket{
|
2018-02-28 16:46:59 +03:00
|
|
|
PUSI: pusi,
|
|
|
|
PID: pmtPid,
|
|
|
|
CC: byte(g.getCC(pmtPid)),
|
|
|
|
AFC: 1,
|
|
|
|
Payload: pmtTable,
|
2018-01-16 08:49:18 +03:00
|
|
|
}
|
2018-02-12 10:58:29 +03:00
|
|
|
pmtPktAsByteSlice, _ := pmtPkt.ToByteSlice()
|
|
|
|
g.outputChan <- pmtPktAsByteSlice
|
|
|
|
|
2018-01-10 06:57:56 +03:00
|
|
|
pkt.PCR = g.genPcr()
|
2018-01-08 04:12:26 +03:00
|
|
|
pusi = false
|
2018-01-04 10:04:33 +03:00
|
|
|
}
|
2018-02-12 10:58:29 +03:00
|
|
|
pktAsBytelice, _ := pkt.ToByteSlice()
|
2018-02-28 16:46:59 +03:00
|
|
|
g.outputChan <- pktAsBytelice
|
2018-01-04 10:04:33 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-13 09:52:18 +03:00
|
|
|
}
|
2018-01-16 08:49:18 +03:00
|
|
|
|
2018-01-16 10:17:38 +03:00
|
|
|
func (g *tsGenerator) getCC(pid int) int {
|
|
|
|
temp := g.ccMap[pid]
|
2018-01-16 08:49:18 +03:00
|
|
|
if g.ccMap[pid]++; g.ccMap[pid] > 15 {
|
|
|
|
g.ccMap[pid] = 0
|
|
|
|
}
|
2018-01-16 10:17:38 +03:00
|
|
|
return temp
|
2018-01-16 08:49:18 +03:00
|
|
|
}
|