Phaser.Video = function (game, key, url){ if (key === undefined) { key = null ; } if (url === undefined) { url = null ; } this.game = game; this.key = key; this.width = 0; this.height = 0; this.type = Phaser.VIDEO; this.disableTextureUpload = false ; this.touchLocked = false ; this.onPlay = new Phaser.Signal(); this.onChangeSource = new Phaser.Signal(); this.onComplete = new Phaser.Signal(); this.onAccess = new Phaser.Signal(); this.onError = new Phaser.Signal(); this.onTimeout = new Phaser.Signal(); this.timeout = 15000; this._timeOutID = null ; this.video = null ; this.videoStream = null ; this.isStreaming = false ; this.retryLimit = 20; this.retry = 0; this.retryInterval = 500; this._retryID = null ; this._codeMuted = false ; this._muted = false ; this._codePaused = false ; this._paused = false ; this._pending = false ; this._autoplay = false ; this._endCallback = null ; this._playCallback = null ; if (key && this.game.cache.checkVideoKey(key)) { var _video = this.game.cache.getVideo(key); if (_video.isBlob) { this.createVideoFromBlob(_video.data); } else { this.video = _video.data; } this.width = this.video.videoWidth; this.height = this.video.videoHeight; } else if (url) { this.createVideoFromURL(url, false ); } if (this.video && !url) { this.baseTexture = new PIXI.BaseTexture(this.video); this.baseTexture.forceLoaded(this.width, this.height); } else { this.baseTexture = new PIXI.BaseTexture(PIXI.TextureCache.__default.baseTexture.source); this.baseTexture.forceLoaded(this.width, this.height); } this.texture = new PIXI.Texture(this.baseTexture); this.textureFrame = new Phaser.Frame(0, 0, 0, this.width, this.height, 'video'); this.texture.setFrame(this.textureFrame); this.texture.valid = false ; if (key !== null && this.video) { this.texture.valid = this.video.canplay; } this.snapshot = null ; if (Phaser.BitmapData) { this.snapshot = new Phaser.BitmapData(this.game, '', this.width, this.height); } if (!this.game.device.cocoonJS && (this.game.device.iOS || this.game.device.android) || (window.PhaserGlobal && window.PhaserGlobal.fakeiOSTouchLock)) { this.setTouchLock(); } else { if (_video) { _video.locked = false ; } } } ; Phaser.Video.prototype = { connectToMediaStream: function (video, stream){ if (video && stream) { this.video = video; this.videoStream = stream; this.isStreaming = true ; this.baseTexture.source = this.video; this.updateTexture(null , this.video.videoWidth, this.video.videoHeight); this.onAccess.dispatch(this); } return this; } , startMediaStream: function (captureAudio, width, height){ if (captureAudio === undefined) { captureAudio = false ; } if (width === undefined) { width = null ; } if (height === undefined) { height = null ; } if (!this.game.device.getUserMedia) { this.onError.dispatch(this, 'No getUserMedia'); return false ; } if (this.videoStream !== null ) { if (this.videoStream.active) { this.videoStream.active = false ; } else { this.videoStream.stop(); } } this.removeVideoElement(); this.video = _AN_Call_createelement('createElement', document, "video"); _AN_Call_setattribute("setAttribute", this.video, 'autoplay', 'autoplay'); if (width !== null ) { this.video.width = width; } if (height !== null ) { this.video.height = height; } this._timeOutID = _AN_Call_settimeout('setTimeout', window, this.getUserMediaTimeout.bind(this), this.timeout); try { navigator.getUserMedia({ "audio": captureAudio, "video": true } , this.getUserMediaSuccess.bind(this), this.getUserMediaError.bind(this)); } catch (error) { this.getUserMediaError(error); } return this; } , getUserMediaTimeout: function (){ clearTimeout(this._timeOutID); this.onTimeout.dispatch(this); } , getUserMediaError: function (event){ clearTimeout(this._timeOutID); this.onError.dispatch(this, event); } , getUserMediaSuccess: function (stream){ clearTimeout(this._timeOutID); this.videoStream = stream; if (this.video.mozSrcObject !== undefined) { this.video.mozSrcObject = stream; } else { _AN_Write_src("src", this.video, false , (_AN_Read_url("URL", window) && _AN_Read_url("URL", window).createObjectURL(stream)) || stream); } var self = this; this.video.onloadeddata = function (){ var retry = 10; function checkStream(){ if (retry > 0) { if (self.video.videoWidth > 0) { var width = self.video.videoWidth; var height = self.video.videoHeight; if (isNaN(self.video.videoHeight)) { height = width / (4 / 3); } self.video.play(); self.isStreaming = true ; self.baseTexture.source = self.video; self.updateTexture(null , width, height); self.onAccess.dispatch(self); } else { _AN_Call_settimeout("setTimeout", window, checkStream, 500); } } else { console.warn('Unable to connect to video stream. Webcam error?'); } retry-- ; } checkStream(); } ; } , createVideoFromBlob: function (blob){ var _this = this; this.video = _AN_Call_createelement('createElement', document, "video"); this.video.controls = false ; _AN_Call_setattribute("setAttribute", this.video, 'autoplay', 'autoplay'); this.video.addEventListener('loadeddata', function (event){ _this.updateTexture(event); } , true ); _AN_Write_src('src', this.video, false , _AN_Read_url('URL', window).createObjectURL(blob)); this.video.canplay = true ; return this; } , createVideoFromURL: function (url, autoplay){ if (autoplay === undefined) { autoplay = false ; } if (this.texture) { this.texture.valid = false ; } this.video = _AN_Call_createelement('createElement', document, "video"); this.video.controls = false ; if (autoplay) { _AN_Call_setattribute("setAttribute", this.video, 'autoplay', 'autoplay'); } _AN_Write_src('src', this.video, false , url); this.video.canplay = true ; _AN_Call_load('load', this.video); this.retry = this.retryLimit; this._retryID = _AN_Call_settimeout('setTimeout', window, this.checkVideoProgress.bind(this), this.retryInterval); this.key = url; return this; } , updateTexture: function (event, width, height){ var change = false ; if (width === undefined || width === null ) { width = this.video.videoWidth; change = true ; } if (height === undefined || height === null ) { height = this.video.videoHeight; } this.width = width; this.height = height; if (this.baseTexture.source !== this.video) { this.baseTexture.source = this.video; } this.baseTexture.forceLoaded(width, height); this.texture.frame.resize(width, height); this.texture.width = width; this.texture.height = height; this.texture.valid = true ; if (this.snapshot) { this.snapshot.resize(width, height); } if (change && this.key !== null ) { this.onChangeSource.dispatch(this, width, height); if (this._autoplay) { this.video.play(); this.onPlay.dispatch(this, this.loop, this.playbackRate); } } } , complete: function (){ this.onComplete.dispatch(this); } , play: function (loop, playbackRate){ if (loop === undefined) { loop = false ; } if (playbackRate === undefined) { playbackRate = 1; } if (this.game.sound.onMute) { this.game.sound.onMute.add(this.setMute, this); this.game.sound.onUnMute.add(this.unsetMute, this); if (this.game.sound.mute) { this.setMute(); } } this.game.onPause.add(this.setPause, this); this.game.onResume.add(this.setResume, this); this._endCallback = this.complete.bind(this); this.video.addEventListener('ended', this._endCallback, true ); if (loop) { this.video.loop = 'loop'; } else { this.video.loop = ''; } this.video.playbackRate = playbackRate; if (this.touchLocked) { this._pending = true ; } else { this._pending = false ; if (this.key !== null ) { if (this.video.readyState !== 4) { this.retry = this.retryLimit; this._retryID = _AN_Call_settimeout('setTimeout', window, this.checkVideoProgress.bind(this), this.retryInterval); } else { this._playCallback = this.playHandler.bind(this); this.video.addEventListener('playing', this._playCallback, true ); } } this.video.play(); this.onPlay.dispatch(this, loop, playbackRate); } return this; } , playHandler: function (){ this.video.removeEventListener('playing', this._playCallback, true ); this.updateTexture(); } , stop: function (){ if (this.game.sound.onMute) { this.game.sound.onMute.remove(this.setMute, this); this.game.sound.onUnMute.remove(this.unsetMute, this); } this.game.onPause.remove(this.setPause, this); this.game.onResume.remove(this.setResume, this); if (this.isStreaming) { if (this.video.mozSrcObject) { this.video.mozSrcObject.stop(); _AN_Write_src('src', this.video, false , null ); } else { _AN_Write_src('src', this.video, false , ""); if (this.videoStream.active) { this.videoStream.active = false ; } else { this.videoStream.stop(); } } this.videoStream = null ; this.isStreaming = false ; } else { this.video.removeEventListener('ended', this._endCallback, true ); this.video.removeEventListener('playing', this._playCallback, true ); if (this.touchLocked) { this._pending = false ; } else { this.video.pause(); } } return this; } , add: function (object){ if (Array.isArray(object)) { for (var i = 0; i < _AN_Read_length('length', object); i++ ){ if (object[i].loadTexture) { object[i].loadTexture(this); } } } else { object.loadTexture(this); } return this; } , addToWorld: function (x, y, anchorX, anchorY, scaleX, scaleY){ scaleX = scaleX || 1; scaleY = scaleY || 1; var image = this.game.add.image(x, y, this); image.anchor.set(anchorX, anchorY); image.scale.set(scaleX, scaleY); return image; } , render: function (){ if (!this.disableTextureUpload && this.playing) { this.baseTexture.dirty(); } } , setMute: function (){ if (this._muted) { return ; } this._muted = true ; this.video.muted = true ; } , unsetMute: function (){ if (!this._muted || this._codeMuted) { return ; } this._muted = false ; this.video.muted = false ; } , setPause: function (){ if (this._paused || this.touchLocked) { return ; } this._paused = true ; this.video.pause(); } , setResume: function (){ if (!this._paused || this._codePaused || this.touchLocked) { return ; } this._paused = false ; if (!this.video.ended) { this.video.play(); } } , changeSource: function (src, autoplay){ if (autoplay === undefined) { autoplay = true ; } this.texture.valid = false ; this.video.pause(); this.retry = this.retryLimit; this._retryID = _AN_Call_settimeout('setTimeout', window, this.checkVideoProgress.bind(this), this.retryInterval); _AN_Write_src('src', this.video, false , src); _AN_Call_load('load', this.video); this._autoplay = autoplay; if (!autoplay) { this.paused = true ; } return this; } , checkVideoProgress: function (){ if (this.video.readyState === 4) { this.updateTexture(); } else { this.retry-- ; if (this.retry > 0) { this._retryID = _AN_Call_settimeout('setTimeout', window, this.checkVideoProgress.bind(this), this.retryInterval); } else { console.warn('Phaser.Video: Unable to start downloading video in time', this.isStreaming); } } } , setTouchLock: function (){ this.game.input.touch.addTouchLockCallback(this.unlock, this); this.touchLocked = true ; } , unlock: function (){ this.touchLocked = false ; this.video.play(); this.onPlay.dispatch(this, this.loop, this.playbackRate); if (this.key) { var _video = this.game.cache.getVideo(this.key); if (_video && !_video.isBlob) { _video.locked = false ; } } return true ; } , grab: function (clear, alpha, blendMode){ if (clear === undefined) { clear = false ; } if (alpha === undefined) { alpha = 1; } if (blendMode === undefined) { blendMode = null ; } if (this.snapshot === null ) { console.warn('Video.grab cannot run because Phaser.BitmapData is unavailable'); return ; } if (clear) { this.snapshot.cls(); } this.snapshot.copy(this.video, 0, 0, this.width, this.height, 0, 0, this.width, this.height, 0, 0, 0, 1, 1, alpha, blendMode); return this.snapshot; } , removeVideoElement: function (){ if (!this.video) { return ; } if (this.video.parentNode) { this.video.parentNode.removeChild(this.video); } while (this.video.hasChildNodes()){ this.video.removeChild(this.video.firstChild); } this.video.removeAttribute('autoplay'); this.video.removeAttribute('src'); this.video = null ; } , destroy: function (){ this.stop(); this.removeVideoElement(); if (this.touchLocked) { this.game.input.touch.removeTouchLockCallback(this.unlock, this); } if (this._retryID) { window.clearTimeout(this._retryID); } } } ; Object.defineProperty(Phaser.Video.prototype, "currentTime", { get: function (){ return (this.video)? this.video.currentTime: 0; } , set: function (value){ this.video.currentTime = value; } } ); Object.defineProperty(Phaser.Video.prototype, "duration", { get: function (){ return (this.video)? this.video.duration: 0; } } ); Object.defineProperty(Phaser.Video.prototype, "progress", { get: function (){ return (this.video)? (this.video.currentTime / this.video.duration): 0; } } ); Object.defineProperty(Phaser.Video.prototype, "mute", { get: function (){ return this._muted; } , set: function (value){ value = value || null ; if (value) { if (this._muted) { return ; } this._codeMuted = true ; this.setMute(); } else { if (!this._muted) { return ; } this._codeMuted = false ; this.unsetMute(); } } } ); Object.defineProperty(Phaser.Video.prototype, "paused", { get: function (){ return this._paused; } , set: function (value){ value = value || null ; if (this.touchLocked) { return ; } if (value) { if (this._paused) { return ; } this._codePaused = true ; this.setPause(); } else { if (!this._paused) { return ; } this._codePaused = false ; this.setResume(); } } } ); Object.defineProperty(Phaser.Video.prototype, "volume", { get: function (){ return (this.video)? this.video.volume: 1; } , set: function (value){ if (value < 0) { value = 0; } else if (value > 1) { value = 1; } if (this.video) { this.video.volume = value; } } } ); Object.defineProperty(Phaser.Video.prototype, "playbackRate", { get: function (){ return (this.video)? this.video.playbackRate: 1; } , set: function (value){ if (this.video) { this.video.playbackRate = value; } } } ); Object.defineProperty(Phaser.Video.prototype, "loop", { get: function (){ return (this.video)? this.video.loop: false ; } , set: function (value){ if (value && this.video) { this.video.loop = 'loop'; } else if (this.video) { this.video.loop = ''; } } } ); Object.defineProperty(Phaser.Video.prototype, "playing", { get: function (){ return !(this.video.paused && this.video.ended); } } ); Phaser.Video.prototype.constructor = Phaser.Video;