03 如何使用浏览器给自己拍照呢?

03 如何使用浏览器给自己拍照呢?

03 如何使用浏览器给自己拍照呢?

在之前的文章中,我向你介绍了如何在浏览器中利用 WebRTC 采集音视频数据。那么,是否可以通过相同的技术进行拍照呢?没错,这是完全可行的。

现代的浏览器功能越来越强大,你不光可以通过它进行拍照,而且还可以对拍下来的照片进行各种滤镜处理。

为了实现上述功能,你需要了解并掌握以下三个知识点:

如何从采集到的视频中获取到图片?

如何将处理后的图片保存成文件?

如何对获取到的图片进行滤镜处理?

这三方面的知识点就是本文要交付的重点内容。下面我们先学习与之相关的基础知识和原理,然后再对这几个知识点逐一进行讲解,各个击破。

在WebRTC处理过程中的位置

在正式进入主题之前,咱们仍然按老规矩,看看本篇文章所介绍的内容在整个 WebRTC 处理过程中的位置。如下图所示:

WebRTC 1对1音视频实时通话过程示意图

你可以看到,这张图与《01 | 原来通过浏览器访问摄像头这么容易》文章中的图一模一样。没错,咱们本篇文章所涉及的知识点仍然属于音视频数据采集的部分。

基础知识

在正式讲解如何进行拍照之前,你需要先了解非编码帧(解码帧)和编码帧这两个知识点,这会有利于你对后面拍照实现内容的理解。

1. 非编码帧

好多人小时候应该都学过,在几张空白的纸上画同一个物体,并让物体之间稍有一些变化,然后连续快速地翻动这几张纸,它就形成了一个小动画。

音视频播放器就是利用这样的原理来播放音视频文件的。当你要播放某个视频文件时,播放器会按照一定的时间间隔连续地播放从音视频文件中解码后的视频帧,这样视频就动起来了。同理,播放从摄像头获取的视频帧也是如此,只不过从摄像头获取的本来就是非编码视频帧,所以就不需要解码了。

通过上面的描述,你应该能得到以下两点信息:

播放的视频帧之间的时间间隔是非常小的。如按每秒钟20帧的帧率计算,每帧之间的间隔是50ms。

播放器播的是非编码帧(解码后的帧),这些非编码帧就是一幅幅独立的图像。

从摄像头里采集的帧或通过解码器解码后的帧都是非编码帧。非编码帧的格式一般是YUV 格式或是 RGB 格式。关于 YUV 与 RGB 的相关知识,我在上一篇文章中已向你做过简要介绍,这里就不再赘述了。

2. 编码帧

相对于非编码帧,通过编码器(如 H264/H265、VP8/VP9)压缩后的帧称为编码帧。这里我们以 H264 为例,经过H264编码的帧包括以下三种类型。

I 帧:关键帧。压缩率低,可以单独解码成一幅完整的图像。

P 帧:参考帧。压缩率较高,解码时依赖于前面已解码的数据。

B 帧:前后参考帧。压缩率最高,解码时不光依赖前面已经解码的帧,而且还依赖它后面的P帧。换句话说就是,B帧后面的P帧要优先于它进行解码,然后才能将 B 帧解码。

关于编码这块的内容,目前你只需了解上面这些知识即可。

通过上面的介绍,现在你应该已经清楚地知道了:从播放器里获取的视频帧一定是非编码帧。也就是说,拍照的过程其实是从连续播放的一幅幅画面中抽取正在显示的那张画面。

如何获取视频流

在获得照片之前,你首先要通过浏览器的API获取视频流,并通过 HTML5 的

HTML 部分代码如下:

WebRTC take picture

上面这段代码很简单,就是定义了一个 video 标签,用于播放从摄像头获取到的视频流。另外,它还引入了一段 JavaScript 脚本:

'use strict'

//获取HTML页面中的video标签

var videoplay = document.querySelector('video#player');

//播放视频流

function gotMediaStream(stream){

videoplay.srcObject = stream;

}

function handleError(err){

console.log('getUserMedia error:', err);

}

//对采集的数据做一些限制

var constraints = {

video : {

width: 1280,

height: 720,

frameRate:15,

},

audio : false

}

//采集音视频数据流

navigator.mediaDevices.getUserMedia(constraints)

.then(gotMediaStream)

.catch(handleError);

在这段脚本中,我们调用了之前所讲的getUserMedia方法,该方法会打开摄像头,并通过它采集音视频流。然后再将采集到的视频流赋值给 HTML 中定义的video标签的srcObject字段,这样video标签就可以从摄像头源源不断地获得视频帧,并将它播放出来了。

以上这些内容,你应该都非常熟悉了。下面的关键点是,获取到视频流后如何从中获取正在显示的视频帧或图片呢?现在就让我们来解决这个问题吧!

如何拍照

实际上,浏览器提供了一个非常强大的对象,称为Canvas。你可以把它想像成一块画布,既可以在这块画布上画上点、线或各种图形,也可以将一幅画直接绘制到上面。

在浏览器中,Canvas 的功能非常强大,可以处理很多图表方面的事情,对于这部分知识我们后面还会做详细的介绍。而这里你只需关注它获取图片这一个知识点。

我们还是通过代码来讲解,这样更一目了然。首先,在 HTML 中增加以下代码:

...

...

...

上面的HTML代码段,包括一个 标签和一个

...

也就是当你点击保存这个