在 iPadOS17 显示采集卡采集到的视频
网页地址
使用方式
在 iPad OS 17 设备上插上采集卡然后 chrome 或者 safari 打开上面的网址允许访问摄像头和麦克风就行了。
源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<select id="select" title="输入设备" onselect="switchDirection()">
<option></option>
</select>
<button onclick="playPause()">播放/暫停</button>
<button onclick="screenshot()">截圖</button>
<!-- video 標籤中的自動播放屬性 autoplay,沒有它,你需要調用 video.play() 才能真正開始顯示圖像 -->
<video autoplay id="video" controls="controls" width="96%"></video>
<canvas id="canvas"></canvas>
<div id="imageData"></div>
</body>
<script>
const select = document.getElementById('select');
// JavaScript訪問設備前後攝像頭
const constraints = { // 初始值
video: {
// width: {
// min: 300,
// ideal: 1920,
// max: 500
// },
// height: {
// min: 250,
// ideal: 1080,
// max: 400
// },
width: { ideal: 1920 },
height: { ideal: 1080 }
}, // 流以正確的寬度和高度比例進入,如果它是處於縱向模式的手機,則需要進行尺寸反轉
audio: true,
};
const myVideo = document.querySelector('#video');
let videoStream = null; // 視頻流對象
let useFrontCamera = true; // 前置攝像頭
if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) { // 檢查瀏覽器是否支持此API
enumerateDevices((devices) => { gotDevices(devices); }); // 瀏覽器支持
} else {
console.log('暫不支持');
}
function playPause() {
if (myVideo.paused)
myVideo.play();
else
myVideo.pause();
}
// 繪製canvas畫布、獲取data
function screenshot() {
canvas.width = myVideo.videoWidth;
canvas.height = myVideo.videoHeight;
canvas.getContext('2d').drawImage(myVideo, 0, 0);
const img = document.createElement('img');
img.src = canvas.toDataURL('image/png');
let divImage = document.getElementById('#imageID');
divImage.appendChild(img);
}
// 你想在已經播放視頻的情況下更換攝像機的前後攝像頭,需要先停止當前的前置或者後置的視頻流,再將其替換成攝像機的前置或者後置的視頻流。
async function switchDirection() {
if (videoStream) {
videoStream.getTracks().forEach((track) => {
track.stop();
});
}
constraints.video.deviceId = select.value;
enumerateDevices((devices) => {
devices.forEach((device) => {
// 重设分辨率
if (device.deviceId == select.value) {
// constraints.video.width.min = device.width.min;
// constraints.video.width.ideal = device.width.ideal;
// constraints.video.width.max = device.width.max;
// constraints.video.height.min = device.height.min;
// constraints.video.height.ideal = device.height.ideal;
// constraints.video.height.max = device.height.max;
}
});
try {
videoStream = navigator.mediaDevices.getUserMedia(constraints).then(videoStream => myVideo.srcObject = videoStream); // 調用將詢問用戶是否允許訪問攝像機。如果用戶拒絕,它將引發異常並且不返回流。因此,必須在 try/catch 塊內處理這種情況,它返回一個Promise,必須使用 async/await 或 then 塊
} catch (error) {
console.log(error)
}
});
}
async function enumerateDevices(callback) {
try {
navigator.mediaDevices.enumerateDevices().then(devices => {
// const filtered = devices.filter(device => device.kind === "videoinput");
callback(devices);
});
} catch (error) {
console.log(error)
}
}
function gotDevices(mediaDevices) {
select.innerHTML = '';
select.appendChild(document.createElement('option'));
let count = 1;
mediaDevices.forEach(mediaDevice => {
if (mediaDevice.kind === 'videoinput') {
const option = document.createElement('option');
option.value = mediaDevice.deviceId;
if (count == 1) {
option.selected = true;
}
const label = mediaDevice.label || `Camera ${count++}`;
const textNode = document.createTextNode(label);
option.appendChild(textNode);
select.appendChild(option);
}
});
switchDirection();
}
</script>
</html>
鸣谢
- IoT Security Wiki
- pi-cast.com
本作品采用《CC 协议》,转载必须注明作者和本文链接