[SOLVED] iOS Videotexture not playing

I had an issue with the VideoTexture that was only affecting iOS, the video would start fine on Windows, Mac and Android with no issues, only iOS gave me a black Texture instead and no real debugging output.

It took me a couple of hours to finally figure out what the issue was, so I wanted to share in case anyone else runs into this problem (as I didn’t really find anything about it here on the forum)

I’m using videoTexture.js from the tutorial page without any modifications:

var VideoTexture = pc.createScript('videoTexture');

VideoTexture.attributes.add('videoAsset', {
    title: 'Video Asset',
    description: 'MP4 video asset to play back on this video texture.',
    type: 'asset'
});

VideoTexture.attributes.add('videoUrl', {
    title: 'Video Url',
    description: 'URL to use if there is video asset selected',
    type: 'string'
});

VideoTexture.attributes.add('playEvent', {
    title: 'Play Event',
    description: 'Event that is fired as soon as the video texture is ready to play.',
    type: 'string',
    default: ''
});

// initialize code called once per entity
VideoTexture.prototype.initialize = function() {
    var app = this.app;
    
    // Create HTML Video Element to play the video
    var video = document.createElement('video');
    video.loop = true;

    // muted attribute is required for videos to autoplay
    video.muted = true;

    // critical for iOS or the video won't initially play, and will go fullscreen when playing
    video.playsInline = true;
    
    // needed because the video is being hosted on a different server url
    video.crossOrigin = "anonymous";
    
    // autoplay the video
    video.autoplay = true;

    // iOS video texture playback requires that you add the video to the DOMParser
    // with at least 1x1 as the video's dimensions
    var style = video.style;
    style.width = '1px';
    style.height = '1px';
    style.position = 'absolute';
    style.opacity = '0';
    style.zIndex = '-1000';
    style.pointerEvents = 'none';

    document.body.appendChild(video);

    // Create a texture to hold the video frame data            
    this.videoTexture = new pc.Texture(app.graphicsDevice, {
        format: pc.PIXELFORMAT_R8_G8_B8,
        minFilter: pc.FILTER_LINEAR_MIPMAP_LINEAR,
        magFilter: pc.FILTER_LINEAR,
        addressU: pc.ADDRESS_CLAMP_TO_EDGE,
        addressV: pc.ADDRESS_CLAMP_TO_EDGE,
        mipmaps: true
    });
    this.videoTexture.setSource(video);

    video.addEventListener('canplaythrough', function (e) {
        app.fire(this.playEvent, this.videoTexture);
        video.play();
    }.bind(this));
        
    // set video source
    video.src = this.videoAsset ? this.videoAsset.getFileUrl() : this.videoUrl;    
    
    document.body.appendChild(video);
    video.load();


    this.on('destroy', function() {
        this.videoTexture.destroy();
        video.remove();
    }, this);
};

// update code called every frame
VideoTexture.prototype.update = function(dt) {
    // Transfer the latest video frame to the video texture
    this.videoTexture.upload();
};

The script should work fine as is, the issue I was facing was that I converted the video to a webm file thinking I was smart and could save a couple MB through compression (webm: 8,5MB, mp4: 12,3MB)

However apparently iOS doesn’t like that and kinda demands mp4 - after trying to debug the issue without any luck (

video.addEventListener('error', function failed(e)
    {
        console.error("Error Loading Video: ",e);
    });

wasn’t really giving any helpful info either) I finally found out about that limitation.

So long story short: Videos for use in Video Textures should best be kept in MP4 Format