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,
118 std::string videoFileName(fileName);
119 if (videoFileName !=
"/dev/null")
121 videoFileName +=
".";
127 gst_init(NULL, NULL);
130 m_pipeline = gst_pipeline_new(
"video_pipeline");
132 ORIGINATE_ERROR(
"Failed to create video pipeline");
135 GstElement *videoSource = gst_element_factory_make(
"nveglstreamsrc", NULL);
137 ORIGINATE_ERROR(
"Failed to create capture source element");
139 if (!gst_bin_add(GST_BIN(m_pipeline), videoSource))
140 ORIGINATE_ERROR(
"Failed to add video source to pipeline");
144 g_object_set(G_OBJECT(videoSource),
"eglstream", videoStream, NULL);
147 GstElement *queue = gst_element_factory_make(
"queue", NULL);
149 ORIGINATE_ERROR(
"Failed to create queue");
151 if (!gst_bin_add(GST_BIN(m_pipeline), queue))
152 ORIGINATE_ERROR(
"Failed to add queue to pipeline");
156 GstElement *videoEncoder = NULL;
160 videoEncoder = gst_element_factory_make(
"omxh264enc", s_videoEncoderName);
163 videoEncoder = gst_element_factory_make(
"omxh265enc", s_videoEncoderName);
166 videoEncoder = gst_element_factory_make(
"omxvp8enc", s_videoEncoderName);
169 videoEncoder = gst_element_factory_make(
"omxvp9enc", s_videoEncoderName);
172 ORIGINATE_ERROR(
"Unhandled video format");
175 ORIGINATE_ERROR(
"Failed to create video encoder");
176 unrefer.
set(videoEncoder);
177 if (!gst_bin_add(GST_BIN(m_pipeline), videoEncoder))
178 ORIGINATE_ERROR(
"Failed to add video encoder to pipeline");
186 else if (height < 1080)
188 else if (height <= 2160)
194 g_object_set(G_OBJECT(videoEncoder),
"bitrate", bitRate, NULL);
200 const uint32_t WIDTH_4K = 3840;
203 ORIGINATE_ERROR(
"\n Resolution > 4k requires videoformat H265 \n");
214 printf(
"\nThe VP9 video format is not supported on Jetson-tx1.\n");
220 printf(
"\nThe video format H265/VP9 is only supported with MKV in current GST version. "
221 "Selecting MKV as container.\n");
225 GstElement *videoMuxer = NULL;
226 switch (videoFileType)
229 videoMuxer = gst_element_factory_make(
"qtmux", NULL);
232 videoMuxer = gst_element_factory_make(
"3gppmux", NULL);
235 videoMuxer = gst_element_factory_make(
"avimux", NULL);
238 videoMuxer = gst_element_factory_make(
"matroskamux", NULL);
241 videoMuxer = gst_element_factory_make(
"identity", NULL);
244 ORIGINATE_ERROR(
"Unhandled video file type");
247 ORIGINATE_ERROR(
"Failed to create video muxer");
248 unrefer.
set(videoMuxer);
249 if (!gst_bin_add(GST_BIN(m_pipeline), videoMuxer))
250 ORIGINATE_ERROR(
"Failed to add video muxer to pipeline");
254 GstElement *videoSink = gst_element_factory_make(
"filesink", NULL);
256 ORIGINATE_ERROR(
"Failed to create video sink");
257 unrefer.
set(videoSink);
258 if (!gst_bin_add(GST_BIN(m_pipeline), videoSink))
259 ORIGINATE_ERROR(
"Failed to add video sink to pipeline");
262 g_object_set(G_OBJECT(videoSink),
"location", videoFileName.c_str(), NULL);
267 if (frameRate == 0.0f)
271 GstCaps *caps = gst_caps_new_simple(
"video/x-raw",
272 "format", G_TYPE_STRING,
"NV12",
273 "width", G_TYPE_INT, width,
274 "height", G_TYPE_INT, height,
275 "framerate", GST_TYPE_FRACTION, static_cast<gint>(frameRate * 100.f), 100,
278 ORIGINATE_ERROR(
"Failed to create caps");
280 GstCapsFeatures *feature = gst_caps_features_new(
"memory:NVMM", NULL);
283 gst_caps_unref(caps);
284 ORIGINATE_ERROR(
"Failed to create caps feature");
287 gst_caps_set_features(caps, 0, feature);
290 if (!gst_element_link_filtered(videoSource, queue, caps))
292 gst_caps_unref(caps);
293 ORIGINATE_ERROR(
"Failed to link source to queue");
295 gst_caps_unref(caps);
298 if (!gst_element_link(queue, videoEncoder))
299 ORIGINATE_ERROR(
"Failed to link queue to encoder");
305 if (!gst_element_link(videoEncoder, videoMuxer))
306 ORIGINATE_ERROR(
"Failed to link encoder to muxer");
310 if (!gst_element_link_pads(videoEncoder,
"src", videoMuxer,
"video_%u"))
311 ORIGINATE_ERROR(
"Failed to link encoder to muxer pad");
315 if (!gst_element_link(videoMuxer, videoSink))
316 ORIGINATE_ERROR(
"Failed to link muxer to sink");
319 #else // GST_SUPPORTED
320 ORIGINATE_ERROR(
"Not supported");
321 #endif // GST_SUPPORTED
328 static bool objectModifyFlags(GObject *obj,
const char *flagName,
const char *valueName,
bool set)
331 GParamSpec **spec = g_object_class_list_properties(G_OBJECT_GET_CLASS(obj), &count);
333 for (guint index = 0; index < count; ++index)
335 GParamSpec *param = spec[index];
336 if (strcmp(param->name, flagName) == 0)
338 if (!G_IS_PARAM_SPEC_FLAGS(param))
339 ORIGINATE_ERROR(
"Param '%s' is not a flag", flagName);
341 GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS(param);
342 GFlagsValue *value = g_flags_get_value_by_nick(pflags->flags_class, valueName);
344 ORIGINATE_ERROR(
"Value '%s' of flag '%s' not found", valueName, flagName);
347 g_object_get(obj, flagName, &flags, NULL);
349 flags |= value->value;
351 flags &= ~value->value;
352 g_object_set(obj, flagName, flags, NULL);
358 ORIGINATE_ERROR(
"Param '%s' not found", flagName);
360 #endif // GST_SUPPORTED
366 gst_init(NULL, NULL);
369 m_pipeline = gst_element_factory_make(
"playbin",
"play");
371 ORIGINATE_ERROR(
"Failed to create playback pipeline");
374 char *uri = gst_filename_to_uri(fileName, NULL);
375 g_object_set(G_OBJECT(m_pipeline),
"uri", uri, NULL);
379 PROPAGATE_ERROR(objectModifyFlags(G_OBJECT(m_pipeline),
"flags",
"text",
false));
380 PROPAGATE_ERROR(objectModifyFlags(G_OBJECT(m_pipeline),
"flags",
"native-video",
true));
383 GstElement *audioSink = gst_element_factory_make(
"autoaudiosink",
"audio_sink");
385 ORIGINATE_ERROR(
"Failed to create audio sink");
388 g_object_set(G_OBJECT(m_pipeline),
"audio-sink", audioSink, NULL);
391 GstElement *videoSinkBin = gst_bin_new(
"video_sink_bin");
393 ORIGINATE_ERROR(
"Failed to create video sink bin");
396 g_object_set(G_OBJECT(m_pipeline),
"video-sink", videoSinkBin, NULL);
399 GstElement *videoConvert = gst_element_factory_make(
"nvvidconv",
"video converter");
401 ORIGINATE_ERROR(
"Failed to create video converter");
403 if (!gst_bin_add(GST_BIN(videoSinkBin), videoConvert))
404 ORIGINATE_ERROR(
"Failed to add video convert to video sink bin");
408 GstElement *videoSink = gst_element_factory_make(
"nvvideosink",
"video sink");
410 ORIGINATE_ERROR(
"Failed to create video sink");
411 unrefer.
set(videoSink);
412 if (!gst_bin_add(GST_BIN(videoSinkBin), videoSink))
413 ORIGINATE_ERROR(
"Failed to add video sink to video sink bin");
419 *videoStream = EGL_NO_STREAM_KHR;
420 g_object_get(G_OBJECT(videoSink),
"stream", videoStream, NULL);
421 if (*videoStream == EGL_NO_STREAM_KHR)
422 ORIGINATE_ERROR(
"Failed to get EGL stream from video sink");
424 if (!gst_element_link(videoConvert, videoSink))
425 ORIGINATE_ERROR(
"Failed to link video convert to video sink");
428 GstPad *pad = gst_element_get_static_pad(videoConvert,
"sink");
430 ORIGINATE_ERROR(
"Failed to get sink pad of video convert");
432 GstPad *ghostPad = gst_ghost_pad_new(
"sink", pad);
434 ORIGINATE_ERROR(
"Failed to create the ghost pad");
436 if (!gst_pad_set_active(ghostPad, TRUE))
437 ORIGINATE_ERROR(
"Failed to set pad active");
438 if (!gst_element_add_pad(videoSinkBin, ghostPad))
439 ORIGINATE_ERROR(
"Failed to add pad");
444 #else // GST_SUPPORTED
445 ORIGINATE_ERROR(
"Not supported");
446 #endif // GST_SUPPORTED
453 ORIGINATE_ERROR(
"Video pipeline is not set up");
455 if (m_state != GST_STATE_PLAYING)
458 if (gst_element_set_state(m_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
459 ORIGINATE_ERROR(
"Failed to set playing state");
461 m_state = GST_STATE_PLAYING;
470 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline),
471 GST_DEBUG_GRAPH_SHOW_ALL,
"argus_camera");
475 #else // GST_SUPPORTED
476 ORIGINATE_ERROR(
"Not supported");
477 #endif // GST_SUPPORTED
484 ORIGINATE_ERROR(
"Video pipeline is not set up");
486 if (m_state != GST_STATE_PAUSED)
488 if (gst_element_set_state(m_pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE)
489 ORIGINATE_ERROR(
"Failed to set pause state");
490 m_state = GST_STATE_PAUSED;
494 #else // GST_SUPPORTED
495 ORIGINATE_ERROR(
"Not supported");
496 #endif // GST_SUPPORTED
504 ORIGINATE_ERROR(
"Video pipeline is not set up");
506 GstState newState = GST_STATE_NULL;
507 if (m_state == GST_STATE_PLAYING)
508 newState = GST_STATE_PAUSED;
509 else if (m_state == GST_STATE_PAUSED)
510 newState = GST_STATE_PLAYING;
512 ORIGINATE_ERROR(
"Invalid state");
514 if (gst_element_set_state(m_pipeline, newState) == GST_STATE_CHANGE_FAILURE)
515 ORIGINATE_ERROR(
"Failed to set pause state");
520 #else // GST_SUPPORTED
521 ORIGINATE_ERROR(
"Not supported");
522 #endif // GST_SUPPORTED
529 ORIGINATE_ERROR(
"Video pipeline is not set up");
531 if (!gst_element_seek_simple(m_pipeline, GST_FORMAT_TIME,
532 static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), 0))
534 ORIGINATE_ERROR(
"Failed to rewind");
538 #else // GST_SUPPORTED
539 ORIGINATE_ERROR(
"Not supported");
540 #endif // GST_SUPPORTED
547 ORIGINATE_ERROR(
"Video pipeline is not set up");
549 if ((m_state == GST_STATE_PLAYING) || (m_state == GST_STATE_PAUSED))
552 GstElement *videoEncoder = gst_bin_get_by_name(GST_BIN(m_pipeline), s_videoEncoderName);
556 GstPad *pad = gst_element_get_static_pad(videoEncoder,
"sink");
558 ORIGINATE_ERROR(
"Failed to get 'sink' pad");
560 if (!gst_pad_send_event(pad, gst_event_new_eos()))
561 ORIGINATE_ERROR(
"Failed to send end of stream event encoder");
565 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline));
567 ORIGINATE_ERROR(
"Failed to get bus");
569 if (!gst_bus_poll(bus, GST_MESSAGE_EOS, GST_CLOCK_TIME_NONE))
570 ORIGINATE_ERROR(
"Failed to wait for the eof event");
575 if (gst_element_set_state(m_pipeline, GST_STATE_NULL) != GST_STATE_CHANGE_SUCCESS)
576 ORIGINATE_ERROR(
"Failed to stop pipeline");
578 m_state = GST_STATE_NULL;
582 #else // GST_SUPPORTED
583 ORIGINATE_ERROR(
"Not supported");
584 #endif // GST_SUPPORTED
592 PROPAGATE_ERROR(
stop());
595 gst_object_unref(GST_OBJECT(m_pipeline));
601 #else // GST_SUPPORTED
602 ORIGINATE_ERROR(
"Not supported");
603 #endif // GST_SUPPORTED
624 return "Unhandled video file type";
629 if (aspectRatio == NULL)
630 ORIGINATE_ERROR(
"'aspectRatio' is NULL");
632 if ((m_state != GST_STATE_PLAYING) && (m_state != GST_STATE_PAUSED))
633 ORIGINATE_ERROR(
"Must be in paused or playing state.");
635 GstState state = GST_STATE_NULL;
636 while ((state != GST_STATE_PLAYING) && (state != GST_STATE_PAUSED))
638 if (gst_element_get_state(m_pipeline, &state, NULL, GST_CLOCK_TIME_NONE) ==
639 GST_STATE_CHANGE_FAILURE)
641 ORIGINATE_ERROR(
"gst_element_get_state failed");
646 GstElement *videoSink;
647 g_object_get(m_pipeline,
"video-sink", &videoSink, NULL);
649 ORIGINATE_ERROR(
"Failed to get video-sink");
652 GstPad *videoSinkPad = gst_element_get_static_pad(videoSink,
"sink");
654 ORIGINATE_ERROR(
"Failed to get video-sink pad");
656 GstCaps *caps = gst_pad_get_current_caps(videoSinkPad);
658 ORIGINATE_ERROR(
"Failed to get video-sink pad caps");
662 GstStructure *structure = gst_caps_get_structure(caps, 0);
665 gst_caps_unref(caps);
666 ORIGINATE_ERROR(
"Failed to get caps structure");
670 gint pixelAspectRatioNumerator, pixelAspectRatioDenominator;
672 if (!gst_structure_get_int(structure,
"width", &width) ||
673 !gst_structure_get_int(structure,
"height", &height) ||
674 !gst_structure_get_fraction(structure,
"pixel-aspect-ratio",
675 &pixelAspectRatioNumerator, &pixelAspectRatioDenominator))
677 gst_caps_unref(caps);
678 ORIGINATE_ERROR(
"Failed to get structure values");
681 *aspectRatio = (float)width / (
float)height;
682 *aspectRatio *= (float)pixelAspectRatioNumerator / (
float)pixelAspectRatioDenominator;
684 gst_caps_unref(caps);
687 #else // GST_SUPPORTED
688 ORIGINATE_ERROR(
"Not supported");
689 #endif // GST_SUPPORTED
696 #else // GST_SUPPORTED
698 #endif // GST_SUPPORTED