container/mts: BytesForPTSInterval renamed to TrimToPTSRange, and now returns a Clip

It was concluded that it would be more useful if a function that provided a data segment from
the original clip just provided a new Clip, i.e. useful things like PTS and meta is still
available in the segment. So, BytesForPTSInterval was renamed to TrimToPTSRange and now
provides a Clip. The test for this function was updated accordingly.
This commit is contained in:
Saxon 2019-06-15 02:04:26 +09:30
parent eff69e87ce
commit ceee163b74
2 changed files with 28 additions and 20 deletions

View File

@ -8,8 +8,11 @@ import (
"github.com/Comcast/gots/pes" "github.com/Comcast/gots/pes"
) )
// TODO: write function for getting subslice of mpegts for meta interval
// Extract extracts the media, PTS, stream ID and meta for an MPEG-TS clip given // Extract extracts the media, PTS, stream ID and meta for an MPEG-TS clip given
// by p, and returns as a Clip. The MPEG-TS must contain only complete packets. // by p, and returns as a Clip. The MPEG-TS must contain only complete packets.
// The resultant data is a copy of the original.
func Extract(p []byte) (*Clip, error) { func Extract(p []byte) (*Clip, error) {
l := len(p) l := len(p)
// Check that clip is divisible by 188, i.e. contains a series of full MPEG-TS clips. // Check that clip is divisible by 188, i.e. contains a series of full MPEG-TS clips.
@ -127,11 +130,12 @@ var (
errPTSRange = errors.New("PTS interval invalid") errPTSRange = errors.New("PTS interval invalid")
) )
// BytesForPTSInterval returns the media data between PTS' from and to. If from // TrimToPTSRange returns the sub Clip in PTS range defined by from and to.
// sits between two PTS, the Frame posessing lower PTS will be considered the start. // The first Frame in the new Clip will be the Frame for which from corresponds
// The Frame before the Frame corresponding to to will be considered the final // exactly with Frame.PTS, or the Frame in which from lies within. The final
// Frame. // Frame in the Clip will be the previous of that for which to coincides with,
func (c *Clip) BytesForPTSInterval(from, to uint64) ([]byte, error) { // or the Frame that to lies within.
func (c *Clip) TrimToPTSRange(from, to uint64) (*Clip, error) {
// First check that the interval makes sense. // First check that the interval makes sense.
if from >= to { if from >= to {
return nil, errPTSRange return nil, errPTSRange
@ -139,7 +143,7 @@ func (c *Clip) BytesForPTSInterval(from, to uint64) ([]byte, error) {
// Use binary search to find 'from'. // Use binary search to find 'from'.
n := len(c.frames) - 1 n := len(c.frames) - 1
idx := sort.Search( startFrameIdx := sort.Search(
n, n,
func(i int) bool { func(i int) bool {
if from < c.frames[i+1].PTS { if from < c.frames[i+1].PTS {
@ -148,17 +152,17 @@ func (c *Clip) BytesForPTSInterval(from, to uint64) ([]byte, error) {
return false return false
}, },
) )
if idx == n { if startFrameIdx == n {
return nil, errPTSLowerBound return nil, errPTSLowerBound
} }
// Now get the start index for the backing slice from this Frame. // Now get the start index for the backing slice from this Frame.
start := c.frames[idx].idx startBackingIdx := c.frames[startFrameIdx].idx
// Now use binary search again to find 'to'. // Now use binary search again to find 'to'.
off := idx + 1 off := startFrameIdx + 1
n = n - (off) n = n - (off)
idx = sort.Search( endFrameIdx := sort.Search(
n, n,
func(i int) bool { func(i int) bool {
if to <= c.frames[i+off].PTS { if to <= c.frames[i+off].PTS {
@ -167,14 +171,18 @@ func (c *Clip) BytesForPTSInterval(from, to uint64) ([]byte, error) {
return false return false
}, },
) )
if idx == n { if endFrameIdx == n {
return nil, errPTSUpperBound return nil, errPTSUpperBound
} }
// Now get the end index for the backing slice from this Frame, and return // Now get the end index for the backing slice from this Frame.
// segment from backing slice corresponding to start and end. endBackingIdx := c.frames[endFrameIdx+off-1].idx
end := c.frames[idx+off-1].idx
return c.backing[start : end+len(c.frames[idx+off].Media)], nil // Now return a new clip. NB: data is not copied.
return &Clip{
frames: c.frames[startFrameIdx : endFrameIdx+1],
backing: c.backing[startBackingIdx : endBackingIdx+len(c.frames[endFrameIdx+off].Media)],
}, nil
} }
// Errors that maybe returned from BytesForMetaInterval. // Errors that maybe returned from BytesForMetaInterval.

View File

@ -225,9 +225,9 @@ func genFrames(n, min, max int) [][]byte {
return frames return frames
} }
// TestBytesForPTSInterval checks that BytesForPTSInterval can correctly return // TestTrimToPTSRange checks that Clip.TrimToPTSRange will correctly return a
// a slice of media data corresponding to a given PTS interval. // sub Clip of the given PTS range.
func TestBytesForPTSInterval(t *testing.T) { func TestTrimToPTSRange(t *testing.T) {
const ( const (
numOfTestFrames = 10 numOfTestFrames = 10
ptsInterval = 4 ptsInterval = 4
@ -298,7 +298,7 @@ func TestBytesForPTSInterval(t *testing.T) {
// Run tests. // Run tests.
for i, test := range tests { for i, test := range tests {
got, err := clip.BytesForPTSInterval(test.from, test.to) got, err := clip.TrimToPTSRange(test.from, test.to)
// First check the error. // First check the error.
if err != nil && err != test.err { if err != nil && err != test.err {
@ -310,7 +310,7 @@ func TestBytesForPTSInterval(t *testing.T) {
} }
// Now check data. // Now check data.
if test.err == nil && !bytes.Equal(test.expect, got) { if test.err == nil && !bytes.Equal(test.expect, got.Bytes()) {
t.Errorf("did not get expected data for test: %v\n Got: %v\n, Want: %v\n", i, got, test.expect) t.Errorf("did not get expected data for test: %v\n Got: %v\n, Want: %v\n", i, got, test.expect)
} }
} }