mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-28 19:20:35 +00:00
audiortppay: handle gaps
Add various conversion functions between time<->bytes<->rtptime that will be used later on. Refactor the min/max packet length code so that it can be used for both sample/frame based payloaders. Cache the returned values. code cleanups. When we discover a DISCONT buffer, make the outgoing RTP timestamps have the same gap as the GStreamer timestamps gap.
This commit is contained in:
parent
3a3c6f309c
commit
c1db9ebb20
1 changed files with 240 additions and 178 deletions
|
@ -70,26 +70,36 @@
|
|||
GST_DEBUG_CATEGORY_STATIC (basertpaudiopayload_debug);
|
||||
#define GST_CAT_DEFAULT (basertpaudiopayload_debug)
|
||||
|
||||
/* function to calculate the min/max length and alignment of a packet */
|
||||
typedef gboolean (*GetLengthsFunc) (GstBaseRTPPayload * basepayload,
|
||||
guint * min_payload_len, guint * max_payload_len, guint * align);
|
||||
/* function to convert bytes to a duration */
|
||||
typedef GstClockTime (*GetDurationFunc) (GstBaseRTPAudioPayload * payload,
|
||||
/* function to convert bytes to a time */
|
||||
typedef GstClockTime (*GetBytesToTimeFunc) (GstBaseRTPAudioPayload * payload,
|
||||
guint64 bytes);
|
||||
/* function to convert bytes to RTP timestamp */
|
||||
typedef guint32 (*GetRTPTimeFunc) (GstBaseRTPAudioPayload * payload,
|
||||
/* function to convert bytes to a RTP time */
|
||||
typedef guint32 (*GetBytesToRTPTimeFunc) (GstBaseRTPAudioPayload * payload,
|
||||
guint64 bytes);
|
||||
/* function to convert time to bytes */
|
||||
typedef guint64 (*GetTimeToBytesFunc) (GstBaseRTPAudioPayload * payload,
|
||||
GstClockTime time);
|
||||
|
||||
struct _GstBaseRTPAudioPayloadPrivate
|
||||
{
|
||||
GetLengthsFunc get_lengths;
|
||||
GetDurationFunc get_duration;
|
||||
GetRTPTimeFunc get_rtptime;
|
||||
GetBytesToTimeFunc bytes_to_time;
|
||||
GetBytesToRTPTimeFunc bytes_to_rtptime;
|
||||
GetTimeToBytesFunc time_to_bytes;
|
||||
|
||||
GstAdapter *adapter;
|
||||
guint fragment_size;
|
||||
GstClockTime frame_duration_ns;
|
||||
gboolean discont;
|
||||
guint64 offset;
|
||||
GstClockTime last_timestamp;
|
||||
guint32 last_rtptime;
|
||||
guint align;
|
||||
|
||||
guint cached_mtu;
|
||||
guint cached_min_ptime;
|
||||
guint cached_max_ptime;
|
||||
guint cached_min_length;
|
||||
guint cached_max_length;
|
||||
};
|
||||
|
||||
|
||||
|
@ -99,29 +109,29 @@ struct _GstBaseRTPAudioPayloadPrivate
|
|||
|
||||
static void gst_base_rtp_audio_payload_finalize (GObject * object);
|
||||
|
||||
/* length functions */
|
||||
static gboolean gst_base_rtp_audio_payload_get_frame_lengths (GstBaseRTPPayload
|
||||
* basepayload, guint * min_payload_len, guint * max_payload_len,
|
||||
guint * align);
|
||||
static gboolean gst_base_rtp_audio_payload_get_sample_lengths (GstBaseRTPPayload
|
||||
* basepayload, guint * min_payload_len, guint * max_payload_len,
|
||||
guint * align);
|
||||
|
||||
/* duration functions */
|
||||
/* bytes to time functions */
|
||||
static GstClockTime
|
||||
gst_base_rtp_audio_payload_get_frame_duration (GstBaseRTPAudioPayload * payload,
|
||||
guint64 bytes);
|
||||
gst_base_rtp_audio_payload_frame_bytes_to_time (GstBaseRTPAudioPayload *
|
||||
payload, guint64 bytes);
|
||||
static GstClockTime
|
||||
gst_base_rtp_audio_payload_get_sample_duration (GstBaseRTPAudioPayload *
|
||||
gst_base_rtp_audio_payload_sample_bytes_to_time (GstBaseRTPAudioPayload *
|
||||
payload, guint64 bytes);
|
||||
|
||||
/* rtptime functions */
|
||||
/* bytes to RTP time functions */
|
||||
static guint32
|
||||
gst_base_rtp_audio_payload_get_frame_rtptime (GstBaseRTPAudioPayload * payload,
|
||||
guint64 bytes);
|
||||
static guint32
|
||||
gst_base_rtp_audio_payload_get_sample_rtptime (GstBaseRTPAudioPayload *
|
||||
gst_base_rtp_audio_payload_frame_bytes_to_rtptime (GstBaseRTPAudioPayload *
|
||||
payload, guint64 bytes);
|
||||
static guint32
|
||||
gst_base_rtp_audio_payload_sample_bytes_to_rtptime (GstBaseRTPAudioPayload *
|
||||
payload, guint64 bytes);
|
||||
|
||||
/* time to bytes functions */
|
||||
static guint64
|
||||
gst_base_rtp_audio_payload_frame_time_to_bytes (GstBaseRTPAudioPayload *
|
||||
payload, GstClockTime time);
|
||||
static guint64
|
||||
gst_base_rtp_audio_payload_sample_time_to_bytes (GstBaseRTPAudioPayload *
|
||||
payload, GstClockTime time);
|
||||
|
||||
static GstFlowReturn gst_base_rtp_audio_payload_handle_buffer (GstBaseRTPPayload
|
||||
* payload, GstBuffer * buffer);
|
||||
|
@ -169,30 +179,29 @@ gst_base_rtp_audio_payload_class_init (GstBaseRTPAudioPayloadClass * klass)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_base_rtp_audio_payload_init (GstBaseRTPAudioPayload * basertpaudiopayload,
|
||||
gst_base_rtp_audio_payload_init (GstBaseRTPAudioPayload * payload,
|
||||
GstBaseRTPAudioPayloadClass * klass)
|
||||
{
|
||||
basertpaudiopayload->priv =
|
||||
GST_BASE_RTP_AUDIO_PAYLOAD_GET_PRIVATE (basertpaudiopayload);
|
||||
payload->priv = GST_BASE_RTP_AUDIO_PAYLOAD_GET_PRIVATE (payload);
|
||||
|
||||
/* these need to be set by child object if frame based */
|
||||
basertpaudiopayload->frame_size = 0;
|
||||
basertpaudiopayload->frame_duration = 0;
|
||||
payload->frame_size = 0;
|
||||
payload->frame_duration = 0;
|
||||
|
||||
/* these need to be set by child object if sample based */
|
||||
basertpaudiopayload->sample_size = 0;
|
||||
payload->sample_size = 0;
|
||||
|
||||
basertpaudiopayload->priv->adapter = gst_adapter_new ();
|
||||
payload->priv->adapter = gst_adapter_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
gst_base_rtp_audio_payload_finalize (GObject * object)
|
||||
{
|
||||
GstBaseRTPAudioPayload *basertpaudiopayload;
|
||||
GstBaseRTPAudioPayload *payload;
|
||||
|
||||
basertpaudiopayload = GST_BASE_RTP_AUDIO_PAYLOAD (object);
|
||||
payload = GST_BASE_RTP_AUDIO_PAYLOAD (object);
|
||||
|
||||
g_object_unref (basertpaudiopayload->priv->adapter);
|
||||
g_object_unref (payload->priv->adapter);
|
||||
|
||||
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
|
||||
}
|
||||
|
@ -209,15 +218,16 @@ gst_base_rtp_audio_payload_set_frame_based (GstBaseRTPAudioPayload *
|
|||
basertpaudiopayload)
|
||||
{
|
||||
g_return_if_fail (basertpaudiopayload != NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->get_lengths == NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->get_duration == NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->time_to_bytes == NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->bytes_to_time == NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->bytes_to_rtptime == NULL);
|
||||
|
||||
basertpaudiopayload->priv->get_lengths =
|
||||
gst_base_rtp_audio_payload_get_frame_lengths;
|
||||
basertpaudiopayload->priv->get_duration =
|
||||
gst_base_rtp_audio_payload_get_frame_duration;
|
||||
basertpaudiopayload->priv->get_rtptime =
|
||||
gst_base_rtp_audio_payload_get_frame_rtptime;
|
||||
basertpaudiopayload->priv->bytes_to_time =
|
||||
gst_base_rtp_audio_payload_frame_bytes_to_time;
|
||||
basertpaudiopayload->priv->bytes_to_rtptime =
|
||||
gst_base_rtp_audio_payload_frame_bytes_to_rtptime;
|
||||
basertpaudiopayload->priv->time_to_bytes =
|
||||
gst_base_rtp_audio_payload_frame_time_to_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -232,15 +242,16 @@ gst_base_rtp_audio_payload_set_sample_based (GstBaseRTPAudioPayload *
|
|||
basertpaudiopayload)
|
||||
{
|
||||
g_return_if_fail (basertpaudiopayload != NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->get_lengths == NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->get_duration == NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->time_to_bytes == NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->bytes_to_time == NULL);
|
||||
g_return_if_fail (basertpaudiopayload->priv->bytes_to_rtptime == NULL);
|
||||
|
||||
basertpaudiopayload->priv->get_lengths =
|
||||
gst_base_rtp_audio_payload_get_sample_lengths;
|
||||
basertpaudiopayload->priv->get_duration =
|
||||
gst_base_rtp_audio_payload_get_sample_duration;
|
||||
basertpaudiopayload->priv->get_rtptime =
|
||||
gst_base_rtp_audio_payload_get_sample_rtptime;
|
||||
basertpaudiopayload->priv->bytes_to_time =
|
||||
gst_base_rtp_audio_payload_sample_bytes_to_time;
|
||||
basertpaudiopayload->priv->bytes_to_rtptime =
|
||||
gst_base_rtp_audio_payload_sample_bytes_to_rtptime;
|
||||
basertpaudiopayload->priv->time_to_bytes =
|
||||
gst_base_rtp_audio_payload_sample_time_to_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -256,12 +267,18 @@ void
|
|||
gst_base_rtp_audio_payload_set_frame_options (GstBaseRTPAudioPayload
|
||||
* basertpaudiopayload, gint frame_duration, gint frame_size)
|
||||
{
|
||||
GstBaseRTPAudioPayloadPrivate *priv;
|
||||
|
||||
g_return_if_fail (basertpaudiopayload != NULL);
|
||||
|
||||
basertpaudiopayload->frame_duration = frame_duration;
|
||||
basertpaudiopayload->frame_size = frame_size;
|
||||
priv = basertpaudiopayload->priv;
|
||||
|
||||
gst_adapter_clear (basertpaudiopayload->priv->adapter);
|
||||
basertpaudiopayload->frame_duration = frame_duration;
|
||||
priv->frame_duration_ns = frame_duration * GST_MSECOND;
|
||||
basertpaudiopayload->frame_size = frame_size;
|
||||
priv->align = frame_size;
|
||||
|
||||
gst_adapter_clear (priv->adapter);
|
||||
|
||||
GST_DEBUG_OBJECT (basertpaudiopayload, "frame set to %d ms and size %d",
|
||||
frame_duration, frame_size);
|
||||
|
@ -299,18 +316,22 @@ gst_base_rtp_audio_payload_set_samplebits_options (GstBaseRTPAudioPayload
|
|||
* basertpaudiopayload, gint sample_size)
|
||||
{
|
||||
guint fragment_size;
|
||||
GstBaseRTPAudioPayloadPrivate *priv;
|
||||
|
||||
g_return_if_fail (basertpaudiopayload != NULL);
|
||||
|
||||
priv = basertpaudiopayload->priv;
|
||||
|
||||
basertpaudiopayload->sample_size = sample_size;
|
||||
|
||||
/* sample_size is in bits and is converted into multiple bytes */
|
||||
fragment_size = sample_size;
|
||||
while ((fragment_size % 8) != 0)
|
||||
fragment_size += fragment_size;
|
||||
basertpaudiopayload->priv->fragment_size = fragment_size / 8;
|
||||
priv->fragment_size = fragment_size / 8;
|
||||
priv->align = priv->fragment_size;
|
||||
|
||||
gst_adapter_clear (basertpaudiopayload->priv->adapter);
|
||||
gst_adapter_clear (priv->adapter);
|
||||
|
||||
GST_DEBUG_OBJECT (basertpaudiopayload,
|
||||
"Samplebits set to sample size %d bits", sample_size);
|
||||
|
@ -321,25 +342,31 @@ gst_base_rtp_audio_payload_set_meta (GstBaseRTPAudioPayload * payload,
|
|||
GstBuffer * buffer, guint payload_len, GstClockTime timestamp)
|
||||
{
|
||||
GstBaseRTPPayload *basepayload;
|
||||
GstBaseRTPAudioPayloadPrivate *priv;
|
||||
|
||||
basepayload = GST_BASE_RTP_PAYLOAD_CAST (payload);
|
||||
priv = payload->priv;
|
||||
|
||||
/* set payload type */
|
||||
gst_rtp_buffer_set_payload_type (buffer, basepayload->pt);
|
||||
/* set marker bit for disconts */
|
||||
if (payload->priv->discont) {
|
||||
if (priv->discont) {
|
||||
GST_DEBUG_OBJECT (payload, "Setting marker and DISCONT");
|
||||
gst_rtp_buffer_set_marker (buffer, TRUE);
|
||||
GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
|
||||
payload->priv->discont = FALSE;
|
||||
priv->discont = FALSE;
|
||||
}
|
||||
GST_BUFFER_TIMESTAMP (buffer) = timestamp;
|
||||
|
||||
/* get the offset in bytes */
|
||||
GST_BUFFER_OFFSET (buffer) =
|
||||
payload->priv->get_rtptime (payload, payload->priv->offset);
|
||||
/* get the offset in RTP time */
|
||||
GST_BUFFER_OFFSET (buffer) = priv->bytes_to_rtptime (payload, priv->offset);
|
||||
|
||||
payload->priv->offset += payload_len;
|
||||
priv->offset += payload_len;
|
||||
|
||||
/* remember the last rtptime/timestamp pair. We will use this to realign our
|
||||
* RTP timestamp after a buffer discont */
|
||||
priv->last_rtptime = GST_BUFFER_OFFSET (buffer);
|
||||
priv->last_timestamp = timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -374,14 +401,14 @@ gst_base_rtp_audio_payload_push (GstBaseRTPAudioPayload * baseaudiopayload,
|
|||
/* create buffer to hold the payload */
|
||||
outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
|
||||
|
||||
/* set metadata */
|
||||
gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
|
||||
timestamp);
|
||||
|
||||
/* copy payload */
|
||||
payload = gst_rtp_buffer_get_payload (outbuf);
|
||||
memcpy (payload, data, payload_len);
|
||||
|
||||
/* set metadata */
|
||||
gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
|
||||
timestamp);
|
||||
|
||||
ret = gst_basertppayload_push (basepayload, outbuf);
|
||||
|
||||
return ret;
|
||||
|
@ -409,13 +436,15 @@ gst_base_rtp_audio_payload_flush (GstBaseRTPAudioPayload * baseaudiopayload,
|
|||
guint payload_len, GstClockTime timestamp)
|
||||
{
|
||||
GstBaseRTPPayload *basepayload;
|
||||
GstBaseRTPAudioPayloadPrivate *priv;
|
||||
GstBuffer *outbuf;
|
||||
guint8 *payload;
|
||||
GstFlowReturn ret;
|
||||
GstAdapter *adapter;
|
||||
guint64 distance;
|
||||
|
||||
adapter = baseaudiopayload->priv->adapter;
|
||||
priv = baseaudiopayload->priv;
|
||||
adapter = priv->adapter;
|
||||
|
||||
basepayload = GST_BASE_RTP_PAYLOAD (baseaudiopayload);
|
||||
|
||||
|
@ -437,8 +466,7 @@ gst_base_rtp_audio_payload_flush (GstBaseRTPAudioPayload * baseaudiopayload,
|
|||
if (GST_CLOCK_TIME_IS_VALID (timestamp) && distance > 0) {
|
||||
/* convert the number of bytes since the last timestamp to time and add to
|
||||
* the last seen timestamp */
|
||||
timestamp +=
|
||||
baseaudiopayload->priv->get_duration (baseaudiopayload, distance);
|
||||
timestamp += priv->bytes_to_time (baseaudiopayload, distance);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,14 +476,14 @@ gst_base_rtp_audio_payload_flush (GstBaseRTPAudioPayload * baseaudiopayload,
|
|||
/* create buffer to hold the payload */
|
||||
outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
|
||||
|
||||
/* set metadata */
|
||||
gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
|
||||
timestamp);
|
||||
|
||||
payload = gst_rtp_buffer_get_payload (outbuf);
|
||||
gst_adapter_copy (adapter, payload, 0, payload_len);
|
||||
gst_adapter_flush (adapter, payload_len);
|
||||
|
||||
/* set metadata */
|
||||
gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
|
||||
timestamp);
|
||||
|
||||
ret = gst_basertppayload_push (basepayload, outbuf);
|
||||
|
||||
return ret;
|
||||
|
@ -463,138 +491,142 @@ gst_base_rtp_audio_payload_flush (GstBaseRTPAudioPayload * baseaudiopayload,
|
|||
|
||||
#define ALIGN_DOWN(val,len) ((val) - ((val) % (len)))
|
||||
|
||||
/* this assumes all frames have a constant duration and a constant size */
|
||||
/* calculate the min and max length of a packet. This depends on the configured
|
||||
* mtu and min/max_ptime values. We cache those so that we don't have to redo
|
||||
* all the calculations */
|
||||
static gboolean
|
||||
gst_base_rtp_audio_payload_get_frame_lengths (GstBaseRTPPayload *
|
||||
gst_base_rtp_audio_payload_get_lengths (GstBaseRTPPayload *
|
||||
basepayload, guint * min_payload_len, guint * max_payload_len,
|
||||
guint * align)
|
||||
{
|
||||
GstBaseRTPAudioPayload *payload;
|
||||
guint frame_size;
|
||||
guint frame_duration;
|
||||
guint max_frames;
|
||||
GstBaseRTPAudioPayloadPrivate *priv;
|
||||
guint max_mtu, mtu;
|
||||
guint maxptime_octets;
|
||||
guint minptime_octets;
|
||||
|
||||
payload = GST_BASE_RTP_AUDIO_PAYLOAD_CAST (basepayload);
|
||||
priv = payload->priv;
|
||||
|
||||
if (payload->frame_size == 0 || payload->frame_duration == 0)
|
||||
if (priv->align == 0)
|
||||
return FALSE;
|
||||
|
||||
*align = frame_size = payload->frame_size;
|
||||
frame_duration = payload->frame_duration * GST_MSECOND;
|
||||
*align = priv->align;
|
||||
|
||||
mtu = GST_BASE_RTP_PAYLOAD_MTU (payload);
|
||||
|
||||
/* check cached values */
|
||||
if (G_LIKELY (priv->cached_mtu == mtu
|
||||
&& priv->cached_max_ptime == basepayload->max_ptime
|
||||
&& priv->cached_min_ptime == basepayload->min_ptime)) {
|
||||
/* if nothing changed, return cached values */
|
||||
*min_payload_len = priv->cached_min_length;
|
||||
*max_payload_len = priv->cached_max_length;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ptime max */
|
||||
if (basepayload->max_ptime != -1) {
|
||||
maxptime_octets =
|
||||
gst_util_uint64_scale (frame_size, basepayload->max_ptime,
|
||||
frame_duration);
|
||||
/* must be a multiple of the frame_size */
|
||||
maxptime_octets = MAX (frame_size, maxptime_octets);
|
||||
maxptime_octets = priv->time_to_bytes (payload, basepayload->max_ptime);
|
||||
} else {
|
||||
maxptime_octets = G_MAXUINT;
|
||||
}
|
||||
|
||||
/* MTU max */
|
||||
max_frames =
|
||||
gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU (payload), 0,
|
||||
0);
|
||||
/* round down to frame_size */
|
||||
max_frames = ALIGN_DOWN (max_frames, frame_size);
|
||||
/* max payload length */
|
||||
*max_payload_len = MIN (max_frames, maxptime_octets);
|
||||
max_mtu = gst_rtp_buffer_calc_payload_len (mtu, 0, 0);
|
||||
/* round down to alignment */
|
||||
max_mtu = ALIGN_DOWN (max_mtu, *align);
|
||||
|
||||
/* min number of bytes based on a given ptime, has to be a multiple
|
||||
of frame duration */
|
||||
minptime_octets =
|
||||
gst_util_uint64_scale (frame_size, basepayload->min_ptime,
|
||||
frame_duration);
|
||||
*min_payload_len = MAX (minptime_octets, frame_size);
|
||||
|
||||
if (*min_payload_len > *max_payload_len)
|
||||
*min_payload_len = *max_payload_len;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstClockTime
|
||||
gst_base_rtp_audio_payload_get_frame_duration (GstBaseRTPAudioPayload *
|
||||
payload, guint64 bytes)
|
||||
{
|
||||
return (bytes / payload->frame_size) * (payload->frame_duration *
|
||||
GST_MSECOND);
|
||||
}
|
||||
|
||||
static guint32
|
||||
gst_base_rtp_audio_payload_get_frame_rtptime (GstBaseRTPAudioPayload * payload,
|
||||
guint64 bytes)
|
||||
{
|
||||
GstClockTime duration;
|
||||
|
||||
duration =
|
||||
(bytes / payload->frame_size) * (payload->frame_duration * GST_MSECOND);
|
||||
|
||||
return gst_util_uint64_scale_int (duration,
|
||||
GST_BASE_RTP_PAYLOAD_CAST (payload)->clock_rate, GST_SECOND);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_base_rtp_audio_payload_get_sample_lengths (GstBaseRTPPayload *
|
||||
basepayload, guint * min_payload_len, guint * max_payload_len,
|
||||
guint * align)
|
||||
{
|
||||
GstBaseRTPAudioPayload *payload;
|
||||
guint maxptime_octets;
|
||||
guint minptime_octets;
|
||||
|
||||
payload = GST_BASE_RTP_AUDIO_PAYLOAD_CAST (basepayload);
|
||||
|
||||
if (payload->sample_size == 0)
|
||||
return FALSE;
|
||||
|
||||
/* sample_size is in bits and is converted into multiple bytes */
|
||||
*align = payload->priv->fragment_size;
|
||||
|
||||
/* max number of bytes based on given ptime */
|
||||
if (basepayload->max_ptime != -1) {
|
||||
maxptime_octets = gst_util_uint64_scale (basepayload->max_ptime * 8,
|
||||
basepayload->clock_rate, payload->sample_size * GST_SECOND);
|
||||
} else {
|
||||
maxptime_octets = G_MAXUINT;
|
||||
}
|
||||
|
||||
*max_payload_len = MIN (
|
||||
/* MTU max */
|
||||
gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU
|
||||
(payload), 0, 0),
|
||||
/* ptime max */
|
||||
maxptime_octets);
|
||||
|
||||
/* min number of bytes based on a given ptime, has to be a multiple
|
||||
* of sample rate */
|
||||
minptime_octets = gst_util_uint64_scale (basepayload->min_ptime * 8,
|
||||
basepayload->clock_rate, payload->sample_size * GST_SECOND);
|
||||
/* combine max ptime and max payload length */
|
||||
*max_payload_len = MIN (max_mtu, maxptime_octets);
|
||||
|
||||
/* min number of bytes based on a given ptime */
|
||||
minptime_octets = priv->time_to_bytes (payload, basepayload->min_ptime);
|
||||
/* must be at least one frame size */
|
||||
*min_payload_len = MAX (minptime_octets, *align);
|
||||
|
||||
if (*min_payload_len > *max_payload_len)
|
||||
*min_payload_len = *max_payload_len;
|
||||
|
||||
/* cache values */
|
||||
priv->cached_mtu = mtu;
|
||||
priv->cached_min_ptime = basepayload->min_ptime;
|
||||
priv->cached_max_ptime = basepayload->max_ptime;
|
||||
priv->cached_min_length = *min_payload_len;
|
||||
priv->cached_max_length = *max_payload_len;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* frame conversions functions */
|
||||
static GstClockTime
|
||||
gst_base_rtp_audio_payload_get_sample_duration (GstBaseRTPAudioPayload *
|
||||
gst_base_rtp_audio_payload_frame_bytes_to_time (GstBaseRTPAudioPayload *
|
||||
payload, guint64 bytes)
|
||||
{
|
||||
return gst_util_uint64_scale (bytes * 8, GST_SECOND,
|
||||
GST_BASE_RTP_PAYLOAD (payload)->clock_rate * payload->sample_size);
|
||||
return (bytes / payload->frame_size) * (payload->priv->frame_duration_ns);
|
||||
}
|
||||
|
||||
static guint32
|
||||
gst_base_rtp_audio_payload_get_sample_rtptime (GstBaseRTPAudioPayload *
|
||||
gst_base_rtp_audio_payload_frame_bytes_to_rtptime (GstBaseRTPAudioPayload *
|
||||
payload, guint64 bytes)
|
||||
{
|
||||
return (bytes * 8) / payload->sample_size;
|
||||
guint64 time;
|
||||
|
||||
time = (bytes / payload->frame_size) * (payload->priv->frame_duration_ns);
|
||||
|
||||
return gst_util_uint64_scale_int (time,
|
||||
GST_BASE_RTP_PAYLOAD (payload)->clock_rate, GST_SECOND);
|
||||
}
|
||||
|
||||
static guint64
|
||||
gst_base_rtp_audio_payload_frame_time_to_bytes (GstBaseRTPAudioPayload *
|
||||
payload, GstClockTime time)
|
||||
{
|
||||
return gst_util_uint64_scale (time, payload->frame_size,
|
||||
payload->priv->frame_duration_ns);
|
||||
}
|
||||
|
||||
/* sample conversion functions */
|
||||
static GstClockTime
|
||||
gst_base_rtp_audio_payload_sample_bytes_to_time (GstBaseRTPAudioPayload *
|
||||
payload, guint64 bytes)
|
||||
{
|
||||
guint64 rtptime;
|
||||
|
||||
/* avoid division when we can */
|
||||
if (G_LIKELY (payload->sample_size != 8))
|
||||
rtptime = gst_util_uint64_scale_int (bytes, 8, payload->sample_size);
|
||||
else
|
||||
rtptime = bytes;
|
||||
|
||||
return gst_util_uint64_scale_int (rtptime, GST_SECOND,
|
||||
GST_BASE_RTP_PAYLOAD (payload)->clock_rate);
|
||||
}
|
||||
|
||||
static guint32
|
||||
gst_base_rtp_audio_payload_sample_bytes_to_rtptime (GstBaseRTPAudioPayload *
|
||||
payload, guint64 bytes)
|
||||
{
|
||||
/* avoid division when we can */
|
||||
if (G_LIKELY (payload->sample_size != 8))
|
||||
return gst_util_uint64_scale_int (bytes, 8, payload->sample_size);
|
||||
else
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static guint64
|
||||
gst_base_rtp_audio_payload_sample_time_to_bytes (GstBaseRTPAudioPayload *
|
||||
payload, guint64 time)
|
||||
{
|
||||
guint64 samples;
|
||||
|
||||
samples = gst_util_uint64_scale_int (time,
|
||||
GST_BASE_RTP_PAYLOAD (payload)->clock_rate, GST_SECOND);
|
||||
|
||||
/* avoid multiplication when we can */
|
||||
if (G_LIKELY (payload->sample_size != 8))
|
||||
return gst_util_uint64_scale_int (samples, payload->sample_size, 8);
|
||||
else
|
||||
return samples;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -602,6 +634,7 @@ gst_base_rtp_audio_payload_handle_buffer (GstBaseRTPPayload *
|
|||
basepayload, GstBuffer * buffer)
|
||||
{
|
||||
GstBaseRTPAudioPayload *payload;
|
||||
GstBaseRTPAudioPayloadPrivate *priv;
|
||||
guint payload_len;
|
||||
GstFlowReturn ret;
|
||||
guint available;
|
||||
|
@ -614,19 +647,37 @@ gst_base_rtp_audio_payload_handle_buffer (GstBaseRTPPayload *
|
|||
ret = GST_FLOW_OK;
|
||||
|
||||
payload = GST_BASE_RTP_AUDIO_PAYLOAD_CAST (basepayload);
|
||||
|
||||
if (payload->priv->get_lengths == NULL || payload->priv->get_duration == NULL)
|
||||
goto config_error;
|
||||
priv = payload->priv;
|
||||
|
||||
discont = GST_BUFFER_IS_DISCONT (buffer);
|
||||
if (discont) {
|
||||
GstClockTime timestamp;
|
||||
|
||||
GST_DEBUG_OBJECT (payload, "Got DISCONT");
|
||||
/* flush everything out of the adapter, mark DISCONT */
|
||||
ret = gst_base_rtp_audio_payload_flush (payload, -1, -1);
|
||||
payload->priv->discont = TRUE;
|
||||
priv->discont = TRUE;
|
||||
|
||||
timestamp = GST_BUFFER_TIMESTAMP (buffer);
|
||||
|
||||
/* get the distance between the timestamp gap and produce the same gap in
|
||||
* the RTP timestamps */
|
||||
if (priv->last_timestamp != -1 && timestamp != -1) {
|
||||
/* we had a last timestamp, compare it to the new timestamp and update the
|
||||
* offset counter for RTP timestamps. The effect is that we will produce
|
||||
* output buffers containing the same RTP timestamp gap as the gap
|
||||
* between the GST timestamps. */
|
||||
if (timestamp > priv->last_timestamp) {
|
||||
/* we're only going to apply a positive gap, otherwise we let the marker
|
||||
* bit do its thing. simply convert to bytes and add the the current
|
||||
* offset */
|
||||
priv->offset +=
|
||||
priv->time_to_bytes (payload, timestamp - priv->last_timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!payload->priv->get_lengths (basepayload, &min_payload_len,
|
||||
if (!gst_base_rtp_audio_payload_get_lengths (basepayload, &min_payload_len,
|
||||
&max_payload_len, &align))
|
||||
goto config_error;
|
||||
|
||||
|
@ -638,7 +689,7 @@ gst_base_rtp_audio_payload_handle_buffer (GstBaseRTPPayload *
|
|||
|
||||
/* shortcut, we don't need to use the adapter when the packet can be pushed
|
||||
* through directly. */
|
||||
available = gst_adapter_available (payload->priv->adapter);
|
||||
available = gst_adapter_available (priv->adapter);
|
||||
|
||||
GST_DEBUG_OBJECT (payload, "got buffer size %u, available %u",
|
||||
size, available);
|
||||
|
@ -652,13 +703,14 @@ gst_base_rtp_audio_payload_handle_buffer (GstBaseRTPPayload *
|
|||
gst_buffer_unref (buffer);
|
||||
} else {
|
||||
/* push the buffer in the adapter */
|
||||
gst_adapter_push (payload->priv->adapter, buffer);
|
||||
gst_adapter_push (priv->adapter, buffer);
|
||||
available += size;
|
||||
|
||||
GST_DEBUG_OBJECT (payload, "available now %u", available);
|
||||
|
||||
/* as long as we have full frames */
|
||||
while (available >= min_payload_len) {
|
||||
/* get multiple of alignment */
|
||||
payload_len = ALIGN_DOWN (available, align);
|
||||
payload_len = MIN (max_payload_len, payload_len);
|
||||
|
||||
|
@ -691,6 +743,16 @@ gst_base_rtp_payload_audio_change_state (GstElement * element,
|
|||
|
||||
basertppayload = GST_BASE_RTP_AUDIO_PAYLOAD (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
basertppayload->priv->cached_mtu = -1;
|
||||
basertppayload->priv->last_rtptime = -1;
|
||||
basertppayload->priv->last_timestamp = -1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
switch (transition) {
|
||||
|
|
Loading…
Reference in a new issue