Я создаю крупномасштабное приложение для мониторинга видео, которое необходимо записывать веб-камеру пользователя и экран на срок до 3 часов и загружать потоки в режиме реального времени на хранилище Blob Blob. Цель состоит в том, чтобы обрабатывать до 10 000 одновременных пользователей. Он отправляет видео каждую секунду в течение двух отдельных веб -билетов. Из Azure Blob Storage для воспроизведения.
Несмотря на то, что основная функциональность существует, я сталкиваюсь с критическими проблемами с надежностью и воспроизведением. Продолжительность может быть намного короче, или видео просто резко останавливается, указывая на значительную потерю данных. Видео играет с самого начала, но вы не можете пропустить различные временные метки.let websocketWebcam = null;
let websocketScreen = null;
let webcamRecorder = null;
let screenRecorder = null;
let isRecording = false;
// Connects to a WebSocket endpoint
function connectWebSocket(streamType, sessionId) {
// Replaced 'your-backend-domain.com' with your actual domain
const wsUrl = `wss://your-backend-domain.com/upload_video/${sessionId}_${streamType}`;
const ws = new WebSocket(wsUrl);
ws.onopen = () => console.log(`WebSocket connected: ${streamType}`);
ws.onclose = () => console.log(`WebSocket closed: ${streamType}`);
ws.onerror = error => console.error(`WebSocket error (${streamType}):`, error);
return ws;
}
// Periodically reconnects WebSockets to keep the connection alive
function reconnectWebSockets(sessionId) {
console.log("Attempting to reconnect WebSockets...");
if (websocketWebcam) websocketWebcam.close();
if (websocketScreen) websocketScreen.close();
websocketWebcam = connectWebSocket("webcam", sessionId);
websocketScreen = connectWebSocket("screen", sessionId);
console.log("WebSockets reconnected.");
}
// Starts the recording process
async function startRecording(sessionId) {
try {
isRecording = true;
// Assume webcamStream and screenStream are already acquired from navigator.mediaDevices
websocketWebcam = connectWebSocket("webcam", sessionId);
websocketScreen = connectWebSocket("screen", sessionId);
// Recorder for webcam stream
webcamRecorder = new MediaRecorder(webcamStream, { mimeType: "video/webm; codecs=vp9" });
webcamRecorder.ondataavailable = event => {
if (event.data.size > 0) sendToWebSocket(event.data, websocketWebcam);
};
webcamRecorder.start(1000); // Send data every 1 second
// Recorder for screen stream
screenRecorder = new MediaRecorder(screenStream, { mimeType: "video/webm; codecs=vp9" });
screenRecorder.ondataavailable = event => {
if (event.data.size > 0) sendToWebSocket(event.data, websocketScreen);
};
screenRecorder.start(1000); // Send data every 1 second
console.log("Recording started for session:", sessionId);
// Set interval to reconnect WebSockets every 45 minutes
setInterval(() => reconnectWebSockets(sessionId), 2700000); // 45 minutes
} catch (error) {
console.error("Error starting recording:", error);
}
}
// Sends a blob of data to the WebSocket
function sendToWebSocket(blob, ws) {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(blob);
} else {
console.warn("WebSocket not open. Data chunk might be lost.");
// Simple retry logic, which might not be robust enough
setTimeout(() => sendToWebSocket(blob, ws), 1000);
}
}
< /code>
import asyncio
from fastapi import FastAPI, WebSocket, HTTPException, Request
from fastapi.responses import StreamingResponse, Response
from azure.storage.blob import BlobServiceClient, BlobClient, AppendBlobService
import re
# Assume blob_service_client and container_name are configured
# blob_service_client = BlobServiceClient.from_connection_string(...)
# container_name = "videos"
app = FastAPI()
@app.websocket("/upload_video/{session_id}")
async def upload_video(websocket: WebSocket, session_id: str):
""" WebSocket endpoint to receive video chunks and append to an Append Blob """
await websocket.accept()
blob_name = f"{session_id}.webm"
blob_client = blob_service_client.get_blob_client(container=container_name, blob=blob_name)
try:
# Create Append Blob if it doesn't exist
if not blob_client.exists():
blob_client.create_append_blob()
except Exception as e:
print(f"Error initializing blob: {e}")
await websocket.close()
return
try:
while True:
data = await websocket.receive_bytes()
blob_client.append_block(data)
except Exception as e:
print(f"Error during video upload for session {session_id}: {e}")
finally:
print(f"Upload completed for session {session_id}")
await websocket.close()
# Video streaming endpoint (simplified for brevity)
@app.get("/video/{session_id}")
async def get_video(session_id: str, request: Request):
""" Video Streaming API with Range Support """
blob_client = blob_service_client.get_blob_client(container=container_name, blob=f"{session_id}.webm")
try:
blob_properties = blob_client.get_blob_properties()
file_size = blob_properties.size
range_header = request.headers.get("Range")
start, end = 0, file_size - 1
status_code = 200 # Full content
if range_header:
match = re.search(r"bytes=(\d+)-(\d*)", range_header)
if match:
start = int(match.group(1))
end = int(match.group(2)) if match.group(2) else file_size - 1
status_code = 206 # Partial content
length = end - start + 1
headers = {
"Content-Range": f"bytes {start}-{end}/{file_size}",
"Content-Length": str(length),
"Accept-Ranges": "bytes",
"Content-Type": "video/webm",
}
def stream_video():
stream = blob_client.download_blob(offset=start, length=length)
yield from stream.chunks()
return StreamingResponse(stream_video(), headers=headers, status_code=status_code)
except Exception as e:
raise HTTPException(status_code=404, detail="Video not found or error in streaming")
< /code>
My Questions
How to Create a Seekable WEBM file? My current process of appending raw MediaRecorder chunks results in a webm file without the proper metadata (like a Cues element) needed for seeking. How can I fix this? Should I be post-processing the file on the server (e.g., with FFmpeg) after the stream ends to inject the right metadata? Is there a way to generate this metadata on the client?
How to Prevent Data Loss? My strategy of reconnecting the WebSocket every 45 minutes feels wrong and is likely a major source of data loss. What is a more robust method for maintaining a long-running, stable connection for 3+ hours? Should I implement a heartbeat (ping/pong) mechanism instead?
**Is Append Blob the Right Architecture? **Is streaming to a single, large Append Blob for 3 hours a sound strategy? Or would it be more reliable to create smaller, timed video chunks (e.g., a new blob every 5 minutes) and then create a manifest file or concatenate them later?
Подробнее здесь: https://stackoverflow.com/questions/796 ... ebsocket-t
Неполное и невидимое видео Webm от MediareCorder, транслируемого через WebSocket в Fastapi и Azure Blob Blob ⇐ Javascript
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение