h5/web 获取实时视频并预览上传

注意:需要在 https 或者 localhost 下才能成功调起摄像头(如果是html使用file协议也能成功)

2022.01.14更新

  • 在chrome内核的浏览器大部分能实现录制上传功能,不支持iPhone 的 safari 浏览器,兼容性较差(MediaRecorder录制api ,这个api在uc浏览器和iphone的safari浏览器中不支持)
  • 下面uniapp已经实现视频上传功能(仅在chrome内核浏览器中)
2020.01.17 更新
  • 在ios14以上,开始支持MediaRecorder

建议大家先阅读一下参考文档

参考文档

html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title>摄像头拍照</title>
	</head>
	<body>
		<video id="video" width="300" height="300" controls>
		</video>
		<div>
			<button id="capture">拍照</button>
		</div>
		<canvas id="canvas" width="480" height="320"></canvas>
		<script src="https://cdn.bootcdn.net/ajax/libs/vConsole/3.11.0/vconsole.min.js"></script>
		<script>
			// var vConsole = new VConsole();
			
			//访问用户媒体设备的兼容方法
			function getUserMedia(constraints, success, error) {
				if (navigator.mediaDevices.getUserMedia) {
					//最新的标准API
					navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
				} else if (navigator.webkitGetUserMedia) {
					//webkit核心浏览器
					navigator.webkitGetUserMedia(constraints, success, error)
				} else if (navigator.mozGetUserMedia) {
					//firfox浏览器
					navigator.mozGetUserMedia(constraints, success, error);
				} else if (navigator.getUserMedia) {
					//旧版API
					navigator.getUserMedia(constraints, success, error);
				}
			}

			let video = document.getElementById('video');
			let canvas = document.getElementById('canvas');
			let context = canvas.getContext('2d');

			function success(stream) {
				//兼容webkit核心浏览器
				let CompatibleURL = window.URL || window.webkitURL;
				//将视频流设置为video元素的源
				console.log(stream);

				// video.src = CompatibleURL.createObjectURL(new Blob(stream));
				video.srcObject = stream;
				video.play();
			}

			function error(error) {
				console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
				console.log(error)
			}

			if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator
				.mozGetUserMedia) {
				//调用用户媒体设备, 访问摄像头
				getUserMedia({
					video: {
						width: 300,
						height: 300
					}
				}, success, error);
			} else {
				alert('不支持访问用户媒体');
			}

			document.getElementById('capture').addEventListener('click', function() {
				context.drawImage(video, 0, 0, 480, 320);
			})
			
		</script>
	</body>
</html>

vue 中使用

<template>
  <div>
    <video id="video" width="300" height="300" controls></video>
    <div>
      <button id="capture" @click="btnClick">拍照</button>
    </div>
    <canvas id="canvas" width="320" height="320"></canvas>
  </div>
</template>

<script>
export default {
  data() {
    return {
      video: null,
      canvas: null,
      context: null,
    }
  },
  mounted() {
    let video = document.getElementById('video');
    let canvas = document.getElementById('canvas');
    // uniapp 对 video 标签进行了封装 所以用下面的方式获取
    // let video = document.getElementsByClassName('uni-video-video')[0]
    // let canvas = document.getElementsByTagName('canvas')[0]

    console.log(canvas)
    let context = canvas.getContext('2d');

    this.video = video
    this.init()
    this.canvas = canvas
    this.context = context
  },
  methods: {
    // 获取设备
    getUserMedia(constraints, successCallback, errorCallback) {
      if (navigator.mediaDevices.getUserMedia) {
        //最新的标准API
        navigator.mediaDevices.getUserMedia(constraints).then(successCallback).catch(errorCallback);
      } else if (navigator.webkitGetUserMedia) {
        //webkit核心浏览器
        navigator.webkitGetUserMedia(constraints, successCallback, errorCallback)
      } else if (navigator.mozGetUserMedia) {
        //firfox浏览器
        navigator.mozGetUserMedia(constraints, successCallback, errorCallback);
      } else if (navigator.getUserMedia) {
        //旧版API
        navigator.getUserMedia(constraints, successCallback, errorCallback);
      }
    },
    successCallback(stream) {
      //兼容webkit核心浏览器
      // let CompatibleURL = window.URL || window.webkitURL;
      // video.src = CompatibleURL.createObjectURL(new Blob(stream));
      //将视频流设置为video元素的源
      console.log(stream);
      console.log(this.video)

      this.video.srcObject = stream;
      this.video.play();
    },
    errorCallback(error) {
      console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
      console.log(error)
    },
    init() {
      if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia) {
        //调用用户媒体设备, 访问摄像头
        this.getUserMedia(
          {
            video: { width: 320, height: 320 },
          },
          this.successCallback,
          this.errorCallback
        );
      } else {
        alert('不支持访问用户媒体');
      }
    },
    btnClick() {
      this.context.drawImage(this.video, 0, 0, 320, 320);
    }
  }
}
</script>

<style>
</style>


uniapp h5端 使用

<template>
	<view>
		<video id="video" class="video-box" width="120" height="120" :controls="false"></video>
		<div>
			<button id="capture" @click="btnClick">拍照</button>
		</div>
		<canvas id="canvas" width="120" height="120"></canvas>
		<!-- <view class="">
			上传成功地址: {{uploadSuccessURL}}
		</view> -->
		<view v-for="(item,index) in list" :key="index">
			{{item}}
		</view>
	</view>
</template>

<script>
	import { uploadFileURL } from '@/common/config.js'
	export default {
		data() {
			return {
				video: null,
				canvas: null,
				context: null,
				uploadSuccessURL: '',
				list: []
			}
		},
		onReady() {
			// #ifdef H5
			// uniapp 对 video 标签进行了封装 所以用下面的方式获取
			let video = document.getElementsByClassName('uni-video-video')[0]
			// let video = document.getElementById('video');
			// let canvas = document.getElementById('canvas');
			let canvas = document.getElementsByTagName('canvas')[0]
			console.log(canvas)
			let context = canvas.getContext('2d');
			
			this.video = video
			this.canvas = canvas
			this.context = context
			const _this = this
			uni.showModal({
				content: '是否进行人脸认证',
				success(r) {
					if(r.confirm) {
						_this.init()
					}
					if(r.cancel) {
						uni.redirectTo({
							url: '/pages/index/index'
						})
					}
				}
			})
			// this.init()
			// #endif
			
		},
		methods: {
			// 获取设备
			// constraints 这个用来控制你需要调取的设备
			getUserMedia(constraints, successCallback, errorCallback) {
				if (navigator.mediaDevices.getUserMedia) {
					//最新的标准API
					navigator.mediaDevices.getUserMedia(constraints).then(successCallback).catch(errorCallback);
				} else if (navigator.webkitGetUserMedia) {
					//webkit核心浏览器
					navigator.webkitGetUserMedia(constraints, successCallback, errorCallback)
				} else if (navigator.mozGetUserMedia) {
					//firfox浏览器
					navigator.mozGetUserMedia(constraints, successCallback, errorCallback);
				} else if (navigator.getUserMedia) {
					//旧版API
					navigator.getUserMedia(constraints, successCallback, errorCallback);
				}
			},
			// 调用摄像头 成功的回调
			successCallback(stream) {
				//兼容webkit核心浏览器
				this.list.push('走进摄像头成功回调')
				//将视频流设置为video元素的源
				console.log(stream);
				// console.log(this.video)
				
				// 录制视频
				this.recordVideo(stream)
				// 录制视频 end
				
				this.video.srcObject = stream;
				this.video.play();
			},
			// 调用摄像头 失败的回调
			errorCallback(error) {
				this.list.push('摄像头调用失败')
				console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
				console.log(error)
				
				const errorMap = {
				 'NotAllowedError': '摄像头已被禁用,请在系统设置或者浏览器设置中开启后重试',
				 'AbortError': '硬件问题,导致无法访问摄像头',
				 'NotFoundError': '未检测到可用摄像头',
				 'NotReadableError': '操作系统上某个硬件、浏览器或者网页层面发生错误,导致无法访问摄像头',
				 'OverConstrainedError': '未检测到可用摄像头',
				 'SecurityError': '摄像头已被禁用,请在系统设置或者浏览器设置中开启后重试',
				 'TypeError': '类型错误,未检测到可用摄像头'
				};
				if(errorMap[error.name]) {
					console.log(errorMap[error.name])
					this.$toast(errorMap[error.name])
				}
			},
			// 录制视频
			recordVideo(stream) {
				this.list.push('走进录制视频')
				const _this = this
				// https://developer.mozilla.org/zh-CN/docs/Web/API/MediaRecorder
				if(!MediaRecorder) {
					this.$toast('当前环境不支持MediaRecorder录制')
					return
				}
				this.list.push('当前环境含有MediaRecorder')
				var chunks = [];
				var mediaRecorder = new MediaRecorder(stream);
				this.list.push('当前环境成功 new MediaRecorder')
				mediaRecorder.start()
				this.list.push('当前环境 mediaRecorder.start')
				// 默认录制3秒后上传 mediaRecorder.stop()会触发 mediaRecorder.ondataavailable()事件
				setTimeout(function() {
					mediaRecorder.stop()
				}, 3000 )
				
				// 获取录制的资源 上传文件
				mediaRecorder.ondataavailable = function(e) {
					_this.list.push('获取录制的资源 ondataavailable')
					chunks.push(e.data);
					console.log('chunks', chunks)
					
					var file = new File(chunks, "media_.mp4");
					_this.list.push('获取录制的资源 new File 成功')
					console.log('file', file)
					
					var formData = new FormData();
					formData.append('file', file);
					console.log('formData', formData)
					console.log(e)
					_this.list.push('获取录制的资源 成功走到上传前')
					// 创建 ajax 开始上传
					var xhr = new XMLHttpRequest();
					
					xhr.open('post', uploadFileURL);
					xhr.send(formData);
					
					xhr.onreadystatechange = function(){
						// 判断服务器是否响应,判断异步对象的响应状态
						if(xhr.status == 200 && xhr.readyState == 4){
					 		console.log(xhr.responseText);
							const res = JSON.parse(xhr.responseText)
							_this.uploadSuccessURL = res.data.path
							_this.$toast(res.message || '上传完成')
						} else if(xhr.readyState == 4 && xhr.status != 200) {
							console.log(xhr.status)
						}
					}
				}
			},
			// 初始化调用
			init() {
				// #ifdef H5
				if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator .mozGetUserMedia) {
					//调用用户媒体设备, 访问摄像头
					this.getUserMedia(
						{ 
							// audio: true, // 调用录音
							video: { 
								width: 120, 
								height: 120,
								facingMode: "user" //调用前置摄像头
							},
						},
						this.successCallback,
						this.errorCallback
					);
				} else {
					alert('不支持访问用户媒体');
				}
				// #endif
			},
			// 点击拍照
			btnClick() {
				this.context.drawImage(this.video, 0, 0, 120, 120);
			},
			close() {
				this.video = null
				this.canvas = null
				this.context = null
			}
		}
	}
</script>

<style scoped>
.video-box {
	width: 120px;
	height: 120px;
	border-radius: 50%;
	margin: 0 auto;
	margin-top: 100rpx;
	display: block;
}
</style>


  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值