From: Wim Taymans Date: Mon, 12 Jul 2010 10:35:15 +0000 (+0200) Subject: rtpmp4gpay: implement perfect timestamps X-Git-Tag: RELEASE-0.10.25~24 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=af70b300cc3655ba52ad16612c77ea9896f7cf70;p=platform%2Fupstream%2Fgst-plugins-good.git rtpmp4gpay: implement perfect timestamps Use bitreader for parsing the config string Reset state variables when going to READY Parse frame length and use it to keep track of the rtptimestamps --- diff --git a/gst/rtp/gstrtpmp4gpay.c b/gst/rtp/gstrtpmp4gpay.c index 75fc92ee7..e2e77ac6f 100644 --- a/gst/rtp/gstrtpmp4gpay.c +++ b/gst/rtp/gstrtpmp4gpay.c @@ -23,6 +23,7 @@ #include +#include #include #include "gstrtpmp4gpay.h" @@ -74,6 +75,9 @@ GST_STATIC_PAD_TEMPLATE ("src", static void gst_rtp_mp4g_pay_finalize (GObject * object); +static GstStateChangeReturn gst_rtp_mp4g_pay_change_state (GstElement * element, + GstStateChange transition); + static gboolean gst_rtp_mp4g_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps); static GstFlowReturn gst_rtp_mp4g_pay_handle_buffer (GstBaseRTPPayload * @@ -101,13 +105,17 @@ static void gst_rtp_mp4g_pay_class_init (GstRtpMP4GPayClass * klass) { GObjectClass *gobject_class; + GstElementClass *gstelement_class; GstBaseRTPPayloadClass *gstbasertppayload_class; gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass; gobject_class->finalize = gst_rtp_mp4g_pay_finalize; + gstelement_class->change_state = gst_rtp_mp4g_pay_change_state; + gstbasertppayload_class->set_caps = gst_rtp_mp4g_pay_setcaps; gstbasertppayload_class->handle_buffer = gst_rtp_mp4g_pay_handle_buffer; @@ -119,20 +127,14 @@ static void gst_rtp_mp4g_pay_init (GstRtpMP4GPay * rtpmp4gpay, GstRtpMP4GPayClass * klass) { rtpmp4gpay->adapter = gst_adapter_new (); - rtpmp4gpay->rate = 90000; - rtpmp4gpay->profile = g_strdup ("1"); - rtpmp4gpay->mode = ""; } static void -gst_rtp_mp4g_pay_finalize (GObject * object) +gst_rtp_mp4g_pay_reset (GstRtpMP4GPay * rtpmp4gpay) { - GstRtpMP4GPay *rtpmp4gpay; + GST_DEBUG_OBJECT (rtpmp4gpay, "reset"); - rtpmp4gpay = GST_RTP_MP4G_PAY (object); - - g_object_unref (rtpmp4gpay->adapter); - rtpmp4gpay->adapter = NULL; + gst_adapter_clear (rtpmp4gpay->adapter); g_free (rtpmp4gpay->params); rtpmp4gpay->params = NULL; @@ -144,6 +146,25 @@ gst_rtp_mp4g_pay_finalize (GObject * object) g_free (rtpmp4gpay->profile); rtpmp4gpay->profile = NULL; + rtpmp4gpay->streamtype = NULL; + rtpmp4gpay->mode = NULL; + + rtpmp4gpay->frame_len = 0; + rtpmp4gpay->offset = 0; +} + +static void +gst_rtp_mp4g_pay_finalize (GObject * object) +{ + GstRtpMP4GPay *rtpmp4gpay; + + rtpmp4gpay = GST_RTP_MP4G_PAY (object); + + gst_rtp_mp4g_pay_reset (rtpmp4gpay); + + g_object_unref (rtpmp4gpay->adapter); + rtpmp4gpay->adapter = NULL; + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -161,39 +182,66 @@ gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay, guint8 objectType; guint8 samplingIdx; guint8 channelCfg; + GstBitReader br; data = GST_BUFFER_DATA (buffer); size = GST_BUFFER_SIZE (buffer); - if (size < 2) - goto too_short; + gst_bit_reader_init (&br, data, size); /* any object type is fine, we need to copy it to the profile-level-id field. */ - objectType = (data[0] & 0xf8) >> 3; + if (!gst_bit_reader_get_bits_uint8 (&br, &objectType, 5)) + goto too_short; if (objectType == 0) goto invalid_object; - samplingIdx = ((data[0] & 0x07) << 1) | ((data[1] & 0x80) >> 7); + if (!gst_bit_reader_get_bits_uint8 (&br, &samplingIdx, 4)) + goto too_short; /* only fixed values for now */ if (samplingIdx > 12 && samplingIdx != 15) goto wrong_freq; - channelCfg = ((data[1] & 0x78) >> 3); + if (!gst_bit_reader_get_bits_uint8 (&br, &channelCfg, 4)) + goto too_short; if (channelCfg > 7) goto wrong_channels; /* rtp rate depends on sampling rate of the audio */ if (samplingIdx == 15) { - if (size < 5) - goto too_short; + guint32 rate; /* index of 15 means we get the rate in the next 24 bits */ - rtpmp4gpay->rate = ((data[1] & 0x7f) << 17) | - ((data[2]) << 9) | ((data[3]) << 1) | ((data[4] & 0x80) >> 7); + if (!gst_bit_reader_get_bits_uint32 (&br, &rate, 24)) + goto too_short; + + rtpmp4gpay->rate = rate; } else { /* else use the rate from the table */ rtpmp4gpay->rate = sampling_table[samplingIdx]; } + + rtpmp4gpay->frame_len = 1024; + + switch (objectType) { + case 1: + case 2: + case 3: + case 4: + case 6: + case 7: + { + guint8 frameLenFlag; + + if (gst_bit_reader_get_bits_uint8 (&br, &frameLenFlag, 1)) + if (frameLenFlag) + rtpmp4gpay->frame_len = 960; + + break; + } + default: + break; + } + /* extra rtp params contain the number of channels */ g_free (rtpmp4gpay->params); rtpmp4gpay->params = g_strdup_printf ("%d", channelCfg); @@ -206,8 +254,9 @@ gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay, rtpmp4gpay->profile = g_strdup_printf ("%d", objectType); GST_DEBUG_OBJECT (rtpmp4gpay, - "objectType: %d, samplingIdx: %d (%d), channelCfg: %d", objectType, - samplingIdx, rtpmp4gpay->rate, channelCfg); + "objectType: %d, samplingIdx: %d (%d), channelCfg: %d, frame_len %d", + objectType, samplingIdx, rtpmp4gpay->rate, channelCfg, + rtpmp4gpay->frame_len); return TRUE; @@ -215,13 +264,13 @@ gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay, too_short: { GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT, - (NULL), ("config string too short, expected 2 bytes, got %d", size)); + (NULL), ("config string too short")); return FALSE; } invalid_object: { GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT, - (NULL), ("invalid object type 0")); + (NULL), ("invalid object type")); return FALSE; } wrong_freq: @@ -479,6 +528,11 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay) GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4gpay->first_timestamp; GST_BUFFER_DURATION (outbuf) = rtpmp4gpay->first_duration; + if (rtpmp4gpay->frame_len) { + GST_BUFFER_OFFSET (outbuf) = rtpmp4gpay->offset; + rtpmp4gpay->offset += rtpmp4gpay->frame_len; + } + ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp4gpay), outbuf); avail -= payload_len; @@ -503,9 +557,31 @@ gst_rtp_mp4g_pay_handle_buffer (GstBaseRTPPayload * basepayload, /* we always encode and flush a full AU */ gst_adapter_push (rtpmp4gpay->adapter, buffer); + return gst_rtp_mp4g_pay_flush (rtpmp4gpay); } +static GstStateChangeReturn +gst_rtp_mp4g_pay_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret; + GstRtpMP4GPay *rtpmp4gpay; + + rtpmp4gpay = GST_RTP_MP4G_PAY (element); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + gst_rtp_mp4g_pay_reset (rtpmp4gpay); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + return ret; +} + gboolean gst_rtp_mp4g_pay_plugin_init (GstPlugin * plugin) { diff --git a/gst/rtp/gstrtpmp4gpay.h b/gst/rtp/gstrtpmp4gpay.h index 491437b07..d79e5df2c 100644 --- a/gst/rtp/gstrtpmp4gpay.h +++ b/gst/rtp/gstrtpmp4gpay.h @@ -48,6 +48,7 @@ struct _GstRtpMP4GPay GstClockTime first_timestamp; GstClockTime first_duration; GstClockTime duration; + guint64 offset; gint rate; gchar *params; @@ -55,6 +56,7 @@ struct _GstRtpMP4GPay const gchar *streamtype; const gchar *mode; GstBuffer *config; + guint frame_len; }; struct _GstRtpMP4GPayClass