Spaces:
Sleeping
Sleeping
| /** | |
| * Web Renderer Utilities for Client-Side Rendering | |
| * | |
| * This module provides utilities for checking browser compatibility | |
| * and rendering videos directly in the browser using @remotion/web-renderer. | |
| */ | |
| import { | |
| canRenderMediaOnWeb, | |
| getEncodableVideoCodecs, | |
| getEncodableAudioCodecs, | |
| type CanRenderIssue, | |
| type WebRendererVideoCodec, | |
| type WebRendererAudioCodec, | |
| } from '@remotion/web-renderer'; | |
| // Types | |
| export interface CSRSupportResult { | |
| canRender: boolean; | |
| issues: CanRenderIssue[]; | |
| resolvedVideoCodec: WebRendererVideoCodec; | |
| resolvedAudioCodec: WebRendererAudioCodec | null; | |
| resolvedOutputTarget: 'web-fs' | 'arraybuffer'; | |
| } | |
| export interface AvailableCodecs { | |
| videoCodecs: WebRendererVideoCodec[]; | |
| audioCodecs: WebRendererAudioCodec[]; | |
| } | |
| export type RenderMode = 'csr' | 'ssr' | 'ssr-local'; | |
| export interface RenderOptions { | |
| mode: RenderMode; | |
| container?: 'mp4' | 'webm'; | |
| videoCodec?: WebRendererVideoCodec; | |
| audioCodec?: WebRendererAudioCodec; | |
| videoBitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high'; | |
| audioBitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high'; | |
| } | |
| /** | |
| * Check if the current browser supports Client-Side Rendering | |
| */ | |
| export async function checkCSRSupport( | |
| width: number, | |
| height: number, | |
| options?: { | |
| container?: 'mp4' | 'webm'; | |
| videoCodec?: WebRendererVideoCodec; | |
| audioCodec?: WebRendererAudioCodec; | |
| } | |
| ): Promise<CSRSupportResult> { | |
| try { | |
| const result = await canRenderMediaOnWeb({ | |
| container: options?.container ?? 'mp4', | |
| videoCodec: options?.videoCodec ?? 'h264', | |
| audioCodec: options?.audioCodec, | |
| width, | |
| height, | |
| }); | |
| return { | |
| canRender: result.canRender, | |
| issues: result.issues, | |
| resolvedVideoCodec: result.resolvedVideoCodec, | |
| resolvedAudioCodec: result.resolvedAudioCodec, | |
| resolvedOutputTarget: result.resolvedOutputTarget, | |
| }; | |
| } catch (error) { | |
| // WebCodecs API not available | |
| return { | |
| canRender: false, | |
| issues: [{ | |
| type: 'webcodecs-unavailable', | |
| message: 'WebCodecs API is not available in this browser', | |
| severity: 'error', | |
| }], | |
| resolvedVideoCodec: 'h264', | |
| resolvedAudioCodec: null, | |
| resolvedOutputTarget: 'arraybuffer', | |
| }; | |
| } | |
| } | |
| /** | |
| * Get available video and audio codecs for the current browser | |
| */ | |
| export async function getAvailableCodecs( | |
| container: 'mp4' | 'webm' = 'mp4' | |
| ): Promise<AvailableCodecs> { | |
| try { | |
| const [videoCodecs, audioCodecs] = await Promise.all([ | |
| getEncodableVideoCodecs(container), | |
| getEncodableAudioCodecs(container), | |
| ]); | |
| return { videoCodecs, audioCodecs }; | |
| } catch (error) { | |
| // Fallback for browsers without WebCodecs | |
| return { | |
| videoCodecs: [], | |
| audioCodecs: [], | |
| }; | |
| } | |
| } | |
| /** | |
| * Format CSR error messages for user display | |
| */ | |
| export function formatCSRErrors(issues: CanRenderIssue[]): string[] { | |
| return issues | |
| .filter(issue => issue.severity === 'error') | |
| .map(issue => issue.message); | |
| } | |
| /** | |
| * Format CSR warnings for user display | |
| */ | |
| export function formatCSRWarnings(issues: CanRenderIssue[]): string[] { | |
| return issues | |
| .filter(issue => issue.severity === 'warning') | |
| .map(issue => issue.message); | |
| } | |
| /** | |
| * Check if WebCodecs API is available in the browser | |
| */ | |
| export function isWebCodecsAvailable(): boolean { | |
| return typeof VideoEncoder !== 'undefined' && typeof AudioEncoder !== 'undefined'; | |
| } | |
| /** | |
| * Get recommended render mode based on browser support | |
| */ | |
| export async function getRecommendedRenderMode( | |
| width: number, | |
| height: number | |
| ): Promise<RenderMode> { | |
| const support = await checkCSRSupport(width, height); | |
| return support.canRender ? 'csr' : 'ssr'; | |
| } | |
| /** | |
| * Get default render options with browser-specific adjustments | |
| */ | |
| export async function getDefaultRenderOptions( | |
| width: number, | |
| height: number | |
| ): Promise<RenderOptions> { | |
| const support = await checkCSRSupport(width, height); | |
| return { | |
| mode: support.canRender ? 'csr' : 'ssr', | |
| container: 'mp4', | |
| videoCodec: support.resolvedVideoCodec, | |
| audioCodec: support.resolvedAudioCodec ?? undefined, | |
| videoBitrate: 'high', | |
| audioBitrate: 'medium', | |
| }; | |
| } | |
| /** | |
| * Download a blob as a file | |
| */ | |
| export function downloadBlob(blob: Blob, filename: string): void { | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = filename; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } | |