Argus Camera Sample
Argus Camera Sample
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
VideoRecord.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 
32 #include "VideoRecord.h"
33 #include "Renderer.h"
34 #include "Dispatcher.h"
35 #include "Error.h"
36 #include "EventThread.h"
37 
38 namespace ArgusSamples
39 {
40 
42  : m_initialized(false)
43  , m_running(false)
44  , m_wasRunning(false)
45  , m_recording(false)
46  , m_captureIndex(0)
47  , m_videoPipeline(NULL)
48  , m_eventThread(NULL)
49 {
50 }
51 
53 {
54  shutdown();
55 }
56 
58 {
59  if (m_initialized)
60  return true;
61 
62  PROPAGATE_ERROR_CONTINUE(Dispatcher::getInstance().m_deviceOpen.registerObserver(this,
63  static_cast<IObserver::CallbackFunction>(&TaskVideoRecord::onDeviceOpenChanged)));
64 
65  m_initialized = true;
66 
67  return true;
68 }
69 
70 bool TaskVideoRecord::onDeviceOpenChanged(const Observed &source)
71 {
72  const bool isOpen = static_cast<const Value<bool>&>(source).get();
73 
74  // If the current device is closed the request needs to be recreated on the new device. Stop
75  // and then start when the device is opened again.
76  if (!isOpen)
77  {
79  PROPAGATE_ERROR(stop());
80  }
81  else if (m_wasRunning)
82  {
83  m_wasRunning = false;
84  PROPAGATE_ERROR(start());
85  }
86 
87  return true;
88 }
89 
91 {
92  if (!m_initialized)
93  ORIGINATE_ERROR("Not initialized");
94  if (m_running)
95  return true;
96 
98 
99  Dispatcher &dispatcher = Dispatcher::getInstance();
100  Renderer &renderer = Renderer::getInstance();
101 
102  PROPAGATE_ERROR(dispatcher.createRequest(m_request, Argus::CAPTURE_INTENT_VIDEO_RECORD));
103 
104  // Create the preview stream
105  PROPAGATE_ERROR(dispatcher.createOutputStream(m_request.get(), m_previewStream));
106 
107  // bind the preview stream to the renderer
108  Argus::IStream *iStream = Argus::interface_cast<Argus::IStream>(m_previewStream.get());
109  if (!iStream)
110  ORIGINATE_ERROR("Failed to get IStream interface");
111 
112  PROPAGATE_ERROR(renderer.bindStream(iStream->getEGLStream()));
113 
114  // Enable the preview stream
115  PROPAGATE_ERROR(dispatcher.enableOutputStream(m_request.get(), m_previewStream.get()));
116 
117  const Argus::Size streamSize = iStream->getResolution();
118  PROPAGATE_ERROR(renderer.setStreamAspectRatio(iStream->getEGLStream(),
119  (float)streamSize.width / (float)streamSize.height));
120  PROPAGATE_ERROR(renderer.setStreamActive(iStream->getEGLStream(), true));
121 
122  // create the event thread
123  std::vector<Argus::EventType> eventTypes;
124  eventTypes.push_back(Argus::EVENT_TYPE_CAPTURE_COMPLETE);
125 
126  Argus::UniqueObj<Argus::EventQueue> eventQueue;
127  PROPAGATE_ERROR(dispatcher.createEventQueue(eventTypes, eventQueue));
128 
129  // pass ownership of eventQueue to EventThread
130  m_eventThread.reset(new EventThread(NULL, eventQueue.release(), &m_perfTracker));
131  if (!m_eventThread)
132  {
133  ORIGINATE_ERROR("Failed to allocate EventThread");
134  }
135 
136  PROPAGATE_ERROR(m_eventThread->initialize());
137  PROPAGATE_ERROR(m_eventThread->waitRunning());
138 
140  // start the preview
141  PROPAGATE_ERROR(dispatcher.startRepeat(m_request.get()));
142 
143  m_running = true;
144 
145  return true;
146 }
147 
149 {
150  if (!m_initialized)
151  ORIGINATE_ERROR("Not initialized");
152  if (!m_running)
153  return true;
154 
156 
157  PROPAGATE_ERROR(m_eventThread->shutdown());
158  m_eventThread.reset();
159 
160  if (m_recording)
161  PROPAGATE_ERROR(stopRecording());
162 
163  Dispatcher &dispatcher = Dispatcher::getInstance();
164  Renderer &renderer = Renderer::getInstance();
165 
166  // stop the repeating request
167  PROPAGATE_ERROR(dispatcher.stopRepeat());
168 
169  PROPAGATE_ERROR(renderer.setStreamActive(
170  Argus::interface_cast<Argus::IStream>(m_previewStream)->getEGLStream(), false));
171 
172  PROPAGATE_ERROR(dispatcher.waitForIdle());
174 
175  if (m_previewStream)
176  {
177  if (m_request)
178  PROPAGATE_ERROR(dispatcher.disableOutputStream(m_request.get(), m_previewStream.get()));
179 
180  const EGLStreamKHR eglStream =
181  Argus::interface_cast<Argus::IStream>(m_previewStream)->getEGLStream();
182 
183  m_previewStream.reset();
184 
185  // unbind the preview stream from the renderer
186  PROPAGATE_ERROR_CONTINUE(renderer.unbindStream(eglStream));
187 
188  }
189  PROPAGATE_ERROR_CONTINUE(dispatcher.destroyRequest(m_request));
190 
191  m_running = false;
193 
194  return true;
195 }
196 
198 {
199  if (!m_initialized)
200  ORIGINATE_ERROR("Not initialized");
201  if (!m_running)
202  ORIGINATE_ERROR("Not running");
203  if (m_recording)
204  ORIGINATE_ERROR("Recording had already been started, can't start again");
205 
206  Dispatcher &dispatcher = Dispatcher::getInstance();
207 
208  // setup the video pipeline with the video stream
210  if (!m_videoPipeline)
211  ORIGINATE_ERROR("Out of memory");
212 
213  // Create the video output stream
214  PROPAGATE_ERROR(dispatcher.createOutputStream(m_request.get(), m_videoStream));
215 
216  Argus::Size outputSize;
217  PROPAGATE_ERROR(dispatcher.getOutputSize(&outputSize));
218 
219  // build the file name
220  std::ostringstream fileName;
221  fileName << dispatcher.m_outputPath.get();
222  if (dispatcher.m_outputPath.get() != "/dev/null")
223  fileName << "/video" << std::setfill('0') << std::setw(4) << m_captureIndex;
224  ++m_captureIndex;
225 
226  PROPAGATE_ERROR(m_videoPipeline->setupForRecording(
227  Argus::interface_cast<Argus::IStream>(m_videoStream)->getEGLStream(),
228  outputSize.width, outputSize.height,
229  dispatcher.m_frameRate.get(), fileName.str().c_str(), dispatcher.m_videoFormat.get(),
230  dispatcher.m_videoFileType.get(), dispatcher.m_videoBitRate.get()));
231 
232  // start recording
233  PROPAGATE_ERROR(m_videoPipeline->start());
234 
235  // Enable the video output stream
236  PROPAGATE_ERROR(dispatcher.enableOutputStream(m_request.get(), m_videoStream.get()));
237 
238  // restart the repeating request to ensure the changed request is executed
239  PROPAGATE_ERROR(dispatcher.startRepeat(m_request.get()));
240 
241  PROPAGATE_ERROR(dispatcher.message("Started recording video at %dx%d, saving to '%s'\n",
242  outputSize.width, outputSize.height, fileName.str().c_str()));
243 
244  m_recording = true;
245 
246  return true;
247 }
248 
250 {
251  if (!m_initialized)
252  ORIGINATE_ERROR("Not initialized");
253 
254  if (!m_recording)
255  ORIGINATE_ERROR("Recording had not been started, can't stop");
256 
257  Dispatcher &dispatcher = Dispatcher::getInstance();
258 
259  // stop the repeating request
260  PROPAGATE_ERROR(dispatcher.stopRepeat());
261 
262  // stop recording
263  PROPAGATE_ERROR(m_videoPipeline->stop());
264 
265  // Wait until all pending captures are done before destroying the stream
266  PROPAGATE_ERROR(dispatcher.waitForIdle());
267 
268  if (m_videoStream)
269  {
270  // disable the output stream
271  PROPAGATE_ERROR(dispatcher.disableOutputStream(m_request.get(), m_videoStream.get()));
272  m_videoStream.reset();
273  }
274 
275  // start the repeating request again to get the preview working
276  PROPAGATE_ERROR(dispatcher.startRepeat(m_request.get()));
277 
278  if (m_videoPipeline)
279  {
280  // destroy the video pipeline
281  PROPAGATE_ERROR(m_videoPipeline->destroy());
282  delete m_videoPipeline;
283  m_videoPipeline = NULL;
284  }
285 
286  PROPAGATE_ERROR(dispatcher.message("Stopped recording video\n"));
287 
288  m_recording = false;
289 
290  return true;
291 }
292 
294 {
295  if (m_recording)
296  PROPAGATE_ERROR(stopRecording());
297  else
298  PROPAGATE_ERROR(startRecording());
299  return true;
300 }
301 
303 {
304  if (!m_initialized)
305  return true;
306 
307  PROPAGATE_ERROR(stop());
308 
309  PROPAGATE_ERROR_CONTINUE(Dispatcher::getInstance().m_deviceOpen.unregisterObserver(this,
310  static_cast<IObserver::CallbackFunction>(&TaskVideoRecord::onDeviceOpenChanged)));
311 
312  m_initialized = false;
313 
314  return true;
315 }
316 
317 }; // namespace ArgusSamples