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  * SPDX-FileCopyrightText: Copyright (c) 2016 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: LicenseRef-NvidiaProprietary
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of NVIDIA CORPORATION nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "AppModuleVideo.h"
31 
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include "Dispatcher.h"
37 #include "Util.h"
38 #include "Error.h"
39 #include "Options.h"
40 #include "ScopedGuard.h"
41 #include "VideoPipeline.h"
42 
43 namespace ArgusSamples
44 {
45 
46 /* static */ bool AppModuleVideo::video(void *userPtr, const char *optArg)
47 {
49  {
50  fprintf(stderr, "------------------------------------------------------\n");
51  fprintf(stderr, "Error: Video recording is not supported on Android due\n");
52  fprintf(stderr, "to the lack of the required gstreamer functionality\n");
53  fprintf(stderr, "------------------------------------------------------\n");
54  ORIGINATE_ERROR("Unsupported function on Android");
55  }
56 
57  AppModuleVideo *module = reinterpret_cast<AppModuleVideo*>(userPtr);
58 
59  const float seconds = atof(optArg);
60  if (seconds <= 0.0f)
61  ORIGINATE_ERROR("'SECONDS' is invalid, must not be less than or equal to zero");
62 
63  // start the video module
64  PROPAGATE_ERROR(module->start());
65  // the scoped guard is used to call the stop function if following calls fail so that
66  // the function is exited with module stopped.
68 
69  const TimeValue endTime = getCurrentTime() + TimeValue::fromSec(seconds);
70 
71  // start the recording
72  PROPAGATE_ERROR(module->m_videoRecord.startRecording());
73  ScopedGuard<TaskVideoRecord> recordingGuard(&module->m_videoRecord,
75 
76  // wait until the time has elapsed
77  while (getCurrentTime() < endTime)
78  {
79  PROPAGATE_ERROR(Window::getInstance().pollEvents());
80  usleep(1000);
81  }
82 
83  // stop recording
84  recordingGuard.cancel();
85  PROPAGATE_ERROR(module->m_videoRecord.stopRecording());
86 
87  // stop the module
88  runningGuard.cancel();
89  PROPAGATE_ERROR(module->stop());
90 
91  return true;
92 }
93 
94 /* static */ bool AppModuleVideo::toggleRecording(void *userPtr, const char *optArg)
95 {
96  AppModuleVideo *module = reinterpret_cast<AppModuleVideo*>(userPtr);
97 
98  PROPAGATE_ERROR(module->m_videoRecord.toggleRecording());
99 
100  return true;
101 }
102 
104  : m_initialized(false)
105  , m_running(false)
106  , m_guiContainerConfig(NULL)
107  , m_guiConfig(NULL)
108 {
109 }
110 
112 {
113  shutdown();
114 }
115 
116 bool AppModuleVideo::initialize(Options &options)
117 {
118  if (m_initialized)
119  return true;
120 
121  PROPAGATE_ERROR(m_videoRecord.initialize());
122 
123  // TODO: Bug 5398832: remove when the feature is supported in openrm stack also.
124  bool result = (bool)system("lsmod | grep 'nvgpu' > /dev/null");
125 
126  PROPAGATE_ERROR(options.addOption(
127  Options::Option("video", 'v', "DURATION", Options::Option::TYPE_ACTION,
128  "record video for DURATION seconds and save to a file.", video, this)));
129 
130  PROPAGATE_ERROR(options.addOption(
131  createValueOption("videobitrate", 0, "RATE",
132  "set the video bit rate to RATE. If RATE is zero a reasonable default "
133  "is selected.", Dispatcher::getInstance().m_videoBitRate)));
134  PROPAGATE_ERROR(options.addOption(
135  createValueOption("videocontrolrate", 0, "MODE",
136  "set the video bit-rate control method.",
137  Dispatcher::getInstance().m_videoControlRate)));
138  if (result == false)
139  {
140  //nvgpu module is loaded; use twoPassCBR for video encoding on nvgpu based stack only
141  PROPAGATE_ERROR(options.addOption(
142  createValueOption("videotwopassCBR", 0, "ENABLE",
143  "set this flag to enable two pass CBR method for encoding.",
144  Dispatcher::getInstance().m_videoTwoPassCBREnable)));
145  }
146  PROPAGATE_ERROR(options.addOption(
147  createValueOption("videoformat", 0, "FORMAT",
148  "set the video format. Jetson-tx1 doesn't support vp9, use other "
149  "available formats.", Dispatcher::getInstance().m_videoFormat)));
150  PROPAGATE_ERROR(options.addOption(
151  createValueOption("videofiletype", 0, "TYPE",
152  "set the video file type. For video format 'h265/vp9' set the file type as 'mkv' "
153  "since 'h265 & vp9' are only supported by the 'mkv' container.",
154  Dispatcher::getInstance().m_videoFileType)));
155 
156  m_initialized = true;
157 
158  return true;
159 }
160 
162 {
163  if (!m_initialized)
164  return true;
165 
166  PROPAGATE_ERROR_CONTINUE(stop());
167 
168  PROPAGATE_ERROR_CONTINUE(m_videoRecord.shutdown());
169 
170  delete m_guiConfig;
171  m_guiConfig = NULL;
172 
173  m_guiContainerConfig = NULL;
174 
175  m_initialized = false;
176 
177  return true;
178 }
179 
180 bool AppModuleVideo::start(Window::IGuiMenuBar *iGuiMenuBar,
181  Window::IGuiContainer *iGuiContainerConfig)
182 {
183  if (m_running)
184  return true;
185 
186  // register key observer
187  PROPAGATE_ERROR(Window::getInstance().registerObserver(this));
188 
189  // initialize the GUI
190  if (iGuiContainerConfig && !m_guiConfig)
191  {
192  // initialize the GUI
193 
194  // create a grid container
195  PROPAGATE_ERROR(Window::IGuiContainerGrid::create(&m_guiConfig));
196 
197  // create the elements
198  UniquePointer<Window::IGuiElement> element;
199  Dispatcher &dispatcher = Dispatcher::getInstance();
200 
201  Window::IGuiContainerGrid::BuildHelper buildHelper(m_guiConfig);
202 
203 #define CREATE_GUI_ELEMENT(_NAME, _VALUE) \
204  PROPAGATE_ERROR(Window::IGuiElement::createValue(&dispatcher._VALUE, &element));\
205  PROPAGATE_ERROR(buildHelper.append(_NAME, element.get())); \
206  element.release();
207 
208 #define CREATE_GUI_ELEMENT_COMBO_BOX(_NAME, _VALUE, _FROMTYPE, _TOTYPE) \
209  assert(sizeof(_FROMTYPE) == sizeof(_TOTYPE)); \
210  PROPAGATE_ERROR(Window::IGuiElement::createValue(reinterpret_cast< \
211  Value<_TOTYPE>*>(&dispatcher._VALUE), &element)); \
212  PROPAGATE_ERROR(buildHelper.append(_NAME, element.get())); \
213  element.release();
214 
215  CREATE_GUI_ELEMENT_COMBO_BOX("Video Format", m_videoFormat,
216  VideoPipeline::VideoFormat, Window::IGuiElement::ValueTypeEnum);
217  CREATE_GUI_ELEMENT_COMBO_BOX("Video File Type", m_videoFileType,
218  VideoPipeline::VideoFileType, Window::IGuiElement::ValueTypeEnum);
219 
220  CREATE_GUI_ELEMENT("Video Bit Rate", m_videoBitRate);
221  CREATE_GUI_ELEMENT_COMBO_BOX("Video Control Rate", m_videoControlRate,
222  VideoPipeline::VideoFormat, Window::IGuiElement::ValueTypeEnum);
223 
224 #undef CREATE_GUI_ELEMENT
225 #undef CREATE_GUI_ELEMENT_COMBO_BOX
226 
227  PROPAGATE_ERROR(Window::IGuiElement::createAction("Toggle Recording",
228  AppModuleVideo::toggleRecording, this, Window::IGuiElement::FLAG_BUTTON_TOGGLE,
229  Window::IGuiElement::ICON_MEDIA_RECORD, &element));
230  PROPAGATE_ERROR(buildHelper.append(element.get(), 2));
231  element.release();
232 
233  m_guiContainerConfig = iGuiContainerConfig;
234  }
235 
237  PROPAGATE_ERROR(m_guiContainerConfig->add(m_guiConfig));
238 
239  PROPAGATE_ERROR(m_videoRecord.start());
240 
241  m_running = true;
242 
243  return true;
244 }
245 
247 {
248  if (!m_running)
249  return true;
250 
251  PROPAGATE_ERROR(m_videoRecord.stop());
252 
254  PROPAGATE_ERROR(m_guiContainerConfig->remove(m_guiConfig));
255 
256  // unregister key observer
257  PROPAGATE_ERROR(Window::getInstance().unregisterObserver(this));
258 
259  m_running = false;
260 
261  return true;
262 }
263 
264 bool AppModuleVideo::onKey(const Key &key)
265 {
266  if (key == Key("space"))
267  {
268  PROPAGATE_ERROR(m_videoRecord.toggleRecording());
269  }
270 
271  return true;
272 }
273 
274 }; // namespace ArgusSamples