1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "VtsHalEvsTest" 18 19 #include "FormatConvert.h" 20 21 #include <algorithm> // std::min 22 23 24 // Round up to the nearest multiple of the given alignment value 25 template<unsigned alignment> 26 int align(int value) { 27 static_assert((alignment && !(alignment & (alignment - 1))), 28 "alignment must be a power of 2"); 29 30 unsigned mask = alignment - 1; 31 return (value + mask) & ~mask; 32 } 33 34 35 // Limit the given value to the provided range. :) 36 static inline float clamp(float v, float min, float max) { 37 if (v < min) return min; 38 if (v > max) return max; 39 return v; 40 } 41 42 43 static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) { 44 // Don't use this if you want to see the best performance. :) 45 // Better to do this in a pixel shader if we really have to, but on actual 46 // embedded hardware we expect to be able to texture directly from the YUV data 47 float U = Uin - 128.0f; 48 float V = Vin - 128.0f; 49 50 float Rf = Y + 1.140f*V; 51 float Gf = Y - 0.395f*U - 0.581f*V; 52 float Bf = Y + 2.032f*U; 53 unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f); 54 unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f); 55 unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f); 56 57 return (R ) | 58 (G << 8) | 59 (B << 16) | 60 0xFF000000; // Fill the alpha channel with ones 61 } 62 63 64 void copyNV21toRGB32(unsigned width, unsigned height, 65 uint8_t* src, 66 uint32_t* dst, unsigned dstStridePixels) 67 { 68 // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleaved 69 // U/V array. It assumes an even width and height for the overall image, and a horizontal 70 // stride that is an even multiple of 16 bytes for both the Y and UV arrays. 71 unsigned strideLum = align<16>(width); 72 unsigned sizeY = strideLum * height; 73 unsigned strideColor = strideLum; // 1/2 the samples, but two interleaved channels 74 unsigned offsetUV = sizeY; 75 76 uint8_t* srcY = src; 77 uint8_t* srcUV = src+offsetUV; 78 79 for (unsigned r = 0; r < height; r++) { 80 // Note that we're walking the same UV row twice for even/odd luminance rows 81 uint8_t* rowY = srcY + r*strideLum; 82 uint8_t* rowUV = srcUV + (r/2 * strideColor); 83 84 uint32_t* rowDest = dst + r*dstStridePixels; 85 86 for (unsigned c = 0; c < width; c++) { 87 unsigned uCol = (c & ~1); // uCol is always even and repeats 1:2 with Y values 88 unsigned vCol = uCol | 1; // vCol is always odd 89 rowDest[c] = yuvToRgbx(rowY[c], rowUV[uCol], rowUV[vCol]); 90 } 91 } 92 } 93 94 95 void copyYV12toRGB32(unsigned width, unsigned height, 96 uint8_t* src, 97 uint32_t* dst, unsigned dstStridePixels) 98 { 99 // The YV12 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 U array, followed 100 // by another 1/2 x 1/2 V array. It assumes an even width and height for the overall image, 101 // and a horizontal stride that is an even multiple of 16 bytes for each of the Y, U, 102 // and V arrays. 103 unsigned strideLum = align<16>(width); 104 unsigned sizeY = strideLum * height; 105 unsigned strideColor = align<16>(strideLum/2); 106 unsigned sizeColor = strideColor * height/2; 107 unsigned offsetU = sizeY; 108 unsigned offsetV = sizeY + sizeColor; 109 110 uint8_t* srcY = src; 111 uint8_t* srcU = src+offsetU; 112 uint8_t* srcV = src+offsetV; 113 114 for (unsigned r = 0; r < height; r++) { 115 // Note that we're walking the same U and V rows twice for even/odd luminance rows 116 uint8_t* rowY = srcY + r*strideLum; 117 uint8_t* rowU = srcU + (r/2 * strideColor); 118 uint8_t* rowV = srcV + (r/2 * strideColor); 119 120 uint32_t* rowDest = dst + r*dstStridePixels; 121 122 for (unsigned c = 0; c < width; c++) { 123 rowDest[c] = yuvToRgbx(rowY[c], rowU[c], rowV[c]); 124 } 125 } 126 } 127 128 129 void copyYUYVtoRGB32(unsigned width, unsigned height, 130 uint8_t* src, unsigned srcStridePixels, 131 uint32_t* dst, unsigned dstStridePixels) 132 { 133 uint32_t* srcWords = (uint32_t*)src; 134 135 const int srcRowPadding32 = srcStridePixels/2 - width/2; // 2 bytes per pixel, 4 bytes per word 136 const int dstRowPadding32 = dstStridePixels - width; // 4 bytes per pixel, 4 bytes per word 137 138 for (unsigned r = 0; r < height; r++) { 139 for (unsigned c = 0; c < width/2; c++) { 140 // Note: we're walking two pixels at a time here (even/odd) 141 uint32_t srcPixel = *srcWords++; 142 143 uint8_t Y1 = (srcPixel) & 0xFF; 144 uint8_t U = (srcPixel >> 8) & 0xFF; 145 uint8_t Y2 = (srcPixel >> 16) & 0xFF; 146 uint8_t V = (srcPixel >> 24) & 0xFF; 147 148 // On the RGB output, we're writing one pixel at a time 149 *(dst+0) = yuvToRgbx(Y1, U, V); 150 *(dst+1) = yuvToRgbx(Y2, U, V); 151 dst += 2; 152 } 153 154 // Skip over any extra data or end of row alignment padding 155 srcWords += srcRowPadding32; 156 dst += dstRowPadding32; 157 } 158 } 159 160 161 void copyMatchedInterleavedFormats(unsigned width, unsigned height, 162 void* src, unsigned srcStridePixels, 163 void* dst, unsigned dstStridePixels, 164 unsigned pixelSize) { 165 for (unsigned row = 0; row < height; row++) { 166 // Copy the entire row of pixel data 167 memcpy(dst, src, width * pixelSize); 168 169 // Advance to the next row (keeping in mind that stride here is in units of pixels) 170 src = (uint8_t*)src + srcStridePixels * pixelSize; 171 dst = (uint8_t*)dst + dstStridePixels * pixelSize; 172 } 173 } 174