Broadcast virtual webcam

pull/768/head
KRSHH 2024-11-07 15:40:36 +05:30
parent 4aadfdf2ca
commit ceaf676b95
1 changed files with 129 additions and 113 deletions

View File

@ -7,7 +7,7 @@ from cv2_enumerate_cameras import enumerate_cameras # Add this import
from PIL import Image, ImageOps from PIL import Image, ImageOps
import time import time
import json import json
import pyvirtualcam
import modules.globals import modules.globals
import modules.metadata import modules.metadata
from modules.face_analyser import ( from modules.face_analyser import (
@ -779,35 +779,43 @@ def create_webcam_preview(camera_index: int):
camera.set(cv2.CAP_PROP_FRAME_WIDTH, PREVIEW_DEFAULT_WIDTH) camera.set(cv2.CAP_PROP_FRAME_WIDTH, PREVIEW_DEFAULT_WIDTH)
camera.set(cv2.CAP_PROP_FRAME_HEIGHT, PREVIEW_DEFAULT_HEIGHT) camera.set(cv2.CAP_PROP_FRAME_HEIGHT, PREVIEW_DEFAULT_HEIGHT)
camera.set(cv2.CAP_PROP_FPS, 60) camera.set(cv2.CAP_PROP_FPS, 60)
camera.set(cv2.CAP_PROP_BUFFERSIZE, 2) # Slightly larger buffer for smoother frames camera.set(cv2.CAP_PROP_BUFFERSIZE, 2)
preview_label.configure(width=PREVIEW_DEFAULT_WIDTH, height=PREVIEW_DEFAULT_HEIGHT) # Get actual camera dimensions
width = int(camera.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Initialize virtual camera with same dimensions
with pyvirtualcam.Camera(width=width, height=height, fps=30) as vcam:
print(f"Virtual camera created: {vcam.device}")
preview_label.configure(
width=PREVIEW_DEFAULT_WIDTH, height=PREVIEW_DEFAULT_HEIGHT
)
PREVIEW.deiconify() PREVIEW.deiconify()
frame_processors = get_frame_processors_modules(modules.globals.frame_processors) frame_processors = get_frame_processors_modules(
modules.globals.frame_processors
# Pre-load source face )
source_face = ( source_face = (
None None
if modules.globals.map_faces if modules.globals.map_faces
else get_one_face(cv2.imread(modules.globals.source_path)) else get_one_face(cv2.imread(modules.globals.source_path))
) )
# Performance tracking # Performance tracking variables
prev_time = time.time() prev_time = time.time()
fps_update_interval = 0.5 fps_update_interval = 0.5
frame_count = 0 frame_count = 0
fps = 0 fps = 0
process_scale = 0.75
# Processing settings - adjusted for better quality min_scale = 0.5
process_scale = 0.75 # Increased base scale for better quality max_scale = 1.0
min_scale = 0.5 # Minimum allowed scale skip_frames = 0
max_scale = 1.0 # Maximum allowed scale max_skip = 1
skip_frames = 0 # Counter for frame skipping target_fps = 24.0
max_skip = 1 # Reduced max skip for smoother video
target_fps = 24.0 # Slightly reduced target FPS for better quality
min_process_time = 1.0 / target_fps min_process_time = 1.0 / target_fps
scale_adjust_rate = 0.02 # More gradual scale adjustments scale_adjust_rate = 0.02
while camera.isOpened() and PREVIEW.state() != "withdrawn": while camera.isOpened() and PREVIEW.state() != "withdrawn":
ret, frame = camera.read() ret, frame = camera.read()
@ -818,16 +826,15 @@ def create_webcam_preview(camera_index: int):
current_time = time.time() current_time = time.time()
elapsed_time = current_time - prev_time elapsed_time = current_time - prev_time
# Skip frames if processing is too slow
if skip_frames > 0: if skip_frames > 0:
skip_frames -= 1 skip_frames -= 1
continue continue
# Create processing copy
if modules.globals.live_mirror: if modules.globals.live_mirror:
frame = cv2.flip(frame, 1) frame = cv2.flip(frame, 1)
# Scale down for processing with better interpolation # Process frame
try:
if process_scale != 1.0: if process_scale != 1.0:
proc_frame = cv2.resize( proc_frame = cv2.resize(
frame, frame,
@ -839,15 +846,16 @@ def create_webcam_preview(camera_index: int):
else: else:
proc_frame = frame.copy() proc_frame = frame.copy()
# Process frame # Apply face swap processing
try:
if not modules.globals.map_faces: if not modules.globals.map_faces:
for processor in frame_processors: for processor in frame_processors:
if processor.NAME == "DLC.FACE-ENHANCER": if processor.NAME == "DLC.FACE-ENHANCER":
if modules.globals.fp_ui["face_enhancer"]: if modules.globals.fp_ui["face_enhancer"]:
proc_frame = processor.process_frame(None, proc_frame) proc_frame = processor.process_frame(None, proc_frame)
else: else:
proc_frame = processor.process_frame(source_face, proc_frame) proc_frame = processor.process_frame(
source_face, proc_frame
)
else: else:
for processor in frame_processors: for processor in frame_processors:
if processor.NAME == "DLC.FACE-ENHANCER": if processor.NAME == "DLC.FACE-ENHANCER":
@ -856,7 +864,6 @@ def create_webcam_preview(camera_index: int):
else: else:
proc_frame = processor.process_frame_v2(proc_frame) proc_frame = processor.process_frame_v2(proc_frame)
# Scale back up if needed, using better interpolation
if process_scale != 1.0: if process_scale != 1.0:
proc_frame = cv2.resize( proc_frame = cv2.resize(
proc_frame, proc_frame,
@ -864,9 +871,9 @@ def create_webcam_preview(camera_index: int):
interpolation=cv2.INTER_LANCZOS4, interpolation=cv2.INTER_LANCZOS4,
) )
# More gradual performance-based scaling adjustments # Performance adjustments
process_time = time.time() - current_time process_time = time.time() - current_time
if process_time > min_process_time * 1.2: # Allow more tolerance if process_time > min_process_time * 1.2:
process_scale = max(min_scale, process_scale - scale_adjust_rate) process_scale = max(min_scale, process_scale - scale_adjust_rate)
skip_frames = min(max_skip, skip_frames + 1) skip_frames = min(max_skip, skip_frames + 1)
elif process_time < min_process_time * 0.8: elif process_time < min_process_time * 0.8:
@ -877,7 +884,7 @@ def create_webcam_preview(camera_index: int):
print(f"Frame processing error: {str(e)}") print(f"Frame processing error: {str(e)}")
proc_frame = frame proc_frame = frame
# Calculate and show FPS # Calculate FPS
if elapsed_time >= fps_update_interval: if elapsed_time >= fps_update_interval:
fps = frame_count / elapsed_time fps = frame_count / elapsed_time
frame_count = 0 frame_count = 0
@ -894,21 +901,30 @@ def create_webcam_preview(camera_index: int):
2, 2,
) )
# Update preview with better quality settings # Convert to RGB for both preview and virtual camera
if modules.globals.live_resizable:
proc_frame = fit_image_to_size(
proc_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
)
# Improve color handling
if modules.globals.color_correction: if modules.globals.color_correction:
proc_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB) output_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
else: else:
proc_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB) output_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
image = Image.fromarray(proc_frame) # Update preview
image = ctk.CTkImage(image, size=(proc_frame.shape[1], proc_frame.shape[0])) if modules.globals.live_resizable:
preview_frame = fit_image_to_size(
output_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
)
else:
preview_frame = output_frame
image = Image.fromarray(preview_frame)
image = ctk.CTkImage(
image, size=(preview_frame.shape[1], preview_frame.shape[0])
)
preview_label.configure(image=image) preview_label.configure(image=image)
# Send to virtual camera
vcam.send(output_frame)
vcam.sleep_until_next_frame()
ROOT.update() ROOT.update()
camera.release() camera.release()