Argus Camera Sample
Argus Camera Sample
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
StillCapture.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 
30 #include <sstream>
31 #include <iomanip>
32 #include <unistd.h>
33 
34 #include "StillCapture.h"
35 #include "Composer.h"
36 #include "Dispatcher.h"
37 #include "Error.h"
38 #include "PerfTracker.h"
39 
40 namespace ArgusSamples
41 {
42 
44  : m_initialized(false)
45  , m_running(false)
46  , m_wasRunning(false)
47  , m_prevRunning(false)
48  , m_captureIndex(0)
49 {
50 }
51 
53 {
54  shutdown();
55 }
56 
58 {
59  if (m_initialized)
60  return true;
61 
62  Dispatcher &dispatcher = Dispatcher::getInstance();
63 
64  PROPAGATE_ERROR_CONTINUE(dispatcher.m_deviceOpen.registerObserver(this,
65  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::onDeviceOpenChanged)));
66  PROPAGATE_ERROR_CONTINUE(dispatcher.m_sensorModeValid.registerObserver(this,
67  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::onSensorModeValidChanged)));
68  PROPAGATE_ERROR_CONTINUE(dispatcher.m_outputSize.registerObserver(this,
69  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::restartStreams)));
70 
71  m_perfTracker.reset(new SessionPerfTracker());
72  if (!m_perfTracker)
73  ORIGINATE_ERROR("Out of memory");
74 
75  m_initialized = true;
76 
77  return true;
78 }
79 
80 bool TaskStillCapture::restartStreams(__attribute__((unused)) const Observed &source)
81 {
82  if (m_running)
83  {
84  PROPAGATE_ERROR(stop());
85  PROPAGATE_ERROR(start());
86  }
87  return true;
88 }
89 
90 bool TaskStillCapture::onDeviceOpenChanged(const Observed &source)
91 {
92  const bool isOpen = static_cast<const Value<bool>&>(source).get();
93 
94  // If the current device is closed the request needs to be recreated on the new device. Stop
95  // and then start when the device is opened again.
96  if (!isOpen)
97  {
99  PROPAGATE_ERROR(stop());
100  }
101  else if (m_wasRunning)
102  {
103  m_wasRunning = false;
104  PROPAGATE_ERROR(start());
105  }
106 
107  return true;
108 }
109 
110 bool TaskStillCapture::onSensorModeValidChanged(const Observed &source)
111 {
112  const bool isTrue = static_cast<const Value<bool>&>(source).get();
113 
114  if (!isTrue)
115  {
117  if (m_running)
118  {
119  PROPAGATE_ERROR(stop());
120  }
121  }
122  else if (m_prevRunning)
123  {
124  m_prevRunning = false;
125  PROPAGATE_ERROR(start());
126  }
127 
128  return true;
129 }
130 
132 {
133  if (!m_initialized)
134  ORIGINATE_ERROR("Not initialized");
135 
136  if (m_running)
137  return true;
138 
139  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_TASK_START));
140 
141  Dispatcher &dispatcher = Dispatcher::getInstance();
142  Composer &composer = Composer::getInstance();
143 
144  PROPAGATE_ERROR(dispatcher.createRequest(m_previewRequest, Argus::CAPTURE_INTENT_PREVIEW));
145 
146  // Create the preview stream
147  PROPAGATE_ERROR(dispatcher.createOutputStream(m_previewRequest.get(), false, m_previewStream));
148 
149  Argus::IStream *iStream = Argus::interface_cast<Argus::IStream>(m_previewStream);
150  if (!iStream)
151  ORIGINATE_ERROR("Failed to get IStream interface");
152 
153  // render the preview stream
154  PROPAGATE_ERROR(composer.bindStream(iStream->getEGLStream()));
155 
156  const Argus::Size2D<uint32_t> streamSize = iStream->getResolution();
157  PROPAGATE_ERROR(composer.setStreamAspectRatio(iStream->getEGLStream(),
158  (float)streamSize.width() / (float)streamSize.height()));
159  PROPAGATE_ERROR(composer.setStreamActive(iStream->getEGLStream(), true));
160 
161  // Enable the preview stream
162  PROPAGATE_ERROR(dispatcher.enableOutputStream(m_previewRequest.get(), m_previewStream.get()));
163 
164  // start the repeating request for the preview
165  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_ISSUE_CAPTURE));
166  PROPAGATE_ERROR(dispatcher.startRepeat(m_previewRequest.get()));
167 
168  m_running = true;
169 
170  return true;
171 }
172 
174 {
175  if (!m_initialized)
176  ORIGINATE_ERROR("Not initialized");
177 
178  if (!m_running)
179  return true;
180 
181  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_CLOSE_REQUESTED));
182 
183  Dispatcher &dispatcher = Dispatcher::getInstance();
184 
185  // stop the repeating request
186  PROPAGATE_ERROR(dispatcher.stopRepeat());
187 
188  PROPAGATE_ERROR(dispatcher.waitForIdle());
189  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_FLUSH_DONE));
190 
191  // disable the output stream
192  PROPAGATE_ERROR(dispatcher.disableOutputStream(m_previewRequest.get(), m_previewStream.get()));
193 
194  Argus::IStream *iStream = Argus::interface_cast<Argus::IStream>(m_previewStream);
195  if (!iStream)
196  ORIGINATE_ERROR("Failed to get IStream interface");
197 
198  // disconnect the EGL stream
199  iStream->disconnect();
200 
201  // unbind the preview stream from the composer
202  PROPAGATE_ERROR(Composer::getInstance().unbindStream(iStream->getEGLStream()));
203 
204  // destroy the preview stream
205  m_previewStream.reset();
206 
207  // destroy the preview request
208  PROPAGATE_ERROR(m_previewRequest.reset());
209 
210  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_CLOSE_DONE));
211 
212  m_running = false;
213 
214  return true;
215 }
216 
218 {
219  if (!m_initialized)
220  ORIGINATE_ERROR("Not initialized");
221  if (!m_running)
222  ORIGINATE_ERROR("Not running");
223 
224  Dispatcher &dispatcher = Dispatcher::getInstance();
225 
227  PROPAGATE_ERROR(dispatcher.createRequest(stillRequest, Argus::CAPTURE_INTENT_STILL_CAPTURE));
228 
229  // Create the still stream
230  Argus::UniqueObj<Argus::OutputStream> stillStream;
231  PROPAGATE_ERROR(dispatcher.createOutputStream(stillRequest.get(), true, stillStream));
232 
233  // Enable the still stream
234  PROPAGATE_ERROR(dispatcher.enableOutputStream(stillRequest.get(), stillStream.get()));
235 
236  // Create the frame consumer
237  Argus::UniqueObj<EGLStream::FrameConsumer> consumer(
238  EGLStream::FrameConsumer::create(stillStream.get()));
239  EGLStream::IFrameConsumer *iFrameConsumer =
240  Argus::interface_cast<EGLStream::IFrameConsumer>(consumer);
241  if (!iFrameConsumer)
242  ORIGINATE_ERROR("Failed to create FrameConsumer");
243 
244  // do the capture
245  PROPAGATE_ERROR(dispatcher.capture(stillRequest.get()));
246 
247  // aquire the frame
248  Argus::UniqueObj<EGLStream::Frame> frame(iFrameConsumer->acquireFrame());
249  if (!frame)
250  ORIGINATE_ERROR("Failed to aquire frame");
251 
252  // Use the IFrame interface to provide access to the Image in the Frame.
253  EGLStream::IFrame *iFrame = Argus::interface_cast<EGLStream::IFrame>(frame);
254  if (!iFrame)
255  ORIGINATE_ERROR("Failed to get IFrame interface.");
256 
257  EGLStream::Image *image = iFrame->getImage();
258  if (!image)
259  ORIGINATE_ERROR("Failed to get image.");
260 
261  // Get the JPEG interface.
262  EGLStream::IImageJPEG *iJPEG =
263  Argus::interface_cast<EGLStream::IImageJPEG>(image);
264  if (!iJPEG)
265  ORIGINATE_ERROR("Failed to get IImageJPEG interface.");
266 
267  // build the file name
268  std::ostringstream fileName;
269  fileName << dispatcher.m_outputPath.get();
270  if (dispatcher.m_outputPath.get() != "/dev/null")
271  fileName << "/image" << std::setfill('0') << std::setw(4) << m_captureIndex << ".jpg";
272 
273  // Write a JPEG to disk.
274  if (iJPEG->writeJPEG(fileName.str().c_str()) == Argus::STATUS_OK)
275  {
276  PROPAGATE_ERROR(dispatcher.message("Captured a still image to '%s'\n",
277  fileName.str().c_str()));
278  }
279  else
280  {
281  ORIGINATE_ERROR("Failed to write JPEG to '%s'\n", fileName.str().c_str());
282  }
283 
284  ++m_captureIndex;
285 
286  // release the frame.
287  frame.reset();
288 
289  // destroy the still stream
290  PROPAGATE_ERROR(dispatcher.disableOutputStream(stillRequest.get(), stillStream.get()));
291  stillStream.reset();
292 
293  // destroy the still request
294  PROPAGATE_ERROR(stillRequest.reset());
295 
296  // destroy the still consumer
297  consumer.reset();
298 
299  return true;
300 }
301 
303 {
304  if (!m_initialized)
305  return true;
306 
307  // stop the module
308  PROPAGATE_ERROR_CONTINUE(stop());
309 
310  PROPAGATE_ERROR_CONTINUE(m_perfTracker->shutdown());
311  m_perfTracker.reset();
312 
313  Dispatcher &dispatcher = Dispatcher::getInstance();
314 
315  PROPAGATE_ERROR_CONTINUE(dispatcher.m_outputSize.unregisterObserver(this,
316  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::restartStreams)));
317  PROPAGATE_ERROR_CONTINUE(dispatcher.m_sensorModeValid.unregisterObserver(this,
318  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::onSensorModeValidChanged)));
319  PROPAGATE_ERROR_CONTINUE(dispatcher.m_deviceOpen.unregisterObserver(this,
320  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::onDeviceOpenChanged)));
321 
322  m_initialized = false;
323 
324  return true;
325 }
326 
327 }; // namespace ArgusSamples