diff --git a/mvsfunc.py b/mvsfunc.py index fdd8406..660f3b7 100644 --- a/mvsfunc.py +++ b/mvsfunc.py @@ -1,6 +1,6 @@ ################################################################################################################################ ## mvsfunc - mawen1250's VapourSynth functions -## 2016.04 +## 2016.07 ################################################################################################################################ ## Requirments: ## fmtconv @@ -11,6 +11,7 @@ ## ToRGB ## ToYUV ## BM3D +## VFRSplice ################################################################################################################################ ## Runtime functions: ## PlaneStatistics @@ -1090,6 +1091,100 @@ def BM3D(input, sigma=None, radius1=None, radius2=None, profile1=None, profile2= ################################################################################################################################ +################################################################################################################################ +## Main function: VFRSplice() +################################################################################################################################ +## Splice multiple clips with different frame rate, and output timecode file. +## Each input clip is CFR(constant frame rate). +## The output clip is VFR(variational frame rate). +################################################################################################################################ +## Basic parameters +## clips {clip}: any number of clips to splice +## each clip should be CFR +## tcfile {str}: timecode file output +## default: None +## v2 {bool}: timecode format +## True for v2 output and False for v1 output +## default: True +## precision {int}: precision of time and frame rate +## a decimal number indicating how many digits should be displayed after the decimal point for a fixed-point value +## default: 6 +################################################################################################################################ +def VFRSplice(clips, tcfile=None, v2=None, precision=None): + # Set VS core and function name + core = vs.get_core() + funcName = 'VFRSplice' + + # Arguments + if isinstance(clips, vs.VideoNode): + clips = [clips] + elif isinstance(clips, list): + for clip in clips: + if not isinstance(clip, vs.VideoNode): + raise TypeError(funcName + ': each element in \"clips\" must be a clip!') + if clip.fps_num == 0 or clip.fps_den == 0: + raise ValueError(funcName + ': each clip in \"clips\" must be CFR!') + else: + raise TypeError(funcName + ': \"clips\" must be a clip or a list of clips!') + + if tcfile is not None and not isinstance(tcfile, str): + raise TypeError(funcName + ': \"tcfile\" must be a str!') + + if v2 is None: + v2 = True + elif not isinstance(v2, int): + raise TypeError(funcName + ': \"v2\" must be a bool!') + + if precision is None: + precision = 6 + elif not isinstance(precision, int): + raise TypeError(funcName + ': \"precision\" must be an int!') + + # Fraction to str function + def frac2str(num, den, precision=6): + return '{:<.{precision}F}'.format(num / den, precision=precision) + + # Timecode file + if tcfile is None: + pass + else: + # Get timecode v1 list + cur_frame = 0 + tc_list = [] + index = 0 + for clip in clips: + if index > 0 and clip.fps_num == tc_list[index - 1][2] and clip.fps_den == tc_list[index - 1][3]: + tc_list[index - 1] = (tc_list[index - 1][0], cur_frame + clip.num_frames - 1, clip.fps_num, clip.fps_den) + else: + tc_list.append((cur_frame, cur_frame + clip.num_frames - 1, clip.fps_num, clip.fps_den)) + cur_frame += clip.num_frames + index += 1 + + # Write to timecode file + ofile = open(tcfile, 'w') + if v2: # timecode v2 + olines = ['# timecode format v2\n'] + frames = tc_list[len(tc_list) - 1][1] + 1 + time = 0 # ms + for tc in tc_list: + frame_duration = 1000 * tc[3] / tc[2] # ms + for frame in range(tc[0], tc[1] + 1): + olines.append('{:<.{precision}F}\n'.format(time, precision=precision)) + time += frame_duration + else: # timecode v1 + olines = ['# timecode format v1\n', 'Assume {}\n'.format(frac2str(tc_list[0][2], tc_list[0][3], precision))] + for tc in tc_list: + olines.append('{},{},{}\n'.format(tc[0], tc[1], frac2str(tc[2], tc[3], precision))) + try: + ofile.writelines(olines) + finally: + ofile.close() + + # Output spliced clip + return core.std.Splice(clips, mismatch=True) +################################################################################################################################ + +