container/mts: wrote BytesForPTSInterval

This function will return the media between two provided PTS. Binary search has been used to
find the corresponding Frames to 'from' and 'to'.
This commit is contained in:
Saxon 2019-06-14 01:09:55 +09:30
parent 12c205d75f
commit 70eb8193cb
1 changed files with 54 additions and 0 deletions

View File

@ -2,6 +2,7 @@ package mts
import (
"errors"
"sort"
"github.com/Comcast/gots/packet"
"github.com/Comcast/gots/pes"
@ -76,6 +77,7 @@ func Extract(p []byte) (*Clip, error) {
// and can add this data to the frame pertaining to the finish frame.
if !firstPUSI {
clip.frames[len(clip.frames)-2].Media = clip.backing[frameStart:lenOfFrame]
clip.frames[len(clip.frames)-2].idx = frameStart
frameStart = lenOfFrame
}
firstPUSI = false
@ -90,6 +92,7 @@ func Extract(p []byte) (*Clip, error) {
}
// We're finished up with media frames, so give the final Frame it's data.
clip.frames[len(clip.frames)-1].Media = clip.backing[frameStart:lenOfFrame]
clip.frames[len(clip.frames)-1].idx = frameStart
return clip, nil
}
@ -105,6 +108,7 @@ type Frame struct {
PTS uint64 // PTS from PES packet (this gives time relative from start of stream).
ID uint8 // StreamID from the PES packet, identifying media codec.
Meta map[string]string // Contains metadata from PMT relevant to this frame.
idx int // Index in the backing slice.
}
// Bytes returns the concatentated media bytes from each frame in the Clip c.
@ -114,3 +118,53 @@ func (c *Clip) Bytes() []byte {
}
return c.backing
}
// BytesForPTSInterval returns the media data between PTS' from and to. If from
// sits between two PTS, the Frame posessing lower PTS will be considered the start.
// The Frame before the Frame corresponding to to will be considered the final
// Frame.
func (c *Clip) BytesForPTSInterval(from, to uint64) ([]byte, error) {
// First check that the interval makes sense.
if from >= to {
return nil, errors.New("PTS interval is invalid")
}
// Use binary search to find 'from'.
n := len(c.frames)
idx := sort.Search(
n,
func(i int) bool {
if from >= c.frames[i].PTS && from < c.frames[i].PTS {
return true
}
return false
},
)
if idx == n {
return nil, errors.New("'from' cannot be found")
}
// Now get the start index for the backing slice from this Frame.
start := c.frames[idx].idx
// Now use binary search again to find 'to'.
off := idx + 1
n = n - (off)
idx = sort.Search(
n,
func(i int) bool {
if to >= c.frames[i+off].PTS && from < c.frames[i+off].PTS {
return true
}
return false
},
)
if idx == n {
return nil, errors.New("'to' cannot be found")
}
// Now get the end index for the backing slice from this Frame, and return
// segment from backing slice corresponding to start and end.
end := c.frames[idx+off].idx
return c.backing[start:end], nil
}