container/mts: added Clip.SegmentForMeta and accompanying testing.

Added a function to segment a Clip into sub Clips that have a consistent meta key and value.
Also added testing for this method.
This commit is contained in:
Saxon 2019-06-17 20:05:08 +09:30
parent 74992aee19
commit b42510ae22
3 changed files with 128 additions and 1 deletions

View File

@ -362,7 +362,7 @@ func TestSegmentForMeta(t *testing.T) {
metaVals: [nPSI]string{"1", "2", val, val, val, "", "3", val, val, "4"},
expectIdxs: []rng{
scale(2, 5),
scale(2, 5),
scale(7, 9),
},
},
{

View File

@ -226,3 +226,56 @@ func (c *Clip) TrimToMetaRange(key, from, to string) (*Clip, error) {
}
return nil, errMetaLowerBound
}
// SegmentForMeta segments sequences of frames within c possesing meta described
// by key and val and are appended to a []Clip which is subsequently returned.
func (c *Clip) SegmentForMeta(key, val string) []Clip {
var (
segmenting bool // If true we are currently in a segment corresponsing to given meta.
res []Clip // The resultant [][]Clip holding the segments.
start int // The start index of the current segment.
)
// Go through frames of clip.
for i, frame := range c.frames {
// If there is no meta (meta = nil) and we are segmenting, then append the
// current segment to res.
if frame.Meta == nil {
if segmenting {
res = appendSegment(res, c, start, i)
segmenting = false
}
continue
}
// If we've got the meta of interest in current frame and we're not
// segmenting, set this i as start and set segmenting true. If we don't
// have the meta of interest and we are segmenting then we
// want to stop and append the segment to res.
if frame.Meta[key] == val && !segmenting {
start = i
segmenting = true
} else if frame.Meta[key] != val && segmenting {
res = appendSegment(res, c, start, i)
segmenting = false
}
}
// We've reached the end of the entire clip so if we're segmenting we need
// to append current segment to res.
if segmenting {
res = appendSegment(res, c, start, len(c.frames))
}
return res
}
// appendSegment is a helper function used by Clip.SegmentForMeta to append a
// clip to a []Clip.
func appendSegment(segs []Clip, c *Clip, start, end int) []Clip {
return append(segs, Clip{
frames: c.frames[start:end],
backing: c.backing[c.frames[start].idx : c.frames[end-1].idx+len(c.frames[end-1].Media)],
},
)
}

View File

@ -399,3 +399,77 @@ func TestClipTrimToMetaRange(t *testing.T) {
}
}
}
// TestClipSegmentForMeta checks that Clip.SegmentForMeta correctly returns
// segments from a clip with consistent meta defined by a key and value.
func TestClipSegmentForMeta(t *testing.T) {
const (
nFrames = 10 // The number of test frames we want to create.
fSize = 3 // The size of the frame media.
key = "n" // Meta key we will use.
val = "*" // The meta val of interest.
)
tests := []struct {
metaVals []string // These will be the meta vals each frame has.
fIndices []rng // These are the indices of the segments of interest.
}{
{
metaVals: []string{"1", "2", "*", "*", "*", "3", "*", "*", "4", "5"},
fIndices: []rng{{2, 5}, {6, 8}},
},
{
metaVals: []string{"1", "2", "*", "*", "*", "", "*", "*", "4", "5"},
fIndices: []rng{{2, 5}, {6, 8}},
},
{
metaVals: []string{"1", "2", "*", "*", "*", "3", "4", "5", "*", "*"},
fIndices: []rng{{2, 5}, {8, nFrames}},
},
{
metaVals: []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"},
fIndices: nil,
},
}
// Run the tests.
for testn, test := range tests {
clip := &Clip{}
// Generate test frames.
for i := 0; i < nFrames; i++ {
clip.backing = append(clip.backing, []byte{byte(i), byte(i), byte(i)}...)
clip.frames = append(
clip.frames,
Frame{
Media: clip.backing[i*fSize : (i+1)*fSize],
idx: i * fSize,
Meta: map[string]string{
key: test.metaVals[i],
},
},
)
}
// Use function we're testing to get segments.
got := clip.SegmentForMeta(key, val)
// Now get expected segments using indices defined in the test.
var want []Clip
for _, indices := range test.fIndices {
// Calculate the indices for the backing array from the original clip.
backStart := clip.frames[indices.start].idx
backEnd := clip.frames[indices.end-1].idx + len(clip.frames[indices.end-1].Media)
// Use calculated indices to create Clip for current expected segment.
want = append(want, Clip{
frames: clip.frames[indices.start:indices.end],
backing: clip.backing[backStart:backEnd],
})
}
if !reflect.DeepEqual(got, want) {
t.Errorf("did not get expected result for test %v\nGot: %v\nWant: %v\n", testn, got, want)
}
}
}