• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <map>
22 #include <utils/Log.h>
23 #include <utils/Trace.h>
24 
25 #include "common/FrameProducer.h"
26 #include "common/FrameProcessorBase.h"
27 
28 namespace android {
29 namespace camera2 {
30 
FrameProcessorBase(wp<FrameProducer> device)31 FrameProcessorBase::FrameProcessorBase(wp<FrameProducer> device) :
32     Thread(/*canCallJava*/false),
33     mDevice(device),
34     mNumPartialResults(1) {
35     sp<FrameProducer> cameraDevice = device.promote();
36     if (cameraDevice != 0) {
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 
~FrameProcessorBase()45 FrameProcessorBase::~FrameProcessorBase() {
46     ALOGV("%s: Exit", __FUNCTION__);
47 }
48 
registerListener(int32_t minId,int32_t maxId,const wp<FilteredListener> & listener,bool sendPartials)49 status_t FrameProcessorBase::registerListener(int32_t minId,
50         int32_t maxId, const 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 
removeListener(int32_t minId,int32_t maxId,const wp<FilteredListener> & listener)71 status_t FrameProcessorBase::removeListener(int32_t minId,
72                                            int32_t maxId,
73                                            const 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 
dump(int fd,const Vector<String16> &)88 void 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     std::map<std::string, CameraMetadata> lastPhysicalFrames;
94     {
95         // Don't race while dumping metadata
96         Mutex::Autolock al(mLastFrameMutex);
97         lastFrame = CameraMetadata(mLastFrame);
98 
99         for (const auto& physicalFrame : mLastPhysicalFrames) {
100             lastPhysicalFrames.emplace(String8(physicalFrame.mPhysicalCameraId),
101                     physicalFrame.mPhysicalCameraMetadata);
102         }
103     }
104     lastFrame.dump(fd, /*verbosity*/2, /*indentation*/6);
105 
106     for (const auto& physicalFrame : lastPhysicalFrames) {
107         result = String8::format("   Latest received frame for physical camera %s:\n",
108                 physicalFrame.first.c_str());
109         write(fd, result.string(), result.size());
110         CameraMetadata lastPhysicalMetadata = CameraMetadata(physicalFrame.second);
111         lastPhysicalMetadata.sort();
112         lastPhysicalMetadata.dump(fd, /*verbosity*/2, /*indentation*/6);
113     }
114 }
115 
threadLoop()116 bool FrameProcessorBase::threadLoop() {
117     status_t res;
118 
119     sp<FrameProducer> device;
120     {
121         device = mDevice.promote();
122         if (device == 0) return false;
123     }
124 
125     res = device->waitForNextFrame(kWaitDuration);
126     if (res == OK) {
127         processNewFrames(device);
128     } else if (res != TIMED_OUT) {
129         ALOGE("FrameProcessorBase: Error waiting for new "
130                 "frames: %s (%d)", strerror(-res), res);
131     }
132 
133     return true;
134 }
135 
processNewFrames(const sp<FrameProducer> & device)136 void FrameProcessorBase::processNewFrames(const sp<FrameProducer> &device) {
137     status_t res;
138     ATRACE_CALL();
139     CaptureResult result;
140 
141     ALOGV("%s: Camera %s: Process new frames", __FUNCTION__, device->getId().string());
142 
143     while ( (res = device->getNextResult(&result)) == OK) {
144 
145         // TODO: instead of getting frame number from metadata, we should read
146         // this from result.mResultExtras when FrameProducer interface is fixed.
147         camera_metadata_entry_t entry;
148 
149         entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
150         if (entry.count == 0) {
151             ALOGE("%s: Camera %s: Error reading frame number",
152                     __FUNCTION__, device->getId().string());
153             break;
154         }
155         ATRACE_INT("cam2_frame", entry.data.i32[0]);
156 
157         if (!processSingleFrame(result, device)) {
158             break;
159         }
160 
161         if (!result.mMetadata.isEmpty()) {
162             Mutex::Autolock al(mLastFrameMutex);
163             mLastFrame.acquire(result.mMetadata);
164 
165             mLastPhysicalFrames = std::move(result.mPhysicalMetadatas);
166         }
167     }
168     if (res != NOT_ENOUGH_DATA) {
169         ALOGE("%s: Camera %s: Error getting next frame: %s (%d)",
170                 __FUNCTION__, device->getId().string(), strerror(-res), res);
171         return;
172     }
173 
174     return;
175 }
176 
processSingleFrame(CaptureResult & result,const sp<FrameProducer> & device)177 bool FrameProcessorBase::processSingleFrame(CaptureResult &result,
178                                             const sp<FrameProducer> &device) {
179     ALOGV("%s: Camera %s: Process single frame (is empty? %d)",
180             __FUNCTION__, device->getId().string(), result.mMetadata.isEmpty());
181     return processListeners(result, device) == OK;
182 }
183 
processListeners(const CaptureResult & result,const sp<FrameProducer> & device)184 status_t FrameProcessorBase::processListeners(const CaptureResult &result,
185         const sp<FrameProducer> &device) {
186     ATRACE_CALL();
187 
188     camera_metadata_ro_entry_t entry;
189 
190     // Check if this result is partial.
191     bool isPartialResult =
192             result.mResultExtras.partialResultCount < mNumPartialResults;
193 
194     // TODO: instead of getting requestID from CameraMetadata, we should get it
195     // from CaptureResultExtras. This will require changing Camera2Device.
196     // Currently Camera2Device uses MetadataQueue to store results, which does not
197     // include CaptureResultExtras.
198     entry = result.mMetadata.find(ANDROID_REQUEST_ID);
199     if (entry.count == 0) {
200         ALOGE("%s: Camera %s: Error reading frame id", __FUNCTION__, device->getId().string());
201         return BAD_VALUE;
202     }
203     int32_t requestId = entry.data.i32[0];
204 
205     List<sp<FilteredListener> > listeners;
206     {
207         Mutex::Autolock l(mInputMutex);
208 
209         List<RangeListener>::iterator item = mRangeListeners.begin();
210         // Don't deliver partial results to listeners that don't want them
211         while (item != mRangeListeners.end()) {
212             if (requestId >= item->minId && requestId < item->maxId &&
213                     (!isPartialResult || item->sendPartials)) {
214                 sp<FilteredListener> listener = item->listener.promote();
215                 if (listener == 0) {
216                     item = mRangeListeners.erase(item);
217                     continue;
218                 } else {
219                     listeners.push_back(listener);
220                 }
221             }
222             item++;
223         }
224     }
225     ALOGV("%s: Camera %s: Got %zu range listeners out of %zu", __FUNCTION__,
226           device->getId().string(), listeners.size(), mRangeListeners.size());
227 
228     List<sp<FilteredListener> >::iterator item = listeners.begin();
229     for (; item != listeners.end(); item++) {
230         (*item)->onResultAvailable(result);
231     }
232     return OK;
233 }
234 
235 }; // namespace camera2
236 }; // namespace android
237