*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <gst/tag/tag.h>
#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/audio/audio.h>
#include <string.h>
#include "gstrtpvorbisdepay.h"
+#include "gstrtputils.h"
GST_DEBUG_CATEGORY_STATIC (rtpvorbisdepay_debug);
#define GST_CAT_DEFAULT (rtpvorbisdepay_debug)
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("application/x-rtp, "
"media = (string) \"audio\", "
- "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
"clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"VORBIS\""
/* All required parameters
*
static gboolean gst_rtp_vorbis_depay_setcaps (GstRTPBaseDepayload * depayload,
GstCaps * caps);
static GstBuffer *gst_rtp_vorbis_depay_process (GstRTPBaseDepayload * depayload,
- GstBuffer * buf);
+ GstRTPBuffer * rtp);
static void gst_rtp_vorbis_depay_finalize (GObject * object);
gstelement_class->change_state = gst_rtp_vorbis_depay_change_state;
- gstrtpbasedepayload_class->process = gst_rtp_vorbis_depay_process;
+ gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_vorbis_depay_process;
gstrtpbasedepayload_class->set_caps = gst_rtp_vorbis_depay_setcaps;
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtp_vorbis_depay_sink_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtp_vorbis_depay_src_template));
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &gst_rtp_vorbis_depay_sink_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &gst_rtp_vorbis_depay_src_template);
- gst_element_class_set_details_simple (gstelement_class,
+ gst_element_class_set_static_metadata (gstelement_class,
"RTP Vorbis depayloader", "Codec/Depayloader/Network/RTP",
"Extracts Vorbis Audio from RTP packets (RFC 5215)",
"Wim Taymans <wim.taymans@gmail.com>");
static void
free_config (GstRtpVorbisConfig * conf)
{
- GList *headers;
-
- for (headers = conf->headers; headers; headers = g_list_next (headers)) {
- GstBuffer *header = GST_BUFFER_CAST (headers->data);
-
- gst_buffer_unref (header);
- }
- g_list_free (conf->headers);
+ g_list_free_full (conf->headers, (GDestroyNotify) gst_buffer_unref);
g_free (conf);
}
static void
free_indents (GstRtpVorbisDepay * rtpvorbisdepay)
{
- GList *walk;
-
- for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
- free_config ((GstRtpVorbisConfig *) walk->data);
- }
- g_list_free (rtpvorbisdepay->configs);
+ g_list_free_full (rtpvorbisdepay->configs, (GDestroyNotify) free_config);
rtpvorbisdepay->configs = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
+static gboolean
+gst_rtp_vorbis_depay_has_ident (GstRtpVorbisDepay * rtpvorbisdepay,
+ guint32 ident)
+{
+ GList *walk;
+
+ for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
+ GstRtpVorbisConfig *conf = (GstRtpVorbisConfig *) walk->data;
+
+ if (conf->ident == ident)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/* takes ownership of confbuf */
static gboolean
gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
{
GstBuffer *buf;
guint32 num_headers;
- guint8 *data, *bdata;
+ GstMapInfo map;
+ guint8 *data;
gsize size;
guint offset;
gint i, j;
- bdata = data = gst_buffer_map (confbuf, &size, NULL, GST_MAP_READ);
+ gst_buffer_map (confbuf, &map, GST_MAP_READ);
+ data = map.data;
+ size = map.size;
GST_DEBUG_OBJECT (rtpvorbisdepay, "config size %" G_GSIZE_FORMAT, size);
offset += 6;
GST_DEBUG_OBJECT (rtpvorbisdepay,
- "header %d, ident 0x%08x, length %u, left %u", i, ident, length, size);
+ "header %d, ident 0x%08x, length %u, left %" G_GSIZE_FORMAT, i, ident,
+ length, size);
/* FIXME check if we already got this ident */
if (size < length && size + 1 != length)
goto too_small;
+ if (gst_rtp_vorbis_depay_has_ident (rtpvorbisdepay, ident)) {
+ size -= length;
+ data += length;
+ offset += length;
+ continue;
+ }
+
/* read header sizes we read 2 sizes, the third size (for which we allocate
* space) must be derived from the total packed header length. */
h_sizes = g_newa (guint, n_headers + 1);
GST_DEBUG_OBJECT (rtpvorbisdepay, "reading header %d, size %u", j,
h_size);
- buf = gst_buffer_copy_region (confbuf, GST_BUFFER_COPY_MEMORY, offset,
+ buf = gst_buffer_copy_region (confbuf, GST_BUFFER_COPY_ALL, offset,
h_size);
conf->headers = g_list_append (conf->headers, buf);
offset += h_size;
rtpvorbisdepay->configs = g_list_append (rtpvorbisdepay->configs, conf);
}
- gst_buffer_unmap (confbuf, bdata, -1);
+ gst_buffer_unmap (confbuf, &map);
gst_buffer_unref (confbuf);
return TRUE;
too_small:
{
GST_DEBUG_OBJECT (rtpvorbisdepay, "configuration too small");
- gst_buffer_unmap (confbuf, bdata, -1);
+ gst_buffer_unmap (confbuf, &map);
gst_buffer_unref (confbuf);
return FALSE;
}
guint length)
{
GstBuffer *confbuf;
- guint8 *conf;
+ GstMapInfo map;
if (G_UNLIKELY (size < 4))
return FALSE;
/* transform inline to out-of-band and parse that one */
confbuf = gst_buffer_new_and_alloc (size + 9);
- conf = gst_buffer_map (confbuf, NULL, NULL, -1);
+ gst_buffer_map (confbuf, &map, GST_MAP_WRITE);
/* 1 header */
- GST_WRITE_UINT32_BE (conf, 1);
+ GST_WRITE_UINT32_BE (map.data, 1);
/* write Ident */
- GST_WRITE_UINT24_BE (conf + 4, ident);
+ GST_WRITE_UINT24_BE (map.data + 4, ident);
/* write sort-of-length */
- GST_WRITE_UINT16_BE (conf + 7, length);
+ GST_WRITE_UINT16_BE (map.data + 7, length);
/* copy remainder */
- memcpy (conf + 9, configuration, size);
- gst_buffer_unmap (confbuf, conf, -1);
+ memcpy (map.data + 9, configuration, size);
+ gst_buffer_unmap (confbuf, &map);
return gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, confbuf);
}
data = g_base64_decode (configuration, &size);
confbuf = gst_buffer_new ();
- gst_buffer_take_memory (confbuf, -1,
- gst_memory_new_wrapped (0, data, g_free, size, 0, size));
+ gst_buffer_append_memory (confbuf,
+ gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
if (!gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, confbuf))
goto invalid_configuration;
} else {
}
static GstBuffer *
-gst_rtp_vorbis_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
+gst_rtp_vorbis_depay_process (GstRTPBaseDepayload * depayload,
+ GstRTPBuffer * rtp)
{
GstRtpVorbisDepay *rtpvorbisdepay;
GstBuffer *outbuf;
GstFlowReturn ret;
gint payload_len;
- guint8 *payload, *to_free = NULL;
+ GstBuffer *payload_buffer = NULL;
+ guint8 *payload;
+ GstMapInfo map;
guint32 header, ident;
guint8 F, VDT, packets;
- GstRTPBuffer rtp;
+ guint length;
rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
- gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
-
- payload_len = gst_rtp_buffer_get_payload_len (&rtp);
+ payload_len = gst_rtp_buffer_get_payload_len (rtp);
GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
if (G_UNLIKELY (payload_len < 4))
goto packet_short;
- payload = gst_rtp_buffer_get_payload (&rtp);
-
+ payload = gst_rtp_buffer_get_payload (rtp);
header = GST_READ_UINT32_BE (payload);
/*
* 0 1 2 3
}
}
- /* skip header */
- payload += 4;
- payload_len -= 4;
-
GST_DEBUG_OBJECT (depayload, "ident: %u, F: %d, VDT: %d, packets: %d", ident,
F, VDT, packets);
/* fragmented packets, assemble */
if (F != 0) {
GstBuffer *vdata;
- guint headerskip;
if (F == 1) {
/* if we start a packet, clear adapter and start assembling. */
if (!rtpvorbisdepay->assembling)
goto no_output;
- /* first assembled packet, reuse 2 bytes to store the length */
- headerskip = (F == 1 ? 4 : 6);
/* skip header and length. */
- vdata = gst_rtp_buffer_get_payload_subbuffer (&rtp, headerskip, -1);
+ vdata = gst_rtp_buffer_get_payload_subbuffer (rtp, 6, -1);
GST_DEBUG_OBJECT (depayload, "assemble vorbis packet");
gst_adapter_push (rtpvorbisdepay->adapter, vdata);
goto no_output;
/* construct assembled buffer */
- payload_len = gst_adapter_available (rtpvorbisdepay->adapter);
- payload = gst_adapter_take (rtpvorbisdepay->adapter, payload_len);
- /* fix the length */
- payload[0] = ((payload_len - 2) >> 8) & 0xff;
- payload[1] = (payload_len - 2) & 0xff;
- to_free = payload;
+ length = gst_adapter_available (rtpvorbisdepay->adapter);
+ payload_buffer = gst_adapter_take_buffer (rtpvorbisdepay->adapter, length);
+ } else {
+ payload_buffer = gst_rtp_buffer_get_payload_subbuffer (rtp, 4, -1);
+ length = 0;
}
GST_DEBUG_OBJECT (depayload, "assemble done");
+ gst_buffer_map (payload_buffer, &map, GST_MAP_READ);
+ payload = map.data;
+ payload_len = map.size;
+
/* we not assembling anymore now */
rtpvorbisdepay->assembling = FALSE;
gst_adapter_clear (rtpvorbisdepay->adapter);
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
*/
while (payload_len > 2) {
- guint16 length;
-
- length = GST_READ_UINT16_BE (payload);
- payload += 2;
- payload_len -= 2;
+ /* If length is not 0, we have a reassembled packet for which we
+ * calculated the length already and don't have to skip over the
+ * length field anymore
+ */
+ if (length == 0) {
+ length = GST_READ_UINT16_BE (payload);
+ payload += 2;
+ payload_len -= 2;
+ }
GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
payload_len);
}
/* create buffer for packet */
- if (G_UNLIKELY (to_free)) {
- outbuf = gst_buffer_new ();
- gst_buffer_take_memory (outbuf, -1,
- gst_memory_new_wrapped (0, to_free, g_free,
- (payload - to_free) + length, payload - to_free, length));
- to_free = NULL;
- } else {
- guint8 *data;
-
- outbuf = gst_buffer_new_and_alloc (length);
- data = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
- memcpy (data, payload, length);
- gst_buffer_unmap (outbuf, data, -1);
- }
+ outbuf =
+ gst_buffer_copy_region (payload_buffer, GST_BUFFER_COPY_ALL,
+ payload - map.data, length);
payload += length;
payload_len -= length;
+ /* make sure to read next length */
+ length = 0;
ret = gst_rtp_base_depayload_push (depayload, outbuf);
if (ret != GST_FLOW_OK)
break;
}
- g_free (to_free);
-
- gst_rtp_buffer_unmap (&rtp);
+ gst_buffer_unmap (payload_buffer, &map);
+ gst_buffer_unref (payload_buffer);
return NULL;
no_output:
{
- gst_rtp_buffer_unmap (&rtp);
+ if (payload_buffer) {
+ gst_buffer_unmap (payload_buffer, &map);
+ gst_buffer_unref (payload_buffer);
+ }
return NULL;
}
- /* ERORRS */
+ /* ERRORS */
switch_failed:
{
GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
(NULL), ("Could not switch codebooks"));
- gst_rtp_buffer_unmap (&rtp);
return NULL;
}
packet_short:
{
GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
(NULL), ("Packet was too short (%d < 4)", payload_len));
- gst_rtp_buffer_unmap (&rtp);
return NULL;
}
ignore_reserved:
{
GST_WARNING_OBJECT (rtpvorbisdepay, "reserved VDT ignored");
- gst_rtp_buffer_unmap (&rtp);
return NULL;
}
length_short:
{
GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
(NULL), ("Packet contains invalid data"));
- gst_rtp_buffer_unmap (&rtp);
+ if (payload_buffer) {
+ gst_buffer_unmap (payload_buffer, &map);
+ gst_buffer_unref (payload_buffer);
+ }
return NULL;
}
invalid_configuration:
/* fatal, as we otherwise risk carrying on without output */
GST_ELEMENT_ERROR (rtpvorbisdepay, STREAM, DECODE,
(NULL), ("Packet contains invalid configuration"));
- gst_rtp_buffer_unmap (&rtp);
+ if (payload_buffer) {
+ gst_buffer_unmap (payload_buffer, &map);
+ gst_buffer_unref (payload_buffer);
+ }
return NULL;
}
}