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, 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 
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 
56 {
57  shutdown();
58 }
59 
61 {
62 }
63 
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.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(), 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::Size2D<uint32_t> 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 
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(m_request.reset());
138  }
139 
140  return true;
141 }
142 
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 
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 
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  {
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 
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()) +
267  m_exposureRange.get().min();
268 
269  PROPAGATE_ERROR(expLevel->initialize(exposureCompensation));
270 
271  m_expLevels.push_back(expLevel.release());
272 
273  if (requestIndex != 0)
274  message << ", ";
275  message << exposureCompensation << " ev";
276  }
277 
278  message << ". " << std::endl;
279  Dispatcher::getInstance().message(message.str().c_str());
280  }
281 
282  // activate the streams and populate the burst request array
283  std::vector<const Argus::Request*> requests;
284  Renderer &renderer = Renderer::getInstance();
285  for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
286  {
287  ExpLevel *expLevel = *it;
288  PROPAGATE_ERROR(renderer.setStreamActive(
289  Argus::interface_cast<Argus::IStream>(expLevel->m_outputStream)->getEGLStream(), true));
290  requests.push_back(expLevel->m_request.get());
291  }
292 
293  // start the repeating burst request for the preview
294  PROPAGATE_ERROR(Dispatcher::getInstance().startRepeatBurst(requests));
295 
296  m_running = true;
297 
298  return true;
299 }
300 
302 {
303  if (!m_initialized)
304  ORIGINATE_ERROR("Not initialized");
305  if (!m_running)
306  return true;
307 
308  // stop the repeating burst request
309  Dispatcher &dispatcher = Dispatcher::getInstance();
310  PROPAGATE_ERROR(dispatcher.stopRepeat());
311 
312  // de-activate the streams
313  Renderer &renderer = Renderer::getInstance();
314  for (std::list<ExpLevel*>::iterator it = m_expLevels.begin(); it != m_expLevels.end(); ++it)
315  {
316  ExpLevel *expLevel = *it;
317  PROPAGATE_ERROR(renderer.setStreamActive(
318  Argus::interface_cast<Argus::IStream>(expLevel->m_outputStream)->getEGLStream(), false));
319  }
320 
321  PROPAGATE_ERROR(dispatcher.waitForIdle());
322 
323  PROPAGATE_ERROR(shutdownExpLevels());
324 
325  m_running = false;
326 
327  return true;
328 }
329 
330 }; // namespace ArgusSamples