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, 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
42 TaskStillCapture::TaskStillCapture()
43 : m_initialized(false)
44 , m_running(false)
45 , m_wasRunning(false)
46 , m_captureIndex(0)
47 , m_eventThread(NULL)
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 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 {
77 m_wasRunning = m_running;
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
89 bool TaskStillCapture::start()
90 {
91 if (!m_initialized)
92 ORIGINATE_ERROR("Not initialized");
93 if (m_running)
94 return true;
95
96 m_perfTracker.onEvent(TASK_START);
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::Size 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
137 m_perfTracker.onEvent(ISSUE_CAPTURE);
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
146 bool TaskStillCapture::stop()
147 {
148 if (!m_initialized)
149 ORIGINATE_ERROR("Not initialized");
150 if (!m_running)
151 return true;
152
153 m_perfTracker.onEvent(CLOSE_REQUESTED);
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());
168 m_perfTracker.onEvent(FLUSH_DONE);
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(dispatcher.destroyRequest(m_previewRequest));
182
183 m_perfTracker.onEvent(CLOSE_DONE);
184
185 m_running = false;
186
187 return true;
188 }
189
190 bool TaskStillCapture::execute()
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
199 Argus::UniqueObj<Argus::Request> stillRequest;
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(dispatcher.destroyRequest(stillRequest));
268
269 // destroy the still consumer
270 consumer.reset();
271
272 return true;
273 }
274
275 bool TaskStillCapture::shutdown()
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