Android WebRTC 入门教程 -- 使用相机

Posted 夏至的稻穗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android WebRTC 入门教程 -- 使用相机相关的知识,希望对你有一定的参考价值。

前言,最近在搞网页投屏,发现 WebRTC 的android 版本较少,这里的话,参考了一些优秀的博客,主要是这个大佬的 https://www.jianshu.com/p/eb5fd116e6c8 博客来整理,然后加一些自己的理解。权当记录

源码工程: https://github.com/LillteZheng/WebRTCDemo
今天要实现的效果:

一. WebRTC 简介

WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间点对对(Peer-to-Peer) 的连接,实现视频流和视频流或者任意数据的传输。

目前,WebRTC 的应用已经不局限在浏览器和浏览器之间,通过官网提供的 SDK ,我们可以实现本地应用的音视频传输。
用法也非常简单,可以用非常简介的代码实现强大可靠的音视频功能。

这一章,我们先实现相机的数据获取和渲染。

二. 关联 WebRTC 官方aar

官方已经打包好了 so 和 java 代码,可直接关联:

implementation 'org.webrtc:google-webrtc:1.0.32006'

当然,如果你想改动源码或者 so ,可在 官方源码src/tools_webrtc/android/中build_aar.py与release_aar.py中有相关生成本地aar与发布aar到maven仓库的脚本。

2.1 添加权限

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

三. 实现相机功能

以前我们使用相机,都是通过 camera1/2/x 去打开相机,再设置 Surface ,这样相机采集的数据就会在 Surface 显示了。
如果你想使用原生相机采集,可参考历史文章。
Android 音视频开发(二) – Camera1 实现预览、拍照功能
Android 音视频开发(三) – Camera2 实现预览、拍照功能
Android 音视频开发(四) – CameraX 实现预览、拍照功能

3.1 创建 Surface

所以,在使用相机时,需要一个承载画面的组建,在WebRTC 中,我们使用 SufaceViewRender ,它是 SurfaceView 的子类。如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CameraActivity">


    <org.webrtc.SurfaceViewRenderer
        android:id="@+id/viewRender"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</androidx.appcompat.widget.LinearLayoutCompat>

3.2 使用相机

WebRTC 有自己一套使用规则,使用相机也是如此,因此想在脑子把 Camera 相关的 api 遗忘,WebRTC 有自己的 API,而它的使用步骤基本不变。

3.2.1 初始化 PeerConnectionFactory

在初次使用 PeerConnectionFactory 时,需要先初始化 PeerConnectionFactory ,调用静态方法 initialize() 进行全局初始化和资源加载,通过Builder 模式。可对 Tracer,Logger 等进行配置。

 // step 1 创建PeerConnectionFactory
 PeerConnectionFactory.initialize(
     PeerConnectionFactory.InitializationOptions.builder(this)
         .setEnableInternalTracer(true)
         .createInitializationOptions()
 )

3.2.2 创建 PeerConnectionFactory 对象

在全局初始化之后,就可以创建 PeerConnectionFactory 对象了。这个工厂类非常重要,后续的音视频采集、编解码中,会为我们生成各种重要的组建,如 VideoSource,VideoTrack 等。
当然我们现在还不需要编解码相关的配置,只需要简单的创建对象即可:

 val peerConnectionFactory =
       PeerConnectionFactory.builder()
           .createPeerConnectionFactory()

3.2.3 创建 Audiosource

创建了 PeerConnectionFactory 后,就可以把音视频的源丢进去,音频的创建,使用 peerConnectionFactory.createAudioSource(MediaConstraints()),其中 MediaConstraints() 为媒体描述符,我们可以它的 mandatory 去添加一些特殊的配置。然后通过 createAudioTrack 添加音频源。
音频创建:

// create AudioSource and AudioTrack
val audioSource = peerConnectionFactory.createAudioSource(MediaConstraints())
peerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, audioSource)

其他 AUDIO_TRACK_ID 可以为任意字符串。

3.3.3 创建 VideoSource

对应音频来说,在创建 AUdioSource 的时候,就开始捕获设备音频数据了。对于视频流说来, WebRTC 定义了 VideoCaturer 抽象接口,并实现了三种实现: ScreenCapturerAndroid、CameraCapturer和FileVideoCapturer,分别为从录屏、摄像头及文件中获取视频流,调用startCapture()后将开始获取数据。
因为我们用到相机,所以是 CamreaCapturer ,它有两个子类,Camera1Enumerator 和 Camera2Enumerator ,我们使用 Camera1Enumerator 即可,创建也非常简单:

   /**
    * 或者 CameraCapture 
    */
   private fun createCameraCapture(): VideoCapturer? 
       val enumerator = Camera1Enumerator(false)
       val deviceNames = enumerator.deviceNames
       //使用后置摄像头
       for (deviceName in deviceNames) 
           if (enumerator.isBackFacing(deviceName)) 
               val capturer = enumerator.createCapturer(deviceName, null)
               if (capturer != null) 
                   return capturer
               
           
       
       return null
   

拿到 VideoCapturer 之后,就可以使用 PeerConnectionFactory 创建视频源了。

createCameraCapture()?.let  camera->
          val videoSource = peerConnectionFactory.createVideoSource(camera.isScreencast)

3.2.4 VideoSource 与 SurfaceViewRender 配合,实现数据渲染

上面,已经创建了音视频源,接着,我们把 SurfaceViewRender 给到 CamreaCapturer ,实现画面渲染。
viewRender.holder.addCallback(object : SurfaceHolder.Callback
override fun surfaceCreated(holder: SurfaceHolder)
//创建并启动VideoCapturer
// 用PeerConnectionFactory创建VideoSource
// 用PeerConnectionFactory和VideoSource创建VideoTrack
createCameraCapture()?.let camera->
val videoSource = peerConnectionFactory.createVideoSource(camera.isScreencast)

                val eglBaseContext = EglBase.create().eglBaseContext
                //拿到 surface工具类,用来表示camera 初始化的线程
                val surfaceTextureHelper = SurfaceTextureHelper.create("caputerTHread", eglBaseContext)
                //用来表示当前初始化 camera 的线程,和 application context,当调用 startCapture 才会回调。
                camera.initialize(surfaceTextureHelper, application, videoSource.capturerObserver)
                //开始采集
                camera.startCapture(
                    viewRender.width,
                    viewRender.height,
                    30
                )
                //是否镜像
                //viewRender.setMirror(true)
                // 初始化 SurfaceViewRender ,这个方法非常重要,不初始化黑屏
                viewRender.init(eglBaseContext,null)

                //添加视频轨道
                val videoTrack =
                    peerConnectionFactory.createVideoTrack(AUDIO_TRACK_ID, videoSource)

                // 添加渲染接收端器到轨道中,画面开始呈现
                videoTrack.addSink(viewRender)
            


        

效果如下:

参考:
https://webrtc.org.cn/
https://www.jianshu.com/p/eb5fd116e6c8
https://webrtc.googlesource.com/src
https://webrtc.org.cn/20190419_tutorial3_webrtc_android/

以上是关于Android WebRTC 入门教程 -- 使用相机的主要内容,如果未能解决你的问题,请参考以下文章

Android WebRTC完整入门教程02: 本地回环

Webrtc入门——基于阿里云ubuntu 最新webrtc Android平台编译详细说明

Android WebRTC 入门教程 -- 模拟p2p本地视频传输

Android WebRTC 入门教程 -- 模拟p2p本地视频传输

Android技术分享| Android WebRTC 开启H264软件编解码教程

如何构建一个可以进行基本视频通话的简单 Native WebRTC Android 应用程序?