H5调用原生摄像头,使用video标签实时渲染流数据到页面(拍照),处理ios自动全屏播放问题

500 阅读2分钟

调用摄像头

使用navigator.mediaDevices.getUserMedia

常用方法

方法描述
load()重新加载音频/视频元素。
play()开始播放音频/视频。
pause()暂停当前播放的音频/视频。

常用事件

事件描述
canplay当浏览器可以开始播放音频/视频时触发。
ended当目前的播放列表已结束时触发。
pause当音频/视频已暂停时触发。
play当音频/视频已开始或不再暂停时触发。
ratechange当音频/视频的播放速度已更改时触发。
timeupdate当目前的播放位置已更改时触发。

常用属性

属性描述
src设置或返回音频/视频元素的当前来源。
poster规定视频正在下载时显示的图像,直到用户点击播放按钮。
autoplay设置或返回是否在加载完成后随即播放音频/视频。
controls设置或返回音频/视频是否显示控件(比如播放/暂停等)。
currentTime设置或返回音频/视频中的当前播放位置(以秒计)。
duration返回当前音频/视频的长度(以秒计)。
ended返回音频/视频的播放是否已结束。
muted设置或返回音频/视频是否静音。
paused设置或返回音频/视频是否暂停。
playbackRate设置或返回音频/视频播放的速度。
preload设置或返回音频/视频是否应该在页面加载后进行加载。
volume设置或返回音频/视频的音量。

demo 实现

import React, { useRef } from 'react'

function Camera() {
    const wrapper = useRef<any>()
    const videoEl = useRef<any>()
    let stream: any

    async function checkCamera() {
        const navigator = window.navigator.mediaDevices
        const devices = await navigator.enumerateDevices()
        // console.log('devices: ', devices)
        if (devices) {
            stream = await navigator.getUserMedia({
                audio: false,
                video: {
                    // facingMode: { exact: "environment" }, //强制后置摄像头
                    facingMode: 'user', // 前置摄像头
                },
            })
            // console.log('stream: ', stream)
            if (!videoEl.current) return
            // 将摄像头流数据赋值给video【srcObject】属性
            videoEl.current.srcObject = stream
            /* 在video播放流 */
            videoEl.current.play()
        }
    }

    function captureFrame() {
        if (!videoEl.current || !videoEl.current) return
        const el = document.querySelector('#canvasElementCarrier') as any
        const canvas = document.createElement('canvas')
        canvas.width = videoEl.current.width
        canvas.height = videoEl.current.height

        // 拿到 canvas 上下文对象
        const ctx = canvas.getContext('2d')
        ctx?.drawImage(videoEl.current, 0, 0, canvas.width, canvas.height)
        // 插入截取图片展示
        el.appendChild(canvas)
    }

    return (
        <div className="home">
            <div
                ref={wrapper}
                style={{
                    width: '200px',
                    height: '300px',
                    background: 'pink',
                    fontSize: '20px',
                }}
        >
                {/* 截屏展示载体 */}
                <div
                    id="canvasElementCarrier"
                    style={{
                            width: '200px',
                            height: '100px',
                            background: 'yellow',
                    }}
                ></div>
                {/* 拍摄流数据展示载体 */}
                <video
                    ref={videoEl}
                    width={200}
                    height={100}
                    // 处理ios默认全屏播放视频
                    x5-video-player-type={'h5'}
                    x5-video-player-fullscreen={'true'}
                    playsInline
                    webkit-playsinline={'true'}
                    // autoPlay={true}
                    controls
                />
                {/* 操作按钮 */}
                <div style={{ display: 'flex' }}>
                    <div
                        onClick={captureFrame}
                        style={{
                            width: '50px',
                            height: '50px',
                            marginLeft: '10px',
                            background: 'blue',
                        }}
                    > 拍摄 </div>
                    <div
                        onClick={() => {
                                checkCamera()
                        }}
                        style={{
                            width: '50px',
                            height: '50px',
                            marginLeft: '10px',
                            background: 'green',
                        }}
                    > 开启 </div>
                    <div
                        onClick={() => {
                            function closeVideo() {
                                videoEl.current.srcObject.getVideoTracks()[0].enabled = false
                                videoEl.current.srcObject.getVideoTracks()[0].stop()
                            }
                            closeVideo()
                            videoEl.current.srcObject = null
                        }}
                        style={{
                            width: '50px',
                            height: '50px',
                            marginLeft: '10px',
                            background: 'red',
                        }}
                    > 关闭 </div>
                </div>
            </div>
        </div>
    )
}

export default Camera