Spaces:
Running
on
Zero
Running
on
Zero
| 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. | |
| 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() |