最近在做一个后台管理系统,使用ueditor上传视频到腾讯云点播,前台网站再使用js-sdk-v6(即腾讯云点播提供的播放器插件),在ios和pc上可以正常播放,但是在安卓手机的微信浏览器和QQ浏览器(这两个都是X5内核的浏览器)上播放不正常,播放界面非常小,如下图:
播放界面特别小,根本就看不清。咨询云点播说是视频被劫持了,但是加上x5-video-player-type="h5" x5-video-player-fullscreen="true" webkit-playsinline playsinline 这几个属性还是不行。
最后想到一个解决方案:就是后端判断,如果访问设备是安卓,就不引用云点播的播放器,使用video原生的h5播放器。但是这样还是有一个问题是在安卓机的微信浏览器中不显示视频的封面图,没开始播放的时候界面是黑色的,产品希望在视频没播放之前有一个封面图,截取视频的第一帧作为封面图。后来在网上搜索到使用canvas绘图,但是这个有一个限制是视频文件和页面必须在一个服务器上才可以,不然会报这个错:
Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
经过查阅和分析,发现这个其实是由于视频文件所在的域和图片和页面所在域不同,出现跨域传输的问题
解决方案:
因为: 【 如果视频文件所在的 域 和 当前index.html页面所在域不同,就会出现跨域传输的问题】,【及便是给img标签加上crossOrigin': 'anonymous'
貌似也没用!】。
所以: 请将 视频文件 和 当前index.html页面放在同一个域中,并在服务器中打开(用phpStudy工具或live-server等),才能正常运行。
主要代码如下:
<style>
canvas,
img {
width: 600px;
height: 350px;
border: 1px solid darkgray;
}
</style>
<header>
<video id="video" src="./video.mp4" controls width="600" height="400" loop></video>
<!-- <video id="video" src="http://video.vocy.cn/93/video/1553929815754.mp4" controls width="600" height="400"
loop></video> -->
<p>视频播放器-VIDEO</p>
</header>
<div >
<canvas id="canvas" class="canvas"></canvas>
<p>视频同步渲染到-CANVAS</p>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script>
(function () {
var video = document.getElementById("video");
var canvas = document.getElementById("canvas");
var interval1 = interval2 = null;
//截取视频画面
var CaptureFirstFrame = function () {
this.saveImageInfo = function () {
console.log('base64图片:', canvas.toDataURL("image/png"))
}
};
//打开全屏方法
CaptureFirstFrame.prototype = {
CaptureVideo: function (img, rsy, bbg) {
//canvas 缩放比率
this.scale = 1;
//创建canvas元素
this.cvs = document.createElement("canvas");
//设置canvas画布大小
this.cvs.width = canvas.width = video.videoWidth * this.scale;
this.cvs.height = canvas.height = video.videoHeight * this.scale;
//设置canvas画布内容、位置
this.cvs.getContext('2d').drawImage(video, 0, 0, this.cvs.width, this.cvs.height);
//注:
/*
* canvas.toDataURL("image/png", 1) 方法可能会出错!!!
* 因为 【 如果视频文件所在的 域 和 当前index.html页面所在域不同,就会出现跨域传输的问题】,【及便是给img标签加上crossOrigin': 'anonymous' 也没用!】
* 所以 请将 视频文件 和 当前index.html页面放在同一个域中,并在服务器中打开(用phpStudy工具等),才能正常运行。
*/
if (img) {
$('#rendering-img').attr({
'crossOrigin': 'anonymous',
'src': this.cvs.toDataURL("image/png", 1)
});
};
if (rsy) {
canvas.getContext('2d').drawImage(video, 0, 0, this.cvs.width, this.cvs.height);
};
if (bbg) {
$(document.body).css('background-image', 'url(' + this.cvs.toDataURL("image/png", 1) + ')');
};
},
};
var V = new CaptureFirstFrame();
//监听视频加载完成时 获取第一帧
video.addEventListener('loadeddata', function () {
V.CaptureVideo(true);
}, false);
})();
</script>
但是这个对于视频还没开始播放的视频来说是不运行的。所以这种方案最后也只能放弃。
最后在腾讯云点播的api中找到一个接口,可以返回视频某一帧的截图。此接口地址为:https://cloud.tencent.com/document/product/266/8102
需要后端去处理,然后我需在视频上传成功的回调中调后台返回 的接口(此接口返回截图的url),然后我再在video标签中把这个url赋值给poster。代码如下:
uploader.done().then(function (doneResult) {
console.log("doneResult:", doneResult)
let mediaInfo = {}
console.log("signature:", getSignature)
/* axios.post(`${CFG.API_URL}xsnArticle/getMediaInfos`, { fileId: doneResult.fileId })
.then(function (response) {
console.log('video:==', response.vo)
if (response.status === 200) {
mediaInfo = { width: response.data.vo.MediaInfoSet[0].MetaData.width, height: response.data.vo.MediaInfoSet[0].MetaData.height, coverUrl: response.data.vo.MediaInfoSet[0].BasicInfo.CoverUrl }
console.log("media:", mediaInfo)
}
}) */
UE.instants[index].execCommand(
'insertHtml',
'<img width="600" height="400" id="video_' +
doneResult.fileId +
'" _url="' +
doneResult.video.url +
'" alt="' +
doneResult.fileId +
'" class="edui-upload-video vjs-default-skin video-js" src="/static/UEditor/themes/default/images/spacer.gif" style ="background:url(/static/UEditor/themes/default/images/videologo.gif) no-repeat center center; border:1px solid gray;" x5-video-player-type="h5" playsinline webkit-playsinline controls="true" />'
)
}).then(function (videoUrl) {
self.$refs.vExample.reset()
self.dialogVisible = false
})