av/mpegts/MpegTs.go

191 lines
8.8 KiB
Go
Raw Normal View History

/*
NAME
MpegTs.go - provides a data structure intended to encapsulate the properties
of an MpegTs packet and also functions to allow manipulation of these packets.
DESCRIPTION
See Readme.md
AUTHOR
Saxon A. Nelson-Milton <saxon.milton@gmail.com>
LICENSE
MpegTs.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 mpegts
2018-05-30 10:23:57 +03:00
import "bitbucket.org/ausocean/av/tools"
const (
2018-03-14 04:18:03 +03:00
mpegTsSize = 188
mpegtsPayloadSize = 176
)
/*
The below data struct encapsulates the fields of an MPEG-TS packet. Below is
the formatting of an MPEG-TS packet for reference!
MPEG-TS Packet Formatting
============================================================================
| octet no | bit 0 | bit 1 | bit 2 | bit 3 | bit 4 | bit 5 | bit 6 | bit 7 |
============================================================================
| octet 0 | sync byte (0x47) |
----------------------------------------------------------------------------
| octet 1 | TEI | PUSI | Prior | PID |
----------------------------------------------------------------------------
| octet 2 | PID cont. |
----------------------------------------------------------------------------
| octet 3 | TSC | AFC | CC |
----------------------------------------------------------------------------
| octet 4 | AFL |
----------------------------------------------------------------------------
| octet 5 | DI | RAI | ESPI | PCRF | OPCRF | SPF | TPDF | AFEF |
----------------------------------------------------------------------------
| optional | PCR (48 bits => 6 bytes) |
----------------------------------------------------------------------------
| - | PCR cont. |
----------------------------------------------------------------------------
| - | PCR cont. |
----------------------------------------------------------------------------
| - | PCR cont. |
----------------------------------------------------------------------------
| - | PCR cont. |
----------------------------------------------------------------------------
| - | PCR cont. |
----------------------------------------------------------------------------
| optional | OPCR (48 bits => 6 bytes) |
----------------------------------------------------------------------------
| - | OPCR cont. |
----------------------------------------------------------------------------
| - | OPCR cont. |
----------------------------------------------------------------------------
| - | OPCR cont. |
----------------------------------------------------------------------------
| - | OPCR cont. |
----------------------------------------------------------------------------
| - | OPCR cont. |
----------------------------------------------------------------------------
| optional | SC |
----------------------------------------------------------------------------
| optional | TPDL |
----------------------------------------------------------------------------
| optional | TPD (variable length) |
----------------------------------------------------------------------------
| - | ... |
----------------------------------------------------------------------------
| optional | Extension (variable length) |
----------------------------------------------------------------------------
| - | ... |
----------------------------------------------------------------------------
| optional | Stuffing (variable length) |
----------------------------------------------------------------------------
| - | ... |
----------------------------------------------------------------------------
| optional | Payload (variable length) |
----------------------------------------------------------------------------
| - | ... |
----------------------------------------------------------------------------
*/
type MpegTsPacket struct {
TEI bool // Transport Error Indicator
PUSI bool // Payload Unit Start Indicator
Priority bool // Tranposrt priority indicator
PID uint16 // Packet identifier
TSC byte // Transport Scrambling Control
AFC byte // Adaption Field Control
CC byte // Continuity Counter
DI bool // Discontinouty indicator
RAI bool // random access indicator
ESPI bool // Elementary stream priority indicator
PCRF bool // PCR flag
OPCRF bool // OPCR flag
SPF bool // Splicing point flag
TPDF bool // Transport private data flag
AFEF bool // Adaptation field extension flag
PCR uint64 // Program clock reference
OPCR uint64 // Original program clock reference
SC byte // Splice countdown
TPDL byte // Tranposrt private data length
TPD []byte // Private data
Ext []byte // Adaptation field extension
2018-03-13 07:33:31 +03:00
Payload []byte // Mpeg ts Payload
}
2018-03-13 07:33:31 +03:00
// FillPayload takes a channel and fills the packets Payload field until the
2018-03-13 03:54:37 +03:00
// channel is empty or we've the packet reaches capacity
2018-03-14 04:18:03 +03:00
func (p *MpegTsPacket) FillPayload(channel chan byte) {
p.Payload = make([]byte, 0, mpegtsPayloadSize)
2018-04-16 08:03:03 +03:00
currentPktLength := 6 + int(toByte(p.PCRF))*6 + int(toByte(p.OPCRF))*6 +
int(toByte(p.SPF))*1 + int(toByte(p.TPDF))*1 + len(p.TPD)
2018-02-28 16:46:59 +03:00
// While we're within the mpegts packet size and we still have data we can use
2018-03-13 07:33:31 +03:00
for (currentPktLength+len(p.Payload)) < mpegTsSize && len(channel) > 0 {
2018-03-14 04:18:03 +03:00
p.Payload = append(p.Payload, <-channel)
2018-01-08 04:12:26 +03:00
}
}
2018-04-16 08:03:03 +03:00
// toByte is a simple wrapper function for tools.BoolToByte which takes a bool
2018-03-13 03:54:37 +03:00
// and returns an equivalent byte
2018-04-16 08:03:03 +03:00
func toByte(b bool) byte {
2018-02-28 16:46:59 +03:00
return tools.BoolToByte(b)
}
2018-03-13 03:54:37 +03:00
// ToByteSlice interprets the fields of the ts packet instance and outputs a
2018-03-13 07:33:31 +03:00
// corresponding byte slice
2018-02-28 16:46:59 +03:00
func (p *MpegTsPacket) ToByteSlice() (output []byte) {
2018-04-16 08:03:03 +03:00
stuffingLength := 182 - len(p.Payload) - len(p.TPD) - int(toByte(p.PCRF))*6 -
int(toByte(p.OPCRF))*6 - int(toByte(p.SPF))
2018-01-16 10:17:38 +03:00
var stuffing []byte
if stuffingLength > 0 {
2018-03-14 04:18:03 +03:00
stuffing = make([]byte, stuffingLength)
2018-01-16 10:17:38 +03:00
}
2018-01-08 04:12:26 +03:00
for i := range stuffing {
stuffing[i] = 0xFF
}
2018-04-16 08:03:03 +03:00
afl := 1 + int(toByte(p.PCRF))*6 + int(toByte(p.OPCRF))*6 + int(toByte(p.SPF)) + int(toByte(p.TPDF)) + len(p.TPD) + len(stuffing)
2018-03-14 04:18:03 +03:00
output = make([]byte, 0, mpegTsSize)
output = append(output, []byte{
0x47,
2018-04-16 08:03:03 +03:00
(toByte(p.TEI)<<7 | toByte(p.PUSI)<<6 | toByte(p.Priority)<<5 | byte((p.PID&0xFF00)>>8)),
byte(p.PID & 0x00FF),
2018-02-28 17:10:52 +03:00
(p.TSC<<6 | p.AFC<<4 | p.CC),
}...)
2018-01-16 08:49:18 +03:00
if p.AFC == 3 || p.AFC == 2 {
output = append(output, []byte{
2018-04-16 08:03:03 +03:00
byte(afl), (toByte(p.DI)<<7 | toByte(p.RAI)<<6 | toByte(p.ESPI)<<5 |
toByte(p.PCRF)<<4 | toByte(p.OPCRF)<<3 | toByte(p.SPF)<<2 |
toByte(p.TPDF)<<1 | toByte(p.AFEF)),
2018-01-16 08:49:18 +03:00
}...)
2018-03-14 04:18:03 +03:00
for i := 40; p.PCRF && i >= 0; i -= 8 {
2018-01-16 08:49:18 +03:00
output = append(output, byte((p.PCR<<15)>>uint(i)))
}
2018-03-14 04:18:03 +03:00
for i := 40; p.OPCRF && i >= 0; i -= 8 {
2018-01-16 08:49:18 +03:00
output = append(output, byte(p.OPCR>>uint(i)))
}
if p.SPF {
output = append(output, p.SC)
}
if p.TPDF {
output = append(output, append([]byte{p.TPDL}, p.TPD...)...)
}
2018-01-16 10:17:38 +03:00
output = append(output, p.Ext...)
output = append(output, stuffing...)
2018-01-07 06:55:13 +03:00
}
2018-01-16 08:49:18 +03:00
output = append(output, p.Payload...)
return
}