rtpamrpay: properly support perfect-rtptime

This commit is contained in:
Mark Nauwelaerts 2010-08-18 14:40:48 +02:00
parent 275e352a2e
commit 2953801a5f
2 changed files with 85 additions and 1 deletions

View file

@ -90,6 +90,9 @@ static gboolean gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload,
static GstFlowReturn gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * pad, static GstFlowReturn gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * pad,
GstBuffer * buffer); GstBuffer * buffer);
static GstStateChangeReturn
gst_rtp_amr_pay_change_state (GstElement * element, GstStateChange transition);
GST_BOILERPLATE (GstRtpAMRPay, gst_rtp_amr_pay, GstBaseRTPPayload, GST_BOILERPLATE (GstRtpAMRPay, gst_rtp_amr_pay, GstBaseRTPPayload,
GST_TYPE_BASE_RTP_PAYLOAD); GST_TYPE_BASE_RTP_PAYLOAD);
@ -113,6 +116,10 @@ static void
gst_rtp_amr_pay_class_init (GstRtpAMRPayClass * klass) gst_rtp_amr_pay_class_init (GstRtpAMRPayClass * klass)
{ {
GstBaseRTPPayloadClass *gstbasertppayload_class; GstBaseRTPPayloadClass *gstbasertppayload_class;
GstElementClass *gstelement_class;
gstelement_class = (GstElementClass *) klass;
gstelement_class->change_state = gst_rtp_amr_pay_change_state;
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass; gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
@ -129,6 +136,14 @@ gst_rtp_amr_pay_init (GstRtpAMRPay * rtpamrpay, GstRtpAMRPayClass * klass)
/* needed because of GST_BOILERPLATE */ /* 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 static gboolean
gst_rtp_amr_pay_setcaps (GstBaseRTPPayload * basepayload, GstCaps * caps) 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 */ /* -1 is invalid */
static gint nb_frame_size[16] = { static gint nb_frame_size[16] = {
12, 13, 15, 17, 19, 20, 26, 31, 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 i, num_packets, num_nonempty_packets;
gint amr_len; gint amr_len;
gint *frame_size; gint *frame_size;
gboolean sid = FALSE;
rtpamrpay = GST_RTP_AMR_PAY (basepayload); rtpamrpay = GST_RTP_AMR_PAY (basepayload);
mtu = GST_BASE_RTP_PAYLOAD_MTU (rtpamrpay); mtu = GST_BASE_RTP_PAYLOAD_MTU (rtpamrpay);
@ -234,11 +273,14 @@ gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
FT = (data[i] & 0x78) >> 3; FT = (data[i] & 0x78) >> 3;
fr_size = frame_size[FT]; 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.. */ /* FIXME, we don't handle this yet.. */
if (fr_size <= 0) if (fr_size <= 0)
goto wrong_size; goto wrong_size;
if (fr_size == 5)
sid = TRUE;
amr_len += fr_size; amr_len += fr_size;
num_nonempty_packets++; num_nonempty_packets++;
num_packets++; num_packets++;
@ -272,8 +314,22 @@ gst_rtp_amr_pay_handle_buffer (GstBaseRTPPayload * basepayload,
GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit"); GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit");
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
gst_rtp_buffer_set_marker (outbuf, TRUE); 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 */ /* get payload, this is now writable */
payload = gst_rtp_buffer_get_payload (outbuf); 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 gboolean
gst_rtp_amr_pay_plugin_init (GstPlugin * plugin) gst_rtp_amr_pay_plugin_init (GstPlugin * plugin)
{ {

View file

@ -51,6 +51,9 @@ struct _GstRtpAMRPay
GstBaseRTPPayload payload; GstBaseRTPPayload payload;
GstRtpAMRPayMode mode; GstRtpAMRPayMode mode;
GstClockTime first_ts;
guint32 first_rtp_time;
guint32 next_rtp_time;
}; };
struct _GstRtpAMRPayClass struct _GstRtpAMRPayClass