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;
rtph264pay = GST_RTP_H264_PAY (object);
+ g_queue_free (rtph264pay->queue);
+
g_free (rtph264pay->sps);
g_free (rtph264pay->pps);
}
}
-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);
/* 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)
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;
}
}
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
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);
}
} else {
guint next;
+ gboolean update = FALSE;
/* get offset of first start code */
next = next_start_code (data, size);
* 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;
} 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;