xref: /aosp_15_r20/frameworks/rs/toolkit/test/ReferenceYuvToRgb.kt (revision e1eccf28f96817838ad6867f7f39d2351ec11f56)
1*e1eccf28SAndroid Build Coastguard Worker /*
2*e1eccf28SAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*e1eccf28SAndroid Build Coastguard Worker  *
4*e1eccf28SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*e1eccf28SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*e1eccf28SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*e1eccf28SAndroid Build Coastguard Worker  *
8*e1eccf28SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*e1eccf28SAndroid Build Coastguard Worker  *
10*e1eccf28SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*e1eccf28SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*e1eccf28SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*e1eccf28SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*e1eccf28SAndroid Build Coastguard Worker  * limitations under the License.
15*e1eccf28SAndroid Build Coastguard Worker  */
16*e1eccf28SAndroid Build Coastguard Worker 
17*e1eccf28SAndroid Build Coastguard Worker package com.example.testapp
18*e1eccf28SAndroid Build Coastguard Worker 
19*e1eccf28SAndroid Build Coastguard Worker import android.renderscript.toolkit.YuvFormat
20*e1eccf28SAndroid Build Coastguard Worker import java.lang.IllegalArgumentException
21*e1eccf28SAndroid Build Coastguard Worker 
22*e1eccf28SAndroid Build Coastguard Worker /**
23*e1eccf28SAndroid Build Coastguard Worker  * Reference implementation of a YUV to RGB operation.
24*e1eccf28SAndroid Build Coastguard Worker  */
25*e1eccf28SAndroid Build Coastguard Worker @ExperimentalUnsignedTypes
referenceYuvToRgbnull26*e1eccf28SAndroid Build Coastguard Worker fun referenceYuvToRgb(inputSignedArray: ByteArray, sizeX: Int, sizeY: Int, format: YuvFormat): ByteArray {
27*e1eccf28SAndroid Build Coastguard Worker     require(sizeX % 2 == 0) { "The width of the input should be even."}
28*e1eccf28SAndroid Build Coastguard Worker     val inputArray = inputSignedArray.asUByteArray()
29*e1eccf28SAndroid Build Coastguard Worker 
30*e1eccf28SAndroid Build Coastguard Worker     val outputArray = ByteArray(sizeX * sizeY * 4)
31*e1eccf28SAndroid Build Coastguard Worker     val output = Vector2dArray(outputArray.asUByteArray(), 4, sizeX, sizeY)
32*e1eccf28SAndroid Build Coastguard Worker 
33*e1eccf28SAndroid Build Coastguard Worker     when (format) {
34*e1eccf28SAndroid Build Coastguard Worker         YuvFormat.NV21 -> {
35*e1eccf28SAndroid Build Coastguard Worker             val startY = 0
36*e1eccf28SAndroid Build Coastguard Worker             val startU = sizeX * sizeY + 1
37*e1eccf28SAndroid Build Coastguard Worker             val startV = sizeX * sizeY
38*e1eccf28SAndroid Build Coastguard Worker 
39*e1eccf28SAndroid Build Coastguard Worker             for (y in 0 until sizeY) {
40*e1eccf28SAndroid Build Coastguard Worker                 for (x in 0 until sizeX) {
41*e1eccf28SAndroid Build Coastguard Worker                     val offsetY = y * sizeX + x
42*e1eccf28SAndroid Build Coastguard Worker                     val offsetU = ((y shr 1) * sizeX + (x shr 1) * 2)
43*e1eccf28SAndroid Build Coastguard Worker                     val offsetV = ((y shr 1) * sizeX + (x shr 1) * 2)
44*e1eccf28SAndroid Build Coastguard Worker                     output[x, y] = yuvToRGBA4(
45*e1eccf28SAndroid Build Coastguard Worker                         inputArray[startY + offsetY],
46*e1eccf28SAndroid Build Coastguard Worker                         inputArray[startU + offsetU],
47*e1eccf28SAndroid Build Coastguard Worker                         inputArray[startV + offsetV]
48*e1eccf28SAndroid Build Coastguard Worker                     )
49*e1eccf28SAndroid Build Coastguard Worker                 }
50*e1eccf28SAndroid Build Coastguard Worker             }
51*e1eccf28SAndroid Build Coastguard Worker         }
52*e1eccf28SAndroid Build Coastguard Worker 
53*e1eccf28SAndroid Build Coastguard Worker         YuvFormat.YV12 -> {
54*e1eccf28SAndroid Build Coastguard Worker             /* According to https://developer.android.com/reference/kotlin/android/graphics/ImageFormat#yv12,
55*e1eccf28SAndroid Build Coastguard Worker              * strideX and strideUV should be aligned to 16 byte boundaries. If we do this, we
56*e1eccf28SAndroid Build Coastguard Worker              * won't get the same results as RenderScript.
57*e1eccf28SAndroid Build Coastguard Worker              *
58*e1eccf28SAndroid Build Coastguard Worker              * We may want to test & require that sizeX is a multiple of 16/32.
59*e1eccf28SAndroid Build Coastguard Worker              */
60*e1eccf28SAndroid Build Coastguard Worker             val strideX = roundUpTo16(sizeX) // sizeX //
61*e1eccf28SAndroid Build Coastguard Worker             val strideUV = roundUpTo16(strideX / 2) // strideX / 2 //
62*e1eccf28SAndroid Build Coastguard Worker             val startY = 0
63*e1eccf28SAndroid Build Coastguard Worker             val startU = strideX * sizeY
64*e1eccf28SAndroid Build Coastguard Worker             val startV = startU + strideUV * sizeY / 2
65*e1eccf28SAndroid Build Coastguard Worker 
66*e1eccf28SAndroid Build Coastguard Worker             for (y in 0 until sizeY) {
67*e1eccf28SAndroid Build Coastguard Worker                 for (x in 0 until sizeX) {
68*e1eccf28SAndroid Build Coastguard Worker                     val offsetY = y * sizeX + x
69*e1eccf28SAndroid Build Coastguard Worker                     val offsetUV = (y shr 1) * strideUV + (x shr 1)
70*e1eccf28SAndroid Build Coastguard Worker                     output[x, y] = yuvToRGBA4(
71*e1eccf28SAndroid Build Coastguard Worker                         inputArray[startY + offsetY],
72*e1eccf28SAndroid Build Coastguard Worker                         inputArray[startU + offsetUV],
73*e1eccf28SAndroid Build Coastguard Worker                         inputArray[startV + offsetUV],
74*e1eccf28SAndroid Build Coastguard Worker                     )
75*e1eccf28SAndroid Build Coastguard Worker                 }
76*e1eccf28SAndroid Build Coastguard Worker             }
77*e1eccf28SAndroid Build Coastguard Worker         }
78*e1eccf28SAndroid Build Coastguard Worker         else -> throw IllegalArgumentException("Unknown YUV format $format")
79*e1eccf28SAndroid Build Coastguard Worker     }
80*e1eccf28SAndroid Build Coastguard Worker 
81*e1eccf28SAndroid Build Coastguard Worker     return outputArray
82*e1eccf28SAndroid Build Coastguard Worker }
83*e1eccf28SAndroid Build Coastguard Worker 
84*e1eccf28SAndroid Build Coastguard Worker @ExperimentalUnsignedTypes
yuvToRGBA4null85*e1eccf28SAndroid Build Coastguard Worker private fun yuvToRGBA4(y: UByte, u: UByte, v: UByte): UByteArray {
86*e1eccf28SAndroid Build Coastguard Worker     val intY = y.toInt() - 16
87*e1eccf28SAndroid Build Coastguard Worker     val intU = u.toInt() - 128
88*e1eccf28SAndroid Build Coastguard Worker     val intV = v.toInt() - 128
89*e1eccf28SAndroid Build Coastguard Worker     val p = intArrayOf(
90*e1eccf28SAndroid Build Coastguard Worker         intY * 298 + intV * 409 + 128 shr 8,
91*e1eccf28SAndroid Build Coastguard Worker         intY * 298 - intU * 100 - intV * 208 + 128 shr 8,
92*e1eccf28SAndroid Build Coastguard Worker         intY * 298 + intU * 516 + 128 shr 8,
93*e1eccf28SAndroid Build Coastguard Worker         255
94*e1eccf28SAndroid Build Coastguard Worker     )
95*e1eccf28SAndroid Build Coastguard Worker     return UByteArray(4) { p[it].clampToUByte() }
96*e1eccf28SAndroid Build Coastguard Worker }
97*e1eccf28SAndroid Build Coastguard Worker 
98*e1eccf28SAndroid Build Coastguard Worker /* To be used if we support Float
yuvToRGBA_f4null99*e1eccf28SAndroid Build Coastguard Worker private fun yuvToRGBA_f4(y: UByte, u: UByte, v: UByte): UByteArray {
100*e1eccf28SAndroid Build Coastguard Worker     val yuv_U_values = floatArrayOf(0f, -0.392f * 0.003921569f, 2.02f * 0.003921569f, 0f)
101*e1eccf28SAndroid Build Coastguard Worker     val yuv_V_values = floatArrayOf(1.603f * 0.003921569f, -0.815f * 0.003921569f, 0f, 0f)
102*e1eccf28SAndroid Build Coastguard Worker 
103*e1eccf28SAndroid Build Coastguard Worker     var color = FloatArray(4) {y.toFloat() * 0.003921569f}
104*e1eccf28SAndroid Build Coastguard Worker     val fU = FloatArray(4) {u.toFloat() - 128f}
105*e1eccf28SAndroid Build Coastguard Worker     val fV = FloatArray(4) {v.toFloat() - 128f}
106*e1eccf28SAndroid Build Coastguard Worker 
107*e1eccf28SAndroid Build Coastguard Worker     color += fU * yuv_U_values;
108*e1eccf28SAndroid Build Coastguard Worker     color += fV * yuv_V_values;
109*e1eccf28SAndroid Build Coastguard Worker     //color = clamp(color, 0.f, 1.f);
110*e1eccf28SAndroid Build Coastguard Worker     return UByteArray(4) { unitFloatClampedToUByte(color[it]) }
111*e1eccf28SAndroid Build Coastguard Worker }
112*e1eccf28SAndroid Build Coastguard Worker */
113