Real-Time Webcam Streaming with Flask and Socket.IO

In this tutorial, we’ll walk through the process of creating a real-time webcam streaming application using Flask and Socket.IO. This project will allow us to capture video frames from a webcam and stream them live to a web browser.

Prerequisites

Before we begin, make sure you have Python installed on your system. Additionally, you’ll need to install several Python packages:

pip install Flask flask-socketio opencv-python-headless eventlet
  • Flask: A web framework for Python.
  • Flask-SocketIO: Integrates Socket.IO with Flask for real-time bidirectional communication.
  • OpenCV (headless): OpenCV library for capturing and processing video frames.
  • Eventlet: A concurrent networking library for handling multiple clients asynchronously.

Setting Up the Project

First, create a new directory for your project and navigate into it:

mkdir webcam_streaming
cd webcam_streaming

Project Structure

Your project structure should look like this:

webcam_streaming/

├── app.py
└── templates/
└── index.html

Writing the Flask Application (app.py)

Create a Python file app.py and add the following code:

# Import necessary libraries
import cv2
import base64
import eventlet
from flask import Flask, render_template
from flask_socketio import SocketIO

# Initialize Flask application and Socket.IO
app = Flask(__name__)
socketio = SocketIO(app)

@app.route('/')
def index():
"""Render the index.html template on the root URL."""
return render_template('index.html')

def capture_frames():
"""Capture frames from the default camera and emit them to clients."""
cap = cv2.VideoCapture(0)

if not cap.isOpened():
print("Error: Could not open camera.")
return

while True:
ret, frame = cap.read()
if not ret:
print("Error: Failed to capture frame.")
break

# Encode the frame as JPEG
_, buffer = cv2.imencode('.jpg', frame)
jpg_as_text = base64.b64encode(buffer).decode('utf-8')

# Emit the encoded frame to all connected clients
socketio.emit('frame', jpg_as_text)

eventlet.sleep(0.1)

cap.release()

if __name__ == '__main__':
socketio.start_background_task(capture_frames)
socketio.run(app, host='0.0.0.0', port=5000)

Creating the HTML Template (index.html)

Create a templates directory and within it, create index.html with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Live Camera Feed</title>
<!-- Socket.IO library for real-time communication -->
<script src="https://cdn.socket.io/4.3.2/socket.io.min.js"></script>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f0f0f0;
margin: 0;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
max-width: 800px;
background-color: #fff;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
padding: 20px;
border-radius: 12px;
text-align: center;
}
h1 {
color: #333;
font-size: 2.5rem;
margin-bottom: 20px;
}
#video-container {
display: flex;
justify-content: center;
margin-top: 20px;
position: relative;
overflow: hidden;
border-radius: 12px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
#video {
max-width: 100%;
height: auto;
transition: transform 0.3s ease-out;
}
#status {
margin-top: 20px;
color: #555;
font-size: 1.2rem;
}
.status-text {
display: inline-block;
padding: 8px 20px;
border-radius: 20px;
font-weight: bold;
text-transform: uppercase;
}
.status-connected {
background-color: #4CAF50;
color: white;
}
.status-disconnected {
background-color: #FF5722;
color: white;
}
</style>
</head>
<body>
<div class="container">
<h1>Live Camera Feed</h1>

<div id="video-container">
<img id="video" src="" alt="Live Camera Feed">
</div>

<div id="status">
<span id="status-text" class="status-text status-disconnected">Connecting...</span>
</div>
</div>

<script>
const socket = io();

socket.on('connect', () => {
console.log('Connected to server');
setStatus('Connected');
});

socket.on('frame', (jpg_as_text) => {
const img = document.getElementById('video');
img.src = 'data:image/jpeg;base64,' + jpg_as_text;
});

socket.on('disconnect', () => {
console.log('Disconnected from server');
setStatus('Disconnected');
});

function setStatus(status) {
const statusText = document.getElementById('status-text');
statusText.textContent = status;
if (status === 'Connected') {
statusText.classList.remove('status-disconnected');
statusText.classList.add('status-connected');
statusText.textContent = 'Connected';
} else {
statusText.classList.remove('status-connected');
statusText.classList.add('status-disconnected');
statusText.textContent = 'Disconnected';
}
}
</script>
</body>
</html>

Running the Application

To run the application, execute the following command:

python app.py

Open a web browser and navigate to http://localhost:5000. You should see the live camera feed from your default webcam.

Conclusion

In this tutorial, we’ve built a real-time webcam streaming application using Flask and Socket.IO. This project demonstrates the power of combining web frameworks with real-time communication libraries to create interactive web applications that stream data from devices like webcams. You can further extend this project by adding features such as multiple camera support, video recording, or integrating machine learning models for real-time image processing.

I hope you found this tutorial helpful for creating your own real-time webcam streaming application. Happy coding!

Leave a Comment

Your email address will not be published. Required fields are marked *

Shopping Basket