首页 > 其他分享 >WebRTC学习五:从视频中提取图片

WebRTC学习五:从视频中提取图片

时间:2024-10-19 20:19:39浏览次数:8  
标签:视频 Canvas const picture filter 提取 WebRTC

系列文章目录

第一篇 基于SRS 的 WebRTC 环境搭建
第二篇 基于SRS 实现RTSP接入与WebRTC播放
第三篇 centos下基于ZLMediaKit 的WebRTC 环境搭建
第四篇 WebRTC学习一:获取音频和视频设备
第五篇 WebRTC学习二:WebRTC音视频数据采集
第六篇 WebRTC学习三:WebRTC音视频约束
第七篇 WebRTC学习四:WebRTC常规视觉滤镜
第八篇 WebRTC学习五:从视频中提取图片


文章目录


前言

在前几篇文章中,我们探讨了WebRTC的环境搭建、音视频数据采集、音视频约束以及如何应用视觉滤镜。本篇文章将进一步扩展我们对WebRTC的理解,介绍如何从应用视觉滤镜的实时视频流中提取一张静态图片。我们将使用HTML5的Canvas API来实现这一功能,探索相关的网页端代码和JavaScript实现逻辑。


一、概述

提取视频流中的静态图片在许多应用场景中非常实用,比如视频通话中的截图、实时监控的快照等。本篇文章将介绍如何使用Canvas API从WebRTC的视频流中获取一张图片,并展示其实现方法。

二、修改页面布局

在前面实现的基础上,对页面进行了布局上的调整。
1、视频和 Canvas 布局:视频和 Canvas 将并排显示,左边是视频,右边是 Canvas,且保持相等宽度。
2、控件的排布:控件 (音频、视频源选择和滤镜选择等) 保持在顶部,整齐排列。
3、按钮位置: “Take snapshot” 按钮位于视频和 Canvas 下面,且居中显示。以下是修改后的HTML结构:

1.页面修改

页面代码如下:

    <div id="videoContainer">
        <video autoplay playsinline id="player"></video>
        <canvas id="picture" width="400" height="320"></canvas>
    </div>
    
    <button id="snapshot">Take snapshot</button>

2.css样式

代码如下:

#player {
    width: 400px; /* 设置视频宽度 */
    height: auto; /* 自动高度 */
    border: 1px solid #ccc; /* 可选,给视频一个边框 */
}

#picture {
    width: 400px; /* 设置Canvas宽度 */
    height: auto; /* 自动高度 */
    border: 1px solid #ccc; /* 可选,给画布一个边框 */
    background-color: bisque;
    margin-left: 20px; /* 视频和画布之间的间距 */
}

button {
    margin-top: 10px; /* 按钮与其它元素之间的间距 */
}

三、实现功能

在原来的基础上增加获取图片功能,主要是通过HTML5 Canvas getContext函数获取上下文,drawImage函数绘制图像。

核心代码如下:

const snapshot = document.querySelector('button#snapshot');
const picture = document.querySelector('canvas#picture');

// 快照功能
snapshot.onclick = function () {
    const context = picture.getContext('2d');
    // 清空 Canvas
    context.clearRect(0, 0, picture.width, picture.height);
    // 应用滤镜
    context.filter = getFilterValue(filterSelect.value);
    // 绘制视频帧
    context.drawImage(videoplay, 0, 0, picture.width, picture.height);
    // 清除滤镜设置(可选,便于后续操作)
    context.filter = 'none';
};

四、完整示例代码

1.html代码

   <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebRTC获取图片</title>
    <link rel="stylesheet" href="./css/style.css"> <!-- 引入CSS文件 -->
</head>
<body>
    <div id="controls">
        <div>
            <label>Audio Source:</label>
            <select id="audioSource"></select>
        </div>

        <div>
            <label>Audio Output:</label>
            <select id="audioOutput"></select>
        </div>

        <div>
            <label>Video Source:</label>
            <select id="videoSource"></select>
        </div>

        <div>
            <label>Filter:</label>
            <select id="filter">
                <option value="none">None</option>
                <option value="blur">Blur</option>
                <option value="grayscale">Grayscale</option>
                <option value="invert">Invert</option>
                <option value="sepia">sepia</option>
            </select>
        </div>
    </div>

    <div id="videoContainer">
        <video autoplay playsinline id="player"></video>
        <canvas id="picture" width="400" height="320"></canvas>
    </div>
    
    <button id="snapshot">Take snapshot</button>
    <script src="./js/client.js"></script>
</body>
</html>

2.css代码

style.css文件内容如下:

body {
    display: flex;
    flex-direction: column;
    align-items: center;
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 20px;
}

#controls {
    display: flex;
    justify-content: space-between;
    width: 100%;
    max-width: 800px; /* 设置一个最大宽度 */
    margin-bottom: 20px; /* 控件与视频和画布的间距 */
}

#videoContainer {
    display: flex;
}

#player {
    width: 400px; /* 设置视频宽度 */
    height: auto; /* 自动高度 */
    border: 1px solid #ccc; /* 可选,给视频一个边框 */
}

#picture {
    width: 400px; /* 设置Canvas宽度 */
    height: auto; /* 自动高度 */
    border: 1px solid #ccc; /* 可选,给画布一个边框 */
    background-color: bisque;
    margin-left: 20px; /* 视频和画布之间的间距 */
}

button {
    margin-top: 10px; /* 按钮与其它元素之间的间距 */
}

select {
    margin-right: 10px; /* 下拉框之间的间距 */
}

.none {
    -webkit-filter:none;
}
.blur {
    -webkit-filter: blur(3px);
}
.grayscale {
    -webkit-filter: grayscale(1);
}
.invert {
    -webkit-filter: invert(1);
}
.sepia {
    -webkit-filter: sepia(1);
}

3.js代码

client.js文件内容如下:

'use strict';

const audioSource = document.querySelector('select#audioSource');
const audioOutput = document.querySelector('select#audioOutput');
const videoSource = document.querySelector('select#videoSource');
const filterSelect = document.querySelector('select#filter');
const videoplay = document.querySelector('video#player');
const snapshot = document.querySelector('button#snapshot');
const picture = document.querySelector('canvas#picture');

// 获取设备列表
function gotDevices(deviceInfos) {
    deviceInfos.forEach(deviceInfo => {
        const option = document.createElement('option');
        option.text = deviceInfo.label;
        option.value = deviceInfo.deviceId;

        switch (deviceInfo.kind) {
            case "audioinput":
                audioSource.appendChild(option);
                break;
            case "audiooutput":
                audioOutput.appendChild(option);
                break;
            case "videoinput":
                videoSource.appendChild(option);
                break;
        }
    });
}

// 获取媒体流
function gotMediaStream(stream) {
    videoplay.srcObject = stream;
    return navigator.mediaDevices.enumerateDevices();
}

// 处理错误
function handleError(err) {
    console.error('getUserMedia error:', err);
}

// 启动媒体流
function start() {
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
        console.error('getUserMedia is not supported!');
        return;
    }

    const constraints = {
        video: {
            width: 640,
            height: 480,
            frameRate: 30,
            facingMode: "environment",
            deviceId: videoSource.value ? { exact: videoSource.value } : undefined, // 确保使用确切的设备ID
        },
        audio: {
            noiseSuppression: true,
            echoCancellation: true
        }
    };

    navigator.mediaDevices.getUserMedia(constraints)
        .then(gotMediaStream)
        .then(gotDevices)
        .catch(handleError);
}

// 滤镜选择更改事件
filterSelect.onchange = function () {
    videoplay.className = filterSelect.value;
};

// 快照功能
snapshot.onclick = function () {
    const context = picture.getContext('2d');
    // 清空 Canvas
    context.clearRect(0, 0, picture.width, picture.height);
    // 应用滤镜
    context.filter = getFilterValue(filterSelect.value);
    // 绘制视频帧
    context.drawImage(videoplay, 0, 0, picture.width, picture.height);
    // 清除滤镜设置(可选,便于后续操作)
    context.filter = 'none';

};

// 获取滤镜值
function getFilterValue(filter) {
    switch (filter) {
        case 'blur':
            return 'blur(3px)';
        case 'grayscale':
            return 'grayscale(1)';
        case 'invert':
            return 'invert(1)';
        case 'sepia':
            return 'sepia(1)';
        default:
            return 'none';
    }
}

// 初始化
start();
videoSource.onchange = start;

五、运行效果

在浏览器中打开 index.html 文件,通过右上Filter下拉菜单选择不同的视觉滤镜,实时视频中可即时看到效果,点击“Task snapshot”按钮,可以看到抓取到的图片,图片上右键单击,选择图片另存为,即可保存图片到磁盘。下图是我的浏览器上显示的效果。
在这里插入图片描述


总结

在本篇文章中,我们学习了如何从WebRTC的视频流中提取静态图片,结合了HTML5的Canvas API。通过这种方式,我们可以轻松实现实时图像捕获的功能。这为我们后续更复杂的WebRTC应用奠定了基础。

希望能给大家提供一些帮助和启发。欢迎留言讨论!

你好,我是阿灿,慢慢理解世界,慢慢更新自己。

标签:视频,Canvas,const,picture,filter,提取,WebRTC
From: https://blog.csdn.net/wel_006/article/details/143081288

相关文章

  • 鸿蒙ArkWeb 组件多媒体探究:从视频到音频
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。引言ArkWeb是华为鸿蒙系统提供的一......
  • 基于SpringBoot+Vue+MySQL的驾校管理系统设计与实现(源码+文档+部署视频等)
    文章目录1.前言2.详细视频演示3.程序运行示例图4.文档参考5.技术框架5.1后端采用SpringBoot框架5.2前端框架Vue5.3程序操作流程6.选题推荐7.原创毕设案例8.系统测试8.1系统测试的目的8.2系统功能测试9.代码参考10.为什么选择我?11.获取源码1.前言......
  • 基于SpringBoot+Vue+MySQL的数码论坛系统设计与实现(源码+文档+部署视频等)
    文章目录1.前言2.详细视频演示3.程序运行示例图4.文档参考5.技术框架5.1后端采用SpringBoot框架5.2前端框架Vue5.3程序操作流程6.选题推荐7.原创毕设案例8.系统测试8.1系统测试的目的8.2系统功能测试9.代码参考10.为什么选择我?11.获取源码1.前言......
  • 视频编解码学习资料
    视频编解码学习资料一.包括H264/AVC官方提案网站,JM参考软件以及学习书籍和paper1.1H264spec(白皮书)下载网址:https://www.itu.int/ITU-T/recommendations/rec.aspx?rec=131891.2H264视频编码标准提案下载网址:https://www.itu.int/wftp3/av-arch/jvt-site/1.3H264参......
  • 基于nodejs+vue基于springboot和vue技术的视频与图集网站[开题+源码+程序+论文]计算机
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于视频与图集网站的研究,现有研究主要集中在大型综合视频平台或者单一功能的视频网站方面,专门针对结合视频与图集功能的网站研究较少。在国内外,视频网......
  • 51单片机的超声波视力保护仪【proteus仿真+程序+报告+原理图+演示视频】
    1、主要功能 该系统由AT89C51/STC89C52单片机+LCD1602显示模块+温度传感器+光照传感器+超声波传感器+按键、LED、蜂鸣器等模块构成。适用于视力保护仪、坐姿矫正器、超声波防近视等相似项目。可实现功能:1、LCD1602显示温度、光照、距离和学习时间2、超声波传感器采集头......
  • 51单片机的超声波水位检测【proteus仿真+程序+报告+原理图+演示视频】
    1、主要功能 该系统由AT89C51/STC89C52单片机+LCD1602显示模块+超声波传感器+继电器+按键、LED、蜂鸣器等模块构成。适用于超声波液位监测与控制等相似项目。可实现功能:1、LCD1602显示水位信息2、超声波传感器采集水位信息3、如果水位低于阈值,声光报警,同时加水继电器......
  • 小心!这样分享 B 站视频会暴露身份
    ‍在2022年6月10日0点,B站在视频的网址上加了个参数?vd_source=XXXXXXXXXXXXXXX​,如图:​经过网友的测试,这个参数值很可能就是用户ID的hash值(简单来说就是用户身份),所以如果直接复制网址的话,是有可能被“开盒”的。‍其实快手和抖音类似,分享时会有选项“分享视频......
  • 基于51单片机的智能台灯光照坐姿检测PWM红外无线手机蓝牙/WiFi/WiFi视频监控APP设计C0
    51单片机+人走灯灭+光敏AD采集+自动+手动+10档调节+坐姿监测+蜂鸣器+OLED屏/C01N51+蓝牙APP控制+人走灯灭+光敏AD采集+自动+手动+10档调节+坐姿监测+蜂鸣器+OLED屏/C01B51+WIFI-APP控制+人走灯灭+光敏AD采集+自动+手动+10档调节+坐姿监测+蜂鸣器+OLED屏/C01W51+视频监控+WIF......
  • 基于51单片机宠物自动喂食器定时时钟提醒加水水位无线手机蓝牙/WiFi/WiFi视频监控APP
    51单片机+时钟+校时+喂食+水位+加水喂水+三餐3定时+声光提醒+OLED屏+手动+自动/C16N51+蓝牙APP控制+时钟+校时+喂食+水位+喂水+三餐3定时+声光+OLED屏+手动+自动/C16B51+WIFI-APP控制+时钟+校时+喂食+水位+喂水+三餐3定时+声光+OLED屏+手动+自动/C16W51+视频监控+WIFI+时钟+......