Av1an/av1an/scenedetection/pyscene.py
2021-04-13 02:23:48 +03:00

90 lines
2.9 KiB
Python
Executable file

#!/bin/env python
import sys
from subprocess import Popen
try:
from scenedetect.detectors import ContentDetector
from scenedetect.scene_manager import SceneManager
from scenedetect.video_manager import VideoManager
from scenedetect.frame_timecode import FrameTimecode
except ImportError:
ContentDetector = None
from av1an.logger import log
from av1an.utils import frame_probe
from av1an.vapoursynth import compose_vapoursynth_pipe
if sys.platform == "linux":
from os import mkfifo
def pyscene(video, threshold, min_scene_len, is_vs, temp, quiet):
"""
Running PySceneDetect detection on source video for segmenting.
Optimal threshold settings 15-50
"""
if ContentDetector is None:
log(
f"Unable to start PySceneDetect because it was not found. Please install scenedetect[opencv] to use"
)
return []
log(f"Starting PySceneDetect:")
log(f"Threshold: {threshold}")
log(f"Min scene length: {min_scene_len}")
log(f"Is Vapoursynth input: {is_vs}")
if is_vs:
# Handling vapoursynth, so we need to create a named pipe to feed to VideoManager.
# TODO: Do we clean this up after pyscenedetect has run, or leave it as part of the temp dir, where it will be cleaned up later?
if sys.platform == "linux":
vspipe_fifo = temp / "vspipe.y4m"
mkfifo(vspipe_fifo)
else:
vspipe_fifo = None
vspipe_cmd = compose_vapoursynth_pipe(video, vspipe_fifo)
vspipe_process = Popen(vspipe_cmd)
# Get number of frames from Vapoursynth script to pass as duration to VideoManager.
# We need to pass the number of frames to the manager, otherwise it won't close the
# receiving end of the pipe, and will simply sit waiting after vspipe has finished sending
# the last frame.
frames = frame_probe(video)
video_manager = VideoManager([str(vspipe_fifo if is_vs else video)])
scene_manager = SceneManager()
scene_manager.add_detector(
ContentDetector(threshold=threshold, min_scene_len=min_scene_len)
)
base_timecode = video_manager.get_base_timecode()
video_manager.set_duration(
duration=FrameTimecode(frames, video_manager.get_framerate()) if is_vs else None
)
# Set downscale factor to improve processing speed.
video_manager.set_downscale_factor()
# Start video_manager.
video_manager.start()
scene_manager.detect_scenes(frame_source=video_manager, show_progress=(not quiet))
# If fed using a vspipe process, ensure that vspipe has finished.
if is_vs:
vspipe_process.wait()
# Obtain list of detected scenes.
scene_list = scene_manager.get_scene_list(base_timecode)
scenes = [int(scene[0].get_frames()) for scene in scene_list]
# Remove 0 from list
if scenes[0] == 0:
scenes.remove(0)
log(f"Found scenes: {len(scenes)}")
return scenes