1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/* 2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2013 The Android Open Source Project 3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License"); 5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License. 6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at 7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * http://www.apache.org/licenses/LICENSE-2.0 9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software 11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS, 12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and 14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License. 15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "colorspace.h" 18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <jni.h> 20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <stdint.h> 21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickstypedef uint8_t uint8; 23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickstypedef uint32_t uint32; 24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickstypedef int32_t int32; 25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// RGBA helper struct allows access as int and individual channels 27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// WARNING: int value depends on endianness and should not be used to analyze individual channels. 28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksunion Rgba { 29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks uint32 color; 30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks uint8 channel[4]; 31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}; 32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Channel index constants 34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic const uint8 kRed = 0; 35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic const uint8 kGreen = 1; 36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic const uint8 kBlue = 2; 37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic const uint8 kAlpha = 3; 38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Clamp to range 0-255 40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic inline uint32 clamp(int32 x) { 41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return x > 255 ? 255 : (x < 0 ? 0 : x); 42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Convert YUV to RGBA 45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// This uses the ITU-R BT.601 coefficients. 46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksstatic inline Rgba convertYuvToRgba(int32 y, int32 u, int32 v) { 47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba color; 48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color.channel[kRed] = clamp(y + static_cast<int>(1.402 * v)); 49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color.channel[kGreen] = clamp(y - static_cast<int>(0.344 * u + 0.714 * v)); 50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color.channel[kBlue] = clamp(y + static_cast<int>(1.772 * u)); 51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color.channel[kAlpha] = 0xFF; 52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return color; 53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Colorspace conversion functions ///////////////////////////////////////////////////////////////// 56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksvoid JNI_COLORSPACE_METHOD(nativeYuv420pToRgba8888)( 57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks JNIEnv* env, jclass clazz, jobject input, jobject output, jint width, jint height) { 58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks uint8* const pInput = static_cast<uint8*>(env->GetDirectBufferAddress(input)); 59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba* const pOutput = static_cast<Rgba*>(env->GetDirectBufferAddress(output)); 60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks const int size = width * height; 62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks uint8* pInY = pInput; 64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks uint8* pInU = pInput + size; 65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks uint8* pInV = pInput + size + size / 4; 66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba* pOutColor = pOutput; 67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (int y = 0; y < height; y += 2) { 69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (int x = 0; x < width; x += 2) { 70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int u, v, y1, y2, y3, y4; 71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks y1 = pInY[0]; 73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks y2 = pInY[1]; 74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks y3 = pInY[width]; 75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks y4 = pInY[width + 1]; 76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks u = *pInU - 128; 78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks v = *pInV - 128; 79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pOutColor[0] = convertYuvToRgba(y1, u, v); 81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pOutColor[1] = convertYuvToRgba(y2, u, v); 82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pOutColor[width] = convertYuvToRgba(y3, u, v); 83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pOutColor[width + 1] = convertYuvToRgba(y4, u, v); 84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pInY += 2; 86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pInU++; 87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pInV++; 88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pOutColor += 2; 89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pInY += width; 91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pOutColor += width; 92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksvoid JNI_COLORSPACE_METHOD(nativeArgb8888ToRgba8888)( 96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks JNIEnv* env, jclass clazz, jobject input, jobject output, jint width, jint height) { 97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba* pInput = static_cast<Rgba*>(env->GetDirectBufferAddress(input)); 98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba* pOutput = static_cast<Rgba*>(env->GetDirectBufferAddress(output)); 99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (int i = 0; i < width * height; ++i) { 101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba color_in = *pInput++; 102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba& color_out = *pOutput++; 103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kRed] = color_in.channel[kGreen]; 104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kGreen] = color_in.channel[kBlue]; 105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kBlue] = color_in.channel[kAlpha]; 106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kAlpha] = color_in.channel[kRed]; 107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksvoid JNI_COLORSPACE_METHOD(nativeRgba8888ToHsva8888)( 111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks JNIEnv* env, jclass clazz, jobject input, jobject output, jint width, jint height) { 112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba* pInput = static_cast<Rgba*>(env->GetDirectBufferAddress(input)); 113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba* pOutput = static_cast<Rgba*>(env->GetDirectBufferAddress(output)); 114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int r, g, b, a, h, s, v, c_max, c_min; 116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float delta; 117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (int i = 0; i < width * height; ++i) { 118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba color_in = *pInput++; 119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba& color_out = *pOutput++; 120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks r = color_in.channel[kRed]; 121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks g = color_in.channel[kGreen]; 122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks b = color_in.channel[kBlue]; 123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks a = color_in.channel[kAlpha]; 124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (r > g) { 126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks c_min = (g > b) ? b : g; 127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks c_max = (r > b) ? r : b; 128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks c_min = (r > b) ? b : r; 130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks c_max = (g > b) ? g : b; 131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks delta = c_max -c_min; 133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float scaler = 255 * 60 / 360.0f; 135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (c_max == r) { 136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks h = (g > b) ? static_cast<int>(scaler * (g - b) / delta) : 137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks static_cast<int>(scaler * ((g - b) / delta + 6)); 138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else if (c_max == g) { 139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks h = static_cast<int>(scaler * ((b - r) / delta + 2)); 140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { // Cmax == b 141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks h = static_cast<int>(scaler * ((r - g) / delta + 4)); 142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks s = (delta == 0.0f) ? 0 : static_cast<unsigned char>(delta / c_max * 255); 144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks v = c_max; 145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kRed] = h; 147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kGreen] = s; 148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kBlue] = v; 149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kAlpha] = a; 150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksvoid JNI_COLORSPACE_METHOD(nativeRgba8888ToYcbcra8888)( 154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks JNIEnv* env, jclass clazz, jobject input, jobject output, jint width, jint height) { 155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba* pInput = static_cast<Rgba*>(env->GetDirectBufferAddress(input)); 156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba* pOutput = static_cast<Rgba*>(env->GetDirectBufferAddress(output)); 157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int r, g, b; 159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (int i = 0; i < width * height; ++i) { 160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba color_in = *pInput++; 161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Rgba& color_out = *pOutput++; 162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks r = color_in.channel[kRed]; 163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks g = color_in.channel[kGreen]; 164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks b = color_in.channel[kBlue]; 165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kRed] = 167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks static_cast<unsigned char>((65.738 * r + 129.057 * g + 25.064 * b) / 256 + 16); 168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kGreen] = 169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks static_cast<unsigned char>((-37.945 * r - 74.494 * g + 112.439 * b) / 256 + 128); 170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kBlue] = 171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks static_cast<unsigned char>((112.439 * r - 94.154 * g - 18.285 * b) / 256 + 128); 172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks color_out.channel[kAlpha] = color_in.channel[kAlpha]; 173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 175