blob: cfded72caa8db3bfa51c9db3e56c0000fd25aaa2 [file] [log] [blame]
Dharmaray Kundargi643290d2011-01-16 16:02:42 -08001/*
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
Santosh Madhavabfece172011-02-03 16:59:47 -080032PreviewRenderer* PreviewRenderer::CreatePreviewRenderer (OMX_COLOR_FORMATTYPE colorFormat,
33 const sp<Surface> &surface,
34 size_t displayWidth, size_t displayHeight,
35 size_t decodedWidth, size_t decodedHeight,
36 int32_t rotationDegrees) {
37
38 PreviewRenderer* returnCtx =
39 new PreviewRenderer(colorFormat,
40 surface,
41 displayWidth, displayHeight,
42 decodedWidth, decodedHeight,
43 rotationDegrees);
44
45 int result = 0;
46
47 int halFormat;
48 switch (returnCtx->mColorFormat) {
49 case OMX_COLOR_FormatYUV420Planar:
50 {
51 halFormat = HAL_PIXEL_FORMAT_YV12;
52 returnCtx->mYUVMode = None;
53 break;
54 }
55 default:
56 halFormat = HAL_PIXEL_FORMAT_RGB_565;
57
58 returnCtx->mConverter = new ColorConverter(
59 returnCtx->mColorFormat, OMX_COLOR_Format16bitRGB565);
60 CHECK(returnCtx->mConverter->isValid());
61 break;
62 }
63
64 CHECK(returnCtx->mSurface.get() != NULL);
65 CHECK(returnCtx->mDecodedWidth > 0);
66 CHECK(returnCtx->mDecodedHeight > 0);
67 CHECK(returnCtx->mConverter == NULL || returnCtx->mConverter->isValid());
68
69 result = native_window_set_usage(
70 returnCtx->mSurface.get(),
71 GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
72 | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
73
74 if ( result == 0 ) {
75 result = native_window_set_buffer_count(returnCtx->mSurface.get(), 3);
76
77 if (result == 0) {
78 result = native_window_set_buffers_geometry(
79 returnCtx->mSurface.get(), returnCtx->mDecodedWidth, returnCtx->mDecodedHeight,
80 halFormat);
81 if ( result == 0) {
82 uint32_t transform;
83 switch (rotationDegrees) {
84 case 0: transform = 0; break;
85 case 90: transform = HAL_TRANSFORM_ROT_90; break;
86 case 180: transform = HAL_TRANSFORM_ROT_180; break;
87 case 270: transform = HAL_TRANSFORM_ROT_270; break;
88 default: transform = 0; break;
89 }
90 if (transform) {
91 result = native_window_set_buffers_transform(
92 returnCtx->mSurface.get(), transform);
93
94 }
95 }
96 }
97 }
98
99 if ( result != 0 )
100 {
101 /* free the ctx */
102 returnCtx->~PreviewRenderer();
103 return NULL;
104 }
105
106 return returnCtx;
107}
108
Dharmaray Kundargi643290d2011-01-16 16:02:42 -0800109PreviewRenderer::PreviewRenderer(
110 OMX_COLOR_FORMATTYPE colorFormat,
111 const sp<Surface> &surface,
112 size_t displayWidth, size_t displayHeight,
113 size_t decodedWidth, size_t decodedHeight,
114 int32_t rotationDegrees)
115 : mColorFormat(colorFormat),
116 mConverter(NULL),
117 mYUVMode(None),
118 mSurface(surface),
119 mDisplayWidth(displayWidth),
120 mDisplayHeight(displayHeight),
121 mDecodedWidth(decodedWidth),
122 mDecodedHeight(decodedHeight) {
Santosh Madhavabfece172011-02-03 16:59:47 -0800123
Dharmaray Kundargi643290d2011-01-16 16:02:42 -0800124 LOGV("input format = %d", mColorFormat);
125 LOGV("display = %d x %d, decoded = %d x %d",
126 mDisplayWidth, mDisplayHeight, mDecodedWidth, mDecodedHeight);
127
128 mDecodedWidth = mDisplayWidth;
129 mDecodedHeight = mDisplayHeight;
Dharmaray Kundargi643290d2011-01-16 16:02:42 -0800130}
131
132PreviewRenderer::~PreviewRenderer() {
133 delete mConverter;
134 mConverter = NULL;
135}
136
137
138//
139// Provides a buffer and associated stride
140// This buffer is allocated by the SurfaceFlinger
141//
142// For optimal display performances, you should :
143// 1) call getBufferYV12()
144// 2) fill the buffer with your data
145// 3) call renderYV12() to take these changes into account
146//
147// For each call to getBufferYV12(), you must also call renderYV12()
148// Expected format in the buffer is YV12 formats (similar to YUV420 planar fromat)
149// for more details on this YV12 cf hardware/libhardware/include/hardware/hardware.h
150//
151void PreviewRenderer::getBufferYV12(uint8_t **data, size_t *stride) {
152 int err = OK;
153 LOGV("getBuffer START");
154
155 if ((err = mSurface->dequeueBuffer(mSurface.get(), &mBuf)) != 0) {
156 LOGW("Surface::dequeueBuffer returned error %d", err);
157 return;
158 }
159
160 CHECK_EQ(0, mSurface->lockBuffer(mSurface.get(), mBuf));
161
162 GraphicBufferMapper &mapper = GraphicBufferMapper::get();
163
164 Rect bounds(mDecodedWidth, mDecodedHeight);
165
166 void *dst;
167 CHECK_EQ(0, mapper.lock(
168 mBuf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
169 LOGV("Buffer locked");
170
171 *data = (uint8_t*)dst;
172 *stride = mBuf->stride;
173
174 LOGV("getBuffer END %p %d", dst, mBuf->stride);
175}
176
177
178//
179// Display the content of the buffer provided by last call to getBufferYV12()
180//
181// See getBufferYV12() for details.
182//
183void PreviewRenderer::renderYV12() {
184 LOGV("renderYV12() START");
185 int err = OK;
186
187 GraphicBufferMapper &mapper = GraphicBufferMapper::get();
188
189 if (mBuf!= NULL) {
190 CHECK_EQ(0, mapper.unlock(mBuf->handle));
191
192 if ((err = mSurface->queueBuffer(mSurface.get(), mBuf)) != 0) {
193 LOGW("Surface::queueBuffer returned error %d", err);
194 }
195 }
196 mBuf = NULL;
197 LOGV("renderYV12() END");
198}
199
200
201
202//
203// Display the given data buffer
204// platformPrivate is not used (kept for backwrad compatibility)
205// Please rather use getbuffer() and the other render()functions (with no params)
206// for optimal display
207//
208void PreviewRenderer::render(
209 const void *data, size_t size, void *platformPrivate) {
210 android_native_buffer_t *buf;
211 int err;
212
213 if ((err = mSurface->dequeueBuffer(mSurface.get(), &buf)) != 0) {
214 LOGW("Surface::dequeueBuffer returned error %d", err);
215 return;
216 }
217
218 CHECK_EQ(0, mSurface->lockBuffer(mSurface.get(), buf));
219
220 GraphicBufferMapper &mapper = GraphicBufferMapper::get();
221
222 Rect bounds(mDecodedWidth, mDecodedHeight);
223
224 void *dst;
225 CHECK_EQ(0, mapper.lock(
226 buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
227 LOGV("Buffer locked");
228
229 if (mConverter) {
230 LOGV("Convert to RGB565");
231 mConverter->convert(data,
232 mDecodedWidth, mDecodedHeight,
233 0,0,mDecodedWidth, mDecodedHeight,
234 dst, mDecodedWidth, mDecodedHeight,
235 0,0,mDecodedWidth, mDecodedHeight);
236 } else if (mYUVMode == None) {
237 // Input and output are both YUV420sp, but the alignment requirements
238 // are different.
239 LOGV("mYUVMode == None %d x %d", mDecodedWidth, mDecodedHeight);
240 size_t srcYStride = mDecodedWidth;
241 const uint8_t *srcY = (const uint8_t *)data;
242 uint8_t *dstY = (uint8_t *)dst;
243 LOGV("srcY = %p dstY = %p", srcY, dstY);
244 LOGV("srcYStride = %d dstYstride = %d", srcYStride, buf->stride);
245 for (size_t i = 0; i < mDecodedHeight; ++i) {
246 memcpy(dstY, srcY, mDecodedWidth);
247 srcY += srcYStride;
248 dstY += buf->stride;
249 }
250
251 size_t srcUVStride = (mDecodedWidth + 1) / 2;
252 size_t dstUVStride = ALIGN(mDecodedWidth / 2, 32);
253 LOGV("srcUVStride = %d dstUVStride = %d", srcUVStride, dstUVStride);
254
255 // Copy V
256 // Source buffer is YUV, skip U
257 const uint8_t *srcV = (const uint8_t *)data
258 + mDecodedHeight * mDecodedWidth + (mDecodedHeight * mDecodedWidth)/4;
259 // Destination buffer is YVU
260 uint8_t *dstUV = (uint8_t *)dst
261 + buf->stride*mDecodedHeight;
262 LOGV("srcV = %p dstUV = %p", srcV, dstUV);
263 for (size_t i = 0; i < (mDecodedHeight+1)/2; ++i) {
264 memcpy(dstUV, srcV, mDecodedWidth/2);
265 srcV += srcUVStride;
266 dstUV += dstUVStride;
267 }
268
269
270 // Copy V
271 // Source buffer is YUV, go back to end of Y
272 const uint8_t *srcU = (const uint8_t *)data
273 + mDecodedHeight * mDecodedWidth ;
274 // Destination buffer is YVU
275 // Keep writing after V buffer has been filled, U follows immediately
276 LOGV("srcU = %p dstUV = %p", srcU, dstUV);
277 for (size_t i = 0; i < (mDecodedHeight+1)/2; ++i) {
278 memcpy(dstUV, srcU, mDecodedWidth/2);
279 srcU += srcUVStride;
280 dstUV += dstUVStride;
281 }
282 } else {
283 memcpy(dst, data, size);
284 }
285
286 CHECK_EQ(0, mapper.unlock(buf->handle));
287
288 if ((err = mSurface->queueBuffer(mSurface.get(), buf)) != 0) {
289 LOGW("Surface::queueBuffer returned error %d", err);
290 }
291 buf = NULL;
292}
293
294} // namespace android