Commit 207f6eea by lijiabin

feat: 视频上传前检测 H.265 编码并提示转码

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
parent 4a583bc0
......@@ -12,7 +12,7 @@
accept="video/*"
class="upload-area"
>
<div v-if="!uploading && !videoInfo" class="upload-placeholder">
<div v-if="!uploading && !videoInfo && !codecChecking" class="upload-placeholder">
<el-icon class="upload-icon"><IEpVideoCamera /></el-icon>
<div class="upload-text">
<p>拖拽视频文件到此处,或点击选择文件</p>
......@@ -20,6 +20,17 @@
</div>
</div>
<!-- 上传前的视频编码检测 -->
<div v-if="codecChecking" class="upload-progress">
<div class="progress-info">
<el-icon class="progress-icon is-loading"><IEpLoading /></el-icon>
<div class="progress-details">
<p class="file-name">{{ currentFile?.name }}</p>
<p class="progress-text">正在检测视频编码格式...</p>
</div>
</div>
</div>
<!-- 上传进度 -->
<div v-if="uploading" class="upload-progress">
<div class="progress-info">
......@@ -71,13 +82,18 @@
</div>
</template>
<script setup lang="ts">
<script setup lang="tsx">
import { uploadFile as uploadFileApi } from '@/api/common'
import type { UploadFile } from 'element-plus'
import type { UploadVideoProps } from './types'
import { getVideoMetadata } from '@/utils'
import { useMediaInfo, useMessageBox } from '@/hooks'
import { push } from 'notivue'
// 视频转码工具下载地址 安装包放在 public/downloads 下
// 测试环境打包带了 base 前缀 所以要拼 BASE_URL 不能写死根路径
const H265_TOOL_DOWNLOAD_URL = `${import.meta.env.BASE_URL}downloads/YswgToolbox_0.3.0_x64-setup.exe`
interface VideoInfo {
url: string
name: string
......@@ -92,6 +108,7 @@ const {
maxSize = 1000,
acceptFormats = ['mp4', 'avi', 'mov', 'wmv', 'flv'],
btnClass = '',
checkVideoCodec = true,
} = defineProps<UploadVideoProps>()
const modelValue = defineModel<string>('modelValue', { required: true })
const videoInfo = defineModel<VideoInfo | null>('videoInfo', { required: false, default: null })
......@@ -106,6 +123,12 @@ const uploading = ref(false)
const uploadProgress = ref(0)
const uploadError = ref('')
const currentFile = ref<File | null>(null)
// 正在检测视频编码格式
const codecChecking = ref(false)
const { isH265Video, cleanup: cleanupMediaInfo } = useMediaInfo()
const { confirm } = useMessageBox()
onBeforeUnmount(cleanupMediaInfo)
// 文件大小格式化
const formatFileSize = (bytes: number): string => {
......@@ -138,12 +161,67 @@ const beforeUpload = (file: File): boolean => {
return true
}
/**
* 上传前检测视频编码格式
* H.265(HEVC) 编码的视频浏览器普遍无法解码播放 上传上去也是放不了的
* 所以先提示用户去转成 H.264 再传 用户坚持的话也允许继续上传
* 返回 true 表示继续上传
*/
const confirmVideoCodec = async (file: File) => {
let isH265 = false
try {
codecChecking.value = true
isH265 = await isH265Video(file)
} catch (error) {
// 检测失败(如 wasm 加载不到)不阻塞上传 按原流程走
console.error('视频编码检测失败', error)
} finally {
codecChecking.value = false
}
if (!isH265) return true
try {
await confirm({
title: '视频编码格式提示',
type: 'warning',
confirmText: '仍然上传',
cancelText: '取消上传',
message: () => (
<span>
<span class="block mb-2">检测到该视频为 H.265(HEVC) 编码,部分浏览器可能无法正常播放。</span>
<span class="block mb-2">建议使用转码工具将视频转换为 H.264 编码后再重新上传。</span>
<a
href={H265_TOOL_DOWNLOAD_URL}
target="_blank"
rel="noopener"
class="text-[#7083FF] underline"
>
点击下载视频转码工具
</a>
</span>
),
})
return true
} catch {
return false
}
}
// 文件选择处理 - 选择后自动上传
const handleFileChange = async (file: UploadFile) => {
if (!file.raw) return
currentFile.value = file.raw
// H.265 检测不通过且用户选择取消时 不进入上传
if (checkVideoCodec && !(await confirmVideoCodec(file.raw))) {
currentFile.value = null
// 清掉内部文件列表 否则再次选择同一个文件不会触发 change
uploadRef.value?.clearFiles()
return
}
await startUpload()
}
......@@ -272,6 +350,7 @@ const retryUpload = () => {
const reset = () => {
uploadRef.value = null
uploading.value = false
codecChecking.value = false
uploadProgress.value = 0
uploadError.value = ''
currentFile.value = null
......
......@@ -2,4 +2,6 @@ export interface UploadVideoProps {
maxSize?: number // MB
acceptFormats?: string[]
btnClass?: string
/** 上传前是否检测视频编码 检测到 H.265(HEVC) 时提示用户先转成 H.264 默认开启 */
checkVideoCodec?: boolean
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment