琢磨了很久,翻了很多相关文档,才实现了用threejs渲染视频的方法
思路如下
1 在wxml文件里写两个canvas
<canvas type="webgl" class="myCanvas" id="myCanvas"></canvas>
<canvas style="position: absolute;left: 0;top:300rpx;background-color: red;" type="2d" id="target1"></canvas>
2 实例threeJs相关实例和方法,具体参考,可以百度,
3 添加2d相关实例方法,
export default class VideoPlayer {
constructor(component){// component 是组件里的this,
this.decoder = wx.createVideoDecoder()
this.component = component
const videoUrl = 'https://cdn2.h5no1.com/static-cdn/cpbz/v.mp4';
this.dataUriList = []
}
getCanvasNode(id) {
return new Promise((resolve) => {
this.component.createSelectorQuery()
.select('#' + id)
.node(res => resolve(res.node))
.exec();
});
}
async downLoad(url){ // 下载视频并压缩视频,如果不压缩可能会卡
return new Promise(resolve=>{
wx.downloadFile({
url,
success:res=>{
wx.compressVideo({
quality:'low',
// resolution:0.9,
// fps:60,
src:res.tempFilePath,
success:result=>{
console.log(result)
resolve(result.tempFilePath)
}
})
},
fail:()=>{
resolve(url)
}
})
})
}
async playVideo(id,videoUrl,cb){
const canvas = await this.getCanvasNode(id) //获取2dcanvas节点
const path = await this.downLoad(videoUrl) // 下载视频并返回本地地址
const context = canvas.getContext('2d') // 2d上下文
const render = ({ data, width, height }) => { // 渲染2d时,返回DataURI数据,作为纹理数据
canvas.height = height
canvas.width = width
const imageData = canvas.createImageData(data, width, height)
context.putImageData(imageData, 0, 0)
if(canvas.toDataURL()){
cb && cb(canvas.toDataURL()) // cb回调方法
}
}
const decoder = wx.createVideoDecoder() // 创建视频解码器
await decoder.start({ // 开始解码
abortAudio: true,
source:path || videoUrl // tempFilePath,
})
return Promise.resolve({
decoder,
stop(){
return decoder.remove()
},
play:async ()=>{
let imageData = decoder.getFrameData() // 获取下一帧的解码数据
if (imageData){
render(imageData)
}
}
})
}
}
4 在threejs中引入上面的代码
import VideoPlayer from "./video.js"
/*
省略前面的代码
*/
this.videoPlayer = new VideoPlayer(this)
this.vp = null
var geometry = new THREE.PlaneGeometry( 520, 320, 1);
var material = new THREE.MeshBasicMaterial( {side: THREE.DoubleSide} );
var plane3 = new THREE.Mesh( geometry, material );
plane3.position.set(0,rangeSize/2/2,-rangeSize/2)
scence.add( plane3 );
this.videoPlayer.playVideo('target1','https://video-qn.51miz.com/preview/video/00/00/12/22/V-122260-B7D997DF.mp4',async (res)=>{
if(res){
textureLoader.load(res,texture=>{ // 加载datauri数据到纹理,一定要写在回调里,不然也看着卡顿
texture.minFilter = THREE.NearestFilter
plane3.material.map = texture
});
}
}).then(res=>{
this.vp =res
})
// 动画帧方法
this.wgbglCanvas.requestAnimationFrame(()=>{
if(this.vp && this.vp.play){
this.vp.play()
}
})
5 视频解码器 文档 https://developers.weixin.qq.com/miniprogram/dev/api/media/video-decoder/wx.createVideoDecoder.html
这个方法很重要,没有这个方法,根本就不能实现webgl视频播放
大哥可以更详细点吗