2005-09-21 Wim Taymans <wim@fluendo.com>
+ * gst/rtp/gstrtpamrdec.c: (gst_rtpamrdec_sink_setcaps),
+ (gst_rtpamrdec_chain):
+ Handle multiple AMr packets per payload. Handle CRC and
+ parse ILL/ILP.
+
+ * gst/rtp/gstrtpamrenc.c: (gst_rtpamrenc_setcaps):
+ Make caps params strings for easy SDP mapping.
+
+ * gst/rtp/gstrtpdec.c: (gst_rtpdec_init), (gst_rtpdec_getcaps):
+ Handle capsnego better.
+
+ * gst/rtp/gstrtpmp4vdec.c: (gst_rtpmp4vdec_setcaps):
+ * gst/rtp/gstrtpmp4venc.c: (gst_rtpmp4venc_new_caps):
+ Generate and parse config string in the caps.
+
+2005-09-21 Wim Taymans <wim@fluendo.com>
+
* gst/rtp/README:
Update README
"clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", "
- "octet-align = (string) 1, "
- "crc = (string) 0, "
- "robust-sorting = (string) 0, " "interleaving = (string) 0"
+ "octet-align = (string) \"1\", "
+ "crc = (string) { \"0\", \"1\" }, "
+ "robust-sorting = (string) \"0\", " "interleaving = (string) \"0\""
/* following options are not needed for a decoder
*
"mode-set = (int) [ 0, 7 ], "
return FALSE;
if (rtpamrdec->octet_align != TRUE)
return FALSE;
- if (rtpamrdec->crc != FALSE)
- return FALSE;
if (rtpamrdec->robust_sorting != FALSE)
return FALSE;
if (rtpamrdec->interleaving != FALSE)
return TRUE;
}
+/* -1 is invalid */
+static gint frame_size[16] = {
+ 12, 13, 15, 17, 19, 20, 26, 31,
+ 5, -1, -1, -1, -1, -1, -1, 0
+};
+
static GstFlowReturn
gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
{
* no robust sorting, no interleaving data is to be parsed */
{
gint payload_len;
- guint8 *payload;
+ guint8 *payload, *p, *dp;
guint32 timestamp;
- guint8 CMR, F, FT, Q;
+ guint8 CMR;
+ gint i, num_packets, num_nonempty_packets;
+ gint amr_len;
+ gint ILL, ILP;
payload_len = gst_rtpbuffer_get_payload_len (buf);
payload = gst_rtpbuffer_get_payload (buf);
- /* parse header
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
- * | CMR |R|R|R|R|F| FT |Q|P|P|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
+ /* parse CMR. The CMR is used by the sender to request
+ * a new encoding mode.
+ *
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * | CMR |R|R|R|R|
+ * +-+-+-+-+-+-+-+-+
*/
CMR = (payload[0] & 0xf0) >> 4;
- F = (payload[1] & 0x80) >> 7;
- /* we only support 1 packet per RTP packet for now */
- if (F != 0)
- goto one_packet_only;
-
- FT = (payload[1] & 0x78) >> 3;
- Q = (payload[1] & 0x04) >> 2;
-
- /* skip packet */
- if (FT > 9 && FT < 15) {
- ret = GST_FLOW_OK;
- goto skip;
- }
- /* strip header now, leave FT in the data for the decoder */
+ /* strip CMR header now, pack FT and the data for the decoder */
payload_len -= 1;
payload += 1;
+ if (rtpamrdec->interleaving) {
+ ILL = (payload[0] & 0xf0) >> 4;
+ ILP = (payload[0] & 0x0f);
+
+ payload_len -= 1;
+ payload += 1;
+
+ if (ILP > ILL)
+ goto bad_packet;
+ }
+
+ /*
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+ * +-+-+-+-+-+-+-+-+..
+ * |F| FT |Q|P|P| more FT..
+ * +-+-+-+-+-+-+-+-+..
+ */
+ /* count number of packets by counting the FTs. Also
+ * count number of amr data bytes and number of non-empty
+ * packets (this is also the number of CRCs if present). */
+ amr_len = 0;
+ num_nonempty_packets = 0;
+ num_packets = 0;
+ for (i = 0; i < payload_len; i++) {
+ gint fr_size;
+ guint8 FT;
+
+ FT = (payload[i] & 0x78) >> 3;
+
+ fr_size = frame_size[FT];
+ if (fr_size == -1)
+ goto bad_packet;
+
+ if (fr_size > 0) {
+ amr_len += fr_size;
+ num_nonempty_packets++;
+ }
+ num_packets++;
+
+ if ((payload[i] & 0x80) == 0)
+ break;
+ }
+
+ /* this is impossible */
+ if (num_packets == payload_len)
+ goto bad_packet;
+
+ if (rtpamrdec->crc) {
+ /* data len + CRC len + header bytes should be smaller than payload_len */
+ if (num_packets + num_nonempty_packets + amr_len > payload_len)
+ goto bad_packet;
+ } else {
+ /* data len + header bytes should be smaller than payload_len */
+ if (num_packets + amr_len > payload_len)
+ goto bad_packet;
+ }
+
timestamp = gst_rtpbuffer_get_timestamp (buf);
outbuf = gst_buffer_new_and_alloc (payload_len);
-
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / rtpamrdec->rate;
- memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
+ /* point to destination */
+ p = GST_BUFFER_DATA (outbuf);
+ /* point to first data packet */
+ dp = payload + num_packets;
+ if (rtpamrdec->crc) {
+ /* skip CRC if present */
+ dp += num_nonempty_packets;
+ }
+
+ for (i = 0; i < num_packets; i++) {
+ gint fr_size;
+
+ fr_size = frame_size[(payload[i] & 0x78) >> 3];
+ if (fr_size > 0) {
+ /* copy FT */
+ *p++ = payload[i];
+ /* copy data packet, FIXME, calc CRC here. */
+ memcpy (p, dp, fr_size);
+ p += fr_size;
+ dp += fr_size;
+ }
+ }
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdec->srcpad));
GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
GST_BUFFER_SIZE (outbuf));
ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
- skip:
gst_buffer_unref (buf);
}
not_negotiated:
{
- GST_DEBUG ("not_negotiated");
+ GST_ELEMENT_ERROR (rtpamrdec, STREAM, NOT_IMPLEMENTED,
+ ("not negotiated"), (NULL));
gst_buffer_unref (buf);
return GST_FLOW_NOT_NEGOTIATED;
}
bad_packet:
{
- GST_DEBUG ("Packet did not validate");
- gst_buffer_unref (buf);
- return GST_FLOW_ERROR;
- }
-one_packet_only:
- {
- GST_DEBUG ("One packet per RTP packet only");
+ GST_ELEMENT_WARNING (rtpamrdec, STREAM, DECODE,
+ ("amr packet did not validate"), (NULL));
gst_buffer_unref (buf);
- return GST_FLOW_ERROR;
+ return GST_FLOW_OK;
}
}
"clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", "
- "octet-align = (string) 1, "
- "crc = (string) 0, "
- "robust-sorting = (string) 0, " "interleaving = (string) 0"
+ "octet-align = (string) \"1\", "
+ "crc = (string) { \"0\", \"1\" }, "
+ "robust-sorting = (string) \"0\", " "interleaving = (string) \"0\""
/* following options are not needed for a decoder
*
"mode-set = (int) [ 0, 7 ], "
return FALSE;
if (rtpamrdec->octet_align != TRUE)
return FALSE;
- if (rtpamrdec->crc != FALSE)
- return FALSE;
if (rtpamrdec->robust_sorting != FALSE)
return FALSE;
if (rtpamrdec->interleaving != FALSE)
return TRUE;
}
+/* -1 is invalid */
+static gint frame_size[16] = {
+ 12, 13, 15, 17, 19, 20, 26, 31,
+ 5, -1, -1, -1, -1, -1, -1, 0
+};
+
static GstFlowReturn
gst_rtpamrdec_chain (GstPad * pad, GstBuffer * buf)
{
* no robust sorting, no interleaving data is to be parsed */
{
gint payload_len;
- guint8 *payload;
+ guint8 *payload, *p, *dp;
guint32 timestamp;
- guint8 CMR, F, FT, Q;
+ guint8 CMR;
+ gint i, num_packets, num_nonempty_packets;
+ gint amr_len;
+ gint ILL, ILP;
payload_len = gst_rtpbuffer_get_payload_len (buf);
payload = gst_rtpbuffer_get_payload (buf);
- /* parse header
- * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
- * | CMR |R|R|R|R|F| FT |Q|P|P|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+..
+ /* parse CMR. The CMR is used by the sender to request
+ * a new encoding mode.
+ *
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * | CMR |R|R|R|R|
+ * +-+-+-+-+-+-+-+-+
*/
CMR = (payload[0] & 0xf0) >> 4;
- F = (payload[1] & 0x80) >> 7;
- /* we only support 1 packet per RTP packet for now */
- if (F != 0)
- goto one_packet_only;
-
- FT = (payload[1] & 0x78) >> 3;
- Q = (payload[1] & 0x04) >> 2;
-
- /* skip packet */
- if (FT > 9 && FT < 15) {
- ret = GST_FLOW_OK;
- goto skip;
- }
- /* strip header now, leave FT in the data for the decoder */
+ /* strip CMR header now, pack FT and the data for the decoder */
payload_len -= 1;
payload += 1;
+ if (rtpamrdec->interleaving) {
+ ILL = (payload[0] & 0xf0) >> 4;
+ ILP = (payload[0] & 0x0f);
+
+ payload_len -= 1;
+ payload += 1;
+
+ if (ILP > ILL)
+ goto bad_packet;
+ }
+
+ /*
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+ * +-+-+-+-+-+-+-+-+..
+ * |F| FT |Q|P|P| more FT..
+ * +-+-+-+-+-+-+-+-+..
+ */
+ /* count number of packets by counting the FTs. Also
+ * count number of amr data bytes and number of non-empty
+ * packets (this is also the number of CRCs if present). */
+ amr_len = 0;
+ num_nonempty_packets = 0;
+ num_packets = 0;
+ for (i = 0; i < payload_len; i++) {
+ gint fr_size;
+ guint8 FT;
+
+ FT = (payload[i] & 0x78) >> 3;
+
+ fr_size = frame_size[FT];
+ if (fr_size == -1)
+ goto bad_packet;
+
+ if (fr_size > 0) {
+ amr_len += fr_size;
+ num_nonempty_packets++;
+ }
+ num_packets++;
+
+ if ((payload[i] & 0x80) == 0)
+ break;
+ }
+
+ /* this is impossible */
+ if (num_packets == payload_len)
+ goto bad_packet;
+
+ if (rtpamrdec->crc) {
+ /* data len + CRC len + header bytes should be smaller than payload_len */
+ if (num_packets + num_nonempty_packets + amr_len > payload_len)
+ goto bad_packet;
+ } else {
+ /* data len + header bytes should be smaller than payload_len */
+ if (num_packets + amr_len > payload_len)
+ goto bad_packet;
+ }
+
timestamp = gst_rtpbuffer_get_timestamp (buf);
outbuf = gst_buffer_new_and_alloc (payload_len);
-
GST_BUFFER_TIMESTAMP (outbuf) = timestamp * GST_SECOND / rtpamrdec->rate;
- memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
+ /* point to destination */
+ p = GST_BUFFER_DATA (outbuf);
+ /* point to first data packet */
+ dp = payload + num_packets;
+ if (rtpamrdec->crc) {
+ /* skip CRC if present */
+ dp += num_nonempty_packets;
+ }
+
+ for (i = 0; i < num_packets; i++) {
+ gint fr_size;
+
+ fr_size = frame_size[(payload[i] & 0x78) >> 3];
+ if (fr_size > 0) {
+ /* copy FT */
+ *p++ = payload[i];
+ /* copy data packet, FIXME, calc CRC here. */
+ memcpy (p, dp, fr_size);
+ p += fr_size;
+ dp += fr_size;
+ }
+ }
gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrdec->srcpad));
GST_DEBUG ("gst_rtpamrdec_chain: pushing buffer of size %d",
GST_BUFFER_SIZE (outbuf));
ret = gst_pad_push (rtpamrdec->srcpad, outbuf);
- skip:
gst_buffer_unref (buf);
}
not_negotiated:
{
- GST_DEBUG ("not_negotiated");
+ GST_ELEMENT_ERROR (rtpamrdec, STREAM, NOT_IMPLEMENTED,
+ ("not negotiated"), (NULL));
gst_buffer_unref (buf);
return GST_FLOW_NOT_NEGOTIATED;
}
bad_packet:
{
- GST_DEBUG ("Packet did not validate");
- gst_buffer_unref (buf);
- return GST_FLOW_ERROR;
- }
-one_packet_only:
- {
- GST_DEBUG ("One packet per RTP packet only");
+ GST_ELEMENT_WARNING (rtpamrdec, STREAM, DECODE,
+ ("amr packet did not validate"), (NULL));
gst_buffer_unref (buf);
- return GST_FLOW_ERROR;
+ return GST_FLOW_OK;
}
}
"clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", "
- "octet-align = (boolean) TRUE, "
- "crc = (boolean) FALSE, "
- "robust-sorting = (boolean) FALSE, "
- "interleaving = (boolean) FALSE, "
+ "octet-align = (string) \"1\", "
+ "crc = (string) \"0\", "
+ "robust-sorting = (string) \"0\", "
+ "interleaving = (string) \"0\", "
"mode-set = (int) [ 0, 7 ], "
"mode-change-period = (int) [ 1, MAX ], "
- "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
+ "mode-change-neighbor = (string) { \"0\", \"1\" }, "
"maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
);
gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
gst_basertppayload_set_outcaps (basepayload,
- "encoding-params", G_TYPE_STRING, "1",
- "octet-align", G_TYPE_BOOLEAN, TRUE,
- "crc", G_TYPE_BOOLEAN, FALSE,
- "robust-sorting", G_TYPE_BOOLEAN, FALSE,
- "interleaving", G_TYPE_BOOLEAN, FALSE, NULL);
+ "encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
+ /* don't set the defaults
+ *
+ * "crc", G_TYPE_STRING, "0",
+ * "robust-sorting", G_TYPE_STRING, "0",
+ * "interleaving", G_TYPE_STRING, "0",
+ */
+ NULL);
return TRUE;
}
"clock-rate = (int) 8000, "
"encoding-name = (string) \"AMR\", "
"encoding-params = (string) \"1\", "
- "octet-align = (boolean) TRUE, "
- "crc = (boolean) FALSE, "
- "robust-sorting = (boolean) FALSE, "
- "interleaving = (boolean) FALSE, "
+ "octet-align = (string) \"1\", "
+ "crc = (string) \"0\", "
+ "robust-sorting = (string) \"0\", "
+ "interleaving = (string) \"0\", "
"mode-set = (int) [ 0, 7 ], "
"mode-change-period = (int) [ 1, MAX ], "
- "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
+ "mode-change-neighbor = (string) { \"0\", \"1\" }, "
"maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
);
gst_basertppayload_set_options (basepayload, "audio", TRUE, "AMR", 8000);
gst_basertppayload_set_outcaps (basepayload,
- "encoding-params", G_TYPE_STRING, "1",
- "octet-align", G_TYPE_BOOLEAN, TRUE,
- "crc", G_TYPE_BOOLEAN, FALSE,
- "robust-sorting", G_TYPE_BOOLEAN, FALSE,
- "interleaving", G_TYPE_BOOLEAN, FALSE, NULL);
+ "encoding-params", G_TYPE_STRING, "1", "octet-align", G_TYPE_STRING, "1",
+ /* don't set the defaults
+ *
+ * "crc", G_TYPE_STRING, "0",
+ * "robust-sorting", G_TYPE_STRING, "0",
+ * "interleaving", G_TYPE_STRING, "0",
+ */
+ NULL);
return TRUE;
}
static void gst_rtpdec_class_init (gpointer g_class);
static void gst_rtpdec_init (GstRTPDec * rtpdec);
+static GstCaps *gst_rtpdec_getcaps (GstPad * pad);
static GstFlowReturn gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer);
static GstFlowReturn gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_rtpdec_sink_rtp_template), "sinkrtp");
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtp);
+ gst_pad_set_getcaps_function (rtpdec->sink_rtp, gst_rtpdec_getcaps);
gst_pad_set_chain_function (rtpdec->sink_rtp, gst_rtpdec_chain_rtp);
/* the input rtcp pad */
rtpdec->src_rtp =
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_rtpdec_src_rtp_template), "srcrtp");
+ gst_pad_set_getcaps_function (rtpdec->src_rtp, gst_rtpdec_getcaps);
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtp);
/* the output rtcp pad */
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtcp);
}
+static GstCaps *
+gst_rtpdec_getcaps (GstPad * pad)
+{
+ GstRTPDec *src;
+ GstPad *other;
+
+ src = GST_RTPDEC (GST_PAD_PARENT (pad));
+
+ other = pad == src->src_rtp ? src->sink_rtp : src->src_rtp;
+
+ return gst_pad_peer_get_caps (other);
+}
+
static GstFlowReturn
gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer)
{
static void gst_rtpdec_class_init (gpointer g_class);
static void gst_rtpdec_init (GstRTPDec * rtpdec);
+static GstCaps *gst_rtpdec_getcaps (GstPad * pad);
static GstFlowReturn gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer);
static GstFlowReturn gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_rtpdec_sink_rtp_template), "sinkrtp");
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtp);
+ gst_pad_set_getcaps_function (rtpdec->sink_rtp, gst_rtpdec_getcaps);
gst_pad_set_chain_function (rtpdec->sink_rtp, gst_rtpdec_chain_rtp);
/* the input rtcp pad */
rtpdec->src_rtp =
gst_pad_new_from_template (gst_static_pad_template_get
(&gst_rtpdec_src_rtp_template), "srcrtp");
+ gst_pad_set_getcaps_function (rtpdec->src_rtp, gst_rtpdec_getcaps);
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtp);
/* the output rtcp pad */
gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtcp);
}
+static GstCaps *
+gst_rtpdec_getcaps (GstPad * pad)
+{
+ GstRTPDec *src;
+ GstPad *other;
+
+ src = GST_RTPDEC (GST_PAD_PARENT (pad));
+
+ other = pad == src->src_rtp ? src->sink_rtp : src->src_rtp;
+
+ return gst_pad_peer_get_caps (other);
+}
+
static GstFlowReturn
gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer)
{
GstStructure *structure;
GstRtpMP4VDec *rtpmp4vdec;
GstCaps *srccaps;
+ const gchar *str;
rtpmp4vdec = GST_RTP_MP4V_DEC (GST_OBJECT_PARENT (pad));
gst_pad_set_caps (rtpmp4vdec->srcpad, srccaps);
gst_caps_unref (srccaps);
+ if ((str = gst_structure_get_string (structure, "config"))) {
+ GValue v = { 0 };
+
+ g_print ("config=%s\n", str);
+
+ g_value_init (&v, GST_TYPE_BUFFER);
+ if (gst_value_deserialize (&v, str)) {
+ GstBuffer *buffer;
+
+ buffer = gst_value_get_buffer (&v);
+ gst_buffer_ref (buffer);
+ g_value_unset (&v);
+
+ g_print ("buf=%p\n", buffer);
+
+ gst_buffer_set_caps (buffer, GST_PAD_CAPS (rtpmp4vdec->srcpad));
+
+ gst_pad_push (rtpmp4vdec->srcpad, buffer);
+ } else {
+ g_warning ("cannot convert config to buffer");
+ }
+ }
+
return TRUE;
}
GstStructure *structure;
GstRtpMP4VDec *rtpmp4vdec;
GstCaps *srccaps;
+ const gchar *str;
rtpmp4vdec = GST_RTP_MP4V_DEC (GST_OBJECT_PARENT (pad));
gst_pad_set_caps (rtpmp4vdec->srcpad, srccaps);
gst_caps_unref (srccaps);
+ if ((str = gst_structure_get_string (structure, "config"))) {
+ GValue v = { 0 };
+
+ g_print ("config=%s\n", str);
+
+ g_value_init (&v, GST_TYPE_BUFFER);
+ if (gst_value_deserialize (&v, str)) {
+ GstBuffer *buffer;
+
+ buffer = gst_value_get_buffer (&v);
+ gst_buffer_ref (buffer);
+ g_value_unset (&v);
+
+ g_print ("buf=%p\n", buffer);
+
+ gst_buffer_set_caps (buffer, GST_PAD_CAPS (rtpmp4vdec->srcpad));
+
+ gst_pad_push (rtpmp4vdec->srcpad, buffer);
+ } else {
+ g_warning ("cannot convert config to buffer");
+ }
+ }
+
return TRUE;
}
GST_STATIC_CAPS ("application/x-rtp, "
"media = (string) \"video\", "
"payload = (int) [ 96, 255 ], "
- "clock-rate = (int) [1, MAX ], "
- "encoding-name = (string) \"MP4V-ES\", " "profile-level-id=[1,MAX]"
- /* All optional parameters
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
+ /* two string params
*
- * "config="
+ "profile-level-id = (string) [1,MAX]"
+ "config = (string) [1,MAX]"
*/
)
);
static void
gst_rtpmp4venc_new_caps (GstRtpMP4VEnc * rtpmp4venc)
{
+ gchar *profile, *config;
+ GValue v = { 0 };
+
+ profile = g_strdup_printf ("%d", rtpmp4venc->profile);
+ g_value_init (&v, GST_TYPE_BUFFER);
+ gst_value_set_buffer (&v, rtpmp4venc->config);
+ config = gst_value_serialize (&v);
+
gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4venc),
- "profile-level-id", G_TYPE_INT, rtpmp4venc->profile,
- "config", GST_TYPE_BUFFER, rtpmp4venc->config, NULL);
+ "profile-level-id", G_TYPE_STRING, profile,
+ "config", G_TYPE_STRING, config, NULL);
+
+ g_value_unset (&v);
+
+ g_free (profile);
+ g_free (config);
}
static gboolean
GST_STATIC_CAPS ("application/x-rtp, "
"media = (string) \"video\", "
"payload = (int) [ 96, 255 ], "
- "clock-rate = (int) [1, MAX ], "
- "encoding-name = (string) \"MP4V-ES\", " "profile-level-id=[1,MAX]"
- /* All optional parameters
+ "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
+ /* two string params
*
- * "config="
+ "profile-level-id = (string) [1,MAX]"
+ "config = (string) [1,MAX]"
*/
)
);
static void
gst_rtpmp4venc_new_caps (GstRtpMP4VEnc * rtpmp4venc)
{
+ gchar *profile, *config;
+ GValue v = { 0 };
+
+ profile = g_strdup_printf ("%d", rtpmp4venc->profile);
+ g_value_init (&v, GST_TYPE_BUFFER);
+ gst_value_set_buffer (&v, rtpmp4venc->config);
+ config = gst_value_serialize (&v);
+
gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4venc),
- "profile-level-id", G_TYPE_INT, rtpmp4venc->profile,
- "config", GST_TYPE_BUFFER, rtpmp4venc->config, NULL);
+ "profile-level-id", G_TYPE_STRING, profile,
+ "config", G_TYPE_STRING, config, NULL);
+
+ g_value_unset (&v);
+
+ g_free (profile);
+ g_free (config);
}
static gboolean