Argus Camera Sample Argus Camera Sample

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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
43 TaskStillCapture::TaskStillCapture()
44 : m_initialized(false)
45 , m_running(false)
46 , m_wasRunning(false)
47 , m_prevRunning(false)
48 , m_captureIndex(0)
49 {
50 }
51
52 TaskStillCapture::~TaskStillCapture()
53 {
54 shutdown();
55 }
56
57 bool TaskStillCapture::initialize()
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 {
98 m_wasRunning = m_running;
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 {
116 m_prevRunning = m_running;
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
131 bool TaskStillCapture::start()
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
173 bool TaskStillCapture::stop()
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
217 bool TaskStillCapture::execute()
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
226 TrackedUniqueObj<Argus::Request> stillRequest;
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
302 bool TaskStillCapture::shutdown()
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