37 namespace ArgusSamples
42 : m_state(GST_STATE_NULL)
54 static const char *s_videoEncoderName =
"video encoder";
85 gst_object_unref(
m_p);
112 float frameRate,
const char *fileName,
VideoFormat videoFormat,
117 gst_init(NULL, NULL);
120 m_pipeline = gst_pipeline_new(
"video_pipeline");
122 ORIGINATE_ERROR(
"Failed to create video pipeline");
125 GstElement *videoSource = gst_element_factory_make(
"nveglstreamsrc", NULL);
127 ORIGINATE_ERROR(
"Failed to create capture source element");
129 if (!gst_bin_add(GST_BIN(m_pipeline), videoSource))
130 ORIGINATE_ERROR(
"Failed to add video source to pipeline");
134 g_object_set(G_OBJECT(videoSource),
"eglstream", videoStream, NULL);
137 GstElement *queue = gst_element_factory_make(
"queue", NULL);
139 ORIGINATE_ERROR(
"Failed to create queue");
141 if (!gst_bin_add(GST_BIN(m_pipeline), queue))
142 ORIGINATE_ERROR(
"Failed to add queue to pipeline");
146 GstElement *videoEncoder = NULL;
150 videoEncoder = gst_element_factory_make(
"avenc_h263", s_videoEncoderName);
153 videoEncoder = gst_element_factory_make(
"omxh264enc", s_videoEncoderName);
156 videoEncoder = gst_element_factory_make(
"omxh265enc", s_videoEncoderName);
159 videoEncoder = gst_element_factory_make(
"omxvp8enc", s_videoEncoderName);
162 videoEncoder = gst_element_factory_make(
"avenc_mpeg4", s_videoEncoderName);
165 ORIGINATE_ERROR(
"Unhandled video format");
168 ORIGINATE_ERROR(
"Failed to create video encoder");
169 unrefer.
set(videoEncoder);
170 if (!gst_bin_add(GST_BIN(m_pipeline), videoEncoder))
171 ORIGINATE_ERROR(
"Failed to add video encoder to pipeline");
179 else if (height < 1080)
181 else if (height <= 2160)
187 g_object_set(G_OBJECT(videoEncoder),
"bitrate", bitRate, NULL);
192 REPORT_ERROR(
"The video format H263 is not supported by the video file type MP4, "
193 "using AVI instead.");
199 REPORT_ERROR(
"The video format H265 is only supported with MKV in current GST version. "
200 "Selecting MKV as container");
204 GstElement *videoMuxer = NULL;
205 switch (videoFileType)
208 videoMuxer = gst_element_factory_make(
"qtmux", NULL);
211 videoMuxer = gst_element_factory_make(
"3gppmux", NULL);
214 videoMuxer = gst_element_factory_make(
"avimux", NULL);
217 videoMuxer = gst_element_factory_make(
"matroskamux", NULL);
220 videoMuxer = gst_element_factory_make(
"identity", NULL);
223 ORIGINATE_ERROR(
"Unhandled video file type");
226 ORIGINATE_ERROR(
"Failed to create video muxer");
227 unrefer.
set(videoMuxer);
228 if (!gst_bin_add(GST_BIN(m_pipeline), videoMuxer))
229 ORIGINATE_ERROR(
"Failed to add video muxer to pipeline");
233 GstElement *videoSink = gst_element_factory_make(
"filesink", NULL);
235 ORIGINATE_ERROR(
"Failed to create video sink");
236 unrefer.
set(videoSink);
237 if (!gst_bin_add(GST_BIN(m_pipeline), videoSink))
238 ORIGINATE_ERROR(
"Failed to add video sink to pipeline");
242 std::string videoFileName(fileName);
243 if (videoFileName !=
"/dev/null")
245 videoFileName +=
".";
249 g_object_set(G_OBJECT(videoSink),
"location", videoFileName.c_str(), NULL);
254 if (frameRate == 0.0f)
258 GstCaps *caps = gst_caps_new_simple(
"video/x-raw",
259 "format", G_TYPE_STRING,
"I420",
260 "width", G_TYPE_INT, width,
261 "height", G_TYPE_INT, height,
262 "framerate", GST_TYPE_FRACTION, static_cast<gint>(frameRate * 100.f), 100,
265 ORIGINATE_ERROR(
"Failed to create caps");
267 GstCapsFeatures *feature = gst_caps_features_new(
"memory:NVMM", NULL);
270 gst_caps_unref(caps);
271 ORIGINATE_ERROR(
"Failed to create caps feature");
274 gst_caps_set_features(caps, 0, feature);
277 if (!gst_element_link_filtered(videoSource, queue, caps))
279 gst_caps_unref(caps);
280 ORIGINATE_ERROR(
"Failed to link source to queue");
282 gst_caps_unref(caps);
285 if (!gst_element_link(queue, videoEncoder))
286 ORIGINATE_ERROR(
"Failed to link queue to encoder");
292 if (!gst_element_link(videoEncoder, videoMuxer))
293 ORIGINATE_ERROR(
"Failed to link encoder to muxer");
297 if (!gst_element_link_pads(videoEncoder,
"src", videoMuxer,
"video_%u"))
298 ORIGINATE_ERROR(
"Failed to link encoder to muxer pad");
302 if (!gst_element_link(videoMuxer, videoSink))
303 ORIGINATE_ERROR(
"Failed to link muxer to sink");
306 #else // GST_SUPPORTED
307 ORIGINATE_ERROR(
"Not supported");
308 #endif // GST_SUPPORTED
315 static bool objectModifyFlags(GObject *obj,
const char *flagName,
const char *valueName,
bool set)
318 GParamSpec **spec = g_object_class_list_properties(G_OBJECT_GET_CLASS(obj), &count);
320 for (guint index = 0; index < count; ++index)
322 GParamSpec *param = spec[index];
323 if (strcmp(param->name, flagName) == 0)
325 if (!G_IS_PARAM_SPEC_FLAGS(param))
326 ORIGINATE_ERROR(
"Param '%s' is not a flag", flagName);
328 GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS(param);
329 GFlagsValue *value = g_flags_get_value_by_nick(pflags->flags_class, valueName);
331 ORIGINATE_ERROR(
"Value '%s' of flag '%s' not found", valueName, flagName);
334 g_object_get(obj, flagName, &flags, NULL);
336 flags |= value->value;
338 flags &= ~value->value;
339 g_object_set(obj, flagName, flags, NULL);
345 ORIGINATE_ERROR(
"Param '%s' not found", flagName);
347 #endif // GST_SUPPORTED
353 gst_init(NULL, NULL);
356 m_pipeline = gst_element_factory_make(
"playbin",
"play");
358 ORIGINATE_ERROR(
"Failed to create playback pipeline");
361 char *uri = gst_filename_to_uri(fileName, NULL);
362 g_object_set(G_OBJECT(m_pipeline),
"uri", uri, NULL);
366 PROPAGATE_ERROR(objectModifyFlags(G_OBJECT(m_pipeline),
"flags",
"text",
false));
367 PROPAGATE_ERROR(objectModifyFlags(G_OBJECT(m_pipeline),
"flags",
"native-video",
true));
370 GstElement *audioSink = gst_element_factory_make(
"autoaudiosink",
"audio_sink");
372 ORIGINATE_ERROR(
"Failed to create audio sink");
375 g_object_set(G_OBJECT(m_pipeline),
"audio-sink", audioSink, NULL);
378 GstElement *videoSinkBin = gst_bin_new(
"video_sink_bin");
380 ORIGINATE_ERROR(
"Failed to create video sink bin");
383 g_object_set(G_OBJECT(m_pipeline),
"video-sink", videoSinkBin, NULL);
386 GstElement *videoConvert = gst_element_factory_make(
"nvvidconv",
"video converter");
388 ORIGINATE_ERROR(
"Failed to create video converter");
390 if (!gst_bin_add(GST_BIN(videoSinkBin), videoConvert))
391 ORIGINATE_ERROR(
"Failed to add video convert to video sink bin");
395 GstElement *videoSink = gst_element_factory_make(
"nvvideosink",
"video sink");
397 ORIGINATE_ERROR(
"Failed to create video sink");
398 unrefer.
set(videoSink);
399 if (!gst_bin_add(GST_BIN(videoSinkBin), videoSink))
400 ORIGINATE_ERROR(
"Failed to add video sink to video sink bin");
406 *videoStream = EGL_NO_STREAM_KHR;
407 g_object_get(G_OBJECT(videoSink),
"stream", videoStream, NULL);
408 if (*videoStream == EGL_NO_STREAM_KHR)
409 ORIGINATE_ERROR(
"Failed to get EGL stream from video sink");
411 if (!gst_element_link(videoConvert, videoSink))
412 ORIGINATE_ERROR(
"Failed to link video convert to video sink");
415 GstPad *pad = gst_element_get_static_pad(videoConvert,
"sink");
417 ORIGINATE_ERROR(
"Failed to get sink pad of video convert");
419 GstPad *ghostPad = gst_ghost_pad_new(
"sink", pad);
421 ORIGINATE_ERROR(
"Failed to create the ghost pad");
423 if (!gst_pad_set_active(ghostPad, TRUE))
424 ORIGINATE_ERROR(
"Failed to set pad active");
425 if (!gst_element_add_pad(videoSinkBin, ghostPad))
426 ORIGINATE_ERROR(
"Failed to add pad");
431 #else // GST_SUPPORTED
432 ORIGINATE_ERROR(
"Not supported");
433 #endif // GST_SUPPORTED
440 ORIGINATE_ERROR(
"Video pipeline is not set up");
442 if (m_state != GST_STATE_PLAYING)
445 if (gst_element_set_state(m_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE)
446 ORIGINATE_ERROR(
"Failed to set playing state");
448 m_state = GST_STATE_PLAYING;
457 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(m_pipeline),
458 GST_DEBUG_GRAPH_SHOW_ALL,
"argus_camera");
462 #else // GST_SUPPORTED
463 ORIGINATE_ERROR(
"Not supported");
464 #endif // GST_SUPPORTED
471 ORIGINATE_ERROR(
"Video pipeline is not set up");
473 if (m_state != GST_STATE_PAUSED)
475 if (gst_element_set_state(m_pipeline, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE)
476 ORIGINATE_ERROR(
"Failed to set pause state");
477 m_state = GST_STATE_PAUSED;
481 #else // GST_SUPPORTED
482 ORIGINATE_ERROR(
"Not supported");
483 #endif // GST_SUPPORTED
491 ORIGINATE_ERROR(
"Video pipeline is not set up");
493 GstState newState = GST_STATE_NULL;
494 if (m_state == GST_STATE_PLAYING)
495 newState = GST_STATE_PAUSED;
496 else if (m_state == GST_STATE_PAUSED)
497 newState = GST_STATE_PLAYING;
499 ORIGINATE_ERROR(
"Invalid state");
501 if (gst_element_set_state(m_pipeline, newState) == GST_STATE_CHANGE_FAILURE)
502 ORIGINATE_ERROR(
"Failed to set pause state");
507 #else // GST_SUPPORTED
508 ORIGINATE_ERROR(
"Not supported");
509 #endif // GST_SUPPORTED
516 ORIGINATE_ERROR(
"Video pipeline is not set up");
518 if (!gst_element_seek_simple(m_pipeline, GST_FORMAT_TIME,
519 static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), 0))
521 ORIGINATE_ERROR(
"Failed to rewind");
525 #else // GST_SUPPORTED
526 ORIGINATE_ERROR(
"Not supported");
527 #endif // GST_SUPPORTED
534 ORIGINATE_ERROR(
"Video pipeline is not set up");
536 if ((m_state == GST_STATE_PLAYING) || (m_state == GST_STATE_PAUSED))
539 GstElement *videoEncoder = gst_bin_get_by_name(GST_BIN(m_pipeline), s_videoEncoderName);
543 GstPad *pad = gst_element_get_static_pad(videoEncoder,
"sink");
545 ORIGINATE_ERROR(
"Failed to get 'sink' pad");
547 if (!gst_pad_send_event(pad, gst_event_new_eos()))
548 ORIGINATE_ERROR(
"Failed to send end of stream event encoder");
552 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline));
554 ORIGINATE_ERROR(
"Failed to get bus");
556 if (!gst_bus_poll(bus, GST_MESSAGE_EOS, GST_CLOCK_TIME_NONE))
557 ORIGINATE_ERROR(
"Failed to wait for the eof event");
562 if (gst_element_set_state(m_pipeline, GST_STATE_NULL) != GST_STATE_CHANGE_SUCCESS)
563 ORIGINATE_ERROR(
"Failed to stop pipeline");
565 m_state = GST_STATE_NULL;
569 #else // GST_SUPPORTED
570 ORIGINATE_ERROR(
"Not supported");
571 #endif // GST_SUPPORTED
579 PROPAGATE_ERROR(
stop());
582 gst_object_unref(GST_OBJECT(m_pipeline));
588 #else // GST_SUPPORTED
589 ORIGINATE_ERROR(
"Not supported");
590 #endif // GST_SUPPORTED
611 return "Unhandled video file type";
616 if (aspectRatio == NULL)
617 ORIGINATE_ERROR(
"'aspectRatio' is NULL");
619 if ((m_state != GST_STATE_PLAYING) && (m_state != GST_STATE_PAUSED))
620 ORIGINATE_ERROR(
"Must be in paused or playing state.");
622 GstState state = GST_STATE_NULL;
623 while ((state != GST_STATE_PLAYING) && (state != GST_STATE_PAUSED))
625 if (gst_element_get_state(m_pipeline, &state, NULL, GST_CLOCK_TIME_NONE) ==
626 GST_STATE_CHANGE_FAILURE)
628 ORIGINATE_ERROR(
"gst_element_get_state failed");
633 GstElement *videoSink;
634 g_object_get(m_pipeline,
"video-sink", &videoSink, NULL);
636 ORIGINATE_ERROR(
"Failed to get video-sink");
639 GstPad *videoSinkPad = gst_element_get_static_pad(videoSink,
"sink");
641 ORIGINATE_ERROR(
"Failed to get video-sink pad");
643 GstCaps *caps = gst_pad_get_current_caps(videoSinkPad);
645 ORIGINATE_ERROR(
"Failed to get video-sink pad caps");
649 GstStructure *structure = gst_caps_get_structure(caps, 0);
652 gst_caps_unref(caps);
653 ORIGINATE_ERROR(
"Failed to get caps structure");
657 gint pixelAspectRatioNumerator, pixelAspectRatioDenominator;
659 if (!gst_structure_get_int(structure,
"width", &width) ||
660 !gst_structure_get_int(structure,
"height", &height) ||
661 !gst_structure_get_fraction(structure,
"pixel-aspect-ratio",
662 &pixelAspectRatioNumerator, &pixelAspectRatioDenominator))
664 gst_caps_unref(caps);
665 ORIGINATE_ERROR(
"Failed to get structure values");
668 *aspectRatio = (float)width / (
float)height;
669 *aspectRatio *= (float)pixelAspectRatioNumerator / (
float)pixelAspectRatioDenominator;
671 gst_caps_unref(caps);
674 #else // GST_SUPPORTED
675 ORIGINATE_ERROR(
"Not supported");
676 #endif // GST_SUPPORTED