dubhater/vapoursynth-wwxd

Only 50% CPU usage

Infiziert90 opened this issue · 3 comments

Hiho,

when i'm using wwxd for keyframe generation, i only got 50% on every core ... i tested it on an i5 4690k, Xeon 1245v3 and on new Ryzen 1700.
Is there any chance that you can fix that problem?

For the test i used a 1080p Episode(24min) and this script:

    core = vs.get_core(accept_lowercase=True)
    clip = core.resize.Bilinear(clip, 640, 360)  # speed up the analysis by resizing first
    clip = core.wwxd.WWXD(clip)
    outtxt = ""
    for i in range(clip.num_frames):
        if clip.get_frame(i).props.Scenechange == 1:
            outtxt += "%d I -1\\n" % i

To be honest, this filter is rather shitty. You'll get better results with xvid.

The low CPU usage is due to get_frame. It's synchronous, so WWXD will only process one frame at a time. Try get_frame_async, though don't ask me how to use it. I don't understand that "Future" stuff.

I already use get_frame_async in one of my other scripts ... but i got the same problem

def get_frame(clip, frameno):
    with _cache_lock:
        if frameno in _frame_cache:
            return _frame_cache[frameno]

        fut = clip.get_frame_async(frameno)
        _frame_cache[frameno] = fut
    return fut


def find_keyframes(clip, frame, epsilon=7):
    """Output frames when scenechange == True"""
    _waiting = {}
    for frameno in range(frame - epsilon, frame + epsilon):
        if not (0 <= frameno < len(clip)):
            continue
        with _cache_lock:
            if frameno in _keyframe_cache:
                if _keyframe_cache[frameno]:
                    yield frameno
                    continue

        future = get_frame(clip, frameno)
        _waiting[future] = frameno

    for future in as_completed(_waiting):
        frameno = _waiting[future]
        frame = future.result()
        with _cache_lock:
            change = _keyframe_cache[frameno] = frame.props.Scenechange
            del _frame_cache[frameno]

        if change:
            yield frameno


def get_nearest_scenechange(clip, start, end, epsilon=7):
    """Resize frame and start check the frame with wwxd for scenechanges

    A resized clip is faster ... but with a resolution under 640x360 wwxd cant work really good and will give you a lot
    of bullshit.
    """
    core = vs.get_core(accept_lowercase=True)
    clip = core.resize.Bilinear(clip, 640, 360)  # speed up the analysis by resizing first
    clip = core.wwxd.WWXD(clip)

    start = tuple(find_keyframes(clip, start, epsilon))
    end = tuple(find_keyframes(clip, end, epsilon))

    return TimeFrame(start, end)

But still the same problem ... only 50% Usage

I will try your xvid Vapoursynth Port ...
The normal scxvid for arch linux is 20-30s slower for the ~same result.

I just checked the code and... I remembered wrong. This filter will run in a single thread no matter what.