1 /*
2  * Copyright (C) 2016 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 "bufferCopy.h"
18 
19 
20 namespace android {
21 namespace hardware {
22 namespace automotive {
23 namespace evs {
24 namespace V1_0 {
25 namespace implementation {
26 
27 
28 // Round up to the nearest multiple of the given alignment value
29 template<unsigned alignment>
align(int value)30 int align(int value) {
31     static_assert((alignment && !(alignment & (alignment - 1))),
32                   "alignment must be a power of 2");
33 
34     unsigned mask = alignment - 1;
35     return (value + mask) & ~mask;
36 }
37 
38 
39 // Limit the given value to the provided range.  :)
clamp(float v,float min,float max)40 static inline float clamp(float v, float min, float max) {
41     if (v < min) return min;
42     if (v > max) return max;
43     return v;
44 }
45 
46 
yuvToRgbx(const unsigned char Y,const unsigned char Uin,const unsigned char Vin)47 static uint32_t yuvToRgbx(const unsigned char Y, const unsigned char Uin, const unsigned char Vin) {
48     // Don't use this if you want to see the best performance.  :)
49     // Better to do this in a pixel shader if we really have to, but on actual
50     // embedded hardware we expect to be able to texture directly from the YUV data
51     float U = Uin - 128.0f;
52     float V = Vin - 128.0f;
53 
54     float Rf = Y + 1.140f*V;
55     float Gf = Y - 0.395f*U - 0.581f*V;
56     float Bf = Y + 2.032f*U;
57     unsigned char R = (unsigned char)clamp(Rf, 0.0f, 255.0f);
58     unsigned char G = (unsigned char)clamp(Gf, 0.0f, 255.0f);
59     unsigned char B = (unsigned char)clamp(Bf, 0.0f, 255.0f);
60 
61     return ((R & 0xFF))       |
62            ((G & 0xFF) << 8)  |
63            ((B & 0xFF) << 16) |
64            0xFF000000;  // Fill the alpha channel with ones
65 }
66 
67 
fillNV21FromNV21(const BufferDesc & tgtBuff,uint8_t * tgt,void * imgData,unsigned)68 void fillNV21FromNV21(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned) {
69     // The NV21 format provides a Y array of 8bit values, followed by a 1/2 x 1/2 interleave U/V array.
70     // It assumes an even width and height for the overall image, and a horizontal stride that is
71     // an even multiple of 16 bytes for both the Y and UV arrays.
72 
73     // Target  and source image layout properties (They match since the formats match!)
74     const unsigned strideLum = align<16>(tgtBuff.width);
75     const unsigned sizeY = strideLum * tgtBuff.height;
76     const unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
77     const unsigned sizeColor = strideColor * tgtBuff.height/2;
78     const unsigned totalBytes = sizeY + sizeColor;
79 
80     // Simply copy the data byte for byte
81     memcpy(tgt, imgData, totalBytes);
82 }
83 
84 
fillNV21FromYUYV(const BufferDesc & tgtBuff,uint8_t * tgt,void * imgData,unsigned imgStride)85 void fillNV21FromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
86     // The YUYV format provides an interleaved array of pixel values with U and V subsampled in
87     // the horizontal direction only.  Also known as interleaved 422 format.  A 4 byte
88     // "macro pixel" provides the Y value for two adjacent pixels and the U and V values shared
89     // between those two pixels.  The width of the image must be an even number.
90     // We need to down sample the UV values and collect them together after all the packed Y values
91     // to construct the NV21 format.
92     // NV21 requires even width and height, so we assume that is the case for the incomming image
93     // as well.
94     uint32_t *srcDataYUYV = (uint32_t*)imgData;
95     struct YUYVpixel {
96         uint8_t Y1;
97         uint8_t U;
98         uint8_t Y2;
99         uint8_t V;
100     };
101 
102     // Target image layout properties
103     const unsigned strideLum = align<16>(tgtBuff.width);
104     const unsigned sizeY = strideLum * tgtBuff.height;
105     const unsigned strideColor = strideLum;   // 1/2 the samples, but two interleaved channels
106 
107     // Source image layout properties
108     const unsigned srcRowPixels = imgStride/4;  // imgStride is in units of bytes
109     const unsigned srcRowDoubleStep = srcRowPixels * 2;
110     uint32_t* topSrcRow =  srcDataYUYV;
111     uint32_t* botSrcRow =  srcDataYUYV + srcRowPixels;
112 
113     // We're going to work on one 2x2 cell in the output image at at time
114     for (unsigned cellRow = 0; cellRow < tgtBuff.height/2; cellRow++) {
115 
116         // Set up the output pointers
117         uint8_t* yTopRow = tgt + (cellRow*2) * strideLum;
118         uint8_t* yBotRow = yTopRow + strideLum;
119         uint8_t* uvRow   = (tgt + sizeY) + cellRow * strideColor;
120 
121         for (unsigned cellCol = 0; cellCol < tgtBuff.width/2; cellCol++) {
122             // Collect the values from the YUYV interleaved data
123             const YUYVpixel* pTopMacroPixel = (YUYVpixel*)&topSrcRow[cellCol];
124             const YUYVpixel* pBotMacroPixel = (YUYVpixel*)&botSrcRow[cellCol];
125 
126             // Down sample the U/V values by linear average between rows
127             const uint8_t uValue = (pTopMacroPixel->U + pBotMacroPixel->U) >> 1;
128             const uint8_t vValue = (pTopMacroPixel->V + pBotMacroPixel->V) >> 1;
129 
130             // Store the values into the NV21 layout
131             yTopRow[cellCol*2]   = pTopMacroPixel->Y1;
132             yTopRow[cellCol*2+1] = pTopMacroPixel->Y2;
133             yBotRow[cellCol*2]   = pBotMacroPixel->Y1;
134             yBotRow[cellCol*2+1] = pBotMacroPixel->Y2;
135             uvRow[cellCol*2]     = uValue;
136             uvRow[cellCol*2+1]   = vValue;
137         }
138 
139         // Skipping two rows to get to the next set of two source rows
140         topSrcRow += srcRowDoubleStep;
141         botSrcRow += srcRowDoubleStep;
142     }
143 }
144 
145 
fillRGBAFromYUYV(const BufferDesc & tgtBuff,uint8_t * tgt,void * imgData,unsigned imgStride)146 void fillRGBAFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
147     unsigned width = tgtBuff.width;
148     unsigned height = tgtBuff.height;
149     uint32_t* src = (uint32_t*)imgData;
150     uint32_t* dst = (uint32_t*)tgt;
151     unsigned srcStridePixels = imgStride / 2;
152     unsigned dstStridePixels = tgtBuff.stride;
153 
154     const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
155     const int dstRowPadding32 = dstStridePixels   - width;    // 4 bytes per pixel, 4 bytes per word
156 
157     for (unsigned r=0; r<height; r++) {
158         for (unsigned c=0; c<width/2; c++) {
159             // Note:  we're walking two pixels at a time here (even/odd)
160             uint32_t srcPixel = *src++;
161 
162             uint8_t Y1 = (srcPixel)       & 0xFF;
163             uint8_t U  = (srcPixel >> 8)  & 0xFF;
164             uint8_t Y2 = (srcPixel >> 16) & 0xFF;
165             uint8_t V  = (srcPixel >> 24) & 0xFF;
166 
167             // On the RGB output, we're writing one pixel at a time
168             *(dst+0) = yuvToRgbx(Y1, U, V);
169             *(dst+1) = yuvToRgbx(Y2, U, V);
170             dst += 2;
171         }
172 
173         // Skip over any extra data or end of row alignment padding
174         src += srcRowPadding32;
175         dst += dstRowPadding32;
176     }
177 }
178 
179 
fillYUYVFromYUYV(const BufferDesc & tgtBuff,uint8_t * tgt,void * imgData,unsigned imgStride)180 void fillYUYVFromYUYV(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
181     unsigned width = tgtBuff.width;
182     unsigned height = tgtBuff.height;
183     uint8_t* src = (uint8_t*)imgData;
184     uint8_t* dst = (uint8_t*)tgt;
185     unsigned srcStrideBytes = imgStride;
186     unsigned dstStrideBytes = tgtBuff.stride * 2;
187 
188     for (unsigned r=0; r<height; r++) {
189         // Copy a pixel row at a time (2 bytes per pixel, averaged over a YUYV macro pixel)
190         memcpy(dst+r*dstStrideBytes, src+r*srcStrideBytes, width*2);
191     }
192 }
193 
194 
fillYUYVFromUYVY(const BufferDesc & tgtBuff,uint8_t * tgt,void * imgData,unsigned imgStride)195 void fillYUYVFromUYVY(const BufferDesc& tgtBuff, uint8_t* tgt, void* imgData, unsigned imgStride) {
196     unsigned width = tgtBuff.width;
197     unsigned height = tgtBuff.height;
198     uint32_t* src = (uint32_t*)imgData;
199     uint32_t* dst = (uint32_t*)tgt;
200     unsigned srcStridePixels = imgStride / 2;
201     unsigned dstStridePixels = tgtBuff.stride;
202 
203     const int srcRowPadding32 = srcStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
204     const int dstRowPadding32 = dstStridePixels/2 - width/2;  // 2 bytes per pixel, 4 bytes per word
205 
206     for (unsigned r=0; r<height; r++) {
207         for (unsigned c=0; c<width/2; c++) {
208             // Note:  we're walking two pixels at a time here (even/odd)
209             uint32_t srcPixel = *src++;
210 
211             uint8_t Y1 = (srcPixel)       & 0xFF;
212             uint8_t U  = (srcPixel >> 8)  & 0xFF;
213             uint8_t Y2 = (srcPixel >> 16) & 0xFF;
214             uint8_t V  = (srcPixel >> 24) & 0xFF;
215 
216             // Now we write back the pair of pixels with the components swizzled
217             *dst++ = (U)        |
218                      (Y1 << 8)  |
219                      (V  << 16) |
220                      (Y2 << 24);
221         }
222 
223         // Skip over any extra data or end of row alignment padding
224         src += srcRowPadding32;
225         dst += dstRowPadding32;
226     }
227 }
228 
229 
230 } // namespace implementation
231 } // namespace V1_0
232 } // namespace evs
233 } // namespace automotive
234 } // namespace hardware
235 } // namespace android
236