mirror of
https://github.com/aler9/gortsplib
synced 2025-10-30 02:01:57 +08:00
h264: support extracting DTS from nvenc (https://github.com/aler9/rtsp-simple-server/issues/989)
This commit is contained in:
@@ -68,7 +68,7 @@ func getPOC(buf []byte, sps *SPS) (uint32, error) {
|
||||
return uint32(picOrderCntLsb), nil
|
||||
}
|
||||
|
||||
func getNALUSPOC(nalus [][]byte, sps *SPS) (uint32, error) {
|
||||
func findPOC(nalus [][]byte, sps *SPS) (uint32, error) {
|
||||
for _, nalu := range nalus {
|
||||
typ := NALUType(nalu[0] & 0x1F)
|
||||
if typ == NALUTypeIDR || typ == NALUTypeNonIDR {
|
||||
@@ -94,6 +94,70 @@ func getPOCDiff(poc1 uint32, poc2 uint32, sps *SPS) int32 {
|
||||
return diff
|
||||
}
|
||||
|
||||
func getSEIPicTimingDPBOutputDelay(buf []byte, sps *SPS) (uint32, bool) {
|
||||
buf = AntiCompetitionRemove(buf)
|
||||
pos := 1
|
||||
|
||||
for {
|
||||
if pos >= (len(buf) - 1) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
payloadType := 0
|
||||
for {
|
||||
byt := buf[pos]
|
||||
pos++
|
||||
payloadType += int(byt)
|
||||
if byt != 0xFF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
payloadSize := 0
|
||||
for {
|
||||
byt := buf[pos]
|
||||
pos++
|
||||
payloadSize += int(byt)
|
||||
if byt != 0xFF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if payloadType == 1 { // timing info
|
||||
br := bitio.NewReader(bytes.NewReader(buf[pos : pos+payloadSize]))
|
||||
|
||||
// cpbRemovalDelay
|
||||
_, err := br.ReadBits(sps.VUI.NalHRD.CpbRemovalDelayLengthMinus1 + 1)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
tmp, err := br.ReadBits(sps.VUI.NalHRD.DpbOutputDelayLengthMinus1 + 1)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
dpbOutputDelay := uint32(tmp)
|
||||
|
||||
return dpbOutputDelay, true
|
||||
}
|
||||
|
||||
pos += payloadSize
|
||||
}
|
||||
}
|
||||
|
||||
func findSEIPicTimingDPBOutputDelay(nalus [][]byte, sps *SPS) (uint32, bool) {
|
||||
for _, nalu := range nalus {
|
||||
typ := NALUType(nalu[0] & 0x1F)
|
||||
if typ == NALUTypeSEI {
|
||||
ret, ok := getSEIPicTimingDPBOutputDelay(nalu, sps)
|
||||
if ok {
|
||||
return ret, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// DTSExtractor is a utility that allows to extract NALU DTS from PTS.
|
||||
type DTSExtractor struct {
|
||||
sps []byte
|
||||
@@ -110,27 +174,22 @@ func NewDTSExtractor() *DTSExtractor {
|
||||
return &DTSExtractor{}
|
||||
}
|
||||
|
||||
func (d *DTSExtractor) extractInner(
|
||||
nalus [][]byte,
|
||||
pts time.Duration,
|
||||
) (time.Duration, int32, error) {
|
||||
func (d *DTSExtractor) extractInner(nalus [][]byte, pts time.Duration) (time.Duration, int32, error) {
|
||||
idrPresent := false
|
||||
|
||||
for _, nalu := range nalus {
|
||||
typ := NALUType(nalu[0] & 0x1F)
|
||||
switch typ {
|
||||
// parse SPS
|
||||
case NALUTypeSPS:
|
||||
if d.sps == nil || !bytes.Equal(d.sps, nalu) {
|
||||
var spsp SPS
|
||||
err := spsp.Unmarshal(nalu)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
return 0, 0, fmt.Errorf("invalid SPS: %v", err)
|
||||
}
|
||||
d.sps = append([]byte(nil), nalu...)
|
||||
d.spsp = &spsp
|
||||
|
||||
// in case of B-frames, we have to subtract from DTS the maximum number of reordered frames
|
||||
if d.spsp.VUI != nil && d.spsp.VUI.TimingInfo != nil &&
|
||||
d.spsp.VUI.BitstreamRestriction != nil {
|
||||
d.ptsDTSOffset = time.Duration(math.Round(float64(
|
||||
@@ -141,7 +200,6 @@ func (d *DTSExtractor) extractInner(
|
||||
}
|
||||
}
|
||||
|
||||
// set IDR present flag
|
||||
case NALUTypeIDR:
|
||||
idrPresent = true
|
||||
}
|
||||
@@ -151,51 +209,68 @@ func (d *DTSExtractor) extractInner(
|
||||
return 0, 0, fmt.Errorf("SPS not received yet")
|
||||
}
|
||||
|
||||
if idrPresent || d.spsp.PicOrderCntType == 2 {
|
||||
d.expectedPOC = 0
|
||||
return pts - d.ptsDTSOffset, 0, nil
|
||||
}
|
||||
|
||||
// compute expectedPOC immediately in order to store it even in case of errors
|
||||
d.expectedPOC += 2
|
||||
d.expectedPOC &= ((1 << (d.spsp.Log2MaxPicOrderCntLsbMinus4 + 4)) - 1)
|
||||
|
||||
poc, err := getNALUSPOC(nalus, d.spsp)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
pocDiff := getPOCDiff(poc, d.expectedPOC, d.spsp)
|
||||
|
||||
if pocDiff == 0 {
|
||||
return pts - d.ptsDTSOffset, 0, nil
|
||||
}
|
||||
|
||||
// special case to eliminate errors near 0
|
||||
if d.spsp.VUI != nil && d.spsp.VUI.TimingInfo != nil && d.spsp.VUI.BitstreamRestriction != nil &&
|
||||
pocDiff == -int32(d.spsp.VUI.BitstreamRestriction.MaxNumReorderFrames)*2 {
|
||||
return pts, pocDiff, nil
|
||||
}
|
||||
|
||||
if d.prevPOCDiff == 0 {
|
||||
if pocDiff == -2 {
|
||||
return 0, 0, fmt.Errorf("invalid frame POC")
|
||||
switch {
|
||||
// DTS is computed from SEI
|
||||
case d.spsp.VUI != nil && d.spsp.VUI.TimingInfo != nil && d.spsp.VUI.NalHRD != nil:
|
||||
dpbOutputDelay, ok := findSEIPicTimingDPBOutputDelay(nalus, d.spsp)
|
||||
if !ok {
|
||||
return 0, 0, fmt.Errorf("SEI / pic_timing not found")
|
||||
}
|
||||
|
||||
return d.prevPTS - d.ptsDTSOffset +
|
||||
time.Duration(math.Round(float64(pts-d.prevPTS)/float64(pocDiff/2+1))), pocDiff, nil
|
||||
}
|
||||
return pts - time.Duration(dpbOutputDelay)/2*time.Second*
|
||||
time.Duration(d.spsp.VUI.TimingInfo.NumUnitsInTick)*2/time.Duration(d.spsp.VUI.TimingInfo.TimeScale), 0, nil
|
||||
|
||||
// pocDiff : prevPOCDiff = (pts - dts - ptsDTSOffset) : (prevPTS - prevDTS - ptsDTSOffset)
|
||||
return pts - d.ptsDTSOffset + time.Duration(math.Round(float64(d.prevDTS-d.prevPTS+d.ptsDTSOffset)*
|
||||
float64(pocDiff)/float64(d.prevPOCDiff))), pocDiff, nil
|
||||
// DTS is always equal to PTS
|
||||
case d.spsp.PicOrderCntType == 2:
|
||||
return pts, 0, nil
|
||||
|
||||
// DTS is computed by using POC, timing infos and max_num_reorder_frames
|
||||
case d.spsp.VUI != nil && d.spsp.VUI.TimingInfo != nil && d.spsp.VUI.BitstreamRestriction != nil:
|
||||
if idrPresent {
|
||||
d.expectedPOC = 0
|
||||
return pts - d.ptsDTSOffset, 0, nil
|
||||
}
|
||||
|
||||
// compute expectedPOC immediately in order to store it even in case of errors
|
||||
d.expectedPOC += 2
|
||||
d.expectedPOC &= ((1 << (d.spsp.Log2MaxPicOrderCntLsbMinus4 + 4)) - 1)
|
||||
|
||||
poc, err := findPOC(nalus, d.spsp)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
pocDiff := getPOCDiff(poc, d.expectedPOC, d.spsp)
|
||||
|
||||
if pocDiff == 0 {
|
||||
return pts - d.ptsDTSOffset, 0, nil
|
||||
}
|
||||
|
||||
// special case to eliminate errors near 0
|
||||
if pocDiff == -int32(d.spsp.VUI.BitstreamRestriction.MaxNumReorderFrames)*2 {
|
||||
return pts, pocDiff, nil
|
||||
}
|
||||
|
||||
if d.prevPOCDiff == 0 {
|
||||
if pocDiff == -2 {
|
||||
return 0, 0, fmt.Errorf("invalid frame POC")
|
||||
}
|
||||
|
||||
return d.prevPTS - d.ptsDTSOffset +
|
||||
time.Duration(math.Round(float64(pts-d.prevPTS)/float64(pocDiff/2+1))), pocDiff, nil
|
||||
}
|
||||
|
||||
// pocDiff : prevPOCDiff = (pts - dts - ptsDTSOffset) : (prevPTS - prevDTS - ptsDTSOffset)
|
||||
return pts - d.ptsDTSOffset + time.Duration(math.Round(float64(d.prevDTS-d.prevPTS+d.ptsDTSOffset)*
|
||||
float64(pocDiff)/float64(d.prevPOCDiff))), pocDiff, nil
|
||||
|
||||
default:
|
||||
return 0, 0, fmt.Errorf("unable to compute H264 DTS")
|
||||
}
|
||||
}
|
||||
|
||||
// Extract extracts the DTS of a NALU group.
|
||||
func (d *DTSExtractor) Extract(
|
||||
nalus [][]byte,
|
||||
pts time.Duration,
|
||||
) (time.Duration, error) {
|
||||
// Extract extracts the DTS of a group of NALUs.
|
||||
func (d *DTSExtractor) Extract(nalus [][]byte, pts time.Duration) (time.Duration, error) {
|
||||
dts, pocDiff, err := d.extractInner(nalus, pts)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
||||
@@ -8,137 +8,195 @@ import (
|
||||
)
|
||||
|
||||
func TestDTSExtractor(t *testing.T) {
|
||||
sequence := []struct {
|
||||
type sequenceSample struct {
|
||||
nalus [][]byte
|
||||
pts time.Duration
|
||||
dts time.Duration
|
||||
}
|
||||
|
||||
for _, ca := range []struct {
|
||||
name string
|
||||
sequence []sequenceSample
|
||||
}{
|
||||
{
|
||||
[][]byte{
|
||||
"max_num_reorder_frames-based",
|
||||
[]sequenceSample{
|
||||
{
|
||||
0x67, 0x64, 0x00, 0x28, 0xac, 0xd9, 0x40, 0x78,
|
||||
0x02, 0x27, 0xe5, 0xc0, 0x44, 0x00, 0x00, 0x03,
|
||||
0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0x28, 0x3c,
|
||||
0x60, 0xc6, 0x58,
|
||||
[][]byte{
|
||||
{
|
||||
0x67, 0x64, 0x00, 0x28, 0xac, 0xd9, 0x40, 0x78,
|
||||
0x02, 0x27, 0xe5, 0xc0, 0x44, 0x00, 0x00, 0x03,
|
||||
0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0x28, 0x3c,
|
||||
0x60, 0xc6, 0x58,
|
||||
},
|
||||
{0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0},
|
||||
{
|
||||
0x65, 0x88, 0x82, 0x00, 0x05, 0xbf, 0xfe, 0xf7,
|
||||
0xd3, 0x3f, 0xcc, 0xb2, 0xec, 0x9a, 0x24, 0xb5,
|
||||
0xe3, 0xa8, 0xf7, 0xa2, 0x9e, 0x26, 0x5f, 0x43,
|
||||
0x75, 0x25, 0x01, 0x9b, 0x96, 0xc4, 0xed, 0x3a,
|
||||
0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x55,
|
||||
0xda, 0xf7, 0x10, 0xe5, 0xc4, 0x70, 0xe1, 0xfe,
|
||||
0x83, 0xc0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x1f, 0xa0, 0x00, 0x00, 0x05, 0x68, 0x00,
|
||||
0x00, 0x03, 0x01, 0xc6, 0x00, 0x00, 0x03, 0x01,
|
||||
0x0c, 0x00, 0x00, 0x03, 0x00, 0xb1, 0x00, 0x00,
|
||||
0x03, 0x00, 0x8f, 0x80, 0x00, 0x00, 0x8a, 0x80,
|
||||
0x00, 0x00, 0x9d, 0x00, 0x00, 0x03, 0x00, 0xb2,
|
||||
0x00, 0x00, 0x03, 0x01, 0x1c, 0x00, 0x00, 0x03,
|
||||
0x01, 0x7c, 0x00, 0x00, 0x03, 0x02, 0xf0, 0x00,
|
||||
0x00, 0x04, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0b,
|
||||
0x78,
|
||||
},
|
||||
},
|
||||
0,
|
||||
-400 * time.Millisecond,
|
||||
},
|
||||
{0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0},
|
||||
{
|
||||
0x65, 0x88, 0x82, 0x00, 0x05, 0xbf, 0xfe, 0xf7,
|
||||
0xd3, 0x3f, 0xcc, 0xb2, 0xec, 0x9a, 0x24, 0xb5,
|
||||
0xe3, 0xa8, 0xf7, 0xa2, 0x9e, 0x26, 0x5f, 0x43,
|
||||
0x75, 0x25, 0x01, 0x9b, 0x96, 0xc4, 0xed, 0x3a,
|
||||
0x80, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x55,
|
||||
0xda, 0xf7, 0x10, 0xe5, 0xc4, 0x70, 0xe1, 0xfe,
|
||||
0x83, 0xc0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x1f, 0xa0, 0x00, 0x00, 0x05, 0x68, 0x00,
|
||||
0x00, 0x03, 0x01, 0xc6, 0x00, 0x00, 0x03, 0x01,
|
||||
0x0c, 0x00, 0x00, 0x03, 0x00, 0xb1, 0x00, 0x00,
|
||||
0x03, 0x00, 0x8f, 0x80, 0x00, 0x00, 0x8a, 0x80,
|
||||
0x00, 0x00, 0x9d, 0x00, 0x00, 0x03, 0x00, 0xb2,
|
||||
0x00, 0x00, 0x03, 0x01, 0x1c, 0x00, 0x00, 0x03,
|
||||
0x01, 0x7c, 0x00, 0x00, 0x03, 0x02, 0xf0, 0x00,
|
||||
0x00, 0x04, 0x40, 0x00, 0x00, 0x08, 0x80, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0b,
|
||||
0x78,
|
||||
[][]byte{
|
||||
{
|
||||
0x41, 0x9a, 0x24, 0x6c, 0x41, 0x4f, 0xfe, 0xd6,
|
||||
0x8c, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x6d, 0x40,
|
||||
},
|
||||
},
|
||||
800 * time.Millisecond,
|
||||
-200 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
[][]byte{
|
||||
{
|
||||
0x41, 0x9e, 0x42, 0x78, 0x82, 0x1f, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x02,
|
||||
0x0f,
|
||||
},
|
||||
},
|
||||
400 * time.Millisecond,
|
||||
0,
|
||||
},
|
||||
{
|
||||
[][]byte{
|
||||
{
|
||||
0x01, 0x9e, 0x61, 0x74, 0x43, 0xff, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x9c,
|
||||
},
|
||||
},
|
||||
200 * time.Millisecond,
|
||||
200 * time.Millisecond,
|
||||
},
|
||||
},
|
||||
0,
|
||||
-400 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
[][]byte{
|
||||
"sei-based",
|
||||
[]sequenceSample{
|
||||
{
|
||||
0x41, 0x9a, 0x24, 0x6c, 0x41, 0x4f, 0xfe, 0xd6,
|
||||
0x8c, 0xb0, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x6d, 0x40,
|
||||
[][]byte{
|
||||
// SEI (buffering period)
|
||||
{6, 0, 7, 128, 117, 48, 0, 0, 3, 0, 64, 128},
|
||||
// SEI (pic timing)
|
||||
{6, 1, 4, 0, 0, 8, 16, 128},
|
||||
// SPS
|
||||
{
|
||||
103, 100, 0, 42, 172, 44, 172, 7,
|
||||
128, 34, 126, 92, 5, 168, 8, 8,
|
||||
10, 0, 0, 7, 208, 0, 3, 169,
|
||||
129, 192, 0, 0, 76, 75, 0, 0,
|
||||
38, 37, 173, 222, 92, 20,
|
||||
},
|
||||
},
|
||||
0,
|
||||
-16666666 * time.Nanosecond,
|
||||
},
|
||||
{
|
||||
[][]byte{
|
||||
// SEI
|
||||
{6, 1, 4, 0, 2, 32, 16, 128},
|
||||
},
|
||||
66666666 * time.Nanosecond,
|
||||
0,
|
||||
},
|
||||
{
|
||||
[][]byte{
|
||||
// SEI
|
||||
{6, 1, 4, 0, 4, 0, 16, 128},
|
||||
},
|
||||
16666666 * time.Nanosecond,
|
||||
16666666 * time.Nanosecond,
|
||||
},
|
||||
{
|
||||
[][]byte{
|
||||
// SEI
|
||||
{6, 1, 4, 0, 6, 0, 16, 128},
|
||||
},
|
||||
33333333 * time.Nanosecond,
|
||||
33333333 * time.Nanosecond,
|
||||
},
|
||||
},
|
||||
800 * time.Millisecond,
|
||||
-200 * time.Millisecond,
|
||||
},
|
||||
{
|
||||
[][]byte{
|
||||
{
|
||||
0x41, 0x9e, 0x42, 0x78, 0x82, 0x1f, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x02,
|
||||
0x0f,
|
||||
},
|
||||
},
|
||||
400 * time.Millisecond,
|
||||
0,
|
||||
},
|
||||
{
|
||||
[][]byte{
|
||||
{
|
||||
0x01, 0x9e, 0x61, 0x74, 0x43, 0xff, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00,
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x9c,
|
||||
},
|
||||
},
|
||||
200 * time.Millisecond,
|
||||
200 * time.Millisecond,
|
||||
},
|
||||
}
|
||||
|
||||
ex := NewDTSExtractor()
|
||||
|
||||
for _, sample := range sequence {
|
||||
dts, err := ex.Extract(sample.nalus, sample.pts)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sample.dts, dts)
|
||||
} {
|
||||
t.Run(ca.name, func(t *testing.T) {
|
||||
ex := NewDTSExtractor()
|
||||
for _, sample := range ca.sequence {
|
||||
dts, err := ex.Extract(sample.nalus, sample.pts)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sample.dts, dts)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -841,7 +841,7 @@ func (s SPS) Height() int {
|
||||
return int((2 - f) * (s.PicHeightInMbsMinus1 + 1) * 16)
|
||||
}
|
||||
|
||||
// FPS returns the frame per second of the video.
|
||||
// FPS returns the frames per second of the video.
|
||||
func (s SPS) FPS() float64 {
|
||||
if s.VUI == nil || s.VUI.TimingInfo == nil {
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user