Argus Camera Sample Argus Camera Sample

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MultiExposure.cpp
Go to the documentation of this file.
1 /*
2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of NVIDIA CORPORATION nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sstream>
30
31 #include "MultiExposure.h"
32 #include "Composer.h"
33 #include "Dispatcher.h"
34 #include "Error.h"
35 #include "UniquePointer.h"
36
37 namespace ArgusSamples
38 {
39
40 TaskMultiExposure::TaskMultiExposure()
41 : m_exposureStepsRange(3)
42 , m_exposureSteps(new ValidatorRange<uint32_t>(&m_exposureStepsRange), 3)
43 , m_exposureRange(
44 new ValidatorRange<Argus::Range<float> >(
45 Argus::Range<float>(-10.0f, 10.0f),
46 Argus::Range<float>(-10.0f, 10.0f)),
47 Argus::Range<float>(-2.0f, 2.0f))
48 , m_initialized(false)
49 , m_running(false)
50 , m_wasRunning(false)
51 , m_prevRunning(false)
52 {
53 }
54
55 TaskMultiExposure::~TaskMultiExposure()
56 {
57 shutdown();
58 }
59
60 TaskMultiExposure::ExpLevel::ExpLevel()
61 {
62 }
63
64 TaskMultiExposure::ExpLevel::~ExpLevel()
65 {
66 shutdown();
67 }
68
69 bool TaskMultiExposure::ExpLevel::initialize(float exposureCompensation)
70 {
71 Composer &composer = Composer::getInstance();
72 Dispatcher &dispatcher = Dispatcher::getInstance();
73
74 // create the request
75 PROPAGATE_ERROR(dispatcher.createRequest(m_request, Argus::CAPTURE_INTENT_STILL_CAPTURE));
76
77 Argus::IRequest *iRequest = Argus::interface_cast<Argus::IRequest>(m_request.get());
78 if (!iRequest)
79 ORIGINATE_ERROR("Failed to get IRequest interface");
80
81 // get the autocontrol settings and set the exposure compensation value
82 Argus::IAutoControlSettings *iAutoControlSettings =
83 Argus::interface_cast<Argus::IAutoControlSettings>(iRequest->getAutoControlSettings());
84 if (!iAutoControlSettings)
85 ORIGINATE_ERROR("Failed to get IAutoControlSettings interface");
86
87 // lock AE
88 if (iAutoControlSettings->setAeLock(true) != Argus::STATUS_OK)
89 ORIGINATE_ERROR("Failed to set AE lock");
90
91 // set exposure compensation value
92 if (iAutoControlSettings->setExposureCompensation(exposureCompensation) != Argus::STATUS_OK)
93 ORIGINATE_ERROR("Failed to set exposure compensation");
94
95 // Create the preview stream
96 PROPAGATE_ERROR(dispatcher.createOutputStream(m_request.get(), false, m_outputStream));
97
98 Argus::IStream *iStream = Argus::interface_cast<Argus::IStream>(m_outputStream.get());
99 if (!iStream)
100 ORIGINATE_ERROR("Failed to get IStream interface");
101
102 // Bind the stream to the composer
103 PROPAGATE_ERROR(composer.bindStream(iStream->getEGLStream()));
104
105 const Argus::Size2D<uint32_t> streamSize = iStream->getResolution();
106 PROPAGATE_ERROR(composer.setStreamAspectRatio(iStream->getEGLStream(),
107 (float)streamSize.width() / (float)streamSize.height()));
108
109 // Enable the output stream
110 PROPAGATE_ERROR(dispatcher.enableOutputStream(m_request.get(), m_outputStream.get()));
111
112 return true;
113 }
114
115 bool TaskMultiExposure::ExpLevel::shutdown()
116 {
117 if (m_request)
118 {
119 Dispatcher &dispatcher = Dispatcher::getInstance();
120 Composer &composer = Composer::getInstance();
121
122 if (m_outputStream)
123 {
124 // disable the output stream
125 PROPAGATE_ERROR_CONTINUE(dispatcher.disableOutputStream(m_request.get(),
126 m_outputStream.get()));
127
128 Argus::IStream *iStream = Argus::interface_cast<Argus::IStream>(m_outputStream);
129 if (!iStream)
130 REPORT_ERROR("Failed to get IStream interface");
131
132 // disconnect the EGL stream
133 iStream->disconnect();
134
135 // unbind the EGL stream from the composer
136 PROPAGATE_ERROR_CONTINUE(composer.unbindStream(iStream->getEGLStream()));
137
138 m_outputStream.reset();
139 }
140
141 // destroy the request
142 PROPAGATE_ERROR_CONTINUE(m_request.reset());
143 }
144
145 return true;
146 }
147
148 bool TaskMultiExposure::initialize()
149 {
150 if (m_initialized)
151 return true;
152
153 Dispatcher &dispatcher = Dispatcher::getInstance();
154
155 m_initialized = true;
156
157 // register the device observers after 'm_initialize' is set, the call back will be
158 // called immediately and assert that 'm_initialize' is set
159 PROPAGATE_ERROR_CONTINUE(dispatcher.m_deviceOpen.registerObserver(this,
160 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onDeviceOpenChanged)));
161 PROPAGATE_ERROR_CONTINUE(dispatcher.m_sensorModeValid.registerObserver(this,
162 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onSensorModeValidChanged)));
163 PROPAGATE_ERROR_CONTINUE(dispatcher.m_outputSize.registerObserver(this,
164 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::restartStreams)));
165 PROPAGATE_ERROR_CONTINUE(m_exposureRange.registerObserver(this,
166 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
167 PROPAGATE_ERROR_CONTINUE(m_exposureSteps.registerObserver(this,
168 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
169
170 return true;
171 }
172
173 bool TaskMultiExposure::shutdown()
174 {
175 if (!m_initialized)
176 return true;
177
178 // stop the preview
179 PROPAGATE_ERROR(stop());
180
181 Dispatcher &dispatcher = Dispatcher::getInstance();
182
183 PROPAGATE_ERROR_CONTINUE(m_exposureSteps.unregisterObserver(this,
184 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
185 PROPAGATE_ERROR_CONTINUE(m_exposureRange.unregisterObserver(this,
186 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
187 PROPAGATE_ERROR_CONTINUE(dispatcher.m_outputSize.unregisterObserver(this,
188 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::restartStreams)));
189 PROPAGATE_ERROR_CONTINUE(dispatcher.m_sensorModeValid.unregisterObserver(this,
190 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onSensorModeValidChanged)));
191 PROPAGATE_ERROR_CONTINUE(dispatcher.m_deviceOpen.unregisterObserver(this,
192 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onDeviceOpenChanged)));
193
194 m_initialized = false;
195
196 return true;
197 }
198
199 bool TaskMultiExposure::shutdownExpLevels()
200 {
201 if (!m_expLevels.empty())
202 {
203 // shutdown the exposure streams
204 for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
205 {
206 ExpLevel *expLevel = *it;
207 PROPAGATE_ERROR_CONTINUE(expLevel->shutdown());
208 delete expLevel;
209 }
210 m_expLevels.clear();
211 }
212
213 return true;
214 }
215
216 bool TaskMultiExposure::restartStreams(__attribute__((unused)) const Observed &source)
217 {
218 if (m_running)
219 {
220 PROPAGATE_ERROR(stop());
221 PROPAGATE_ERROR(start());
222 }
223 return true;
224 }
225
226 bool TaskMultiExposure::onDeviceOpenChanged(const Observed &source)
227 {
228 const bool isOpen = static_cast<const Value<bool>&>(source).get();
229
230 // If the current device is closed the request needs to be recreated on the new device. Stop
231 // and then start when the device is opened again.
232 if (!isOpen)
233 {
234 m_wasRunning = m_running;
235 PROPAGATE_ERROR(stop());
236 }
237 else
238 {
239 PROPAGATE_ERROR(m_exposureStepsRange.set(
240 Argus::Range<uint32_t>(2, Dispatcher::getInstance().maxBurstRequests())));
241
242 if (m_wasRunning)
243 {
244 m_wasRunning = false;
245 PROPAGATE_ERROR(start());
246 }
247 }
248
249 return true;
250 }
251
252 bool TaskMultiExposure::onSensorModeValidChanged(const Observed &source)
253 {
254 const bool isTrue = static_cast<const Value<bool>&>(source).get();
255
256 if (!isTrue)
257 {
258 m_prevRunning = m_running;
259 if (m_running)
260 {
261 PROPAGATE_ERROR(stop());
262 }
263 }
264 else if (m_prevRunning)
265 {
266 m_prevRunning = false;
267 PROPAGATE_ERROR(start());
268 }
269
270 return true;
271 }
272
273 bool TaskMultiExposure::onParametersChanged(const Observed &source)
274 {
275 assert(m_initialized);
276
277 // if preview is running, stop, shutdown levels, set the new value and start again
278 const bool wasRunning = m_running;
279 PROPAGATE_ERROR(stop());
280 PROPAGATE_ERROR(shutdownExpLevels());
281
282 if (wasRunning)
283 PROPAGATE_ERROR(start());
284
285 return true;
286 }
287
288 bool TaskMultiExposure::start()
289 {
290 if (!m_initialized)
291 ORIGINATE_ERROR("Not initialized");
292 if (m_running)
293 return true;
294
295 if (m_expLevels.empty())
296 {
297 std::ostringstream message;
298
299 message << "Creating " << m_exposureSteps << " streams with exposure compensation set to ";
300
301 // create a request and streams for each exposure level
302 for (uint32_t requestIndex = 0; requestIndex < m_exposureSteps; ++requestIndex)
303 {
304 UniquePointer<ExpLevel> expLevel(new ExpLevel);
305
306 if (!expLevel)
307 ORIGINATE_ERROR("Out of memory");
308
309 const float exposureCompensation =
310 ((float)requestIndex / (float)(m_exposureSteps - 1)) *
311 (m_exposureRange.get().max() - m_exposureRange.get().min()) +
312 m_exposureRange.get().min();
313
314 PROPAGATE_ERROR(expLevel->initialize(exposureCompensation));
315
316 m_expLevels.push_back(expLevel.release());
317
318 if (requestIndex != 0)
319 message << ", ";
320 message << exposureCompensation << " ev";
321 }
322
323 message << ". " << std::endl;
324 Dispatcher::getInstance().message(message.str().c_str());
325 }
326
327 // activate the streams and populate the burst request array
328 std::vector<const Argus::Request*> requests;
329 Composer &composer = Composer::getInstance();
330 for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
331 {
332 ExpLevel *expLevel = *it;
333 PROPAGATE_ERROR(composer.setStreamActive(
334 Argus::interface_cast<Argus::IStream>(expLevel->m_outputStream)->getEGLStream(), true));
335 requests.push_back(expLevel->m_request.get());
336 }
337
338 // start the repeating burst request for the preview
339 PROPAGATE_ERROR(Dispatcher::getInstance().startRepeatBurst(requests));
340
341 m_running = true;
342
343 return true;
344 }
345
346 bool TaskMultiExposure::stop()
347 {
348 if (!m_initialized)
349 ORIGINATE_ERROR("Not initialized");
350 if (!m_running)
351 return true;
352
353 // stop the repeating burst request
354 Dispatcher &dispatcher = Dispatcher::getInstance();
355 PROPAGATE_ERROR(dispatcher.stopRepeat());
356
357 // de-activate the streams
358 Composer &composer = Composer::getInstance();
359 for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
360 {
361 ExpLevel *expLevel = *it;
362 PROPAGATE_ERROR(composer.setStreamActive(
363 Argus::interface_cast<Argus::IStream>(expLevel->m_outputStream)->getEGLStream(), false));
364 }
365
366 PROPAGATE_ERROR(dispatcher.waitForIdle());
367
368 PROPAGATE_ERROR(shutdownExpLevels());
369
370 m_running = false;
371
372 return true;
373 }
374
375 }; // namespace ArgusSamples