diff --git a/.gitignore b/.gitignore index df338eb..0d13db6 100755 --- a/.gitignore +++ b/.gitignore @@ -352,4 +352,5 @@ $RECYCLE.BIN/ *.ass *.xml *.png -printdens.py \ No newline at end of file +printdens.py +*.mp4 \ No newline at end of file diff --git a/README.md b/README.md index aaa08fc..ad9d3a1 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,32 @@ Auto slice the shorts based on the density of danmaku. - Detect the dense period of danmaku based on the sliding window algorithm. - Slice the video based on the density of danmaku. -- Support GPU accelerated calculation. +- Support GPU accelerated calculation.(Automatically choose whether to use GPU acceleration) +- Support custom quantity slicing videos. +- Support custom slice duration. + +## Prerequisites + +To use this tool, you need to install ffmpeg first. + +- Windows: `choco install ffmpeg` (via [Chocolatey](https://chocolatey.org/)) or other methods. +- macOS: `brew install ffmpeg` (via [Homebrew](https://brew.sh/)). +- Linux: `sudo apt install ffmpeg` (Debian/Ubuntu). + +More OS please refer to the [official website](https://ffmpeg.org/download.html). ## Usage +### cli usage + ```bash python -m autoslice.autosv ``` +### api usage + +```python +from autoslice.autosv import slice_video_by_danmaku + +slice_video_by_danmaku(ass_path, video_path, duration=300, top_n=3, max_overlap=60, step=1) +``` diff --git a/autoslice/autosv.py b/autoslice/autosv.py index 7d3bcc7..d12f1ce 100644 --- a/autoslice/autosv.py +++ b/autoslice/autosv.py @@ -1,6 +1,8 @@ # Copyright (c) 2025 auto-slice-video +import os from .calculate.selection import find_dense_periods +from .slice.slice_video import slice_video def parse_time(time_str): """Convert ASS time format to seconds with milliseconds.""" @@ -19,6 +21,28 @@ def extract_timestamps(file_path): timestamps.append(start_time) return timestamps -timestamps = extract_timestamps('./sample.ass') -dense_periods = find_dense_periods(timestamps, 300, 3, 60) -print(dense_periods) \ No newline at end of file +def slice_video_by_danmaku(ass_path, video_path, duration=300, top_n=3, max_overlap=60, step=1): + """ + Slice the video by the dense periods of danmaku. + + Args: + ass_path: The path to the ASS file. + video_path: The path to the video file. + duration: The duration of the slice. + top_n: The number of top dense periods to return. + max_overlap: The maximum allowed overlap between periods (in seconds). + step: The step size for sliding window (in seconds). + """ + output_folder = os.path.dirname(video_path) + video_name = os.path.splitext(os.path.basename(video_path))[0] + timestamps = extract_timestamps(ass_path) + dense_periods = find_dense_periods(timestamps, duration, top_n, max_overlap, step) + print("The dense periods and their count are:") + i = 1 + for period in dense_periods: + print(f"Start from {period[0]} seconds with the count is {period[1]}") + slice_video(video_path, f'{output_folder}/{video_name}_{i}.mp4', period[0], duration) + i += 1 + +if __name__ == "__main__": + slice_video_by_danmaku('./sample.ass', './sample.mp4', 300, 3, 60, 1) \ No newline at end of file diff --git a/autoslice/calculate/selection.py b/autoslice/calculate/selection.py index f3fa1d6..0f0f402 100644 --- a/autoslice/calculate/selection.py +++ b/autoslice/calculate/selection.py @@ -18,12 +18,12 @@ def check_cuda_available(): except ImportError: USE_GPU = False -def find_dense_periods(timestamps, window_size=300, top_n=3, max_overlap=60): +def find_dense_periods(timestamps, window_size=300, top_n=3, max_overlap=60, step=1): """Find dense periods using either GPU or CPU implementation based on GPU availability.""" if USE_GPU: print("Using GPU implementation") - return find_dense_periods_gpu(timestamps, window_size, top_n, max_overlap) + return find_dense_periods_gpu(timestamps, window_size, top_n, max_overlap, step) print("Using CPU implementation") - return find_dense_periods_cpu(timestamps, window_size, top_n, max_overlap) + return find_dense_periods_cpu(timestamps, window_size, top_n, max_overlap, step) diff --git a/autoslice/slice/slice_video.py b/autoslice/slice/slice_video.py new file mode 100644 index 0000000..753806b --- /dev/null +++ b/autoslice/slice/slice_video.py @@ -0,0 +1,29 @@ +# Copyright (c) 2024 bilive. +# Copyright (c) 2025 auto-slice-video + +import subprocess + +def format_time(seconds): + """Format seconds to hh:mm:ss.""" + h = int(seconds // 3600) + m = int((seconds % 3600) // 60) + s = int(seconds % 60) + return f"{h:02}:{m:02}:{s:02}" + +def slice_video(video_path, output_path, start_time, duration=30): + """Slice the video using ffmpeg.""" + duration = format_time(duration) + command = [ + 'ffmpeg', + '-ss', format_time(start_time), + '-i', video_path, + '-t', duration, + '-map_metadata', '-1', + '-c:v', 'copy', + '-c:a', 'copy', + output_path + ] + try: + result = subprocess.run(command, check=True, capture_output=True, text=True) + except subprocess.CalledProcessError as e: + print(f"Error: {e.stderr}") \ No newline at end of file