MS2130采集卡网页显示视频流(当显示器用)

最新版代码更新到https://github.com/MotorBottle/HtmlUSBVideoViewer

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>USB / UVC 采集卡预览</title>
<style>
    body{margin:0;font-family:system-ui,Helvetica,Arial,sans-serif;background:#101010;color:#eaeaea;display:flex;flex-direction:column;height:100vh}
    #controls{display:flex;gap:8px;padding:8px;background:#222;align-items:center;flex-wrap:wrap}
    select,button{padding:6px 10px;font-size:14px;border-radius:4px;border:none}
    button{cursor:pointer;background:#2964ff;color:#fff}
    button:hover{background:#1e54e6}
    video{flex:1 1 auto;width:100%;height:100%;object-fit:contain;background:#000}
</style>
</head>
<body>
    <div id="controls">
        <label for="videoSource">视频输入源:</label>
        <select id="videoSource"></select>
        <button id="fullScreenBtn">进入全屏</button>
    </div>

    <video id="video" autoplay playsinline></video>

<script>
(async () => {
    // DOM
    const video   = document.getElementById('video');
    const select  = document.getElementById('videoSource');
    const fsBtn   = document.getElementById('fullScreenBtn');
    const SAVEKEY = 'selectedDeviceId';

    // 1. 确保支持
    if (!navigator.mediaDevices?.enumerateDevices) {
        alert('当前浏览器不支持 WebRTC,无法访问摄像头');
        return;
    }

    // 2. 若无任何权限,先最小化地申请一次,避免空列表
    async function ensurePermission() {
        try {
            await navigator.mediaDevices.getUserMedia({video:true, audio:false});
        } catch (e) {
            console.error('未能取得摄像头权限:', e);
            alert('需要摄像头权限才能列出设备,请允许后刷新页面');
            throw e;
        }
    }

    // 3. 列举并填充下拉框
    async function populate() {
        const devices = await navigator.mediaDevices.enumerateDevices();
        const cams    = devices.filter(d => d.kind === 'videoinput');

        select.innerHTML = '';
        cams.forEach((cam, i) => {
            const opt = document.createElement('option');
            opt.value = cam.deviceId;
            opt.textContent = cam.label || `Camera ${i+1}`;
            select.appendChild(opt);
        });

        // 恢复首选
        const saved = localStorage.getItem(SAVEKEY);
        if (saved && cams.some(c => c.deviceId === saved)) select.value = saved;

        // 自动开流
        startStream(select.value || cams[0]?.deviceId);
    }

    // 4. 启动视频流
    async function startStream(id) {
        if (!id) { console.warn('无可用摄像头'); return; }
        const stream = await navigator.mediaDevices.getUserMedia({
            video:{deviceId:{exact:id}, width:{ideal:1920}, height:{ideal:1080}, frameRate:{ideal:60}},
            audio:false
        });
        video.srcObject = stream;
        localStorage.setItem(SAVEKEY, id);
    }

    // 5. 事件绑定
    select.onchange = () => startStream(select.value);
    fsBtn.onclick   = () =>
        document.fullscreenElement ? document.exitFullscreen()
                                   : document.documentElement.requestFullscreen().catch(console.error);
    document.addEventListener('fullscreenchange', () => {
        fsBtn.textContent = document.fullscreenElement ? '退出全屏' : '进入全屏';
    });

    // 6. 设备插拔动态刷新
    navigator.mediaDevices.addEventListener('devicechange', populate);

    // == 启动流程 ==
    await ensurePermission();
    await populate();
})();
</script>
</body>
</html>
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇