def test_validate(self): vs = VideoSequence(1,10) s1 = Subregion(0, 0.1) vs.add_subregion(s1) self.assertTrue(vs.validate(Subregion(0.2, 0.3))) self.assertTrue(vs.validate(Subregion(0.4, 0.8))) self.assertTrue(vs.validate(Subregion(0.9, 1.0)))
def test_validate_fails_out_of_bounds(self): vs = VideoSequence(1,1) s = Subregion(0,1.1) with self.assertRaises(RuntimeError): vs.add_subregion(s) s = Subregion(0,2) s.fa = 1 s.fb = 2 with self.assertRaises(RuntimeError): vs.add_subregion(s)
def sequence_from_input_str(s, src_duration, src_frs): seq = VideoSequence(src_duration, src_frs) if not s: seq.subregions[0].skip = False return seq src_duration = str(datetime.timedelta(seconds=src_duration / 1000.0)) partition = list(src_duration.partition('.')) partition[-1] = partition[-1][:3] # keep secs.xxx... src_duration = ''.join(partition) s = re.sub(sr_ful_pattern, 'a=0,b={}'.format(src_duration), re.sub(sr_end_pattern, src_duration, s)) subs = re.split(':a', s) new_subs = [] if len(subs) > 1: for sub in subs: if not sub.startswith('a'): new_subs.append('a'+sub) else: new_subs.append(sub) subs = new_subs for sub in subs: match = re.match(sr_pattern, sub) if match: substr = str(sub) try: sub = Subregion( time_str_to_milliseconds(match.groupdict()['tm_a']), time_str_to_milliseconds(match.groupdict()['tm_b'])) except AttributeError as e: raise AttributeError("Bad subregion: {} ({})".format(substr, e)) target = match.groupdict()['target'] val = match.groupdict()['val'] if target == 'fps': val = rate_from_input_str(val, -1) elif target == 'dur': val = float(val)*1000.0 elif target == 'spd': val = float(val) setattr(sub, 'target_'+target, val) try: seq.add_subregion(sub) except ValueError as e: raise ValueError("Bad subregion: {} ({})".format(substr, e)) else: raise ValueError('Unknown subregion syntax: {}'.format(sub)) return seq
def sequence_from_str(duration, frames, string): # return a vid sequence from -s <subregion>:<subregion>... seq = VideoSequence(duration, frames) if string is None: return seq # check for bad separators # if there is a char before `a` that is not `:` like `,` def find_char(str, ch): idxs = [] for i, ltr in enumerate(str): if ltr == ch: idxs.append(i) return idxs idxs_of_a = find_char(string, 'a') for i in idxs_of_a: if i == 0: continue else: ch_before_a = string[i - 1] if ch_before_a != ':': msg = 'invalid separator `{}` at idx={}'.format(ch_before_a, i) raise ValueError(msg) # look for `:a` which is the start of a new subregion newsubstrs = [] substrs = string.split(':a') if len(substrs) > 1: # replace `a` character that was stripped when split for substr in substrs: if not substr.startswith('a'): newsubstrs.append('a' + substr) else: newsubstrs.append(substr) substrs = newsubstrs for substr in substrs: sub = None # has the full key if 'full' in substr: sub = sub_from_str_full_key(substr, duration) # has the end key elif 'end' in substr: sub = sub_from_str_end_key(substr, duration) else: sub = sub_from_str(substr) seq.add_subregion(sub) return seq
def test_add_subregion(self): vs = VideoSequence(1,4) self.assertEqual(len(vs.subregions), 0) vs.add_subregion(Subregion(0,0.1)) self.assertEqual(len(vs.subregions), 1) vs.add_subregion(Subregion(0.1,0.2)) self.assertEqual(len(vs.subregions), 2) vs.add_subregion(Subregion(0.2,0.3)) self.assertEqual(len(vs.subregions), 3) vs.add_subregion(Subregion(0.9,1)) self.assertEqual(len(vs.subregions), 4)
def sequence_from_input_str(s, src_dur, src_nfrs): seq = VideoSequence(src_dur, src_nfrs) if not s: return seq src_dur = str(datetime.timedelta(seconds=src_dur / 1000.0)) partition = list(src_dur.partition('.')) partition[-1] = partition[-1][:3] # keep secs.xxx... src_dur = ''.join(partition) s = re.sub(sr_ful_pattern, 'a=0,b={}'.format(src_dur), re.sub(sr_end_pattern, src_dur, s)) subs = re.split(':a', s) new_subs = [] if len(subs) > 1: for sub in subs: if not sub.startswith('a'): new_subs.append('a' + sub) else: new_subs.append(sub) subs = new_subs for sub in subs: match = re.match(sr_pattern, sub) if match: sub = Subregion( time_str_to_milliseconds(match.groupdict()['tm_a']), time_str_to_milliseconds(match.groupdict()['tm_b'])) target = match.groupdict()['target'] val = match.groupdict()['val'] if target == 'fps': val = rate_from_input_str(val, -1) elif target == 'dur': val = float(val) * 1000.0 elif target == 'spd': val = float(val) setattr(sub, 'target_' + target, val) seq.add_subregion(sub) else: raise RuntimeError return seq
def test_validate_fails_intersects(self): vs = VideoSequence(1,10) s1 = Subregion(0.1,0.2) s2 = Subregion(0.15,0.25) vs.add_subregion(s1) with self.assertRaises(RuntimeError): vs.add_subregion(s2) vs = VideoSequence(5,1) s1 = Subregion(1,1) s2 = Subregion(0,5) with self.assertRaises(RuntimeError): vs.add_subregion(s1) vs.add_subregion(s2) with self.assertRaises(RuntimeError): vs.add_subregion(s2) vs.add_subregion(s1)
def test_add_subregion_ordering(self): vs = VideoSequence(1,10) s1 = Subregion(0, 0.1) s2 = Subregion(0.3, 0.4) s3 = Subregion(0.4, 0.5) s4 = Subregion(0.5, 0.6) s5 = Subregion(0.9, 1) vs.add_subregion(s5) vs.add_subregion(s1) vs.add_subregion(s4) vs.add_subregion(s2) vs.add_subregion(s3) self.assertEqual(vs.subregions[0], s1) self.assertEqual(vs.subregions[1], s2) self.assertEqual(vs.subregions[2], s3) self.assertEqual(vs.subregions[3], s4) self.assertEqual(vs.subregions[4], s5)
def test_add_subregion(self): cnt_skip_subs = lambda x: \ len([s for s in x.subregions if s.skip]) cnt_usr_subs = lambda x: \ len(x.subregions) - cnt_skip_subs(x) vs = VideoSequence(1, 1) self.assertEqual(cnt_usr_subs(vs), 0) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0, 0.1)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 1) vs = VideoSequence(1, 1) vs.add_subregion(Subregion(0.9, 1)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 1) vs = VideoSequence(1, 1) vs.add_subregion(Subregion(0, 1)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 0) vs = VideoSequence(1, 2) vs.add_subregion(Subregion(0, 0.5)) vs.add_subregion(Subregion(0.5, 0.6)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 1) vs = VideoSequence(1, 2) vs.add_subregion(Subregion(0.5, 0.6)) vs.add_subregion(Subregion(0, 0.1)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 2) vs = VideoSequence(1, 3) vs.add_subregion(Subregion(0, 0.1)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0.9, 1)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0.66, 0.66)) self.assertEqual(cnt_usr_subs(vs), 3) self.assertEqual(cnt_skip_subs(vs), 2) vs = VideoSequence(1, 3) vs.add_subregion(Subregion(0.66, 0.66)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 2) vs.add_subregion(Subregion(0, 0.1)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 2) vs.add_subregion(Subregion(0.9, 1)) self.assertEqual(cnt_usr_subs(vs), 3) self.assertEqual(cnt_skip_subs(vs), 2) vs = VideoSequence(1, 4) vs.add_subregion(Subregion(0.25, 0.5)) vs.add_subregion(Subregion(0.5, 0.75)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 2) vs.add_subregion(Subregion(0, 0.25)) self.assertEqual(cnt_usr_subs(vs), 3) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0.75, 1)) self.assertEqual(cnt_usr_subs(vs), 4) self.assertEqual(cnt_skip_subs(vs), 0) vs = VideoSequence(1, 5) vs.add_subregion(Subregion(0.2, 0.4)) vs.add_subregion(Subregion(0.6, 0.8)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 3) vs.add_subregion(Subregion(0.4, 0.6)) self.assertEqual(cnt_usr_subs(vs), 3) self.assertEqual(cnt_skip_subs(vs), 2) vs.add_subregion(Subregion(0.8, 1)) self.assertEqual(cnt_usr_subs(vs), 4) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0, 0.2)) self.assertEqual(cnt_usr_subs(vs), 5) self.assertEqual(cnt_skip_subs(vs), 0)
def test_add_subregion(self): cnt_skip_subs = lambda x: \ len([s for s in x.subregions if s.skip]) cnt_usr_subs = lambda x: \ len(x.subregions) - cnt_skip_subs(x) vs = VideoSequence(1,1) self.assertEqual(cnt_usr_subs(vs), 0) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0,0.1)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 1) vs = VideoSequence(1,1) vs.add_subregion(Subregion(0.9,1)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 1) vs = VideoSequence(1,1) vs.add_subregion(Subregion(0,1)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 0) vs = VideoSequence(1,2) vs.add_subregion(Subregion(0,0.5)) vs.add_subregion(Subregion(0.5,0.6)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 1) vs = VideoSequence(1,2) vs.add_subregion(Subregion(0.5,0.6)) vs.add_subregion(Subregion(0,0.1)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 2) vs = VideoSequence(1,3) vs.add_subregion(Subregion(0,0.1)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0.9,1)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0.66,0.66)) self.assertEqual(cnt_usr_subs(vs), 3) self.assertEqual(cnt_skip_subs(vs), 2) vs = VideoSequence(1,3) vs.add_subregion(Subregion(0.66,0.66)) self.assertEqual(cnt_usr_subs(vs), 1) self.assertEqual(cnt_skip_subs(vs), 2) vs.add_subregion(Subregion(0,0.1)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 2) vs.add_subregion(Subregion(0.9,1)) self.assertEqual(cnt_usr_subs(vs), 3) self.assertEqual(cnt_skip_subs(vs), 2) vs = VideoSequence(1,4) vs.add_subregion(Subregion(0.25,0.5)) vs.add_subregion(Subregion(0.5,0.75)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 2) vs.add_subregion(Subregion(0,0.25)) self.assertEqual(cnt_usr_subs(vs), 3) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0.75,1)) self.assertEqual(cnt_usr_subs(vs), 4) self.assertEqual(cnt_skip_subs(vs), 0) vs = VideoSequence(1,5) vs.add_subregion(Subregion(0.2,0.4)) vs.add_subregion(Subregion(0.6,0.8)) self.assertEqual(cnt_usr_subs(vs), 2) self.assertEqual(cnt_skip_subs(vs), 3) vs.add_subregion(Subregion(0.4,0.6)) self.assertEqual(cnt_usr_subs(vs), 3) self.assertEqual(cnt_skip_subs(vs), 2) vs.add_subregion(Subregion(0.8,1)) self.assertEqual(cnt_usr_subs(vs), 4) self.assertEqual(cnt_skip_subs(vs), 1) vs.add_subregion(Subregion(0,0.2)) self.assertEqual(cnt_usr_subs(vs), 5) self.assertEqual(cnt_skip_subs(vs), 0)
def get_renderable_sequence(self): # this method will fill holes in the sequence with dummy subregions dur = self.vid_info['duration'] frs = self.vid_info['frames'] new_subregions = [] if self.sequence.subregions is None or \ len(self.sequence.subregions) == 0: # make a subregion from 0 to vid duration if there are no regions # in the video sequence. only the framerate could be changing fa, ta = (0, 0) fb, tb = (frs - 1, dur) s = RenderSubregion(ta, tb) s.fa = fa s.fb = fb s.fps = self.playback_rate s.dur = tb - ta s.spd = 1.0 setattr(s, 'trim', False) new_subregions.append(s) else: # create placeholder/dummy subregions that fill holes in the video # sequence where subregions were not explicity specified cut_points = set([]) # add start and end of video cutting points # (fr index, dur in milliseconds) cut_points.add((0, 0)) # frame 0 and time 0 cut_points.add((frs - 1, dur)) # last frame and end time # add current subregions for s in self.sequence.subregions: cut_points.add((s.fa, s.ta)) cut_points.add((s.fb, s.tb)) # sort them out cut_points = list(cut_points) cut_points = sorted(cut_points, key=lambda x: (x[0], x[1]), reverse=False) # make dummy regions to_make = len(cut_points) - 1 for x in range(0, to_make): fa, ta = cut_points[x] # get start of region fb, tb = cut_points[x + 1] # get end sub_for_range = None # matching subregion in range # look for matching subregion for s in self.sequence.subregions: if s.fa == fa and s.fb == fb: sub_for_range = s setattr(s, 'trim', False) # found it, won't trim it break # if subregion isnt found, make a dummy region if sub_for_range is None: s = RenderSubregion(ta, tb) s.fa = fa s.fb = fb s.fps = self.playback_rate s.dur = tb - ta s.spd = 1.0 sub_for_range = s setattr(s, 'trim', self.trim) new_subregions.append(sub_for_range) # create a new video sequence w/ original plus dummy regions # they will automatically be validated and sorted as they are added in seq = VideoSequence(dur, frs) for s in new_subregions: seq.add_subregion(s) return seq