/** * 从视频文件中提取第一帧并返回为File对象 * @param videoFile 视频文件 * @returns 包含视频第一帧的File对象 */ export const extractVideoFirstFrame = (videoFile: File): Promise => { return new Promise((resolve, reject) => { const videoUrl = URL.createObjectURL(videoFile); const video = document.createElement('video'); video.src = videoUrl; video.crossOrigin = 'anonymous'; video.muted = true; video.preload = 'metadata'; video.onloadeddata = () => { try { // 设置视频时间到第一帧 video.currentTime = 0.1; } catch (e) { URL.revokeObjectURL(videoUrl); reject(e); } }; video.onseeked = () => { try { const canvas = document.createElement('canvas'); canvas.width = video.videoWidth; canvas.height = video.videoHeight; const ctx = canvas.getContext('2d'); if (!ctx) { throw new Error('无法获取canvas上下文'); } // 绘制视频帧到canvas ctx.drawImage(video, 0, 0, canvas.width, canvas.height); // 将canvas转换为DataURL const dataUrl = canvas.toDataURL('image/jpeg'); // 将DataURL转换为Blob const byteString = atob(dataUrl.split(',')[1]); const mimeString = dataUrl.split(',')[0].split(':')[1].split(';')[0]; const ab = new ArrayBuffer(byteString.length); const ia = new Uint8Array(ab); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } const blob = new Blob([ab], { type: mimeString }); // 创建File对象 const frameFile = new File( [blob], `${videoFile.name.replace(/\.[^/.]+$/, '')}_frame.jpg`, { type: 'image/jpeg' } ); // 清理URL对象 URL.revokeObjectURL(videoUrl); resolve(frameFile); } catch (e) { URL.revokeObjectURL(videoUrl); reject(e); } }; video.onerror = () => { URL.revokeObjectURL(videoUrl); reject(new Error('视频加载失败')); }; }); }; // 获取视频时长 export const getVideoDuration = (file: File): Promise => { return new Promise((resolve) => { const video = document.createElement('video'); video.preload = 'metadata'; video.onloadedmetadata = () => { URL.revokeObjectURL(video.src); resolve(video.duration); }; video.onerror = () => { URL.revokeObjectURL(video.src); resolve(0); // Return 0 if we can't get the duration }; video.src = URL.createObjectURL(file); }); }; // 根据 mp4 的url来获取视频时长 /** * 根据视频URL获取视频时长 * @param videoUrl 视频的URL * @returns 返回一个Promise,解析为视频时长(秒) */ export const getVideoDurationFromUrl = async (videoUrl: string): Promise => { return await new Promise((resolve, reject) => { // 创建临时的video元素 const video = document.createElement('video'); // 设置为只加载元数据,不加载整个视频 video.preload = 'metadata'; // 处理加载成功 video.onloadedmetadata = () => { // 释放URL对象 URL.revokeObjectURL(video.src); // 返回视频时长(秒) resolve(video.duration); }; // 处理加载错误 video.onerror = () => { URL.revokeObjectURL(video.src); reject(new Error('无法加载视频')); }; // 处理网络错误 video.onabort = () => { URL.revokeObjectURL(video.src); reject(new Error('视频加载被中止')); }; // 设置视频源 video.src = videoUrl; // 添加跨域属性(如果需要) video.setAttribute('crossOrigin', 'anonymous'); // 开始加载元数据 video.load(); }); };