Неполное и невидимое видео Webm от MediareCorder, транслируемого через WebSocket в Fastapi и Azure Blob BlobJavascript

Форум по Javascript
Ответить Пред. темаСлед. тема
Anonymous
 Неполное и невидимое видео Webm от MediareCorder, транслируемого через WebSocket в Fastapi и Azure Blob Blob

Сообщение Anonymous »

Я создаю крупномасштабное приложение для мониторинга видео, которое необходимо записывать веб-камеру пользователя и экран на срок до 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
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Javascript»