From 2bfb42c5f8ffec7fa15666b1e6072ae11700a427 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 3 Aug 2009 18:55:19 +0200 Subject: rtph264pay: push NALs only after SPS/PPS parse complete (bytestream) buffer for SPS/PPS before pushing NALs. Fixes #564501. --- gst/rtp/gstrtph264pay.c | 121 +++++++++++++++++++++++++++++------------------- gst/rtp/gstrtph264pay.h | 1 + 2 files changed, 74 insertions(+), 48 deletions(-) (limited to 'gst/rtp') 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; -- cgit