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