Argus Camera Sample
Argus Camera Sample
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
MultiSession.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 "MultiSession.h"
32 #include "Composer.h"
33 #include "Dispatcher.h"
34 #include "Error.h"
35 #include "UniquePointer.h"
36 #include "PerfTracker.h"
37 #include <algorithm>
38 
39 namespace ArgusSamples
40 {
41 
43  : m_initialized(false)
44  , m_running(false)
45  , m_prevRunning(false)
46 {
47 }
48 
50 {
51  shutdown();
52 }
53 
55 {
56 }
57 
59 {
60  shutdown();
61 }
62 
63 bool TaskMultiSession::Session::initialize(uint32_t deviceIndex)
64 {
65  // create the perf tracker
66  m_perfTracker.reset(new SessionPerfTracker());
67  if (!m_perfTracker)
68  ORIGINATE_ERROR("Out of memory");
69 
70  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_TASK_START));
71 
72  Composer &composer = Composer::getInstance();
73  Dispatcher &dispatcher = Dispatcher::getInstance();
74 
75  // create the session using the current device index
76  PROPAGATE_ERROR(dispatcher.createSession(m_session, deviceIndex));
77  PROPAGATE_ERROR(m_perfTracker->setSession(m_session.get()));
78 
79  // create the request
80  PROPAGATE_ERROR(dispatcher.createRequest(m_request, Argus::CAPTURE_INTENT_STILL_CAPTURE,
81  m_session.get()));
82 
83  // Create the preview stream
84  PROPAGATE_ERROR(dispatcher.createOutputStream(m_request.get(), false, m_outputStream,
85  m_session.get()));
86 
87  // bind the preview stream to the composer
88  Argus::IEGLOutputStream *iEGLOutputStream =
89  Argus::interface_cast<Argus::IEGLOutputStream>(m_outputStream.get());
90  if (!iEGLOutputStream)
91  ORIGINATE_ERROR("Failed to get IEGLOutputStream interface");
92 
93  // Bind the stream to the composer
94  PROPAGATE_ERROR(composer.bindStream(iEGLOutputStream->getEGLStream()));
95 
96  const Argus::Size2D<uint32_t> streamSize = iEGLOutputStream->getResolution();
97  PROPAGATE_ERROR(composer.setStreamAspectRatio(iEGLOutputStream->getEGLStream(),
98  (float)streamSize.width() / (float)streamSize.height()));
99 
100  // Enable the output stream
101  PROPAGATE_ERROR(dispatcher.enableOutputStream(m_request.get(), m_outputStream.get()));
102 
103  return true;
104 }
105 
107 {
108  Composer &composer = Composer::getInstance();
109 
110  // activate the streams and populate the burst request array
111  PROPAGATE_ERROR(composer.setStreamActive(
112  Argus::interface_cast<Argus::IEGLOutputStream>(m_outputStream)->getEGLStream(), true));
113 
114  // start the repeating burst request for the preview
115  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_ISSUE_CAPTURE));
116  PROPAGATE_ERROR(Dispatcher::getInstance().startRepeat(m_request.get(), m_session.get()));
117 
118  return true;
119 }
120 
122 {
123  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_CLOSE_REQUESTED));
124 
125  Dispatcher &dispatcher = Dispatcher::getInstance();
126  Composer &composer = Composer::getInstance();
127 
128  PROPAGATE_ERROR(dispatcher.stopRepeat(m_session.get()));
129  PROPAGATE_ERROR(composer.setStreamActive(
130  Argus::interface_cast<Argus::IEGLOutputStream>(m_outputStream)->getEGLStream(), false));
131  PROPAGATE_ERROR(dispatcher.waitForIdle(m_session.get()));
132  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_FLUSH_DONE));
133 
134  return true;
135 }
136 
138 {
139  if (m_request)
140  {
141  Dispatcher &dispatcher = Dispatcher::getInstance();
142  Composer &composer = Composer::getInstance();
143 
144  if (m_outputStream)
145  {
146  // destroy the producer
147  PROPAGATE_ERROR_CONTINUE(dispatcher.disableOutputStream(m_request.get(),
148  m_outputStream.get()));
149 
150  Argus::IEGLOutputStream *iEGLOutputStream =
151  Argus::interface_cast<Argus::IEGLOutputStream>(m_outputStream);
152  if (!iEGLOutputStream)
153  REPORT_ERROR("Failed to get IEGLOutputStream interface");
154 
155  // disconnect the EGL stream
156  iEGLOutputStream->disconnect();
157 
158  // unbind the EGL stream from the composer
159  PROPAGATE_ERROR_CONTINUE(composer.unbindStream(iEGLOutputStream->getEGLStream()));
160 
161  m_outputStream.reset();
162  }
163 
164  // destroy the request
165  PROPAGATE_ERROR_CONTINUE(m_request.reset());
166  }
167 
168  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_CLOSE_DONE));
169 
170  // Destroy the session
171  m_session.reset();
172 
173  return true;
174 }
175 
177 {
178  if (m_initialized)
179  return true;
180 
181  PROPAGATE_ERROR(Dispatcher::getInstance().m_sensorModeValid.registerObserver(this,
182  static_cast<IObserver::CallbackFunction>(&TaskMultiSession::onSensorModeValidChanged)));
183  PROPAGATE_ERROR(Dispatcher::getInstance().m_outputSize.registerObserver(this,
184  static_cast<IObserver::CallbackFunction>(&TaskMultiSession::restartStreams)));
185 
186  m_initialized = true;
187 
188  return true;
189 }
190 
192 {
193  if (!m_initialized)
194  return true;
195 
196  // stop the preview
197  PROPAGATE_ERROR(stop());
198 
199  PROPAGATE_ERROR_CONTINUE(Dispatcher::getInstance().m_outputSize.unregisterObserver(this,
200  static_cast<IObserver::CallbackFunction>(&TaskMultiSession::restartStreams)));
201  PROPAGATE_ERROR_CONTINUE(Dispatcher::getInstance().m_sensorModeValid.unregisterObserver(this,
202  static_cast<IObserver::CallbackFunction>(&TaskMultiSession::onSensorModeValidChanged)));
203 
204  m_initialized = false;
205 
206  return true;
207 }
208 
210 {
211  if (!m_sessions.empty())
212  {
213  // shutdown the sessions
214  for (std::list<Session*>::iterator it = m_sessions.begin(); it != m_sessions.end(); ++it)
215  {
216  Session *session = *it;
217  PROPAGATE_ERROR_CONTINUE(session->shutdown());
218  delete session;
219  }
220  m_sessions.clear();
221  }
222 
223  return true;
224 }
225 
227 {
228  if (m_running)
229  return true;
230 
231  Dispatcher &dispatcher = Dispatcher::getInstance();
232 
233  if (m_sessions.empty())
234  {
235  const uint32_t deviceCount = dispatcher.getDeviceCount();
236 
237  if (deviceCount == 0)
238  ORIGINATE_ERROR("No camera devices found");
239 
240  std::vector<uint32_t> devices;
241 
242  if (m_multiDevices.get().size() > 0)
243  {
244  // m_multiDevices will not be changed by UI
245  // it has special validation requirements, so validate m_multiDevices here
246  devices = m_multiDevices.get();
247  std::sort(devices.begin(), devices.end());
248 
249  // compare with deviceCount
250  if (devices.back() >= deviceCount)
251  ORIGINATE_ERROR("index %u is out of range [0 - %u)", devices.back(), deviceCount);
252 
253  // check no duplicate
254  std::vector<uint32_t>::iterator it = std::unique(devices.begin(), devices.end());
255  if (it != devices.end())
256  ORIGINATE_ERROR("duplicated indexes");
257  }
258  else
259  {
260  // use all available camera devices
261  for (uint32_t deviceIndex = 0; deviceIndex < deviceCount; ++deviceIndex)
262  {
263  devices.push_back(deviceIndex);
264  }
265  }
266 
267  // create a request and streams for each session
268  for (std::vector<uint32_t>::iterator it = devices.begin(); it != devices.end(); ++it)
269  {
270  UniquePointer<Session> session(new Session);
271 
272  if (!session)
273  ORIGINATE_ERROR("Out of memory");
274 
275  PROPAGATE_ERROR(session->initialize(*it));
276 
277  m_sessions.push_back(session.release());
278  }
279  }
280 
281  // start the sessions
282  for (std::list<Session*>::iterator it = m_sessions.begin(); it != m_sessions.end(); ++it)
283  {
284  Session *session = *it;
285  PROPAGATE_ERROR(session->start());
286  }
287 
288  m_running = true;
289 
290  return true;
291 }
292 
294 {
295  if (!m_running)
296  return true;
297 
298  for (std::list<Session*>::iterator it = m_sessions.begin(); it != m_sessions.end(); ++it)
299  {
300  Session *session = *it;
301  PROPAGATE_ERROR(session->stop());
302  }
303 
304  PROPAGATE_ERROR(shutdownSessions());
305 
306  m_running = false;
307 
308  return true;
309 }
310 
311 bool TaskMultiSession::onSensorModeValidChanged(const Observed &source)
312 {
313  const bool isTrue = static_cast<const Value<bool>&>(source).get();
314 
315  if (!isTrue)
316  {
318  if (m_running)
319  {
320  PROPAGATE_ERROR(stop());
321  }
322  }
323  else if (m_prevRunning)
324  {
325  m_prevRunning = false;
326  PROPAGATE_ERROR(start());
327  }
328 
329  return true;
330 }
331 
332 bool TaskMultiSession::restartStreams(__attribute__((unused)) const Observed &source)
333 {
334  if (m_running)
335  {
336  PROPAGATE_ERROR(stop());
337  PROPAGATE_ERROR(start());
338  }
339  return true;
340 }
341 
342 }; // namespace ArgusSamples