diff options
author | Wim Taymans <wim.taymans@gmail.com> | 2008-04-04 10:32:21 +0000 |
---|---|---|
committer | Wim Taymans <wim.taymans@gmail.com> | 2008-04-04 10:32:21 +0000 |
commit | 631982f16007ca65ba688c3a8ec9e6bd21082342 (patch) | |
tree | 1deb9b2acc6f7a8dfe8a13d252b51394d639bda7 /gst | |
parent | bf7cf95033d1416556aa376018077ada772f51fb (diff) |
gst/rtp/gstrtph264pay.*: Parse codec_data for future AVC compatibility.
Original commit message from CVS:
* gst/rtp/gstrtph264pay.c: (encode_base64),
(gst_rtp_h264_pay_setcaps), (gst_rtp_h264_pay_handle_buffer):
* gst/rtp/gstrtph264pay.h:
Parse codec_data for future AVC compatibility.
Fail when we encounter AVC data for now.
Diffstat (limited to 'gst')
-rw-r--r-- | gst/rtp/gstrtph264pay.c | 194 | ||||
-rw-r--r-- | gst/rtp/gstrtph264pay.h | 3 |
2 files changed, 172 insertions, 25 deletions
diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c index c437c065..d0598113 100644 --- a/gst/rtp/gstrtph264pay.c +++ b/gst/rtp/gstrtph264pay.c @@ -135,18 +135,174 @@ gst_rtp_h264_pay_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +static gchar * +encode_base64 (const guint8 * in, guint size, guint * len) +{ + gchar *ret, *d; + static const gchar *v = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + *len = ((size + 2) / 3) * 4; + d = ret = (gchar *) g_malloc (*len + 1); + for (; size; in += 3) { /* process tuplets */ + *d++ = v[in[0] >> 2]; /* byte 1: high 6 bits (1) */ + /* byte 2: low 2 bits (1), high 4 bits (2) */ + *d++ = v[((in[0] << 4) + (--size ? (in[1] >> 4) : 0)) & 0x3f]; + /* byte 3: low 4 bits (2), high 2 bits (3) */ + *d++ = size ? v[((in[1] << 2) + (--size ? (in[2] >> 6) : 0)) & 0x3f] : '='; + /* byte 4: low 6 bits (3) */ + *d++ = size ? v[in[2] & 0x3f] : '='; + if (size) + size--; /* count third character if processed */ + } + *d = '\0'; /* tie off string */ + + return ret; /* return the resulting string */ +} + static gboolean gst_rtp_h264_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps) { GstRtpH264Pay *rtph264pay; + GstStructure *str; + const GValue *value; + guint8 *data; + guint size; rtph264pay = GST_RTP_H264_PAY (basepayload); + str = gst_caps_get_structure (caps, 0); + /* we can only set the output caps when we found the sprops and profile * NALs */ gst_basertppayload_set_options (basepayload, "video", TRUE, "H264", 90000); + /* packetized AVC video has a codec_data */ + if ((value = gst_structure_get_value (str, "codec_data"))) { + GstBuffer *buffer; + GString *sprops; + guint num_sps, num_pps; + gint i, count, nal_size; + gint profile; + gchar *profile_str; + + GST_DEBUG_OBJECT (rtph264pay, "have packetized h264"); + rtph264pay->packetized = TRUE; + + buffer = gst_value_get_buffer (value); + data = GST_BUFFER_DATA (buffer); + size = GST_BUFFER_SIZE (buffer); + + /* parse the avcC data */ + if (size < 7) + goto avcc_too_small; + /* parse the version, this must be 1 */ + if (data[0] != 1) + goto wrong_version; + + /* AVCProfileIndication */ + /* profile_compat */ + /* AVCLevelIndication */ + profile = (data[1] << 16) | (data[2] << 8) | data[3]; + GST_DEBUG_OBJECT (rtph264pay, "profile %06x", profile); + + /* 6 bits reserved | 2 bits lengthSizeMinusOne */ + rtph264pay->nal_length_size = (data[4] & 0x03) + 1; + GST_DEBUG_OBJECT (rtph264pay, "nal length %u", rtph264pay->nal_length_size); + /* 3 bits reserved | 5 bits numOfSequenceParameterSets */ + num_sps = data[5] & 0x1f; + GST_DEBUG_OBJECT (rtph264pay, "num SPS %u", num_sps); + + data += 6; + size -= 6; + + /* create the sprop-parameter-sets */ + sprops = g_string_new (""); + count = 0; + + for (i = 0; i < num_sps; i++) { + gchar *set; + guint len; + + if (size < 2) + goto avcc_error; + + nal_size = (data[0] << 8) | data[1]; + data += 2; + size -= 2; + + if (size < nal_size) + goto avcc_error; + + set = encode_base64 (data, nal_size, &len); + g_string_append_printf (sprops, "%s%s", count ? "," : "", set); + count++; + g_free (set); + + data += nal_size; + size -= nal_size; + } + if (size < 1) + goto avcc_error; + + num_pps = data[0]; + data += 1; + size -= 1; + + GST_DEBUG_OBJECT (rtph264pay, "num PPS %u", num_pps); + for (i = 0; i < num_pps; i++) { + gchar *set; + guint len; + + if (size < 2) + goto avcc_error; + + nal_size = (data[0] << 8) | data[1]; + data += 2; + size -= 2; + + if (size < nal_size) + goto avcc_error; + + set = encode_base64 (data, nal_size, &len); + g_string_append_printf (sprops, "%s%s", count ? "," : "", set); + count++; + g_free (set); + + data += nal_size; + size -= nal_size; + } + GST_DEBUG_OBJECT (rtph264pay, "sprops %s", sprops->str); + + profile_str = g_strdup_printf ("%06x", profile); + gst_basertppayload_set_outcaps (basepayload, "profile-level-id", + G_TYPE_STRING, profile_str, + "sprop-parameter-sets", G_TYPE_STRING, sprops->str, NULL); + g_free (profile_str); + + g_string_free (sprops, TRUE); + } else { + GST_DEBUG_OBJECT (rtph264pay, "have bytestream h264"); + rtph264pay->packetized = FALSE; + } + return TRUE; + +avcc_too_small: + { + GST_ERROR_OBJECT (rtph264pay, "avcC size %u < 7", size); + return FALSE; + } +wrong_version: + { + GST_ERROR_OBJECT (rtph264pay, "wrong avcC version", size); + return FALSE; + } +avcc_error: + { + GST_ERROR_OBJECT (rtph264pay, "avcC too small "); + return FALSE; + } } static guint @@ -320,31 +476,6 @@ gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader, } } -static gchar * -encode_base64 (const guint8 * in, guint size, guint * len) -{ - gchar *ret, *d; - static const gchar *v = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - *len = ((size + 2) / 3) * 4; - d = ret = (gchar *) g_malloc (*len + 1); - for (; size; in += 3) { /* process tuplets */ - *d++ = v[in[0] >> 2]; /* byte 1: high 6 bits (1) */ - /* byte 2: low 2 bits (1), high 4 bits (2) */ - *d++ = v[((in[0] << 4) + (--size ? (in[1] >> 4) : 0)) & 0x3f]; - /* byte 3: low 4 bits (2), high 2 bits (3) */ - *d++ = size ? v[((in[1] << 2) + (--size ? (in[2] >> 6) : 0)) & 0x3f] : '='; - /* byte 4: low 6 bits (3) */ - *d++ = size ? v[in[2] & 0x3f] : '='; - if (size) - size--; /* count third character if processed */ - } - *d = '\0'; /* tie off string */ - - return ret; /* return the resulting string */ -} - static void gst_rtp_h264_pay_parse_sps_pps (GstBaseRTPPayload * basepayload, guint8 * data, guint size) @@ -412,6 +543,10 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload, GST_DEBUG_OBJECT (basepayload, "got %d bytes", size); + /* we don't support AVC input yet */ + if (rtph264pay->packetized) + goto not_supported; + /* H264 stream analysis */ pdata = data; @@ -525,11 +660,20 @@ gst_rtp_h264_pay_handle_buffer (GstBaseRTPPayload * basepayload, return ret; } + /* ERRORS */ GST_ELEMENT_ERROR (basepayload, STREAM, FORMAT, (NULL), ("Should not be there !!")); gst_buffer_unref (buffer); return GST_FLOW_ERROR; + +not_supported: + { + GST_ELEMENT_ERROR (basepayload, STREAM, FORMAT, + (NULL), ("AVC H264 is not supported yet")); + gst_buffer_unref (buffer); + return GST_FLOW_NOT_SUPPORTED; + } } static GstStateChangeReturn diff --git a/gst/rtp/gstrtph264pay.h b/gst/rtp/gstrtph264pay.h index d1ecb27c..d5615e5d 100644 --- a/gst/rtp/gstrtph264pay.h +++ b/gst/rtp/gstrtph264pay.h @@ -46,6 +46,9 @@ struct _GstRtpH264Pay guint profile; guint8 *sps, *pps; guint sps_len, pps_len; + + gboolean packetized; + guint nal_length_size; }; struct _GstRtpH264PayClass |