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