2017-12-13 09:52:18 +03:00
|
|
|
/*
|
|
|
|
NAME
|
|
|
|
RtpToTsConverter.go - provides utilities for the conversion of Rtp packets
|
|
|
|
to equivalent MpegTs packets.
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
See Readme.md
|
|
|
|
|
|
|
|
AUTHOR
|
|
|
|
Saxon Nelson-Milton <saxon.milton@gmail.com>
|
|
|
|
|
|
|
|
LICENSE
|
|
|
|
RtpToTsConverter.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 packets
|
|
|
|
|
2018-01-01 12:14:59 +03:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
)
|
2017-12-30 11:31:50 +03:00
|
|
|
|
2017-12-13 09:52:18 +03:00
|
|
|
type RtpToTsConverter interface {
|
|
|
|
Convert()
|
|
|
|
}
|
|
|
|
|
|
|
|
type rtpToTsConverter struct {
|
|
|
|
TsChan <-chan *MpegTsPacket
|
|
|
|
tsChan chan<- *MpegTsPacket
|
2017-12-30 11:31:50 +03:00
|
|
|
InputChan chan<- RtpPacket
|
|
|
|
inputChan <-chan RtpPacket
|
2017-12-13 09:52:18 +03:00
|
|
|
currentTsPacket *MpegTsPacket
|
|
|
|
payloadByteChan chan byte
|
|
|
|
currentCC byte
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewRtpToTsConverter() (c *rtpToTsConverter) {
|
|
|
|
c = new(rtpToTsConverter)
|
|
|
|
tsChan := make(chan *MpegTsPacket,100)
|
|
|
|
c.TsChan = tsChan
|
|
|
|
c.tsChan = tsChan
|
2017-12-30 11:31:50 +03:00
|
|
|
inputChan := make(chan RtpPacket,100)
|
2017-12-26 11:44:21 +03:00
|
|
|
c.InputChan = inputChan
|
|
|
|
c.inputChan = inputChan
|
2017-12-13 09:52:18 +03:00
|
|
|
c.currentCC = 0
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-12-26 11:44:21 +03:00
|
|
|
func (c* rtpToTsConverter) Convert() {
|
2018-01-01 12:14:59 +03:00
|
|
|
file,_ := os.Create("video")
|
2017-12-30 11:31:50 +03:00
|
|
|
pesPktChan := make(chan []byte, 10000)
|
|
|
|
pesDataChan := make(chan byte, 15000)
|
2018-01-01 12:14:59 +03:00
|
|
|
nalAccessChan := make(chan []byte, 100)
|
|
|
|
data := make(chan byte,10000)
|
2017-12-30 11:31:50 +03:00
|
|
|
payloadByteChan := make(chan byte, 15000)
|
2017-12-20 09:47:28 +03:00
|
|
|
// Get nal units from incoming rtp
|
2018-01-01 12:14:59 +03:00
|
|
|
var sps []byte
|
|
|
|
var pps []byte
|
|
|
|
// Frist find sps
|
|
|
|
for {
|
|
|
|
rtpPacket := <-c.inputChan
|
|
|
|
fragmentType := rtpPacket.Payload[0] & 0x1F
|
|
|
|
if fragmentType == 7 {
|
|
|
|
sps = make([]byte,4+len(rtpPacket.Payload))
|
|
|
|
sps[0] = 0x00
|
|
|
|
sps[1] = 0x00
|
|
|
|
sps[2] = 0x00
|
|
|
|
sps[3] = 0x01
|
|
|
|
for i := range rtpPacket.Payload {
|
|
|
|
sps[i+4] = rtpPacket.Payload[i]
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// now find pps
|
|
|
|
for {
|
|
|
|
rtpPacket := <-c.inputChan
|
|
|
|
fragmentType := rtpPacket.Payload[0] & 0x1F
|
|
|
|
if fragmentType == 8 {
|
|
|
|
pps = make([]byte,4+len(rtpPacket.Payload))
|
|
|
|
pps[0] = 0x00
|
|
|
|
pps[1] = 0x00
|
|
|
|
pps[2] = 0x00
|
|
|
|
pps[3] = 0x01
|
|
|
|
for i := range rtpPacket.Payload {
|
|
|
|
pps[i+4] = rtpPacket.Payload[i]
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2017-12-26 11:44:21 +03:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
default:
|
|
|
|
case rtpPacket := <-c.inputChan:
|
2018-01-01 12:14:59 +03:00
|
|
|
threeNUBs := rtpPacket.Payload[0] & 0xE0
|
|
|
|
fragmentType := rtpPacket.Payload[0] & 0x1F
|
|
|
|
startBit := (rtpPacket.Payload[1] & 0x80)>>7
|
|
|
|
fiveNUBs := rtpPacket.Payload[1] & 0x1F
|
|
|
|
fragmentData := rtpPacket.Payload[2:]
|
|
|
|
fmt.Printf("fragmentType: %v\n", fragmentType)
|
|
|
|
if fragmentType == 28 {
|
|
|
|
if startBit == 1 {
|
|
|
|
if len(data) > 0 {
|
|
|
|
dataArray := make([]byte, len(data))
|
|
|
|
for ii:=0; len(data) > 0; ii++ {
|
|
|
|
dataArray[ii] = <-data
|
|
|
|
}
|
|
|
|
fmt.Printf("data array size: %v\n", len(dataArray))
|
|
|
|
nalAccessChan<-dataArray
|
|
|
|
file.Write(dataArray)
|
|
|
|
}
|
|
|
|
// load sps into data
|
|
|
|
for ii := range sps {
|
|
|
|
data<-sps[ii]
|
|
|
|
}
|
|
|
|
// load pps into data
|
|
|
|
for ii := range pps {
|
|
|
|
data<-pps[ii]
|
|
|
|
}
|
|
|
|
buffer := make([]byte,5+len(fragmentData))
|
|
|
|
buffer[0] = 0x00
|
|
|
|
buffer[1] = 0x00
|
|
|
|
buffer[2] = 0x00
|
|
|
|
buffer[3] = 0x01
|
|
|
|
buffer[4] = threeNUBs | fiveNUBs
|
|
|
|
for i := range fragmentData {
|
|
|
|
buffer[i+5] = fragmentData[i]
|
|
|
|
}
|
|
|
|
// load data into data chan
|
|
|
|
for ii := range buffer {
|
|
|
|
data<-buffer[ii]
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if len(data) > 0 {
|
|
|
|
for ii := range fragmentData {
|
|
|
|
data<-fragmentData[ii]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-21 05:45:50 +03:00
|
|
|
}
|
2018-01-01 12:14:59 +03:00
|
|
|
case nalUnit := <-nalAccessChan:
|
|
|
|
for ii := range nalUnit {
|
|
|
|
pesDataChan<-nalUnit[ii]
|
2017-12-20 09:47:28 +03:00
|
|
|
}
|
2018-01-01 12:14:59 +03:00
|
|
|
pesDataChanLen := len(nalUnit)
|
|
|
|
pesPkt := new(PESPacket)
|
|
|
|
pesPkt.StreamID = 0xE0
|
|
|
|
pesPkt.Length = uint16( 3 + pesDataChanLen )
|
|
|
|
pesPkt.ScramblingControl = 0
|
|
|
|
pesPkt.Priority = true
|
|
|
|
pesPkt.DAI = false
|
|
|
|
pesPkt.Copyright = false
|
|
|
|
pesPkt.Original = true
|
|
|
|
pesPkt.PDI = 0
|
|
|
|
pesPkt.ESCR = false
|
|
|
|
pesPkt.ESRate = false
|
|
|
|
pesPkt.DSMTrickMode = false
|
|
|
|
pesPkt.ACI = false
|
|
|
|
pesPkt.CRC = false
|
|
|
|
pesPkt.Ext = false
|
|
|
|
pesPkt.HeaderLength = 0
|
|
|
|
pesPkt.Data = make([]byte,pesDataChanLen)
|
|
|
|
for ii:=0; ii<pesDataChanLen; ii++ {
|
|
|
|
pesPkt.Data[ii] = <-pesDataChan
|
2017-12-20 09:47:28 +03:00
|
|
|
}
|
2018-01-01 12:14:59 +03:00
|
|
|
pesPktChan<-pesPkt.ToByteSlice()
|
2017-12-26 11:44:21 +03:00
|
|
|
case pesPkt := <-pesPktChan:
|
|
|
|
for ii:=range pesPkt {
|
|
|
|
payloadByteChan<-pesPkt[ii]
|
2017-12-20 09:47:28 +03:00
|
|
|
}
|
2017-12-26 11:44:21 +03:00
|
|
|
firstPacket:=true
|
|
|
|
for len(payloadByteChan) > 0 {
|
|
|
|
lengthOfByteChan := len(payloadByteChan)
|
|
|
|
c.currentTsPacket = new(MpegTsPacket)
|
|
|
|
c.currentTsPacket.SyncByte = 0x47
|
|
|
|
c.currentTsPacket.TEI = false
|
|
|
|
c.currentTsPacket.PUSI = false
|
|
|
|
if firstPacket { // if it's the start of the payload
|
|
|
|
c.currentTsPacket.PUSI = true
|
|
|
|
firstPacket = false
|
|
|
|
}
|
|
|
|
c.currentTsPacket.Priority = false
|
|
|
|
c.currentTsPacket.PID = 256
|
|
|
|
c.currentTsPacket.TSC = 0
|
|
|
|
c.currentTsPacket.CC = c.currentCC
|
|
|
|
if c.currentCC++; c.currentCC > 15 { c.currentCC = 0 }
|
|
|
|
payloadLength := 182
|
|
|
|
if lengthOfByteChan < 182 {
|
|
|
|
payloadLength = lengthOfByteChan
|
|
|
|
}
|
|
|
|
c.currentTsPacket.AFC = 3
|
|
|
|
stuffingLength := 182-payloadLength
|
|
|
|
c.currentTsPacket.AF = make([]byte,2 + stuffingLength) // adaptationfield flag length = 16
|
|
|
|
c.currentTsPacket.AF[0] = byte(1 + stuffingLength)
|
|
|
|
c.currentTsPacket.AF[1] = 0
|
|
|
|
if c.currentTsPacket.PUSI {
|
|
|
|
c.currentTsPacket.AF[1] = 0x00
|
|
|
|
}
|
|
|
|
for ii := 0; ii < stuffingLength; ii++ {
|
|
|
|
c.currentTsPacket.AF[2+ii] = 0xFF
|
|
|
|
}
|
|
|
|
c.currentTsPacket.Payload = make([]byte, payloadLength)
|
|
|
|
for ii:=0; ii < payloadLength; ii++ {
|
|
|
|
c.currentTsPacket.Payload[ii] = <-payloadByteChan
|
|
|
|
}
|
|
|
|
c.tsChan<-c.currentTsPacket
|
2017-12-13 09:52:18 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|