rtpg729pay: properly support perfect-rtptime

This commit is contained in:
Mark Nauwelaerts 2010-08-18 11:39:06 +02:00
parent 713719f705
commit d1974e386a
2 changed files with 62 additions and 21 deletions

View file

@ -136,6 +136,9 @@ gst_rtp_g729_pay_reset (GstRTPG729Pay * pay)
{ {
gst_adapter_clear (pay->adapter); gst_adapter_clear (pay->adapter);
pay->discont = FALSE; pay->discont = FALSE;
pay->next_rtp_time = 0;
pay->first_ts = GST_CLOCK_TIME_NONE;
pay->first_rtp_time = 0;
} }
static gboolean static gboolean
@ -159,10 +162,11 @@ gst_rtp_g729_pay_set_caps (GstBaseRTPPayload * payload, GstCaps * caps)
static GstFlowReturn static GstFlowReturn
gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay, gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay,
const guint8 * data, guint payload_len, GstClockTime timestamp, const guint8 * data, guint payload_len)
GstClockTime duration)
{ {
GstBaseRTPPayload *basepayload; GstBaseRTPPayload *basepayload;
GstClockTime duration;
guint frames;
GstBuffer *outbuf; GstBuffer *outbuf;
guint8 *payload; guint8 *payload;
GstFlowReturn ret; GstFlowReturn ret;
@ -170,7 +174,7 @@ gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay,
basepayload = GST_BASE_RTP_PAYLOAD (rtpg729pay); basepayload = GST_BASE_RTP_PAYLOAD (rtpg729pay);
GST_DEBUG_OBJECT (rtpg729pay, "Pushing %d bytes ts %" GST_TIME_FORMAT, GST_DEBUG_OBJECT (rtpg729pay, "Pushing %d bytes ts %" GST_TIME_FORMAT,
payload_len, GST_TIME_ARGS (timestamp)); payload_len, GST_TIME_ARGS (rtpg729pay->next_ts));
/* create buffer to hold the payload */ /* create buffer to hold the payload */
outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0); outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
@ -180,8 +184,14 @@ gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay,
memcpy (payload, data, payload_len); memcpy (payload, data, payload_len);
/* set metadata */ /* set metadata */
GST_BUFFER_TIMESTAMP (outbuf) = timestamp; frames =
(payload_len / G729_FRAME_SIZE) + ((payload_len % G729_FRAME_SIZE) >> 1);
duration = frames * G729_FRAME_DURATION;
GST_BUFFER_TIMESTAMP (outbuf) = rtpg729pay->next_ts;
GST_BUFFER_DURATION (outbuf) = duration; GST_BUFFER_DURATION (outbuf) = duration;
GST_BUFFER_OFFSET (outbuf) = rtpg729pay->next_rtp_time;
rtpg729pay->next_ts += duration;
rtpg729pay->next_rtp_time += frames * 80;
if (G_UNLIKELY (rtpg729pay->discont)) { if (G_UNLIKELY (rtpg729pay->discont)) {
GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit"); GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit");
@ -195,6 +205,24 @@ gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay,
return ret; return ret;
} }
static void
gst_rtp_g729_pay_recalc_rtp_time (GstRTPG729Pay * rtpg729pay, GstClockTime time)
{
if (GST_CLOCK_TIME_IS_VALID (rtpg729pay->first_ts)
&& GST_CLOCK_TIME_IS_VALID (time) && time >= rtpg729pay->first_ts) {
GstClockTime diff;
guint32 rtpdiff;
diff = time - rtpg729pay->first_ts;
rtpdiff = (diff / GST_MSECOND) * 8;
rtpg729pay->next_rtp_time = rtpg729pay->first_rtp_time + rtpdiff;
GST_DEBUG_OBJECT (rtpg729pay,
"elapsed time %" GST_TIME_FORMAT ", rtp %d, "
"new offset %" G_GUINT64_FORMAT, GST_TIME_ARGS (diff), rtpdiff,
rtpg729pay->next_rtp_time);
}
}
static GstFlowReturn static GstFlowReturn
gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf) gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
{ {
@ -271,34 +299,49 @@ gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
"Calculated min_payload_len %u and max_payload_len %u", "Calculated min_payload_len %u and max_payload_len %u",
min_payload_len, max_payload_len); min_payload_len, max_payload_len);
if (GST_BUFFER_IS_DISCONT (buf))
rtpg729pay->discont = TRUE;
adapter = rtpg729pay->adapter; adapter = rtpg729pay->adapter;
available = gst_adapter_available (adapter);
/* resync rtp time on discont or a discontinuous cn packet */
if (GST_BUFFER_IS_DISCONT (buf)) {
/* flush remainder */
if (available > 0) {
gst_rtp_g729_pay_push (rtpg729pay,
gst_adapter_take (adapter, available), available);
available = 0;
}
rtpg729pay->discont = TRUE;
gst_rtp_g729_pay_recalc_rtp_time (rtpg729pay, GST_BUFFER_TIMESTAMP (buf));
}
if (GST_BUFFER_SIZE (buf) < G729_FRAME_SIZE)
gst_rtp_g729_pay_recalc_rtp_time (rtpg729pay, GST_BUFFER_TIMESTAMP (buf));
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (rtpg729pay->first_ts))) {
rtpg729pay->first_ts = GST_BUFFER_TIMESTAMP (buf);
rtpg729pay->first_rtp_time = rtpg729pay->next_rtp_time;
}
/* let's reset the base timestamp when the adapter is empty */ /* let's reset the base timestamp when the adapter is empty */
if (gst_adapter_available (adapter) == 0) if (available == 0)
rtpg729pay->next_ts = GST_BUFFER_TIMESTAMP (buf); rtpg729pay->next_ts = GST_BUFFER_TIMESTAMP (buf);
if (gst_adapter_available (adapter) == 0 && if (available == 0 &&
GST_BUFFER_SIZE (buf) >= min_payload_len && GST_BUFFER_SIZE (buf) >= min_payload_len &&
GST_BUFFER_SIZE (buf) <= max_payload_len) { GST_BUFFER_SIZE (buf) <= max_payload_len) {
ret = gst_rtp_g729_pay_push (rtpg729pay, ret = gst_rtp_g729_pay_push (rtpg729pay,
GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
GST_BUFFER_TIMESTAMP (buf), GST_BUFFER_DURATION (buf));
gst_buffer_unref (buf); gst_buffer_unref (buf);
return ret; return ret;
} }
gst_adapter_push (adapter, buf); gst_adapter_push (adapter, buf);
available = gst_adapter_available (adapter); available = gst_adapter_available (adapter);
/* as long as we have full frames */ /* as long as we have full frames */
/* this loop will push all available buffers till the last frame */ /* this loop will push all available buffers till the last frame */
while (available >= min_payload_len || while (available >= min_payload_len ||
available % G729_FRAME_SIZE == G729B_CN_FRAME_SIZE) { available % G729_FRAME_SIZE == G729B_CN_FRAME_SIZE) {
GstClockTime duration;
/* We send as much as we can */ /* We send as much as we can */
if (available <= max_payload_len) { if (available <= max_payload_len) {
payload_len = available; payload_len = available;
@ -307,14 +350,9 @@ gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
(available / G729_FRAME_SIZE) * G729_FRAME_SIZE); (available / G729_FRAME_SIZE) * G729_FRAME_SIZE);
} }
duration = (payload_len / G729_FRAME_SIZE) * G729_FRAME_DURATION;
rtpg729pay->next_ts += duration;
ret = gst_rtp_g729_pay_push (rtpg729pay, ret = gst_rtp_g729_pay_push (rtpg729pay,
gst_adapter_take (adapter, payload_len), payload_len, gst_adapter_take (adapter, payload_len), payload_len);
rtpg729pay->next_ts, duration); available -= payload_len;
available = gst_adapter_available (adapter);
} }
return ret; return ret;

View file

@ -46,6 +46,9 @@ struct _GstRTPG729Pay
GstAdapter *adapter; GstAdapter *adapter;
GstClockTime next_ts; GstClockTime next_ts;
guint32 next_rtp_time;
GstClockTime first_ts;
guint32 first_rtp_time;
gboolean discont; gboolean discont;
}; };