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 "../include/SoftwareRenderer.h"
21 
22 #include <cutils/properties.h> // for property_get
23 #include <media/stagefright/foundation/ADebug.h>
24 #include <media/stagefright/foundation/AMessage.h>
25 #include <system/window.h>
26 #include <ui/Fence.h>
27 #include <ui/GraphicBufferMapper.h>
28 #include <ui/GraphicBuffer.h>
29 #include <ui/Rect.h>
30 
31 namespace android {
32 
runningInEmulator()33 static bool runningInEmulator() {
34     char prop[PROPERTY_VALUE_MAX];
35     return (property_get("ro.kernel.qemu", prop, NULL) > 0);
36 }
37 
ALIGN(int x,int y)38 static int ALIGN(int x, int y) {
39     // y must be a power of 2.
40     return (x + y - 1) & ~(y - 1);
41 }
42 
SoftwareRenderer(const sp<ANativeWindow> & nativeWindow,int32_t rotation)43 SoftwareRenderer::SoftwareRenderer(
44         const sp<ANativeWindow> &nativeWindow, int32_t rotation)
45     : mColorFormat(OMX_COLOR_FormatUnused),
46       mConverter(NULL),
47       mYUVMode(None),
48       mNativeWindow(nativeWindow),
49       mWidth(0),
50       mHeight(0),
51       mCropLeft(0),
52       mCropTop(0),
53       mCropRight(0),
54       mCropBottom(0),
55       mCropWidth(0),
56       mCropHeight(0),
57       mRotationDegrees(rotation) {
58 }
59 
~SoftwareRenderer()60 SoftwareRenderer::~SoftwareRenderer() {
61     delete mConverter;
62     mConverter = NULL;
63 }
64 
resetFormatIfChanged(const sp<AMessage> & format)65 void SoftwareRenderer::resetFormatIfChanged(const sp<AMessage> &format) {
66     CHECK(format != NULL);
67 
68     int32_t colorFormatNew;
69     CHECK(format->findInt32("color-format", &colorFormatNew));
70 
71     int32_t widthNew, heightNew;
72     CHECK(format->findInt32("stride", &widthNew));
73     CHECK(format->findInt32("slice-height", &heightNew));
74 
75     int32_t cropLeftNew, cropTopNew, cropRightNew, cropBottomNew;
76     if (!format->findRect(
77             "crop", &cropLeftNew, &cropTopNew, &cropRightNew, &cropBottomNew)) {
78         cropLeftNew = cropTopNew = 0;
79         cropRightNew = widthNew - 1;
80         cropBottomNew = heightNew - 1;
81     }
82 
83     if (static_cast<int32_t>(mColorFormat) == colorFormatNew &&
84         mWidth == widthNew &&
85         mHeight == heightNew &&
86         mCropLeft == cropLeftNew &&
87         mCropTop == cropTopNew &&
88         mCropRight == cropRightNew &&
89         mCropBottom == cropBottomNew) {
90         // Nothing changed, no need to reset renderer.
91         return;
92     }
93 
94     mColorFormat = static_cast<OMX_COLOR_FORMATTYPE>(colorFormatNew);
95     mWidth = widthNew;
96     mHeight = heightNew;
97     mCropLeft = cropLeftNew;
98     mCropTop = cropTopNew;
99     mCropRight = cropRightNew;
100     mCropBottom = cropBottomNew;
101 
102     mCropWidth = mCropRight - mCropLeft + 1;
103     mCropHeight = mCropBottom - mCropTop + 1;
104 
105     // by default convert everything to RGB565
106     int halFormat = HAL_PIXEL_FORMAT_RGB_565;
107     size_t bufWidth = mCropWidth;
108     size_t bufHeight = mCropHeight;
109 
110     // hardware has YUV12 and RGBA8888 support, so convert known formats
111     if (!runningInEmulator()) {
112         switch (mColorFormat) {
113             case OMX_COLOR_FormatYUV420Planar:
114             case OMX_COLOR_FormatYUV420SemiPlanar:
115             case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
116             {
117                 halFormat = HAL_PIXEL_FORMAT_YV12;
118                 bufWidth = (mCropWidth + 1) & ~1;
119                 bufHeight = (mCropHeight + 1) & ~1;
120                 break;
121             }
122             case OMX_COLOR_Format24bitRGB888:
123             {
124                 halFormat = HAL_PIXEL_FORMAT_RGB_888;
125                 bufWidth = (mCropWidth + 1) & ~1;
126                 bufHeight = (mCropHeight + 1) & ~1;
127                 break;
128             }
129             case OMX_COLOR_Format32bitARGB8888:
130             case OMX_COLOR_Format32BitRGBA8888:
131             {
132                 halFormat = HAL_PIXEL_FORMAT_RGBA_8888;
133                 bufWidth = (mCropWidth + 1) & ~1;
134                 bufHeight = (mCropHeight + 1) & ~1;
135                 break;
136             }
137             default:
138             {
139                 break;
140             }
141         }
142     }
143 
144     if (halFormat == HAL_PIXEL_FORMAT_RGB_565) {
145         mConverter = new ColorConverter(
146                 mColorFormat, OMX_COLOR_Format16bitRGB565);
147         CHECK(mConverter->isValid());
148     }
149 
150     CHECK(mNativeWindow != NULL);
151     CHECK(mCropWidth > 0);
152     CHECK(mCropHeight > 0);
153     CHECK(mConverter == NULL || mConverter->isValid());
154 
155     CHECK_EQ(0,
156             native_window_set_usage(
157             mNativeWindow.get(),
158             GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
159             | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
160 
161     CHECK_EQ(0,
162             native_window_set_scaling_mode(
163             mNativeWindow.get(),
164             NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
165 
166     // Width must be multiple of 32???
167     CHECK_EQ(0, native_window_set_buffers_dimensions(
168                 mNativeWindow.get(),
169                 bufWidth,
170                 bufHeight));
171     CHECK_EQ(0, native_window_set_buffers_format(
172                 mNativeWindow.get(),
173                 halFormat));
174 
175     // NOTE: native window uses extended right-bottom coordinate
176     android_native_rect_t crop;
177     crop.left = mCropLeft;
178     crop.top = mCropTop;
179     crop.right = mCropRight + 1;
180     crop.bottom = mCropBottom + 1;
181     ALOGV("setting crop: [%d, %d, %d, %d] for size [%zu, %zu]",
182           crop.left, crop.top, crop.right, crop.bottom, bufWidth, bufHeight);
183 
184     CHECK_EQ(0, native_window_set_crop(mNativeWindow.get(), &crop));
185 
186     int32_t rotationDegrees;
187     if (!format->findInt32("rotation-degrees", &rotationDegrees)) {
188         rotationDegrees = mRotationDegrees;
189     }
190     uint32_t transform;
191     switch (rotationDegrees) {
192         case 0: transform = 0; break;
193         case 90: transform = HAL_TRANSFORM_ROT_90; break;
194         case 180: transform = HAL_TRANSFORM_ROT_180; break;
195         case 270: transform = HAL_TRANSFORM_ROT_270; break;
196         default: transform = 0; break;
197     }
198 
199     CHECK_EQ(0, native_window_set_buffers_transform(
200                 mNativeWindow.get(), transform));
201 }
202 
clearTracker()203 void SoftwareRenderer::clearTracker() {
204     mRenderTracker.clear(-1 /* lastRenderTimeNs */);
205 }
206 
render(const void * data,size_t size,int64_t mediaTimeUs,nsecs_t renderTimeNs,void *,const sp<AMessage> & format)207 std::list<FrameRenderTracker::Info> SoftwareRenderer::render(
208         const void *data, size_t size, int64_t mediaTimeUs, nsecs_t renderTimeNs,
209         void* /*platformPrivate*/, const sp<AMessage>& format) {
210     resetFormatIfChanged(format);
211     FrameRenderTracker::Info *info = NULL;
212 
213     ANativeWindowBuffer *buf;
214     int fenceFd = -1;
215     int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd);
216     if (err == 0 && fenceFd >= 0) {
217         info = mRenderTracker.updateInfoForDequeuedBuffer(buf, fenceFd, 0);
218         sp<Fence> fence = new Fence(fenceFd);
219         err = fence->waitForever("SoftwareRenderer::render");
220     }
221     if (err != 0) {
222         ALOGW("Surface::dequeueBuffer returned error %d", err);
223         // complete (drop) dequeued frame if fence wait failed; otherwise,
224         // this returns an empty list as no frames should have rendered and not yet returned.
225         return mRenderTracker.checkFencesAndGetRenderedFrames(info, false /* dropIncomplete */);
226     }
227 
228     GraphicBufferMapper &mapper = GraphicBufferMapper::get();
229 
230     Rect bounds(mCropWidth, mCropHeight);
231 
232     void *dst;
233     CHECK_EQ(0, mapper.lock(
234                 buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
235 
236     // TODO move the other conversions also into ColorConverter, and
237     // fix cropping issues (when mCropLeft/Top != 0 or mWidth != mCropWidth)
238     if (mConverter) {
239         mConverter->convert(
240                 data,
241                 mWidth, mHeight,
242                 mCropLeft, mCropTop, mCropRight, mCropBottom,
243                 dst,
244                 buf->stride, buf->height,
245                 0, 0, mCropWidth - 1, mCropHeight - 1);
246     } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
247         if ((size_t)mWidth * mHeight * 3 / 2 > size) {
248             goto skip_copying;
249         }
250         const uint8_t *src_y = (const uint8_t *)data;
251         const uint8_t *src_u =
252                 (const uint8_t *)data + mWidth * mHeight;
253         const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
254 
255         uint8_t *dst_y = (uint8_t *)dst;
256         size_t dst_y_size = buf->stride * buf->height;
257         size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
258         size_t dst_c_size = dst_c_stride * buf->height / 2;
259         uint8_t *dst_v = dst_y + dst_y_size;
260         uint8_t *dst_u = dst_v + dst_c_size;
261 
262         for (int y = 0; y < mCropHeight; ++y) {
263             memcpy(dst_y, src_y, mCropWidth);
264 
265             src_y += mWidth;
266             dst_y += buf->stride;
267         }
268 
269         for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
270             memcpy(dst_u, src_u, (mCropWidth + 1) / 2);
271             memcpy(dst_v, src_v, (mCropWidth + 1) / 2);
272 
273             src_u += mWidth / 2;
274             src_v += mWidth / 2;
275             dst_u += dst_c_stride;
276             dst_v += dst_c_stride;
277         }
278     } else if (mColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar
279             || mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
280         if ((size_t)mWidth * mHeight * 3 / 2 > size) {
281             goto skip_copying;
282         }
283         const uint8_t *src_y = (const uint8_t *)data;
284         const uint8_t *src_uv = (const uint8_t *)data
285                 + mWidth * (mHeight - mCropTop / 2);
286 
287         uint8_t *dst_y = (uint8_t *)dst;
288 
289         size_t dst_y_size = buf->stride * buf->height;
290         size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
291         size_t dst_c_size = dst_c_stride * buf->height / 2;
292         uint8_t *dst_v = dst_y + dst_y_size;
293         uint8_t *dst_u = dst_v + dst_c_size;
294 
295         for (int y = 0; y < mCropHeight; ++y) {
296             memcpy(dst_y, src_y, mCropWidth);
297 
298             src_y += mWidth;
299             dst_y += buf->stride;
300         }
301 
302         for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
303             size_t tmp = (mCropWidth + 1) / 2;
304             for (size_t x = 0; x < tmp; ++x) {
305                 dst_u[x] = src_uv[2 * x];
306                 dst_v[x] = src_uv[2 * x + 1];
307             }
308 
309             src_uv += mWidth;
310             dst_u += dst_c_stride;
311             dst_v += dst_c_stride;
312         }
313     } else if (mColorFormat == OMX_COLOR_Format24bitRGB888) {
314         if ((size_t)mWidth * mHeight * 3 > size) {
315             goto skip_copying;
316         }
317         uint8_t* srcPtr = (uint8_t*)data;
318         uint8_t* dstPtr = (uint8_t*)dst;
319 
320         for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
321             memcpy(dstPtr, srcPtr, mCropWidth * 3);
322             srcPtr += mWidth * 3;
323             dstPtr += buf->stride * 3;
324         }
325     } else if (mColorFormat == OMX_COLOR_Format32bitARGB8888) {
326         if ((size_t)mWidth * mHeight * 4 > size) {
327             goto skip_copying;
328         }
329         uint8_t *srcPtr, *dstPtr;
330 
331         for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
332             srcPtr = (uint8_t*)data + mWidth * 4 * y;
333             dstPtr = (uint8_t*)dst + buf->stride * 4 * y;
334             for (size_t x = 0; x < (size_t)mCropWidth; ++x) {
335                 uint8_t a = *srcPtr++;
336                 for (size_t i = 0; i < 3; ++i) {   // copy RGB
337                     *dstPtr++ = *srcPtr++;
338                 }
339                 *dstPtr++ = a;  // alpha last (ARGB to RGBA)
340             }
341         }
342     } else if (mColorFormat == OMX_COLOR_Format32BitRGBA8888) {
343         if ((size_t)mWidth * mHeight * 4 > size) {
344             goto skip_copying;
345         }
346         uint8_t* srcPtr = (uint8_t*)data;
347         uint8_t* dstPtr = (uint8_t*)dst;
348 
349         for (size_t y = 0; y < (size_t)mCropHeight; ++y) {
350             memcpy(dstPtr, srcPtr, mCropWidth * 4);
351             srcPtr += mWidth * 4;
352             dstPtr += buf->stride * 4;
353         }
354     } else {
355         LOG_ALWAYS_FATAL("bad color format %#x", mColorFormat);
356     }
357 
358 skip_copying:
359     CHECK_EQ(0, mapper.unlock(buf->handle));
360 
361     if (renderTimeNs >= 0) {
362         if ((err = native_window_set_buffers_timestamp(mNativeWindow.get(),
363                 renderTimeNs)) != 0) {
364             ALOGW("Surface::set_buffers_timestamp returned error %d", err);
365         }
366     }
367 
368     // TODO: propagate color aspects to software renderer to allow better
369     // color conversion to RGB. For now, just mark dataspace for YUV rendering.
370     android_dataspace dataSpace;
371     if (format->findInt32("android._dataspace", (int32_t *)&dataSpace) && dataSpace != mDataSpace) {
372         ALOGD("setting dataspace on output surface to #%x", dataSpace);
373         if ((err = native_window_set_buffers_data_space(mNativeWindow.get(), dataSpace))) {
374             ALOGW("failed to set dataspace on surface (%d)", err);
375         }
376         mDataSpace = dataSpace;
377     }
378     if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf, -1)) != 0) {
379         ALOGW("Surface::queueBuffer returned error %d", err);
380     } else {
381         mRenderTracker.onFrameQueued(mediaTimeUs, (GraphicBuffer *)buf, Fence::NO_FENCE);
382     }
383 
384     buf = NULL;
385     return mRenderTracker.checkFencesAndGetRenderedFrames(info, info != NULL /* dropIncomplete */);
386 }
387 
388 }  // namespace android
389