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