Vue 控制多个摄像头拍照

Vue 控制多个摄像头拍照

1. 文档目录

.
├── app.js
├── css
│   └── index.css
├── index.html
└── scss
    └── index.scss

2. 源码

js

// app.js
var app = new Vue({
    el: '#app',
    data: {
        cameraList: [],
        myCanvas: null,
        myContext: null
    },
    methods: {
        main () {
            this.myCanvas = document.getElementById('canvas')
            this.myContext = this.myCanvas.getContext('2d')
            this.cameraList.forEach((camera, index) => {
                let domId = `video${index}`
                let video = document.getElementById(domId)
                this.enableCamera(camera.id, video)
            })
        },

        /** @desc 摄像头使能封装 */
        enableCamera (deviceId, video) {
            this.getUserMedia(this.setConstraints(deviceId), (stream) => {
                video.srcObject = stream;
                video.onloadedmetadata = (e) => {
                    video.play()
                }
            }, error => {
                console.log(`访问用户媒体设备失败${error.name}, ${error.message}`)
            })
        },

        /** @desc 获取计算机外设列表 储存摄像头数据 */
        getDevices () {
            return new Promise((resolve, reject) => {
                if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
                    window.alert("不支持 mediaDevices.enumerateDevices()")
                }
                navigator.mediaDevices.enumerateDevices().then(devices => {
                    console.log(devices)
                    this.cameraList = []
                    devices.forEach((device, index) => {
                        if (device.kind && device.kind === 'videoinput') {
                            this.cameraList.push({
                                id: device.deviceId,
                                label: device.label
                            })
                        }
                    })
                    resolve()
                }).catch((err) => {
                    console.log(err.name + ": " + err.message)
                    reject()
                })
            })
        },

        takePhoto (idx) {
            let videoId = `video${idx}`
            let videoDom = document.getElementById(videoId)
            this.myContext.drawImage(videoDom, 0, 0, 480, 320)
        },

        // tools
        /** @desc API getUserMedia  兼容封装 */
        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)
            }
        },
        /** @desc 摄像头配置项通用配置 */
        setConstraints (deviceId) {
            return {
                audio: false,
                video: {
                    width: 480,
                    height: 320,
                    deviceId: deviceId
                }
            }
        }
    },
    mounted () {
        this.getDevices().then(() => {
            this.main()
        })
    }
})

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">
    <link rel="stylesheet" href="./css/index.css">
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>摄像头拍照</title>
</head>

<body>
    <div id="app">
        <div class="video-list">
            <div class="video-container" v-for="(item, index) in cameraList" :key="index">
                <video :id="'video' + index" width="480" height="320" controls></video>
                <div class="btns">
                    <button @click="takePhoto(index)">拍照</button>
                </div>
                <div class="name" :id="'name' + index">{{item.label}}</div>
            </div>
        </div>
    </div>

    <canvas id="canvas" width="480" height="320"></canvas>

    <script src="./app.js"></script>
</body>

</html>

css

/* index.css */
.video-list {
    .video-container {
        position: relative;
        z-index: 1;
        padding: 4px;
        display: inline-block;
        vertical-align: top;
        background-color: #eee;
        .btns {
            text-align: center;
        }
        .name {
            position: absolute;
            top: 8px;
            left: 8px;
            z-index: 2;
            font-size: 24px;
            white-space: nowrap;
            color: red;
        }
    }
}

3. 注意点

  • 浏览器兼容性:只能使用现代浏览器
  • Safari浏览器:只能检测外接摄像头
  • 部署问题:由于浏览器安全限制,只能部署在https 或 localhost 上

API兼容性 参考Web APIs | MDN

猜你喜欢

转载自blog.csdn.net/liu_moran/article/details/106758814