Skip to content

frame_eval ΒΆ

frame_eval(base_clip: VideoNode) -> Callable[[FE_N_FUNC], VideoNode]
frame_eval(
    base_clip: VideoNode, /, frame: Literal[True] = ...
) -> Callable[[FE_F_FUNC], VideoNode]
frame_eval(
    base_clip: VideoNode, frame_clips: VideoNode = ..., /, frame: bool = ...
) -> Callable[[FE_F_FUNC], VideoNode]
frame_eval(
    base_clip: VideoNode, frame_clips: None = ..., /, frame: Literal[True] = ...
) -> Callable[[FE_F_FUNC], VideoNode]
frame_eval(
    base_clip: VideoNode,
    frame_clips: list[VideoNode] = ...,
    /,
    frame: bool = ...,
) -> Callable[[FE_L_FUNC], VideoNode]
frame_eval(
    base_clip: VideoNode,
    frame_clips: VideoNode | list[VideoNode] | None = None,
    /,
    frame: bool = False,
) -> Callable[[FE_N_FUNC | FE_F_FUNC | FE_L_FUNC], VideoNode]
Source code
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
def frame_eval(  # type: ignore
    base_clip: vs.VideoNode, frame_clips: vs.VideoNode | list[vs.VideoNode] | None = None, /, frame: bool = False
) -> Callable[[FE_N_FUNC | FE_F_FUNC | FE_L_FUNC], vs.VideoNode]:
    if frame and not frame_clips:
        frame_clips = base_clip

    base_clip = base_clip.std.BlankClip(keep=True)

    def _decorator(func: FE_N_FUNC | FE_F_FUNC | FE_L_FUNC) -> vs.VideoNode:
        args = func.__annotations__
        keys = list(filter(lambda x: x not in {'self', 'return'}, args.keys()))

        rtype = args.get('return', vs.VideoNode)

        if isinstance(rtype, type):
            rtype = rtype.__name__

        n_args = len(keys)
        ret_frame = str(rtype) == 'VideoFrame'

        if n_args == 1:
            if ret_frame:
                def _inner(n: int) -> vs.VideoNode:
                    return base_clip.std.ModifyFrame(base_clip, lambda n, f: func(n))  # type: ignore
            else:
                if 'n' in keys:
                    _inner = func  # type: ignore
                else:
                    def _inner(n: int) -> vs.VideoNode:
                        return func(n)  # type: ignore
        elif n_args == 2:
            if isinstance(frame_clips, list) and len(frame_clips) < 2:
                if ret_frame:
                    def _inner(n: int) -> vs.VideoNode:
                        return base_clip.std.ModifyFrame(frame_clips, lambda n, f: func(n, [f]))  # type: ignore
                else:
                    def _inner(n: int, f: vs.VideoFrame) -> vs.VideoNode:  # type: ignore
                        return func(n, [f])  # type: ignore
            else:
                if ret_frame:
                    def _inner(n: int) -> vs.VideoNode:
                        return base_clip.std.ModifyFrame(frame_clips, lambda n, f: func(n, f))  # type: ignore
                else:
                    if 'n' in keys and 'f' in keys:
                        _inner = func  # type: ignore
                    else:
                        def _inner(n: int, f: list[vs.VideoFrame]) -> vs.VideoNode:  # type: ignore
                            return func(n, f)  # type: ignore
        else:
            raise CustomValueError('Function must have 1-2 arguments!', frame_eval)

        if ret_frame:
            return base_clip.std.FrameEval(_inner)
        return base_clip.std.FrameEval(_inner, frame_clips, base_clip)

    return _decorator