| 325 | }; |
| 326 | |
| 327 | const processTrim = async (): Promise<void> => { |
| 328 | return new Promise((resolve, reject) => { |
| 329 | if (!videoPreviewRef.current || !fileState.file) { |
| 330 | reject(new Error("Video not loaded")); |
| 331 | return; |
| 332 | } |
| 333 | |
| 334 | try { |
| 335 | const video = videoPreviewRef.current; |
| 336 | const canvas = document.createElement("canvas"); |
| 337 | canvas.width = video.videoWidth; |
| 338 | canvas.height = video.videoHeight; |
| 339 | const ctx = canvas.getContext("2d", { alpha: false }); |
| 340 | |
| 341 | if (!ctx) { |
| 342 | throw new Error("Failed to create canvas context"); |
| 343 | } |
| 344 | |
| 345 | let inputFormat = "video/webm"; |
| 346 | if (fileState.file.type) { |
| 347 | inputFormat = fileState.file.type; |
| 348 | } else if (fileState.file.name) { |
| 349 | const extension = fileState.file.name.split(".").pop()?.toLowerCase(); |
| 350 | if (extension === "mp4") inputFormat = "video/mp4"; |
| 351 | else if (extension === "webm") inputFormat = "video/webm"; |
| 352 | else if (extension === "mov") inputFormat = "video/quicktime"; |
| 353 | } |
| 354 | |
| 355 | let mimeTypes: string[] = []; |
| 356 | if (inputFormat.includes("mp4")) { |
| 357 | mimeTypes = [ |
| 358 | "video/mp4", |
| 359 | "video/webm;codecs=vp9,opus", |
| 360 | "video/webm;codecs=vp8,opus", |
| 361 | "video/webm;codecs=vp9", |
| 362 | "video/webm;codecs=vp8", |
| 363 | "video/webm", |
| 364 | ]; |
| 365 | } else { |
| 366 | mimeTypes = [ |
| 367 | "video/webm;codecs=vp9,opus", |
| 368 | "video/webm;codecs=vp8,opus", |
| 369 | "video/webm;codecs=vp9", |
| 370 | "video/webm;codecs=vp8", |
| 371 | "video/webm", |
| 372 | "video/mp4", |
| 373 | ]; |
| 374 | } |
| 375 | |
| 376 | let selectedMimeType = ""; |
| 377 | for (const type of mimeTypes) { |
| 378 | if (MediaRecorder.isTypeSupported(type)) { |
| 379 | selectedMimeType = type; |
| 380 | break; |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | if (!selectedMimeType) { |