diff --git a/stream/mts/discontinuity.go b/stream/mts/discontinuity.go new file mode 100644 index 00000000..69378916 --- /dev/null +++ b/stream/mts/discontinuity.go @@ -0,0 +1,99 @@ +/* +NAME + discontinuity.go + +DESCRIPTION + discontinuity.go provides functionality for detecting discontinuities in + mpegts and accounting for using the discontinuity indicator in the adaptation + field. + +AUTHOR + Saxon A. Nelson-Milton + +LICENSE + discontinuity.go is Copyright (C) 2017-2019 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 mts + +import "github.com/Comcast/gots/packet" + +// discontinuityRepairer provides function to detect discontinuities in mpegts +// and set the discontinuity indicator as appropriate. +type DiscontinuityRepairer struct { + expCC uint8 +} + +// NewDiscontinuityRepairer returns a pointer to a new discontinuityRepairer +func NewDiscontinuityRepairer() *DiscontinuityRepairer { + return &DiscontinuityRepairer{expCC: 16} +} + +func (dr *DiscontinuityRepairer) Failed() { + dr.decExpectedCC() +} + +// Repair takes a slice of mpegts +func (dr *DiscontinuityRepairer) Repair(d []byte) error { + var pkt [PacketSize]byte + copy(pkt[:], d[:PacketSize]) + p := (*packet.Packet)(&pkt) + if p.PID() != PatPid { + panic("Clip to repair must have PAT first") + } + cc := p.ContinuityCounter() + expect, exists := dr.expectedCC() + dr.incExpectedCC() + if !exists { + dr.setExpectedCC(uint8(cc)) + } else if cc != int(expect) { + if packet.ContainsAdaptationField(p) { + (*packet.AdaptationField)(p).SetDiscontinuity(true) + } else { + err := addAdaptationField(&pkt, DiscontinuityIndicator(true)) + if err != nil { + return err + } + } + dr.setExpectedCC(uint8(cc)) + copy(d[:PacketSize], pkt[:]) + } + return nil +} + +// expectedCC returns the expected cc for the given pid. If the cc hasn't been +// used yet, then 16 and false is returned. +func (dr *DiscontinuityRepairer) expectedCC() (byte, bool) { + if dr.expCC == 16 { + return 16, false + } + return dr.expCC, true +} + +// incExpectedCC increments the expected cc in dr's cc map for the given pid. +func (dr *DiscontinuityRepairer) incExpectedCC() { + dr.expCC = (dr.expCC + 1) & 0xf +} + +// decExpectedCC decrements the expected cc in dr's cc map for the given pid. +func (dr *DiscontinuityRepairer) decExpectedCC() { + dr.expCC = (dr.expCC - 1) & 0xf +} + +// setExpectedCC sets the expected cc in dr's cc map for the given pid, and cc. +func (dr *DiscontinuityRepairer) setExpectedCC(cc uint8) { + dr.expCC = cc +}