From 4cba535913ebab164a483d69fc17296f989a70a2 Mon Sep 17 00:00:00 2001 From: Robert George Date: Tue, 29 Sep 2020 09:23:47 -0700 Subject: [PATCH] video sync support, moved video loading to toolbar --- src/app/app.component.ts | 4 ++ src/app/core/map/layers/background-layer.ts | 56 +++++++++++++++------ src/app/core/map/map-container.ts | 4 +- src/app/core/map/models/loader.ts | 14 ++++-- src/app/core/toolbar/toolbar.component.html | 6 ++- src/app/core/toolbar/toolbar.component.ts | 9 ++-- src/app/shared/models/wsevent.ts | 5 +- src/app/shared/services/data.service.ts | 12 +++++ 8 files changed, 82 insertions(+), 28 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index de20ee2..251b31c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -137,6 +137,10 @@ export class AppComponent implements OnInit, AfterViewInit { break; } + case WSEventName.mapVideoControlUpdated: { + this.mapComponent.mapContainer.backgroundLayer.videoControl(event.data); + } + case WSEventName.creatureUpdated: { // udpdate state diff --git a/src/app/core/map/layers/background-layer.ts b/src/app/core/map/layers/background-layer.ts index 98f2fdb..5120921 100644 --- a/src/app/core/map/layers/background-layer.ts +++ b/src/app/core/map/layers/background-layer.ts @@ -13,7 +13,7 @@ export class BackgroundLayer extends Layer { videoSprite: PIXI.Sprite; loadingText = new PIXI.Text("Loading map resources...", {fontFamily : 'Arial', fontSize: 18, fill : 0xffffff, align : 'center'}); - vidloadingText = new PIXI.Text("Loading video map...", {fontFamily : 'Arial', fontSize: 18, fill : 0xffffff, align : 'center'}); + // vidloadingText = new PIXI.Text("Loading video map...", {fontFamily : 'Arial', fontSize: 18, fill : 0xffffff, align : 'center'}); image: string; video: string; @@ -77,6 +77,8 @@ export class BackgroundLayer extends Layer { } this.clear(); + this.dataService.updateVideoLoaded(false); + if (this.image == null && this.video == null) { return this; } @@ -103,7 +105,7 @@ export class BackgroundLayer extends Layer { videoSrc = this.loadedVideoUrl; } if (this.allowVideo) { - Loader.shared.loadVideoTexture(videoSrc,this.vidloadingText).then( vidtex => { + Loader.shared.loadVideoTexture(videoSrc,this.dataService).then( vidtex => { this.videoTexture = vidtex; this.drawVideo(); } ).catch((error) => { @@ -119,13 +121,13 @@ export class BackgroundLayer extends Layer { this.removeChildren(); //add video loading node - if (this.allowVideo && this.video != null) { - this.addChild(this.vidloadingText); - this.vidloadingText.style.fontSize = this.h*.05; - this.vidloadingText.anchor.set(0, 1); - this.vidloadingText.position.set(0,this.h); - } - + // if (this.allowVideo && this.video != null) { + // this.addChild(this.vidloadingText); + // this.vidloadingText.style.fontSize = this.h*.05; + // this.vidloadingText.anchor.set(0, 1); + // this.vidloadingText.position.set(0,this.h); + // } + // return if there is no texture if(this.imageTexture == null && this.videoTexture == null) { return this; @@ -137,12 +139,12 @@ export class BackgroundLayer extends Layer { sprite.height = this.imageTexture.height; this.addChild(sprite); this.imageSprite = sprite; - if (this.allowVideo && this.video) { - this.addChild(this.vidloadingText); - this.vidloadingText.style.fontSize = sprite.height*.05; - this.vidloadingText.anchor.set(0, 1); - this.vidloadingText.position.set(0,sprite.height); - } + // if (this.allowVideo && this.video) { + // this.addChild(this.vidloadingText); + // this.vidloadingText.style.fontSize = sprite.height*.05; + // this.vidloadingText.anchor.set(0, 1); + // this.vidloadingText.position.set(0,sprite.height); + // } } console.log(`map size: ${this.w}x${this.h}`) @@ -165,12 +167,34 @@ export class BackgroundLayer extends Layer { if (this.videoPaused) { video.pause(); } - video.muted = this.videoMuted; + video.onplay = () => this.dataService.updateVideoPaused(false); + video.onpause = () => this.dataService.updateVideoPaused(true); + this.dataService.updateVideoLoaded(true); + this.dataService.updateVideoLoadingText(null); this.emit("videoloaded"); } + videoControl(e) { + if (this.videoTexture) { + const videoResource = this.videoTexture.baseTexture.resource as PIXI.resources.VideoResource; + const video = videoResource.source as HTMLVideoElement; + const delay = Number(video.getAttribute('playbackdelay')) || 0; + const pos = ((e.time + delay) <= video.duration) ? (e.time + delay) : (e.time + delay - video.duration); + if (e.state == "play") { + video.play(); + } else if (e.state == "pause") { + video.pause(); + } + if (video.fastSeek) { + video.fastSeek(pos) + } else { + video.currentTime = pos; + } + } + } + clear() { // this.imageSprite = null; // this.videoSprite = null diff --git a/src/app/core/map/map-container.ts b/src/app/core/map/map-container.ts index 93df71d..2ca1fac 100644 --- a/src/app/core/map/map-container.ts +++ b/src/app/core/map/map-container.ts @@ -117,9 +117,6 @@ export class MapContainer extends Layer { return; } - // if (this.map.video) { - // this.backgroundLayer.once('videoloaded', () => this.draw()); - // } // update grid this.grid.update(this.state.map); this.gridLayer.update(this.grid); @@ -145,6 +142,7 @@ export class MapContainer extends Layer { this.markersLayer.update(); this.tiles = state.map.tiles; + } updateTiles(tiles: Array) { diff --git a/src/app/core/map/models/loader.ts b/src/app/core/map/models/loader.ts index c79c5a7..fb7040b 100644 --- a/src/app/core/map/models/loader.ts +++ b/src/app/core/map/models/loader.ts @@ -1,4 +1,5 @@ import { NineSlicePlane } from 'pixi.js'; +import { DataService } from 'src/app/shared/services/data.service'; export class Loader { @@ -85,8 +86,8 @@ export class Loader { } // TOOD: this is not working very well - async loadVideoTexture(src: string, loadingText: PIXI.Text = null, local: boolean = false): Promise { - loadingText.text = `Loading video map...`; + async loadVideoTexture(src: string, dataService: DataService, local: boolean = false): Promise { + dataService.updateVideoLoadingText(`Loading video map...`); if (local == false && !src.startsWith("blob:")) { src = this.remoteBaseURL + src; } @@ -150,6 +151,7 @@ export class Loader { req.onreadystatechange = () => { if (req.readyState == req.HEADERS_RECEIVED) { const size = req.getResponseHeader("Content-Length"); + req.abort(); resolve(Number(size)); } } @@ -166,7 +168,7 @@ export class Loader { req.onprogress = (e) => { if (e.lengthComputable && Math.trunc(e.loaded/e.total*100) > pos) { pos = Math.trunc(e.loaded/e.total*100) - loadingText.text = `Loading video map: ${pos}%`; + dataService.updateVideoLoadingText(`Loading video map: ${pos}%`); } }; req.onload = () => resolve(req.response); @@ -186,6 +188,12 @@ export class Loader { console.log("returning promise"); return new Promise((resolve, reject) => { video.oncanplaythrough = () => { + const start = new Date().getTime(); + video.addEventListener('play',() => { + const end = new Date().getTime(); + const diff = (end - start)/1000; + video.setAttribute('playbackdelay', `${diff}`); + }, { once: true } ); console.log(`video size: ${video.videoWidth}x${video.videoHeight}`) video.height = video.videoHeight; diff --git a/src/app/core/toolbar/toolbar.component.html b/src/app/core/toolbar/toolbar.component.html index 31f8983..6d3ef51 100644 --- a/src/app/core/toolbar/toolbar.component.html +++ b/src/app/core/toolbar/toolbar.component.html @@ -25,7 +25,11 @@ -
+
+ +
+ +
diff --git a/src/app/core/toolbar/toolbar.component.ts b/src/app/core/toolbar/toolbar.component.ts index eec8e07..63fa621 100644 --- a/src/app/core/toolbar/toolbar.component.ts +++ b/src/app/core/toolbar/toolbar.component.ts @@ -38,9 +38,10 @@ export class ToolbarComponent implements OnInit { activeTool: Tool = Tool.move; messages: Boolean = false; - videoControlsVisible: Boolean = false; videoPaused: boolean = false; videoMuted: boolean = true; + videoLoaded: boolean = false; + videoLoadingText: string; activeToolChanged(newTool) { this.tool.emit(newTool); @@ -74,7 +75,9 @@ export class ToolbarComponent implements OnInit { ngOnInit() { this.messages = (localStorage.getItem("activePanel") || Panel.none) == Panel.messages; - this.dataService.videoMuted.subscribe(value => this.videoMuted); - this.dataService.videoPaused.subscribe(value => this.videoPaused); + this.dataService.videoMuted.subscribe(value => this.videoMuted = value); + this.dataService.videoPaused.subscribe(value => this.videoPaused = value); + this.dataService.videoLoaded.subscribe(value => this.videoLoaded = value); + this.dataService.videoLoadingText.subscribe(value => this.videoLoadingText = value); } } diff --git a/src/app/shared/models/wsevent.ts b/src/app/shared/models/wsevent.ts index 5c2651f..46e936b 100644 --- a/src/app/shared/models/wsevent.ts +++ b/src/app/shared/models/wsevent.ts @@ -24,10 +24,11 @@ export enum WSEventName { reload = "reload", messageCreated = "messageCreated", messageDeleted = "messageDeleted", - createMessage = "createMessage" + createMessage = "createMessage", + mapVideoControlUpdated = "mapVideoControlUpdated" } export interface WSEvent { name: WSEventName; data: any; -} \ No newline at end of file +} diff --git a/src/app/shared/services/data.service.ts b/src/app/shared/services/data.service.ts index acb2823..f2f6212 100644 --- a/src/app/shared/services/data.service.ts +++ b/src/app/shared/services/data.service.ts @@ -19,12 +19,24 @@ export class DataService { public remoteHost: string; public protocol: string; + private videoLoadingText$ = new BehaviorSubject(null); + private videoLoaded$ = new BehaviorSubject(false); private videoPaused$ = new BehaviorSubject(false); private videoMuted$ = new BehaviorSubject(true); + videoLoadingText = this.videoLoadingText$.asObservable(); + videoLoaded = this.videoLoaded$.asObservable(); videoPaused = this.videoPaused$.asObservable(); videoMuted = this.videoMuted$.asObservable(); + updateVideoLoadingText(value: string) { + this.videoLoadingText$.next(value); + } + + updateVideoLoaded(value: boolean) { + this.videoLoaded$.next(value); + } + updateVideoPaused(value: boolean) { this.videoPaused$.next(value); }