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