SoftwareRenderer.cpp revision 3571d50a2582bc9c63f09cd81b4f490ea3522bd9
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 <binder/MemoryHeapBase.h>
23#include <binder/MemoryHeapPmem.h>
24#include <media/stagefright/foundation/ADebug.h>
25#include <media/stagefright/MetaData.h>
26#include <surfaceflinger/Surface.h>
27#include <ui/android_native_buffer.h>
28#include <ui/GraphicBufferMapper.h>
29#include <gui/ISurfaceTexture.h>
30
31namespace android {
32
33SoftwareRenderer::SoftwareRenderer(
34        const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
35    : mConverter(NULL),
36      mYUVMode(None),
37      mNativeWindow(nativeWindow) {
38    int32_t tmp;
39    CHECK(meta->findInt32(kKeyColorFormat, &tmp));
40    mColorFormat = (OMX_COLOR_FORMATTYPE)tmp;
41
42    CHECK(meta->findInt32(kKeyWidth, &mWidth));
43    CHECK(meta->findInt32(kKeyHeight, &mHeight));
44
45    if (!meta->findRect(
46                kKeyCropRect,
47                &mCropLeft, &mCropTop, &mCropRight, &mCropBottom)) {
48        mCropLeft = mCropTop = 0;
49        mCropRight = mWidth - 1;
50        mCropBottom = mHeight - 1;
51    }
52
53    mCropWidth = mCropRight - mCropLeft + 1;
54    mCropHeight = mCropBottom - mCropTop + 1;
55
56    int32_t rotationDegrees;
57    if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
58        rotationDegrees = 0;
59    }
60
61    int halFormat;
62    size_t bufWidth, bufHeight;
63
64    switch (mColorFormat) {
65        case OMX_COLOR_FormatYUV420Planar:
66        case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar:
67        {
68            halFormat = HAL_PIXEL_FORMAT_YV12;
69            bufWidth = (mCropWidth + 1) & ~1;
70            bufHeight = (mCropHeight + 1) & ~1;
71            break;
72        }
73
74        default:
75            halFormat = HAL_PIXEL_FORMAT_RGB_565;
76            bufWidth = mCropWidth;
77            bufHeight = mCropHeight;
78
79            mConverter = new ColorConverter(
80                    mColorFormat, OMX_COLOR_Format16bitRGB565);
81            CHECK(mConverter->isValid());
82            break;
83    }
84
85    CHECK(mNativeWindow != NULL);
86    CHECK(mCropWidth > 0);
87    CHECK(mCropHeight > 0);
88    CHECK(mConverter == NULL || mConverter->isValid());
89
90    CHECK_EQ(0,
91            native_window_set_usage(
92            mNativeWindow.get(),
93            GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
94            | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
95
96    // Width must be multiple of 32???
97    CHECK_EQ(0, native_window_set_buffers_geometry(
98                mNativeWindow.get(),
99                bufWidth,
100                bufHeight,
101                halFormat));
102
103    uint32_t transform;
104    switch (rotationDegrees) {
105        case 0: transform = 0; break;
106        case 90: transform = HAL_TRANSFORM_ROT_90; break;
107        case 180: transform = HAL_TRANSFORM_ROT_180; break;
108        case 270: transform = HAL_TRANSFORM_ROT_270; break;
109        default: transform = 0; break;
110    }
111
112    if (transform) {
113        CHECK_EQ(0, native_window_set_buffers_transform(
114                    mNativeWindow.get(), transform));
115    }
116}
117
118SoftwareRenderer::~SoftwareRenderer() {
119    delete mConverter;
120    mConverter = NULL;
121}
122
123static int ALIGN(int x, int y) {
124    // y must be a power of 2.
125    return (x + y - 1) & ~(y - 1);
126}
127
128void SoftwareRenderer::render(
129        const void *data, size_t size, void *platformPrivate) {
130    ANativeWindowBuffer *buf;
131    int err;
132    if ((err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf)) != 0) {
133        LOGW("Surface::dequeueBuffer returned error %d", err);
134        return;
135    }
136
137    CHECK_EQ(0, mNativeWindow->lockBuffer(mNativeWindow.get(), buf));
138
139    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
140
141    Rect bounds(mCropWidth, mCropHeight);
142
143    void *dst;
144    CHECK_EQ(0, mapper.lock(
145                buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
146
147    if (mConverter) {
148        mConverter->convert(
149                data,
150                mWidth, mHeight,
151                mCropLeft, mCropTop, mCropRight, mCropBottom,
152                dst,
153                buf->stride, buf->height,
154                0, 0, mCropWidth - 1, mCropHeight - 1);
155    } else if (mColorFormat == OMX_COLOR_FormatYUV420Planar) {
156        const uint8_t *src_y = (const uint8_t *)data;
157        const uint8_t *src_u = (const uint8_t *)data + mWidth * mHeight;
158        const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);
159
160        uint8_t *dst_y = (uint8_t *)dst;
161        size_t dst_y_size = buf->stride * buf->height;
162        size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
163        size_t dst_c_size = dst_c_stride * buf->height / 2;
164        uint8_t *dst_v = dst_y + dst_y_size;
165        uint8_t *dst_u = dst_v + dst_c_size;
166
167        for (int y = 0; y < mCropHeight; ++y) {
168            memcpy(dst_y, src_y, mCropWidth);
169
170            src_y += mWidth;
171            dst_y += buf->stride;
172        }
173
174        for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
175            memcpy(dst_u, src_u, (mCropWidth + 1) / 2);
176            memcpy(dst_v, src_v, (mCropWidth + 1) / 2);
177
178            src_u += mWidth / 2;
179            src_v += mWidth / 2;
180            dst_u += dst_c_stride;
181            dst_v += dst_c_stride;
182        }
183    } else {
184        CHECK_EQ(mColorFormat, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar);
185
186        const uint8_t *src_y =
187            (const uint8_t *)data;
188
189        const uint8_t *src_uv =
190            (const uint8_t *)data + mWidth * (mHeight - mCropTop / 2);
191
192        uint8_t *dst_y = (uint8_t *)dst;
193
194        size_t dst_y_size = buf->stride * buf->height;
195        size_t dst_c_stride = ALIGN(buf->stride / 2, 16);
196        size_t dst_c_size = dst_c_stride * buf->height / 2;
197        uint8_t *dst_v = dst_y + dst_y_size;
198        uint8_t *dst_u = dst_v + dst_c_size;
199
200        for (int y = 0; y < mCropHeight; ++y) {
201            memcpy(dst_y, src_y, mCropWidth);
202
203            src_y += mWidth;
204            dst_y += buf->stride;
205        }
206
207        for (int y = 0; y < (mCropHeight + 1) / 2; ++y) {
208            size_t tmp = (mCropWidth + 1) / 2;
209            for (size_t x = 0; x < tmp; ++x) {
210                dst_u[x] = src_uv[2 * x];
211                dst_v[x] = src_uv[2 * x + 1];
212            }
213
214            src_uv += mWidth;
215            dst_u += dst_c_stride;
216            dst_v += dst_c_stride;
217        }
218    }
219
220    CHECK_EQ(0, mapper.unlock(buf->handle));
221
222    if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf)) != 0) {
223        LOGW("Surface::queueBuffer returned error %d", err);
224    }
225    buf = NULL;
226}
227
228}  // namespace android
229