WebRTC之摄像头预览

2024-08-22 15:32
文章标签 摄像头 预览 webrtc

本文主要是介绍WebRTC之摄像头预览,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在前面《WebRTC之服务器搭建》 我们已经搭建好了WebRTC所需的服务器环境,主要是三个服务器:
房间服务器、信令服务器以及TURN穿透服务器。

后续我们将学习如何使用WebRTC一步一步实现音视频通话。今天我们将学习如何使用WebRTC预览摄像头数据。

这里透个底,后面的学习过程中大部分的实践都是基于WebRTC的官方封装库,因此绝大部分的代码都是Java或者Kotlin,暂时不会涉及到JNI的相关代码,所以门槛还是非常低的。

Good good study,day day up. So easy…

引入依赖库

首先我们在Android Studio工程中引入WebRTC的依赖库:

 implementation 'org.webrtc:google-webrtc:1.0.+'

动态权限

首先肯定是需要CAMERA权限的,如果需要音频数据则还需要RECORD_AUDIO权限。

对于动态权限相信有Android开发基础的童鞋们都不陌生了,gitHub上也有很多相关的开源库,笔者在这里就不多做介绍了。

预览摄像头

WebRTC作为一个点对点通信完整的解决方案,对于摄像头数据的获取及预览都已经做好了完整封装,开发者直接调用相关的API即可,
并不需要开发者编写OpenGL纹理渲染等相关的逻辑代码。

如果童鞋们对如何使用OpenGL渲染摄像头数据感兴趣的话可以参考笔者之前的文章:《使用OpenGL预览CameraX摄像头数据》

使用WebRTC预览摄像头数据主要有以下几个步骤:

1、创建EglBase及SurfaceViewRenderer

其中EglBase一个重要的功能就是提供EGL的渲染上下文及EGL的版本兼容。

SurfaceViewRenderer则是一个继承于SurfaceView的渲染View,提供了OpenGL渲染图像数据的功能。

// 创建EglBase
rootEglBase = EglBase.create()
camera_preview.init(rootEglBase?.eglBaseContext, null)
//硬件加速
camera_preview.setEnableHardwareScaler(true)
camera_preview.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)

2、创建VideoCapturer

VideoCapturer主要作用则是提供摄像头数据,比如控制分辨率以及帧率等。

通过CameraEnumerator接口兼容Camera1和Camera2:

   // 创建VideoCapturerprivate fun createVideoCapture(): VideoCapturer? {return if (Camera2Enumerator.isSupported(this)) {createCameraCapture(Camera2Enumerator(this))} else {createCameraCapture(Camera1Enumerator(true))}}//  真正创建VideoCapturer的实现private fun createCameraCapture(enumerator: CameraEnumerator): VideoCapturer? {val deviceNames = enumerator.deviceNames// First, try to find front facing camerafor (deviceName in deviceNames) {if (enumerator.isFrontFacing(deviceName)) {val videoCapture: VideoCapturer? = enumerator.createCapturer(deviceName, null)if (videoCapture != null) {return videoCapture}}}for (deviceName in deviceNames) {if (!enumerator.isFrontFacing(deviceName)) {val videoCapture: VideoCapturer? = enumerator.createCapturer(deviceName, null)if (videoCapture != null) {return videoCapture}}}return null}

VideoCapturer创建完成之后需要使用SurfaceTextureHelper进行初始化,否则调用预览的时候会抛出未初始化的异常:

  // 初始化mSurfaceTextureHelper =SurfaceTextureHelper.create("CaptureThread", rootEglBase?.eglBaseContext)// 创建VideoSourceval videoSource = mPeerConnectionFactory!!.createVideoSource(false)mVideoCapture?.initialize(mSurfaceTextureHelper,applicationContext,videoSource.capturerObserver)/*** 创建PeerConnectionFactory*/private fun createPeerConnectionFactory(context: Context?): PeerConnectionFactory? {val encoderFactory: VideoEncoderFactoryval decoderFactory: VideoDecoderFactoryencoderFactory = DefaultVideoEncoderFactory(rootEglBase?.eglBaseContext,false /* enableIntelVp8Encoder */,true)decoderFactory = DefaultVideoDecoderFactory(rootEglBase?.eglBaseContext)PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(context).setEnableInternalTracer(true).createInitializationOptions())val builder = PeerConnectionFactory.builder().setVideoEncoderFactory(encoderFactory).setVideoDecoderFactory(decoderFactory)builder.setOptions(null)return builder.createPeerConnectionFactory()}

3、创建VideoTrack

VideoTrack是视频轨道,类似的还有AudioTrack音频轨道,它的作用将VideoCapturer获取到的视频数据结合VideoSource输出到SurfaceViewRenderer渲染显示。

val VIDEO_TRACK_ID = "1" //"ARDAMSv0"
// 创建VideoTrackmVideoTrack = mPeerConnectionFactory!!.createVideoTrack(VIDEO_TRACK_ID,videoSource)mVideoTrack?.setEnabled(true)// 绑定渲染ViewmVideoTrack?.addSink(camera_preview)

使用VideoCapturer开启渲染

在Activity的相关生命周期中开启预览即可:

   override fun onResume() {super.onResume()// 开启摄像头预览mVideoCapture?.startCapture(VIDEO_RESOLUTION_WIDTH,VIDEO_RESOLUTION_HEIGHT,VIDEO_FPS)}

完整代码

CapturePreviewActivity.kt:

package com.fly.webrtcandroidimport android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import org.webrtc.*/*** 摄像头预览*/
class CapturePreviewActivity : AppCompatActivity() {val VIDEO_TRACK_ID = "1" //"ARDAMSv0"private val VIDEO_RESOLUTION_WIDTH = 1280private val VIDEO_RESOLUTION_HEIGHT = 720private val VIDEO_FPS = 30//    绘制全局的上下文private var rootEglBase: EglBase? = nullprivate var mVideoTrack: VideoTrack? = nullprivate var mPeerConnectionFactory: PeerConnectionFactory? = null//纹理渲染private var mSurfaceTextureHelper: SurfaceTextureHelper? = nullprivate var mVideoCapture: VideoCapturer? = nullprivate val camera_preview by lazy {findViewById<SurfaceViewRenderer>(R.id.camera_preview)}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_capture_preview)rootEglBase = EglBase.create()camera_preview.init(rootEglBase?.eglBaseContext, null)//悬浮顶端camera_preview.setZOrderMediaOverlay(true)//硬件加速camera_preview.setEnableHardwareScaler(true)camera_preview.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)mPeerConnectionFactory = createPeerConnectionFactory(this)mVideoCapture = createVideoCapture()// 初始化mSurfaceTextureHelper =SurfaceTextureHelper.create("CaptureThread", rootEglBase?.eglBaseContext)// 创建VideoSourceval videoSource = mPeerConnectionFactory!!.createVideoSource(false)mVideoCapture?.initialize(mSurfaceTextureHelper,applicationContext,videoSource.capturerObserver)mVideoTrack = mPeerConnectionFactory!!.createVideoTrack(VIDEO_TRACK_ID,videoSource)mVideoTrack?.setEnabled(true)mVideoTrack?.addSink(camera_preview)}/*** 创建PeerConnectionFactory*/private fun createPeerConnectionFactory(context: Context?): PeerConnectionFactory? {val encoderFactory: VideoEncoderFactoryval decoderFactory: VideoDecoderFactoryencoderFactory = DefaultVideoEncoderFactory(rootEglBase?.eglBaseContext,false /* enableIntelVp8Encoder */,true)decoderFactory = DefaultVideoDecoderFactory(rootEglBase?.eglBaseContext)PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(context).setEnableInternalTracer(true).createInitializationOptions())val builder = PeerConnectionFactory.builder().setVideoEncoderFactory(encoderFactory).setVideoDecoderFactory(decoderFactory)builder.setOptions(null)return builder.createPeerConnectionFactory()}private fun createVideoCapture(): VideoCapturer? {return if (Camera2Enumerator.isSupported(this)) {createCameraCapture(Camera2Enumerator(this))} else {createCameraCapture(Camera1Enumerator(true))}}private fun createCameraCapture(enumerator: CameraEnumerator): VideoCapturer? {val deviceNames = enumerator.deviceNames// First, try to find front facing camerafor (deviceName in deviceNames) {if (enumerator.isFrontFacing(deviceName)) {val videoCapture: VideoCapturer? = enumerator.createCapturer(deviceName, null)if (videoCapture != null) {return videoCapture}}}for (deviceName in deviceNames) {if (!enumerator.isFrontFacing(deviceName)) {val videoCapture: VideoCapturer? = enumerator.createCapturer(deviceName, null)if (videoCapture != null) {return videoCapture}}}return null}override fun onResume() {super.onResume()// 开启摄像头预览mVideoCapture?.startCapture(VIDEO_RESOLUTION_WIDTH,VIDEO_RESOLUTION_HEIGHT,VIDEO_FPS)}}

布局文件activity_capture_preview.xml:

<?xml version="1.0" encoding="utf-8"?>
<org.webrtc.SurfaceViewRenderer 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:id="@+id/camera_preview"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".CapturePreviewActivity"></org.webrtc.SurfaceViewRenderer>

关注我,一起进步,人生不止coding!!!

微信扫码关注

这篇关于WebRTC之摄像头预览的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1096670

相关文章

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

雷动WEBRTC产品

http://www.rtcpower.com/html/leidongwebrtc.html ; 1.前言      WebRTC是一项在浏览器内部进行实时视频和音频通信的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得一项技术。WebRTC实现了基于网页的视频会议,标准是WHATWG 协议,目的是通过浏览器提供简单的javascript就可以

Apple quietly slips WebRTC audio, video into Safari's WebKit spec

转自:http://www.zdnet.com/article/apple-quietly-slips-webrtc-audio-video-into-safaris-webkit-spec/?from=timeline&isappinstalled=0 http://www.zdnet.com/article/apple-quietly-slips-webrtc-audio-video-

WebRTC-nack机制详解

1.NACK的含义 丢包重传(NACK)是抵抗网络错误的重要手段。NACK在接收端检测到数据丢包后,发送NACK报文到发送端;发送端根据NACK报文中的序列号,在发送缓冲区找到对应的数据包,重新发送到接收端。NACK需要发送端,发送缓冲区的支持。 WebRTC中支持音频和视频的NACK重传。我们这里只分析nack机制,不分析jitterbuffer或者neteq的更多实现。 2.WebRTC

4-4.Andorid Camera 之简化编码模板(获取摄像头 ID、选择最优预览尺寸)

一、Camera 简化思路 在 Camera 的开发中,其实我们通常只关注打开相机、图像预览和关闭相机,其他的步骤我们不应该花费太多的精力 为此,应该提供一个工具类,它有处理相机的一些基本工具方法,包括获取摄像头 ID、选择最优预览尺寸以及打印相机参数信息 二、Camera 工具类 CameraIdResult.java public class CameraIdResult {

用了虚拟机后,本机摄像头打不开了(联想电脑thinkpad)

虚拟机有摄像头,我断开了连接,现在本机的摄像头打开就是一个锁 我先把虚拟机的摄像头关了 然后把本机的vm usb关闭了 Win+R),输入services.msc,找到VMware USB Arbitration Service,确保其状态为“关闭 然后打开桌面助手 开启 参考: 联想知识库

摄像头模组介绍和技术指标

1 手机摄像头概述 1.1 手机摄像头概述  手机的数码相机功能指的是手机是否可以通过内置或是外接的数码相机进行拍摄静态图片或短片拍摄,作为手机的一项新的附加功能,手机的数码相机功能得到了迅速的发展。 手机摄像头分为内置与外置,内置摄像头是指摄像头在手机内部,更方便。外置手机通过数据线或者手机下部接口与数码相机相连,来完成数码相机的一切拍摄功能。 外置数码相机的优点在于可以减轻手机的重

第二天旅游线路规划和预览

第二天:从克拉玛依市乌尔禾区到五彩滩,晚上住宿贾登峪; 规划结果见下图: 1、行程安排 根据上面的耗时情况,规划一天的行程安排如下: 1)早上7:30起床,吃完早饭,8:30出发; 2)从克拉玛依市乌尔禾区到五彩滩风景区,路程229公里,车程3小时,中午12:00左右到达五彩滩景区; 3)中午吃饭1小时; 3)五彩滩游玩时间约3小时,在五彩滩游玩到16:00; 4)乘车前往阿勒泰地区布尔津县

Nginx跨域运行案例:云台控制http请求,通过 http server 代理转发功能,实现跨域运行。(基于大华摄像头WEB无插件开发包)

文章目录 引言I 跨域运行案例开发资源测试/生产环境,Nginx代理转发,实现跨域运行本机开发运行 II nginx的location指令Nginx配置中, 获取自定义请求header头Nginx 配置中,获取URL参数 引言 背景:全景监控 需求:感知站点由于云台相关操作为 http 请求,http 请求受浏览器跨域限制,不能直接访问,因此需要进行 http 的代理,实

yolov5 +gui界面+单目测距 实现对图片视频摄像头的测距

可实现对图片,视频,摄像头的检测  项目概述 本项目旨在实现一个集成了YOLOv5目标检测算法、图形用户界面(GUI)以及单目测距功能的系统。该系统能够对图片、视频或实时摄像头输入进行目标检测,并估算目标的距离。通过结合YOLOv5的强大检测能力和单目测距技术,系统能够在多种应用场景中提供高效、准确的目标检测和测距功能。 技术栈 YOLOv5:用于目标检测的深度学习模型。Open