38 namespace ArgusSamples
43 : m_state(GST_STATE_NULL)
55 static const char *s_videoEncoderName =
"video encoder";
86 gst_object_unref(
m_p);
113 float frameRate,
const char *fileName,
VideoFormat videoFormat,
115 bool enableTwoPassCBR)
119 std::string videoFileName(fileName);
120 if (videoFileName !=
"/dev/null")
122 videoFileName +=
".";
128 gst_init(NULL, NULL);
131 m_pipeline = gst_pipeline_new(
"video_pipeline");
133 ORIGINATE_ERROR(
"Failed to create video pipeline");
136 GstElement *videoSource = gst_element_factory_make(
"nveglstreamsrc", NULL);
138 ORIGINATE_ERROR(
"Failed to create capture source element");
140 if (!gst_bin_add(GST_BIN(m_pipeline), videoSource))
141 ORIGINATE_ERROR(
"Failed to add video source to pipeline");
145 g_object_set(G_OBJECT(videoSource),
"eglstream", videoStream, NULL);
148 GstElement *queue = gst_element_factory_make(
"queue", NULL);
150 ORIGINATE_ERROR(
"Failed to create queue");
152 if (!gst_bin_add(GST_BIN(m_pipeline), queue))
153 ORIGINATE_ERROR(
"Failed to add queue to pipeline");
157 GstElement *videoEncoder = NULL;
161 videoEncoder = gst_element_factory_make(
"nvv4l2h264enc", s_videoEncoderName);
164 videoEncoder = gst_element_factory_make(
"nvv4l2h265enc", s_videoEncoderName);
167 printf(
"\n***vp8 encode is not supported for Jetson-Xavier & beyond\n");
168 videoEncoder = gst_element_factory_make(
"nvv4l2vp8enc", s_videoEncoderName);
171 videoEncoder = gst_element_factory_make(
"nvv4l2vp9enc", s_videoEncoderName);
174 ORIGINATE_ERROR(
"Unhandled video format");
177 ORIGINATE_ERROR(
"Failed to create video encoder");
178 unrefer.
set(videoEncoder);
179 if (!gst_bin_add(GST_BIN(m_pipeline), videoEncoder))
180 ORIGINATE_ERROR(
"Failed to add video encoder to pipeline");
188 else if (height < 1080)
190 else if (height <= 2160)
196 g_object_set(G_OBJECT(videoEncoder),
"bitrate", bitRate, NULL);
197 g_object_set(G_OBJECT(videoEncoder),
"control-rate", controlRate, NULL);
198 g_object_set(G_OBJECT(videoEncoder),
"EnableTwopassCBR", enableTwoPassCBR, NULL);
204 const uint32_t WIDTH_4K = 3840;
207 ORIGINATE_ERROR(
"\n Resolution > 4k requires videoformat H265 \n");
218 printf(
"\nThe VP9 video format is not supported on Jetson-tx1.\n");
224 printf(
"\nThe 3GP is only supported with H264 in current GST version. "
225 "Selecting other containers.\n");
232 printf(
"\nThe AVI is not supported with H265 in current GST version. "
233 "Selecting other containers.\n");
237 GstElement *videoParse = NULL;
241 videoParse = gst_element_factory_make(
"h264parse", NULL);
243 ORIGINATE_ERROR(
"Failed to create video parser");
246 videoParse = gst_element_factory_make(
"h265parse", NULL);
248 ORIGINATE_ERROR(
"Failed to create video parser");
254 ORIGINATE_ERROR(
"Unhandled video file type");
258 unrefer.
set(videoParse);
259 if (!gst_bin_add(GST_BIN(m_pipeline), videoParse))
260 ORIGINATE_ERROR(
"Failed to add video parser to pipeline");
264 GstElement *videoMuxer = NULL;
265 switch (videoFileType)
268 videoMuxer = gst_element_factory_make(
"qtmux", NULL);
271 videoMuxer = gst_element_factory_make(
"3gppmux", NULL);
274 videoMuxer = gst_element_factory_make(
"avimux", NULL);
277 videoMuxer = gst_element_factory_make(
"matroskamux", NULL);
280 ORIGINATE_ERROR(
"Unhandled video file type");
283 ORIGINATE_ERROR(
"Failed to create video muxer");
284 unrefer.
set(videoMuxer);
285 if (!gst_bin_add(GST_BIN(m_pipeline), videoMuxer))
286 ORIGINATE_ERROR(
"Failed to add video muxer to pipeline");
290 GstElement *videoSink = gst_element_factory_make(
"filesink", NULL);
292 ORIGINATE_ERROR(
"Failed to create video sink");
293 unrefer.
set(videoSink);
294 if (!gst_bin_add(GST_BIN(m_pipeline), videoSink))
295 ORIGINATE_ERROR(
"Failed to add video sink to pipeline");
298 g_object_set(G_OBJECT(videoSink),
"location", videoFileName.c_str(), NULL);
303 if (frameRate == 0.0f)
307 GstCaps *caps = gst_caps_new_simple(
"video/x-raw",
308 "format", G_TYPE_STRING,
"NV12",
309 "width", G_TYPE_INT, width,
310 "height", G_TYPE_INT, height,
311 "framerate", GST_TYPE_FRACTION, static_cast<gint>(frameRate * 100.f), 100,
314 ORIGINATE_ERROR(
"Failed to create caps");
316 GstCapsFeatures *feature = gst_caps_features_new(
"memory:NVMM", NULL);
319 gst_caps_unref(caps);
320 ORIGINATE_ERROR(
"Failed to create caps feature");
323 gst_caps_set_features(caps, 0, feature);
326 if (!gst_element_link_filtered(videoSource, queue, caps))
328 gst_caps_unref(caps);
329 ORIGINATE_ERROR(
"Failed to link source to queue");
331 gst_caps_unref(caps);
334 if (!gst_element_link(queue, videoEncoder))
335 ORIGINATE_ERROR(
"Failed to link queue to encoder");
340 if (!gst_element_link(videoEncoder, videoParse))
341 ORIGINATE_ERROR(
"Failed to link encoder to parser");
343 if (!gst_element_link(videoParse, videoMuxer))
344 ORIGINATE_ERROR(
"Failed to link parser to muxer");
348 if (!gst_element_link(videoEncoder, videoMuxer))
349 ORIGINATE_ERROR(
"Failed to link encoder to muxer");
353 if (!gst_element_link(videoMuxer, videoSink))
354 ORIGINATE_ERROR(
"Failed to link muxer to sink");
357 #else // GST_SUPPORTED
358 ORIGINATE_ERROR(
"Not supported");
359 #endif // GST_SUPPORTED
366 static bool objectModifyFlags(GObject *obj,
const char *flagName,
const char *valueName,
bool set)
369 GParamSpec **spec = g_object_class_list_properties(G_OBJECT_GET_CLASS(obj), &count);
371 for (guint index = 0; index < count; ++index)
373 GParamSpec *param = spec[index];
374 if (strcmp(param->name, flagName) == 0)
376 if (!G_IS_PARAM_SPEC_FLAGS(param))
377 ORIGINATE_ERROR(
"Param '%s' is not a flag", flagName);
379 GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS(param);
380 GFlagsValue *value = g_flags_get_value_by_nick(pflags->flags_class, valueName);
382 ORIGINATE_ERROR(
"Value '%s' of flag '%s' not found", valueName, flagName);
385 g_object_get(obj, flagName, &flags, NULL);
387 flags |= value->value;
389 flags &= ~value->value;
390 g_object_set(obj, flagName, flags, NULL);
396 ORIGINATE_ERROR(
"Param '%s' not found", flagName);
398 #endif // GST_SUPPORTED
404 gst_init(NULL, NULL);
407 m_pipeline = gst_element_factory_make(
"playbin",
"play");
409 ORIGINATE_ERROR(
"Failed to create playback pipeline");
412 char *uri = gst_filename_to_uri(fileName, NULL);
413 g_object_set(G_OBJECT(m_pipeline),
"uri", uri, NULL);
417 PROPAGATE_ERROR(objectModifyFlags(G_OBJECT(m_pipeline),
"flags",
"text",
false));
418 PROPAGATE_ERROR(objectModifyFlags(G_OBJECT(m_pipeline),
"flags",
"native-video",
true));
421 GstElement *audioSink = gst_element_factory_make(
"autoaudiosink",
"audio_sink");
423 ORIGINATE_ERROR(
"Failed to create audio sink");
426 g_object_set(G_OBJECT(m_pipeline),
"audio-sink", audioSink, NULL);
429 GstElement *videoSinkBin = gst_bin_new(
"video_sink_bin");
431 ORIGINATE_ERROR(
"Failed to create video sink bin");
434 g_object_set(G_OBJECT(m_pipeline),
"video-sink", videoSinkBin, NULL);
437 GstElement *videoConvert = gst_element_factory_make(
"nvvidconv",
"video converter");
439 ORIGINATE_ERROR(
"Failed to create video converter");
441 if (!gst_bin_add(GST_BIN(videoSinkBin), videoConvert))
442 ORIGINATE_ERROR(
"Failed to add video convert to video sink bin");
446 GstElement *videoSink = gst_element_factory_make(
"nvvideosink",
"video sink");
448 ORIGINATE_ERROR(
"Failed to create video sink");
449 unrefer.
set(videoSink);
450 if (!gst_bin_add(GST_BIN(videoSinkBin), videoSink))
451 ORIGINATE_ERROR(
"Failed to add video sink to video sink bin");
457 *videoStream = EGL_NO_STREAM_KHR;
458 g_object_get(G_OBJECT(videoSink),
"stream", videoStream, NULL);
459 if (*videoStream == EGL_NO_STREAM_KHR)
460 ORIGINATE_ERROR(
"Failed to get EGL stream from video sink");
462 if (!gst_element_link(videoConvert, videoSink))
463 ORIGINATE_ERROR(
"Failed to link video convert to video sink");
466 GstPad *pad = gst_element_get_static_pad(videoConvert,
"sink");
468 ORIGINATE_ERROR(
"Failed to get sink pad of video convert");
470 GstPad *ghostPad = gst_ghost_pad_new(
"sink", pad);
472 ORIGINATE_ERROR(
"Failed to create the ghost pad");
474 if (!gst_pad_set_active(ghostPad, TRUE))
475 ORIGINATE_ERROR(
"Failed to set pad active");
476 if (!gst_element_add_pad(videoSinkBin, ghostPad))
477 ORIGINATE_ERROR(
"Failed to add pad");
482 #else // GST_SUPPORTED
483 ORIGINATE_ERROR(
"Not supported");
484 #endif // GST_SUPPORTED
491 ORIGINATE_ERROR(
"Video pipeline is not set up");
493 if (m_state != GST_STATE_PLAYING)
496 if (gst_element_set_state(m_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
497 ORIGINATE_ERROR(
"Failed to set playing state");
499 m_state = GST_STATE_PLAYING;
508 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline),
509 GST_DEBUG_GRAPH_SHOW_ALL,
"argus_camera");
513 #else // GST_SUPPORTED
514 ORIGINATE_ERROR(
"Not supported");
515 #endif // GST_SUPPORTED
522 ORIGINATE_ERROR(
"Video pipeline is not set up");
524 if (m_state != GST_STATE_PAUSED)
526 if (gst_element_set_state(m_pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE)
527 ORIGINATE_ERROR(
"Failed to set pause state");
528 m_state = GST_STATE_PAUSED;
532 #else // GST_SUPPORTED
533 ORIGINATE_ERROR(
"Not supported");
534 #endif // GST_SUPPORTED
542 ORIGINATE_ERROR(
"Video pipeline is not set up");
544 GstState newState = GST_STATE_NULL;
545 if (m_state == GST_STATE_PLAYING)
546 newState = GST_STATE_PAUSED;
547 else if (m_state == GST_STATE_PAUSED)
548 newState = GST_STATE_PLAYING;
550 ORIGINATE_ERROR(
"Invalid state");
552 if (gst_element_set_state(m_pipeline, newState) == GST_STATE_CHANGE_FAILURE)
553 ORIGINATE_ERROR(
"Failed to set pause state");
558 #else // GST_SUPPORTED
559 ORIGINATE_ERROR(
"Not supported");
560 #endif // GST_SUPPORTED
567 ORIGINATE_ERROR(
"Video pipeline is not set up");
569 if (!gst_element_seek_simple(m_pipeline, GST_FORMAT_TIME,
570 static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), 0))
572 ORIGINATE_ERROR(
"Failed to rewind");
576 #else // GST_SUPPORTED
577 ORIGINATE_ERROR(
"Not supported");
578 #endif // GST_SUPPORTED
585 ORIGINATE_ERROR(
"Video pipeline is not set up");
587 if ((m_state == GST_STATE_PLAYING) || (m_state == GST_STATE_PAUSED))
590 GstElement *videoEncoder = gst_bin_get_by_name(GST_BIN(m_pipeline), s_videoEncoderName);
594 GstPad *pad = gst_element_get_static_pad(videoEncoder,
"sink");
596 ORIGINATE_ERROR(
"Failed to get 'sink' pad");
598 if (!gst_pad_send_event(pad, gst_event_new_eos()))
599 ORIGINATE_ERROR(
"Failed to send end of stream event encoder");
603 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline));
605 ORIGINATE_ERROR(
"Failed to get bus");
607 if (!gst_bus_poll(bus, GST_MESSAGE_EOS, GST_CLOCK_TIME_NONE))
608 ORIGINATE_ERROR(
"Failed to wait for the eof event");
613 if (gst_element_set_state(m_pipeline, GST_STATE_NULL) != GST_STATE_CHANGE_SUCCESS)
614 ORIGINATE_ERROR(
"Failed to stop pipeline");
616 m_state = GST_STATE_NULL;
620 #else // GST_SUPPORTED
621 ORIGINATE_ERROR(
"Not supported");
622 #endif // GST_SUPPORTED
630 PROPAGATE_ERROR(
stop());
633 gst_object_unref(GST_OBJECT(m_pipeline));
639 #else // GST_SUPPORTED
640 ORIGINATE_ERROR(
"Not supported");
641 #endif // GST_SUPPORTED
662 return "Unhandled video file type";
667 if (aspectRatio == NULL)
668 ORIGINATE_ERROR(
"'aspectRatio' is NULL");
670 if ((m_state != GST_STATE_PLAYING) && (m_state != GST_STATE_PAUSED))
671 ORIGINATE_ERROR(
"Must be in paused or playing state.");
673 GstState state = GST_STATE_NULL;
674 while ((state != GST_STATE_PLAYING) && (state != GST_STATE_PAUSED))
676 if (gst_element_get_state(m_pipeline, &state, NULL, GST_CLOCK_TIME_NONE) ==
677 GST_STATE_CHANGE_FAILURE)
679 ORIGINATE_ERROR(
"gst_element_get_state failed");
684 GstElement *videoSink;
685 g_object_get(m_pipeline,
"video-sink", &videoSink, NULL);
687 ORIGINATE_ERROR(
"Failed to get video-sink");
690 GstPad *videoSinkPad = gst_element_get_static_pad(videoSink,
"sink");
692 ORIGINATE_ERROR(
"Failed to get video-sink pad");
694 GstCaps *caps = gst_pad_get_current_caps(videoSinkPad);
696 ORIGINATE_ERROR(
"Failed to get video-sink pad caps");
700 GstStructure *structure = gst_caps_get_structure(caps, 0);
703 gst_caps_unref(caps);
704 ORIGINATE_ERROR(
"Failed to get caps structure");
708 gint pixelAspectRatioNumerator, pixelAspectRatioDenominator;
710 if (!gst_structure_get_int(structure,
"width", &width) ||
711 !gst_structure_get_int(structure,
"height", &height) ||
712 !gst_structure_get_fraction(structure,
"pixel-aspect-ratio",
713 &pixelAspectRatioNumerator, &pixelAspectRatioDenominator))
715 gst_caps_unref(caps);
716 ORIGINATE_ERROR(
"Failed to get structure values");
719 *aspectRatio = (float)width / (
float)height;
720 *aspectRatio *= (float)pixelAspectRatioNumerator / (
float)pixelAspectRatioDenominator;
722 gst_caps_unref(caps);
725 #else // GST_SUPPORTED
726 ORIGINATE_ERROR(
"Not supported");
727 #endif // GST_SUPPORTED
734 #else // GST_SUPPORTED
736 #endif // GST_SUPPORTED