first changes to original scripts

This commit is contained in:
2025-07-20 09:18:02 +02:00
parent e9fb8b8b7d
commit 33767e1f54
3 changed files with 65 additions and 18 deletions

View File

@@ -31,17 +31,7 @@ python scene_cutter.py "path/to/your/video.mkv"
```
### 3. Encode Segments
Choose one of the encoder scripts to process the files from the `cuts/` directory. Encoded files will be placed in the `segments/` directory.
**Option A: VMAF-based Encoding (Recommended)**
Use [`vmaf_encoder.py`](vmaf_encoder.py) to encode each segment to a target VMAF quality level.
```bash
python vmaf_encoder.py --target-vmaf 96.0
```
**Option B: Static CRF Encoding**
Use [`static_encoder.py`](static_encoder.py) to encode all segments with a single, fixed CRF value.
Use [`static_encoder.py`](static_encoder.py) to encode all segments from the `cuts/` directory with a single, fixed CRF value. Encoded files will be placed in the `segments/` directory.
```bash
python static_encoder.py --crf 27

View File

@@ -66,7 +66,44 @@ def get_video_duration(video_path):
# --- Core Logic Functions ---
def detect_scenes(video_path, json_output_path, hwaccel=None, threshold=0.4):
def detect_crop(video_path, hwaccel=None):
"""
Detects black bars using FFmpeg's cropdetect filter and returns the crop filter string.
Analyzes the first 60 seconds of the video for efficiency.
"""
print("\nStarting crop detection...")
command = ['ffmpeg', '-hide_banner']
if hwaccel:
command.extend(['-hwaccel', hwaccel])
# Analyze a portion of the video to find crop values
command.extend(['-i', video_path, '-t', '60', '-vf', 'cropdetect', '-f', 'null', '-'])
try:
# Using Popen to read stderr line by line
process = subprocess.Popen(command, stderr=subprocess.PIPE, text=True, encoding='utf-8')
last_crop_line = ""
for line in iter(process.stderr.readline, ''):
if 'crop=' in line:
last_crop_line = line.strip()
process.wait()
if last_crop_line:
# Extract the crop filter part, e.g., "crop=1920:800:0:140"
crop_filter = last_crop_line.split('] ')[-1]
print(f"Crop detection finished. Recommended filter: {crop_filter}")
return crop_filter
else:
print("Could not determine crop. No black bars detected or an error occurred.")
return None
except (FileNotFoundError, Exception) as e:
print(f"\nAn error occurred during crop detection: {e}")
return None
def detect_scenes(video_path, json_output_path, hwaccel=None, threshold=0.4, crop_filter=None):
"""Uses FFmpeg to detect scene changes and saves timestamps to a JSON file."""
print(f"\nStarting scene detection for: {os.path.basename(video_path)}")
command = ['ffmpeg', '-hide_banner']
@@ -74,7 +111,13 @@ def detect_scenes(video_path, json_output_path, hwaccel=None, threshold=0.4):
print(f"Attempting to use hardware acceleration: {hwaccel}")
command.extend(['-hwaccel', hwaccel])
filter_string = f"select='gt(scene,{threshold})',showinfo"
filters = []
if crop_filter:
print(f"Applying crop filter during scene detection: {crop_filter}")
filters.append(crop_filter)
filters.append(f"select='gt(scene,{threshold})',showinfo")
filter_string = ",".join(filters)
command.extend(['-i', video_path, '-vf', filter_string, '-f', 'null', '-'])
try:
@@ -105,7 +148,7 @@ def detect_scenes(video_path, json_output_path, hwaccel=None, threshold=0.4):
print(f"\nAn error occurred during scene detection: {e}")
return False
def cut_video_into_scenes(video_path, json_path, max_segment_length, hwaccel=None):
def cut_video_into_scenes(video_path, json_path, max_segment_length, hwaccel=None, crop_filter=None):
"""Cuts a video into segments, ensuring no segment exceeds a maximum length."""
print(f"\nStarting segment cutting for: {os.path.basename(video_path)}")
try:
@@ -148,7 +191,13 @@ def cut_video_into_scenes(video_path, json_path, max_segment_length, hwaccel=Non
if hwaccel:
command.extend(['-hwaccel', hwaccel])
command.extend(['-i', video_path, '-c:v', 'utvideo', '-an', '-sn', '-dn', '-map_metadata', '-1', '-map_chapters', '-1', '-f', 'segment', '-segment_times', segment_times_str, '-segment_start_number', '1', '-reset_timestamps', '1', output_pattern])
command.extend(['-i', video_path])
if crop_filter:
print(f"Applying crop filter during cutting: {crop_filter}")
command.extend(['-vf', crop_filter])
command.extend(['-c:v', 'utvideo', '-an', '-sn', '-dn', '-map_metadata', '-1', '-map_chapters', '-1', '-f', 'segment', '-segment_times', segment_times_str, '-segment_start_number', '1', '-reset_timestamps', '1', output_pattern])
print("\nStarting FFmpeg to cut all segments in a single pass...")
try:
@@ -167,6 +216,11 @@ def main():
formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument("video_path", help="Path to the input video file.")
parser.add_argument(
"--autocrop",
action='store_true',
help="Automatically detect and apply cropping to remove black bars. Default: False"
)
parser.add_argument(
"--so", "--sceneonly",
action='store_true',
@@ -195,21 +249,24 @@ def main():
json_path = f"{base_name}.scenes.json"
hwaccel_method = get_best_hwaccel()
crop_filter = None
if args.autocrop:
crop_filter = detect_crop(args.video_path, hwaccel_method)
if args.sceneonly:
detect_scenes(args.video_path, json_path, hwaccel_method, args.threshold)
detect_scenes(args.video_path, json_path, hwaccel_method, args.threshold, crop_filter)
sys.exit(0)
# --- Full Workflow (Detect if needed, then Cut) ---
if not os.path.isfile(json_path):
print("--- Scene file not found, running detection first ---")
if not detect_scenes(args.video_path, json_path, hwaccel_method, args.threshold):
if not detect_scenes(args.video_path, json_path, hwaccel_method, args.threshold, crop_filter):
print("\nScene detection failed. Aborting process.")
sys.exit(1)
else:
print(f"--- Found existing scene file: {os.path.basename(json_path)} ---")
cut_video_into_scenes(args.video_path, json_path, args.segtime, hwaccel_method)
cut_video_into_scenes(args.video_path, json_path, args.segtime, hwaccel_method, crop_filter)
if __name__ == "__main__":
main()