/* 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 packets import ( "fmt" "os" ) type RtpToTsConverter interface { Convert() } type rtpToTsConverter struct { TsChan <-chan *MpegTsPacket tsChan chan<- *MpegTsPacket InputChan chan<- RtpPacket inputChan <-chan RtpPacket 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 inputChan := make(chan RtpPacket,100) c.InputChan = inputChan c.inputChan = inputChan c.currentCC = 0 return } func (c* rtpToTsConverter) Convert() { file,_ := os.Create("video") pesPktChan := make(chan []byte, 10000) pesDataChan := make(chan byte, 15000) nalAccessChan := make(chan []byte, 100) data := make(chan byte,10000) payloadByteChan := make(chan byte, 15000) // Get nal units from incoming rtp 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 } } for { select { default: case rtpPacket := <-c.inputChan: 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] } } } } case nalUnit := <-nalAccessChan: for ii := range nalUnit { pesDataChan<-nalUnit[ii] } 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 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 } } } }