mirror of
https://github.com/blw1138/Zordon.git
synced 2025-12-17 08:48:13 +00:00
* Expose renderer availability in status api * Remove redundant is_available_for_job API call * New server split logic by cpu and moved to server_helper.py * Remove old dead code * Add RenderStatus.WAITING to proxy categories
124 lines
4.8 KiB
Python
124 lines
4.8 KiB
Python
import logging
|
|
import os
|
|
import socket
|
|
import subprocess
|
|
import threading
|
|
|
|
import psutil
|
|
|
|
from lib.server.server_proxy import RenderServerProxy
|
|
from lib.utilities.ffmpeg_helper import generate_thumbnail, save_first_frame
|
|
|
|
logger = logging.getLogger()
|
|
|
|
|
|
def generate_thumbnail_for_job(job, thumb_video_path, thumb_image_path, max_width=320):
|
|
|
|
# Simple thread to generate thumbs in background
|
|
def generate_thumb_thread(source):
|
|
in_progress_path = thumb_video_path + '_IN-PROGRESS'
|
|
subprocess.run(['touch', in_progress_path])
|
|
try:
|
|
logger.debug(f"Generating video thumbnail for {source}")
|
|
generate_thumbnail(source_path=source, dest_path=thumb_video_path, max_width=max_width)
|
|
except subprocess.CalledProcessError as e:
|
|
logger.error(f"Error generating video thumbnail for {source}: {e}")
|
|
|
|
try:
|
|
os.remove(in_progress_path)
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
# Determine best source file to use for thumbs
|
|
source_files = job.file_list() or [job.input_path]
|
|
if source_files:
|
|
video_formats = ['.mp4', '.mov', '.avi', '.mpg', '.mpeg', '.mxf', '.m4v', 'mkv']
|
|
image_formats = ['.jpg', '.png', '.exr']
|
|
|
|
image_files = [f for f in source_files if os.path.splitext(f)[-1].lower() in image_formats]
|
|
video_files = [f for f in source_files if os.path.splitext(f)[-1].lower() in video_formats]
|
|
|
|
if (video_files or image_files) and not os.path.exists(thumb_image_path):
|
|
try:
|
|
path_of_source = image_files[0] if image_files else video_files[0]
|
|
logger.debug(f"Generating image thumbnail for {path_of_source}")
|
|
save_first_frame(source_path=path_of_source, dest_path=thumb_image_path, max_width=max_width)
|
|
except Exception as e:
|
|
logger.error(f"Exception saving first frame: {e}")
|
|
|
|
if video_files and not os.path.exists(thumb_video_path):
|
|
x = threading.Thread(target=generate_thumb_thread, args=(video_files[0],))
|
|
x.start()
|
|
|
|
|
|
def divide_frames_evenly(start_frame, end_frame, num_servers):
|
|
frame_range = end_frame - start_frame + 1
|
|
frames_per_server = frame_range // num_servers
|
|
leftover_frames = frame_range % num_servers
|
|
|
|
ranges = []
|
|
current_start = start_frame
|
|
for i in range(num_servers):
|
|
current_end = current_start + frames_per_server - 1
|
|
if leftover_frames > 0:
|
|
current_end += 1
|
|
leftover_frames -= 1
|
|
if current_start <= current_end:
|
|
ranges.append((current_start, current_end))
|
|
current_start = current_end + 1
|
|
|
|
return ranges
|
|
|
|
|
|
def divide_frames_by_cpu_count(frame_start, frame_end, servers):
|
|
total_frames = frame_end - frame_start + 1
|
|
total_performance = sum(server['cpu_count'] for server in servers)
|
|
|
|
frame_ranges = {}
|
|
current_frame = frame_start
|
|
allocated_frames = 0
|
|
|
|
for i, server in enumerate(servers):
|
|
if i == len(servers) - 1: # if it's the last server
|
|
# Give all remaining frames to the last server
|
|
num_frames = total_frames - allocated_frames
|
|
else:
|
|
num_frames = round((server['cpu_count'] / total_performance) * total_frames)
|
|
allocated_frames += num_frames
|
|
|
|
frame_end_for_server = current_frame + num_frames - 1
|
|
|
|
if current_frame <= frame_end_for_server:
|
|
frame_ranges[server['hostname']] = (current_frame, frame_end_for_server)
|
|
current_frame = frame_end_for_server + 1
|
|
|
|
return frame_ranges
|
|
|
|
|
|
def find_available_servers(server_list, renderer, start_frame, end_frame):
|
|
local_hostname = socket.gethostname()
|
|
subjob_servers = [{'hostname': local_hostname, 'cpu_count': psutil.cpu_count(logical=False)}]
|
|
for hostname in server_list:
|
|
if hostname != local_hostname:
|
|
response = RenderServerProxy(hostname).get_status()
|
|
if response and response.get('renderers', {}).get(renderer, {}).get('is_ready', False):
|
|
subjob_servers.append({'hostname': hostname, 'cpu_count': int(response['cpu_count'])})
|
|
|
|
if len(subjob_servers) == 1:
|
|
logger.debug("No available servers to split job with. Skipping subjob creation.")
|
|
return subjob_servers
|
|
|
|
# Calculate respective frames for each server
|
|
breakdown = divide_frames_by_cpu_count(start_frame, end_frame, subjob_servers)
|
|
subjob_servers = [server for server in subjob_servers if breakdown.get(server['hostname']) is not None]
|
|
for server in subjob_servers:
|
|
server['frame_range'] = breakdown[server['hostname']]
|
|
server['total_frames'] = breakdown[server['hostname']][-1] - breakdown[server['hostname']][0] + 1
|
|
|
|
return subjob_servers
|
|
|
|
|
|
if __name__ == "__main__":
|
|
found_servers = ['kamino.local', 'deathstar.local']
|
|
print(find_available_servers(found_servers, 'blender', 1, 5))
|