PreviewRenderer.cpp revision 4f155f0cffa2414545854e899dff4861187e1f68
1/*
2 * Copyright (C) 2011 NXP Software
3 * Copyright (C) 2011 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19#define LOG_NDEBUG 1
20#define LOG_TAG "PreviewRenderer"
21#include <utils/Log.h>
22
23#include "PreviewRenderer.h"
24
25#include <binder/MemoryHeapBase.h>
26#include <binder/MemoryHeapPmem.h>
27#include <media/stagefright/MediaDebug.h>
28#include <surfaceflinger/Surface.h>
29
30namespace android {
31
32PreviewRenderer::PreviewRenderer(
33        OMX_COLOR_FORMATTYPE colorFormat,
34        const sp<Surface> &surface,
35        size_t displayWidth, size_t displayHeight,
36        size_t decodedWidth, size_t decodedHeight,
37        int32_t rotationDegrees)
38    : mColorFormat(colorFormat),
39      mConverter(NULL),
40      mYUVMode(None),
41      mSurface(surface),
42      mDisplayWidth(displayWidth),
43      mDisplayHeight(displayHeight),
44      mDecodedWidth(decodedWidth),
45      mDecodedHeight(decodedHeight) {
46    LOGV("input format = %d", mColorFormat);
47    LOGV("display = %d x %d, decoded = %d x %d",
48            mDisplayWidth, mDisplayHeight, mDecodedWidth, mDecodedHeight);
49
50    mDecodedWidth = mDisplayWidth;
51    mDecodedHeight = mDisplayHeight;
52
53    int halFormat;
54    switch (mColorFormat) {
55        case OMX_COLOR_FormatYUV420Planar:
56        {
57            halFormat = HAL_PIXEL_FORMAT_YV12;
58            mYUVMode = None;
59            break;
60        }
61        default:
62            halFormat = HAL_PIXEL_FORMAT_RGB_565;
63
64            mConverter = new ColorConverter(
65                    mColorFormat, OMX_COLOR_Format16bitRGB565);
66            CHECK(mConverter->isValid());
67            break;
68    }
69
70    CHECK(mSurface.get() != NULL);
71    CHECK(mDecodedWidth > 0);
72    CHECK(mDecodedHeight > 0);
73    CHECK(mConverter == NULL || mConverter->isValid());
74
75    CHECK_EQ(0,
76            native_window_set_usage(
77            mSurface.get(),
78            GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
79            | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
80
81    CHECK_EQ(0, native_window_set_buffer_count(mSurface.get(), 3));
82
83    // Width must be multiple of 32???
84    CHECK_EQ(0, native_window_set_buffers_geometry(
85                mSurface.get(), mDecodedWidth, mDecodedHeight,
86                halFormat));
87
88    uint32_t transform;
89    switch (rotationDegrees) {
90        case 0: transform = 0; break;
91        case 90: transform = HAL_TRANSFORM_ROT_90; break;
92        case 180: transform = HAL_TRANSFORM_ROT_180; break;
93        case 270: transform = HAL_TRANSFORM_ROT_270; break;
94        default: transform = 0; break;
95    }
96
97    if (transform) {
98        CHECK_EQ(0, native_window_set_buffers_transform(
99                    mSurface.get(), transform));
100    }
101}
102
103PreviewRenderer::~PreviewRenderer() {
104    delete mConverter;
105    mConverter = NULL;
106}
107
108
109//
110// Provides a buffer and associated stride
111// This buffer is allocated by the SurfaceFlinger
112//
113// For optimal display performances, you should :
114// 1) call getBufferYV12()
115// 2) fill the buffer with your data
116// 3) call renderYV12() to take these changes into account
117//
118// For each call to getBufferYV12(), you must also call renderYV12()
119// Expected format in the buffer is YV12 formats (similar to YUV420 planar fromat)
120// for more details on this YV12 cf hardware/libhardware/include/hardware/hardware.h
121//
122void PreviewRenderer::getBufferYV12(uint8_t **data, size_t *stride) {
123    int err = OK;
124    LOGV("getBuffer START");
125
126    if ((err = mSurface->dequeueBuffer(mSurface.get(), &mBuf)) != 0) {
127        LOGW("Surface::dequeueBuffer returned error %d", err);
128        return;
129    }
130
131    CHECK_EQ(0, mSurface->lockBuffer(mSurface.get(), mBuf));
132
133    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
134
135    Rect bounds(mDecodedWidth, mDecodedHeight);
136
137    void *dst;
138    CHECK_EQ(0, mapper.lock(
139                mBuf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
140    LOGV("Buffer locked");
141
142    *data   = (uint8_t*)dst;
143    *stride = mBuf->stride;
144
145    LOGV("getBuffer END %p %d", dst, mBuf->stride);
146}
147
148
149//
150// Display the content of the buffer provided by last call to getBufferYV12()
151//
152// See getBufferYV12() for details.
153//
154void PreviewRenderer::renderYV12() {
155    LOGV("renderYV12() START");
156    int err = OK;
157
158    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
159
160    if (mBuf!= NULL) {
161        CHECK_EQ(0, mapper.unlock(mBuf->handle));
162
163        if ((err = mSurface->queueBuffer(mSurface.get(), mBuf)) != 0) {
164            LOGW("Surface::queueBuffer returned error %d", err);
165        }
166    }
167    mBuf = NULL;
168    LOGV("renderYV12() END");
169}
170
171
172
173//
174// Display the given data buffer
175// platformPrivate is not used (kept for backwrad compatibility)
176// Please rather use getbuffer() and the other render()functions (with no params)
177// for optimal display
178//
179void PreviewRenderer::render(
180        const void *data, size_t size, void *platformPrivate) {
181    android_native_buffer_t *buf;
182    int err;
183
184    if ((err = mSurface->dequeueBuffer(mSurface.get(), &buf)) != 0) {
185        LOGW("Surface::dequeueBuffer returned error %d", err);
186        return;
187    }
188
189    CHECK_EQ(0, mSurface->lockBuffer(mSurface.get(), buf));
190
191    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
192
193    Rect bounds(mDecodedWidth, mDecodedHeight);
194
195    void *dst;
196    CHECK_EQ(0, mapper.lock(
197                buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
198    LOGV("Buffer locked");
199
200    if (mConverter) {
201        LOGV("Convert to RGB565");
202        mConverter->convert(data,
203                mDecodedWidth, mDecodedHeight,
204                0,0,mDecodedWidth, mDecodedHeight,
205                dst, mDecodedWidth, mDecodedHeight,
206                0,0,mDecodedWidth, mDecodedHeight);
207    } else if (mYUVMode == None) {
208        // Input and output are both YUV420sp, but the alignment requirements
209        // are different.
210        LOGV("mYUVMode == None %d x %d", mDecodedWidth, mDecodedHeight);
211        size_t srcYStride = mDecodedWidth;
212        const uint8_t *srcY = (const uint8_t *)data;
213        uint8_t *dstY = (uint8_t *)dst;
214        LOGV("srcY =       %p   dstY =       %p", srcY, dstY);
215        LOGV("srcYStride = %d   dstYstride = %d", srcYStride, buf->stride);
216        for (size_t i = 0; i < mDecodedHeight; ++i) {
217            memcpy(dstY, srcY, mDecodedWidth);
218            srcY += srcYStride;
219            dstY += buf->stride;
220        }
221
222        size_t srcUVStride = (mDecodedWidth + 1) / 2;
223        size_t dstUVStride = ALIGN(mDecodedWidth / 2, 32);
224        LOGV("srcUVStride = %d   dstUVStride = %d", srcUVStride, dstUVStride);
225
226        // Copy V
227        // Source buffer is YUV, skip U
228        const uint8_t *srcV = (const uint8_t *)data
229                + mDecodedHeight * mDecodedWidth + (mDecodedHeight * mDecodedWidth)/4;
230        // Destination buffer is YVU
231        uint8_t *dstUV = (uint8_t *)dst
232                + buf->stride*mDecodedHeight;
233        LOGV("srcV =       %p   dstUV =       %p", srcV, dstUV);
234        for (size_t i = 0; i < (mDecodedHeight+1)/2; ++i) {
235            memcpy(dstUV, srcV, mDecodedWidth/2);
236            srcV += srcUVStride;
237            dstUV += dstUVStride;
238        }
239
240
241        // Copy V
242        // Source buffer is YUV, go back to end of Y
243        const uint8_t *srcU = (const uint8_t *)data
244            + mDecodedHeight * mDecodedWidth ;
245        // Destination buffer is YVU
246        // Keep writing after V buffer has been filled, U follows immediately
247        LOGV("srcU =       %p   dstUV =       %p", srcU, dstUV);
248        for (size_t i = 0; i < (mDecodedHeight+1)/2; ++i) {
249            memcpy(dstUV, srcU, mDecodedWidth/2);
250            srcU += srcUVStride;
251            dstUV += dstUVStride;
252        }
253    } else {
254        memcpy(dst, data, size);
255    }
256
257    CHECK_EQ(0, mapper.unlock(buf->handle));
258
259    if ((err = mSurface->queueBuffer(mSurface.get(), buf)) != 0) {
260        LOGW("Surface::queueBuffer returned error %d", err);
261    }
262    buf = NULL;
263}
264
265}  // namespace android
266