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::IEGLOutputStream *iEGLOutputStream =
99 Argus::interface_cast<Argus::IEGLOutputStream>(m_outputStream.get());
100 if (!iEGLOutputStream)
101 ORIGINATE_ERROR("Failed to get IEGLOuptutStream interface");
102
103 // Bind the stream to the composer
104 PROPAGATE_ERROR(composer.bindStream(iEGLOutputStream->getEGLStream()));
105
106 const Argus::Size2D<uint32_t> streamSize = iEGLOutputStream->getResolution();
107 PROPAGATE_ERROR(composer.setStreamAspectRatio(iEGLOutputStream->getEGLStream(),
108 (float)streamSize.width() / (float)streamSize.height()));
109
110 // Enable the output stream
111 PROPAGATE_ERROR(dispatcher.enableOutputStream(m_request.get(), m_outputStream.get()));
112
113 return true;
114 }
115
116 bool TaskMultiExposure::ExpLevel::shutdown()
117 {
118 if (m_request)
119 {
120 Dispatcher &dispatcher = Dispatcher::getInstance();
121 Composer &composer = Composer::getInstance();
122
123 if (m_outputStream)
124 {
125 // disable the output stream
126 PROPAGATE_ERROR_CONTINUE(dispatcher.disableOutputStream(m_request.get(),
127 m_outputStream.get()));
128
129 Argus::IEGLOutputStream *iEGLOutputStream =
130 Argus::interface_cast<Argus::IEGLOutputStream>(m_outputStream);
131 if (!iEGLOutputStream)
132 REPORT_ERROR("Failed to get IEGLOutputStream interface");
133
134 // disconnect the EGL stream
135 iEGLOutputStream->disconnect();
136
137 // unbind the EGL stream from the composer
138 PROPAGATE_ERROR_CONTINUE(composer.unbindStream(iEGLOutputStream->getEGLStream()));
139
140 m_outputStream.reset();
141 }
142
143 // destroy the request
144 PROPAGATE_ERROR_CONTINUE(m_request.reset());
145 }
146
147 return true;
148 }
149
150 bool TaskMultiExposure::initialize()
151 {
152 if (m_initialized)
153 return true;
154
155 Dispatcher &dispatcher = Dispatcher::getInstance();
156
157 m_initialized = true;
158
159 // register the device observers after 'm_initialize' is set, the call back will be
160 // called immediately and assert that 'm_initialize' is set
161 PROPAGATE_ERROR(dispatcher.m_deviceOpen.registerObserver(this,
162 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onDeviceOpenChanged)));
163 PROPAGATE_ERROR(dispatcher.m_sensorModeValid.registerObserver(this,
164 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onSensorModeValidChanged)));
165 PROPAGATE_ERROR(dispatcher.m_outputSize.registerObserver(this,
166 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::restartStreams)));
167 PROPAGATE_ERROR(m_exposureRange.registerObserver(this,
168 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
169 PROPAGATE_ERROR(m_exposureSteps.registerObserver(this,
170 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
171 PROPAGATE_ERROR(dispatcher.m_captureYuvFormat.registerObserver(this,
172 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::restartStreams)));
173
174 return true;
175 }
176
177 bool TaskMultiExposure::shutdown()
178 {
179 if (!m_initialized)
180 return true;
181
182 // stop the preview
183 PROPAGATE_ERROR(stop());
184
185 Dispatcher &dispatcher = Dispatcher::getInstance();
186
187 PROPAGATE_ERROR_CONTINUE(m_exposureSteps.unregisterObserver(this,
188 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
189 PROPAGATE_ERROR_CONTINUE(m_exposureRange.unregisterObserver(this,
190 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
191 PROPAGATE_ERROR_CONTINUE(dispatcher.m_outputSize.unregisterObserver(this,
192 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::restartStreams)));
193 PROPAGATE_ERROR_CONTINUE(dispatcher.m_sensorModeValid.unregisterObserver(this,
194 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onSensorModeValidChanged)));
195 PROPAGATE_ERROR_CONTINUE(dispatcher.m_deviceOpen.unregisterObserver(this,
196 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onDeviceOpenChanged)));
197 PROPAGATE_ERROR_CONTINUE(dispatcher.m_captureYuvFormat.unregisterObserver(this,
198 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::restartStreams)));
199
200 m_initialized = false;
201
202 return true;
203 }
204
205 bool TaskMultiExposure::shutdownExpLevels()
206 {
207 if (!m_expLevels.empty())
208 {
209 // shutdown the exposure streams
210 for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
211 {
212 ExpLevel *expLevel = *it;
213 PROPAGATE_ERROR_CONTINUE(expLevel->shutdown());
214 delete expLevel;
215 }
216 m_expLevels.clear();
217 }
218
219 return true;
220 }
221
222 bool TaskMultiExposure::restartStreams(__attribute__((unused)) const Observed &source)
223 {
224 if (m_running)
225 {
226 PROPAGATE_ERROR(stop());
227 PROPAGATE_ERROR(start());
228 }
229 return true;
230 }
231
232 bool TaskMultiExposure::onDeviceOpenChanged(const Observed &source)
233 {
234 const bool isOpen = static_cast<const Value<bool>&>(source).get();
235
236 // If the current device is closed the request needs to be recreated on the new device. Stop
237 // and then start when the device is opened again.
238 if (!isOpen)
239 {
240 m_wasRunning = m_running;
241 PROPAGATE_ERROR(stop());
242 }
243 else
244 {
245 PROPAGATE_ERROR(m_exposureStepsRange.set(
246 Argus::Range<uint32_t>(2, Dispatcher::getInstance().maxBurstRequests())));
247
248 if (m_wasRunning)
249 {
250 m_wasRunning = false;
251 PROPAGATE_ERROR(start());
252 }
253 }
254
255 return true;
256 }
257
258 bool TaskMultiExposure::onSensorModeValidChanged(const Observed &source)
259 {
260 const bool isTrue = static_cast<const Value<bool>&>(source).get();
261
262 if (!isTrue)
263 {
264 m_prevRunning = m_running;
265 if (m_running)
266 {
267 PROPAGATE_ERROR(stop());
268 }
269 }
270 else if (m_prevRunning)
271 {
272 m_prevRunning = false;
273 PROPAGATE_ERROR(start());
274 }
275
276 return true;
277 }
278
279 bool TaskMultiExposure::onParametersChanged(const Observed &source)
280 {
281 assert(m_initialized);
282
283 // if preview is running, stop, shutdown levels, set the new value and start again
284 const bool wasRunning = m_running;
285 PROPAGATE_ERROR(stop());
286 PROPAGATE_ERROR(shutdownExpLevels());
287
288 if (wasRunning)
289 PROPAGATE_ERROR(start());
290
291 return true;
292 }
293
294 bool TaskMultiExposure::start()
295 {
296 if (!m_initialized)
297 ORIGINATE_ERROR("Not initialized");
298 if (m_running)
299 return true;
300
301 if (m_expLevels.empty())
302 {
303 std::ostringstream message;
304
305 message << "Creating " << m_exposureSteps << " streams with exposure compensation set to ";
306
307 // create a request and streams for each exposure level
308 for (uint32_t requestIndex = 0; requestIndex < m_exposureSteps; ++requestIndex)
309 {
310 UniquePointer<ExpLevel> expLevel(new ExpLevel);
311
312 if (!expLevel)
313 ORIGINATE_ERROR("Out of memory");
314
315 const float exposureCompensation =
316 ((float)requestIndex / (float)(m_exposureSteps - 1)) *
317 (m_exposureRange.get().max() - m_exposureRange.get().min()) +
318 m_exposureRange.get().min();
319
320 PROPAGATE_ERROR(expLevel->initialize(exposureCompensation));
321
322 m_expLevels.push_back(expLevel.release());
323
324 if (requestIndex != 0)
325 message << ", ";
326 message << exposureCompensation << " ev";
327 }
328
329 message << ". " << std::endl;
330 Dispatcher::getInstance().message(message.str().c_str());
331 }
332
333 // activate the streams and populate the burst request array
334 std::vector<const Argus::Request*> requests;
335 Composer &composer = Composer::getInstance();
336 for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
337 {
338 ExpLevel *expLevel = *it;
339 PROPAGATE_ERROR(composer.setStreamActive(
340 Argus::interface_cast<Argus::IEGLOutputStream>
341 (expLevel->m_outputStream)->getEGLStream(), true));
342 requests.push_back(expLevel->m_request.get());
343 }
344
345 // start the repeating burst request for the preview
346 PROPAGATE_ERROR(Dispatcher::getInstance().startRepeatBurst(requests));
347
348 m_running = true;
349
350 return true;
351 }
352
353 bool TaskMultiExposure::stop()
354 {
355 if (!m_initialized)
356 ORIGINATE_ERROR("Not initialized");
357 if (!m_running)
358 return true;
359
360 // stop the repeating burst request
361 Dispatcher &dispatcher = Dispatcher::getInstance();
362 PROPAGATE_ERROR(dispatcher.stopRepeat());
363
364 // de-activate the streams
365 Composer &composer = Composer::getInstance();
366 for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
367 {
368 ExpLevel *expLevel = *it;
369 PROPAGATE_ERROR(composer.setStreamActive(
370 Argus::interface_cast<Argus::IEGLOutputStream>
371 (expLevel->m_outputStream)->getEGLStream(), false));
372 }
373
374 PROPAGATE_ERROR(dispatcher.waitForIdle());
375
376 PROPAGATE_ERROR(shutdownExpLevels());
377
378 m_running = false;
379
380 return true;
381 }
382
383 }; // namespace ArgusSamples