rtpg729pay: avoid basertppayload perfect-rtptime mode
G729 packets may only occur intermittently (e.g. cn packets), and as such do not allow for perfect-rtptime calculating rtp times based on frame or byte count. In particular, do not use rtp audio base payloader as base class, but rather base payloader directly.
This commit is contained in:
parent
6405df0c50
commit
f1fe0e7157
@ -48,6 +48,9 @@ gst_rtp_g729_pay_set_caps (GstBaseRTPPayload * payload, GstCaps * caps);
|
|||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf);
|
gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf);
|
||||||
|
|
||||||
|
static GstStateChangeReturn
|
||||||
|
gst_rtp_g729_pay_change_state (GstElement * element, GstStateChange transition);
|
||||||
|
|
||||||
static GstStaticPadTemplate gst_rtp_g729_pay_sink_template =
|
static GstStaticPadTemplate gst_rtp_g729_pay_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
GST_PAD_SINK,
|
GST_PAD_SINK,
|
||||||
@ -71,8 +74,8 @@ static GstStaticPadTemplate gst_rtp_g729_pay_src_template =
|
|||||||
"clock-rate = (int) 8000, " "encoding-name = (string) \"G729\"")
|
"clock-rate = (int) 8000, " "encoding-name = (string) \"G729\"")
|
||||||
);
|
);
|
||||||
|
|
||||||
GST_BOILERPLATE (GstRTPG729Pay, gst_rtp_g729_pay, GstBaseRTPAudioPayload,
|
GST_BOILERPLATE (GstRTPG729Pay, gst_rtp_g729_pay, GstBaseRTPPayload,
|
||||||
GST_TYPE_BASE_RTP_AUDIO_PAYLOAD);
|
GST_TYPE_BASE_RTP_PAYLOAD);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtp_g729_pay_base_init (gpointer klass)
|
gst_rtp_g729_pay_base_init (gpointer klass)
|
||||||
@ -92,11 +95,27 @@ gst_rtp_g729_pay_base_init (gpointer klass)
|
|||||||
"G.729 RTP Payloader");
|
"G.729 RTP Payloader");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtp_g729_pay_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
GstRTPG729Pay *pay = GST_RTP_G729_PAY (object);
|
||||||
|
|
||||||
|
g_object_unref (pay->adapter);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_rtp_g729_pay_class_init (GstRTPG729PayClass * klass)
|
gst_rtp_g729_pay_class_init (GstRTPG729PayClass * klass)
|
||||||
{
|
{
|
||||||
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||||
|
GstElementClass *gstelement_class = (GstElementClass *) klass;
|
||||||
GstBaseRTPPayloadClass *payload_class = GST_BASE_RTP_PAYLOAD_CLASS (klass);
|
GstBaseRTPPayloadClass *payload_class = GST_BASE_RTP_PAYLOAD_CLASS (klass);
|
||||||
|
|
||||||
|
gobject_class->finalize = gst_rtp_g729_pay_finalize;
|
||||||
|
|
||||||
|
gstelement_class->change_state = gst_rtp_g729_pay_change_state;
|
||||||
|
|
||||||
payload_class->set_caps = gst_rtp_g729_pay_set_caps;
|
payload_class->set_caps = gst_rtp_g729_pay_set_caps;
|
||||||
payload_class->handle_buffer = gst_rtp_g729_pay_handle_buffer;
|
payload_class->handle_buffer = gst_rtp_g729_pay_handle_buffer;
|
||||||
}
|
}
|
||||||
@ -105,15 +124,18 @@ static void
|
|||||||
gst_rtp_g729_pay_init (GstRTPG729Pay * pay, GstRTPG729PayClass * klass)
|
gst_rtp_g729_pay_init (GstRTPG729Pay * pay, GstRTPG729PayClass * klass)
|
||||||
{
|
{
|
||||||
GstBaseRTPPayload *payload = GST_BASE_RTP_PAYLOAD (pay);
|
GstBaseRTPPayload *payload = GST_BASE_RTP_PAYLOAD (pay);
|
||||||
GstBaseRTPAudioPayload *audiopayload = GST_BASE_RTP_AUDIO_PAYLOAD (pay);
|
|
||||||
|
|
||||||
payload->pt = GST_RTP_PAYLOAD_G729;
|
payload->pt = GST_RTP_PAYLOAD_G729;
|
||||||
gst_basertppayload_set_options (payload, "audio", FALSE, "G729", 8000);
|
gst_basertppayload_set_options (payload, "audio", FALSE, "G729", 8000);
|
||||||
|
|
||||||
gst_base_rtp_audio_payload_set_frame_based (audiopayload);
|
pay->adapter = gst_adapter_new ();
|
||||||
gst_base_rtp_audio_payload_set_frame_options (audiopayload,
|
}
|
||||||
G729_FRAME_DURATION_MS, G729_FRAME_SIZE);
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rtp_g729_pay_reset (GstRTPG729Pay * pay)
|
||||||
|
{
|
||||||
|
gst_adapter_clear (pay->adapter);
|
||||||
|
pay->discont = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -135,12 +157,49 @@ gst_rtp_g729_pay_set_caps (GstBaseRTPPayload * payload, GstCaps * caps)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay,
|
||||||
|
const guint8 * data, guint payload_len, GstClockTime timestamp,
|
||||||
|
GstClockTime duration)
|
||||||
|
{
|
||||||
|
GstBaseRTPPayload *basepayload;
|
||||||
|
GstBuffer *outbuf;
|
||||||
|
guint8 *payload;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
|
basepayload = GST_BASE_RTP_PAYLOAD (rtpg729pay);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (rtpg729pay, "Pushing %d bytes ts %" GST_TIME_FORMAT,
|
||||||
|
payload_len, GST_TIME_ARGS (timestamp));
|
||||||
|
|
||||||
|
/* create buffer to hold the payload */
|
||||||
|
outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
|
||||||
|
|
||||||
|
/* copy payload */
|
||||||
|
payload = gst_rtp_buffer_get_payload (outbuf);
|
||||||
|
memcpy (payload, data, payload_len);
|
||||||
|
|
||||||
|
/* set metadata */
|
||||||
|
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
|
||||||
|
GST_BUFFER_DURATION (outbuf) = duration;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (rtpg729pay->discont)) {
|
||||||
|
GST_DEBUG_OBJECT (basepayload, "discont, setting marker bit");
|
||||||
|
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
|
||||||
|
gst_rtp_buffer_set_marker (outbuf, TRUE);
|
||||||
|
rtpg729pay->discont = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gst_basertppayload_push (basepayload, outbuf);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
|
gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
GstBaseRTPAudioPayload *basertpaudiopayload =
|
GstRTPG729Pay *rtpg729pay = GST_RTP_G729_PAY (payload);
|
||||||
GST_BASE_RTP_AUDIO_PAYLOAD (payload);
|
|
||||||
GstAdapter *adapter = NULL;
|
GstAdapter *adapter = NULL;
|
||||||
guint payload_len;
|
guint payload_len;
|
||||||
guint available;
|
guint available;
|
||||||
@ -164,7 +223,7 @@ gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
|
|||||||
(int) (ptime_ms / G729_FRAME_DURATION_MS);
|
(int) (ptime_ms / G729_FRAME_DURATION_MS);
|
||||||
|
|
||||||
if (maxptime_octets < G729_FRAME_SIZE) {
|
if (maxptime_octets < G729_FRAME_SIZE) {
|
||||||
GST_WARNING_OBJECT (basertpaudiopayload, "Given ptime %" G_GINT64_FORMAT
|
GST_WARNING_OBJECT (payload, "Given ptime %" G_GINT64_FORMAT
|
||||||
" is smaller than minimum %d ns, overwriting to minimum",
|
" is smaller than minimum %d ns, overwriting to minimum",
|
||||||
payload->max_ptime, G729_FRAME_DURATION_MS);
|
payload->max_ptime, G729_FRAME_DURATION_MS);
|
||||||
maxptime_octets = G729_FRAME_SIZE;
|
maxptime_octets = G729_FRAME_SIZE;
|
||||||
@ -174,7 +233,8 @@ gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
|
|||||||
max_payload_len = MIN (
|
max_payload_len = MIN (
|
||||||
/* MTU max */
|
/* MTU max */
|
||||||
(int) (gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU
|
(int) (gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU
|
||||||
(basertpaudiopayload), 0, 0) / G729_FRAME_SIZE) * G729_FRAME_SIZE,
|
(payload), 0, 0) / G729_FRAME_SIZE)
|
||||||
|
* G729_FRAME_SIZE,
|
||||||
/* ptime max */
|
/* ptime max */
|
||||||
maxptime_octets);
|
maxptime_octets);
|
||||||
|
|
||||||
@ -207,25 +267,26 @@ gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
|
|||||||
min_payload_len = max_payload_len = ptime_in_bytes;
|
min_payload_len = max_payload_len = ptime_in_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOG_OBJECT (basertpaudiopayload,
|
GST_LOG_OBJECT (payload,
|
||||||
"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);
|
||||||
|
|
||||||
adapter = gst_base_rtp_audio_payload_get_adapter (basertpaudiopayload);
|
if (GST_BUFFER_IS_DISCONT (buf))
|
||||||
|
rtpg729pay->discont = TRUE;
|
||||||
|
|
||||||
|
adapter = rtpg729pay->adapter;
|
||||||
|
|
||||||
/* 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 (gst_adapter_available (adapter) == 0)
|
||||||
basertpaudiopayload->base_ts = GST_BUFFER_TIMESTAMP (buf);
|
rtpg729pay->next_ts = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
|
||||||
if (gst_adapter_available (adapter) == 0 &&
|
if (gst_adapter_available (adapter) == 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_base_rtp_audio_payload_push (basertpaudiopayload,
|
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_TIMESTAMP (buf), GST_BUFFER_DURATION (buf));
|
||||||
gst_buffer_unref (buf);
|
gst_buffer_unref (buf);
|
||||||
g_object_unref (adapter);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,7 +297,7 @@ gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
|
|||||||
/* 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) {
|
||||||
guint num;
|
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) {
|
||||||
@ -246,17 +307,16 @@ gst_rtp_g729_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buf)
|
|||||||
(available / G729_FRAME_SIZE) * G729_FRAME_SIZE);
|
(available / G729_FRAME_SIZE) * G729_FRAME_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = gst_base_rtp_audio_payload_flush (basertpaudiopayload, payload_len,
|
duration = (payload_len / G729_FRAME_SIZE) * G729_FRAME_DURATION;
|
||||||
basertpaudiopayload->base_ts);
|
rtpg729pay->next_ts += duration;
|
||||||
|
|
||||||
num = payload_len / G729_FRAME_SIZE;
|
ret = gst_rtp_g729_pay_push (rtpg729pay,
|
||||||
basertpaudiopayload->base_ts += G729_FRAME_DURATION * num;
|
gst_adapter_take (adapter, payload_len), payload_len,
|
||||||
|
rtpg729pay->next_ts, duration);
|
||||||
|
|
||||||
available = gst_adapter_available (adapter);
|
available = gst_adapter_available (adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_object_unref (adapter);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
@ -272,6 +332,31 @@ invalid_size:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstStateChangeReturn
|
||||||
|
gst_rtp_g729_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_g729_pay_reset (GST_RTP_G729_PAY (element));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtp_g729_pay_plugin_init (GstPlugin * plugin)
|
gst_rtp_g729_pay_plugin_init (GstPlugin * plugin)
|
||||||
{
|
{
|
||||||
|
@ -43,6 +43,10 @@ typedef struct _GstRTPG729PayClass GstRTPG729PayClass;
|
|||||||
struct _GstRTPG729Pay
|
struct _GstRTPG729Pay
|
||||||
{
|
{
|
||||||
GstBaseRTPAudioPayload audiopayload;
|
GstBaseRTPAudioPayload audiopayload;
|
||||||
|
|
||||||
|
GstAdapter *adapter;
|
||||||
|
GstClockTime next_ts;
|
||||||
|
gboolean discont;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstRTPG729PayClass
|
struct _GstRTPG729PayClass
|
||||||
|
Loading…
x
Reference in New Issue
Block a user