@@ -2,18 +2,14 @@ package dev.steenbakker.mobile_scanner.utils
22
33import android.content.Context
44import android.graphics.Bitmap
5- import android.graphics.ImageFormat
65import android.media.Image
7- import android.os.Build
86import android.renderscript.Allocation
97import android.renderscript.Element
108import android.renderscript.RenderScript
119import android.renderscript.ScriptIntrinsicYuvToRGB
1210import android.renderscript.Type
13- import androidx.annotation.RequiresApi
1411import java.nio.ByteBuffer
1512
16-
1713/* *
1814 * Helper class used to efficiently convert a [Media.Image] object from
1915 * YUV_420_888 format to an RGB [Bitmap] object.
@@ -23,59 +19,84 @@ import java.nio.ByteBuffer
2319 * The [yuvToRgb] method is able to achieve the same FPS as the CameraX image
2420 * analysis use case at the default analyzer resolution, which is 30 FPS with
2521 * 640x480 on a Pixel 3 XL device.
26- */ class YuvToRgbConverter (context : Context ) {
22+ */
23+ // / TODO: Upgrade to implementation without deprecated android.renderscript, but with same or better performance. See https://github.com/juliansteenbakker/mobile_scanner/issues/1142
24+ class YuvToRgbConverter (context : Context ) {
25+ @Suppress(" DEPRECATION" )
2726 private val rs = RenderScript .create(context)
27+ @Suppress(" DEPRECATION" )
2828 private val scriptYuvToRgb =
2929 ScriptIntrinsicYuvToRGB .create(rs, Element .U8_4 (rs))
3030
31- // Do not add getters/setters functions to these private variables
32- // because yuvToRgb() assume they won't be modified elsewhere
3331 private var yuvBits: ByteBuffer ? = null
3432 private var bytes: ByteArray = ByteArray (0 )
33+ @Suppress(" DEPRECATION" )
3534 private var inputAllocation: Allocation ? = null
35+ @Suppress(" DEPRECATION" )
3636 private var outputAllocation: Allocation ? = null
3737
3838 @Synchronized
3939 fun yuvToRgb (image : Image , output : Bitmap ) {
40- val yuvBuffer = YuvByteBuffer (image, yuvBits)
41- yuvBits = yuvBuffer.buffer
40+ try {
41+ val yuvBuffer = YuvByteBuffer (image, yuvBits)
42+ yuvBits = yuvBuffer.buffer
4243
43- if (needCreateAllocations(image, yuvBuffer)) {
44- val yuvType = Type .Builder (rs, Element .U8 (rs))
45- .setX(image.width)
46- .setY(image.height)
47- .setYuvFormat(yuvBuffer.type)
48- inputAllocation = Allocation .createTyped(
49- rs,
50- yuvType.create(),
51- Allocation .USAGE_SCRIPT
52- )
53- bytes = ByteArray (yuvBuffer.buffer.capacity())
54- val rgbaType = Type .Builder (rs, Element .RGBA_8888 (rs))
55- .setX(image.width)
56- .setY(image.height)
57- outputAllocation = Allocation .createTyped(
58- rs,
59- rgbaType.create(),
60- Allocation .USAGE_SCRIPT
61- )
62- }
44+ if (needCreateAllocations(image, yuvBuffer)) {
45+ createAllocations(image, yuvBuffer)
46+ }
6347
64- yuvBuffer.buffer.get(bytes)
65- inputAllocation!! .copyFrom(bytes)
48+ yuvBuffer.buffer.get(bytes)
49+ @Suppress(" DEPRECATION" )
50+ inputAllocation!! .copyFrom(bytes)
6651
67- // Convert NV21 or YUV_420_888 format to RGB
68- inputAllocation!! .copyFrom(bytes)
69- scriptYuvToRgb.setInput(inputAllocation)
70- scriptYuvToRgb.forEach(outputAllocation)
71- outputAllocation!! .copyTo(output)
52+ @Suppress(" DEPRECATION" )
53+ scriptYuvToRgb.setInput(inputAllocation)
54+ @Suppress(" DEPRECATION" )
55+ scriptYuvToRgb.forEach(outputAllocation)
56+ @Suppress(" DEPRECATION" )
57+ outputAllocation!! .copyTo(output)
58+ } catch (e: Exception ) {
59+ throw IllegalStateException (" Failed to convert YUV to RGB" , e)
60+ }
7261 }
7362
7463 private fun needCreateAllocations (image : Image , yuvBuffer : YuvByteBuffer ): Boolean {
75- return (inputAllocation == null || // the very 1st call
76- inputAllocation!! .type.x != image.width || // image size changed
77- inputAllocation!! .type.y != image.height ||
78- inputAllocation!! .type.yuv != yuvBuffer.type || // image format changed
79- bytes.size == yuvBuffer.buffer.capacity())
64+ @Suppress(" DEPRECATION" )
65+ return inputAllocation?.type?.x != image.width ||
66+ inputAllocation?.type?.y != image.height ||
67+ inputAllocation?.type?.yuv != yuvBuffer.type
68+ }
69+
70+ private fun createAllocations (image : Image , yuvBuffer : YuvByteBuffer ) {
71+ @Suppress(" DEPRECATION" )
72+ val yuvType = Type .Builder (rs, Element .U8 (rs))
73+ .setX(image.width)
74+ .setY(image.height)
75+ .setYuvFormat(yuvBuffer.type)
76+ @Suppress(" DEPRECATION" )
77+ inputAllocation = Allocation .createTyped(
78+ rs,
79+ yuvType.create(),
80+ Allocation .USAGE_SCRIPT
81+ )
82+ bytes = ByteArray (yuvBuffer.buffer.capacity())
83+ @Suppress(" DEPRECATION" )
84+ val rgbaType = Type .Builder (rs, Element .RGBA_8888 (rs))
85+ .setX(image.width)
86+ .setY(image.height)
87+ @Suppress(" DEPRECATION" )
88+ outputAllocation = Allocation .createTyped(
89+ rs,
90+ rgbaType.create(),
91+ Allocation .USAGE_SCRIPT
92+ )
93+ }
94+
95+ @Suppress(" DEPRECATION" )
96+ fun release () {
97+ inputAllocation?.destroy()
98+ outputAllocation?.destroy()
99+ scriptYuvToRgb.destroy()
100+ rs.destroy()
80101 }
81102}
0 commit comments