Broadcast virtual webcam
							parent
							
								
									4aadfdf2ca
								
							
						
					
					
						commit
						ceaf676b95
					
				
								
									
									
										
											242
										
									
									modules/ui.py
									
									
									
									
								
								
							
							
										
											242
										
									
									modules/ui.py
									
									
									
									
								| 
						 | 
					@ -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,140 +779,156 @@ 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
 | 
				
			||||||
    PREVIEW.deiconify()
 | 
					    width = int(camera.get(cv2.CAP_PROP_FRAME_WIDTH))
 | 
				
			||||||
 | 
					    height = int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    frame_processors = get_frame_processors_modules(modules.globals.frame_processors)
 | 
					    # Initialize virtual camera with same dimensions
 | 
				
			||||||
 | 
					    with pyvirtualcam.Camera(width=width, height=height, fps=30) as vcam:
 | 
				
			||||||
 | 
					        print(f"Virtual camera created: {vcam.device}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Pre-load source face
 | 
					        preview_label.configure(
 | 
				
			||||||
    source_face = (
 | 
					            width=PREVIEW_DEFAULT_WIDTH, height=PREVIEW_DEFAULT_HEIGHT
 | 
				
			||||||
        None
 | 
					        )
 | 
				
			||||||
        if modules.globals.map_faces
 | 
					        PREVIEW.deiconify()
 | 
				
			||||||
        else get_one_face(cv2.imread(modules.globals.source_path))
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Performance tracking
 | 
					        frame_processors = get_frame_processors_modules(
 | 
				
			||||||
    prev_time = time.time()
 | 
					            modules.globals.frame_processors
 | 
				
			||||||
    fps_update_interval = 0.5
 | 
					        )
 | 
				
			||||||
    frame_count = 0
 | 
					        source_face = (
 | 
				
			||||||
    fps = 0
 | 
					            None
 | 
				
			||||||
 | 
					            if modules.globals.map_faces
 | 
				
			||||||
 | 
					            else get_one_face(cv2.imread(modules.globals.source_path))
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Processing settings - adjusted for better quality
 | 
					        # Performance tracking variables
 | 
				
			||||||
    process_scale = 0.75  # Increased base scale for better quality
 | 
					        prev_time = time.time()
 | 
				
			||||||
    min_scale = 0.5  # Minimum allowed scale
 | 
					        fps_update_interval = 0.5
 | 
				
			||||||
    max_scale = 1.0  # Maximum allowed scale
 | 
					        frame_count = 0
 | 
				
			||||||
    skip_frames = 0  # Counter for frame skipping
 | 
					        fps = 0
 | 
				
			||||||
    max_skip = 1  # Reduced max skip for smoother video
 | 
					        process_scale = 0.75
 | 
				
			||||||
    target_fps = 24.0  # Slightly reduced target FPS for better quality
 | 
					        min_scale = 0.5
 | 
				
			||||||
    min_process_time = 1.0 / target_fps
 | 
					        max_scale = 1.0
 | 
				
			||||||
    scale_adjust_rate = 0.02  # More gradual scale adjustments
 | 
					        skip_frames = 0
 | 
				
			||||||
 | 
					        max_skip = 1
 | 
				
			||||||
 | 
					        target_fps = 24.0
 | 
				
			||||||
 | 
					        min_process_time = 1.0 / target_fps
 | 
				
			||||||
 | 
					        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()
 | 
				
			||||||
        if not ret:
 | 
					            if not ret:
 | 
				
			||||||
            break
 | 
					                break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        frame_count += 1
 | 
					            frame_count += 1
 | 
				
			||||||
        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
 | 
				
			||||||
        if process_scale != 1.0:
 | 
					            try:
 | 
				
			||||||
            proc_frame = cv2.resize(
 | 
					                if process_scale != 1.0:
 | 
				
			||||||
                frame,
 | 
					                    proc_frame = cv2.resize(
 | 
				
			||||||
                None,
 | 
					                        frame,
 | 
				
			||||||
                fx=process_scale,
 | 
					                        None,
 | 
				
			||||||
                fy=process_scale,
 | 
					                        fx=process_scale,
 | 
				
			||||||
                interpolation=cv2.INTER_AREA,
 | 
					                        fy=process_scale,
 | 
				
			||||||
            )
 | 
					                        interpolation=cv2.INTER_AREA,
 | 
				
			||||||
        else:
 | 
					                    )
 | 
				
			||||||
            proc_frame = frame.copy()
 | 
					                else:
 | 
				
			||||||
 | 
					                    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(
 | 
				
			||||||
                        proc_frame = processor.process_frame(source_face, proc_frame)
 | 
					                                source_face, proc_frame
 | 
				
			||||||
            else:
 | 
					                            )
 | 
				
			||||||
                for processor in frame_processors:
 | 
					                else:
 | 
				
			||||||
                    if processor.NAME == "DLC.FACE-ENHANCER":
 | 
					                    for processor in frame_processors:
 | 
				
			||||||
                        if modules.globals.fp_ui["face_enhancer"]:
 | 
					                        if processor.NAME == "DLC.FACE-ENHANCER":
 | 
				
			||||||
 | 
					                            if modules.globals.fp_ui["face_enhancer"]:
 | 
				
			||||||
 | 
					                                proc_frame = processor.process_frame_v2(proc_frame)
 | 
				
			||||||
 | 
					                        else:
 | 
				
			||||||
                            proc_frame = processor.process_frame_v2(proc_frame)
 | 
					                            proc_frame = processor.process_frame_v2(proc_frame)
 | 
				
			||||||
                    else:
 | 
					 | 
				
			||||||
                        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,
 | 
				
			||||||
 | 
					                        (frame.shape[1], frame.shape[0]),
 | 
				
			||||||
 | 
					                        interpolation=cv2.INTER_LANCZOS4,
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Performance adjustments
 | 
				
			||||||
 | 
					                process_time = time.time() - current_time
 | 
				
			||||||
 | 
					                if process_time > min_process_time * 1.2:
 | 
				
			||||||
 | 
					                    process_scale = max(min_scale, process_scale - scale_adjust_rate)
 | 
				
			||||||
 | 
					                    skip_frames = min(max_skip, skip_frames + 1)
 | 
				
			||||||
 | 
					                elif process_time < min_process_time * 0.8:
 | 
				
			||||||
 | 
					                    process_scale = min(max_scale, process_scale + scale_adjust_rate)
 | 
				
			||||||
 | 
					                    skip_frames = max(0, skip_frames - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                print(f"Frame processing error: {str(e)}")
 | 
				
			||||||
 | 
					                proc_frame = frame
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Calculate FPS
 | 
				
			||||||
 | 
					            if elapsed_time >= fps_update_interval:
 | 
				
			||||||
 | 
					                fps = frame_count / elapsed_time
 | 
				
			||||||
 | 
					                frame_count = 0
 | 
				
			||||||
 | 
					                prev_time = current_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if modules.globals.show_fps:
 | 
				
			||||||
 | 
					                cv2.putText(
 | 
				
			||||||
                    proc_frame,
 | 
					                    proc_frame,
 | 
				
			||||||
                    (frame.shape[1], frame.shape[0]),
 | 
					                    f"FPS: {fps:.1f}",
 | 
				
			||||||
                    interpolation=cv2.INTER_LANCZOS4,
 | 
					                    (10, 30),
 | 
				
			||||||
 | 
					                    cv2.FONT_HERSHEY_SIMPLEX,
 | 
				
			||||||
 | 
					                    1,
 | 
				
			||||||
 | 
					                    (0, 255, 0),
 | 
				
			||||||
 | 
					                    2,
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # More gradual performance-based scaling adjustments
 | 
					            # Convert to RGB for both preview and virtual camera
 | 
				
			||||||
            process_time = time.time() - current_time
 | 
					            if modules.globals.color_correction:
 | 
				
			||||||
            if process_time > min_process_time * 1.2:  # Allow more tolerance
 | 
					                output_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
 | 
				
			||||||
                process_scale = max(min_scale, process_scale - scale_adjust_rate)
 | 
					            else:
 | 
				
			||||||
                skip_frames = min(max_skip, skip_frames + 1)
 | 
					                output_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
 | 
				
			||||||
            elif process_time < min_process_time * 0.8:
 | 
					 | 
				
			||||||
                process_scale = min(max_scale, process_scale + scale_adjust_rate)
 | 
					 | 
				
			||||||
                skip_frames = max(0, skip_frames - 1)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        except Exception as e:
 | 
					            # Update preview
 | 
				
			||||||
            print(f"Frame processing error: {str(e)}")
 | 
					            if modules.globals.live_resizable:
 | 
				
			||||||
            proc_frame = frame
 | 
					                preview_frame = fit_image_to_size(
 | 
				
			||||||
 | 
					                    output_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                preview_frame = output_frame
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Calculate and show FPS
 | 
					            image = Image.fromarray(preview_frame)
 | 
				
			||||||
        if elapsed_time >= fps_update_interval:
 | 
					            image = ctk.CTkImage(
 | 
				
			||||||
            fps = frame_count / elapsed_time
 | 
					                image, size=(preview_frame.shape[1], preview_frame.shape[0])
 | 
				
			||||||
            frame_count = 0
 | 
					 | 
				
			||||||
            prev_time = current_time
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if modules.globals.show_fps:
 | 
					 | 
				
			||||||
            cv2.putText(
 | 
					 | 
				
			||||||
                proc_frame,
 | 
					 | 
				
			||||||
                f"FPS: {fps:.1f}",
 | 
					 | 
				
			||||||
                (10, 30),
 | 
					 | 
				
			||||||
                cv2.FONT_HERSHEY_SIMPLEX,
 | 
					 | 
				
			||||||
                1,
 | 
					 | 
				
			||||||
                (0, 255, 0),
 | 
					 | 
				
			||||||
                2,
 | 
					 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					            preview_label.configure(image=image)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Update preview with better quality settings
 | 
					            # Send to virtual camera
 | 
				
			||||||
        if modules.globals.live_resizable:
 | 
					            vcam.send(output_frame)
 | 
				
			||||||
            proc_frame = fit_image_to_size(
 | 
					            vcam.sleep_until_next_frame()
 | 
				
			||||||
                proc_frame, PREVIEW.winfo_width(), PREVIEW.winfo_height()
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Improve color handling
 | 
					            ROOT.update()
 | 
				
			||||||
        if modules.globals.color_correction:
 | 
					 | 
				
			||||||
            proc_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            proc_frame = cv2.cvtColor(proc_frame, cv2.COLOR_BGR2RGB)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        image = Image.fromarray(proc_frame)
 | 
					        camera.release()
 | 
				
			||||||
        image = ctk.CTkImage(image, size=(proc_frame.shape[1], proc_frame.shape[0]))
 | 
					        PREVIEW.withdraw()
 | 
				
			||||||
        preview_label.configure(image=image)
 | 
					 | 
				
			||||||
        ROOT.update()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    camera.release()
 | 
					 | 
				
			||||||
    PREVIEW.withdraw()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_source_target_popup_for_webcam(
 | 
					def create_source_target_popup_for_webcam(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue