惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
小众软件
小众软件
GbyAI
GbyAI
B
Blog RSS Feed
月光博客
月光博客
A
About on SuperTechFans
Microsoft Security Blog
Microsoft Security Blog
Blog — PlanetScale
Blog — PlanetScale
U
Unit 42
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Vercel News
Vercel News
F
Fortinet All Blogs
Apple Machine Learning Research
Apple Machine Learning Research
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
Engineering at Meta
Engineering at Meta
aimingoo的专栏
aimingoo的专栏
博客园_首页
G
Google Developers Blog

WishMeLz - 未分类

VOXI 使用记录 · WishMeLz MailHub · WishMeLz Docker 客户端中文 · WishMeLz SuJian 1.0:给自己的博客换一张素笺 · WishMeLz MailHub - 服务条款 · WishMeLz MailHub - 隐私权政策 · WishMeLz blog.itsse.cn 柯尼卡美能达 bizhub C226 复印机 SMB 扫描到电脑配置教程 minio 最后的绝唱 搭建配置流程 - WishMeLz 港卡,CSL 记录 - WishMeLz Safari 解锁 120hz - WishMeLz CraneMail 优化访问速度之 - Stunnel/HAProxy - WishMeLz Racknerd 2025 黑五闪购套餐汇总 - WishMeLz 香港各大机房/商家测试 IP 整理|DMIT、BWG、LocVPS、SurferCloud、UCloud、51IDC 等 NodeBB 搭建安装笔记 v4.x - WishMeLz 阿里云保备案,不花一分钱 - WishMeLz App Store App历史版本下载 - WishMeLz
前端分片解析 MP4 视频编码,判断是否为 H.265/HEVC · WishMeLz
Wish · 2026-09-16 · via WishMeLz - 未分类
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)
                    })
                })