/* NAME RtpToTsConverter.go - provides utilities for the conversion of Rtp packets to equivalent MpegTs packets. DESCRIPTION See Readme.md AUTHOR Saxon Nelson-Milton 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 tsgenerator import ( _ "fmt" _"os" "../mpegts" "../pes" "../tools" "../rtp" ) type TsConverter interface { Convert() } type tsCreator struct { TsChan <-chan *mpegts.MpegTsPacket tsChan chan<- *mpegts.MpegTsPacket InputChan chan<- rtp.RtpPacket inputChan <-chan rtp.RtpPacket NalInputChan chan<- []byte nalInputChan <-chan []byte currentTsPacket *mpegts.MpegTsPacket payloadByteChan chan byte currentCC byte currentPtsTime float64 currentPcrTime float64 fps uint isGenerating bool } func NewTsCreator(fps uint) (c *tsCreator) { c = new(tsCreator) tsChan := make(chan *mpegts.MpegTsPacket, 100) c.TsChan = tsChan c.tsChan = tsChan inputChan := make(chan rtp.RtpPacket, 100) c.InputChan = inputChan c.inputChan = inputChan nalInputChan := make(chan []byte, 10000) c.NalInputChan = nalInputChan c.nalInputChan = nalInputChan c.currentCC = 0 c.fps = fps c.currentPcrTime = .0 c.currentPtsTime = .7 return } func (c* tsgenerator) genPts()(pts uint64){ pts = uint64(c.currentPtsTime * float64(90000)) c.currentPtsTime += 1.0/float64(c.fps) return } func (c* tsgenerator) genPcr()(pcr uint64){ pcr = uint64(c.currentPcrTime * float64(90000)) c.currentPcrTime += 1.0/float64(c.fps) return } func (c *tsgenerator) Stop(){ isGenerating = false } func (c *tsgenerator) Convert() { isGenerating = true pesPktChan := make(chan []byte, 1000) payloadByteChan := make(chan byte, 100000) var rtpBuffer [](*rtp.RtpPacket) for isGenerating { select { default: case rtpPacket := <-c.inputChan: rtpBuffer = append(rtpBuffer, &rtpPacket) if len(rtpBuffer) > 2 { // if there's something weird going on with sequence numbers then // insertion sort if rtpPacket.SequenceNumber < rtpBuffer[len(rtpBuffer)-2].SequenceNumber { for i := 1; i < len(rtpBuffer); i++ { for j := i; j > 0 && rtpBuffer[j].SequenceNumber < rtpBuffer[j-1].SequenceNumber; j-- { temp := rtpBuffer[j] rtpBuffer[j] = rtpBuffer[j-1] rtpBuffer[j-1] = temp } } } } if len(rtpBuffer) > 200 { for tools.GetOctectType(rtpBuffer[0]) != 7 { rtpBuffer = rtpBuffer[1:] } sps := make([]byte, len(rtpBuffer[0].Payload)) copy(sps[:], rtpBuffer[0].Payload[:]) rtpBuffer = rtpBuffer[1:] pps := make([]byte, len(rtpBuffer[0].Payload)) copy(pps[:], rtpBuffer[0].Payload[:]) rtpBuffer = rtpBuffer[1:] sei := make([]byte, len(rtpBuffer[0].Payload)) copy(sei[:], rtpBuffer[0].Payload[:]) rtpBuffer = rtpBuffer[1:] for tools.GetOctectType(rtpBuffer[0]) != 7 { switch tools.GetOctectType(rtpBuffer[0]) { case 28: if tools.GetStartBit(rtpBuffer[0]) == 1 { var buffer []byte buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, []byte{0x09, 0x10}...) buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, sps...) buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, pps...) buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, sei...) buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, rtpBuffer[0].Payload[0]&0xE0|rtpBuffer[0].Payload[1]&0x1F) buffer = append(buffer, rtpBuffer[0].Payload[2:]...) rtpBuffer = rtpBuffer[1:] for { buffer = append(buffer, rtpBuffer[0].Payload[2:]...) if tools.GetEndBit(rtpBuffer[0]) == 1 { rtpBuffer = rtpBuffer[1:] c.NalInputChan <- buffer break } rtpBuffer = rtpBuffer[1:] } } case 1: var buffer []byte buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, []byte{0x09, 0x10}...) buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, sps...) buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, pps...) buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, sei...) buffer = append(buffer, []byte{0x00, 0x00, 0x01}...) buffer = append(buffer, rtpBuffer[0].Payload[0]&0xE0|rtpBuffer[0].Payload[1]&0x1F) buffer = append(buffer, rtpBuffer[0].Payload[2:]...) rtpBuffer = rtpBuffer[1:] c.NalInputChan <- buffer default: } } } case nalUnit := <-c.nalInputChan: pesPkt := pes.PESPacket{ StreamID: 0xE0, PDI: byte(2), PTS: c.genPts(), Data: nalUnit, HeaderLength: 5, } pesPktChan <- pesPkt.ToByteSlice() case pesPkt := <-pesPktChan: for ii := range pesPkt { payloadByteChan <- pesPkt[ii] } pusi := true for len(payloadByteChan) > 0 { pkt := mpegts.MpegTsPacket{ PUSI: pusi, PID: 256, RAI: pusi, CC: c.currentCC, AFC: byte(3), PCRF: pusi, } pkt.FillPayload(payloadByteChan) if pusi { pkt.PCR = c.genPcr() pusi = false } if c.currentCC++; c.currentCC > 15 { c.currentCC = 0 } c.tsChan <- &pkt } } } }