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