mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
rtpmp4gpay: implement perfect timestamps
Use bitreader for parsing the config string Reset state variables when going to READY Parse frame length and use it to keep track of the rtptimestamps
This commit is contained in:
parent
29b32853d5
commit
af70b300cc
2 changed files with 100 additions and 22 deletions
|
@ -23,6 +23,7 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include <gst/base/gstbitreader.h>
|
||||
#include <gst/rtp/gstrtpbuffer.h>
|
||||
|
||||
#include "gstrtpmp4gpay.h"
|
||||
|
@ -74,6 +75,9 @@ GST_STATIC_PAD_TEMPLATE ("src",
|
|||
|
||||
static void gst_rtp_mp4g_pay_finalize (GObject * object);
|
||||
|
||||
static GstStateChangeReturn gst_rtp_mp4g_pay_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
|
||||
static gboolean gst_rtp_mp4g_pay_setcaps (GstBaseRTPPayload * payload,
|
||||
GstCaps * caps);
|
||||
static GstFlowReturn gst_rtp_mp4g_pay_handle_buffer (GstBaseRTPPayload *
|
||||
|
@ -101,13 +105,17 @@ static void
|
|||
gst_rtp_mp4g_pay_class_init (GstRtpMP4GPayClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseRTPPayloadClass *gstbasertppayload_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
|
||||
|
||||
gobject_class->finalize = gst_rtp_mp4g_pay_finalize;
|
||||
|
||||
gstelement_class->change_state = gst_rtp_mp4g_pay_change_state;
|
||||
|
||||
gstbasertppayload_class->set_caps = gst_rtp_mp4g_pay_setcaps;
|
||||
gstbasertppayload_class->handle_buffer = gst_rtp_mp4g_pay_handle_buffer;
|
||||
|
||||
|
@ -119,20 +127,14 @@ static void
|
|||
gst_rtp_mp4g_pay_init (GstRtpMP4GPay * rtpmp4gpay, GstRtpMP4GPayClass * klass)
|
||||
{
|
||||
rtpmp4gpay->adapter = gst_adapter_new ();
|
||||
rtpmp4gpay->rate = 90000;
|
||||
rtpmp4gpay->profile = g_strdup ("1");
|
||||
rtpmp4gpay->mode = "";
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtp_mp4g_pay_finalize (GObject * object)
|
||||
gst_rtp_mp4g_pay_reset (GstRtpMP4GPay * rtpmp4gpay)
|
||||
{
|
||||
GstRtpMP4GPay *rtpmp4gpay;
|
||||
GST_DEBUG_OBJECT (rtpmp4gpay, "reset");
|
||||
|
||||
rtpmp4gpay = GST_RTP_MP4G_PAY (object);
|
||||
|
||||
g_object_unref (rtpmp4gpay->adapter);
|
||||
rtpmp4gpay->adapter = NULL;
|
||||
gst_adapter_clear (rtpmp4gpay->adapter);
|
||||
|
||||
g_free (rtpmp4gpay->params);
|
||||
rtpmp4gpay->params = NULL;
|
||||
|
@ -144,6 +146,25 @@ gst_rtp_mp4g_pay_finalize (GObject * object)
|
|||
g_free (rtpmp4gpay->profile);
|
||||
rtpmp4gpay->profile = NULL;
|
||||
|
||||
rtpmp4gpay->streamtype = NULL;
|
||||
rtpmp4gpay->mode = NULL;
|
||||
|
||||
rtpmp4gpay->frame_len = 0;
|
||||
rtpmp4gpay->offset = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtp_mp4g_pay_finalize (GObject * object)
|
||||
{
|
||||
GstRtpMP4GPay *rtpmp4gpay;
|
||||
|
||||
rtpmp4gpay = GST_RTP_MP4G_PAY (object);
|
||||
|
||||
gst_rtp_mp4g_pay_reset (rtpmp4gpay);
|
||||
|
||||
g_object_unref (rtpmp4gpay->adapter);
|
||||
rtpmp4gpay->adapter = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
@ -161,39 +182,66 @@ gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
|
|||
guint8 objectType;
|
||||
guint8 samplingIdx;
|
||||
guint8 channelCfg;
|
||||
GstBitReader br;
|
||||
|
||||
data = GST_BUFFER_DATA (buffer);
|
||||
size = GST_BUFFER_SIZE (buffer);
|
||||
|
||||
if (size < 2)
|
||||
goto too_short;
|
||||
gst_bit_reader_init (&br, data, size);
|
||||
|
||||
/* any object type is fine, we need to copy it to the profile-level-id field. */
|
||||
objectType = (data[0] & 0xf8) >> 3;
|
||||
if (!gst_bit_reader_get_bits_uint8 (&br, &objectType, 5))
|
||||
goto too_short;
|
||||
if (objectType == 0)
|
||||
goto invalid_object;
|
||||
|
||||
samplingIdx = ((data[0] & 0x07) << 1) | ((data[1] & 0x80) >> 7);
|
||||
if (!gst_bit_reader_get_bits_uint8 (&br, &samplingIdx, 4))
|
||||
goto too_short;
|
||||
/* only fixed values for now */
|
||||
if (samplingIdx > 12 && samplingIdx != 15)
|
||||
goto wrong_freq;
|
||||
|
||||
channelCfg = ((data[1] & 0x78) >> 3);
|
||||
if (!gst_bit_reader_get_bits_uint8 (&br, &channelCfg, 4))
|
||||
goto too_short;
|
||||
if (channelCfg > 7)
|
||||
goto wrong_channels;
|
||||
|
||||
/* rtp rate depends on sampling rate of the audio */
|
||||
if (samplingIdx == 15) {
|
||||
if (size < 5)
|
||||
goto too_short;
|
||||
guint32 rate;
|
||||
|
||||
/* index of 15 means we get the rate in the next 24 bits */
|
||||
rtpmp4gpay->rate = ((data[1] & 0x7f) << 17) |
|
||||
((data[2]) << 9) | ((data[3]) << 1) | ((data[4] & 0x80) >> 7);
|
||||
if (!gst_bit_reader_get_bits_uint32 (&br, &rate, 24))
|
||||
goto too_short;
|
||||
|
||||
rtpmp4gpay->rate = rate;
|
||||
} else {
|
||||
/* else use the rate from the table */
|
||||
rtpmp4gpay->rate = sampling_table[samplingIdx];
|
||||
}
|
||||
|
||||
rtpmp4gpay->frame_len = 1024;
|
||||
|
||||
switch (objectType) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
{
|
||||
guint8 frameLenFlag;
|
||||
|
||||
if (gst_bit_reader_get_bits_uint8 (&br, &frameLenFlag, 1))
|
||||
if (frameLenFlag)
|
||||
rtpmp4gpay->frame_len = 960;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* extra rtp params contain the number of channels */
|
||||
g_free (rtpmp4gpay->params);
|
||||
rtpmp4gpay->params = g_strdup_printf ("%d", channelCfg);
|
||||
|
@ -206,8 +254,9 @@ gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
|
|||
rtpmp4gpay->profile = g_strdup_printf ("%d", objectType);
|
||||
|
||||
GST_DEBUG_OBJECT (rtpmp4gpay,
|
||||
"objectType: %d, samplingIdx: %d (%d), channelCfg: %d", objectType,
|
||||
samplingIdx, rtpmp4gpay->rate, channelCfg);
|
||||
"objectType: %d, samplingIdx: %d (%d), channelCfg: %d, frame_len %d",
|
||||
objectType, samplingIdx, rtpmp4gpay->rate, channelCfg,
|
||||
rtpmp4gpay->frame_len);
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
@ -215,13 +264,13 @@ gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
|
|||
too_short:
|
||||
{
|
||||
GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
|
||||
(NULL), ("config string too short, expected 2 bytes, got %d", size));
|
||||
(NULL), ("config string too short"));
|
||||
return FALSE;
|
||||
}
|
||||
invalid_object:
|
||||
{
|
||||
GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
|
||||
(NULL), ("invalid object type 0"));
|
||||
(NULL), ("invalid object type"));
|
||||
return FALSE;
|
||||
}
|
||||
wrong_freq:
|
||||
|
@ -479,6 +528,11 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
|
|||
GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4gpay->first_timestamp;
|
||||
GST_BUFFER_DURATION (outbuf) = rtpmp4gpay->first_duration;
|
||||
|
||||
if (rtpmp4gpay->frame_len) {
|
||||
GST_BUFFER_OFFSET (outbuf) = rtpmp4gpay->offset;
|
||||
rtpmp4gpay->offset += rtpmp4gpay->frame_len;
|
||||
}
|
||||
|
||||
ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp4gpay), outbuf);
|
||||
|
||||
avail -= payload_len;
|
||||
|
@ -503,9 +557,31 @@ gst_rtp_mp4g_pay_handle_buffer (GstBaseRTPPayload * basepayload,
|
|||
|
||||
/* we always encode and flush a full AU */
|
||||
gst_adapter_push (rtpmp4gpay->adapter, buffer);
|
||||
|
||||
return gst_rtp_mp4g_pay_flush (rtpmp4gpay);
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_rtp_mp4g_pay_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstStateChangeReturn ret;
|
||||
GstRtpMP4GPay *rtpmp4gpay;
|
||||
|
||||
rtpmp4gpay = GST_RTP_MP4G_PAY (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
gst_rtp_mp4g_pay_reset (rtpmp4gpay);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_rtp_mp4g_pay_plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
|
|
|
@ -48,6 +48,7 @@ struct _GstRtpMP4GPay
|
|||
GstClockTime first_timestamp;
|
||||
GstClockTime first_duration;
|
||||
GstClockTime duration;
|
||||
guint64 offset;
|
||||
|
||||
gint rate;
|
||||
gchar *params;
|
||||
|
@ -55,6 +56,7 @@ struct _GstRtpMP4GPay
|
|||
const gchar *streamtype;
|
||||
const gchar *mode;
|
||||
GstBuffer *config;
|
||||
guint frame_len;
|
||||
};
|
||||
|
||||
struct _GstRtpMP4GPayClass
|
||||
|
|
Loading…
Reference in a new issue