ps-tcplayer
Version:
Tencent Cloud Player component with Vue2/Vue3 compatibility
180 lines (149 loc) • 5.09 kB
JavaScript
import snapshotHtml from './index.html'
import './index.scss'
import { parseDom } from '../../utils'
/**
* 视频截图组件
*/
export default class SnapshotComponent {
/**
* @constructor 视频截图组件构造函数
*/
constructor(player) {
this.player = player
this.html = parseDom(snapshotHtml)
}
createEl(el) {
const controlBar = el.querySelector('.vjs-control-bar');
if (controlBar) {
const tcpVideoQualitySwitcher = controlBar.querySelector('.vjs-fullscreen-control')
controlBar.insertBefore(this.html, tcpVideoQualitySwitcher.previousSibling)
} else {
console.warn('找不到播放器控制栏,尝试添加到根元素');
el.appendChild(this.html);
}
}
ready() {
// 设置视频跨域属性
this.setupVideoForSnapshot()
// 添加点击事件监听器
this.html.addEventListener('click', () => {
this.captureSnapshot()
})
}
/**
* 设置视频元素支持跨域截图
*/
setupVideoForSnapshot() {
const video = this.player.tech_.el_
if (video && !video.crossOrigin) {
// 设置跨域属性
video.crossOrigin = 'anonymous'
video.setAttribute('crossOrigin', 'anonymous')
}
}
/**
* 捕获当前视频帧并下载
*/
captureSnapshot() {
const player = this.player
const video = player.tech_.el_
if (!video) {
console.error('视频元素不存在')
this.showErrorMessage('视频元素不存在')
return
}
const canvas = document.createElement('canvas')
canvas.width = video.videoWidth || video.clientWidth
canvas.height = video.videoHeight || video.clientHeight
const ctx = canvas.getContext('2d')
try {
// 绘制视频帧到 canvas
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
// 尝试导出图片数据
const imageData = canvas.toDataURL('image/png')
const link = document.createElement('a')
link.href = imageData
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
const title = player.el_.getAttribute('title') || 'video'
const filename = `${title}_${timestamp}.png`
link.download = filename
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
console.log('截图成功:', filename)
} catch (error) {
console.error('截图失败:', error)
if (error.name === 'SecurityError') {
// this.showErrorMessage('截图失败:视频跨域限制,请联系管理员配置 CORS 头部')
// 尝试使用替代方案
this.tryAlternativeSnapshot(video)
} else {
this.showErrorMessage('截图失败:' + error.message)
}
}
}
/**
* 尝试替代截图方案
*/
tryAlternativeSnapshot(video) {
try {
// 方案1: 尝试重新加载视频并设置跨域
const videoSrc = video.src || video.currentSrc
if (videoSrc) {
console.log('尝试重新加载视频并设置跨域属性...')
// 创建新的视频元素用于截图
const tempVideo = document.createElement('video')
tempVideo.crossOrigin = 'anonymous'
tempVideo.muted = true
tempVideo.style.display = 'none'
tempVideo.addEventListener('loadeddata', () => {
tempVideo.currentTime = video.currentTime
})
tempVideo.addEventListener('seeked', () => {
this.captureFromTempVideo(tempVideo)
document.body.removeChild(tempVideo)
})
document.body.appendChild(tempVideo)
tempVideo.src = videoSrc
tempVideo.load()
}
} catch (altError) {
console.error('替代方案也失败了:', altError)
this.showErrorMessage('所有截图方案都失败了,请检查视频源的 CORS 配置')
}
}
/**
* 从临时视频元素截图
*/
captureFromTempVideo(video) {
const canvas = document.createElement('canvas')
canvas.width = video.videoWidth
canvas.height = video.videoHeight
const ctx = canvas.getContext('2d')
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
try {
const imageData = canvas.toDataURL('image/png')
const link = document.createElement('a')
link.href = imageData
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
const title = this.player.el_.getAttribute('title') || 'video'
const filename = `${title}_${timestamp}.png`
link.download = filename
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
} catch (error) {
console.error('替代方案截图失败:', error)
this.showErrorMessage('替代方案截图失败')
}
}
/**
* 显示错误消息
*/
showErrorMessage(message) {
// if (typeof window !== 'undefined' && window.alert) {
// alert(message)
// }
console.warn('[SnapshotComponent]', message)
}
}