From 8a7a327db7dd0e677844599f4a0db76a7d06b512 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Olivier=20Cr=C3=AAte?= Date: Wed, 6 Oct 2010 21:17:28 -0400 Subject: [PATCH] rtptheoradepay: Request new keyframe on lost packets 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 | 52 ++++++++++++++++++++++++++++++++++++++++++--- gst/rtp/gstrtptheoradepay.h | 2 ++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/gst/rtp/gstrtptheoradepay.c b/gst/rtp/gstrtptheoradepay.c index dfe6de3..a21cc6c 100644 --- a/gst/rtp/gstrtptheoradepay.c +++ b/gst/rtp/gstrtptheoradepay.c @@ -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; +} diff --git a/gst/rtp/gstrtptheoradepay.h b/gst/rtp/gstrtptheoradepay.h index 0d1a911..dff261c 100644 --- a/gst/rtp/gstrtptheoradepay.h +++ b/gst/rtp/gstrtptheoradepay.h @@ -54,6 +54,8 @@ struct _GstRtpTheoraDepay GstAdapter *adapter; gboolean assembling; + + gboolean needs_keyframe; }; struct _GstRtpTheoraDepayClass -- 2.7.4