npm install mp4box@0.5.4
const MP4Box = require('mp4box')
const DEFAULT_CHUNK_SIZE = 1024 * 1024
const DEFAULT_MAX_READ_SIZE = 16 * 1024 * 1024
export interface VideoCodecParseOptions {
chunkSize?: number
maxReadSize?: number
}
/**
* 分片解析 MP4 中的视频轨道编码,解析失败或未解析到编码时返回空数组。
*/
export function parseVideoCodecs(
file: File,
options: VideoCodecParseOptions = {},
): Promise<string[]> {
const chunkSize = options.chunkSize || DEFAULT_CHUNK_SIZE
const maxReadSize = options.maxReadSize || DEFAULT_MAX_READ_SIZE
return new Promise(resolve => {
const mp4File = MP4Box.createFile(false)
let readSize = 0
let settled = false
const finish = (codecs: string[]) => {
if (settled) {
return
}
settled = true
resolve(codecs)
}
mp4File.onReady = (info: any) => {
const tracks = info.videoTracks ||
(info.tracks || []).filter((track: any) => track.video)
const codecs = tracks
.map((track: any) => String(track.codec || '').toLowerCase())
.filter(Boolean)
finish(codecs)
}
mp4File.onError = () => {
finish([])
}
const readChunk = (start: number) => {
if (settled) {
return
}
if (start >= file.size || readSize >= maxReadSize) {
finish([])
return
}
const end = Math.min(start + chunkSize, file.size)
const reader = new FileReader()
reader.onload = () => {
const buffer: any = reader.result
if (!buffer) {
finish([])
return
}
buffer.fileStart = start
readSize += buffer.byteLength
let nextStart
try {
nextStart = mp4File.appendBuffer(buffer)
} catch (error) {
finish([])
return
}
if (!settled) {
const offset = typeof nextStart === 'number' && nextStart > start
? nextStart
: end
readChunk(offset)
}
}
reader.onerror = () => {
finish([])
}
reader.readAsArrayBuffer(file.slice(start, end))
}
readChunk(0)
})
}
使用
const BLOCKED_VIDEO_CODECS = ['hvc1', 'hev1', 'hevc', 'h265', 'h.265']
const codecs = await parseVideoCodecs(file)
let isBlockedCodec = codecs.some(codec => {
return BLOCKED_VIDEO_CODECS.some(blockedCodec => {
return codec.startsWith(blockedCodec) || codec.includes(blockedCodec)
})
})