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, 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 "Renderer.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_captureIndex(0)
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 Renderer &renderer = Renderer::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);
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(), 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 renderer
103 PROPAGATE_ERROR(renderer.bindStream(iStream->getEGLStream()));
104
105 const Argus::Size streamSize = iStream->getResolution();
106 PROPAGATE_ERROR(renderer.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
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 const EGLStreamKHR eglStream =
128 Argus::interface_cast<Argus::IStream>(m_outputStream)->getEGLStream();
129
130 m_outputStream.reset();
131
132 // unbind the EGL stream from the renderer
133 PROPAGATE_ERROR_CONTINUE(Renderer::getInstance().unbindStream(eglStream));
134 }
135
136 // destroy the request
137 PROPAGATE_ERROR_CONTINUE(dispatcher.destroyRequest(m_request));
138 }
139
140 return true;
141 }
142
143 bool TaskMultiExposure::initialize()
144 {
145 if (m_initialized)
146 return true;
147
148 Dispatcher &dispatcher = Dispatcher::getInstance();
149
150 PROPAGATE_ERROR_CONTINUE(dispatcher.m_deviceOpen.registerObserver(this,
151 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onDeviceOpenChanged)));
152
153 m_initialized = true;
154
155 // register the device observers after 'm_initialize' is set, the call back will be
156 // called immediately and assert that 'm_initialize' is set
157 PROPAGATE_ERROR_CONTINUE(m_exposureRange.registerObserver(this,
158 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
159 PROPAGATE_ERROR_CONTINUE(m_exposureSteps.registerObserver(this,
160 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
161
162 return true;
163 }
164
165 bool TaskMultiExposure::shutdown()
166 {
167 if (!m_initialized)
168 return true;
169
170 // stop the preview
171 PROPAGATE_ERROR(stop());
172
173 PROPAGATE_ERROR_CONTINUE(Dispatcher::getInstance().m_deviceOpen.unregisterObserver(this,
174 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onDeviceOpenChanged)));
175 PROPAGATE_ERROR_CONTINUE(m_exposureRange.unregisterObserver(this,
176 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
177 PROPAGATE_ERROR_CONTINUE(m_exposureSteps.unregisterObserver(this,
178 static_cast<IObserver::CallbackFunction>(&TaskMultiExposure::onParametersChanged)));
179
180 m_initialized = false;
181
182 return true;
183 }
184
185 bool TaskMultiExposure::shutdownExpLevels()
186 {
187 if (!m_expLevels.empty())
188 {
189 // shutdown the exposure streams
190 for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
191 {
192 ExpLevel *expLevel = *it;
193 PROPAGATE_ERROR_CONTINUE(expLevel->shutdown());
194 delete expLevel;
195 }
196 m_expLevels.clear();
197 }
198
199 return true;
200 }
201
202 bool TaskMultiExposure::onDeviceOpenChanged(const Observed &source)
203 {
204 const bool isOpen = static_cast<const Value<bool>&>(source).get();
205
206 // If the current device is closed the request needs to be recreated on the new device. Stop
207 // and then start when the device is opened again.
208 if (!isOpen)
209 {
210 m_wasRunning = m_running;
211 PROPAGATE_ERROR(stop());
212 }
213 else
214 {
215 uint32_t maxBurstRequests = Dispatcher::getInstance().maxBurstRequests();
216 PROPAGATE_ERROR(m_exposureStepsRange.set(Argus::Range<uint32_t>(2, maxBurstRequests)));
217
218 if (m_wasRunning)
219 {
220 m_wasRunning = false;
221 PROPAGATE_ERROR(start());
222 }
223 }
224
225 return true;
226 }
227
228 bool TaskMultiExposure::onParametersChanged(const Observed &source)
229 {
230 assert(m_initialized);
231
232 // if preview is running, stop, shutdown levels, set the new value and start again
233 const bool wasRunning = m_running;
234 PROPAGATE_ERROR(stop());
235 PROPAGATE_ERROR(shutdownExpLevels());
236
237 if (wasRunning)
238 PROPAGATE_ERROR(start());
239
240 return true;
241 }
242
243 bool TaskMultiExposure::start()
244 {
245 if (!m_initialized)
246 ORIGINATE_ERROR("Not initialized");
247 if (m_running)
248 return true;
249
250 if (m_expLevels.empty())
251 {
252 std::ostringstream message;
253
254 message << "Creating " << m_exposureSteps << " streams with exposure compensation set to ";
255
256 // create a request and streams for each exposure level
257 for (uint32_t requestIndex = 0; requestIndex < m_exposureSteps; ++requestIndex)
258 {
259 UniquePointer<ExpLevel> expLevel(new ExpLevel);
260
261 if (!expLevel)
262 ORIGINATE_ERROR("Out of memory");
263
264 const float exposureCompensation =
265 ((float)requestIndex / (float)(m_exposureSteps - 1)) *
266 (m_exposureRange.get().max - m_exposureRange.get().min) + m_exposureRange.get().min;
267
268 PROPAGATE_ERROR(expLevel->initialize(exposureCompensation));
269
270 m_expLevels.push_back(expLevel.release());
271
272 if (requestIndex != 0)
273 message << ", ";
274 message << exposureCompensation << " ev";
275 }
276
277 message << ". " << std::endl;
278 Dispatcher::getInstance().message(message.str().c_str());
279 }
280
281 // activate the streams and populate the burst request array
282 std::vector<const Argus::Request*> requests;
283 Renderer &renderer = Renderer::getInstance();
284 for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
285 {
286 ExpLevel *expLevel = *it;
287 PROPAGATE_ERROR(renderer.setStreamActive(
288 Argus::interface_cast<Argus::IStream>(expLevel->m_outputStream)->getEGLStream(), true));
289 requests.push_back(expLevel->m_request.get());
290 }
291
292 // start the repeating burst request for the preview
293 PROPAGATE_ERROR(Dispatcher::getInstance().startRepeatBurst(requests));
294
295 m_running = true;
296
297 return true;
298 }
299
300 bool TaskMultiExposure::stop()
301 {
302 if (!m_initialized)
303 ORIGINATE_ERROR("Not initialized");
304 if (!m_running)
305 return true;
306
307 // stop the repeating burst request
308 Dispatcher &dispatcher = Dispatcher::getInstance();
309 PROPAGATE_ERROR(dispatcher.stopRepeat());
310
311 // de-activate the streams
312 Renderer &renderer = Renderer::getInstance();
313 for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
314 {
315 ExpLevel *expLevel = *it;
316 PROPAGATE_ERROR(renderer.setStreamActive(
317 Argus::interface_cast<Argus::IStream>(expLevel->m_outputStream)->getEGLStream(), false));
318 }
319
320 PROPAGATE_ERROR(dispatcher.waitForIdle());
321
322 PROPAGATE_ERROR(shutdownExpLevels());
323
324 m_running = false;
325
326 return true;
327 }
328
329 }; // namespace ArgusSamples