| /* |
| * Copyright (C) 2021 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 |
| * |
| * http://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.testapp |
| |
| import android.renderscript.toolkit.YuvFormat |
| import java.lang.IllegalArgumentException |
| |
| /** |
| * Reference implementation of a YUV to RGB operation. |
| */ |
| @ExperimentalUnsignedTypes |
| fun referenceYuvToRgb(inputSignedArray: ByteArray, sizeX: Int, sizeY: Int, format: YuvFormat): ByteArray { |
| require(sizeX % 2 == 0) { "The width of the input should be even."} |
| val inputArray = inputSignedArray.asUByteArray() |
| |
| val outputArray = ByteArray(sizeX * sizeY * 4) |
| val output = Vector2dArray(outputArray.asUByteArray(), 4, sizeX, sizeY) |
| |
| when (format) { |
| YuvFormat.NV21 -> { |
| val startY = 0 |
| val startU = sizeX * sizeY + 1 |
| val startV = sizeX * sizeY |
| |
| for (y in 0 until sizeY) { |
| for (x in 0 until sizeX) { |
| val offsetY = y * sizeX + x |
| val offsetU = ((y shr 1) * sizeX + (x shr 1) * 2) |
| val offsetV = ((y shr 1) * sizeX + (x shr 1) * 2) |
| output[x, y] = yuvToRGBA4( |
| inputArray[startY + offsetY], |
| inputArray[startU + offsetU], |
| inputArray[startV + offsetV] |
| ) |
| } |
| } |
| } |
| |
| YuvFormat.YV12 -> { |
| /* According to https://developer.android.com/reference/kotlin/android/graphics/ImageFormat#yv12, |
| * strideX and strideUV should be aligned to 16 byte boundaries. If we do this, we |
| * won't get the same results as RenderScript. |
| * |
| * We may want to test & require that sizeX is a multiple of 16/32. |
| */ |
| val strideX = roundUpTo16(sizeX) // sizeX // |
| val strideUV = roundUpTo16(strideX / 2) // strideX / 2 // |
| val startY = 0 |
| val startU = strideX * sizeY |
| val startV = startU + strideUV * sizeY / 2 |
| |
| for (y in 0 until sizeY) { |
| for (x in 0 until sizeX) { |
| val offsetY = y * sizeX + x |
| val offsetUV = (y shr 1) * strideUV + (x shr 1) |
| output[x, y] = yuvToRGBA4( |
| inputArray[startY + offsetY], |
| inputArray[startU + offsetUV], |
| inputArray[startV + offsetUV], |
| ) |
| } |
| } |
| } |
| else -> throw IllegalArgumentException("Unknown YUV format $format") |
| } |
| |
| return outputArray |
| } |
| |
| @ExperimentalUnsignedTypes |
| private fun yuvToRGBA4(y: UByte, u: UByte, v: UByte): UByteArray { |
| val intY = y.toInt() - 16 |
| val intU = u.toInt() - 128 |
| val intV = v.toInt() - 128 |
| val p = intArrayOf( |
| intY * 298 + intV * 409 + 128 shr 8, |
| intY * 298 - intU * 100 - intV * 208 + 128 shr 8, |
| intY * 298 + intU * 516 + 128 shr 8, |
| 255 |
| ) |
| return UByteArray(4) { p[it].clampToUByte() } |
| } |
| |
| /* To be used if we support Float |
| private fun yuvToRGBA_f4(y: UByte, u: UByte, v: UByte): UByteArray { |
| val yuv_U_values = floatArrayOf(0f, -0.392f * 0.003921569f, 2.02f * 0.003921569f, 0f) |
| val yuv_V_values = floatArrayOf(1.603f * 0.003921569f, -0.815f * 0.003921569f, 0f, 0f) |
| |
| var color = FloatArray(4) {y.toFloat() * 0.003921569f} |
| val fU = FloatArray(4) {u.toFloat() - 128f} |
| val fV = FloatArray(4) {v.toFloat() - 128f} |
| |
| color += fU * yuv_U_values; |
| color += fV * yuv_V_values; |
| //color = clamp(color, 0.f, 1.f); |
| return UByteArray(4) { unitFloatClampedToUByte(color[it]) } |
| } |
| */ |