支撑在线直播网站源码发展的关键就是直播技术的实现,在整个流媒体传输中视频的采集时开始,一般利用到的是设备端的摄像头,我们在实现视频采集时,不仅需要获取摄像头的调用权限,还要获取到视频录制的数据。

我们先来了解一下在在线直播网站源码开发中需要掌握的音视频基础知识点:

  • ffmpeg 强大的音视频处理库,(cpu软编等)
  • mediaCodec 安卓sdk自带的编解码器,(硬编)
  • opengles 使用gpu进行图像处理
  • h264,h265 图像编码压缩算法
  • yuv420p ,nv21 ,yuv_420_888,I420 需要了解的视频编码格式
  • yuv和rgb的相互转化
  • pcm,acc 需要了解的音频编码格式
  • camerax,mediaRecorder,audioRecorder 采集相关的api

音视频在安卓中一般就有2种表现形式,一种是播放在线或者本地视频(录制和播放),另一种就是在线直播网站源码中的直播(推流和拉流),下面我们首先从视频的采集来对在线直播网站源码做一下详细的探索。

视频的采集

  • Camerax的使用

camerax是jetpack中新加的一个相机库,设计的非常好,不用像之前camera1和camera2使用那么的繁琐,并且是和生命周期绑定,方便开发者管理生命周期。

1.添加依赖

implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:1.0.0-alpha10"

2.创建预览布局

 <androidx.camera.view.PreviewViewandroid:id="@+id/viewFinder"app:layout_constraintTop_toTopOf="parent"app:layout_constraintBottom_toTopOf="@+id/camera_capture_button"android:layout_width="match_parent"android:layout_height="0dp"/>

3.获取相机权限(略)
4.打开相机,获取预览

@SuppressLint("RestrictedApi")
private fun startCamera() {initMediaCodec(480,640,20)val cameraProviderFuture = ProcessCameraProvider.getInstance(this)cameraProviderFuture.addListener(Runnable {bindImage(cameraProviderFuture)}, ContextCompat.getMainExecutor(this))
}private fun bindImage(cameraProviderFuture:ListenableFuture<ProcessCameraProvider>) {val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()preview = Preview.Builder().build()val cameraSelector =CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()val imageAnalysis = ImageAnalysis.Builder().setTargetResolution(Size(1280, 720)).setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST).build()imageAnalysis.setAnalyzer(cameraExecutor, ImageAnalysis.Analyzer { image ->Thread {val data =ImageUtils.getDataFromImage2(image,ImageUtils.COLOR_FormatI420)val out = FileOutputStream(File(Environment.getExternalStorageDirectory(),"hhh.yuv"))out.write(data)image.close();}.start()})try {cameraProvider.unbindAll()camera = cameraProvider.bindToLifecycle(this, cameraSelector, imageAnalysis, preview)preview?.setSurfaceProvider(viewFinder.createSurfaceProvider(camera?.cameraInfo))} catch (exc: Exception) {Log.e(TAG, "Use case binding failed", exc)}
}

5.获取视频录制数据
使用ImageAnalysis的setAnalyzer方法可以获取到在线直播网站源码录制的视频原始数据,默认的视频数据格式是
yuv_420_888,这种数据格式是不能直接使用ffmepeg或者mediacodec编码的,需要转成i420格式,

yuv_420_888是YCbCr的泛化格式,能够表示任何4:2:0的平面和半平面格式,每个分量用8 bits 表示。带有这种格式的图像使用3个独立的Buffer表示,每一个Buffer表示一个颜色平面(Plane),除了Buffer外,它还提供rowStride、pixelStride来描述对应的Plane。

按照官方的说法,第一个平面全是y数据,第2个平面包含所有的u数据,第3个平面包含所有的v数据,我们只需要解析出原始数据中的yuv分量在按照i420的排列和比例就可以得到我们最终可以使用的数据了。

但是实际解析过程中我发现了在线直播网站源码原始数据中有比较多的填充数据,按照网上的说法是用作对齐处理。

public class ImageUtils {private static final boolean VERBOSE = true;private static final String TAG = "ImageUtils";public static final int COLOR_FormatI420 = 1;public static final int COLOR_FormatNV21 = 2;public static boolean isImageFormatSupported(ImageProxy image) {int format = image.getFormat();switch (format) {case ImageFormat.YUV_420_888:case ImageFormat.NV21:case ImageFormat.YV12:return true;}return false;}public static byte[] getDataFromImage2(ImageProxy image, int colorFormat) {if (colorFormat != COLOR_FormatI420 && colorFormat != COLOR_FormatNV21) {throw new IllegalArgumentException("only support COLOR_FormatI420 " + "and COLOR_FormatNV21");}if (!isImageFormatSupported(image)) {throw new RuntimeException("can't convert Image to byte array, format " + image.getFormat());}Rect crop = image.getCropRect();int format = image.getFormat();// 888int width = crop.width();int height = crop.height();ImageProxy.PlaneProxy[] planes = image.getPlanes();int yRe = planes[0].getBuffer().remaining();int uvRe = planes[1].getBuffer().remaining();int vuRe = planes[2].getBuffer().remaining();int yStride = planes[0].getRowStride();int uvStride = planes[1].getRowStride();int vuStride = planes[2].getRowStride();int yLength = yRe - (yStride-width)*(height-1);int uvLength = uvRe - (uvStride-width)*(height/2-1);int vuLength = vuRe - (vuStride-width)*(height/2-1);byte[] data = new byte[width * height * 12 /8];byte[] yData = new byte[yLength];byte[] uData = new byte[uvLength/2+1];byte[] vData = new byte[vuLength/2 + 1];//uv 占 2分之1byte[] uvData = new byte[uvLength];//vu 占 2分之1byte[] vuData = new byte[vuLength];byte[] rowData = new byte[planes[0].getRowStride()];for (int i = 0; i < planes.length; i++) {ImageProxy.PlaneProxy plane = planes[i];ByteBuffer buffer = plane.getBuffer();int offset = 0;Log.e("getDataFromImage",plane.getPixelStride() + "");buffer.position(0);int col = height / plane.getPixelStride();if(plane.getPixelStride() == 1){ //原矩阵是i420for (int j = 0; j < col; j++) {if(i == 0){ //yif(j < height/plane.getPixelStride() -1){buffer.get(yData,offset,width);}else {buffer.get(yData,offset,yRe - (plane.getRowStride() * (height-1)));}offset +=width;if(j < height/plane.getPixelStride()-1){buffer.position(buffer.position()+ plane.getRowStride() - width);}}else if(i == 1){ //uvbuffer.get(uData,offset,width);offset +=width;if(j < height/plane.getPixelStride() -1){buffer.position(buffer.position()+ plane.getRowStride() - width);}}else { // vubuffer.get(vData,offset,width);offset +=width;if(j < height/plane.getPixelStride()-1){buffer.position(buffer.position()+ plane.getRowStride() - width);}}}}else { // 原矩阵是 nv12 或者 nv21for (int j = 0; j < col; j++) {if(i == 0){ //yif(j < height/plane.getPixelStride() -1){buffer.get(yData,offset,width);}else {buffer.get(yData,offset,yRe - (plane.getRowStride() * ( height/plane.getPixelStride() -1)));}offset +=width;if(j < height/plane.getPixelStride() -1){buffer.position(buffer.position()+ plane.getRowStride() - width);}}else if(i == 1){ //uvif(j < height/plane.getPixelStride() -1){buffer.get(uvData,offset,width);}else {buffer.get(uvData,offset,uvRe - (plane.getRowStride() * (height/plane.getPixelStride()-1)));}offset +=width;if(j < height/plane.getPixelStride() -1){buffer.position(buffer.position()+ plane.getRowStride() - width);}}else { // vuif(j < height/plane.getPixelStride() -1){buffer.get(vuData,offset,width);}else {buffer.get(vuData,offset,vuRe - (plane.getRowStride() * (height/plane.getPixelStride()-1)));}offset +=width;if(j < height/plane.getPixelStride()-1){buffer.position(buffer.position()+ plane.getRowStride() - width);}}}}}boolean isI420 = image.getPlanes()[1].getPixelStride() == 1;//ydata uvdata vudata//提取 u ,vif(!isI420){//for (int i = 0; i < uvData.length; i+=2) {uData[i/2] = uvData[i];}for (int i = 0; i < vuData.length; i+=2) {vData[i/2] = uvData[i];}Log.e("getDataFromImage",uData.length + "");Log.e("getDataFromImage",vData.length + "");}//组装 i420System.arraycopy(yData,0,data,0,yData.length);System.arraycopy(uData,0,data,yData.length,uData.length);System.arraycopy(vData,0,data,yData.length + uData.length ,vData.length);return data;}
}

以上就是“在线直播网站源码开发,视频的采集如何实现?”的全部内容,希望对大家有帮助,在线直播网站源码在开发过程中需要注意每一个细节,否则可能会导致差之毫米失之千里。

在线直播网站源码开发,视频的采集如何实现?相关推荐

  1. 在线教育网站源码教学视频加速的解决方案

    互联网高速发展的今天,在线教育作为一种新兴教育方式,引得越来越多的教育培训机构参与其中,决定找专业服务商选择优质的在线教育网站源码,搭建出属于教育培训机构自己的在线教育网站.从服务商的角度来看,所涉及 ...

  2. python开发直播网站_开发直播网站源码的三种计算机语言

    直播网站源码开发所用的语言,根据未来运营平台不同,其选择也不同.一般来说,如果是PC后台,那么会采用PHP语言编写,如果是在安卓上开发,则选择Java语言,如果是在iOS上开发,则采用object-c ...

  3. 用H5做直播网站源码,如何实现格式推流和播放

    上一篇文章我们讲到,在了解视频流协议HLS与RTMP.明晰目前直播网站源码的主流形式,以及实现直播的简要流程后,我们来继续讲利用Html5实现直播网站源码的剩余步骤. Html5直播网站源码实现录制 ...

  4. 斗鱼做直播已经年收益突破40亿:一对一在线直播程序源码、直播网站搭建就找布谷科技...

    斗鱼做直播已经年收益突破40亿:一对一在线直播程序源码.直播网站搭建就找布谷科技 据相关部门报道在3月25日斗鱼单靠直播现在年收益已经突破40亿了,游戏直播在线直播程序源码依旧是名列前茅的,占据的市场 ...

  5. 视频直播APP源码开发iOS音频播放流程

    视频直播APP源码开发iOS音频播放流程 概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的, ...

  6. 直播网站源码直播平台软件开发iOS动手做一个直播(原理篇)

    直播网站源码直播平台软件开发iOS动手做一个直播(原理篇) 上篇文章主要给出了代码,但是并没有详细说明直播相关的知识,这篇文章就说一下直播的相关理论知识.附上直播代码篇地址. ###推流 腾讯直播平台 ...

  7. 视频交友直播软件源码开发的必备功能讲解

    相信通过这两年行业的发展我们不难看出.视频交友直播源码拥有简单直接的变现方式,深受平台和用户的喜爱,越来越多的年轻人也热衷于视频直播. 视频交友直播软件开发,支持用户在视频过程中用文字沟通,可以互相发 ...

  8. 视频直播网站源码,uniapp页面跳转的几种方法和区别

    视频直播网站源码,uniapp页面跳转的几种方法和区别 保留当前页面,可跳转到非 tabBar 页面,使用uni.navigateBack可以返回到原页面(可传参) uni.navigateTo({u ...

  9. 一对一直播软件源码开发,iOS视频采集的实现过程

    在一对一直播软件源码日益火热的发展形势下,音视频开发(采集.编解码.传输.播放.美颜)等技术也随之成为开发者们关注的重点,本系列文章就音视频开发过程中所运用到的技术和原理进行梳理和总结. 认识 AVC ...

最新文章

  1. BZOJ2038 小Z的袜子(hose)
  2. 模拟器抓取https方法
  3. Qt下Tcp通信的简单使用三
  4. php启动后no input file specified.,nginx+php出现No input file specified解决办法
  5. 箭头函数和普通函数有什么区别?
  6. C++---布隆过滤器
  7. Java分布式锁的概念以及使用优点
  8. 【SQL学习】select语句使用实例
  9. python交通流预测代码,使用python进行交通流量预测
  10. PHP如何接入短信接口,通过短信群发通知
  11. 初级会计实务--第二章第五节、固定资产
  12. idea中maven打包报错:Compilation failure: Compilation failure
  13. Java后端传图片字节流到Vue前端显示
  14. MGRE结合OSPF(超详解)
  15. SciPyCon 2018 sklearn 教程(上)
  16. 研发二部二组-问题点归纳
  17. float和double的精度
  18. Python3 序列解包
  19. 计算机鼠标不会动,为什么鼠标突然不动了 有什么解决方法
  20. 1.4 Qt工具之Qt Linguist介绍

热门文章

  1. 电子或通讯领域当前的主流技术及其社会需求调查报告
  2. QT QElapsedTimer QDeadlineTimer 计算已用时间的方法
  3. openid和unionid的区别
  4. dubbo-源码环境搭建
  5. matlab编程excosxdx求积分,求定积分∫e^2xcosxdx.
  6. 遨博机器人AUBO C语言的SDK接口说明(2)
  7. ## 项目第十五天 ##
  8. 数据预处理--医学图像归一化
  9. 【OpenCV】图像梯度处理
  10. 计算机网络工程的发展,谈计算机网络工程全面信息化管理的应用与发展