@@ -4,11 +4,13 @@ import { type Size } from "@layouts/geometry";
44import { type ResolvedClip , type VideoAsset } from "@schemas" ;
55import * as pixi from "pixi.js" ;
66
7+ import { createPlaceholderGraphic } from "./placeholder-graphic" ;
78import { Player , PlayerType } from "./player" ;
89
910export class VideoPlayer extends Player {
1011 private texture : pixi . Texture < pixi . VideoSource > | null ;
1112 private sprite : pixi . Sprite | null ;
13+ private placeholder : pixi . Graphics | null ;
1214 private isPlaying : boolean ;
1315
1416 private volumeKeyframeBuilder : KeyframeBuilder ;
@@ -22,6 +24,7 @@ export class VideoPlayer extends Player {
2224
2325 this . texture = null ;
2426 this . sprite = null ;
27+ this . placeholder = null ;
2528 this . isPlaying = false ;
2629
2730 const videoAsset = this . clipConfiguration . asset as VideoAsset ;
@@ -34,7 +37,21 @@ export class VideoPlayer extends Player {
3437
3538 public override async load ( ) : Promise < void > {
3639 await super . load ( ) ;
37- await this . loadVideo ( ) ;
40+ try {
41+ await this . loadVideo ( ) ;
42+ this . configureKeyframes ( ) ;
43+ } catch ( error ) {
44+ console . warn ( `[VideoPlayer.load] FAILED clipId=${ this . clipId } :` , error ) ;
45+ this . createFallbackGraphic ( ) ;
46+ }
47+ }
48+
49+ private createFallbackGraphic ( ) : void {
50+ const { width, height } = this . getDisplaySize ( ) ;
51+ this . clearPlaceholder ( ) ;
52+
53+ this . placeholder = createPlaceholderGraphic ( width , height ) ;
54+ this . contentContainer . addChild ( this . placeholder ) ;
3855 this . configureKeyframes ( ) ;
3956 }
4057
@@ -98,11 +115,9 @@ export class VideoPlayer extends Player {
98115 }
99116
100117 public override dispose ( ) : void {
101- try {
102- super . dispose ( ) ;
103- } finally {
104- this . disposeVideo ( ) ;
105- }
118+ this . disposeVideo ( ) ;
119+ this . clearPlaceholder ( ) ;
120+ super . dispose ( ) ;
106121 }
107122
108123 public override getSize ( ) : Size {
@@ -113,7 +128,11 @@ export class VideoPlayer extends Player {
113128 } ;
114129 }
115130
116- return { width : this . sprite ?. width ?? 0 , height : this . sprite ?. height ?? 0 } ;
131+ if ( this . sprite ) {
132+ return { width : this . sprite . width , height : this . sprite . height } ;
133+ }
134+
135+ return this . placeholder ? this . getDisplaySize ( ) : { width : 0 , height : 0 } ;
117136 }
118137
119138 public override supportsEdgeResize ( ) : boolean {
@@ -123,12 +142,20 @@ export class VideoPlayer extends Player {
123142 /** Reload the video asset when asset.src changes (e.g., merge field update) */
124143 public override async reloadAsset ( ) : Promise < void > {
125144 this . skipVideoUpdate = true ;
126- this . disposeVideo ( ) ;
127- await this . loadVideo ( ) ;
128145 this . isPlaying = false ;
129146 this . syncTimer = 0 ;
130147 this . activeSyncTimer = 0 ;
131- this . skipVideoUpdate = false ;
148+
149+ try {
150+ this . disposeVideo ( ) ;
151+ this . clearPlaceholder ( ) ;
152+ await this . loadVideo ( ) ;
153+ } catch ( error ) {
154+ console . warn ( `[VideoPlayer.reloadAsset] FAILED clipId=${ this . clipId } :` , error ) ;
155+ this . createFallbackGraphic ( ) ;
156+ } finally {
157+ this . skipVideoUpdate = false ;
158+ }
132159 }
133160
134161 public override reconfigureAfterRestore ( ) : void {
@@ -157,6 +184,8 @@ export class VideoPlayer extends Player {
157184 throw new Error ( `Invalid video source '${ src } '.` ) ;
158185 }
159186
187+ this . clearPlaceholder ( ) ;
188+
160189 // Fix alpha channel rendering for WebM VP9 videos (PixiJS 8 auto-detection is buggy)
161190 texture . source . alphaMode = "no-premultiply-alpha" ;
162191
@@ -202,6 +231,16 @@ export class VideoPlayer extends Player {
202231 }
203232 }
204233
234+ private clearPlaceholder ( ) : void {
235+ if ( ! this . placeholder ) {
236+ return ;
237+ }
238+
239+ this . contentContainer . removeChild ( this . placeholder ) ;
240+ this . placeholder . destroy ( ) ;
241+ this . placeholder = null ;
242+ }
243+
205244 public getVolume ( ) : number {
206245 return this . volumeKeyframeBuilder . getValue ( this . getPlaybackTime ( ) ) ;
207246 }
0 commit comments