Argus Camera Sample
Argus Camera Sample
 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 
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 
55 {
56  shutdown();
57 }
58 
60 {
61 }
62 
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 
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 
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 
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 
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  {
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 
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 
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