Closed tobbee closed 7 months ago
Some outliners were found while testing.
For example, file bbb_1s.ts is parsed into
{"pid":256,"codec":"AVC","type":"video"}
{"pid":257,"codec":"AAC","type":"audio"}
{"pid":256,"parameterSet":"SPS","nr":0,"hex":"6764001facd9405005bb011000000300100000030300f1831960","length":26}
{"pid":256,"parameterSet":"PPS","nr":0,"hex":"68ebecb22c","length":5}
{"pid":256,"rai":true,"pts":133500,"dts":126000,"nalus":[{"type":"AUD_9","len":2},{"type":"SEI_6","len":701},{"type":"SPS_7","len":26},{"type":"PPS_8","len":5},{"type":"IDR_5","len":209}]}
{"pid":256,"rai":false,"pts":144750,"dts":129750,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":34}]}
{"pid":256,"rai":false,"pts":137250,"dts":133500,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":32}]}
{"pid":256,"rai":false,"pts":141000,"dts":137250,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":32}]}
{"pid":256,"rai":false,"pts":148500,"dts":141000,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":48}]}
{"pid":256,"rai":false,"pts":152250,"dts":144750,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":145}]}
{"pid":256,"rai":false,"pts":156000,"dts":148500,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":204}]}
{"pid":256,"rai":false,"pts":163500,"dts":152250,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":143}]}
{"pid":256,"rai":false,"pts":159750,"dts":156000,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":150}]}
{"pid":256,"rai":false,"pts":167250,"dts":159750,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":315}]}
{"pid":256,"rai":false,"pts":171000,"dts":163500,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":679}]}
{"SDT":[{"serviceId":1,"descriptors":[{"serviceName":"ts-info","providerName":"Eyevinn Technology"}]}]}
{"pid":256,"rai":false,"pts":174750,"dts":167250,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":1718}]}
{"pid":256,"rai":false,"pts":182250,"dts":171000,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":918}]}
{"pid":256,"rai":false,"pts":178500,"dts":174750,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":506}]}
{"pid":256,"rai":false,"pts":189750,"dts":178500,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":1342}]}
{"pid":256,"rai":false,"pts":186000,"dts":182250,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":704}]}
{"pid":256,"rai":false,"pts":201000,"dts":186000,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":6516}]}
{"pid":256,"rai":false,"pts":193500,"dts":189750,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":1073}]}
{"pid":256,"rai":false,"pts":197250,"dts":193500,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":1739}]}
{"pid":256,"rai":false,"pts":204750,"dts":197250,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":12196}]}
{"pid":256,"rai":false,"pts":219750,"dts":201000,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":18657}]}
{"pid":256,"rai":false,"pts":212250,"dts":204750,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":7371}]}
{"pid":256,"rai":false,"pts":208500,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":3435}]}
{"pid":256,"rai":false,"pts":216000,"dts":212250,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":4061}]}
{"pid":256,"parameterSet":"SPS","nr":0,"hex":"6764001facd9405005bb011000000300100000030300f1831960","length":26}
{"pid":256,"parameterSet":"PPS","nr":0,"hex":"68ebecb22c","length":5}
{"pid":256,"rai":true,"pts":223500,"dts":216000,"nalus":[{"type":"AUD_9","len":2},{"type":"SPS_7","len":26},{"type":"PPS_8","len":5},{"type":"IDR_5","len":12975}]}
{"pid":256,"rai":false,"pts":234750,"dts":219750,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":24332}]}
{"streamType":"AVC","pid":256,"frameRate":23.04147465437788,"maxStep":7500,"minStep":3750,"avgStep":3906,"RAIGopDuration":1,"IDRGopDuration":1}
Here we noticed that dts
is missing in
{"pid":256,"rai":false,"pts":208500,"nalus":[{"type":"AUD_9","len":2},{"type":"NonIDR_1","len":3435}]}
Since we are using dts
to calculate frame rate, this outliner resulted in output "frameRate":23.04147465437788,"maxStep":7500,"minStep":3750
Similar outliners can be found in other ts files too.
It is important to handle PTS/DTS wrap-around by using right modulo operations. This must be included in tests (TODO).
An error
field is added to statistics to indicate possible problems. Example messages are "PTS/DTS steps are not constant", or "Not enough PTS steps to calculate GOP duration".
To handle PTS/DTS wrap-arounds, we check for each timestamp step and pad it up if necessary. This is done by checking if a step is lower than -MAXSTEP/2, if so, we add it by MAXSTEP. Here MAXSTEP = 2^33 - 1.
maxPic should be 0 by default (infinite loops).
Some useful functions for TS difference calculations could be
const (
ptsWrap = 1 << 33
pcrWrap = ptsWrap * 300
)
func SignedPTSDiff(p2, p1 int64) int64 {
return (p2-p1+3*ptsWrap/2)%ptsWrap - ptsWrap/2
}
func UnsignedPTSDiff(p2, p1 int64) int64 {
return (p2 - p1 + 2*ptsWrap) % ptsWrap
}
func AddPTS(p1, p2 int64) int64 {
return (p1 + p2) % ptsWrap
}
func RewritePCR(p *packet.Packet, dtsOffset uint64) {
deltaPCR := dtsOffset * 300
pcrBytes, _ := adaptationfield.PCR(p)
pcr := gots.ExtractPCR(pcrBytes)
newPcr := (pcr + deltaPCR) % pcrWrap
gots.InsertPCR(pcrBytes, newPcr)
}
// GetPCRValue - return PCR value or -1 if absent
func GetPCRValue(p *packet.Packet) int64 {
if adaptationfield.HasPCR(p) {
pcrBytes, _ := adaptationfield.PCR(p)
pcr := gots.ExtractPCR(pcrBytes)
return int64(pcr)
}
return -1
}
// SignedPCRDiff - calculate signed diff pcr1 - pcr2 considering wrap-around
func SignedPCRDiff(pcr1 int64, pcr2 int64) int64 {
if pcr1-pcr2 < -pcrWrap/2 {
return pcr1 - pcr2 + pcrWrap
}
if pcr1-pcr2 > pcrWrap/2 {
return pcr1 - pcr2 - pcrWrap
}
return pcr1 - pcr2
}
func UnsignedPCRDiff(pcr1 int64, pcr2 int64) int64 {
if pcr1-pcr2 < 0 {
return pcr1 - pcr2 + pcrWrap
}
return pcr1 - pcr2
}
The tool should present the frame rate, video bitrate, and video GoP duration (with variation) in JSON format at the end of processing. It should also happen when pressing Ctrl-C (useful for live case when piping data to stdin).
Frame-rate is most easily obtained from video timestamps. If DTS is present, use that, otherwise use PTS to get a continuously growing timeline. There is also wrap-around since PTS/DTS is 33bits.
GoP-duration can be obtained from RAI-marker distance, but also from checking the NAL type (IDR distance). Collect and present both.
It may now happen that the timing information is more interesting than the nalu and SEI information, so make the latter optional by introducing two command line options:
-nalu -sei