lrj
1 天以前 9f8395fab13ca4b230a0f7d62636e209745c91d4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**
 * 视频处理工具函数
 */
 
/**
 * 从视频文件中提取第一帧作为封面图
 * @param {File} videoFile - 视频文件对象
 * @param {number} quality - 图片质量 (0-1),默认0.8
 * @returns {Promise<Blob>} 返回图片Blob对象
 */
export const extractVideoFrame = (videoFile, quality = 0.8) => {
  return new Promise((resolve, reject) => {
    // 创建video元素
    const video = document.createElement('video')
    video.crossOrigin = 'anonymous'
    video.muted = true
    video.playsInline = true
    
    // 创建canvas元素
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    
    // 监听视频加载完成
    video.addEventListener('loadedmetadata', () => {
      // 设置canvas尺寸为视频尺寸
      canvas.width = video.videoWidth
      canvas.height = video.videoHeight
      
      // 跳转到第一帧(0.1秒处,避免黑屏)
      video.currentTime = 0.1
    })
    
    // 监听视频可以播放
    video.addEventListener('canplay', () => {
      // 绘制当前帧到canvas
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
      
      // 将canvas转换为Blob
      canvas.toBlob((blob) => {
        if (blob) {
          resolve(blob)
        } else {
          reject(new Error('无法提取视频帧'))
        }
      }, 'image/jpeg', quality)
      
      // 清理资源
      video.src = ''
      URL.revokeObjectURL(video.src)
    })
    
    // 监听错误
    video.addEventListener('error', (e) => {
      reject(new Error('视频加载失败: ' + e.message))
    })
    
    // 设置视频源
    video.src = URL.createObjectURL(videoFile)
  })
}
 
/**
 * 检查文件是否为视频
 * @param {File} file - 文件对象
 * @returns {boolean} 是否为视频文件
 */
export const isVideoFile = (file) => {
  return file && file.type && file.type.startsWith('video/')
}
 
/**
 * 获取视频文件的基本信息
 * @param {File} videoFile - 视频文件对象
 * @returns {Promise<Object>} 返回视频信息对象
 */
export const getVideoInfo = (videoFile) => {
  return new Promise((resolve, reject) => {
    const video = document.createElement('video')
    video.crossOrigin = 'anonymous'
    video.muted = true
    video.playsInline = true
    
    video.addEventListener('loadedmetadata', () => {
      const info = {
        duration: video.duration,
        width: video.videoWidth,
        height: video.videoHeight,
        size: videoFile.size,
        type: videoFile.type,
        name: videoFile.name
      }
      resolve(info)
      
      // 清理资源
      video.src = ''
      URL.revokeObjectURL(video.src)
    })
    
    video.addEventListener('error', (e) => {
      reject(new Error('无法获取视频信息: ' + e.message))
    })
    
    video.src = URL.createObjectURL(videoFile)
  })
}
 
/**
 * 生成缩略图文件名
 * @param {string} originalFileName - 原始文件名
 * @returns {string} 缩略图文件名
 */
export const generateThumbnailFileName = (originalFileName) => {
  const nameWithoutExt = originalFileName.replace(/\.[^/.]+$/, '')
  const timestamp = Date.now()
  return `${nameWithoutExt}_thumb_${timestamp}.jpg`
}