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-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
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(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 {
101 m_wasRunning = m_running;
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 {
119 m_prevRunning = m_running;
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
134 bool TaskStillCapture::start()
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
177 bool TaskStillCapture::stop()
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
222 bool TaskStillCapture::execute()
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
231 TrackedUniqueObj<Argus::Request> stillRequest;
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
298 case STILL_FILE_TYPE_HEADERLESS:
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
361 bool TaskStillCapture::shutdown()
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