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  , m_prevRunning(false)
52 {
53 }
54 
56 {
57  shutdown();
58 }
59 
61 {
62 }
63 
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 
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 
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 
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 
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  {
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 
259 {
260  const bool isTrue = static_cast<const Value<bool>&>(source).get();
261 
262  if (!isTrue)
263  {
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 
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 
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