mirror of https://bitbucket.org/ausocean/av.git
generator: refactor main processing loop and improve commentary
This commit is contained in:
parent
7d1bfcefe9
commit
3279a4746d
|
@ -57,10 +57,17 @@ const (
|
||||||
patPid = 0
|
patPid = 0
|
||||||
pmtPid = 4096
|
pmtPid = 4096
|
||||||
videoPid = 256
|
videoPid = 256
|
||||||
streamID = 0xe0
|
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
|
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.
|
// tsGenerator encapsulates properties of an mpegts generator.
|
||||||
|
@ -112,14 +119,46 @@ func (g *tsGenerator) OutputChan() <-chan []byte {
|
||||||
return g.outputChan
|
return g.outputChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
hasPayload = 0x1
|
||||||
|
hasAdaptationField = 0x2
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hasDTS = 0x1
|
||||||
|
hasPTS = 0x2
|
||||||
|
)
|
||||||
|
|
||||||
// generate handles the incoming data and generates equivalent mpegts packets -
|
// generate handles the incoming data and generates equivalent mpegts packets -
|
||||||
// sending them to the output channel
|
// sending them to the output channel
|
||||||
func (g *tsGenerator) generate() {
|
func (g *tsGenerator) generate() {
|
||||||
for {
|
for {
|
||||||
nalu := <-g.nalInputChan
|
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{
|
pesPkt := pes.Packet{
|
||||||
StreamID: streamID,
|
StreamID: streamID,
|
||||||
PDI: 2,
|
PDI: hasPTS,
|
||||||
PTS: g.pts(),
|
PTS: g.pts(),
|
||||||
Data: nalu,
|
Data: nalu,
|
||||||
HeaderLength: 5,
|
HeaderLength: 5,
|
||||||
|
@ -133,44 +172,23 @@ func (g *tsGenerator) generate() {
|
||||||
PID: videoPid,
|
PID: videoPid,
|
||||||
RAI: pusi,
|
RAI: pusi,
|
||||||
CC: g.ccFor(videoPid),
|
CC: g.ccFor(videoPid),
|
||||||
AFC: 3,
|
AFC: hasAdaptationField | hasPayload,
|
||||||
PCRF: pusi,
|
PCRF: pusi,
|
||||||
}
|
}
|
||||||
n := pkt.FillPayload(buf)
|
n := pkt.FillPayload(buf)
|
||||||
buf = buf[n:]
|
buf = buf[n:]
|
||||||
|
|
||||||
// TODO: create consts for AFC parameters
|
|
||||||
if pusi {
|
if pusi {
|
||||||
// Create pat table
|
// If the packet has a Payload Unit Start Indicator
|
||||||
patPkt := mpegts.Packet{
|
// flag set then we need to write a PCR.
|
||||||
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
|
|
||||||
pkt.PCR = g.pcr()
|
pkt.PCR = g.pcr()
|
||||||
|
|
||||||
g.tick()
|
|
||||||
|
|
||||||
pusi = false
|
pusi = false
|
||||||
}
|
}
|
||||||
|
|
||||||
g.outputChan <- pkt.Bytes()
|
g.outputChan <- pkt.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g.tick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,17 +199,18 @@ func (g *tsGenerator) tick() {
|
||||||
|
|
||||||
// pts retuns the current presentation timestamp.
|
// pts retuns the current presentation timestamp.
|
||||||
func (g *tsGenerator) pts() uint64 {
|
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.
|
// pcr returns the current program clock reference.
|
||||||
func (g *tsGenerator) pcr() uint64 {
|
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.
|
// ccFor returns the next continuity counter for pid.
|
||||||
func (g *tsGenerator) ccFor(pid int) byte {
|
func (g *tsGenerator) ccFor(pid int) byte {
|
||||||
cc := g.continuity[pid]
|
cc := g.continuity[pid]
|
||||||
g.continuity[pid] = (cc + 1) & maxCC
|
const continuityCounterMask = 0xf
|
||||||
|
g.continuity[pid] = (cc + 1) & continuityCounterMask
|
||||||
return cc
|
return cc
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue