rpicamsrc: Implement use-stc property to disable STC timestamps
authorJan Schmidt <thaytan@noraisin.net>
Fri, 30 Jun 2017 14:51:13 +0000 (00:51 +1000)
committerTim-Philipp Müller <tim@centricular.com>
Fri, 10 Jul 2020 15:46:12 +0000 (16:46 +0100)
If use-stc=false, then rpicamsrc won't apply
the camera timestamping to outgoing buffers, instead
relying on real-time timestamping by the
GStreamer clock. It means slightly less accuracy
and more jitter in timestamps, but might help on some
CSI inputs with broken timestamping.

sys/rpicamsrc/RaspiCapture.c
sys/rpicamsrc/RaspiCapture.h
sys/rpicamsrc/gstrpicamsrc.c

index c50ef99..d0616c5 100644 (file)
@@ -929,6 +929,7 @@ GstFlowReturn
 raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp,
     GstClock *clock, GstClockTime base_time)
 {
+  RASPIVID_CONFIG *config = &state->config;
   GstBuffer *buf;
   MMAL_BUFFER_HEADER_T *buffer;
   GstFlowReturn ret = GST_FLOW_ERROR;
@@ -939,7 +940,7 @@ raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp,
   buffer = mmal_queue_wait(state->encoded_buffer_q);
 
 
-  if (G_LIKELY (clock)) {
+  if (G_LIKELY (config->useSTC && clock)) {
     MMAL_PARAMETER_INT64_T param;
     GstClockTime runtime;
 
@@ -951,7 +952,7 @@ raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp,
 
     mmal_port_parameter_get(state->encoder_output_port, &param.hdr);
 
-    if (param.value != -1 && param.value >= buffer->pts) {
+    if (buffer->pts != -1 && param.value != -1 && param.value >= buffer->pts) {
       /* Convert microsecond RPi TS to GStreamer clock: */
       GstClockTime offset = (param.value - buffer->pts) * 1000;
       if (runtime >= offset)
@@ -963,13 +964,16 @@ raspi_capture_fill_buffer(RASPIVID_STATE *state, GstBuffer **bufp,
         buffer->pts, buffer->dts, param.value, param.value - buffer->pts,
         GST_TIME_ARGS (gst_pts));
   }
-
+  else {
+    GST_LOG ("use-stc=false. Not applying STC to buffer");
+  }
 
   mmal_buffer_header_mem_lock(buffer);
   buf = gst_buffer_new_allocate(NULL, buffer->length, NULL);
   if (buf) {
+    if (config->useSTC)
+        GST_BUFFER_DTS(buf) = GST_BUFFER_PTS(buf) = gst_pts;
     /* FIXME: Can we avoid copies and give MMAL our own buffers to fill? */
-    GST_BUFFER_PTS(buf) = gst_pts;
     gst_buffer_fill(buf, 0, buffer->data, buffer->length);
     ret = GST_FLOW_OK;
   }
index 6a79ac5..053ae1c 100644 (file)
@@ -116,6 +116,8 @@ typedef struct
 
    int jpegQuality;
    int jpegRestartInterval;
+
+   int useSTC;
 } RASPIVID_CONFIG;
 
 typedef struct RASPIVID_STATE_T RASPIVID_STATE;
index f2a993c..7cd369e 100644 (file)
@@ -138,7 +138,8 @@ enum
 #ifdef GST_RPI_CAM_SRC_ENABLE_VIDEO_DIRECTION
   PROP_VIDEO_DIRECTION,
 #endif
-  PROP_JPEG_QUALITY
+  PROP_JPEG_QUALITY,
+  PROP_USE_STC
 };
 
 #define CAMERA_DEFAULT 0
@@ -488,6 +489,10 @@ gst_rpi_cam_src_class_init (GstRpiCamSrcClass * klass)
   g_object_class_override_property (gobject_class, PROP_VIDEO_DIRECTION,
       "video-direction");
 #endif
+  g_object_class_install_property (gobject_class, PROP_USE_STC,
+      g_param_spec_boolean ("use-stc", "Use System Time Clock",
+          "Use the camera STC for timestamping buffers", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   gst_element_class_set_static_metadata (gstelement_class,
       "Raspberry Pi Camera Source", "Source/Video",
@@ -517,12 +522,12 @@ gst_rpi_cam_src_init (GstRpiCamSrc * src)
   raspicapture_default_config (&src->capture_config);
   src->capture_config.intraperiod = KEYFRAME_INTERVAL_DEFAULT;
   src->capture_config.verbose = 1;
+  src->capture_config.useSTC = TRUE;
 
   g_mutex_init (&src->config_lock);
 
-  /* Don't let basesrc set timestamps, we'll do it using
-   * buffer PTS and system times */
-  gst_base_src_set_do_timestamp (GST_BASE_SRC (src), FALSE);
+  /* basesrc will generate timestamps if use-stc = false */
+  gst_base_src_set_do_timestamp (GST_BASE_SRC (src), TRUE);
 
   /* Generate the channels list */
   channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
@@ -1006,6 +1011,9 @@ gst_rpi_cam_src_set_property (GObject * object, guint prop_id,
       gst_rpi_cam_src_set_orientation (src, g_value_get_enum (value));
       break;
 #endif
+    case PROP_USE_STC:
+      src->capture_config.useSTC = g_value_get_boolean (value);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1170,6 +1178,9 @@ gst_rpi_cam_src_get_property (GObject * object, guint prop_id,
       g_value_set_enum (value, src->orientation);
       break;
 #endif
+    case PROP_USE_STC:
+      g_value_set_boolean (value, src->capture_config.useSTC);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1182,6 +1193,9 @@ gst_rpi_cam_src_start (GstBaseSrc * parent)
 {
   GstRpiCamSrc *src = GST_RPICAMSRC (parent);
   GST_LOG_OBJECT (src, "In src_start()");
+  /* Ensure basesrc timestamping is off is use-stc is on */
+  if (src->capture_config.useSTC)
+    gst_base_src_set_do_timestamp (GST_BASE_SRC (src), FALSE);
   g_mutex_lock (&src->config_lock);
   src->capture_state = raspi_capture_setup (&src->capture_config);
   /* Clear all capture flags */
@@ -1417,7 +1431,10 @@ gst_rpi_cam_src_create (GstPushSrc * parent, GstBuffer ** buf)
   if (*buf) {
     GST_LOG_OBJECT (src, "Made buffer of size %" G_GSIZE_FORMAT,
         gst_buffer_get_size (*buf));
-    GST_BUFFER_DURATION (*buf) = src->duration;
+    /* Only set the duration when we have a PTS update from the rpi encoder.
+     * not every buffer is a frame */
+    if (GST_BUFFER_PTS_IS_VALID (*buf))
+      GST_BUFFER_DURATION (*buf) = src->duration;
   }
 
   if (clock)