def checkForContinuousVideo(videoDir, matchedFileList, dumpSegments): previousFileInfo = {} videoSegments = [] currentVideoSegment = makeNewVideoSegment(videoDir, matchedFileList[0]) videoSegments.append(currentVideoSegment) for f in matchedFileList: xmlMetafilePath = "%s/%s.xml" % (videoDir, f) docroot = ET.parse(xmlMetafilePath).getroot() endTimecode = Timecode(CINEDEK_FRAME_RATE, docroot.find("endTimecode").text) startTimecode = Timecode(CINEDEK_FRAME_RATE, docroot.find("startTimecode").text) if previousFileInfo: prevEndFrameCount = previousFileInfo["endTimecode"].frames currentStartFrameCount = startTimecode.frames if (currentStartFrameCount - prevEndFrameCount) != 1: if currentStartFrameCount < prevEndFrameCount: print "Overlapping video detected!" print " %s overlaps %s" % (previousFileInfo["filename"], f) else: print "Gap detected (%d frames)!" % (currentStartFrameCount - prevEndFrameCount) print " Start new segment for:", f currentVideoSegment = makeNewVideoSegment(videoDir, f) videoSegments.append(currentVideoSegment) currentVideoSegment.fileList.append("%s.%s" % (f, VIDEO_FILE_EXTENSION)) currentVideoSegment.updateEndtimeFromMetadata(docroot) previousFileInfo["endTimecode"] = endTimecode previousFileInfo["filename"] = f if dumpSegments: return videoSegments else: return None
def grab(target: str, tc: str): """ :param target: Path to search for media files :param tc: Desired timecode of stills """ clips, camera = get_clips_from_path(Path(target)) looking_for = Timecode(FPS, tc) print(looking_for) for clip in clips: if clip.suffix.lower() == '.mov': # Quick way to control for only Alexa quicktimes stats = get_media_info(clip) start_tc_frame = Timecode(FPS, stats['Start TC']) duration_frames = Timecode(FPS, start_timecode=None, frames=stats['Duration-Frames']) print('Start frame is: ' + str(start_tc_frame)) print('Duration frames are: ' + str(duration_frames)) end_frame = start_tc_frame + duration_frames print('End frame is: ' + str(end_frame.frames)) print('Looking for frame: ' + str(looking_for.frames)) if looking_for.frames in range(start_tc_frame.frames, end_frame.frames): abs_time = looking_for - start_tc_frame abs_time.set_fractional(True) print('Asking ffmpeg for frame: ' + str(abs_time)) make_thumb(clip, TEST_OUTPUT, abs_time, stats) else: print('Cannot find requested timecode in: ' + clip.name) elif clip.suffix.lower() == '.mp4': # Deal with A7s shit here elif clip.suffix.lower() == '.mxf':
def test_repr_overload(self): timeobj = Timecode('24', '01:00:00:00') self.assertEqual('01:00:00:00', timeobj.__repr__()) timeobj = Timecode('23.98', '20:00:00:00') self.assertEqual('20:00:00:00', timeobj.__repr__()) timeobj = Timecode('29.97', '00:09:00;00') self.assertEqual('00:08:59;28', timeobj.__repr__()) timeobj = Timecode('30', '00:10:00:00') self.assertEqual('00:10:00:00', timeobj.__repr__()) timeobj = Timecode('60', '00:00:09:00') self.assertEqual('00:00:09:00', timeobj.__repr__()) timeobj = Timecode('59.94', '00:00:20;00') self.assertEqual('00:00:20;00', timeobj.__repr__()) timeobj = Timecode('59.94', '00:00:20;00') self.assertNotEqual('00:00:20:00', timeobj.__repr__()) timeobj = Timecode('ms', '00:00:00.900') self.assertEqual('00:00:00.900', timeobj.__repr__()) timeobj = Timecode('ms', '00:00:00.900') self.assertNotEqual('00:00:00:900', timeobj.__repr__()) timeobj = Timecode('24', frames=49) self.assertEqual('00:00:02:00', timeobj.__repr__())
def make_subtitle(comps, name, padding): '''writes out a subtitle file for the supercut''' fpses = {} out = '' rec_in = 0 print("[+] Creating subtitle file.") for index, comp in enumerate(comps): if comp['file'] not in fpses: fpses[comp['file']] = get_fps(comp['file']) fps = fpses[comp['file']] time_in = comp['start'] time_out = comp['end'] duration = time_out - time_in rec_out = rec_in + duration #timestamp['duration'] filename = os.path.basename(comp['file']) rec_in_timecode = str(Timecode(fps, start_seconds=rec_in + padding)) rec_out_timecode = str(Timecode(fps, start_seconds=rec_out)) rec_in_srt_format = rec_in_timecode[:8] + ',' + rec_in_timecode[9:] rec_out_srt_format = rec_out_timecode[:8] + ',' + rec_out_timecode[9:] out += '{}\n{} --> {}\n<i>{}</i>\n{}\n\n'.format( index + 1, rec_in_srt_format, rec_out_srt_format, filename, comp['line']) rec_in = rec_out with open(os.path.splitext(name)[0] + '.srt', 'w') as outfile: outfile.write(out)
def make_edl_segment(n, time_in, time_out, rec_in, rec_out, full_name, filename, fps=25): reel = full_name if len(full_name) > 7: reel = full_name[0:7] template = '{} {} AA/V C {} {} {} {}\n* FROM CLIP NAME: {}\n* COMMENT: \n FINAL CUT PRO REEL: {} REPLACED BY: {}\n\n' # print time_in, time_out, rec_in, rec_out # print Timecode(fps, start_seconds=time_in), Timecode(fps, start_seconds=time_out), Timecode(fps, start_seconds=rec_in), Timecode(fps, start_seconds=rec_out) # # print '' out = template.format(n, full_name, Timecode(fps, start_seconds=time_in), Timecode(fps, start_seconds=time_out), Timecode(fps, start_seconds=rec_in), Timecode(fps, start_seconds=rec_out), filename, full_name, reel) return out
def make_caption_data(video_element_name, caption_path, timecodes, duration, fps, punct, mode, segmenter): start, end = Timecode(fps, timecodes[0]), Timecode(fps, timecodes[1]) captions = webvtt.read(caption_path) captions[1].start = captions[0].start captions = captions[1:] caption_dict_list, joined_sentence = make_caption_dict_list( captions, fps, start, end, mode) sentences = segement_sentences(joined_sentence, segmenter, punct) if len(caption_dict_list) > 0: timestamps = make_timestamps(caption_dict_list, sentences, mode) try: assert len(timestamps) == len( sentences ), f'timestamps:{len(timestamps)} sentences:{len(sentences)}' except AssertionError as err: print('AssertionError:', err) annotation = { video_element_name: { 'duration': duration, 'timestamps': timestamps, 'sentences': sentences } } return annotation else: return {}
def test_24_hour_limit_in_24fps(self): """testing if the timecode will loop back to 00:00:00:00 after 24 hours in 24 fps """ tc = Timecode('24', '00:00:00:21') tc2 = Timecode('24', '23:59:59:23') self.assertEqual('00:00:00:21', (tc + tc2).__str__()) self.assertEqual('02:00:00:00', (tc2 + 159840001).__str__())
def get_comment_duration(tc1_in, tc2_in, fps): tc1 = Timecode(fps, tc1_in) tc2 = Timecode(fps, tc2_in) tc1a = tc1 + Timecode(fps, "00:00:00:00") tc2a = tc2 + Timecode(fps, "00:00:00:00") duration_frames = str((tc2 - tc1).frames) durations = {"tc1": str(tc1), "tc2": str(tc2), "tc1a": str(tc1a), "tc2a": str(tc2a), "duration_frames": duration_frames} return durations
def test_setting_frame_rate_to_2997_forces_drop_frame(self): """testing if setting the frame rate to 29.97 forces the dropframe to True """ tc = Timecode('29.97') self.assertTrue(tc.drop_frame) tc = Timecode('29.97') self.assertTrue(tc.drop_frame)
def __init__(self, start, end, line, fps): self.start = Timecode(fps, start) self.end = Timecode(fps, end) self.delta: Timecode = self.end - self.start self.num_frames = self.delta.frames if line == '': self.line = [line] else: self.line = re.split(r'\\n|\\N', line)
def test_setting_frame_rate_to_ms_or_1000_forces_drop_frame(self): """testing if setting the frame rate to 59.94 forces the dropframe to True """ tc = Timecode('ms') self.assertTrue(tc.ms_frame) tc = Timecode('1000') self.assertTrue(tc.ms_frame)
def test_le_overload(self): tc1 = Timecode(24, '00:00:00:00') tc2 = Timecode(24, '00:00:00:00') tc3 = Timecode(24, '00:00:00:01') self.assertTrue(tc1 == tc2) self.assertTrue(tc1 <= tc2) self.assertTrue(tc2 <= tc3) self.assertFalse(tc2 >= tc3)
def test_rational_frame_delimiter(self): tc = Timecode('24000/1000', frames=1) self.assertFalse(';' in tc.__repr__()) tc = Timecode('24000/1001', frames=1) self.assertFalse(';' in tc.__repr__()) tc = Timecode('30000/1001', frames=1) self.assertTrue(';' in tc.__repr__())
def test_setting_frame_rate_to_5994_forces_drop_frame(self): """testing if setting the frame rate to 59.94 forces the dropframe to True """ tc = Timecode('59.94') self.assertTrue(tc.drop_frame) tc = Timecode('59.94') self.assertTrue(tc.drop_frame)
def test_add_with_two_different_frame_rates(self): """testing if the resultant object will have the left sides frame rate when two timecodes with different frame rates are added together """ tc1 = Timecode('29.97', '00:00:00;00') tc2 = Timecode('24', '00:00:00:10') tc3 = tc1 + tc2 self.assertEqual('29.97', tc3.framerate) self.assertEqual(12, tc3.frames) self.assertEqual('00:00:00;11', tc3)
def to_edl(self): """Returns an edl.List instance equivalent of this Sequence instance """ from edl import List, Event from timecode import Timecode l = List(self.timebase) l.title = self.name # convert clips to events if not self.media: raise RuntimeError( 'Can not run %(class)s.to_edl() without a Media instance, ' 'please add a Media instance to this %(class)s instance.' % {'class': self.__class__.__name__}) video = self.media.video if video is not None: i = 0 for track in video.tracks: for clip in track.clips: i += 1 e = Event({}) e.num = '%06i' % i e.clip_name = clip.id e.reel = clip.name e.track = 'V' if clip.type == 'Video' else 'A' e.tr_code = 'C' # TODO: for now use C (Cut) later on # expand it to add other transition codes src_start_tc = Timecode(self.timebase, frames=clip.in_ + 1) # 1 frame after last frame shown src_end_tc = Timecode(self.timebase, frames=clip.out + 1) e.src_start_tc = str(src_start_tc) e.src_end_tc = str(src_end_tc) rec_start_tc = Timecode(self.timebase, frames=clip.start + 1) # 1 frame after last frame shown rec_end_tc = Timecode(self.timebase, frames=clip.end + 1) e.rec_start_tc = str(rec_start_tc) e.rec_end_tc = str(rec_end_tc) source_file = clip.file.pathurl.replace('file://', '') e.source_file = source_file e.comments.extend([ '* FROM CLIP NAME: %s' % clip.name, '* SOURCE FILE: %s' % source_file ]) l.append(e) return l
def Convert_toTC(TC, FPS): global status_text if str(TC) == str(neg_error) or TC == "": print() else: tc3 = Timecode(FPS, start_timecode=None, frames=int(TC)) + Timecode( FPS, "00:00:00:00") # tc3 = tc1.frame_number itm['Result']({"Text": tc3}) status_text = str(tc3)
def test_gt_overload(self): tc1 = Timecode(24, '00:00:00:00') tc2 = Timecode(24, '00:00:00:00') tc3 = Timecode(24, '00:00:00:01') tc4 = Timecode(24, '00:00:01.100') tc5 = Timecode(24, '00:00:01.200') self.assertFalse(tc1 > tc2) self.assertFalse(tc2 > tc2) self.assertTrue(tc3 > tc2) self.assertTrue(tc5 > tc4)
def test_fps_compatibility(self): a = Timecode('12:34:56:12', fps=25) b = Timecode('12:34:56:12', fps=50) def add(a1, a2): return a1 + a2 def sub(a1, a2): return a1 - a2 self.assertRaises(Timecode.FPSMismatch, add, a, b) self.assertRaises(Timecode.FPSMismatch, sub, a, b)
def test_math(self): a = Timecode('12:34:56:12', fps=25) b = Timecode('00:00:01:10', fps=25) c = a + b self.assertEqual(c, Timecode('12:34:57:22', fps=25)) d = a - b self.assertEqual(d, Timecode('12:34:55:02', fps=25))
def test_ge_overload(self): tc1 = Timecode(24, '00:00:00:00') tc2 = Timecode(24, '00:00:00:00') tc3 = Timecode(24, '00:00:00:01') tc4 = Timecode(24, '00:00:01.100') tc5 = Timecode(24, '00:00:01.200') self.assertTrue(tc1 == tc2) self.assertTrue(tc1 >= tc2) self.assertTrue(tc3 >= tc2) self.assertFalse(tc2 >= tc3) self.assertTrue(tc4 <= tc5)
def test_ms_vs_fraction_frames(self): tc1 = Timecode('ms', '00:00:00.040') self.assertTrue(tc1.ms_frame) self.assertFalse(tc1.fraction_frame) tc2 = Timecode(24, '00:00:00.042') self.assertTrue(tc2.fraction_frame) self.assertFalse(tc2.ms_frame) self.assertNotEqual(tc1, tc2) self.assertEqual(tc1.frame_number, 40) self.assertEqual(tc2.frame_number, 1)
def sixIndexSplitter(splitLine): splitLine = re.split(r'\s{2,}', splitter) dstIn = splitTimes[2] dstOut = splitTimes[3] dstOutSplit = dstOut.split("'") # Separates timecode from '] at end dstOut = dstOutSplit[0] # isolates timecode into dstOut variable dstIn = Timecode('25', dstIn) dstOut = Timecode('25', dstOut) srcDur = dstOut - dstIn del splitLine[0] splitLine.insert(0, num) del splitLine[-1] splitLine.append(str(srcDur)) finalFileWriter.writerow(splitLine)
def __init__(self, edit: pycmx.Edit, timecode_rate: int = 24): self.source_file = edit.source_file self.source_name = edit.source self.frame_rate = int(timecode_rate) self.source_in = Timecode(framerate=timecode_rate, start_timecode=edit.source_in).frames self.source_out = Timecode(framerate=timecode_rate, start_timecode=edit.source_out).frames self.record_in = Timecode(framerate=timecode_rate, start_timecode=edit.record_in).frames self.record_out = Timecode(framerate=timecode_rate, start_timecode=edit.record_out).frames self.channels = edit.channels self.clip_name = edit.clip_name
def test_tc_to_frame_test_in_2997(self): """testing if timecode to frame conversion is ok in 2997 """ tc = Timecode('29.97', '00:00:00;00') self.assertEqual(tc.frames, 1) tc = Timecode('29.97', '00:00:00;21') self.assertEqual(tc.frames, 22) tc = Timecode('29.97', '00:00:00;29') self.assertEqual(tc.frames, 30) tc = Timecode('29.97', '00:00:00;60') self.assertEqual(tc.frames, 61) tc = Timecode('29.97', '00:00:01;00') self.assertEqual(tc.frames, 31) tc = Timecode('29.97', '00:00:10;00') self.assertEqual(tc.frames, 301) # test with non existing timecodes tc = Timecode('29.97', '00:01:00;00') self.assertEqual(1799, tc.frames) self.assertEqual('00:00:59;28', tc.__str__()) # test the limit tc = Timecode('29.97', '23:59:59;29') self.assertEqual(2589408, tc.frames)
def handleFootageImport(self, files=[]): if not files: files = nuke.getFilename('Import footage', pattern=' '.join(IngestPanel.FOOTAGE_FORMATS), multiple=True) if not files: return for file in files: if file in self.footage: return self.footage.append(file) self.ui.LST_files.addItem(file) read = nuke.nodes.Read() read['file'].fromUserText(file) fps = self.ui.CMB_fps.currentText() viewerNode = nuke.activeViewer().node() viewerStart, viewerEnd = viewerNode.knob('frame_range').value().split('-') viewerNode.knob('frame_range').setValue('0-{}'.format(viewerEnd)) # Set viewer so start frame is 0 nuke.activeViewer().frameControl(-6) # Set it so the viewer is actually at 0 prior to querying the timecode metadata frameOffset = Timecode(fps, read.metadata().get('r3d/absolute_time_code', '00:00:00:00')).frame_number self.reads[file] = (read, frameOffset)
def plot_multi_vmaf_timegraph(output_path, frame_nums, baseline_frame_scores, variant_list, target_bitrate, source_duration, fps, test_item='bitrate'): timecode = Timecode(fps, '00:00:00:00') title = " Effect of Bitrate Changes on VMAF over Asset Duration" plt.suptitle(title, fontsize=14, color='blue') plt.title("Blue line is VMAF/time of existing VOD transcode (4sec GOPs). Gray lines are quality/time for 2sec GOPs at various bitrates", fontsize=7, color='black') upper = max(baseline_frame_scores) lower = min(baseline_frame_scores) higher_bitrate_scores = [variant['vmaf_frame_scores'] for variant in variant_list if variant[test_item] > target_bitrate] lower_bitrate_scores = [variant['vmaf_frame_scores'] for variant in variant_list if variant[test_item] < target_bitrate] # generate lighter lineshades higher_lineshades = np.linspace(0.7, 0.9, len(higher_bitrate_scores)) for idx, frame_scores in enumerate(higher_bitrate_scores): upper = max(upper, max(frame_scores)) lower = min(lower, min(frame_scores)) plt.plot(frame_nums, frame_scores, str(higher_lineshades[idx])) lower_lineshades = np.linspace(0.9, 0.7, len(lower_bitrate_scores)) for idx, frame_scores in enumerate(lower_bitrate_scores): upper = max(upper, max(frame_scores)) lower = min(lower, min(frame_scores)) # plt.plot(frame_nums, frame_scores, str(1 - (0.1 * (1 + idx)))) plt.plot(frame_nums, frame_scores, str(lower_lineshades[idx])) plt.plot(frame_nums, baseline_frame_scores) # generate major tics based on evenly divided time chosen_frames = np.linspace(0, len(frame_nums) - 1, 20) ticframes = [frame_nums[int(i)] for i in chosen_frames] ticlabels = [timecode.tc_to_string( *timecode.frames_to_tc(ticframe)) for ticframe in ticframes] plt.xticks(ticframes, ticlabels, rotation='vertical') ax = plt.axes() # style = dict(size=10, color='gray') # # label the valleys # for idx, lowval in enumerate(lowest_values): # ax.text(lowval, frame_scores[lowval] - 5, str(idx + 1), **style) ax.set_xticks(ticframes, minor=True) ax.grid() plt.ylabel('vmaf score') plt.ylim(lower, upper) plt.xlabel('time') plt.subplots_adjust(bottom=0.3) plt.gcf().set_size_inches(15, 5) plt.savefig(output_path) plt.clf()
def plot_vmaf_graph(output_path, frame_nums, frame_scores, source_duration, lowest_values, fps, title=""): timecode = Timecode(fps, '00:00:00:00') plt.title(title) # generate major tics based on evenly divided time chosen_frames = np.linspace(0, len(frame_nums) - 1, 20) ticframes = [frame_nums[int(i)] for i in chosen_frames] ticlabels = [timecode.tc_to_string( *timecode.frames_to_tc(ticframe)) for ticframe in ticframes] plt.xticks(ticframes, ticlabels, rotation='vertical') plt.plot(frame_nums, frame_scores) ax = plt.axes() if lowest_values != None: style = dict(size=10, color='gray') # label the valleys for idx, lowval in enumerate(lowest_values): ax.text(lowval, frame_scores[lowval] - 5, str(idx + 1), **style) ax.set_xticks(ticframes, minor=True) ax.grid() plt.ylabel('vmaf score') plt.ylim(0, 100) plt.xlabel('time') plt.subplots_adjust(bottom=0.3) plt.gcf().set_size_inches(9, 5) plt.savefig(output_path) plt.clf()
def from_plist(data, framerate_string='29.97'): timecode = Timecode(framerate_string) timecode.drop_frame = False events = [] for e in data.values(): if 'Timecode' in e: # convert iCoder-style timecode to frame number timecode.set_timecode('{}:{}:{}:{}'.format( e['Timecode']['Hour'], e['Timecode']['Minute'], e['Timecode']['Second'], e['Timecode']['Frame']) ) e['Frame'] = timecode.frames - 1 has_offset = True # by assumption; we don't know if the timecode of the first frame is 00:00:00:00 else: has_offset = False events.append( Event(trial=e['Trial'], status=e['Trial Status'] in ('on', True), response=e['Type'], frame=e['Frame'], has_offset=has_offset) ) return Events(events)
def mtc_decode(mtc_bytes): rhh, mins, secs, frs = mtc_bytes rateflag = rhh >> 5 hrs = rhh & 31 fps = ['24', '25', '29.97', '30'][rateflag] total_frames = int(frs + float(fps) * (secs + mins * 60 + hrs * 60 * 60)) return Timecode(fps, frames=total_frames)