From 3279a4746def1902354a412586a062d8c96c9355 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Sat, 18 Aug 2018 17:19:26 +0930 Subject: [PATCH] generator: refactor main processing loop and improve commentary --- generator/mpegts_generator.go | 93 +++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/generator/mpegts_generator.go b/generator/mpegts_generator.go index 1f31983a..b6646668 100644 --- a/generator/mpegts_generator.go +++ b/generator/mpegts_generator.go @@ -53,14 +53,21 @@ func init() { } const ( - sdtPid = 17 - patPid = 0 - pmtPid = 4096 - videoPid = 256 - streamID = 0xe0 + sdtPid = 17 + patPid = 0 + pmtPid = 4096 + videoPid = 256 + streamID = 0xe0 // First video stream ID. +) + +// Time related constants. +const ( + // ptsOffset is the offset added to the clock to determine + // the current presentation timestamp, ptsOffset = 700 * time.Millisecond - ptsFreq = 90000 // Hz - maxCC = 0xf + + // pcrFreq is the base Program Clock Reference frequency. + pcrFreq = 90000 // Hz ) // tsGenerator encapsulates properties of an mpegts generator. @@ -112,14 +119,46 @@ func (g *tsGenerator) OutputChan() <-chan []byte { return g.outputChan } +const ( + hasPayload = 0x1 + hasAdaptationField = 0x2 +) + +const ( + hasDTS = 0x1 + hasPTS = 0x2 +) + // generate handles the incoming data and generates equivalent mpegts packets - // sending them to the output channel func (g *tsGenerator) generate() { for { nalu := <-g.nalInputChan + + // Write PAT + patPkt := mpegts.Packet{ + PUSI: true, + PID: patPid, + CC: g.ccFor(patPid), + AFC: hasPayload, + Payload: patTable, + } + g.outputChan <- patPkt.Bytes() + + // Write PMT. + pmtPkt := mpegts.Packet{ + PUSI: true, + PID: pmtPid, + CC: g.ccFor(pmtPid), + AFC: hasPayload, + Payload: pmtTable, + } + g.outputChan <- pmtPkt.Bytes() + + // Prepare PES data. pesPkt := pes.Packet{ StreamID: streamID, - PDI: 2, + PDI: hasPTS, PTS: g.pts(), Data: nalu, HeaderLength: 5, @@ -133,44 +172,23 @@ func (g *tsGenerator) generate() { PID: videoPid, RAI: pusi, CC: g.ccFor(videoPid), - AFC: 3, + AFC: hasAdaptationField | hasPayload, PCRF: pusi, } n := pkt.FillPayload(buf) buf = buf[n:] - // TODO: create consts for AFC parameters if pusi { - // Create pat table - patPkt := mpegts.Packet{ - PUSI: pusi, - PID: patPid, - CC: g.ccFor(patPid), - AFC: 1, - Payload: patTable, - } - g.outputChan <- patPkt.Bytes() - - // Create pmt table - pmtPkt := mpegts.Packet{ - PUSI: pusi, - PID: pmtPid, - CC: g.ccFor(pmtPid), - AFC: 1, - Payload: pmtTable, - } - g.outputChan <- pmtPkt.Bytes() - - // If pusi then we need to gen a pcr + // If the packet has a Payload Unit Start Indicator + // flag set then we need to write a PCR. pkt.PCR = g.pcr() - - g.tick() - pusi = false } g.outputChan <- pkt.Bytes() } + + g.tick() } } @@ -181,17 +199,18 @@ func (g *tsGenerator) tick() { // pts retuns the current presentation timestamp. func (g *tsGenerator) pts() uint64 { - return uint64((g.clock + g.ptsOffset).Seconds() * ptsFreq) + return uint64((g.clock + g.ptsOffset).Seconds() * pcrFreq) } // pcr returns the current program clock reference. func (g *tsGenerator) pcr() uint64 { - return uint64(g.clock.Seconds() * ptsFreq) + return uint64(g.clock.Seconds() * pcrFreq) } // ccFor returns the next continuity counter for pid. func (g *tsGenerator) ccFor(pid int) byte { cc := g.continuity[pid] - g.continuity[pid] = (cc + 1) & maxCC + const continuityCounterMask = 0xf + g.continuity[pid] = (cc + 1) & continuityCounterMask return cc }