summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>2010-08-18 14:40:48 +0200
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>2010-09-06 14:47:05 +0200
commit2953801a5f49d80b0deaaafb06aa6fb8f9891f80 (patch)
tree0019573014af025c31f45f4ba3ebe1d518c3d566
parent275e352a2e6e6e05fac8e047985445422c4a6177 (diff)
rtpamrpay: properly support perfect-rtptime
-rw-r--r--gst/rtp/gstrtpamrpay.c83
-rw-r--r--gst/rtp/gstrtpamrpay.h3
2 files changed, 85 insertions, 1 deletions
diff --git a/gst/rtp/gstrtpamrpay.c b/gst/rtp/gstrtpamrpay.c
index 2ade6a757..ded5cfe98 100644
--- a/gst/rtp/gstrtpamrpay.c
+++ b/gst/rtp/gstrtpamrpay.c
@@ -90,6 +90,9 @@ static gboolean gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload,
static GstFlowReturn gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * pad,
GstBuffer * buffer);
+static GstStateChangeReturn
+gst_rtp_amr_pay_change_state (GstElement * element, GstStateChange transition);
+
GST_BOILERPLATE (GstRtpAMRPay, gst_rtp_amr_pay, GstBaseRTPPayload,
GST_TYPE_BASE_RTP_PAYLOAD);
@@ -113,6 +116,10 @@ static void
gst_rtp_amr_pay_class_init (GstRtpAMRPayClass * klass)
{
GstBaseRTPPayloadClass *gstbasertppayload_class;
+ GstElementClass *gstelement_class;
+
+ gstelement_class = (GstElementClass *) klass;
+ gstelement_class->change_state = gst_rtp_amr_pay_change_state;
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
@@ -129,6 +136,14 @@ gst_rtp_amr_pay_init (GstRtpAMRPay * rtpamrpay, GstRtpAMRPayClass * klass)
/* needed because of GST_BOILERPLATE */
}
+static void
+gst_rtp_amr_pay_reset (GstRtpAMRPay * pay)
+{
+ pay->next_rtp_time = 0;
+ pay->first_ts = GST_CLOCK_TIME_NONE;
+ pay->first_rtp_time = 0;
+}
+
static gboolean
gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps)
{
@@ -178,6 +193,29 @@ wrong_type:
}
}
+static void
+gst_rtp_amr_pay_recalc_rtp_time (GstRtpAMRPay * rtpamrpay,
+ GstClockTime timestamp)
+{
+ /* re-sync rtp time */
+ if (GST_CLOCK_TIME_IS_VALID (rtpamrpay->first_ts) &&
+ GST_CLOCK_TIME_IS_VALID (timestamp) && timestamp >= rtpamrpay->first_ts) {
+ GstClockTime diff;
+ guint32 rtpdiff;
+
+ /* interpolate to reproduce gap from start, rather than intermediate
+ * intervals to avoid roundup accumulation errors */
+ diff = timestamp - rtpamrpay->first_ts;
+ rtpdiff = ((diff / GST_MSECOND) * 8) <<
+ (rtpamrpay->mode == GST_RTP_AMR_P_MODE_WB);
+ rtpamrpay->next_rtp_time = rtpamrpay->first_rtp_time + rtpdiff;
+ GST_DEBUG_OBJECT (rtpamrpay,
+ "elapsed time %" GST_TIME_FORMAT ", rtp %d, "
+ "new offset %" G_GUINT64_FORMAT, GST_TIME_ARGS (diff), rtpdiff,
+ rtpamrpay->next_rtp_time);
+ }
+}
+
/* -1 is invalid */
static gint nb_frame_size[16] = {
12, 13, 15, 17, 19, 20, 26, 31,
@@ -203,6 +241,7 @@ gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
gint i, num_packets, num_nonempty_packets;
gint amr_len;
gint *frame_size;
+ gboolean sid = FALSE;
rtpamrpay = GST_RTP_AMR_PAY (basepayload);
mtu = GST_BASE_RTP_PAYLOAD_MTU (rtpamrpay);
@@ -234,11 +273,14 @@ gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
FT = (data[i] & 0x78) >> 3;
fr_size = frame_size[FT];
- GST_DEBUG_OBJECT (basepayload, "frame size %d", fr_size);
+ GST_DEBUG_OBJECT (basepayload, "frame type %d, frame size %d", FT, fr_size);
/* FIXME, we don't handle this yet.. */
if (fr_size <= 0)
goto wrong_size;
+ if (fr_size == 5)
+ sid = TRUE;
+
amr_len += fr_size;
num_nonempty_packets++;
num_packets++;
@@ -272,7 +314,21 @@ gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit");
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
gst_rtp_buffer_set_marker (outbuf, TRUE);
+ gst_rtp_amr_pay_recalc_rtp_time (rtpamrpay, timestamp);
+ }
+
+ if (G_UNLIKELY (sid)) {
+ gst_rtp_amr_pay_recalc_rtp_time (rtpamrpay, timestamp);
+ }
+
+ /* perfect rtptime */
+ if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (rtpamrpay->first_ts))) {
+ rtpamrpay->first_ts = timestamp;
+ rtpamrpay->first_rtp_time = rtpamrpay->next_rtp_time;
}
+ GST_BUFFER_OFFSET (outbuf) = rtpamrpay->next_rtp_time;
+ rtpamrpay->next_rtp_time +=
+ (num_packets * 160) << (rtpamrpay->mode == GST_RTP_AMR_P_MODE_WB);
/* get payload, this is now writable */
payload = gst_rtp_buffer_get_payload (outbuf);
@@ -350,6 +406,31 @@ too_big:
}
}
+static GstStateChangeReturn
+gst_rtp_amr_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ /* handle upwards state changes here */
+ switch (transition) {
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+ /* handle downwards state changes */
+ switch (transition) {
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_rtp_amr_pay_reset (GST_RTP_AMR_PAY (element));
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
gboolean
gst_rtp_amr_pay_plugin_init (GstPlugin * plugin)
{
diff --git a/gst/rtp/gstrtpamrpay.h b/gst/rtp/gstrtpamrpay.h
index ce86d0d9c..36e32fc17 100644
--- a/gst/rtp/gstrtpamrpay.h
+++ b/gst/rtp/gstrtpamrpay.h
@@ -51,6 +51,9 @@ struct _GstRtpAMRPay
GstBaseRTPPayload payload;
GstRtpAMRPayMode mode;
+ GstClockTime first_ts;
+ guint32 first_rtp_time;
+ guint32 next_rtp_time;
};
struct _GstRtpAMRPayClass