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