Search code examples
three.jssafaricorswebglvimeo

Three.js webgl video texture CORS issue on safari


In my vuejs nuxt static site hosted on netlify, I'm trying to use a mp4 video hosted on Vimeo Pro as a video texture in three.js with the following (simplified version)

// create video dom element
let video_ele = document.createElement('video')
video_ele.className = 'video_texture'
video_ele.setAttribute('playsinline', true)
video_ele.muted = true
video_ele.loop = true
video_ele.autoplay = true
video_ele.crossOrigin = 'anonymous'
video_ele.src = "https://vimeo-video-url-here.....mp4"
document.body.appendChild(video_ele)


// create video texture from video
let video_texture = new THREE.VideoTexture(video_ele)
video_texture.minFilter = THREE.LinearFilter
video_texture.magFilter = THREE.LinearFilter
video_texture.format = THREE.RGBFormat

// map video texture to material
material = new THREE.MeshStandardMaterial({
    color: 0xa8a8a8,
    map: video_texture
})

Everything else works fine on chrome, firefox and also chrome mobile browser. but in Safari 13 on mac os and ios 13, i get this error thrown in the console

THREE.WebGLState:
SecurityError: The operation is insecure. 

I tried replacing the vimeo video with urls of other videos hosted elsewhere and i get same error in safari only.

I'm pretty sure its a CORS issue because when i replace the vimeo or external url with a static video hosted within same host (netlify), it works fine.

I also tried appending a timestamp to the video url just to be sure its not a cache issue, but still no luck

Wondering how can i make this work with an externally hosted video like vimeo?


Solution

  • Upon further testing, it seems to me that the issue was caused by the 302 redirect to their CDN that happens when you use a vimeo file url.

    As @gman pointed out, there's a similar issue on Soundclound and i found that the solution provided there worked for my case too. How to get Safari 12 to process audio from soundcloud?

    I solved it by making an async fetch request to get the CDN url and then passing it to the video.src. Works in safari mac and ios (13) now now!

      async function getMediaURLForTrack(texture_to_update, passed_url) {
        await fetch(passed_url, {
          method: 'HEAD'
        })
        .then((response) => {
          texture_to_update.src = response.url
        });
      }