/* NAME discontinuity.go DESCRIPTION discontinuity.go provides functionality for detecting discontinuities in MPEG-TS and accounting for using the discontinuity indicator in the adaptation field. AUTHOR Saxon A. Nelson-Milton <saxon@ausocean.org> 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 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 MPEG-TS // and set the discontinuity indicator as appropriate. type DiscontinuityRepairer struct { expCC map[int]int } // NewDiscontinuityRepairer returns a pointer to a new discontinuityRepairer. func NewDiscontinuityRepairer() *DiscontinuityRepairer { return &DiscontinuityRepairer{ expCC: map[int]int{ PatPid: 16, PmtPid: 16, VideoPid: 16, }, } } // Failed is to be called in the case of a failed send. This will decrement the // expectedCC so that it aligns with the failed chunks cc. func (dr *DiscontinuityRepairer) Failed() { dr.decExpectedCC(PatPid) } // Repair takes a clip of MPEG-TS and checks that the first packet, which should // be a PAT, contains a cc that is expected, otherwise the discontinuity indicator // is set to true. func (dr *DiscontinuityRepairer) Repair(d []byte) error { var pkt packet.Packet copy(pkt[:], d[:PacketSize]) pid := pkt.PID() if pid != PatPid { panic("Clip to repair must have PAT first") } cc := pkt.ContinuityCounter() expect, _ := dr.ExpectedCC(pid) if cc != int(expect) { if packet.ContainsAdaptationField(&pkt) { (*packet.AdaptationField)(&pkt).SetDiscontinuity(true) } else { err := addAdaptationField(&pkt, DiscontinuityIndicator(true)) if err != nil { return err } } dr.SetExpectedCC(pid, cc) copy(d[:PacketSize], pkt[:]) } dr.IncExpectedCC(pid) return nil } // expectedCC returns the expected cc. If the cc hasn't been used yet, then 16 // and false is returned. func (dr *DiscontinuityRepairer) ExpectedCC(pid int) (int, bool) { if dr.expCC[pid] == 16 { return 16, false } return dr.expCC[pid], true } // incExpectedCC increments the expected cc. func (dr *DiscontinuityRepairer) IncExpectedCC(pid int) { dr.expCC[pid] = (dr.expCC[pid] + 1) & 0xf } // decExpectedCC decrements the expected cc. func (dr *DiscontinuityRepairer) decExpectedCC(pid int) { dr.expCC[pid] = (dr.expCC[pid] - 1) & 0xf } // setExpectedCC sets the expected cc. func (dr *DiscontinuityRepairer) SetExpectedCC(pid, cc int) { dr.expCC[pid] = cc }