I’m trying to apply YUV to RGB conversion in Android. I am currently using this official code from Android Camera samples (the code below) but it uses RenderScript
which is going to be deprecated.
How can I rewrite it without using RenderScript to be as efficient? Any Android native solutions available?
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.camera.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.ImageFormat
import android.media.Image
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
import android.renderscript.ScriptIntrinsicYuvToRGB
import android.renderscript.Type
import java.nio.ByteBuffer
/**
* Helper class used to convert a [Image] object from
* [ImageFormat.YUV_420_888] format to an RGB [Bitmap] object, it has equivalent
* functionality to https://github
* .com/androidx/androidx/blob/androidx-main/camera/camera-core/src/main/java/androidx/camera/core/ImageYuvToRgbConverter.java
*
* NOTE: This has been tested in a limited number of devices and is not
* considered production-ready code. It was created for illustration purposes,
* since this is not an efficient camera pipeline due to the multiple copies
* required to convert each frame. For example, this
* implementation
* (/questions/52726002/camera2-captured-picture-conversion-from-yuv-420-888-to-nv21/52740776#52740776)
* might have better performance.
*/
class YuvToRgbConverter(context: Context) {
private val rs = RenderScript.create(context)
private val scriptYuvToRgb =
ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs))
// Do not add getters/setters functions to these private variables
// because yuvToRgb() assume they won't be modified elsewhere
private var yuvBits: ByteBuffer? = null
private var bytes: ByteArray = ByteArray(0)
private var inputAllocation: Allocation? = null
private var outputAllocation: Allocation? = null
@Synchronized
fun yuvToRgb(image: Image, output: Bitmap) {
val yuvBuffer = YuvByteBuffer(image, yuvBits)
yuvBits = yuvBuffer.buffer
if (needCreateAllocations(image, yuvBuffer)) {
val yuvType = Type.Builder(rs, Element.U8(rs))
.setX(image.width)
.setY(image.height)
.setYuvFormat(yuvBuffer.type)
inputAllocation = Allocation.createTyped(
rs,
yuvType.create(),
Allocation.USAGE_SCRIPT
)
bytes = ByteArray(yuvBuffer.buffer.capacity())
val rgbaType = Type.Builder(rs, Element.RGBA_8888(rs))
.setX(image.width)
.setY(image.height)
outputAllocation = Allocation.createTyped(
rs,
rgbaType.create(),
Allocation.USAGE_SCRIPT
)
}
yuvBuffer.buffer.get(bytes)
inputAllocation!!.copyFrom(bytes)
// Convert NV21 or YUV_420_888 format to RGB
inputAllocation!!.copyFrom(bytes)
scriptYuvToRgb.setInput(inputAllocation)
scriptYuvToRgb.forEach(outputAllocation)
outputAllocation!!.copyTo(output)
}
private fun needCreateAllocations(image: Image, yuvBuffer: YuvByteBuffer): Boolean {
return (inputAllocation == null || // the very 1st call
inputAllocation!!.type.x != image.width || // image size changed
inputAllocation!!.type.y != image.height ||
inputAllocation!!.type.yuv != yuvBuffer.type || // image format changed
bytes.size == yuvBuffer.buffer.capacity())
}
}