cmd/ts-repair: updated comments and made funcs more robust

This commit is contained in:
saxon 2019-01-25 16:10:13 +10:30
parent cac7184737
commit 90a85fbfbb
1 changed files with 51 additions and 17 deletions

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"errors"
"flag" "flag"
"fmt" "fmt"
"io" "io"
@ -10,21 +11,26 @@ import (
"github.com/Comcast/gots/packet" "github.com/Comcast/gots/packet"
) )
// Various errors that we can encounter.
const ( const (
errBadInPath = "No file path provided, or file does not exist" errBadInPath = "No file path provided, or file does not exist"
errCantCreateOut = "Can't create output file" errCantCreateOut = "Can't create output file"
errCantGetPid = "Can't get pid from packet" errCantGetPid = "Can't get pid from packet"
errReadFail = "Read failed" errReadFail = "Read failed"
errWriteFail = "Write to file failed" errWriteFail = "Write to file failed"
errBadMode = "Bad fix mode" errBadMode = "Bad fix mode"
errAdaptationPresent = "Adaptation field is already present in packet"
errNoAdaptationField = "No adaptation field in this packet"
) )
// Consts describing flag usage.
const ( const (
inUsage = "The path to the file to be repaired" inUsage = "The path to the file to be repaired"
outUsage = "Output file path" outUsage = "Output file path"
modeUsage = "Fix mode: 0 = cc-shift, 1 = di-update" modeUsage = "Fix mode: 0 = cc-shift, 1 = di-update"
) )
// Repair modes.
const ( const (
ccShift = iota ccShift = iota
diUpdate diUpdate
@ -36,20 +42,27 @@ var ccMap = map[int]byte{
mts.VideoPid: 16, mts.VideoPid: 16,
} }
// packetNo will keep track of the ts packet number for reference.
var packetNo int var packetNo int
// Option defines a func that performs an action on p in order to change a ts option.
type Option func(p *Packet) type Option func(p *Packet)
// Packet is a byte array of size mts.PacketSize i.e. 188 bytes. We define this
// to allow us to write receiver funcs for the [mts.PacketSize]byte type.
type Packet [mts.PacketSize]byte type Packet [mts.PacketSize]byte
// CC returns the CC of p.
func (p *Packet) CC() byte { func (p *Packet) CC() byte {
return (*p)[3] & 0x0f return (*p)[3] & 0x0f
} }
// setCC sets the CC of p.
func (p *Packet) setCC(cc byte) { func (p *Packet) setCC(cc byte) {
(*p)[3] |= cc & 0xf (*p)[3] |= cc & 0xf
} }
// setDI sets the discontinuity counter of p.
func (p *Packet) setDI(di bool) { func (p *Packet) setDI(di bool) {
if di { if di {
p[5] |= 0x80 p[5] |= 0x80
@ -58,27 +71,41 @@ func (p *Packet) setDI(di bool) {
} }
} }
func (p *Packet) addAdaptationField(options ...Option) { // addAdaptationField adds an adaptation field to p, and applys the passed options to this field.
// Create space for adaptation field // TODO: this will probably break if we already have adaptation field.
func (p *Packet) addAdaptationField(options ...Option) error {
if p.hasAdaptation() {
return errors.New(errAdaptationPresent)
}
// Create space for adaptation field.
copy(p[mts.HeadSize+mts.DefaultAdaptationSize:], p[mts.HeadSize:len(p)-mts.DefaultAdaptationSize]) copy(p[mts.HeadSize+mts.DefaultAdaptationSize:], p[mts.HeadSize:len(p)-mts.DefaultAdaptationSize])
// TODO: seperate into own function // TODO: seperate into own function
// Update adaptation field control // Update adaptation field control.
p[mts.AdaptationControlIdx] &= 0xff ^ mts.AdaptationControlMask p[mts.AdaptationControlIdx] &= 0xff ^ mts.AdaptationControlMask
p[mts.AdaptationControlIdx] |= mts.AdaptationControlMask p[mts.AdaptationControlIdx] |= mts.AdaptationControlMask
// Default the adaptationfield // Default the adaptationfield.
p.resetAdaptation() p.resetAdaptation()
// Apply and options that have bee passed.
for _, option := range options { for _, option := range options {
option(p) option(p)
} }
return nil
} }
func (p *Packet) resetAdaptation() { // resetAdaptation sets fields in ps adaptation field to 0 if the adaptation field
// exists, otherwise an error is returned.
func (p *Packet) resetAdaptation() error {
if !p.hasAdaptation() {
return errors.New(errNoAdaptationField)
}
p[mts.AdaptationIdx] = mts.DefaultAdaptationBodySize p[mts.AdaptationIdx] = mts.DefaultAdaptationBodySize
p[mts.AdaptationBodyIdx] = 0x00 p[mts.AdaptationBodyIdx] = 0x00
return nil
} }
// hasAdaptation returns true if p has an adaptation field and false otherwise.
func (p *Packet) hasAdaptation() bool { func (p *Packet) hasAdaptation() bool {
afc := p[mts.AdaptationControlIdx] & mts.AdaptationControlMask afc := p[mts.AdaptationControlIdx] & mts.AdaptationControlMask
if afc == 0x20 || afc == 0x30 { if afc == 0x20 || afc == 0x30 {
@ -88,6 +115,8 @@ func (p *Packet) hasAdaptation() bool {
} }
} }
// DiscontinuityIndicator returns and Option that will set p's discontinuity
// indicator according to f.
func DiscontinuityIndicator(f bool) Option { func DiscontinuityIndicator(f bool) Option {
return func(p *Packet) { return func(p *Packet) {
set := byte(mts.DiscontinuityIndicatorMask) set := byte(mts.DiscontinuityIndicatorMask)
@ -130,23 +159,26 @@ func main() {
panic(errReadFail + ": " + err.Error()) panic(errReadFail + ": " + err.Error())
} }
packetNo++ packetNo++
// Get the pid from the packet and set the cc based on this pid using our map
// Get the pid from the packet
pid, err := packet.Pid((*packet.Packet)(&p)) pid, err := packet.Pid((*packet.Packet)(&p))
if err != nil { if err != nil {
panic(errCantGetPid) panic(errCantGetPid)
} }
// Get the cc from the packet and also the expected cc (if exists)
cc := p.CC() cc := p.CC()
expect, exists := expectedCC(int(pid)) expect, exists := expectedCC(int(pid))
if !exists { if !exists {
updateCCMap(int(pid), cc) updateCCMap(int(pid), cc)
} else { } else {
switch *modePtr { switch *modePtr {
// ccShift mode shifts all CC regardless of presence of Discontinuities or not
case ccShift: case ccShift:
p.setCC(expect) p.setCC(expect)
// diUpdate mode finds discontinuities and sets the discontinuity indicator to true.
// If we have a pat or pmt then we need to add an adaptation field and then set the DI.
case diUpdate: case diUpdate:
if cc != expect { if cc != expect {
fmt.Printf("***** Discontinuity found (packetNo: %v pid: %v, cc: %v, expect: %v)\n", packetNo, pid, cc, expect) fmt.Printf("***** Discontinuity found (packetNo: %v pid: %v, cc: %v, expect: %v)\n", packetNo, pid, cc, expect)
if p.hasAdaptation() { if p.hasAdaptation() {
@ -156,19 +188,20 @@ func main() {
} }
updateCCMap(int(pid), p.CC()) updateCCMap(int(pid), p.CC())
} }
default: default:
panic(errBadMode) panic(errBadMode)
} }
} }
// Write this packet to the output file
// Write this packet to the output file.
if _, err := outFile.Write(p[:]); err != nil { if _, err := outFile.Write(p[:]); err != nil {
panic(errWriteFail + ": " + err.Error()) panic(errWriteFail + ": " + err.Error())
} }
} }
} }
// ccFor gets the next cc for the given pid // expectedCC returns the expected cc for the given pid. If the cc hasn't been
// used yet, then 16 and false is returned.
func expectedCC(pid int) (byte, bool) { func expectedCC(pid int) (byte, bool) {
cc := ccMap[pid] cc := ccMap[pid]
if cc == 16 { if cc == 16 {
@ -178,6 +211,7 @@ func expectedCC(pid int) (byte, bool) {
return cc, true return cc, true
} }
// updateCCMap updates the cc for the passed pid.
func updateCCMap(pid int, cc byte) { func updateCCMap(pid int, cc byte) {
ccMap[pid] = (cc + 1) & 0xf ccMap[pid] = (cc + 1) & 0xf
} }