Shenya
Shenya

Reputation: 344

Media stream recording only doesn't work on iPhone Safari. Do I have to consider something especially?

I want to record video from smartphone cam by using the WebRTC and the script of github.io (demo: https://webrtc.github.io/samples/src/content/getusermedia/record/). But the demo link just doesn't work on iPhone Safari.

I tried also the source script here

Here is the original code of the record demo:

'use strict';

/* globals MediaRecorder */

const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', handleSourceOpen, false);
let mediaRecorder;
let recordedBlobs;
let sourceBuffer;

const errorMsgElement = document.querySelector('span#errorMsg');
const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
  if (recordButton.textContent === 'Start Recording') {
    startRecording();
  } else {
    stopRecording();
    recordButton.textContent = 'Start Recording';
    playButton.disabled = false;
    downloadButton.disabled = false;
  }
});

const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
  const superBuffer = new Blob(recordedBlobs, {type: 'video/webm'});
  recordedVideo.src = null;
  recordedVideo.srcObject = null;
  recordedVideo.src = window.URL.createObjectURL(superBuffer);
  recordedVideo.controls = true;
  recordedVideo.play();
});

const downloadButton = document.querySelector('button#download');
downloadButton.addEventListener('click', () => {
  const blob = new Blob(recordedBlobs, {type: 'video/webm'});
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.style.display = 'none';
  a.href = url;
  a.download = 'test.webm';
  document.body.appendChild(a);
  a.click();
  setTimeout(() => {
    document.body.removeChild(a);
    window.URL.revokeObjectURL(url);
  }, 100);
});

function handleSourceOpen(event) {
  console.log('MediaSource opened');
  sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"');
  console.log('Source buffer: ', sourceBuffer);
}

function handleDataAvailable(event) {
  if (event.data && event.data.size > 0) {
    recordedBlobs.push(event.data);
  }
}

function startRecording() {
  recordedBlobs = [];
  let options = {mimeType: 'video/webm;codecs=vp9'};
  if (!MediaRecorder.isTypeSupported(options.mimeType)) {
    console.error(`${options.mimeType} is not Supported`);
    errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
    options = {mimeType: 'video/webm;codecs=vp8'};
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
      console.error(`${options.mimeType} is not Supported`);
      errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
      options = {mimeType: 'video/webm'};
      if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        console.error(`${options.mimeType} is not Supported`);
        errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
        options = {mimeType: ''};
      }
    }
  }

  try {
    mediaRecorder = new MediaRecorder(window.stream, options);
  } catch (e) {
    console.error('Exception while creating MediaRecorder:', e);
    errorMsgElement.innerHTML = `Exception while creating MediaRecorder: ${JSON.stringify(e)}`;
    return;
  }

  console.log('Created MediaRecorder', mediaRecorder, 'with options', options);
  recordButton.textContent = 'Stop Recording';
  playButton.disabled = true;
  downloadButton.disabled = true;
  mediaRecorder.onstop = (event) => {
    console.log('Recorder stopped: ', event);
  };
  mediaRecorder.ondataavailable = handleDataAvailable;
  mediaRecorder.start(10); // collect 10ms of data
  console.log('MediaRecorder started', mediaRecorder);
}

function stopRecording() {
  mediaRecorder.stop();
  console.log('Recorded Blobs: ', recordedBlobs);
}

function handleSuccess(stream) {
  recordButton.disabled = false;
  console.log('getUserMedia() got stream:', stream);
  window.stream = stream;

  const gumVideo = document.querySelector('video#gum');
  gumVideo.srcObject = stream;
}

async function init(constraints) {
  try {
    const stream = await navigator.mediaDevices.getUserMedia(constraints);
    handleSuccess(stream);
  } catch (e) {
    console.error('navigator.getUserMedia error:', e);
    errorMsgElement.innerHTML = `navigator.getUserMedia error:${e.toString()}`;
  }
}

document.querySelector('button#start').addEventListener('click', async () => {
  const hasEchoCancellation = document.querySelector('#echoCancellation').checked;
  const constraints = {
    audio: {
      echoCancellation: {exact: hasEchoCancellation}
    },
    video: {
      width: 1280, height: 720
    }
  };
  console.log('Using media constraints:', constraints);
  await init(constraints);
});

I also tested the script in fiddle on different smartphones. It only doesn't work on the iPhone apparently.

Upvotes: 4

Views: 6656

Answers (3)

Maxwell
Maxwell

Reputation: 546

I know this might not be answering OP's question, but I spent many days working on this problem until I discovered it was futile. Then I resorted to this solution as 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: 0

Ranjeet Eppakayala
Ranjeet Eppakayala

Reputation: 3058

Check this out: https://en.wikipedia.org/wiki/WebM WebM video working on safari too.

There are 2 ways -

Solution #1 (NOT GUARANTEED) :

  • Try with VP8 codec like so: new Blob(recordedBlobs, {'video/webm;codecs=vp8'});

Solution #2 (GUARANTEED) :

  • Record with video/webm;codecs=h264, as MP4 and Webm supports h264 codec.

    check for available containers here -> video_codec_and_container

  • Now you just need to change the video container from WEBM to MP4. Which is way easy using tool such as ffmpeg - Note: copy the video codec, so that re-encoding will be avoided

    ffmpeg -i INPUT.webm -codec:v copy OUTPUT.mp4
    

Recommendation: Convert videos to MP4 because WEBM has support for limited browsers.

Upvotes: 3

Edy
Edy

Reputation: 21

Exactly, mediaSource isnt available on iOS Safari yet, although its in Experimental state. Check this thread for more info: https://bugs.webkit.org/show_bug.cgi?id=85851

Upvotes: 2

Related Questions