-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathbulk_process_videos.py
More file actions
212 lines (178 loc) · 7.05 KB
/
bulk_process_videos.py
File metadata and controls
212 lines (178 loc) · 7.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#!/usr/bin/env python3
"""
Bulk process videos using nemo/pipeline2.py with high-quality identity image.
This will process all videos in junk/ folder using nemo/data/IMG_1.png as the identity source.
"""
import os
import sys
import glob
import argparse
import subprocess
from pathlib import Path
from tqdm import tqdm
import logging
import time
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def process_single_video(source_image_path, video_path, output_path, fps=25, max_len=1000):
"""
Process a single video using pipeline2.py
Args:
source_image_path: Path to identity image (IMG_1.png)
video_path: Path to driving video
output_path: Path to save result
fps: Output video FPS
max_len: Maximum frames to process
"""
# Change to nemo directory for pipeline2.py to work properly
original_dir = os.getcwd()
nemo_dir = os.path.join(original_dir, 'nemo')
try:
os.chdir(nemo_dir)
# Build the command
cmd = [
sys.executable, # Use current Python interpreter
'pipeline2.py',
'--source_image_path', source_image_path,
'--driven_video_path', video_path,
'--saved_to_path', output_path,
'--fps', str(fps),
'--max_len', str(max_len)
]
logger.info(f"Processing: {os.path.basename(video_path)}")
logger.debug(f"Command: {' '.join(cmd)}")
# Run the command
result = subprocess.run(
cmd,
capture_output=True,
text=True,
check=False
)
if result.returncode == 0:
logger.info(f"✓ Successfully processed: {os.path.basename(video_path)}")
return True
else:
logger.error(f"✗ Failed to process: {os.path.basename(video_path)}")
logger.error(f"Error: {result.stderr}")
return False
except Exception as e:
logger.error(f"Exception processing {video_path}: {str(e)}")
return False
finally:
# Always change back to original directory
os.chdir(original_dir)
def main():
parser = argparse.ArgumentParser(description="Bulk process videos with high-quality identity")
parser.add_argument('--identity_image', type=str,
default='data/IMG_1.png',
help='Path to identity image (relative to nemo/)')
parser.add_argument('--input_dir', type=str,
default='../junk',
help='Input video directory (relative to nemo/)')
parser.add_argument('--output_dir', type=str,
default='data/bulk_results',
help='Output directory (relative to nemo/)')
parser.add_argument('--video_pattern', type=str,
default='*.mp4',
help='Video file pattern to match')
parser.add_argument('--fps', type=float,
default=25.0,
help='Output video FPS')
parser.add_argument('--max_len', type=int,
default=300,
help='Maximum frames per video')
parser.add_argument('--skip_existing', action='store_true',
help='Skip videos that already have output')
parser.add_argument('--max_videos', type=int,
default=None,
help='Maximum number of videos to process')
args = parser.parse_args()
# Get absolute paths
script_dir = Path(__file__).parent.absolute()
nemo_dir = script_dir / 'nemo'
# Verify nemo directory exists
if not nemo_dir.exists():
logger.error(f"nemo directory not found at: {nemo_dir}")
sys.exit(1)
# Build full paths relative to nemo directory
identity_path = nemo_dir / args.identity_image
input_dir = nemo_dir / args.input_dir
output_dir = nemo_dir / args.output_dir
# Verify identity image exists
if not identity_path.exists():
logger.error(f"Identity image not found: {identity_path}")
sys.exit(1)
logger.info(f"Using identity image: {identity_path}")
# Verify input directory exists
if not input_dir.exists():
logger.error(f"Input directory not found: {input_dir}")
sys.exit(1)
# Create output directory if it doesn't exist
output_dir.mkdir(parents=True, exist_ok=True)
logger.info(f"Output directory: {output_dir}")
# Find all videos
video_pattern = str(input_dir / args.video_pattern)
video_files = sorted(glob.glob(video_pattern))
if not video_files:
logger.error(f"No videos found matching pattern: {video_pattern}")
sys.exit(1)
logger.info(f"Found {len(video_files)} videos to process")
# Limit number of videos if specified
if args.max_videos:
video_files = video_files[:args.max_videos]
logger.info(f"Processing only first {args.max_videos} videos")
# Process statistics
successful = 0
failed = 0
skipped = 0
# Process each video
for video_path in tqdm(video_files, desc="Processing videos"):
video_name = Path(video_path).stem
output_filename = f"{video_name}_identity.mp4"
output_path = output_dir / output_filename
# Skip if output exists and skip_existing is True
if args.skip_existing and output_path.exists():
logger.info(f"Skipping existing: {output_filename}")
skipped += 1
continue
# Convert paths to relative paths from nemo directory
identity_rel = os.path.relpath(identity_path, nemo_dir)
video_rel = os.path.relpath(video_path, nemo_dir)
output_rel = os.path.relpath(output_path, nemo_dir)
# Process the video
success = process_single_video(
identity_rel,
video_rel,
output_rel,
args.fps,
args.max_len
)
if success:
successful += 1
else:
failed += 1
# Small delay between videos to avoid overwhelming the system
time.sleep(1)
# Print summary
logger.info("\n" + "="*60)
logger.info("PROCESSING COMPLETE")
logger.info("="*60)
logger.info(f"Total videos: {len(video_files)}")
logger.info(f"Successful: {successful}")
logger.info(f"Failed: {failed}")
logger.info(f"Skipped: {skipped}")
if successful > 0:
logger.info(f"\nResults saved in: {output_dir}")
# List output files
output_files = list(output_dir.glob("*.mp4"))
if output_files:
logger.info(f"Generated {len(output_files)} output videos:")
for f in output_files[:5]: # Show first 5
logger.info(f" - {f.name}")
if len(output_files) > 5:
logger.info(f" ... and {len(output_files) - 5} more")
if __name__ == "__main__":
main()