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