File size: 2,745 Bytes
6f9faf9
5f82f10
379cab9
5f82f10
6f9faf9
77185d8
 
 
5f82f10
 
7e0b27a
5f82f10
 
7e0b27a
5f82f10
ee11946
77185d8
 
 
 
5f82f10
 
 
 
 
 
 
 
 
 
6f9faf9
 
5f82f10
 
ee11946
77185d8
ee11946
6f9faf9
 
77185d8
7e0b27a
 
 
 
 
ee11946
 
7e0b27a
 
77185d8
6f9faf9
77185d8
7e0b27a
 
 
6f9faf9
 
ee11946
 
bd6580c
6f9faf9
5f82f10
77185d8
 
 
 
5f82f10
c551a63
77185d8
6f9faf9
 
 
7e0b27a
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
import gradio as gr
import numpy as np
import spaces
from fastrtc import WebRTC, get_turn_credentials

# This is the core processing function that will be assigned to the GPU.
# It receives a generator (`frame_stream`) that yields frames from the webcam
# and it yields processed frames back to the output component.
@spaces.GPU
def process_frames_on_gpu(frame_stream):
    """
    This function runs as a persistent process on the GPU.
    It iterates over incoming frames, processes them, and yields the results.
    """
    print("🚀 GPU Frame processing loop started.")
    
    if frame_stream is None:
        print("Input stream is None, ending.")
        return

    # This loop will block until a new frame is available, making it reactive.
    for frame in frame_stream:
        if frame is not None:
            # This is where your GPU-intensive work would happen.
            flipped_frame = np.flip(frame, axis=(0, 1))
            
            # Yield the processed frame to the output stream.
            yield flipped_frame
            
    print("🛑 GPU Frame processing loop finished.")

# --- Gradio UI Layout ---
with gr.Blocks(theme=gr.themes.Soft(), title="FastRTC ZeroGPU Flipper") as demo:
    gr.Markdown("# 🚀 FastRTC Webcam Flipper for ZeroGPU")
    gr.Markdown(
        "*This version uses a separate button to trigger the stream, correctly using Gradio's streaming iterator pattern for ZeroGPU without conflicting with the `fastrtc` component's internal logic.*"
    )
    
    with gr.Row():
        with gr.Column(scale=1):
            gr.Markdown("### 1. Your Webcam Feed (Input)")
            webcam_input = WebRTC(
                label="Webcam Input",
                modality="video", 
                mode="send",
                width=640,
                height=480,
                rtc_configuration=get_turn_credentials(),
            )
            start_button = gr.Button("🚀 Start Processing Stream", variant="primary")
            
        with gr.Column(scale=1):
            gr.Markdown("### 2. Flipped Video (Output)")
            video_output = WebRTC(
                label="Flipped Output Stream",
                modality="video", 
                mode="receive",
                width=640,
                height=480,
                rtc_configuration=get_turn_credentials(),
            )
        
    # By using a button's `click` event to start the stream, we use Gradio's
    # standard streaming API, which correctly provides the iterator to our
    # decorated function without causing a conflict.
    start_button.click(
        fn=process_frames_on_gpu, 
        inputs=[webcam_input],
        outputs=[video_output]
    )

if __name__ == "__main__":
    demo.queue().launch()