2

I have a React web app that gets the video URL from a server, then requests the video as a blob and tries to play this on an HTML video tag. I'm doing this because the client sometimes has issues with the internet and videos can stutter while playing, they'd rather wait longer for the video to load and then play it smoothly than have a choppy video. (I'm also saving the blob to IndexedDB as cache, but that's not related to the issue I'm having now, I'm just adding this as context but it has been disabled while I try to figure out this iOS problem)

I have a function to download the video, which then returns the Blob and a URL created from that blob object.

async function downloadVideo(videoUrl) {
  return new Promise(function(resolve, reject) {
    var req = new XMLHttpRequest();
    req.open('GET', videoUrl, true);
    req.responseType = 'blob';

    req.onload = function() {
      // Onload is triggered even on 404
      // so we need to check the status code
      if (this.status === 200) {
        var videoBlob = new Blob([this.response], { type: 'video/mp4' });
        console.log('Video blob?', videoBlob);
        var vid = { objBlob: videoBlob, vidURL: URL.createObjectURL(videoBlob) };
        // Video is now downloaded and converted into ObjectURL
        resolve(vid);
      } else {
        reject('Video download failed with status ', this.status);
      }
    };
    req.onerror = function() {
      reject('Unable to Download Video');
    };

    req.send();
  });
} 

And then I have the element that plays the blob video:

<video
    muted={true}
    autoPlay={true}
    loop={false}
    onError={err => {
      alert('Video load error. ' + err.target.error.iosMessage);
    }}
    src={downloadedVideo.url}
/>

That downloadedVideo.url is the blob object URL created on the DownloadVideo function

All of this works fine on desktop (Linux) and on Android, but the video doesn't play from the Blob on iOS devices. I've tried Safari, Chrome, and Firefox and the problem is the same. on iOS I can get the video Blob and create an URL from it, but when I pass it as src it doesn't work, all I can get from the error (a MediaError object) is the code, 4, but the message is undefined.

If instead of the blob I pass the original video URL as src, it works on all devices, but then I can't cache the video and this feature will have to be dropped.

I've tried several videos and made sure encoding was compatible with iOS.

I could not find anything stating that iOS is not compatible with Blob URLs for video, so this should work, but I can't figure out why it doesn't.

Sweta Jain
  • 3,248
  • 6
  • 30
  • 50
Lucas Dias
  • 31
  • 1
  • 4

3 Answers3

1

Save the captured video with the type of "mp4"

IMPORTANT >>> new Blob(vid, {type: "video/mp4", })

 const blobb = await new Blob(vid, {type: "video/mp4", }); // Important Line
ethry
  • 731
  • 6
  • 17
0

I have a similar problem, but only on iOS 15.x (it works fine till iOS 14.5)

I think it's a bug on iOS 15.x - see also https://developer.apple.com/forums/thread/693447

Guenter
  • 360
  • 1
  • 2
  • 8
0

There is a bug in webkit on iOS 15 builds, that do not include byte range headers to blob urls.

See: https://bugs.webkit.org/show_bug.cgi?id=232076 and Safari on iOS 15 inline video playback issues

As noted in the webkit issue, there is a workaround using a service worker. https://bug-232076-attachments.webkit.org/attachment.cgi?id=442151 Mind though, service workers do not work in WKWebView.

  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/31134684) – gru Feb 27 '22 at 21:20