summaryrefslogtreecommitdiffstats
path: root/gst/rtp
diff options
context:
space:
mode:
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>2009-08-03 18:55:19 +0200
committerWim Taymans <wim.taymans@collabora.co.uk>2009-08-06 11:14:44 +0200
commit2bfb42c5f8ffec7fa15666b1e6072ae11700a427 (patch)
treee8a0185ebc4c6a156d886f1fc33eb1823d9e6077 /gst/rtp
parent198604c108f7f0561ebf1e6fca7c2825a5011397 (diff)
rtph264pay: push NALs only after SPS/PPS
parse complete (bytestream) buffer for SPS/PPS before pushing NALs. Fixes #564501.
Diffstat (limited to 'gst/rtp')
-rw-r--r--gst/rtp/gstrtph264pay.c121
-rw-r--r--gst/rtp/gstrtph264pay.h1
2 files changed, 74 insertions, 48 deletions
diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c
index b8e4773c..77bce728 100644
--- a/gst/rtp/gstrtph264pay.c
+++ b/gst/rtp/gstrtph264pay.c
@@ -184,6 +184,7 @@ gst_rtp_h264_pay_class_init (GstRtpH264PayClass * klass)
static void
gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay, GstRtpH264PayClass * klass)
{
+ rtph264pay->queue = g_queue_new ();
rtph264pay->profile = 0;
rtph264pay->sps = NULL;
rtph264pay->pps = NULL;
@@ -198,6 +199,8 @@ gst_rtp_h264_pay_finalize (GObject * object)
rtph264pay = GST_RTP_H264_PAY (object);
+ g_queue_free (rtph264pay->queue);
+
g_free (rtph264pay->sps);
g_free (rtph264pay->pps);
@@ -437,17 +440,18 @@ is_nal_equal (const guint8 * nal1, const guint8 * nal2, guint len)
}
}
-static void
+static gboolean
gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
- guint8 * data, guint size, gboolean * updated)
+ guint8 * data, guint size)
{
guint8 *sps = NULL, *pps = NULL;
guint sps_len = 0, pps_len = 0;
guint8 header, type;
guint len;
+ gboolean updated;
/* default is no update */
- *updated = FALSE;
+ updated = FALSE;
GST_DEBUG ("NAL payload len=%u", size);
@@ -479,7 +483,7 @@ gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
/* If we encountered an SPS and/or a PPS, check if it's the
* same as the one we have. If not, update our version and
- * set *updated to TRUE
+ * set updated to TRUE
*/
if (sps_len > 0) {
if ((payloader->sps_len != sps_len)
@@ -494,7 +498,7 @@ gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
payloader->sps = sps_len ? g_new (guint8, sps_len) : NULL;
memcpy (payloader->sps, sps, sps_len);
payloader->sps_len = sps_len;
- *updated = TRUE;
+ updated = TRUE;
}
}
@@ -507,53 +511,47 @@ gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
payloader->pps = pps_len ? g_new (guint8, pps_len) : NULL;
memcpy (payloader->pps, pps, pps_len);
payloader->pps_len = pps_len;
- *updated = TRUE;
+ updated = TRUE;
}
}
+
+ return updated;
}
static void
-gst_rtp_h264_pay_parse_sps_pps (GstBaseRTPPayload * basepayload,
- guint8 * data, guint size)
+gst_rtp_h264_pay_set_sps_pps (GstBaseRTPPayload * basepayload)
{
- gboolean update = FALSE;
GstRtpH264Pay *payloader = GST_RTP_H264_PAY (basepayload);
-
- gst_rtp_h264_pay_decode_nal (payloader, data, size, &update);
-
- /* if has new SPS & PPS, update the output caps */
- if (update) {
- gchar *profile;
- gchar *sps;
- gchar *pps;
- gchar *sprops;
-
- /* profile is 24 bit. Force it to respect the limit */
- profile = g_strdup_printf ("%06x", payloader->profile & 0xffffff);
-
- /* build the sprop-parameter-sets */
- sps = (payloader->sps_len > 0)
- ? g_base64_encode (payloader->sps, payloader->sps_len) : NULL;
- pps = (payloader->pps_len > 0)
- ? g_base64_encode (payloader->pps, payloader->pps_len) : NULL;
-
- if (sps)
- sprops = g_strjoin (",", sps, pps, NULL);
- else
- sprops = g_strdup (pps);
-
- gst_basertppayload_set_outcaps (basepayload, "profile-level-id",
- G_TYPE_STRING, profile,
- "sprop-parameter-sets", G_TYPE_STRING, sprops, NULL);
-
- GST_DEBUG ("outcaps udpate: profile=%s, sps=%s, pps=%s",
- profile, GST_STR_NULL (sps), GST_STR_NULL (pps));
-
- g_free (sprops);
- g_free (profile);
- g_free (sps);
- g_free (pps);
- }
+ gchar *profile;
+ gchar *sps;
+ gchar *pps;
+ gchar *sprops;
+
+ /* profile is 24 bit. Force it to respect the limit */
+ profile = g_strdup_printf ("%06x", payloader->profile & 0xffffff);
+
+ /* build the sprop-parameter-sets */
+ sps = (payloader->sps_len > 0)
+ ? g_base64_encode (payloader->sps, payloader->sps_len) : NULL;
+ pps = (payloader->pps_len > 0)
+ ? g_base64_encode (payloader->pps, payloader->pps_len) : NULL;
+
+ if (sps)
+ sprops = g_strjoin (",", sps, pps, NULL);
+ else
+ sprops = g_strdup (pps);
+
+ gst_basertppayload_set_outcaps (basepayload, "profile-level-id",
+ G_TYPE_STRING, profile,
+ "sprop-parameter-sets", G_TYPE_STRING, sprops, NULL);
+
+ GST_DEBUG ("outcaps udpate: profile=%s, sps=%s, pps=%s",
+ profile, GST_STR_NULL (sps), GST_STR_NULL (pps));
+
+ g_free (sprops);
+ g_free (profile);
+ g_free (sps);
+ g_free (pps);
}
static GstFlowReturn
@@ -735,8 +733,9 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
GstRtpH264Pay *rtph264pay;
GstFlowReturn ret;
guint size, nal_len;
- guint8 *data;
+ guint8 *data, *nal_data;
GstClockTime timestamp;
+ GQueue *nal_queue;
rtph264pay = GST_RTP_H264_PAY (basepayload);
@@ -788,6 +787,7 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
}
} else {
guint next;
+ gboolean update = FALSE;
/* get offset of first start code */
next = next_start_code (data, size);
@@ -796,10 +796,13 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
* will not collect data. */
data += next;
size -= next;
+ nal_data = data;
+ nal_queue = rtph264pay->queue;
GST_DEBUG_OBJECT (basepayload, "found first start at %u, bytes left %u",
next, size);
+ /* first pass to locate NALs and parse SPS/PPS */
while (size > 4) {
/* skip start code */
data += 4;
@@ -842,21 +845,43 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload,
} else {
/* We know our stream is a valid H264 NAL packet,
* go parse it for SPS/PPS to enrich the caps */
- gst_rtp_h264_pay_parse_sps_pps (basepayload, data, nal_len);
+ /* order: make sure to check nal */
+ update = gst_rtp_h264_pay_decode_nal (rtph264pay, data, nal_len) ||
+ update;
}
+ /* move to next NAL packet */
+ data += nal_len;
+ size -= nal_len;
+
+ g_queue_push_tail (nal_queue, GUINT_TO_POINTER (nal_len));
+ }
+
+ /* if has new SPS & PPS, update the output caps */
+ if (G_UNLIKELY (update))
+ gst_rtp_h264_pay_set_sps_pps (basepayload);
+
+ /* second pass to payload and push */
+ data = nal_data;
+ while ((nal_len = GPOINTER_TO_UINT (g_queue_pop_head (nal_queue))) > 0) {
+ /* skip start code */
+ data += 4;
+
/* put the data in one or more RTP packets */
ret =
gst_rtp_h264_pay_payload_nal (basepayload, data, nal_len, timestamp,
buffer);
- if (ret != GST_FLOW_OK)
+ if (ret != GST_FLOW_OK) {
+ g_queue_clear (nal_queue);
break;
+ }
/* move to next NAL packet */
data += nal_len;
size -= nal_len;
}
}
+
gst_buffer_unref (buffer);
return ret;
diff --git a/gst/rtp/gstrtph264pay.h b/gst/rtp/gstrtph264pay.h
index 596d0619..3865b42e 100644
--- a/gst/rtp/gstrtph264pay.h
+++ b/gst/rtp/gstrtph264pay.h
@@ -56,6 +56,7 @@ struct _GstRtpH264Pay
gboolean packetized;
guint nal_length_size;
+ GQueue *queue;
gchar *profile_level_id;
gchar *sprop_parameter_sets;