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-2018, 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(dispatcher.m_deviceOpen.registerObserver(this,
65  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::onDeviceOpenChanged)));
66  PROPAGATE_ERROR(dispatcher.m_sensorModeValid.registerObserver(this,
67  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::onSensorModeValidChanged)));
68  PROPAGATE_ERROR(dispatcher.m_outputSize.registerObserver(this,
69  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::restartStreams)));
70  PROPAGATE_ERROR(dispatcher.m_captureYuvFormat.registerObserver(this,
71  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::restartStreams)));
72 
73 
74  m_perfTracker.reset(new SessionPerfTracker());
75  if (!m_perfTracker)
76  ORIGINATE_ERROR("Out of memory");
77 
78  m_initialized = true;
79 
80  return true;
81 }
82 
83 bool TaskStillCapture::restartStreams(__attribute__((unused)) const Observed &source)
84 {
85  if (m_running)
86  {
87  PROPAGATE_ERROR(stop());
88  PROPAGATE_ERROR(start());
89  }
90  return true;
91 }
92 
93 bool TaskStillCapture::onDeviceOpenChanged(const Observed &source)
94 {
95  const bool isOpen = static_cast<const Value<bool>&>(source).get();
96 
97  // If the current device is closed the request needs to be recreated on the new device. Stop
98  // and then start when the device is opened again.
99  if (!isOpen)
100  {
102  PROPAGATE_ERROR(stop());
103  }
104  else if (m_wasRunning)
105  {
106  m_wasRunning = false;
107  PROPAGATE_ERROR(start());
108  }
109 
110  return true;
111 }
112 
113 bool TaskStillCapture::onSensorModeValidChanged(const Observed &source)
114 {
115  const bool isTrue = static_cast<const Value<bool>&>(source).get();
116 
117  if (!isTrue)
118  {
120  if (m_running)
121  {
122  PROPAGATE_ERROR(stop());
123  }
124  }
125  else if (m_prevRunning)
126  {
127  m_prevRunning = false;
128  PROPAGATE_ERROR(start());
129  }
130 
131  return true;
132 }
133 
135 {
136  if (!m_initialized)
137  ORIGINATE_ERROR("Not initialized");
138 
139  if (m_running)
140  return true;
141 
142  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_TASK_START));
143 
144  Dispatcher &dispatcher = Dispatcher::getInstance();
145  Composer &composer = Composer::getInstance();
146 
147  PROPAGATE_ERROR(dispatcher.createRequest(m_previewRequest, Argus::CAPTURE_INTENT_PREVIEW));
148 
149  // Create the preview stream
150  PROPAGATE_ERROR(dispatcher.createOutputStream(m_previewRequest.get(), false, m_previewStream));
151 
152  Argus::IEGLOutputStream *iEGLOutputStream =
153  Argus::interface_cast<Argus::IEGLOutputStream>(m_previewStream);
154  if (!iEGLOutputStream)
155  ORIGINATE_ERROR("Failed to get IEGLOutputStream interface");
156 
157  // render the preview stream
158  PROPAGATE_ERROR(composer.bindStream(iEGLOutputStream->getEGLStream()));
159 
160  const Argus::Size2D<uint32_t> streamSize = iEGLOutputStream->getResolution();
161  PROPAGATE_ERROR(composer.setStreamAspectRatio(iEGLOutputStream->getEGLStream(),
162  (float)streamSize.width() / (float)streamSize.height()));
163  PROPAGATE_ERROR(composer.setStreamActive(iEGLOutputStream->getEGLStream(), true));
164 
165  // Enable the preview stream
166  PROPAGATE_ERROR(dispatcher.enableOutputStream(m_previewRequest.get(), m_previewStream.get()));
167 
168  // start the repeating request for the preview
169  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_ISSUE_CAPTURE));
170  PROPAGATE_ERROR(dispatcher.startRepeat(m_previewRequest.get()));
171 
172  m_running = true;
173 
174  return true;
175 }
176 
178 {
179  if (!m_initialized)
180  ORIGINATE_ERROR("Not initialized");
181 
182  if (!m_running)
183  return true;
184 
185  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_CLOSE_REQUESTED));
186 
187  Dispatcher &dispatcher = Dispatcher::getInstance();
188 
189  // stop the repeating request
190  PROPAGATE_ERROR(dispatcher.stopRepeat());
191 
192  PROPAGATE_ERROR(dispatcher.waitForIdle());
193  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_FLUSH_DONE));
194 
195  // disable the output stream
196  PROPAGATE_ERROR(dispatcher.disableOutputStream(m_previewRequest.get(), m_previewStream.get()));
197 
198  Argus::IEGLOutputStream *iEGLOutputStream =
199  Argus::interface_cast<Argus::IEGLOutputStream>(m_previewStream);
200  if (!iEGLOutputStream)
201  ORIGINATE_ERROR("Failed to get IEGLOutputStream interface");
202 
203  // disconnect the EGL stream
204  iEGLOutputStream->disconnect();
205 
206  // unbind the preview stream from the composer
207  PROPAGATE_ERROR(Composer::getInstance().unbindStream(iEGLOutputStream->getEGLStream()));
208 
209  // destroy the preview stream
210  m_previewStream.reset();
211 
212  // destroy the preview request
213  PROPAGATE_ERROR(m_previewRequest.reset());
214 
215  PROPAGATE_ERROR(m_perfTracker->onEvent(SESSION_EVENT_CLOSE_DONE));
216 
217  m_running = false;
218 
219  return true;
220 }
221 
223 {
224  if (!m_initialized)
225  ORIGINATE_ERROR("Not initialized");
226  if (!m_running)
227  ORIGINATE_ERROR("Not running");
228 
229  Dispatcher &dispatcher = Dispatcher::getInstance();
230 
232  PROPAGATE_ERROR(dispatcher.createRequest(stillRequest, Argus::CAPTURE_INTENT_STILL_CAPTURE));
233 
234  // Create the still stream
235  Argus::UniqueObj<Argus::OutputStream> stillStream;
236  PROPAGATE_ERROR(dispatcher.createOutputStream(stillRequest.get(), true, stillStream));
237 
238  // Enable the still stream
239  PROPAGATE_ERROR(dispatcher.enableOutputStream(stillRequest.get(), stillStream.get()));
240 
241  // Create the frame consumer
242  Argus::UniqueObj<EGLStream::FrameConsumer> consumer(
243  EGLStream::FrameConsumer::create(stillStream.get()));
244  EGLStream::IFrameConsumer *iFrameConsumer =
245  Argus::interface_cast<EGLStream::IFrameConsumer>(consumer);
246  if (!iFrameConsumer)
247  ORIGINATE_ERROR("Failed to create FrameConsumer");
248 
249  // do the capture
250  PROPAGATE_ERROR(dispatcher.capture(stillRequest.get()));
251 
252  // aquire the frame
253  Argus::UniqueObj<EGLStream::Frame> frame(iFrameConsumer->acquireFrame());
254  if (!frame)
255  ORIGINATE_ERROR("Failed to aquire frame");
256 
257  // Use the IFrame interface to provide access to the Image in the Frame.
258  EGLStream::IFrame *iFrame = Argus::interface_cast<EGLStream::IFrame>(frame);
259  if (!iFrame)
260  ORIGINATE_ERROR("Failed to get IFrame interface.");
261 
262  EGLStream::Image *image = iFrame->getImage();
263  if (!image)
264  ORIGINATE_ERROR("Failed to get image.");
265 
266  switch (dispatcher.m_stillFileType.get())
267  {
268  case STILL_FILE_TYPE_JPG:
269  {
270  // Get the JPEG interface.
271  EGLStream::IImageJPEG *iJPEG =
272  Argus::interface_cast<EGLStream::IImageJPEG>(image);
273  if (!iJPEG)
274  ORIGINATE_ERROR("Failed to get IImageJPEG interface.");
275 
276  // build the file name
277  std::ostringstream fileName;
278  fileName << dispatcher.m_outputPath.get();
279  if (dispatcher.m_outputPath.get() != "/dev/null")
280  fileName << "/image" << std::setfill('0') << std::setw(4) <<
281  m_captureIndex << ".jpg";
282 
283  PROPAGATE_ERROR(validateOutputPath(fileName.str().c_str()));
284 
285  // Write a JPEG to disk.
286  if (iJPEG->writeJPEG(fileName.str().c_str()) == Argus::STATUS_OK)
287  {
288  PROPAGATE_ERROR(dispatcher.message("Captured a still image to '%s'\n",
289  fileName.str().c_str()));
290  }
291  else
292  {
293  ORIGINATE_ERROR("Failed to write JPEG to '%s'\n", fileName.str().c_str());
294  }
295  }
296  break;
297 
299  {
300  // Get the HEADERLESS_FILE interface.
301  EGLStream::IImageHeaderlessFile *iHeaderlessFile =
302  Argus::interface_cast<EGLStream::IImageHeaderlessFile>(image);
303  if (!iHeaderlessFile)
304  ORIGINATE_ERROR("Failed to get IImageHeaderlessFile interface.");
305 
306  EGLStream::IImage2D *i2D =
307  Argus::interface_cast<EGLStream::IImage2D>(image);
308  if (!i2D)
309  ORIGINATE_ERROR("Failed to get IImage2D interface.");
310  const Argus::Size2D<uint32_t> size = i2D->getSize();
311 
312  // build the file name
313  std::ostringstream fileName;
314  fileName << dispatcher.m_outputPath.get();
315  if (dispatcher.m_outputPath.get() != "/dev/null")
316  {
317  fileName << "/image_" <<
318  size.width() << "x" << size.height() << "_" <<
319  std::setfill('0') << std::setw(4) << m_captureIndex <<
320  "." << dispatcher.m_captureYuvFormat.toString();
321  }
322 
323  PROPAGATE_ERROR(validateOutputPath(fileName.str().c_str()));
324 
325  // Write a headerless, unencoded image to disk.
326  if (iHeaderlessFile->writeHeaderlessFile(fileName.str().c_str()) == Argus::STATUS_OK)
327  {
328  PROPAGATE_ERROR(dispatcher.message("Captured a still image to '%s'\n",
329  fileName.str().c_str()));
330  }
331  else
332  {
333  ORIGINATE_ERROR("Failed to write headerless raw image to '%s'\n",
334  fileName.str().c_str());
335  }
336  }
337  break;
338 
339  default:
340  ORIGINATE_ERROR("unknown still image file type");
341  }
342 
343  ++m_captureIndex;
344 
345  // release the frame.
346  frame.reset();
347 
348  // destroy the still stream
349  PROPAGATE_ERROR(dispatcher.disableOutputStream(stillRequest.get(), stillStream.get()));
350  stillStream.reset();
351 
352  // destroy the still request
353  PROPAGATE_ERROR(stillRequest.reset());
354 
355  // destroy the still consumer
356  consumer.reset();
357 
358  return true;
359 }
360 
362 {
363  if (!m_initialized)
364  return true;
365 
366  // stop the module
367  PROPAGATE_ERROR_CONTINUE(stop());
368 
369  PROPAGATE_ERROR_CONTINUE(m_perfTracker->shutdown());
370  m_perfTracker.reset();
371 
372  Dispatcher &dispatcher = Dispatcher::getInstance();
373 
374  PROPAGATE_ERROR_CONTINUE(dispatcher.m_outputSize.unregisterObserver(this,
375  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::restartStreams)));
376  PROPAGATE_ERROR_CONTINUE(dispatcher.m_sensorModeValid.unregisterObserver(this,
377  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::onSensorModeValidChanged)));
378  PROPAGATE_ERROR_CONTINUE(dispatcher.m_deviceOpen.unregisterObserver(this,
379  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::onDeviceOpenChanged)));
380  PROPAGATE_ERROR_CONTINUE(dispatcher.m_captureYuvFormat.unregisterObserver(this,
381  static_cast<IObserver::CallbackFunction>(&TaskStillCapture::restartStreams)));
382 
383  m_initialized = false;
384 
385  return true;
386 }
387 
388 }; // namespace ArgusSamples