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.
This commit is contained in:
Olivier Crête 2010-10-06 21:17:28 -04:00 committed by Wim Taymans
parent cd923223dd
commit 8a7a327db7
2 changed files with 51 additions and 3 deletions

View file

@ -67,6 +67,8 @@ static gboolean gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload,
GstCaps * caps); GstCaps * caps);
static GstBuffer *gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload, static GstBuffer *gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload,
GstBuffer * buf); GstBuffer * buf);
static gboolean gst_rtp_theora_depay_packet_lost (GstBaseRTPDepayload *
depayload, GstEvent * event);
static void gst_rtp_theora_depay_finalize (GObject * object); 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->process = gst_rtp_theora_depay_process;
gstbasertpdepayload_class->set_caps = gst_rtp_theora_depay_setcaps; 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, GST_DEBUG_CATEGORY_INIT (rtptheoradepay_debug, "rtptheoradepay", 0,
"Theora RTP Depayloader"); "Theora RTP Depayloader");
@ -308,6 +311,8 @@ gst_rtp_theora_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload); rtptheoradepay = GST_RTP_THEORA_DEPAY (depayload);
rtptheoradepay->needs_keyframe = FALSE;
structure = gst_caps_get_structure (caps, 0); structure = gst_caps_get_structure (caps, 0);
/* read and parse configuration string */ /* 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); memcpy (GST_BUFFER_DATA (outbuf), payload, length);
} }
if ((payload[0] & 0xC0) == 0x0)
rtptheoradepay->needs_keyframe = FALSE;
payload += length; payload += length;
payload_len -= length; payload_len -= length;
@ -573,6 +581,9 @@ gst_rtp_theora_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
g_free (to_free); g_free (to_free);
if (rtptheoradepay->needs_keyframe)
goto request_keyframe;
return NULL; return NULL;
no_output: no_output:
@ -584,13 +595,13 @@ switch_failed:
{ {
GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE, GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
(NULL), ("Could not switch codebooks")); (NULL), ("Could not switch codebooks"));
return NULL; goto request_config;
} }
packet_short: packet_short:
{ {
GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE, GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
(NULL), ("Packet was too short (%d < 4)", payload_len)); (NULL), ("Packet was too short (%d < 4)", payload_len));
return NULL; goto request_keyframe;
} }
ignore_reserved: ignore_reserved:
{ {
@ -601,13 +612,29 @@ length_short:
{ {
GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE, GST_ELEMENT_WARNING (rtptheoradepay, STREAM, DECODE,
(NULL), ("Packet contains invalid data")); (NULL), ("Packet contains invalid data"));
return NULL; goto request_keyframe;
} }
invalid_configuration: invalid_configuration:
{ {
/* fatal, as we otherwise risk carrying on without output */ /* fatal, as we otherwise risk carrying on without output */
GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE, GST_ELEMENT_ERROR (rtptheoradepay, STREAM, DECODE,
(NULL), ("Packet contains invalid configuration")); (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; return NULL;
} }
} }
@ -618,3 +645,22 @@ gst_rtp_theora_depay_plugin_init (GstPlugin * plugin)
return gst_element_register (plugin, "rtptheoradepay", return gst_element_register (plugin, "rtptheoradepay",
GST_RANK_SECONDARY, GST_TYPE_RTP_THEORA_DEPAY); 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;
}

View file

@ -54,6 +54,8 @@ struct _GstRtpTheoraDepay
GstAdapter *adapter; GstAdapter *adapter;
gboolean assembling; gboolean assembling;
gboolean needs_keyframe;
}; };
struct _GstRtpTheoraDepayClass struct _GstRtpTheoraDepayClass