|
4 | 4 | from typing import List |
5 | 5 | import logging |
6 | 6 | from tqdm import tqdm |
| 7 | +from tqdm.contrib.concurrent import process_map |
| 8 | +import psutil |
| 9 | +import os |
| 10 | +from functools import partial |
7 | 11 |
|
8 | 12 | # Note: untested other than .mp4. Support for .webm may have issues: https://github.com/sign-language-processing/pose/pull/126 |
9 | 13 | SUPPORTED_VIDEO_FORMATS = [".mp4", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".webm"] |
@@ -79,6 +83,22 @@ def get_corresponding_pose_path(video_path: Path, keep_video_suffixes: bool = Fa |
79 | 83 | return video_path.with_suffix(".pose") |
80 | 84 |
|
81 | 85 |
|
| 86 | +def process_video(keep_video_suffixes: bool, pose_format: str, additional_config: dict, vid_path: Path) -> bool: |
| 87 | + print(f'Estimating {vid_path} on CPU {psutil.Process().cpu_num()}') |
| 88 | + |
| 89 | + try: |
| 90 | + pose_path = get_corresponding_pose_path(video_path=vid_path, keep_video_suffixes=keep_video_suffixes) |
| 91 | + if pose_path.is_file(): |
| 92 | + print(f"Skipping {vid_path}, corresponding .pose file already created.") |
| 93 | + else: |
| 94 | + pose_video(vid_path, pose_path, pose_format, additional_config, progress=False) |
| 95 | + return True |
| 96 | + |
| 97 | + except ValueError as e: |
| 98 | + print(f"ValueError on {vid_path}") |
| 99 | + logging.exception(e) |
| 100 | + |
| 101 | + |
82 | 102 | def main(): |
83 | 103 | parser = argparse.ArgumentParser() |
84 | 104 | parser.add_argument( |
@@ -114,6 +134,13 @@ def main(): |
114 | 134 | default=SUPPORTED_VIDEO_FORMATS, |
115 | 135 | help="Video extensions to search for. Defaults to searching for all supported.", |
116 | 136 | ) |
| 137 | + parser.add_argument( |
| 138 | + "--num-workers", |
| 139 | + type=int, |
| 140 | + default=1, |
| 141 | + help="Number of multiprocessing workers.", |
| 142 | + required=False |
| 143 | + ) |
117 | 144 | parser.add_argument( |
118 | 145 | "--additional-config", |
119 | 146 | type=str, |
@@ -144,15 +171,14 @@ def main(): |
144 | 171 |
|
145 | 172 | pose_with_no_errors_count = 0 |
146 | 173 |
|
147 | | - for vid_path in tqdm(videos_with_missing_pose_files): |
148 | | - try: |
149 | | - pose_path = get_corresponding_pose_path(video_path=vid_path, keep_video_suffixes=args.keep_video_suffixes) |
150 | | - if pose_path.is_file(): |
151 | | - print(f"Skipping {vid_path}, corresponding .pose file already created.") |
152 | | - continue |
153 | | - pose_video(vid_path, pose_path, args.format, additional_config) |
| 174 | + if args.num_workers == 1: |
| 175 | + print('Process sequentially ...') |
| 176 | + else: |
| 177 | + print(f'Multiprocessing with {args.num_workers} workers on {len(os.sched_getaffinity(0))} available CPUs ...') |
| 178 | + |
| 179 | + func = partial(process_video, args.keep_video_suffixes, args.format, additional_config) |
| 180 | + for success in process_map(func, videos_with_missing_pose_files, max_workers=args.num_workers): |
| 181 | + if success: |
154 | 182 | pose_with_no_errors_count += 1 |
155 | | - except ValueError as e: |
156 | | - print(f"ValueError on {vid_path}") |
157 | | - logging.exception(e) |
| 183 | + |
158 | 184 | print(f"Successfully created pose files for {pose_with_no_errors_count}/{len(videos_with_missing_pose_files)} video files") |
0 commit comments