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