SurfaceTextureClient.cpp revision eafabcdc1639fb96062d9e3c39b0ae27b0238ae1
1/*
2 * Copyright (C) 2010 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 "SurfaceTextureClient"
18//#define LOG_NDEBUG 0
19
20#include <gui/SurfaceTextureClient.h>
21
22#include <utils/Log.h>
23
24namespace android {
25
26SurfaceTextureClient::SurfaceTextureClient(
27        const sp<ISurfaceTexture>& surfaceTexture):
28        mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
29        mReqHeight(0), mReqFormat(0), mReqUsage(0),
30        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0),
31        mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
32        mMutex() {
33    // Initialize the ANativeWindow function pointers.
34    ANativeWindow::setSwapInterval  = setSwapInterval;
35    ANativeWindow::dequeueBuffer    = dequeueBuffer;
36    ANativeWindow::cancelBuffer     = cancelBuffer;
37    ANativeWindow::lockBuffer       = lockBuffer;
38    ANativeWindow::queueBuffer      = queueBuffer;
39    ANativeWindow::query            = query;
40    ANativeWindow::perform          = perform;
41
42    // Get a reference to the allocator.
43    mAllocator = mSurfaceTexture->getAllocator();
44}
45
46sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
47    return mSurfaceTexture;
48}
49
50int SurfaceTextureClient::setSwapInterval(ANativeWindow* window, int interval) {
51    SurfaceTextureClient* c = getSelf(window);
52    return c->setSwapInterval(interval);
53}
54
55int SurfaceTextureClient::dequeueBuffer(ANativeWindow* window,
56        ANativeWindowBuffer** buffer) {
57    SurfaceTextureClient* c = getSelf(window);
58    return c->dequeueBuffer(buffer);
59}
60
61int SurfaceTextureClient::cancelBuffer(ANativeWindow* window,
62        ANativeWindowBuffer* buffer) {
63    SurfaceTextureClient* c = getSelf(window);
64    return c->cancelBuffer(buffer);
65}
66
67int SurfaceTextureClient::lockBuffer(ANativeWindow* window,
68        ANativeWindowBuffer* buffer) {
69    SurfaceTextureClient* c = getSelf(window);
70    return c->lockBuffer(buffer);
71}
72
73int SurfaceTextureClient::queueBuffer(ANativeWindow* window,
74        ANativeWindowBuffer* buffer) {
75    SurfaceTextureClient* c = getSelf(window);
76    return c->queueBuffer(buffer);
77}
78
79int SurfaceTextureClient::query(const ANativeWindow* window,
80                                int what, int* value) {
81    const SurfaceTextureClient* c = getSelf(window);
82    return c->query(what, value);
83}
84
85int SurfaceTextureClient::perform(ANativeWindow* window, int operation, ...) {
86    va_list args;
87    va_start(args, operation);
88    SurfaceTextureClient* c = getSelf(window);
89    return c->perform(operation, args);
90}
91
92int SurfaceTextureClient::setSwapInterval(int interval) {
93    return INVALID_OPERATION;
94}
95
96int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
97    LOGV("SurfaceTextureClient::dequeueBuffer");
98    Mutex::Autolock lock(mMutex);
99    int buf = -1;
100    status_t err = mSurfaceTexture->dequeueBuffer(&buf, mReqWidth, mReqHeight,
101            mReqFormat, mReqUsage);
102    if (err < 0) {
103        LOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"
104             "failed: %d", err, mReqWidth, mReqHeight, mReqFormat, mReqUsage);
105        return err;
106    }
107    sp<GraphicBuffer>& gbuf(mSlots[buf]);
108    if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION || gbuf == 0) {
109        gbuf = mSurfaceTexture->requestBuffer(buf);
110        if (gbuf == 0) {
111            LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
112            return NO_MEMORY;
113        }
114        mQueryWidth  = gbuf->width;
115        mQueryHeight = gbuf->height;
116        mQueryFormat = gbuf->format;
117    }
118    *buffer = gbuf.get();
119    return OK;
120}
121
122int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
123    LOGV("SurfaceTextureClient::cancelBuffer");
124    Mutex::Autolock lock(mMutex);
125    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
126        if (mSlots[i]->handle == buffer->handle) {
127            mSurfaceTexture->cancelBuffer(i);
128            return OK;
129        }
130    }
131    return BAD_VALUE;
132}
133
134int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) {
135    LOGV("SurfaceTextureClient::lockBuffer");
136    Mutex::Autolock lock(mMutex);
137    return OK;
138}
139
140int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
141    LOGV("SurfaceTextureClient::queueBuffer");
142    Mutex::Autolock lock(mMutex);
143    int64_t timestamp;
144    if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
145        timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
146        LOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms",
147             timestamp / 1000000.f);
148    } else {
149        timestamp = mTimestamp;
150    }
151    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
152        if (mSlots[i]->handle == buffer->handle) {
153            return mSurfaceTexture->queueBuffer(i, timestamp);
154        }
155    }
156    LOGE("queueBuffer: unknown buffer queued");
157    return BAD_VALUE;
158}
159
160int SurfaceTextureClient::query(int what, int* value) const {
161    LOGV("SurfaceTextureClient::query");
162    switch (what) {
163    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
164        // TODO: this is not needed anymore
165        *value = 0;
166        return NO_ERROR;
167    case NATIVE_WINDOW_CONCRETE_TYPE:
168        // TODO: this is not needed anymore
169        *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
170        return NO_ERROR;
171    }
172    return mSurfaceTexture->query(what, value);
173}
174
175int SurfaceTextureClient::perform(int operation, va_list args)
176{
177    int res = NO_ERROR;
178    switch (operation) {
179    case NATIVE_WINDOW_CONNECT:
180        res = dispatchConnect(args);
181        break;
182    case NATIVE_WINDOW_DISCONNECT:
183        res = dispatchDisconnect(args);
184        break;
185    case NATIVE_WINDOW_SET_USAGE:
186        res = dispatchSetUsage(args);
187        break;
188    case NATIVE_WINDOW_SET_CROP:
189        res = dispatchSetCrop(args);
190        break;
191    case NATIVE_WINDOW_SET_BUFFER_COUNT:
192        res = dispatchSetBufferCount(args);
193        break;
194    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
195        res = dispatchSetBuffersGeometry(args);
196        break;
197    case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
198        res = dispatchSetBuffersTransform(args);
199        break;
200    case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
201        res = dispatchSetBuffersTimestamp(args);
202        break;
203    default:
204        res = NAME_NOT_FOUND;
205        break;
206    }
207    return res;
208}
209
210int SurfaceTextureClient::dispatchConnect(va_list args) {
211    int api = va_arg(args, int);
212    return connect(api);
213}
214
215int SurfaceTextureClient::dispatchDisconnect(va_list args) {
216    int api = va_arg(args, int);
217    return disconnect(api);
218}
219
220int SurfaceTextureClient::dispatchSetUsage(va_list args) {
221    int usage = va_arg(args, int);
222    return setUsage(usage);
223}
224
225int SurfaceTextureClient::dispatchSetCrop(va_list args) {
226    android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
227    return setCrop(reinterpret_cast<Rect const*>(rect));
228}
229
230int SurfaceTextureClient::dispatchSetBufferCount(va_list args) {
231    size_t bufferCount = va_arg(args, size_t);
232    return setBufferCount(bufferCount);
233}
234
235int SurfaceTextureClient::dispatchSetBuffersGeometry(va_list args) {
236    int w = va_arg(args, int);
237    int h = va_arg(args, int);
238    int f = va_arg(args, int);
239    return setBuffersGeometry(w, h, f);
240}
241
242int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
243    int transform = va_arg(args, int);
244    return setBuffersTransform(transform);
245}
246
247int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {
248    int64_t timestamp = va_arg(args, int64_t);
249    return setBuffersTimestamp(timestamp);
250}
251
252int SurfaceTextureClient::connect(int api) {
253    LOGV("SurfaceTextureClient::connect");
254    Mutex::Autolock lock(mMutex);
255    int err = NO_ERROR;
256    switch (api) {
257        case NATIVE_WINDOW_API_EGL:
258            if (mConnectedApi) {
259                err = -EINVAL;
260            } else {
261                mConnectedApi = api;
262            }
263            break;
264        default:
265            err = -EINVAL;
266            break;
267    }
268    return err;
269}
270
271int SurfaceTextureClient::disconnect(int api) {
272    LOGV("SurfaceTextureClient::disconnect");
273    Mutex::Autolock lock(mMutex);
274    int err = NO_ERROR;
275    switch (api) {
276        case NATIVE_WINDOW_API_EGL:
277            if (mConnectedApi == api) {
278                mConnectedApi = 0;
279            } else {
280                err = -EINVAL;
281            }
282            break;
283        default:
284            err = -EINVAL;
285            break;
286    }
287    return err;
288}
289
290int SurfaceTextureClient::getConnectedApi() const
291{
292    Mutex::Autolock lock(mMutex);
293    return mConnectedApi;
294}
295
296
297int SurfaceTextureClient::setUsage(uint32_t reqUsage)
298{
299    LOGV("SurfaceTextureClient::setUsage");
300    Mutex::Autolock lock(mMutex);
301    mReqUsage = reqUsage;
302    return OK;
303}
304
305int SurfaceTextureClient::setCrop(Rect const* rect)
306{
307    LOGV("SurfaceTextureClient::setCrop");
308    Mutex::Autolock lock(mMutex);
309
310    Rect realRect;
311    if (rect == NULL || rect->isEmpty()) {
312        realRect = Rect(0, 0);
313    } else {
314        realRect = *rect;
315    }
316
317    status_t err = mSurfaceTexture->setCrop(*rect);
318    LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err));
319
320    return err;
321}
322
323int SurfaceTextureClient::setBufferCount(int bufferCount)
324{
325    LOGV("SurfaceTextureClient::setBufferCount");
326    Mutex::Autolock lock(mMutex);
327
328    status_t err = mSurfaceTexture->setBufferCount(bufferCount);
329    LOGE_IF(err, "ISurfaceTexture::setBufferCount(%d) returned %s",
330            bufferCount, strerror(-err));
331
332    if (err == NO_ERROR) {
333        freeAllBuffers();
334    }
335
336    return err;
337}
338
339int SurfaceTextureClient::setBuffersGeometry(int w, int h, int format)
340{
341    LOGV("SurfaceTextureClient::setBuffersGeometry");
342    Mutex::Autolock lock(mMutex);
343
344    if (w<0 || h<0 || format<0)
345        return BAD_VALUE;
346
347    if ((w && !h) || (!w && h))
348        return BAD_VALUE;
349
350    mReqWidth = w;
351    mReqHeight = h;
352    mReqFormat = format;
353
354    status_t err = mSurfaceTexture->setCrop(Rect(0, 0));
355    LOGE_IF(err, "ISurfaceTexture::setCrop(...) returned %s", strerror(-err));
356
357    return err;
358}
359
360int SurfaceTextureClient::setBuffersTransform(int transform)
361{
362    LOGV("SurfaceTextureClient::setBuffersTransform");
363    Mutex::Autolock lock(mMutex);
364    status_t err = mSurfaceTexture->setTransform(transform);
365    return err;
366}
367
368int SurfaceTextureClient::setBuffersTimestamp(int64_t timestamp)
369{
370    LOGV("SurfaceTextureClient::setBuffersTimestamp");
371    Mutex::Autolock lock(mMutex);
372    mTimestamp = timestamp;
373    return NO_ERROR;
374}
375
376void SurfaceTextureClient::freeAllBuffers() {
377    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
378        mSlots[i] = 0;
379    }
380}
381
382}; // namespace android
383