博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android视频直播流(二)Android摄像头YUV数据的获取
阅读量:6638 次
发布时间:2019-06-25

本文共 4948 字,大约阅读时间需要 16 分钟。

hot3.png

这里涉及到了摄像头Camera的使用,和对YUV数据的获取。

这里有一些东西需要格外注意,就是编码格式的选择,以及对宽高的设置

我这里自定义了一个CmeraView 因为摄像头的使用有点复杂,我索性就封装起来,这里一定要注意,宽(prewWidth )高(prewHeight )的设置,很有用,很有用。

import android.app.Activityimport android.content.Contextimport android.graphics.ImageFormatimport android.hardware.*import android.util.AttributeSetimport android.view.SurfaceHolderimport android.view.SurfaceViewimport android.view.Surface/** * Created by xiaolei on 2018/3/26. */class CameraView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : SurfaceView(context, attrs, defStyleAttr), SurfaceHolder.Callback{    private var cameraId = 0    private val camera = Camera.open(cameraId)    private var preViewBlock: ((ByteArray, Camera) -> Unit)? = null    var prewWidth = 640    var prewHeight = 480        init    {        holder.addCallback(this)        holder.setKeepScreenOn(true)        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)        camera.setPreviewCallback { data, camera ->            preViewBlock?.invoke(data, camera)        }        val params = camera.parameters        val supportSizeList = params.supportedPreviewSizes // 获取摄像头支持的分辨率宽高        println(supportSizeList.size)        supportSizeList.forEach { size ->            if (size.width == prewWidth && size.height == prewHeight)            {                params.setPreviewSize(prewWidth, prewHeight)            }        }        params.previewFormat = ImageFormat.NV21 // 设置摄像头输出的格式为 YUV420下 的 NV21        camera.parameters = params    }    override fun surfaceCreated(holder: SurfaceHolder?)    {        try        {            camera.setPreviewDisplay(holder)            camera.startPreview()        } catch (e: Exception)        {            e.printStackTrace()        }    }    override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int)    {        // If your preview can change or rotate, take care of those events here.        // 如果您的预览可以更改或旋转,请在这里处理这些事件。        // Make sure to stop the preview before resizing or reformatting it.        // 在调整或重新格式化之前,务必停止预览。        getHolder() ?: let {            return        }        // stop preview before making changes        // 更改前停止预览。        try        {            camera.startPreview()        } catch (e: Exception)        {            e.printStackTrace()        }        // set preview size and make any resize, rotate or reformatting changes here        // 设置预览大小,并在这里进行任何调整、旋转或重新格式化。        // start preview with new settings        // 使用新的设置开始预览。        try        {            camera.setPreviewDisplay(getHolder())            camera.startPreview()        } catch (e: Exception)        {            e.printStackTrace()        }    }    override fun surfaceDestroyed(holder: SurfaceHolder?)    {        // empty. Take care of releasing the Camera preview in your activity.        // 空的。注意在你的活动中发布相机预览。        camera.setPreviewCallback(null)        camera.stopPreview()        camera.release()    }    /**     * 设置自动旋转     */    fun setAutoRotation(activity: Activity)    {        val rotation = activity.windowManager.defaultDisplay.rotation        val info = Camera.CameraInfo()        Camera.getCameraInfo(cameraId, info)        val degrees = when (rotation)        {            Surface.ROTATION_0 -> 0            Surface.ROTATION_90 -> 90            Surface.ROTATION_180 -> 180            Surface.ROTATION_270 -> 270            else -> 0        }        val result = if (info.facing === Camera.CameraInfo.CAMERA_FACING_FRONT)        {            val r = (info.orientation + degrees) % 360            (360 - r) % 360        } else        {            (info.orientation - degrees + 360) % 360        }        camera.setDisplayOrientation(result)    }    /**     * 设置预览数据的回调     */    fun onPreviewCallback(block: (ByteArray, Camera) -> Unit)    {        this.preViewBlock = block    }    fun autoFocus()    {        camera.autoFocus { success, camera -> }    }    /**     * 把 YUV 的界面旋转90度,使得预览正常,     * 但是会把,宽 高 旋转     */    fun yuv_rotate90(src: ByteArray, width: Int, height: Int): ByteArray    {        val des = ByteArray(src.size)        val wh = width * height        //旋转Y        var k = 0        for (i in 0 until width)        {            for (j in height - 1 downTo 0)            {                des[k++] = src[j * width + i]            }        }        //旋转UV        val uvHeight = height shr 1        val uvWidth = width shr 1        val uvWH = uvHeight * uvWidth        var i = 0        while (i < width)        {            for (j in uvHeight - 1 downTo 0)            {                des[k] = src[wh + width * j + i]                des[k + 1] = src[wh + width * j + i + 1]                k += 2            }            i += 2        }        return des    }}

其实关键代码就是这句:

camera.setPreviewCallback { data, camera ->            preViewBlock?.invoke(data, camera)}

这里拿到的数据,就是刚才设置的 宽*高以及对 UV 数据的排列格式的数据。

转载于:https://my.oschina.net/xiaolei123/blog/1786787

你可能感兴趣的文章
一位老码农的分享:一线程序员该如何面对「中年危机」?
查看>>
java编程思想之注解
查看>>
在 Android 设备上搭建 Web 服务器
查看>>
iOS 网络监控框架 - Reachability 源码解读
查看>>
实战PHP数据结构基础之递归
查看>>
eclipse中如何自动生成构造函数
查看>>
使用Java connector消费ABAP系统的函数
查看>>
【iOS开发】iOS10 Log调试小工具
查看>>
C++ 引用和函数的高级特性
查看>>
code-rhythm:写了个vscode扩展,让代码更有快感
查看>>
机器学习常用算法的分类
查看>>
EM算法学习(二)
查看>>
Android 面试系列 Dn.2---- 广播?
查看>>
用Node.js写爬虫,撸羞羞的图片
查看>>
iOS定时器(时间不在于你拥有多少,而在于你怎样使用)
查看>>
JavaScript 算法之复杂度分析
查看>>
玩转webpack4
查看>>
分布式系统:Lamport 逻辑时钟
查看>>
css代码规范工具stylelint
查看>>
传统加密技术
查看>>