js将视频分解为图片帧 标准码农 技术分享 290 views ###### 电脑CPU是i7-7700 ###### 待处理视频为4K分辨率 3分钟32秒 50fps 一共10600帧 ###### 内存用的不多 但是CPU已经跑满 可能是因为浏览器的js是单线程缘故导致任务无法并行,集中运算CPU性能跟不上 ###### 截取视频思路: ###### 通过 mediainfo.js 来获取视频基本信息:帧率,帧数,时长 ###### js定时器的时间间隔单位是毫秒,帧率是每秒钟播放多少张图片,那么就可以计算每多少毫秒截取一次即为一帧 ###### 那么在定时器设置时间间隔就是:1000 / 帧率 ###### 在定时器的回调函数中,先video.pause(),然后在canvas画布上画出当前视频帧,然后把图片的base64字符串赋值给img.src,最后再video.play() ###### 这样就可以在img标签区域实时“观看”截取的视频帧 ###### 目前来说瓶颈在CPU,回头换个更好的电脑试试能不能在客户端搞定这个事 ###### 前几秒还行,一帧一帧的截取,但是到后来就跳帧跳的明显了。 ```html <body> <div id="wrapper"> <input type="file" id="fileInput" name="fileInput"/> <label id="file-info"></label> <video muted style="visibility: hidden"> </video> <img alt="pic" width="320" height="180" src=""> </div> </body> <script type="text/javascript" src="https://unpkg.com/mediainfo.js/dist/mediainfo.min.js"></script> <script> const fileInput = document.getElementById('fileInput') const onChangeFile = (mediainfo, fn) => { const file = fileInput.files[0] if (file) { const getSize = () => file.size const readChunk = (chunkSize, offset) => new Promise((resolve, reject) => { const reader = new FileReader() reader.onload = (event) => { if (event.target.error) { reject(event.target.error) } resolve(new Uint8Array(event.target.result)) } reader.readAsArrayBuffer(file.slice(offset, offset + chunkSize)) }) mediainfo .analyzeData(getSize, readChunk) .then((result) => { // output.value = result if (typeof fn === 'function') { result.media.track.forEach(function (v) { if (v['@type'] === 'Video') { fn.call(null, file, Number(v['FrameRate']), Number(v['FrameCount']), Number(v['Duration'])); } }); } }) .catch((error) => { console.dir(error) }) } } MediaInfo({format: 'object'}, (mediainfo) => { fileInput.addEventListener('change', () => { onChangeFile(mediainfo, (file, frameRate, frameCount, duration) => { document.querySelector('#file-info').innerHTML = "共" + frameCount + "帧"; window.URL = window.URL || window.webkitURL; let timeoutHandle = null; let url = window.URL.createObjectURL(file); // let video = document.createElement('video'); let video = document.querySelector('video') // video.setAttribute('crossorigin', 'Anonymous'); // video.setAttribute('muted', true); video.innerHTML = "<source src='" + url + "'>"; // video.setAttribute('preload', 'auto'); video.addEventListener('canplay', function () { let width = video.clientWidth || video.width || video.videoWidth; let height = video.clientHeight || video.height || video.videoHeight; let timeInterval = 1000 / frameRate; let canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; let img = document.querySelector('img'); const createImage = function () { if (video.currentTime <= duration) { video.pause(); canvas.getContext('2d').drawImage(video, 0, 0, width, height); img.src = canvas.toDataURL('image/jpeg') video.play(); timeoutHandle = setTimeout(createImage, timeInterval); } else { clearTimeout(timeoutHandle); } } createImage(); }) }); }) }) </script> ``` 帮助PHPZlc项目! 与任何开源项目一样, 贡献代码 或 文档 是最常见的帮助方式, 但我们也有广泛的 赞助机会。 0 加入技术群 评论 去登录