如何在不支持MediaRecorder的Safari 11中实现HTML5视频录制?
Got it, I’ve run into this exact headache with Safari 11 before—native MediaRecorder support was missing entirely back then, but we can work around it using Canvas-based frame capture and a lightweight video synthesis library. Let’s walk through how to make this work:
核心思路
Since Safari 11 doesn’t support the MediaRecorder API, we’ll:
- Feed the
getUserMedia()stream into a video element (which you already have working) - Mirror that video stream to a Canvas element
- Capture individual frames from the Canvas at regular intervals
- Synthesize those frames into a playable video file using a JS library
Step 1: Set Up Video & Canvas Elements
First, make sure you have the necessary HTML elements, and bind your media stream to both the video and canvas:
<video id="liveVideo" autoplay playsinline></video> <canvas id="captureCanvas" style="display: none;"></canvas> <button id="startBtn">Start Recording</button> <button id="stopBtn">Stop Recording</button>
let mediaStream; let videoElement = document.getElementById('liveVideo'); let canvas = document.getElementById('captureCanvas'); let ctx = canvas.getContext('2d'); // Get media stream (you already have this part) navigator.mediaDevices.getUserMedia({ video: true, audio: false }) .then(stream => { mediaStream = stream; videoElement.srcObject = stream; videoElement.onloadedmetadata = () => { // Match canvas size to video resolution canvas.width = videoElement.videoWidth; canvas.height = videoElement.videoHeight; }; }) .catch(err => console.error('Failed to get stream:', err));
Step 2: Capture Frames During Recording
We’ll use setInterval to grab frames from the Canvas at a consistent frame rate (e.g., 30fps or 60fps) and store them as Blobs:
let captureInterval; let capturedFrames = []; // Start recording logic document.getElementById('startBtn').addEventListener('click', () => { capturedFrames = []; // Reset frame array // Capture a frame every ~33ms for 30fps (adjust for 60fps by using 16ms) captureInterval = setInterval(() => { // Draw current video frame to canvas ctx.drawImage(videoElement, 0, 0, canvas.width, canvas.height); // Convert canvas to PNG Blob and store canvas.toBlob(blob => { capturedFrames.push(blob); }, 'image/png'); }, 33); });
Step 3: Synthesize Frames into Video
Once recording stops, we need to turn those frame Blobs into a video file. For this, use a lightweight library like Whammy.js (which creates WebM videos) or FFmpeg.js (for more flexibility, like MP4 output):
Example with Whammy.js
document.getElementById('stopBtn').addEventListener('click', () => { clearInterval(captureInterval); // Create a Whammy Video instance with your target frame rate const videoCreator = new Whammy.Video(30); // Add all captured frames to the video capturedFrames.forEach(frameBlob => { videoCreator.add(frameBlob); }); // Compile the frames into a single video Blob const finalVideoBlob = videoCreator.compile(); // Create a download link for the video const downloadLink = document.createElement('a'); downloadLink.href = URL.createObjectURL(finalVideoBlob); downloadLink.download = 'safari-recorded-video.webm'; downloadLink.click(); // Clean up URL.revokeObjectURL(downloadLink.href); });
Step 4: Handling Audio (If Needed)
The above setup only captures video. If you need audio too:
- Use
AudioContextandMediaStreamAudioSourceNodeto capture raw audio data while recording frames - Sync the audio samples with your video frames
- Use FFmpeg.js to merge the audio and video into a single file (Whammy.js doesn’t support audio)
This is more complex, but FFmpeg.js handles the syncing and format conversion seamlessly.
Key Notes for Safari 11
- Canvas capture performance: Safari 11 isn’t the fastest with Canvas operations, so you might need to lower the video resolution or frame rate if you see lag.
- Video format: Whammy.js outputs WebM, which Safari 11 can’t play natively, but users can download and play it in other players or you can convert it to MP4 with FFmpeg.js.
- Memory: Storing hundreds of frame Blobs can use a lot of memory—consider processing frames in batches instead of storing all at once if you’re recording long videos.
内容的提问来源于stack exchange,提问作者Archna Rangrej




