| import os |
| from glob import glob |
| import time |
| import argparse |
| import numpy as np |
| import librosa |
| from decord import VideoReader |
| import shared.utils.log as log |
| from os.path import exists, basename |
| from natsort import natsorted |
|
|
| def resize_video_simple(input_path, output_path, width=480): |
| import subprocess |
| command = f"""ffmpeg -loglevel quiet -i {input_path} -vf \"scale={width}:-1\" -c:a copy {output_path}""" |
| subprocess.call(command, shell=True) |
|
|
| def load_pending_videos(tracker_file): |
| """Load list of pending videos from tracker file.""" |
| if not exists(tracker_file): |
| return [] |
| |
| with open(tracker_file, 'r') as f: |
| return [line.strip() for line in f.readlines() if line.strip()] |
|
|
| def save_pending_videos(tracker_file, video_paths): |
| """Save list of pending videos to tracker file.""" |
| with open(tracker_file, 'w') as f: |
| for path in video_paths: |
| f.write(f"{path}\n") |
|
|
| def remove_completed_video(tracker_file, completed_video): |
| """Remove a completed video from the tracker file.""" |
| pending_videos = load_pending_videos(tracker_file) |
| if completed_video in pending_videos: |
| pending_videos.remove(completed_video) |
| save_pending_videos(tracker_file, pending_videos) |
|
|
| if __name__ == "__main__": |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "--video_dir", type=str, required=True, |
| help="Directory containing videos to downsize." |
| ) |
| parser.add_argument( |
| "--ext", type=str, default="mp4", |
| help="File extension to search for (default: mp4)." |
| ) |
| parser.add_argument( |
| "--remove_old", action="store_true", |
| help="Remove original video after downsizing." |
| ) |
| parser.add_argument( |
| "--width", type=int, default=480, |
| help="Width to resize videos to (default: 480)." |
| ) |
| parser.add_argument( |
| "--debug", action="store_true", |
| help="Run debug checks after downsizing." |
| ) |
| parser.add_argument("--si", type=int, default=None) |
| parser.add_argument("--ei", type=int, default=None) |
| parser.add_argument( |
| "--tracker_file", type=str, default="video_resize_tracker.txt", |
| help="Tracker file to keep track of pending videos (default: video_resize_tracker.txt)." |
| ) |
| parser.add_argument( |
| "--reset_tracker", action="store_true", |
| help="Reset the tracker file and start fresh." |
| ) |
| args = parser.parse_args() |
|
|
| assert os.path.isdir(args.video_dir), f"Directory {args.video_dir} does not exist." |
| |
| |
| if args.reset_tracker and exists(args.tracker_file): |
| os.remove(args.tracker_file) |
| print(f"> Reset tracker file: {args.tracker_file}") |
| |
| |
| pending_videos = load_pending_videos(args.tracker_file) |
| |
| if pending_videos: |
| print(f"> Found {len(pending_videos)} pending videos from previous run") |
| ifiles = pending_videos |
| ofiles = pending_videos |
| else: |
| |
| pattern = os.path.join(args.video_dir, f"**/*.{args.ext}") |
| ifiles = glob(pattern, recursive=True) |
| ifiles = natsorted(ifiles) |
| ofiles = ifiles |
| print("> Number of videos in the directory:", len(ifiles)) |
| |
| |
| si = args.si if args.si is not None else 0 |
| ei = args.ei if args.ei is not None else len(ifiles) |
| print("> Start index:", si) |
| print("> End index:", ei) |
| ifiles = ifiles[si:ei] |
| ofiles = ofiles[si:ei] |
| |
| |
| save_pending_videos(args.tracker_file, ifiles) |
| print(f"> Saved {len(ifiles)} videos to tracker file: {args.tracker_file}") |
| |
| print("> Number of videos to downsize:", len(ifiles)) |
|
|
| iterator = log.tqdm_iterator( |
| range(len(ifiles)), total=len(ifiles), desc="Downsizing videos", |
| ) |
| for i in iterator: |
| ifile = ifiles[i] |
| ofile = ifile |
| assert exists(ifile), f"Video {ifile} does not exist." |
| tmp_ofile = ifile + ".tmp.mp4" |
| start_time = time.time() |
| resize_video_simple(ifile, tmp_ofile, width=args.width) |
| end_time = time.time() |
| time_taken = end_time - start_time |
| desc = f"Time taken {time_taken:.2f}s for {basename(ifile)}" |
| iterator.set_description(desc) |
|
|
| if args.debug: |
| yold, srold = librosa.load(ifile, offset=1.0, duration=1.0) |
| ynew, srnew = librosa.load(tmp_ofile, offset=1.0, duration=1.0) |
| assert srold == srnew, "Sampling rate mismatch." |
| assert len(yold) == len(ynew), "Length mismatch." |
| assert np.allclose(yold, ynew), "Audio mismatch." |
| vr = VideoReader(tmp_ofile) |
| frames = vr.get_batch(range(0, 10)).asnumpy() |
| assert frames.shape[0] == 10, "Length mismatch." |
| assert frames.shape[2] == args.width, "Width mismatch." |
|
|
| |
| os.replace(tmp_ofile, ofile) |
| |
| |
| remove_completed_video(args.tracker_file, ifile) |
| |
| if args.remove_old: |
| |
| pass |
| |
| |
| if not load_pending_videos(args.tracker_file): |
| os.remove(args.tracker_file) |
| print(f"> All videos completed. Removed tracker file: {args.tracker_file}") |
| else: |
| remaining = len(load_pending_videos(args.tracker_file)) |
| print(f"> {remaining} videos remaining. Tracker file preserved: {args.tracker_file}") |