@revideo/2d 0.4.4 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -71,6 +71,9 @@ export class Video extends Media {
71
71
  this
72
72
  >;
73
73
 
74
+ public detectedFileType: 'mp4' | 'webm' | 'hls' | 'unknown' = 'unknown';
75
+ private fileTypeWasDetected: boolean = false;
76
+
74
77
  private static readonly pool: Record<string, HTMLVideoElement> = {};
75
78
 
76
79
  private static readonly imageCommunication = !import.meta.hot
@@ -79,15 +82,6 @@ export class Video extends Media {
79
82
 
80
83
  public constructor(props: VideoProps) {
81
84
  super(props);
82
-
83
- // If the file is not mp4, warn.
84
- // strip the query string from the source
85
- const src = this.fullSource().split('?')[0];
86
- if (!src.endsWith('.mp4')) {
87
- console.warn(
88
- `WARNING: Video source is not an MP4 file. This may significantly slow down rendering: ${this.fullSource()}`,
89
- );
90
- }
91
85
  }
92
86
 
93
87
  protected override desiredSize(): SerializedVector2<DesiredLength> {
@@ -256,6 +250,10 @@ export class Video extends Media {
256
250
  }
257
251
 
258
252
  protected async seekFunction() {
253
+ if (!this.fileTypeWasDetected) {
254
+ this.detectedFileType = await this.detectFileType();
255
+ this.fileTypeWasDetected = true;
256
+ }
259
257
  const playbackState = this.view().playbackState();
260
258
 
261
259
  // During playback
@@ -283,16 +281,16 @@ export class Video extends Media {
283
281
  return this.webcodecSeekedVideo();
284
282
  }
285
283
 
286
- // If not set explicitly, use file extension to determine decoder
287
- if (this.src().endsWith('.mp4')) {
288
- return this.webcodecSeekedVideo();
284
+ // If not set explicitly, use detected file type to determine decoder
285
+ if (this.detectedFileType === 'webm') {
286
+ return this.ffmpegSeekedVideo();
289
287
  }
290
288
 
291
- if (this.src().endsWith('.webm')) {
292
- return this.ffmpegSeekedVideo();
289
+ if (this.detectedFileType === 'hls') {
290
+ return this.seekedVideo();
293
291
  }
294
292
 
295
- return this.seekedVideo();
293
+ return this.webcodecSeekedVideo();
296
294
  }
297
295
 
298
296
  protected override async draw(context: CanvasRenderingContext2D) {
@@ -326,4 +324,38 @@ export class Video extends Media {
326
324
  this.ratio() ?? video.videoWidth / video.videoHeight
327
325
  ).toString();
328
326
  }
327
+
328
+ private async detectFileType(): Promise<'mp4' | 'webm' | 'hls' | 'unknown'> {
329
+ if (this.fullSource().split('?')[0].endsWith('.mp4')) return 'mp4';
330
+ if (this.fullSource().split('?')[0].endsWith('.webm')) return 'webm';
331
+ if (this.fullSource().split('?')[0].endsWith('.m3u8')) return 'hls';
332
+
333
+ if (
334
+ this.fullSource().startsWith('http:') ||
335
+ this.fullSource().startsWith('https:')
336
+ ) {
337
+ try {
338
+ const response = await fetch(this.fullSource(), {method: 'HEAD'});
339
+ const contentType = response.headers.get('Content-Type');
340
+
341
+ if (contentType) {
342
+ if (contentType.includes('video/mp4')) return 'mp4';
343
+ if (contentType.includes('video/webm')) return 'webm';
344
+ if (
345
+ contentType.includes('application/vnd.apple.mpegurl') ||
346
+ contentType.includes('application/x-mpegURL')
347
+ ) {
348
+ return 'hls';
349
+ }
350
+ }
351
+ } catch (error) {
352
+ // do nothing
353
+ }
354
+ }
355
+
356
+ console.warn(
357
+ `WARNING: Could not detect file type of video (${this.fullSource()}), will default to using mp4 decoder. If your video file is no mp4 file, this will lead to an error - to fix this, reencode your video as an mp4 file (better performance) or specify a different decoder: https://docs.re.video/common-issues/slow-rendering#use-mp4-decoder`,
358
+ );
359
+ return 'unknown';
360
+ }
329
361
  }