39 namespace ArgusSamples
44 : m_state(GST_STATE_NULL)
56 static const char *s_videoEncoderName =
"video encoder";
87 gst_object_unref(
m_p);
114 float frameRate,
const char *fileName,
VideoFormat videoFormat,
116 bool enableTwoPassCBR)
120 std::string videoFileName(fileName);
121 if (videoFileName !=
"/dev/null")
123 videoFileName +=
".";
129 gst_init(NULL, NULL);
132 m_pipeline = gst_pipeline_new(
"video_pipeline");
134 ORIGINATE_ERROR(
"Failed to create video pipeline");
137 GstElement *videoSource = gst_element_factory_make(
"nveglstreamsrc", NULL);
139 ORIGINATE_ERROR(
"Failed to create capture source element");
141 if (!gst_bin_add(GST_BIN(m_pipeline), videoSource))
142 ORIGINATE_ERROR(
"Failed to add video source to pipeline");
146 g_object_set(G_OBJECT(videoSource),
"eglstream", videoStream, NULL);
149 GstElement *queue = gst_element_factory_make(
"queue", NULL);
151 ORIGINATE_ERROR(
"Failed to create queue");
153 if (!gst_bin_add(GST_BIN(m_pipeline), queue))
154 ORIGINATE_ERROR(
"Failed to add queue to pipeline");
158 GstElement *videoEncoder = NULL;
162 videoEncoder = gst_element_factory_make(
"nvv4l2h264enc", s_videoEncoderName);
165 videoEncoder = gst_element_factory_make(
"nvv4l2h265enc", s_videoEncoderName);
168 printf(
"\n***vp8 encode is not supported for Jetson-Xavier & beyond\n");
169 videoEncoder = gst_element_factory_make(
"nvv4l2vp8enc", s_videoEncoderName);
172 videoEncoder = gst_element_factory_make(
"nvv4l2vp9enc", s_videoEncoderName);
175 ORIGINATE_ERROR(
"Unhandled video format");
178 ORIGINATE_ERROR(
"Failed to create video encoder");
179 unrefer.
set(videoEncoder);
180 if (!gst_bin_add(GST_BIN(m_pipeline), videoEncoder))
181 ORIGINATE_ERROR(
"Failed to add video encoder to pipeline");
189 else if (height < 1080)
191 else if (height <= 2160)
196 if (frameRate < 15.0)
198 bitRate = (uint32_t)((
float)bitRate/30.0*frameRate);
202 g_object_set(G_OBJECT(videoEncoder),
"bitrate", bitRate, NULL);
203 g_object_set(G_OBJECT(videoEncoder),
"control-rate", controlRate, NULL);
206 bool result = (bool)system(
"lsmod | grep 'nvgpu' > /dev/null");
210 g_object_set(G_OBJECT(videoEncoder),
"EnableTwopassCBR", enableTwoPassCBR, NULL);
217 const uint32_t WIDTH_4K = 3840;
220 ORIGINATE_ERROR(
"\n Resolution > 4k requires videoformat H265 \n");
231 printf(
"\nThe VP9 video format is not supported on Jetson-tx1.\n");
237 printf(
"\nThe 3GP is only supported with H264 in current GST version. "
238 "Selecting other containers.\n");
245 printf(
"\nThe AVI is not supported with H265 in current GST version. "
246 "Selecting other containers.\n");
250 GstElement *videoParse = NULL;
254 videoParse = gst_element_factory_make(
"h264parse", NULL);
256 ORIGINATE_ERROR(
"Failed to create video parser");
259 videoParse = gst_element_factory_make(
"h265parse", NULL);
261 ORIGINATE_ERROR(
"Failed to create video parser");
267 ORIGINATE_ERROR(
"Unhandled video file type");
271 unrefer.
set(videoParse);
272 if (!gst_bin_add(GST_BIN(m_pipeline), videoParse))
273 ORIGINATE_ERROR(
"Failed to add video parser to pipeline");
277 GstElement *videoMuxer = NULL;
278 switch (videoFileType)
281 videoMuxer = gst_element_factory_make(
"qtmux", NULL);
284 videoMuxer = gst_element_factory_make(
"3gppmux", NULL);
287 videoMuxer = gst_element_factory_make(
"avimux", NULL);
290 videoMuxer = gst_element_factory_make(
"matroskamux", NULL);
293 ORIGINATE_ERROR(
"Unhandled video file type");
296 ORIGINATE_ERROR(
"Failed to create video muxer");
297 unrefer.
set(videoMuxer);
298 if (!gst_bin_add(GST_BIN(m_pipeline), videoMuxer))
299 ORIGINATE_ERROR(
"Failed to add video muxer to pipeline");
303 GstElement *videoSink = gst_element_factory_make(
"filesink", NULL);
305 ORIGINATE_ERROR(
"Failed to create video sink");
306 unrefer.
set(videoSink);
307 if (!gst_bin_add(GST_BIN(m_pipeline), videoSink))
308 ORIGINATE_ERROR(
"Failed to add video sink to pipeline");
311 g_object_set(G_OBJECT(videoSink),
"location", videoFileName.c_str(), NULL);
316 if (frameRate == 0.0f)
320 GstCaps *caps = gst_caps_new_simple(
"video/x-raw",
321 "format", G_TYPE_STRING,
"NV12",
322 "width", G_TYPE_INT, width,
323 "height", G_TYPE_INT, height,
324 "framerate", GST_TYPE_FRACTION, static_cast<gint>(frameRate * 100.f), 100,
327 ORIGINATE_ERROR(
"Failed to create caps");
329 GstCapsFeatures *feature = gst_caps_features_new(
"memory:NVMM", NULL);
332 gst_caps_unref(caps);
333 ORIGINATE_ERROR(
"Failed to create caps feature");
336 gst_caps_set_features(caps, 0, feature);
339 if (!gst_element_link_filtered(videoSource, queue, caps))
341 gst_caps_unref(caps);
342 ORIGINATE_ERROR(
"Failed to link source to queue");
344 gst_caps_unref(caps);
347 if (!gst_element_link(queue, videoEncoder))
348 ORIGINATE_ERROR(
"Failed to link queue to encoder");
353 if (!gst_element_link(videoEncoder, videoParse))
354 ORIGINATE_ERROR(
"Failed to link encoder to parser");
356 if (!gst_element_link(videoParse, videoMuxer))
357 ORIGINATE_ERROR(
"Failed to link parser to muxer");
361 if (!gst_element_link(videoEncoder, videoMuxer))
362 ORIGINATE_ERROR(
"Failed to link encoder to muxer");
366 if (!gst_element_link(videoMuxer, videoSink))
367 ORIGINATE_ERROR(
"Failed to link muxer to sink");
370 #else // GST_SUPPORTED
371 ORIGINATE_ERROR(
"Not supported");
372 #endif // GST_SUPPORTED
379 static bool objectModifyFlags(GObject *obj,
const char *flagName,
const char *valueName,
bool set)
382 GParamSpec **spec = g_object_class_list_properties(G_OBJECT_GET_CLASS(obj), &count);
384 for (guint index = 0; index < count; ++index)
386 GParamSpec *param = spec[index];
387 if (strcmp(param->name, flagName) == 0)
389 if (!G_IS_PARAM_SPEC_FLAGS(param))
390 ORIGINATE_ERROR(
"Param '%s' is not a flag", flagName);
392 GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS(param);
393 GFlagsValue *value = g_flags_get_value_by_nick(pflags->flags_class, valueName);
395 ORIGINATE_ERROR(
"Value '%s' of flag '%s' not found", valueName, flagName);
398 g_object_get(obj, flagName, &flags, NULL);
400 flags |= value->value;
402 flags &= ~value->value;
403 g_object_set(obj, flagName, flags, NULL);
409 ORIGINATE_ERROR(
"Param '%s' not found", flagName);
411 #endif // GST_SUPPORTED
417 gst_init(NULL, NULL);
420 m_pipeline = gst_element_factory_make(
"playbin",
"play");
422 ORIGINATE_ERROR(
"Failed to create playback pipeline");
425 char *uri = gst_filename_to_uri(fileName, NULL);
426 g_object_set(G_OBJECT(m_pipeline),
"uri", uri, NULL);
430 PROPAGATE_ERROR(objectModifyFlags(G_OBJECT(m_pipeline),
"flags",
"text",
false));
431 PROPAGATE_ERROR(objectModifyFlags(G_OBJECT(m_pipeline),
"flags",
"native-video",
true));
434 GstElement *audioSink = gst_element_factory_make(
"autoaudiosink",
"audio_sink");
436 ORIGINATE_ERROR(
"Failed to create audio sink");
439 g_object_set(G_OBJECT(m_pipeline),
"audio-sink", audioSink, NULL);
442 GstElement *videoSinkBin = gst_bin_new(
"video_sink_bin");
444 ORIGINATE_ERROR(
"Failed to create video sink bin");
447 g_object_set(G_OBJECT(m_pipeline),
"video-sink", videoSinkBin, NULL);
450 GstElement *videoConvert = gst_element_factory_make(
"nvvidconv",
"video converter");
452 ORIGINATE_ERROR(
"Failed to create video converter");
454 if (!gst_bin_add(GST_BIN(videoSinkBin), videoConvert))
455 ORIGINATE_ERROR(
"Failed to add video convert to video sink bin");
459 GstElement *videoSink = gst_element_factory_make(
"nvvideosink",
"video sink");
461 ORIGINATE_ERROR(
"Failed to create video sink");
462 unrefer.
set(videoSink);
463 if (!gst_bin_add(GST_BIN(videoSinkBin), videoSink))
464 ORIGINATE_ERROR(
"Failed to add video sink to video sink bin");
470 *videoStream = EGL_NO_STREAM_KHR;
471 g_object_get(G_OBJECT(videoSink),
"stream", videoStream, NULL);
472 if (*videoStream == EGL_NO_STREAM_KHR)
473 ORIGINATE_ERROR(
"Failed to get EGL stream from video sink");
475 if (!gst_element_link(videoConvert, videoSink))
476 ORIGINATE_ERROR(
"Failed to link video convert to video sink");
479 GstPad *pad = gst_element_get_static_pad(videoConvert,
"sink");
481 ORIGINATE_ERROR(
"Failed to get sink pad of video convert");
483 GstPad *ghostPad = gst_ghost_pad_new(
"sink", pad);
485 ORIGINATE_ERROR(
"Failed to create the ghost pad");
487 if (!gst_pad_set_active(ghostPad, TRUE))
488 ORIGINATE_ERROR(
"Failed to set pad active");
489 if (!gst_element_add_pad(videoSinkBin, ghostPad))
490 ORIGINATE_ERROR(
"Failed to add pad");
495 #else // GST_SUPPORTED
496 ORIGINATE_ERROR(
"Not supported");
497 #endif // GST_SUPPORTED
504 ORIGINATE_ERROR(
"Video pipeline is not set up");
506 if (m_state != GST_STATE_PLAYING)
509 if (gst_element_set_state(m_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
510 ORIGINATE_ERROR(
"Failed to set playing state");
512 m_state = GST_STATE_PLAYING;
521 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline),
522 GST_DEBUG_GRAPH_SHOW_ALL,
"argus_camera");
526 #else // GST_SUPPORTED
527 ORIGINATE_ERROR(
"Not supported");
528 #endif // GST_SUPPORTED
535 ORIGINATE_ERROR(
"Video pipeline is not set up");
537 if (m_state != GST_STATE_PAUSED)
539 if (gst_element_set_state(m_pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE)
540 ORIGINATE_ERROR(
"Failed to set pause state");
541 m_state = GST_STATE_PAUSED;
545 #else // GST_SUPPORTED
546 ORIGINATE_ERROR(
"Not supported");
547 #endif // GST_SUPPORTED
555 ORIGINATE_ERROR(
"Video pipeline is not set up");
557 GstState newState = GST_STATE_NULL;
558 if (m_state == GST_STATE_PLAYING)
559 newState = GST_STATE_PAUSED;
560 else if (m_state == GST_STATE_PAUSED)
561 newState = GST_STATE_PLAYING;
563 ORIGINATE_ERROR(
"Invalid state");
565 if (gst_element_set_state(m_pipeline, newState) == GST_STATE_CHANGE_FAILURE)
566 ORIGINATE_ERROR(
"Failed to set pause state");
571 #else // GST_SUPPORTED
572 ORIGINATE_ERROR(
"Not supported");
573 #endif // GST_SUPPORTED
580 ORIGINATE_ERROR(
"Video pipeline is not set up");
582 if (!gst_element_seek_simple(m_pipeline, GST_FORMAT_TIME,
583 static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), 0))
585 ORIGINATE_ERROR(
"Failed to rewind");
589 #else // GST_SUPPORTED
590 ORIGINATE_ERROR(
"Not supported");
591 #endif // GST_SUPPORTED
598 ORIGINATE_ERROR(
"Video pipeline is not set up");
600 if ((m_state == GST_STATE_PLAYING) || (m_state == GST_STATE_PAUSED))
603 GstElement *videoEncoder = gst_bin_get_by_name(GST_BIN(m_pipeline), s_videoEncoderName);
607 GstPad *pad = gst_element_get_static_pad(videoEncoder,
"sink");
609 ORIGINATE_ERROR(
"Failed to get 'sink' pad");
611 if (!gst_pad_send_event(pad, gst_event_new_eos()))
612 ORIGINATE_ERROR(
"Failed to send end of stream event encoder");
616 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline));
618 ORIGINATE_ERROR(
"Failed to get bus");
620 if (!gst_bus_poll(bus, GST_MESSAGE_EOS, GST_CLOCK_TIME_NONE))
621 ORIGINATE_ERROR(
"Failed to wait for the eof event");
626 if (gst_element_set_state(m_pipeline, GST_STATE_NULL) != GST_STATE_CHANGE_SUCCESS)
627 ORIGINATE_ERROR(
"Failed to stop pipeline");
629 m_state = GST_STATE_NULL;
633 #else // GST_SUPPORTED
634 ORIGINATE_ERROR(
"Not supported");
635 #endif // GST_SUPPORTED
643 PROPAGATE_ERROR(
stop());
646 gst_object_unref(GST_OBJECT(m_pipeline));
652 #else // GST_SUPPORTED
653 ORIGINATE_ERROR(
"Not supported");
654 #endif // GST_SUPPORTED
675 return "Unhandled video file type";
680 if (aspectRatio == NULL)
681 ORIGINATE_ERROR(
"'aspectRatio' is NULL");
683 if ((m_state != GST_STATE_PLAYING) && (m_state != GST_STATE_PAUSED))
684 ORIGINATE_ERROR(
"Must be in paused or playing state.");
686 GstState state = GST_STATE_NULL;
687 while ((state != GST_STATE_PLAYING) && (state != GST_STATE_PAUSED))
689 if (gst_element_get_state(m_pipeline, &state, NULL, GST_CLOCK_TIME_NONE) ==
690 GST_STATE_CHANGE_FAILURE)
692 ORIGINATE_ERROR(
"gst_element_get_state failed");
697 GstElement *videoSink;
698 g_object_get(m_pipeline,
"video-sink", &videoSink, NULL);
700 ORIGINATE_ERROR(
"Failed to get video-sink");
703 GstPad *videoSinkPad = gst_element_get_static_pad(videoSink,
"sink");
705 ORIGINATE_ERROR(
"Failed to get video-sink pad");
707 GstCaps *caps = gst_pad_get_current_caps(videoSinkPad);
709 ORIGINATE_ERROR(
"Failed to get video-sink pad caps");
713 GstStructure *structure = gst_caps_get_structure(caps, 0);
716 gst_caps_unref(caps);
717 ORIGINATE_ERROR(
"Failed to get caps structure");
721 gint pixelAspectRatioNumerator, pixelAspectRatioDenominator;
723 if (!gst_structure_get_int(structure,
"width", &width) ||
724 !gst_structure_get_int(structure,
"height", &height) ||
725 !gst_structure_get_fraction(structure,
"pixel-aspect-ratio",
726 &pixelAspectRatioNumerator, &pixelAspectRatioDenominator))
728 gst_caps_unref(caps);
729 ORIGINATE_ERROR(
"Failed to get structure values");
732 *aspectRatio = (float)width / (
float)height;
733 *aspectRatio *= (float)pixelAspectRatioNumerator / (
float)pixelAspectRatioDenominator;
735 gst_caps_unref(caps);
738 #else // GST_SUPPORTED
739 ORIGINATE_ERROR(
"Not supported");
740 #endif // GST_SUPPORTED
747 #else // GST_SUPPORTED
749 #endif // GST_SUPPORTED