Pixi.js: videoTexture.source.play() launches fullscreen on IOS

Created on 14 Oct 2016  ·  25Comments  ·  Source: pixijs/pixi.js

@englercj from yesterdays convo on #2873
this is on #dev branch.
I have a video element hidden on the page no autoplay or anything.

I create the canvas and so forth do all the things necessary and it works fine in desktop/android browsers.

when i hit videoTexture.source.play() it opens FS on ios 9. I think the only solution is to step the video frame by frame with request animation frame. I just wasn't sure if this is implemented into pixijs. Thanks.

👍 Not A Bug 💾 v4.x (Legacy) 📢 Accepting PRs 🕷 Bug

Most helpful comment

omfg unbelievable! that totally fixes it. fml. thank you.

All 25 comments

Now that I looked at the issue list, is this similar to #3078?

3066 is more accurate i think.

for the record I am using (https://github.com/bfred-it/iphone-inline-video) to get a video to play inline by itself on ios 9. This works, however it videoTexture doesn't seem to draw the frames on ios9. that lib create a requestanimationframe call and steps through the video frame by frame.

Hmm, interesting. This is tough one for me since I don't own an iOS device. Hopefully one of the other devs can get this knocked out soon!

@pr1ntr On the previous thread for this I described how ios9 and under cannot play a video without it going full screen. That is part of how Apple designed them.

Now, there is this third party polyfill lib that does some clever shenanigans to actually allow this behaviour. What it does I believe is beyond the scope of PIXI, so I couldn't see it ever being included within PIXI itself.

But.... I have surrounded myself with iPhones of various os versons, and will have a play with this lib. I'll get back to you with any findings :)

Hi, thanks for investigating. The behavior im finding is that the update on the texture isn't updating if if the video is firing its events as normal. That polyfill I am using should be firing all events normally, it just has its own voodoo requestAnimationFrame tick to push the video along. When using it with just a <video> tag it actually works fine.

I think the bug isn't that it goes full screen, but that it doesn't hear the events the same way. I was trying to investigate the source but didn't have that much time and/or frame of reference.

I can try to make an example on codepen to exhibit this behavior. would that be helpful?

If you hold on for a few more mins, I might have found a solution for you :)

sweet!

var renderer = PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight, { transparent: true });
document.body.appendChild(renderer.view);

// create the root of the scene graph
var stage = new PIXI.Container();

// create a video texture from a path
var texture = PIXI.Texture.fromVideo('video.mp4');
texture.baseTexture.autoPlay = false;
makeVideoPlayableInline(texture.baseTexture.source, false);

window.document.addEventListener( 'mousedown', function() {
    texture.baseTexture.source.play();
});

window.document.addEventListener( 'touchstart', function() {
    texture.baseTexture.source.play();
});

var videoSprite = new PIXI.Sprite(texture);
videoSprite.width = renderer.width;
videoSprite.height = renderer.height;
stage.addChild(videoSprite);

animate();

function animate(){
    requestAnimationFrame(animate);

    // render the stage
    renderer.render(stage);
}

So, the above works for me ios8 and ios9. Note, when you call 'makeVideoPlayableInline' you supply 'false'. This is to say that the video has no sound. This is the only way I could get inline working with PIXI with this third party polyfill. Hopefully that is an acceptable trade off for you!

I think the key may be the video not having audio in it at all. I was supplying false but the video has an audio track. I was just using a test video that had audio. The actual video for the app we are making wont have any. Let me try re-encoding and I'll report back.

In my tests with multiple videos, it doesn't matter if the video has audio in it or not. By passing 'false' to 'makeVideoPlayableInline', the video will play inline.

right I am passing false. but I am wrapping the video elsewhere.

This is my video component _Warning_ React.
https://gist.github.com/pr1ntr/8511ede7068eac180f515a18ddf75a89#file-connectvideo-js-L52
This is where it runs the inline polyfill (line 52)
Line 60 it calls a ready function that tells its parent to to render the PixiVideoWrapper
This is it here:
https://gist.github.com/pr1ntr/57032704841e471c3a145308072f3ee2#file-game-js-L37

Then once the PixiVideoWrapper mounts it does all the stuff to get the video texture going:
https://gist.github.com/pr1ntr/3a44f327406d5d5a97824c47d6194484#file-pixivideowrapper-js-L118

So in the Game.js if the user has tapped it should tell the video to play in PixiVideoWrapper line 81 via line 121 componentWillReceiveProps.

If i remove the display:none i can see the inline video play.

also are you using latest #dev?

Yeps

Anything before latest dev either has issues loading base video textures or doesn't contain the inline tag for videos that ios10 requires

ok so your example works for me. But where is the video in the DOM? also what is this button called HOOK DIV? This is strange. Why would it make a difference if the video already exists on the page?

When creating the basevideotexture, if the source is a direct video, it will create the html video tag itself. Perhaps this is where the difference is. Take a look at the source code to see if any event listeners are set up differently? Won't have access to ios devices until Thursday to play with this again I'm afraid

are you testing in simulator?

Nopes, I was testing on real devices.

Hi
I did a basic test to see if providing your own video element would work. It did not on ios9, the example when you provided the source as a string does work.

import inlineVideo from 'iphone-inline-video';

var video = document.createElement('video');
video.setAttribute('playsinline','');
video.setAttribute('webkit-playsinline','');

var src = document.createElement('source');
src.setAttribute('src', vidUrl);
src.setAttribute('type', 'video/mp4');

video.appendChild(src);

console.log(video);

// create the root of the scene graph
var stage = new PIXI.Container();

// create a video texture from a path
var texture = PIXI.Texture.fromVideo(video);
texture.baseTexture.autoPlay = false;
inlineVideo(texture.baseTexture.source, false);

window.document.addEventListener( 'mousedown', function() {
    texture.baseTexture.source.play();
});

window.document.addEventListener( 'touchstart', function() {
    texture.baseTexture.source.play();
});

var videoSprite = new PIXI.Sprite(texture);
videoSprite.width = renderer.width;
videoSprite.height = renderer.height;
stage.addChild(videoSprite);

animate();

function animate(){
    requestAnimationFrame(animate);

    // render the stage
    renderer.render(stage);
}

I couldn't find the difference in PIXI's source. I think I am going insane.

The only thing I can see different is that if you let PIXI create it's own video tag from a string url, it also calls
video.load();
Try that just after
video.appendChild(src);

omfg unbelievable! that totally fixes it. fml. thank you.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sntiagomoreno picture sntiagomoreno  ·  3Comments

YuryKuvetski picture YuryKuvetski  ·  3Comments

distinctdan picture distinctdan  ·  3Comments

finscn picture finscn  ·  3Comments

Makio64 picture Makio64  ·  3Comments