Dois
Dois

Reputation: 813

Recording video on the browser on iPhones/iOS (MediaRecorder)

I'm attempting to access the user's webcam/phone camera to record a video and mix audio in (imagine TikTok). So the user would press record, the audio would play (for the user to time their dance or whatever) and then when the audio ends, the recording stops, and they get to download it.

I can implement it just fine with MediaRecorder and CaptureStream for Chrome on Windows and Android, but no browser on iOS supports CaptureStream. Even MediaRecorder doesn't seem to work.

Does anyone know of a solution (that doesn't involve streaming the video to a server and mixing it there and downloading it back) to record video on iOS (it can certainly playback the stream on a video element) and mix it with audio?

Upvotes: 5

Views: 5739

Answers (3)

The Blind Hawk
The Blind Hawk

Reputation: 1676

2022 MediaRecorder for IOS

This is only a partial answer.
It only solves the issue of not being able to record the video and not the audio.

You will have to find another solution for the audio when merging it together with the video.

As of Safari 14.5 you can use MediaRecorder API.
Here is a working example using MediaRecorder and getUserMedia().

    startIOSVideoRecording: function() {
        console.log("setting up recorder");
        let self = this;
        this.data = [];

        if (MediaRecorder.isTypeSupported('video/mp4')) {
            // IOS does not support webm! So you have to use mp4.
            var options = {mimeType: 'video/mp4', videoBitsPerSecond : 1000000};
        } else {
            // video/webm is recommended for non IOS devices
            console.error("ERROR: Is this really an IOS device??");
            var options = {mimeType: 'video/webm'};
        }

        // this has to be a canvas element (not video!)
        let stream = document.getElementById('self-canvas').captureStream(15);
        this.recorder = new MediaRecorder(stream, options);

        this.recorder.ondataavailable = function(evt) {
            if (evt.data && evt.data.size > 0) {
                self.data.push(evt.data);
                console.log('chunk size: ' + evt.data.size);
            }
        }

        this.recorder.onstop = function(evt) {
            console.log('recorder stopping');
            var blob = new Blob(self.data, {type: "video/mp4"});
            // do something with the blob
        }
        this.recorder.start(1000);
        looper();
    },

Keep in mind that IOS still does not support video.captureStream() or video/webm at all, so you will need to set up a video element to connect the navigator.mediaDevices.getUserMedia() and a canvas element for the MediaRecorder.

Also (on IOS) you can only declare one and only one getUserMedia() stream at a time! So it is best to make the video element or the stream global with this.video or this.localStream in case other elements want to access the stream.

this.localStream = await navigator.mediaDevices.getUserMedia({
    audio: false,
    video: {width: 430, height: 430, facingMode: "user"}
});

let self = this;
self.video = document.createElement('video');
self.video.srcObject = this.localStream;
const canvas = document.getElementById("self-canvas");
const ctx = canvas.getContext('2d');

function draw_2DCanvas(){
    ctx.clearRect(0,0, canvas.width, canvas.height);
        ctx.drawImage(self.video, 0, 0, 430, 430);
    }
    requestAnimationFrame(draw_2DCanvas);
}
draw_2DCanvas();

On any other device you can just use video.captureStream() without having to go though the pain of setting up a canvas element.
Also video/webm is recommended in general.

Important Note
If you do not plan to edit the video in any way, directly passing the localStream to the MediaRecorder will also work, and it will also allow you to record the user's audio.

this.recorder = new MediaRecorder(this.localStream, options);

Upvotes: 4

Maxwell
Maxwell

Reputation: 546

I spent many days working on this problem until I discovered a suitable substitute.

<input type="file" accept="video/*" capture="user" />

Instead of recording in the browser directly (like you can on android and desktops) you can record directly to the phone on ios. And then immediately have it uploaded to the browser as if it was. Also don't forget to grab the data from onChange and depending on how you want to use it, you can change it to a dataURL as well.

Upvotes: 1

thijs
thijs

Reputation: 21

but no browser on iOS supports CaptureStream. Even MediaRecorder doesn't seem to work.

Mobile Safari on iOS 14.4 supports audio+video recording with MediaRecorder using video/mp4. See https://caniuse.com/?search=MediaRecorder for all browsers that support MediaRecorder.

Upvotes: 1

Related Questions