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_captureIndex(0)
48 {
49 }
50
51 TaskStillCapture::~TaskStillCapture()
52 {
53 shutdown();
54 }
55
56 bool TaskStillCapture::initialize()
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 {
97 m_wasRunning = m_running;
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
109 bool TaskStillCapture::start()
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
151 bool TaskStillCapture::stop()
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
195 bool TaskStillCapture::execute()
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
204 TrackedUniqueObj<Argus::Request> stillRequest;
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
280 bool TaskStillCapture::shutdown()
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