JpegProcessor.cpp revision cf70d3469332445dc3ffd09729da3538612b1bb2
1/*
2 * Copyright (C) 2012 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 "Camera2Client::JpegProcessor"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
19//#define LOG_NDEBUG 0
20
21#include <utils/Log.h>
22#include <utils/Trace.h>
23
24#include "JpegProcessor.h"
25#include <gui/SurfaceTextureClient.h>
26#include "../Camera2Device.h"
27#include "../Camera2Client.h"
28
29
30namespace android {
31namespace camera2 {
32
33JpegProcessor::JpegProcessor(
34    wp<Camera2Client> client,
35    wp<CaptureSequencer> sequencer):
36        Thread(false),
37        mClient(client),
38        mSequencer(sequencer),
39        mCaptureAvailable(false),
40        mCaptureStreamId(NO_STREAM) {
41}
42
43JpegProcessor::~JpegProcessor() {
44    ALOGV("%s: Exit", __FUNCTION__);
45    deleteStream();
46}
47
48void JpegProcessor::onFrameAvailable() {
49    Mutex::Autolock l(mInputMutex);
50    if (!mCaptureAvailable) {
51        mCaptureAvailable = true;
52        mCaptureAvailableSignal.signal();
53    }
54}
55
56status_t JpegProcessor::updateStream(const Parameters &params) {
57    ATRACE_CALL();
58    ALOGV("%s", __FUNCTION__);
59    status_t res;
60
61    Mutex::Autolock l(mInputMutex);
62
63    sp<Camera2Client> client = mClient.promote();
64    if (client == 0) return OK;
65    sp<Camera2Device> device = client->getCameraDevice();
66
67    // Find out buffer size for JPEG
68    camera_metadata_ro_entry_t maxJpegSize =
69            params.staticInfo(ANDROID_JPEG_MAX_SIZE);
70    if (maxJpegSize.count == 0) {
71        ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!",
72                __FUNCTION__, client->getCameraId());
73        return INVALID_OPERATION;
74    }
75
76    if (mCaptureConsumer == 0) {
77        // Create CPU buffer queue endpoint
78        mCaptureConsumer = new CpuConsumer(1);
79        mCaptureConsumer->setFrameAvailableListener(this);
80        mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
81        mCaptureWindow = new SurfaceTextureClient(
82            mCaptureConsumer->getProducerInterface());
83        // Create memory for API consumption
84        mCaptureHeap = new Camera2Heap(maxJpegSize.data.i32[0], 1,
85                                       "Camera2Client::CaptureHeap");
86        if (mCaptureHeap->mHeap->getSize() == 0) {
87            ALOGE("%s: Camera %d: Unable to allocate memory for capture",
88                    __FUNCTION__, client->getCameraId());
89            return NO_MEMORY;
90        }
91    }
92
93    if (mCaptureStreamId != NO_STREAM) {
94        // Check if stream parameters have to change
95        uint32_t currentWidth, currentHeight;
96        res = device->getStreamInfo(mCaptureStreamId,
97                &currentWidth, &currentHeight, 0);
98        if (res != OK) {
99            ALOGE("%s: Camera %d: Error querying capture output stream info: "
100                    "%s (%d)", __FUNCTION__,
101                    client->getCameraId(), strerror(-res), res);
102            return res;
103        }
104        if (currentWidth != (uint32_t)params.pictureWidth ||
105                currentHeight != (uint32_t)params.pictureHeight) {
106            res = device->deleteStream(mCaptureStreamId);
107            if (res != OK) {
108                ALOGE("%s: Camera %d: Unable to delete old output stream "
109                        "for capture: %s (%d)", __FUNCTION__,
110                        client->getCameraId(), strerror(-res), res);
111                return res;
112            }
113            mCaptureStreamId = NO_STREAM;
114        }
115    }
116
117    if (mCaptureStreamId == NO_STREAM) {
118        // Create stream for HAL production
119        res = device->createStream(mCaptureWindow,
120                params.pictureWidth, params.pictureHeight,
121                HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0],
122                &mCaptureStreamId);
123        if (res != OK) {
124            ALOGE("%s: Camera %d: Can't create output stream for capture: "
125                    "%s (%d)", __FUNCTION__, client->getCameraId(),
126                    strerror(-res), res);
127            return res;
128        }
129
130    }
131    return OK;
132}
133
134status_t JpegProcessor::deleteStream() {
135    ATRACE_CALL();
136    status_t res;
137
138    Mutex::Autolock l(mInputMutex);
139
140    if (mCaptureStreamId != NO_STREAM) {
141        sp<Camera2Client> client = mClient.promote();
142        if (client == 0) return OK;
143        sp<Camera2Device> device = client->getCameraDevice();
144
145        device->deleteStream(mCaptureStreamId);
146
147        mCaptureHeap.clear();
148        mCaptureWindow.clear();
149        mCaptureConsumer.clear();
150
151        mCaptureStreamId = NO_STREAM;
152    }
153    return OK;
154}
155
156int JpegProcessor::getStreamId() const {
157    Mutex::Autolock l(mInputMutex);
158    return mCaptureStreamId;
159}
160
161void JpegProcessor::dump(int fd, const Vector<String16>& args) const {
162}
163
164bool JpegProcessor::threadLoop() {
165    status_t res;
166
167    {
168        Mutex::Autolock l(mInputMutex);
169        while (!mCaptureAvailable) {
170            res = mCaptureAvailableSignal.waitRelative(mInputMutex,
171                    kWaitDuration);
172            if (res == TIMED_OUT) return true;
173        }
174        mCaptureAvailable = false;
175    }
176
177    do {
178        sp<Camera2Client> client = mClient.promote();
179        if (client == 0) return false;
180        res = processNewCapture(client);
181    } while (res == OK);
182
183    return true;
184}
185
186status_t JpegProcessor::processNewCapture(sp<Camera2Client> &client) {
187    ATRACE_CALL();
188    status_t res;
189    sp<Camera2Heap> captureHeap;
190
191    CpuConsumer::LockedBuffer imgBuffer;
192
193    res = mCaptureConsumer->lockNextBuffer(&imgBuffer);
194    if (res != OK) {
195        if (res != BAD_VALUE) {
196            ALOGE("%s: Camera %d: Error receiving still image buffer: "
197                    "%s (%d)", __FUNCTION__,
198                    client->getCameraId(), strerror(-res), res);
199        }
200        return res;
201    }
202
203    ALOGV("%s: Camera %d: Still capture available", __FUNCTION__,
204            client->getCameraId());
205
206    // TODO: Signal errors here upstream
207    {
208        SharedParameters::Lock l(client->getParameters());
209
210        switch (l.mParameters.state) {
211            case Parameters::STILL_CAPTURE:
212            case Parameters::VIDEO_SNAPSHOT:
213                break;
214            default:
215                ALOGE("%s: Camera %d: Still image produced unexpectedly "
216                        "in state %s!",
217                        __FUNCTION__, client->getCameraId(),
218                        Parameters::getStateName(l.mParameters.state));
219                mCaptureConsumer->unlockBuffer(imgBuffer);
220                return BAD_VALUE;
221        }
222    }
223
224    if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) {
225        ALOGE("%s: Camera %d: Unexpected format for still image: "
226                "%x, expected %x", __FUNCTION__, client->getCameraId(),
227                imgBuffer.format,
228                HAL_PIXEL_FORMAT_BLOB);
229        mCaptureConsumer->unlockBuffer(imgBuffer);
230        return OK;
231    }
232
233    sp<CaptureSequencer> sequencer = mSequencer.promote();
234    if (sequencer != 0) {
235        sequencer->onCaptureAvailable(imgBuffer.timestamp);
236    }
237
238    // TODO: Optimize this to avoid memcopy
239    void* captureMemory = mCaptureHeap->mHeap->getBase();
240    size_t size = mCaptureHeap->mHeap->getSize();
241    memcpy(captureMemory, imgBuffer.data, size);
242
243    mCaptureConsumer->unlockBuffer(imgBuffer);
244
245    captureHeap = mCaptureHeap;
246
247    Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
248    ALOGV("%s: Sending still image to client", __FUNCTION__);
249    if (l.mCameraClient != 0) {
250        l.mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
251                captureHeap->mBuffers[0], NULL);
252    } else {
253        ALOGV("%s: No client!", __FUNCTION__);
254    }
255    return OK;
256}
257
258}; // namespace camera2
259}; // namespace android
260