1
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
export type xCamreaUOpts = {
|
||||
autoOpenCamera : boolean,
|
||||
/**
|
||||
* 是否打开闪光灯,对于orientation为back有效.
|
||||
*/
|
||||
flash : boolean,
|
||||
/**
|
||||
* 摄像头朝向,默认是后置
|
||||
* back,front
|
||||
*/
|
||||
orientation : string,
|
||||
/**
|
||||
* 相机的像素宽
|
||||
*/
|
||||
cameraWidth : number,
|
||||
/**
|
||||
* 相机的像素高
|
||||
*/
|
||||
cameraHeight : number,
|
||||
/**
|
||||
* 容器的宽和高
|
||||
*/
|
||||
width : number,
|
||||
/**
|
||||
* 容器的宽和高
|
||||
*/
|
||||
height : number
|
||||
}
|
||||
|
||||
export class xCamreaU {
|
||||
$element : HTMLDivElement;
|
||||
targetView : HTMLVideoElement = document.createElement("video");
|
||||
config : xCamreaUOpts;
|
||||
opening = false;
|
||||
private stream:any = null;
|
||||
private takeModelType = 'photo'
|
||||
private mediaRecorder: null | MediaRecorder = null
|
||||
private startRecoderVideoFunc = (path:string)=>{}
|
||||
|
||||
constructor(element : HTMLDivElement, opts : xCamreaUOpts) {
|
||||
this.config = opts;
|
||||
this.$element = element;
|
||||
this.createVideo();
|
||||
}
|
||||
private createVideo(){
|
||||
this.targetView.style.width = "100%"
|
||||
this.targetView.style.height = "100%"
|
||||
this.targetView.style.objectFit = "cover"
|
||||
this.targetView.playsInline = true;
|
||||
this.targetView.muted = true;
|
||||
this.targetView.autoplay = true;
|
||||
this.targetView.controls = false;
|
||||
// 针对微信的x5内核
|
||||
this.targetView.setAttribute('playsinline',true)
|
||||
this.targetView.setAttribute('webkit-playsinline',true)
|
||||
this.targetView.setAttribute('x5-playsinline',true)
|
||||
this.targetView.setAttribute('x5-video-player-type','h5')
|
||||
this.targetView.setAttribute('x5-video-player-fullscreen','false')
|
||||
|
||||
this.$element.appendChild(this.targetView)
|
||||
}
|
||||
getIsOpeningCameraing():boolean{
|
||||
return this.opening
|
||||
}
|
||||
setCameraDir(dir:string){
|
||||
}
|
||||
setFlash(flash:boolean){
|
||||
}
|
||||
start(call:(path:string)=>void) {
|
||||
this.takeModelType = 'video'
|
||||
this.startRecoderVideoFunc = call;
|
||||
if(!this.opening){
|
||||
this.openCamrea();
|
||||
}
|
||||
|
||||
}
|
||||
/** 关闭相机 */
|
||||
close() {
|
||||
let t = this;
|
||||
this.targetView.pause()
|
||||
if (t.stream) {
|
||||
t.stream.getTracks().forEach(function (track) {
|
||||
track.stop();
|
||||
});
|
||||
t.stream = null;
|
||||
}
|
||||
this.mediaRecorder = null;
|
||||
this.opening = false;
|
||||
}
|
||||
createMediaRecorder() {
|
||||
let t = this;
|
||||
if (!MediaRecorder.isTypeSupported('video/mp4')) {
|
||||
console.error("设备不支持录制 mp4 格式")
|
||||
this.startRecoderVideoFunc('')
|
||||
return;
|
||||
}
|
||||
const options = { mimeType: 'video/mp4' }; // 默认格式为 WebM
|
||||
this.mediaRecorder = new MediaRecorder(t.stream, options);
|
||||
let chunks = [];
|
||||
|
||||
this.mediaRecorder!.ondataavailable = (event) => {
|
||||
if (event.data.size > 0) {
|
||||
chunks.push(event.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.mediaRecorder!.onstop = () => {
|
||||
// 将录制的片段合并为 Blob 对象
|
||||
const blob = new Blob(chunks, { type: 'video/mp4' });
|
||||
chunks = [];
|
||||
const dataURL = URL.createObjectURL(blob)
|
||||
this.startRecoderVideoFunc(dataURL)
|
||||
};
|
||||
this.mediaRecorder!.onerror = () => {
|
||||
console.error("录制出错,请重试。")
|
||||
this.startRecoderVideoFunc('')
|
||||
}
|
||||
this.mediaRecorder!.start()
|
||||
}
|
||||
openCamrea(){
|
||||
|
||||
if(this.opening) return;
|
||||
this.opening = true;
|
||||
var constraints = {
|
||||
audio: true,
|
||||
video: {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
facingMode:this.config.orientation=='front'?{ exact: 'user' }:{ exact: 'environment' }
|
||||
}
|
||||
};
|
||||
let t = this;
|
||||
|
||||
window.navigator.mediaDevices
|
||||
.getUserMedia(constraints)
|
||||
.then(function (mediaStream) {
|
||||
t.stream = mediaStream
|
||||
t.targetView.srcObject = t.stream;
|
||||
t.targetView.onloadedmetadata = function (e) {
|
||||
t.targetView.play();
|
||||
|
||||
if (t.takeModelType == 'video') {
|
||||
t.createMediaRecorder()
|
||||
}
|
||||
};
|
||||
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.log(err.name + ": " + err.message);
|
||||
t.close()
|
||||
});
|
||||
|
||||
}
|
||||
takePhoto(call:(path:string)=>void){
|
||||
let t = this;
|
||||
if (!t.targetView || !t.stream || !t.opening) return call('');
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = t.targetView.videoWidth; // 设置canvas的宽度为视频的宽度
|
||||
canvas.height = t.targetView.videoHeight; // 设置canvas的高度为视频的高度
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx!.drawImage(t.targetView, 0, 0, canvas.width, canvas.height);
|
||||
canvas.toBlob((data) => {
|
||||
const dataURL = data ? URL.createObjectURL(data) : ""
|
||||
call(dataURL)
|
||||
}, 'image/png', 1)
|
||||
}
|
||||
|
||||
pause(){
|
||||
// this.mediaRecorder?.pause()
|
||||
this.close();
|
||||
}
|
||||
|
||||
stop(){
|
||||
this.mediaRecorder?.stop()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 检查权限
|
||||
export function checkPermissions():Promise<boolean> {
|
||||
return new Promise(async (res, rej) => {
|
||||
|
||||
let devices = await navigator.mediaDevices.enumerateDevices()
|
||||
let videoDevices = devices.filter(
|
||||
(device) => device.kind === 'videoinput'
|
||||
);
|
||||
|
||||
if (videoDevices.length == 0) {
|
||||
rej(false)
|
||||
console.error('没有找到可用的摄像设备')
|
||||
return;
|
||||
}
|
||||
if(!(window.navigator?.mediaDevices??undefined)){
|
||||
rej(false)
|
||||
console.error('设备不支持')
|
||||
return;
|
||||
}
|
||||
res(true)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user