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