• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 "SoftwareRenderer"
18 #include <utils/Log.h>
19 
20 #include <binder/MemoryHeapBase.h>
21 #include <media/stagefright/MediaDebug.h>
22 #include <media/stagefright/SoftwareRenderer.h>
23 #include <ui/ISurface.h>
24 
25 namespace android {
26 
27 #define QCOM_YUV        0
28 
SoftwareRenderer(OMX_COLOR_FORMATTYPE colorFormat,const sp<ISurface> & surface,size_t displayWidth,size_t displayHeight,size_t decodedWidth,size_t decodedHeight)29 SoftwareRenderer::SoftwareRenderer(
30         OMX_COLOR_FORMATTYPE colorFormat,
31         const sp<ISurface> &surface,
32         size_t displayWidth, size_t displayHeight,
33         size_t decodedWidth, size_t decodedHeight)
34     : mColorFormat(colorFormat),
35       mISurface(surface),
36       mDisplayWidth(displayWidth),
37       mDisplayHeight(displayHeight),
38       mDecodedWidth(decodedWidth),
39       mDecodedHeight(decodedHeight),
40       mFrameSize(mDecodedWidth * mDecodedHeight * 2),  // RGB565
41       mMemoryHeap(new MemoryHeapBase(2 * mFrameSize)),
42       mIndex(0),
43       mClip(NULL) {
44     CHECK(mISurface.get() != NULL);
45     CHECK(mDecodedWidth > 0);
46     CHECK(mDecodedHeight > 0);
47     CHECK(mMemoryHeap->heapID() >= 0);
48 
49     ISurface::BufferHeap bufferHeap(
50             mDisplayWidth, mDisplayHeight,
51             mDecodedWidth, mDecodedHeight,
52             PIXEL_FORMAT_RGB_565,
53             mMemoryHeap);
54 
55     status_t err = mISurface->registerBuffers(bufferHeap);
56     CHECK_EQ(err, OK);
57 }
58 
~SoftwareRenderer()59 SoftwareRenderer::~SoftwareRenderer() {
60     mISurface->unregisterBuffers();
61 
62     delete[] mClip;
63     mClip = NULL;
64 }
65 
render(const void * data,size_t size,void * platformPrivate)66 void SoftwareRenderer::render(
67         const void *data, size_t size, void *platformPrivate) {
68     static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
69 
70     switch (mColorFormat) {
71         case OMX_COLOR_FormatYUV420Planar:
72             return renderYUV420Planar(data, size);
73 
74         case OMX_COLOR_FormatCbYCrY:
75             return renderCbYCrY(data, size);
76 
77         case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
78             return renderQCOMYUV420SemiPlanar(data, size);
79 
80         default:
81         {
82             LOGW("Cannot render color format %d", mColorFormat);
83             break;
84         }
85     }
86 }
87 
renderYUV420Planar(const void * data,size_t size)88 void SoftwareRenderer::renderYUV420Planar(
89         const void *data, size_t size) {
90     if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
91         LOGE("size is %d, expected %d",
92                 size, (mDecodedHeight * mDecodedWidth * 3) / 2);
93     }
94     CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
95 
96     uint8_t *kAdjustedClip = initClip();
97 
98     size_t offset = mIndex * mFrameSize;
99 
100     void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
101 
102     uint32_t *dst_ptr = (uint32_t *)dst;
103 
104     const uint8_t *src_y = (const uint8_t *)data;
105 
106     const uint8_t *src_u =
107         (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
108 
109 #if !QCOM_YUV
110     const uint8_t *src_v =
111         (const uint8_t *)src_u + (mDecodedWidth / 2) * (mDecodedHeight / 2);
112 #endif
113 
114     for (size_t y = 0; y < mDecodedHeight; ++y) {
115         for (size_t x = 0; x < mDecodedWidth; x += 2) {
116             // B = 1.164 * (Y - 16) + 2.018 * (U - 128)
117             // G = 1.164 * (Y - 16) - 0.813 * (V - 128) - 0.391 * (U - 128)
118             // R = 1.164 * (Y - 16) + 1.596 * (V - 128)
119 
120             // B = 298/256 * (Y - 16) + 517/256 * (U - 128)
121             // G = .................. - 208/256 * (V - 128) - 100/256 * (U - 128)
122             // R = .................. + 409/256 * (V - 128)
123 
124             // min_B = (298 * (- 16) + 517 * (- 128)) / 256 = -277
125             // min_G = (298 * (- 16) - 208 * (255 - 128) - 100 * (255 - 128)) / 256 = -172
126             // min_R = (298 * (- 16) + 409 * (- 128)) / 256 = -223
127 
128             // max_B = (298 * (255 - 16) + 517 * (255 - 128)) / 256 = 534
129             // max_G = (298 * (255 - 16) - 208 * (- 128) - 100 * (- 128)) / 256 = 432
130             // max_R = (298 * (255 - 16) + 409 * (255 - 128)) / 256 = 481
131 
132             // clip range -278 .. 535
133 
134             signed y1 = (signed)src_y[x] - 16;
135             signed y2 = (signed)src_y[x + 1] - 16;
136 
137 #if QCOM_YUV
138             signed u = (signed)src_u[x & ~1] - 128;
139             signed v = (signed)src_u[(x & ~1) + 1] - 128;
140 #else
141             signed u = (signed)src_u[x / 2] - 128;
142             signed v = (signed)src_v[x / 2] - 128;
143 #endif
144 
145             signed u_b = u * 517;
146             signed u_g = -u * 100;
147             signed v_g = -v * 208;
148             signed v_r = v * 409;
149 
150             signed tmp1 = y1 * 298;
151             signed b1 = (tmp1 + u_b) / 256;
152             signed g1 = (tmp1 + v_g + u_g) / 256;
153             signed r1 = (tmp1 + v_r) / 256;
154 
155             signed tmp2 = y2 * 298;
156             signed b2 = (tmp2 + u_b) / 256;
157             signed g2 = (tmp2 + v_g + u_g) / 256;
158             signed r2 = (tmp2 + v_r) / 256;
159 
160             uint32_t rgb1 =
161                 ((kAdjustedClip[r1] >> 3) << 11)
162                 | ((kAdjustedClip[g1] >> 2) << 5)
163                 | (kAdjustedClip[b1] >> 3);
164 
165             uint32_t rgb2 =
166                 ((kAdjustedClip[r2] >> 3) << 11)
167                 | ((kAdjustedClip[g2] >> 2) << 5)
168                 | (kAdjustedClip[b2] >> 3);
169 
170             dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
171         }
172 
173         src_y += mDecodedWidth;
174 
175         if (y & 1) {
176 #if QCOM_YUV
177             src_u += mDecodedWidth;
178 #else
179             src_u += mDecodedWidth / 2;
180             src_v += mDecodedWidth / 2;
181 #endif
182         }
183 
184         dst_ptr += mDecodedWidth / 2;
185     }
186 
187     mISurface->postBuffer(offset);
188     mIndex = 1 - mIndex;
189 }
190 
renderCbYCrY(const void * data,size_t size)191 void SoftwareRenderer::renderCbYCrY(
192         const void *data, size_t size) {
193     if (size != (mDecodedHeight * mDecodedWidth * 2)) {
194         LOGE("size is %d, expected %d",
195                 size, (mDecodedHeight * mDecodedWidth * 2));
196     }
197     CHECK(size >= (mDecodedWidth * mDecodedHeight * 2));
198 
199     uint8_t *kAdjustedClip = initClip();
200 
201     size_t offset = mIndex * mFrameSize;
202     void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
203     uint32_t *dst_ptr = (uint32_t *)dst;
204 
205     const uint8_t *src = (const uint8_t *)data;
206 
207     for (size_t y = 0; y < mDecodedHeight; ++y) {
208         for (size_t x = 0; x < mDecodedWidth; x += 2) {
209             signed y1 = (signed)src[2 * x + 1] - 16;
210             signed y2 = (signed)src[2 * x + 3] - 16;
211             signed u = (signed)src[2 * x] - 128;
212             signed v = (signed)src[2 * x + 2] - 128;
213 
214             signed u_b = u * 517;
215             signed u_g = -u * 100;
216             signed v_g = -v * 208;
217             signed v_r = v * 409;
218 
219             signed tmp1 = y1 * 298;
220             signed b1 = (tmp1 + u_b) / 256;
221             signed g1 = (tmp1 + v_g + u_g) / 256;
222             signed r1 = (tmp1 + v_r) / 256;
223 
224             signed tmp2 = y2 * 298;
225             signed b2 = (tmp2 + u_b) / 256;
226             signed g2 = (tmp2 + v_g + u_g) / 256;
227             signed r2 = (tmp2 + v_r) / 256;
228 
229             uint32_t rgb1 =
230                 ((kAdjustedClip[r1] >> 3) << 11)
231                 | ((kAdjustedClip[g1] >> 2) << 5)
232                 | (kAdjustedClip[b1] >> 3);
233 
234             uint32_t rgb2 =
235                 ((kAdjustedClip[r2] >> 3) << 11)
236                 | ((kAdjustedClip[g2] >> 2) << 5)
237                 | (kAdjustedClip[b2] >> 3);
238 
239             dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
240         }
241 
242         src += mDecodedWidth * 2;
243         dst_ptr += mDecodedWidth / 2;
244     }
245 
246     mISurface->postBuffer(offset);
247     mIndex = 1 - mIndex;
248 }
249 
renderQCOMYUV420SemiPlanar(const void * data,size_t size)250 void SoftwareRenderer::renderQCOMYUV420SemiPlanar(
251         const void *data, size_t size) {
252     if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
253         LOGE("size is %d, expected %d",
254                 size, (mDecodedHeight * mDecodedWidth * 3) / 2);
255     }
256     CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
257 
258     uint8_t *kAdjustedClip = initClip();
259 
260     size_t offset = mIndex * mFrameSize;
261 
262     void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
263 
264     uint32_t *dst_ptr = (uint32_t *)dst;
265 
266     const uint8_t *src_y = (const uint8_t *)data;
267 
268     const uint8_t *src_u =
269         (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
270 
271     for (size_t y = 0; y < mDecodedHeight; ++y) {
272         for (size_t x = 0; x < mDecodedWidth; x += 2) {
273             signed y1 = (signed)src_y[x] - 16;
274             signed y2 = (signed)src_y[x + 1] - 16;
275 
276             signed u = (signed)src_u[x & ~1] - 128;
277             signed v = (signed)src_u[(x & ~1) + 1] - 128;
278 
279             signed u_b = u * 517;
280             signed u_g = -u * 100;
281             signed v_g = -v * 208;
282             signed v_r = v * 409;
283 
284             signed tmp1 = y1 * 298;
285             signed b1 = (tmp1 + u_b) / 256;
286             signed g1 = (tmp1 + v_g + u_g) / 256;
287             signed r1 = (tmp1 + v_r) / 256;
288 
289             signed tmp2 = y2 * 298;
290             signed b2 = (tmp2 + u_b) / 256;
291             signed g2 = (tmp2 + v_g + u_g) / 256;
292             signed r2 = (tmp2 + v_r) / 256;
293 
294             uint32_t rgb1 =
295                 ((kAdjustedClip[b1] >> 3) << 11)
296                 | ((kAdjustedClip[g1] >> 2) << 5)
297                 | (kAdjustedClip[r1] >> 3);
298 
299             uint32_t rgb2 =
300                 ((kAdjustedClip[b2] >> 3) << 11)
301                 | ((kAdjustedClip[g2] >> 2) << 5)
302                 | (kAdjustedClip[r2] >> 3);
303 
304             dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
305         }
306 
307         src_y += mDecodedWidth;
308 
309         if (y & 1) {
310             src_u += mDecodedWidth;
311         }
312 
313         dst_ptr += mDecodedWidth / 2;
314     }
315 
316     mISurface->postBuffer(offset);
317     mIndex = 1 - mIndex;
318 }
319 
initClip()320 uint8_t *SoftwareRenderer::initClip() {
321     static const signed kClipMin = -278;
322     static const signed kClipMax = 535;
323 
324     if (mClip == NULL) {
325         mClip = new uint8_t[kClipMax - kClipMin + 1];
326 
327         for (signed i = kClipMin; i <= kClipMax; ++i) {
328             mClip[i - kClipMin] = (i < 0) ? 0 : (i > 255) ? 255 : (uint8_t)i;
329         }
330     }
331 
332     return &mClip[-kClipMin];
333 }
334 
335 }  // namespace android
336