camera 拉伸填坑

作者: ZoranLee | 来源:发表于2021-12-24 11:34 被阅读0次

    AndroidTv Camera填坑记


    目标机型

    camera预览图像拉伸

    其中关键核心是YUV 格式和RGB转换
    具体参考了:https://github.com/gordinmitya/yuv2buf

    简述一下:YUV即通过Y、U和V三个分量表示颜色空间,其中Y表示亮度,U和V表示色度。

    YUV_420_888 是一个通用格式,分I420, YV12, NV21, and NV12这几种

    具体参考如下:


    image.png
    • 操刀
    class AutoFitSurfaceView @JvmOverloads constructor(
            context: Context,
            attrs: AttributeSet? = null,
            defStyle: Int = 0
    ) : SurfaceView(context, attrs, defStyle) {
    
        private var aspectRatio = 0f
    
        /**
         * Sets the aspect ratio for this view. The size of the view will be
         * measured based on the ratio calculated from the parameters.
         *
         * @param width  Camera resolution horizontal size
         * @param height Camera resolution vertical size
         */
        fun setAspectRatio(width: Int, height: Int) {
            require(width > 0 && height > 0) { "Size cannot be negative" }
            aspectRatio = width.toFloat() / height.toFloat()
            holder.setFixedSize(width, height)
            requestLayout()
        }
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            val width = MeasureSpec.getSize(widthMeasureSpec)
            val height = MeasureSpec.getSize(heightMeasureSpec)
            if (aspectRatio == 0f) {
                setMeasuredDimension(width, height)
            } else {
    
                // Performs center-crop transformation of the camera frames
                val newWidth: Int
                val newHeight: Int
                val actualRatio = if (width > height) aspectRatio else 1f / aspectRatio
                if (width < height * actualRatio) {
                    newHeight = height
                    newWidth = (height * actualRatio).roundToInt()
                } else {
                    newWidth = width
                    newHeight = (width / actualRatio).roundToInt()
                }
    
                Log.d(TAG, "Measured dimensions set: $newWidth x $newHeight")
                setMeasuredDimension(newWidth, newHeight)
            }
        }
    
        companion object {
            private val TAG = AutoFitSurfaceView::class.java.simpleName
        }
    }
    
    
    • 计算预览大小
    //        AutoFitSurfaceView xml配置
    
           AutoFitSurfaceView.addCallback(object : SurfaceHolder.Callback {
                override fun surfaceDestroyed(holder: SurfaceHolder) = Unit
    
                override fun surfaceChanged(
                        holder: SurfaceHolder,
                        format: Int,
                        width: Int,
                        height: Int) = Unit
    
                override fun surfaceCreated(holder: SurfaceHolder) {
                    // Selects appropriate preview size and configures view finder
                    val previewSize = getPreviewOutputSize(
                        AutoFitSurfaceView .display,
                        characteristics,
                        SurfaceHolder::class.java
                    )
          
                  AutoFitSurfaceView.setAspectRatio(
                        previewSize.width,
                        previewSize.height
                    )
    
                }
            })
    
    
    
    
    fun <T>getPreviewOutputSize(
            display: Display,
            characteristics: CameraCharacteristics,
            targetClass: Class<T>,
            format: Int? = null
    ): Size {
    
        // Find which is smaller: screen or 1080p
        val screenSize = getDisplaySmartSize(display)
        val hdScreen = screenSize.long >= SIZE_1080P.long || screenSize.short >= SIZE_1080P.short
        val maxSize = if (hdScreen) SIZE_1080P else screenSize
    
        // If image format is provided, use it to determine supported sizes; else use target class
        val config = characteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
        if (format == null)
            assert(StreamConfigurationMap.isOutputSupportedFor(targetClass))
        else
            assert(config.isOutputSupportedFor(format))
        val allSizes = if (format == null)
            config.getOutputSizes(targetClass) else config.getOutputSizes(format)
    
        // Get available sizes and sort them by area from largest to smallest
        val validSizes = allSizes
                .sortedWith(compareBy { it.height * it.width })
                .map { SmartSize(it.width, it.height) }.reversed()
    
        // Then, get the largest output size that is smaller or equal than our max size
        return validSizes.first { it.long <= maxSize.long && it.short <= maxSize.short }.size
    }
    
    class SmartSize(width: Int, height: Int) {
        var size = Size(width, height)
        var long = max(size.width, size.height)
        var short = min(size.width, size.height)
        override fun toString() = "SmartSize(${long}x${short})"
    }
    
    val SIZE_1080P: SmartSize = SmartSize(1920, 1080)
    
    fun getDisplaySmartSize(display: Display): SmartSize {
        val outPoint = Point()
        display.getRealSize(outPoint)
        return SmartSize(outPoint.x, outPoint.y)
    }
    
    

    相关文章

      网友评论

        本文标题:camera 拉伸填坑

        本文链接:https://www.haomeiwen.com/subject/vkvefrtx.html