cccombiner: improve behaviour on timeout
authorMathieu Duponchelle <mathieu@centricular.com>
Wed, 13 Mar 2019 12:43:54 +0000 (13:43 +0100)
committerMathieu Duponchelle <mathieu@centricular.com>
Wed, 13 Mar 2019 12:50:29 +0000 (13:50 +0100)
Prior to this, cccombiner stopped consuming video buffers when
data wasn't arriving on its caption pad. In a live situation,
when aggregator is timing out we should still output whatever
video buffers are present, even if no caption buffers can be
aggregated with them.

ext/closedcaption/gstcccombiner.c

index ef4c566..265f350 100644 (file)
@@ -81,8 +81,10 @@ gst_cc_combiner_finalize (GObject * object)
 #define GST_FLOW_NEED_DATA GST_FLOW_CUSTOM_SUCCESS
 
 static GstFlowReturn
-gst_cc_combiner_collect_captions (GstCCCombiner * self)
+gst_cc_combiner_collect_captions (GstCCCombiner * self, gboolean timeout)
 {
+  GstAggregatorPad *src_pad =
+      GST_AGGREGATOR_PAD (GST_AGGREGATOR_SRC_PAD (self));
   GstAggregatorPad *caption_pad;
   GstBuffer *video_buf;
 
@@ -97,7 +99,7 @@ gst_cc_combiner_collect_captions (GstCCCombiner * self)
     GST_LOG_OBJECT (self, "No caption pad, passing through video");
     video_buf = self->current_video_buffer;
     self->current_video_buffer = NULL;
-    return gst_aggregator_finish_buffer (GST_AGGREGATOR_CAST (self), video_buf);
+    goto done;
   }
 
   GST_LOG_OBJECT (self, "Trying to collect captions for queued video buffer");
@@ -111,10 +113,13 @@ gst_cc_combiner_collect_captions (GstCCCombiner * self)
       if (gst_aggregator_pad_is_eos (caption_pad)) {
         GST_DEBUG_OBJECT (self, "Caption pad is EOS, we're done");
         break;
-      } else {
+      } else if (!timeout) {
         GST_DEBUG_OBJECT (self, "Need more caption data");
         gst_object_unref (caption_pad);
         return GST_FLOW_NEED_DATA;
+      } else {
+        GST_DEBUG_OBJECT (self, "No caption data on timeout");
+        break;
       }
     }
 
@@ -193,6 +198,10 @@ gst_cc_combiner_collect_captions (GstCCCombiner * self)
 
   gst_object_unref (caption_pad);
 
+done:
+  src_pad->segment.position =
+      GST_BUFFER_PTS (video_buf) + GST_BUFFER_DURATION (video_buf);
+
   return gst_aggregator_finish_buffer (GST_AGGREGATOR_CAST (self), video_buf);
 }
 
@@ -223,7 +232,7 @@ gst_cc_combiner_aggregate (GstAggregator * aggregator, gboolean timeout)
         if (self->current_video_buffer) {
           self->current_video_running_time_end =
               self->current_video_running_time + 50 * GST_MSECOND;
-          flow_ret = gst_cc_combiner_collect_captions (self);
+          flow_ret = gst_cc_combiner_collect_captions (self, timeout);
         }
 
         /* If we collected all captions for the remaining video frame we're
@@ -234,7 +243,6 @@ gst_cc_combiner_aggregate (GstAggregator * aggregator, gboolean timeout)
         else
           flow_ret = GST_FLOW_EOS;
       } else {
-        GST_LOG_OBJECT (aggregator, "Video pad has no data, waiting");
         flow_ret = GST_FLOW_OK;
       }
 
@@ -318,7 +326,7 @@ gst_cc_combiner_aggregate (GstAggregator * aggregator, gboolean timeout)
   g_assert (GST_CLOCK_TIME_IS_VALID (self->current_video_running_time));
   g_assert (GST_CLOCK_TIME_IS_VALID (self->current_video_running_time_end));
 
-  flow_ret = gst_cc_combiner_collect_captions (self);
+  flow_ret = gst_cc_combiner_collect_captions (self, timeout);
 
   /* Only if we collected all captions we replace the current video buffer
    * with NULL and continue with the next one on the next call */
@@ -350,9 +358,21 @@ gst_cc_combiner_sink_event (GstAggregator * aggregator,
       if (strcmp (GST_OBJECT_NAME (agg_pad), "caption") == 0) {
         self->current_caption_type = gst_video_caption_type_from_caps (caps);
       } else {
-        if (!gst_structure_get_fraction (s, "framerate", &self->video_fps_n,
-                &self->video_fps_d))
-          self->video_fps_n = self->video_fps_d = 0;
+        gint fps_n, fps_d;
+
+        fps_n = fps_d = 0;
+
+        gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d);
+
+        if (fps_n != self->video_fps_n || fps_d != self->video_fps_d) {
+          GstClockTime latency;
+
+          latency = gst_util_uint64_scale (GST_SECOND, fps_d, fps_n);
+          gst_aggregator_set_latency (aggregator, latency, latency);
+        }
+
+        self->video_fps_n = fps_n;
+        self->video_fps_d = fps_d;
 
         self->video_caps = gst_caps_ref (caps);
       }
@@ -388,6 +408,8 @@ static GstFlowReturn
 gst_cc_combiner_flush (GstAggregator * aggregator)
 {
   GstCCCombiner *self = GST_CCCOMBINER (aggregator);
+  GstAggregatorPad *src_pad =
+      GST_AGGREGATOR_PAD (GST_AGGREGATOR_SRC_PAD (aggregator));
 
   self->current_video_running_time = self->current_video_running_time_end =
       GST_CLOCK_TIME_NONE;
@@ -395,6 +417,8 @@ gst_cc_combiner_flush (GstAggregator * aggregator)
 
   g_array_set_size (self->current_frame_captions, 0);
 
+  src_pad->segment.position = GST_CLOCK_TIME_NONE;
+
   return GST_FLOW_OK;
 }
 
@@ -470,6 +494,7 @@ gst_cc_combiner_class_init (GstCCCombinerClass * klass)
   aggregator_class->create_new_pad = gst_cc_combiner_create_new_pad;
   aggregator_class->sink_event = gst_cc_combiner_sink_event;
   aggregator_class->update_src_caps = gst_cc_combiner_update_src_caps;
+  aggregator_class->get_next_time = gst_aggregator_simple_get_next_time;
 
   GST_DEBUG_CATEGORY_INIT (gst_cc_combiner_debug, "cccombiner",
       0, "Closed Caption combiner");