【发布时间】:2020-11-26 06:41:00
【问题描述】:
我有一个网页,用户将在其中放置视频文件,该页面将上传视频,并根据用户提供的时间戳生成缩略图。
目前,我只是尝试根据视频的第一帧生成缩略图。
这里是我当前进度的一个快速示例:
(请使用 chrome,因为 firefox 会抱怨 https 链接,如果它自动下载图像,请见谅) https://stackblitz.com/edit/rxjs-qc8iag
import { Observable, throwError } from 'rxjs'
const VIDEO = {
imageFromFrame(videoSrc: any): Observable<any> {
return new Observable<any>((obs) => {
const canvas = document.createElement('canvas')
const video = document.createElement('video')
const context = canvas.getContext('2d')
const source = document.createElement('source');
source.setAttribute('src', videoSrc);
video.appendChild(source);
document.body.appendChild(canvas)
document.body.appendChild(video)
if (!context) {
throwError(`Couldn't retrieve context 2d`)
obs.complete()
return
}
video.load()
video.addEventListener('loadedmetadata', function () {
console.log('loadedmetadata')
// Set canvas dimensions same as video dimensions
canvas.width = video.videoWidth
canvas.height = video.videoHeight
})
video.addEventListener('canplay', function () {
console.log('canplay')
canvas.style.display = 'inline'
context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight)
// Convert canvas image to Base64
const img = canvas.toDataURL("image/png")
// Convert Base64 image to binary
obs.next(VIDEO.dataURItoBlob(img))
obs.complete()
})
})
},
dataURItoBlob(dataURI: string): Blob {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString
if (dataURI.split(',')[0].indexOf('base64') >= 0) byteString = atob(dataURI.split(',')[1])
else byteString = unescape(dataURI.split(',')[1])
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length)
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i)
}
return new Blob([ia], { type: mimeString })
},
}
VIDEO.imageFromFrame('https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4?_=1').subscribe((r) => {
var a = document.createElement('a')
document.body.appendChild(a)
const url = window.URL.createObjectURL(r)
a.href = url
a.download = 'sdf'
a.click()
window.URL.revokeObjectURL(url)
})
问题是,它下载的图片是空的,不代表视频的第一帧。但应该已经加载了视频。并在画布中绘制。
我正在尝试解决它,但如果有人可以帮助我找出问题,谢谢。
【问题讨论】:
-
FWIW,大多数视频的第一帧会是黑色的或者不是很有趣 - 通常最好使用大约 1 秒的帧。
-
你为什么使用
any?为什么不能使用已定义的类型? -
1) => 是的,这就是为什么我们可以选择不同的帧,但现在我只想要第一个(在演示视频中第一个帧不是黑色的)2)因为它是最小的可重复性stackblitz 上的演示......它是一个草稿,知道它是否可能。当我在我的应用程序中实现它时,我会做得更好...
-
我认为它失败的原因是因为画布被“污染”了,因为视频来自另一个来源,并且它的 CORS 政策不允许这样做。见这里:stackoverflow.com/questions/13674835/…
-
我确实在某些时候收到了这个错误,但它通常会在发生时显示在控制台中。
标签: javascript html typescript