rtptheoradepay: Request new keyframe on lost packets
authorOlivier CrĂȘte <olivier.crete@collabora.co.uk>
Thu, 7 Oct 2010 01:17:28 +0000 (21:17 -0400)
committerWim Taymans <wim.taymans@collabora.co.uk>
Tue, 1 Feb 2011 17:28:51 +0000 (18:28 +0100)
Theora can only use the last frame (or the keyframe) as a reference, so in
practice. If we receive a buffer that references an unknown codebook, request
new headers. It probably means that headers were lost.

gst/rtp/gstrtptheoradepay.c
gst/rtp/gstrtptheoradepay.h

index dfe6de3..a21cc6c 100644 (file)
@@ -67,6 +67,8 @@ static gboolean gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload,
     GstCaps * caps);
 static GstBuffer *gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload,
     GstBuffer * buf);
+static gboolean gst_rtp_theora_depay_packet_lost (GstBaseRTPDepayload *
+    depayload, GstEvent * event);
 
 static void gst_rtp_theora_depay_finalize (GObject * object);
 
@@ -100,6 +102,7 @@ gst_rtp_theora_depay_class_init (GstRtpTheoraDepayClass * klass)
 
   gstbasertpdepayload_class->process = gst_rtp_theora_depay_process;
   gstbasertpdepayload_class->set_caps = gst_rtp_theora_depay_setcaps;
+  gstbasertpdepayload_class->packet_lost = gst_rtp_theora_depay_packet_lost;
 
   GST_DEBUG_CATEGORY_INIT (rtptheoradepay_debug, "rtptheoradepay", 0,
       "Theora RTP Depayloader");
@@ -308,6 +311,8 @@ gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
 
   rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
 
+  rtptheoradepay->needs_keyframe = FALSE;
+
   structure = gst_caps_get_structure (caps, 0);
 
   /* read and parse configuration string */
@@ -554,6 +559,9 @@ gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
       memcpy (GST_BUFFER_DATA (outbuf), payload, length);
     }
 
+    if ((payload[0] & 0xC0) == 0x0)
+      rtptheoradepay->needs_keyframe = FALSE;
+
     payload += length;
     payload_len -= length;
 
@@ -573,6 +581,9 @@ gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
 
   g_free (to_free);
 
+  if (rtptheoradepay->needs_keyframe)
+    goto request_keyframe;
+
   return NULL;
 
 no_output:
@@ -584,13 +595,13 @@ switch_failed:
   {
     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
         (NULL), ("Could not switch codebooks"));
-    return NULL;
+    goto request_config;
   }
 packet_short:
   {
     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
         (NULL), ("Packet was too short (%d < 4)", payload_len));
-    return NULL;
+    goto request_keyframe;
   }
 ignore_reserved:
   {
@@ -601,13 +612,29 @@ length_short:
   {
     GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
         (NULL), ("Packet contains invalid data"));
-    return NULL;
+    goto request_keyframe;
   }
 invalid_configuration:
   {
     /* fatal, as we otherwise risk carrying on without output */
     GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE,
         (NULL), ("Packet contains invalid configuration"));
+    goto request_config;
+  }
+request_config:
+  {
+    gst_pad_push_event (GST_BASE_RTP_DEPAYLOAD_SINKPAD (depayload),
+        gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+            gst_structure_new ("GstForceKeyUnit",
+                "all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
+    return NULL;
+  }
+request_keyframe:
+  {
+    rtptheoradepay->needs_keyframe = TRUE;
+    gst_pad_push_event (GST_BASE_RTP_DEPAYLOAD_SINKPAD (depayload),
+        gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+            gst_structure_new ("GstForceKeyUnit", NULL)));
     return NULL;
   }
 }
@@ -618,3 +645,22 @@ gst_rtp_theora_depay_plugin_init (GstPlugin * plugin)
   return gst_element_register (plugin, "rtptheoradepay",
       GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_DEPAY);
 }
+
+static gboolean
+gst_rtp_theora_depay_packet_lost (GstBaseRTPDepayload * depayload,
+    GstEvent * event)
+{
+  GstRtpTheoraDepay *rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
+  guint seqnum = 0;
+
+  gst_structure_get_uint (event->structure, "seqnum", &seqnum);
+  GST_LOG_OBJECT (depayload, "Requested keyframe because frame with seqnum %u"
+      " is missing", seqnum);
+  rtptheoradepay->needs_keyframe = TRUE;
+
+  gst_pad_push_event (GST_BASE_RTP_DEPAYLOAD_SINKPAD (depayload),
+      gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
+          gst_structure_new ("GstForceKeyUnit", NULL)));
+
+  return TRUE;
+}
index 0d1a911..dff261c 100644 (file)
@@ -54,6 +54,8 @@ struct _GstRtpTheoraDepay
 
   GstAdapter         *adapter;
   gboolean            assembling;
+
+  gboolean            needs_keyframe;
 };
 
 struct _GstRtpTheoraDepayClass