1/*
2 * Copyright (C) 2013 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 "Camera2-FrameProcessorBase"
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 "common/FrameProcessorBase.h"
25#include "common/CameraDeviceBase.h"
26
27namespace android {
28namespace camera2 {
29
30FrameProcessorBase::FrameProcessorBase(wp<CameraDeviceBase> device) :
31    Thread(/*canCallJava*/false),
32    mDevice(device),
33    mNumPartialResults(1) {
34    sp<CameraDeviceBase> cameraDevice = device.promote();
35    if (cameraDevice != 0 &&
36            cameraDevice->getDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_2) {
37        CameraMetadata staticInfo = cameraDevice->info();
38        camera_metadata_entry_t entry = staticInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
39        if (entry.count > 0) {
40            mNumPartialResults = entry.data.i32[0];
41        }
42    }
43}
44
45FrameProcessorBase::~FrameProcessorBase() {
46    ALOGV("%s: Exit", __FUNCTION__);
47}
48
49status_t FrameProcessorBase::registerListener(int32_t minId,
50        int32_t maxId, wp<FilteredListener> listener, bool sendPartials) {
51    Mutex::Autolock l(mInputMutex);
52    List<RangeListener>::iterator item = mRangeListeners.begin();
53    while (item != mRangeListeners.end()) {
54        if (item->minId == minId &&
55                item->maxId == maxId &&
56                item->listener == listener) {
57            // already registered, just return
58            ALOGV("%s: Attempt to register the same client twice, ignoring",
59                    __FUNCTION__);
60            return OK;
61        }
62        item++;
63    }
64    ALOGV("%s: Registering listener for frame id range %d - %d",
65            __FUNCTION__, minId, maxId);
66    RangeListener rListener = { minId, maxId, listener, sendPartials };
67    mRangeListeners.push_back(rListener);
68    return OK;
69}
70
71status_t FrameProcessorBase::removeListener(int32_t minId,
72                                           int32_t maxId,
73                                           wp<FilteredListener> listener) {
74    Mutex::Autolock l(mInputMutex);
75    List<RangeListener>::iterator item = mRangeListeners.begin();
76    while (item != mRangeListeners.end()) {
77        if (item->minId == minId &&
78                item->maxId == maxId &&
79                item->listener == listener) {
80            item = mRangeListeners.erase(item);
81        } else {
82            item++;
83        }
84    }
85    return OK;
86}
87
88void FrameProcessorBase::dump(int fd, const Vector<String16>& /*args*/) {
89    String8 result("    Latest received frame:\n");
90    write(fd, result.string(), result.size());
91
92    CameraMetadata lastFrame;
93    {
94        // Don't race while dumping metadata
95        Mutex::Autolock al(mLastFrameMutex);
96        lastFrame = CameraMetadata(mLastFrame);
97    }
98    lastFrame.dump(fd, 2, 6);
99}
100
101bool FrameProcessorBase::threadLoop() {
102    status_t res;
103
104    sp<CameraDeviceBase> device;
105    {
106        device = mDevice.promote();
107        if (device == 0) return false;
108    }
109
110    res = device->waitForNextFrame(kWaitDuration);
111    if (res == OK) {
112        processNewFrames(device);
113    } else if (res != TIMED_OUT) {
114        ALOGE("FrameProcessorBase: Error waiting for new "
115                "frames: %s (%d)", strerror(-res), res);
116    }
117
118    return true;
119}
120
121void FrameProcessorBase::processNewFrames(const sp<CameraDeviceBase> &device) {
122    status_t res;
123    ATRACE_CALL();
124    CaptureResult result;
125
126    ALOGV("%s: Camera %d: Process new frames", __FUNCTION__, device->getId());
127
128    while ( (res = device->getNextResult(&result)) == OK) {
129
130        // TODO: instead of getting frame number from metadata, we should read
131        // this from result.mResultExtras when CameraDeviceBase interface is fixed.
132        camera_metadata_entry_t entry;
133
134        entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
135        if (entry.count == 0) {
136            ALOGE("%s: Camera %d: Error reading frame number",
137                    __FUNCTION__, device->getId());
138            break;
139        }
140        ATRACE_INT("cam2_frame", entry.data.i32[0]);
141
142        if (!processSingleFrame(result, device)) {
143            break;
144        }
145
146        if (!result.mMetadata.isEmpty()) {
147            Mutex::Autolock al(mLastFrameMutex);
148            mLastFrame.acquire(result.mMetadata);
149        }
150    }
151    if (res != NOT_ENOUGH_DATA) {
152        ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
153                __FUNCTION__, device->getId(), strerror(-res), res);
154        return;
155    }
156
157    return;
158}
159
160bool FrameProcessorBase::processSingleFrame(CaptureResult &result,
161                                            const sp<CameraDeviceBase> &device) {
162    ALOGV("%s: Camera %d: Process single frame (is empty? %d)",
163          __FUNCTION__, device->getId(), result.mMetadata.isEmpty());
164    return processListeners(result, device) == OK;
165}
166
167status_t FrameProcessorBase::processListeners(const CaptureResult &result,
168        const sp<CameraDeviceBase> &device) {
169    ATRACE_CALL();
170
171    camera_metadata_ro_entry_t entry;
172
173    // Check if this result is partial.
174    bool isPartialResult = false;
175    if (device->getDeviceVersion() >= CAMERA_DEVICE_API_VERSION_3_2) {
176        isPartialResult = result.mResultExtras.partialResultCount < mNumPartialResults;
177    } else {
178        entry = result.mMetadata.find(ANDROID_QUIRKS_PARTIAL_RESULT);
179        if (entry.count != 0 &&
180                entry.data.u8[0] == ANDROID_QUIRKS_PARTIAL_RESULT_PARTIAL) {
181            ALOGV("%s: Camera %d: This is a partial result",
182                    __FUNCTION__, device->getId());
183            isPartialResult = true;
184        }
185    }
186
187    // TODO: instead of getting requestID from CameraMetadata, we should get it
188    // from CaptureResultExtras. This will require changing Camera2Device.
189    // Currently Camera2Device uses MetadataQueue to store results, which does not
190    // include CaptureResultExtras.
191    entry = result.mMetadata.find(ANDROID_REQUEST_ID);
192    if (entry.count == 0) {
193        ALOGE("%s: Camera %d: Error reading frame id", __FUNCTION__, device->getId());
194        return BAD_VALUE;
195    }
196    int32_t requestId = entry.data.i32[0];
197
198    List<sp<FilteredListener> > listeners;
199    {
200        Mutex::Autolock l(mInputMutex);
201
202        List<RangeListener>::iterator item = mRangeListeners.begin();
203        // Don't deliver partial results to listeners that don't want them
204        while (item != mRangeListeners.end()) {
205            if (requestId >= item->minId && requestId < item->maxId &&
206                    (!isPartialResult || item->sendPartials)) {
207                sp<FilteredListener> listener = item->listener.promote();
208                if (listener == 0) {
209                    item = mRangeListeners.erase(item);
210                    continue;
211                } else {
212                    listeners.push_back(listener);
213                }
214            }
215            item++;
216        }
217    }
218    ALOGV("%s: Camera %d: Got %zu range listeners out of %zu", __FUNCTION__,
219          device->getId(), listeners.size(), mRangeListeners.size());
220
221    List<sp<FilteredListener> >::iterator item = listeners.begin();
222    for (; item != listeners.end(); item++) {
223        (*item)->onResultAvailable(result);
224    }
225    return OK;
226}
227
228}; // namespace camera2
229}; // namespace android
230