• Android WebRTC 入门教程(一) -- 使用相机


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

    Android WebRTC 入门教程(一) – 使用相机

    Android WebRTC 入门教程(二) – 模拟p2p本地视频传输

    源码工程: 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 添加权限

        
        
    

    三. 实现相机功能

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

    3.1 创建 Surface

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

    
    
    
    
        
    
    
    

    它是 VideoSink 的子类,后面会讲,它内部是通过 opengl 去渲染的。

    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/

  • 相关阅读:
    配置OSPF包文分析和验证
    2023年【广东省安全员A证第四批(主要负责人)】考试试卷及广东省安全员A证第四批(主要负责人)模拟考试
    【MATLAB-Retinex图像增强算法的去雾技术】
    系统日志记录注解方式动态记录
    配置中心微服务(Spring Cloud Config)
    蓝桥杯 字符串和日期
    最新报错注入攻击和代码分析技术
    C++ 输入输出优化
    可靠消息最终一致性分布式事务
    OceanBase社区版单节点安装搭建(Docker)
  • 原文地址:https://blog.csdn.net/u011418943/article/details/127108642