rtph264depay: Cope with FU-A E bit not being set

Some h264 payloaders are unfortunately buggy and don't correctly set the
E bit in FU-A NAL when they have ended. Work around this by assuming
such a fragmentation unit has ended when there was no packet loss and a
new NAL is started
This commit is contained in:
Sjoerd Simons 2011-07-27 18:15:20 +01:00
parent 89564fcb69
commit 4c73439ee3
2 changed files with 56 additions and 19 deletions

View file

@ -168,6 +168,7 @@ gst_rtp_h264_depay_reset (GstRtpH264Depay * rtph264depay)
rtph264depay->picture_start = FALSE; rtph264depay->picture_start = FALSE;
rtph264depay->last_keyframe = FALSE; rtph264depay->last_keyframe = FALSE;
rtph264depay->last_ts = 0; rtph264depay->last_ts = 0;
rtph264depay->current_fu_type = 0;
} }
static void static void
@ -606,6 +607,35 @@ short_nal:
} }
} }
static void
gst_rtp_h264_push_fragmentation_unit (GstRtpH264Depay * rtph264depay)
{
guint outsize;
guint8 *outdata;
GstBuffer *outbuf;
outsize = gst_adapter_available (rtph264depay->adapter);
outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize);
outdata = GST_BUFFER_DATA (outbuf);
GST_DEBUG_OBJECT (rtph264depay, "output %d bytes", outsize);
if (rtph264depay->byte_stream) {
memcpy (outdata, sync_bytes, sizeof (sync_bytes));
} else {
outsize -= 4;
outdata[0] = (outsize >> 24);
outdata[1] = (outsize >> 16);
outdata[2] = (outsize >> 8);
outdata[3] = (outsize);
}
gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf,
rtph264depay->fu_timestamp, rtph264depay->fu_marker);
rtph264depay->current_fu_type = 0;
}
static GstBuffer * static GstBuffer *
gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
{ {
@ -619,6 +649,7 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
if (GST_BUFFER_IS_DISCONT (buf)) { if (GST_BUFFER_IS_DISCONT (buf)) {
gst_adapter_clear (rtph264depay->adapter); gst_adapter_clear (rtph264depay->adapter);
rtph264depay->wait_start = TRUE; rtph264depay->wait_start = TRUE;
rtph264depay->current_fu_type = 0;
} }
{ {
@ -659,6 +690,13 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
GST_DEBUG_OBJECT (rtph264depay, "NRI %d, Type %d", nal_ref_idc, GST_DEBUG_OBJECT (rtph264depay, "NRI %d, Type %d", nal_ref_idc,
nal_unit_type); nal_unit_type);
/* If FU unit was being processed, but the current nal is of a different
* type. Assume that the remote payloader is buggy (didn't set the end bit
* when the FU ended) and send out what we gathered thusfar */
if (G_UNLIKELY (rtph264depay->current_fu_type != 0 &&
nal_unit_type != rtph264depay->current_fu_type))
gst_rtp_h264_push_fragmentation_unit (rtph264depay);
switch (nal_unit_type) { switch (nal_unit_type) {
case 0: case 0:
case 30: case 30:
@ -758,6 +796,15 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
/* NAL unit starts here */ /* NAL unit starts here */
guint8 nal_header; guint8 nal_header;
/* If a new FU unit started, while still processing an older one.
* Assume that the remote payloader is buggy (doesn't set the end
* bit) and send out what we've gathered thusfar */
if (G_UNLIKELY (rtph264depay->current_fu_type != 0))
gst_rtp_h264_push_fragmentation_unit (rtph264depay);
rtph264depay->current_fu_type = nal_unit_type;
rtph264depay->fu_timestamp = timestamp;
rtph264depay->wait_start = FALSE; rtph264depay->wait_start = FALSE;
/* reconstruct NAL header */ /* reconstruct NAL header */
@ -796,26 +843,11 @@ gst_rtp_h264_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
gst_adapter_push (rtph264depay->adapter, outbuf); gst_adapter_push (rtph264depay->adapter, outbuf);
} }
rtph264depay->fu_marker = marker;
/* if NAL unit ends, flush the adapter */ /* if NAL unit ends, flush the adapter */
if (E) { if (E)
GST_DEBUG_OBJECT (rtph264depay, "output %d bytes", outsize); gst_rtp_h264_push_fragmentation_unit (rtph264depay);
outsize = gst_adapter_available (rtph264depay->adapter);
outbuf = gst_adapter_take_buffer (rtph264depay->adapter, outsize);
outdata = GST_BUFFER_DATA (outbuf);
if (rtph264depay->byte_stream) {
memcpy (outdata, sync_bytes, sizeof (sync_bytes));
} else {
outsize -= 4;
outdata[0] = (outsize >> 24);
outdata[1] = (outsize >> 16);
outdata[2] = (outsize >> 8);
outdata[3] = (outsize);
}
gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
marker);
}
break; break;
} }
default: default:

View file

@ -56,6 +56,11 @@ struct _GstRtpH264Depay
gboolean picture_start; gboolean picture_start;
GstClockTime last_ts; GstClockTime last_ts;
gboolean last_keyframe; gboolean last_keyframe;
/* Work around broken payloaders wrt. FU-A & FU-B */
guint8 current_fu_type;
GstClockTime fu_timestamp;
gboolean fu_marker;
}; };
struct _GstRtpH264DepayClass struct _GstRtpH264DepayClass