Argus Camera Sample
Argus Camera Sample
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
AppModuleVideo.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 #include "AppModuleVideo.h"
30 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 
35 #include "Dispatcher.h"
36 #include "Util.h"
37 #include "Error.h"
38 #include "Options.h"
39 #include "ScopedGuard.h"
40 #include "VideoPipeline.h"
41 
42 namespace ArgusSamples
43 {
44 
45 /* static */ bool AppModuleVideo::video(void *userPtr, const char *optArg)
46 {
48  {
49  fprintf(stderr, "------------------------------------------------------\n");
50  fprintf(stderr, "Error: Video recording is not supported on Android due\n");
51  fprintf(stderr, "to the lack of the required gstreamer functionality\n");
52  fprintf(stderr, "------------------------------------------------------\n");
53  ORIGINATE_ERROR("Unsupported function on Android");
54  }
55 
56  AppModuleVideo *module = reinterpret_cast<AppModuleVideo*>(userPtr);
57 
58  const float seconds = atof(optArg);
59  if (seconds <= 0.0f)
60  ORIGINATE_ERROR("'SECONDS' is invalid, must not be less than or equal to zero");
61 
62  // start the video module
63  PROPAGATE_ERROR(module->start());
64  // the scoped guard is used to call the stop function if following calls fail so that
65  // the function is exited with module stopped.
67 
68  const TimeValue endTime = getCurrentTime() + TimeValue::fromSec(seconds);
69 
70  // start the recording
71  PROPAGATE_ERROR(module->m_videoRecord.startRecording());
72  ScopedGuard<TaskVideoRecord> recordingGuard(&module->m_videoRecord,
74 
75  // wait until the time has elapsed
76  while (getCurrentTime() < endTime)
77  {
78  PROPAGATE_ERROR(Window::getInstance().pollEvents());
79  usleep(1000);
80  }
81 
82  // stop recording
83  recordingGuard.cancel();
84  PROPAGATE_ERROR(module->m_videoRecord.stopRecording());
85 
86  // stop the module
87  runningGuard.cancel();
88  PROPAGATE_ERROR(module->stop());
89 
90  return true;
91 }
92 
93 /* static */ bool AppModuleVideo::toggleRecording(void *userPtr, const char *optArg)
94 {
95  AppModuleVideo *module = reinterpret_cast<AppModuleVideo*>(userPtr);
96 
97  PROPAGATE_ERROR(module->m_videoRecord.toggleRecording());
98 
99  return true;
100 }
101 
103  : m_initialized(false)
104  , m_running(false)
105  , m_guiContainerConfig(NULL)
106  , m_guiConfig(NULL)
107 {
108 }
109 
111 {
112  shutdown();
113 }
114 
115 bool AppModuleVideo::initialize(Options &options)
116 {
117  if (m_initialized)
118  return true;
119 
120  PROPAGATE_ERROR(m_videoRecord.initialize());
121 
122  PROPAGATE_ERROR(options.addOption(
123  Options::Option("video", 'v', "DURATION", Options::Option::TYPE_ACTION,
124  "record video for DURATION seconds and save to a file.", video, this)));
125 
126  PROPAGATE_ERROR(options.addOption(
127  createValueOption("videobitrate", 0, "RATE",
128  "set the video bit rate to RATE. If RATE is zero a reasonable default "
129  "is selected.", Dispatcher::getInstance().m_videoBitRate)));
130  PROPAGATE_ERROR(options.addOption(
131  createValueOption("videocontrolrate", 0, "MODE",
132  "set the video bit-rate control method.",
133  Dispatcher::getInstance().m_videoControlRate)));
134  PROPAGATE_ERROR(options.addOption(
135  createValueOption("videotwopassCBR", 0, "ENABLE",
136  "set this flag to enable two pass CBR method for encoding.",
137  Dispatcher::getInstance().m_videoTwoPassCBREnable)));
138  PROPAGATE_ERROR(options.addOption(
139  createValueOption("videoformat", 0, "FORMAT",
140  "set the video format. Jetson-tx1 doesn't support vp9, use other "
141  "available formats.", Dispatcher::getInstance().m_videoFormat)));
142  PROPAGATE_ERROR(options.addOption(
143  createValueOption("videofiletype", 0, "TYPE",
144  "set the video file type. For video format 'h265/vp9' set the file type as 'mkv' "
145  "since 'h265 & vp9' are only supported by the 'mkv' container.",
146  Dispatcher::getInstance().m_videoFileType)));
147 
148  m_initialized = true;
149 
150  return true;
151 }
152 
154 {
155  if (!m_initialized)
156  return true;
157 
158  PROPAGATE_ERROR_CONTINUE(stop());
159 
160  PROPAGATE_ERROR_CONTINUE(m_videoRecord.shutdown());
161 
162  delete m_guiConfig;
163  m_guiConfig = NULL;
164 
165  m_guiContainerConfig = NULL;
166 
167  m_initialized = false;
168 
169  return true;
170 }
171 
172 bool AppModuleVideo::start(Window::IGuiMenuBar *iGuiMenuBar,
173  Window::IGuiContainer *iGuiContainerConfig)
174 {
175  if (m_running)
176  return true;
177 
178  // register key observer
179  PROPAGATE_ERROR(Window::getInstance().registerObserver(this));
180 
181  // initialize the GUI
182  if (iGuiContainerConfig && !m_guiConfig)
183  {
184  // initialize the GUI
185 
186  // create a grid container
187  PROPAGATE_ERROR(Window::IGuiContainerGrid::create(&m_guiConfig));
188 
189  // create the elements
190  UniquePointer<Window::IGuiElement> element;
191  Dispatcher &dispatcher = Dispatcher::getInstance();
192 
193  Window::IGuiContainerGrid::BuildHelper buildHelper(m_guiConfig);
194 
195 #define CREATE_GUI_ELEMENT(_NAME, _VALUE) \
196  PROPAGATE_ERROR(Window::IGuiElement::createValue(&dispatcher._VALUE, &element));\
197  PROPAGATE_ERROR(buildHelper.append(_NAME, element.get())); \
198  element.release();
199 
200 #define CREATE_GUI_ELEMENT_COMBO_BOX(_NAME, _VALUE, _FROMTYPE, _TOTYPE) \
201  assert(sizeof(_FROMTYPE) == sizeof(_TOTYPE)); \
202  PROPAGATE_ERROR(Window::IGuiElement::createValue(reinterpret_cast< \
203  Value<_TOTYPE>*>(&dispatcher._VALUE), &element)); \
204  PROPAGATE_ERROR(buildHelper.append(_NAME, element.get())); \
205  element.release();
206 
207  CREATE_GUI_ELEMENT_COMBO_BOX("Video Format", m_videoFormat,
208  VideoPipeline::VideoFormat, Window::IGuiElement::ValueTypeEnum);
209  CREATE_GUI_ELEMENT_COMBO_BOX("Video File Type", m_videoFileType,
210  VideoPipeline::VideoFileType, Window::IGuiElement::ValueTypeEnum);
211 
212  CREATE_GUI_ELEMENT("Video Bit Rate", m_videoBitRate);
213  CREATE_GUI_ELEMENT_COMBO_BOX("Video Control Rate", m_videoControlRate,
214  VideoPipeline::VideoFormat, Window::IGuiElement::ValueTypeEnum);
215 
216 #undef CREATE_GUI_ELEMENT
217 #undef CREATE_GUI_ELEMENT_COMBO_BOX
218 
219  PROPAGATE_ERROR(Window::IGuiElement::createAction("Toggle Recording",
220  AppModuleVideo::toggleRecording, this, Window::IGuiElement::FLAG_BUTTON_TOGGLE,
221  Window::IGuiElement::ICON_MEDIA_RECORD, &element));
222  PROPAGATE_ERROR(buildHelper.append(element.get(), 2));
223  element.release();
224 
225  m_guiContainerConfig = iGuiContainerConfig;
226  }
227 
229  PROPAGATE_ERROR(m_guiContainerConfig->add(m_guiConfig));
230 
231  PROPAGATE_ERROR(m_videoRecord.start());
232 
233  m_running = true;
234 
235  return true;
236 }
237 
239 {
240  if (!m_running)
241  return true;
242 
243  PROPAGATE_ERROR(m_videoRecord.stop());
244 
246  PROPAGATE_ERROR(m_guiContainerConfig->remove(m_guiConfig));
247 
248  // unregister key observer
249  PROPAGATE_ERROR(Window::getInstance().unregisterObserver(this));
250 
251  m_running = false;
252 
253  return true;
254 }
255 
256 bool AppModuleVideo::onKey(const Key &key)
257 {
258  if (key == Key("space"))
259  {
260  PROPAGATE_ERROR(m_videoRecord.toggleRecording());
261  }
262 
263  return true;
264 }
265 
266 }; // namespace ArgusSamples