Blame gst-libs/gst/rtp/gstrtpbuffer.c

Packit 971217
/* GStreamer
Packit 971217
 * Copyright (C) <2005> Philippe Khalaf <burger@speedy.org>
Packit 971217
 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
/**
Packit 971217
 * SECTION:gstrtpbuffer
Packit 971217
 * @title: GstRTPBuffer
Packit 971217
 * @short_description: Helper methods for dealing with RTP buffers
Packit 971217
 * @see_also: #GstRTPBasePayload, #GstRTPBaseDepayload, gstrtcpbuffer
Packit 971217
 *
Packit 971217
 * The GstRTPBuffer helper functions makes it easy to parse and create regular
Packit 971217
 * #GstBuffer objects that contain RTP payloads. These buffers are typically of
Packit 971217
 * 'application/x-rtp' #GstCaps.
Packit 971217
 *
Packit 971217
 */
Packit 971217
Packit 971217
#include "gstrtpbuffer.h"
Packit 971217
Packit 971217
#include <stdlib.h>
Packit 971217
#include <string.h>
Packit 971217
Packit 971217
#define GST_RTP_HEADER_LEN 12
Packit 971217
Packit 971217
/* Note: we use bitfields here to make sure the compiler doesn't add padding
Packit 971217
 * between fields on certain architectures; can't assume aligned access either
Packit 971217
 */
Packit 971217
typedef struct _GstRTPHeader
Packit 971217
{
Packit 971217
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
Packit 971217
  unsigned int csrc_count:4;    /* CSRC count */
Packit 971217
  unsigned int extension:1;     /* header extension flag */
Packit 971217
  unsigned int padding:1;       /* padding flag */
Packit 971217
  unsigned int version:2;       /* protocol version */
Packit 971217
  unsigned int payload_type:7;  /* payload type */
Packit 971217
  unsigned int marker:1;        /* marker bit */
Packit 971217
#elif G_BYTE_ORDER == G_BIG_ENDIAN
Packit 971217
  unsigned int version:2;       /* protocol version */
Packit 971217
  unsigned int padding:1;       /* padding flag */
Packit 971217
  unsigned int extension:1;     /* header extension flag */
Packit 971217
  unsigned int csrc_count:4;    /* CSRC count */
Packit 971217
  unsigned int marker:1;        /* marker bit */
Packit 971217
  unsigned int payload_type:7;  /* payload type */
Packit 971217
#else
Packit 971217
#error "G_BYTE_ORDER should be big or little endian."
Packit 971217
#endif
Packit 971217
  unsigned int seq:16;          /* sequence number */
Packit 971217
  unsigned int timestamp:32;    /* timestamp */
Packit 971217
  unsigned int ssrc:32;         /* synchronization source */
Packit 971217
  guint8 csrclist[4];           /* optional CSRC list, 32 bits each */
Packit 971217
} GstRTPHeader;
Packit 971217
Packit 971217
#define GST_RTP_HEADER_VERSION(data)      (((GstRTPHeader *)(data))->version)
Packit 971217
#define GST_RTP_HEADER_PADDING(data)      (((GstRTPHeader *)(data))->padding)
Packit 971217
#define GST_RTP_HEADER_EXTENSION(data)    (((GstRTPHeader *)(data))->extension)
Packit 971217
#define GST_RTP_HEADER_CSRC_COUNT(data)   (((GstRTPHeader *)(data))->csrc_count)
Packit 971217
#define GST_RTP_HEADER_MARKER(data)       (((GstRTPHeader *)(data))->marker)
Packit 971217
#define GST_RTP_HEADER_PAYLOAD_TYPE(data) (((GstRTPHeader *)(data))->payload_type)
Packit 971217
#define GST_RTP_HEADER_SEQ(data)          (((GstRTPHeader *)(data))->seq)
Packit 971217
#define GST_RTP_HEADER_TIMESTAMP(data)    (((GstRTPHeader *)(data))->timestamp)
Packit 971217
#define GST_RTP_HEADER_SSRC(data)         (((GstRTPHeader *)(data))->ssrc)
Packit 971217
#define GST_RTP_HEADER_CSRC_LIST_OFFSET(data,i)        \
Packit 971217
    data + G_STRUCT_OFFSET(GstRTPHeader, csrclist) +   \
Packit 971217
    ((i) * sizeof(guint32))
Packit 971217
#define GST_RTP_HEADER_CSRC_SIZE(data)   (GST_RTP_HEADER_CSRC_COUNT(data) * sizeof (guint32))
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_allocate_data:
Packit 971217
 * @buffer: a #GstBuffer
Packit 971217
 * @payload_len: the length of the payload
Packit 971217
 * @pad_len: the amount of padding
Packit 971217
 * @csrc_count: the number of CSRC entries
Packit 971217
 *
Packit 971217
 * Allocate enough data in @buffer to hold an RTP packet with @csrc_count CSRCs,
Packit 971217
 * a payload length of @payload_len and padding of @pad_len.
Packit 971217
 * @buffer must be writable and all previous memory in @buffer will be freed.
Packit 971217
 * If @pad_len is >0, the padding bit will be set. All other RTP header fields
Packit 971217
 * will be set to 0/FALSE.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_allocate_data (GstBuffer * buffer, guint payload_len,
Packit 971217
    guint8 pad_len, guint8 csrc_count)
Packit 971217
{
Packit 971217
  GstMapInfo map;
Packit 971217
  GstMemory *mem;
Packit 971217
  gsize hlen;
Packit 971217
Packit 971217
  g_return_if_fail (csrc_count <= 15);
Packit 971217
  g_return_if_fail (GST_IS_BUFFER (buffer));
Packit 971217
  g_return_if_fail (gst_buffer_is_writable (buffer));
Packit 971217
Packit 971217
  gst_buffer_remove_all_memory (buffer);
Packit 971217
Packit 971217
  hlen = GST_RTP_HEADER_LEN + csrc_count * sizeof (guint32);
Packit 971217
Packit 971217
  mem = gst_allocator_alloc (NULL, hlen, NULL);
Packit 971217
Packit 971217
  gst_memory_map (mem, &map, GST_MAP_WRITE);
Packit 971217
  /* fill in defaults */
Packit 971217
  GST_RTP_HEADER_VERSION (map.data) = GST_RTP_VERSION;
Packit 971217
  if (pad_len)
Packit 971217
    GST_RTP_HEADER_PADDING (map.data) = TRUE;
Packit 971217
  else
Packit 971217
    GST_RTP_HEADER_PADDING (map.data) = FALSE;
Packit 971217
  GST_RTP_HEADER_EXTENSION (map.data) = FALSE;
Packit 971217
  GST_RTP_HEADER_CSRC_COUNT (map.data) = csrc_count;
Packit 971217
  memset (GST_RTP_HEADER_CSRC_LIST_OFFSET (map.data, 0), 0,
Packit 971217
      csrc_count * sizeof (guint32));
Packit 971217
  GST_RTP_HEADER_MARKER (map.data) = FALSE;
Packit 971217
  GST_RTP_HEADER_PAYLOAD_TYPE (map.data) = 0;
Packit 971217
  GST_RTP_HEADER_SEQ (map.data) = 0;
Packit 971217
  GST_RTP_HEADER_TIMESTAMP (map.data) = 0;
Packit 971217
  GST_RTP_HEADER_SSRC (map.data) = 0;
Packit 971217
  gst_memory_unmap (mem, &map);
Packit 971217
Packit 971217
  gst_buffer_append_memory (buffer, mem);
Packit 971217
Packit 971217
  if (payload_len) {
Packit 971217
    mem = gst_allocator_alloc (NULL, payload_len, NULL);
Packit 971217
    gst_buffer_append_memory (buffer, mem);
Packit 971217
  }
Packit 971217
  if (pad_len) {
Packit 971217
    mem = gst_allocator_alloc (NULL, pad_len, NULL);
Packit 971217
Packit 971217
    gst_memory_map (mem, &map, GST_MAP_WRITE);
Packit 971217
    map.data[pad_len - 1] = pad_len;
Packit 971217
    gst_memory_unmap (mem, &map);
Packit 971217
Packit 971217
    gst_buffer_append_memory (buffer, mem);
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_new_take_data:
Packit 971217
 * @data: (array length=len) (transfer full) (element-type guint8):
Packit 971217
 *   data for the new buffer
Packit 971217
 * @len: the length of data
Packit 971217
 *
Packit 971217
 * Create a new buffer and set the data and size of the buffer to @data and @len
Packit 971217
 * respectively. @data will be freed when the buffer is unreffed, so this
Packit 971217
 * function transfers ownership of @data to the new buffer.
Packit 971217
 *
Packit 971217
 * Returns: A newly allocated buffer with @data and of size @len.
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_rtp_buffer_new_take_data (gpointer data, gsize len)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (data != NULL, NULL);
Packit 971217
  g_return_val_if_fail (len > 0, NULL);
Packit 971217
Packit 971217
  return gst_buffer_new_wrapped (data, len);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_new_copy_data:
Packit 971217
 * @data: (array length=len) (element-type guint8): data for the new
Packit 971217
 *   buffer
Packit 971217
 * @len: the length of data
Packit 971217
 *
Packit 971217
 * Create a new buffer and set the data to a copy of @len
Packit 971217
 * bytes of @data and the size to @len. The data will be freed when the buffer
Packit 971217
 * is freed.
Packit 971217
 *
Packit 971217
 * Returns: A newly allocated buffer with a copy of @data and of size @len.
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_rtp_buffer_new_copy_data (gconstpointer data, gsize len)
Packit 971217
{
Packit 971217
  return gst_rtp_buffer_new_take_data (g_memdup (data, len), len);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_new_allocate:
Packit 971217
 * @payload_len: the length of the payload
Packit 971217
 * @pad_len: the amount of padding
Packit 971217
 * @csrc_count: the number of CSRC entries
Packit 971217
 *
Packit 971217
 * Allocate a new #GstBuffer with enough data to hold an RTP packet with
Packit 971217
 * @csrc_count CSRCs, a payload length of @payload_len and padding of @pad_len.
Packit 971217
 * All other RTP header fields will be set to 0/FALSE.
Packit 971217
 *
Packit 971217
 * Returns: A newly allocated buffer that can hold an RTP packet with given
Packit 971217
 * parameters.
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_rtp_buffer_new_allocate (guint payload_len, guint8 pad_len,
Packit 971217
    guint8 csrc_count)
Packit 971217
{
Packit 971217
  GstBuffer *result;
Packit 971217
Packit 971217
  g_return_val_if_fail (csrc_count <= 15, NULL);
Packit 971217
Packit 971217
  result = gst_buffer_new ();
Packit 971217
  gst_rtp_buffer_allocate_data (result, payload_len, pad_len, csrc_count);
Packit 971217
Packit 971217
  return result;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_new_allocate_len:
Packit 971217
 * @packet_len: the total length of the packet
Packit 971217
 * @pad_len: the amount of padding
Packit 971217
 * @csrc_count: the number of CSRC entries
Packit 971217
 *
Packit 971217
 * Create a new #GstBuffer that can hold an RTP packet that is exactly
Packit 971217
 * @packet_len long. The length of the payload depends on @pad_len and
Packit 971217
 * @csrc_count and can be calculated with gst_rtp_buffer_calc_payload_len().
Packit 971217
 * All RTP header fields will be set to 0/FALSE.
Packit 971217
 *
Packit 971217
 * Returns: A newly allocated buffer that can hold an RTP packet of @packet_len.
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_rtp_buffer_new_allocate_len (guint packet_len, guint8 pad_len,
Packit 971217
    guint8 csrc_count)
Packit 971217
{
Packit 971217
  guint len;
Packit 971217
Packit 971217
  g_return_val_if_fail (csrc_count <= 15, NULL);
Packit 971217
Packit 971217
  len = gst_rtp_buffer_calc_payload_len (packet_len, pad_len, csrc_count);
Packit 971217
Packit 971217
  return gst_rtp_buffer_new_allocate (len, pad_len, csrc_count);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_calc_header_len:
Packit 971217
 * @csrc_count: the number of CSRC entries
Packit 971217
 *
Packit 971217
 * Calculate the header length of an RTP packet with @csrc_count CSRC entries.
Packit 971217
 * An RTP packet can have at most 15 CSRC entries.
Packit 971217
 *
Packit 971217
 * Returns: The length of an RTP header with @csrc_count CSRC entries.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtp_buffer_calc_header_len (guint8 csrc_count)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (csrc_count <= 15, 0);
Packit 971217
Packit 971217
  return GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32));
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_calc_packet_len:
Packit 971217
 * @payload_len: the length of the payload
Packit 971217
 * @pad_len: the amount of padding
Packit 971217
 * @csrc_count: the number of CSRC entries
Packit 971217
 *
Packit 971217
 * Calculate the total length of an RTP packet with a payload size of @payload_len,
Packit 971217
 * a padding of @pad_len and a @csrc_count CSRC entries.
Packit 971217
 *
Packit 971217
 * Returns: The total length of an RTP header with given parameters.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtp_buffer_calc_packet_len (guint payload_len, guint8 pad_len,
Packit 971217
    guint8 csrc_count)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (csrc_count <= 15, 0);
Packit 971217
Packit 971217
  return payload_len + GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32))
Packit 971217
      + pad_len;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_calc_payload_len:
Packit 971217
 * @packet_len: the length of the total RTP packet
Packit 971217
 * @pad_len: the amount of padding
Packit 971217
 * @csrc_count: the number of CSRC entries
Packit 971217
 *
Packit 971217
 * Calculate the length of the payload of an RTP packet with size @packet_len,
Packit 971217
 * a padding of @pad_len and a @csrc_count CSRC entries.
Packit 971217
 *
Packit 971217
 * Returns: The length of the payload of an RTP packet  with given parameters.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtp_buffer_calc_payload_len (guint packet_len, guint8 pad_len,
Packit 971217
    guint8 csrc_count)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (csrc_count <= 15, 0);
Packit 971217
Packit 971217
  if (packet_len <
Packit 971217
      GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32)) + pad_len)
Packit 971217
    return 0;
Packit 971217
Packit 971217
  return packet_len - GST_RTP_HEADER_LEN - (csrc_count * sizeof (guint32))
Packit 971217
      - pad_len;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_map:
Packit 971217
 * @buffer: a #GstBuffer
Packit 971217
 * @flags: #GstMapFlags
Packit 971217
 * @rtp: (out): a #GstRTPBuffer
Packit 971217
 *
Packit 971217
 * Map the contents of @buffer into @rtp.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if @buffer could be mapped.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_map (GstBuffer * buffer, GstMapFlags flags, GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  guint8 padding;
Packit 971217
  guint8 csrc_count;
Packit 971217
  guint header_len;
Packit 971217
  guint8 version, pt;
Packit 971217
  guint8 *data;
Packit 971217
  guint size;
Packit 971217
  gsize bufsize, skip;
Packit 971217
  guint idx, length;
Packit 971217
  guint n_mem;
Packit 971217
Packit 971217
  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
Packit 971217
  g_return_val_if_fail (rtp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (rtp->buffer == NULL, FALSE);
Packit 971217
Packit 971217
  n_mem = gst_buffer_n_memory (buffer);
Packit 971217
  if (n_mem < 1)
Packit 971217
    goto no_memory;
Packit 971217
Packit 971217
  /* map first memory, this should be the header */
Packit 971217
  if (!gst_buffer_map_range (buffer, 0, 1, &rtp->map[0], flags))
Packit 971217
    goto map_failed;
Packit 971217
Packit 971217
  data = rtp->data[0] = rtp->map[0].data;
Packit 971217
  size = rtp->map[0].size;
Packit 971217
Packit 971217
  /* the header must be completely in the first buffer */
Packit 971217
  header_len = GST_RTP_HEADER_LEN;
Packit 971217
  if (G_UNLIKELY (size < header_len))
Packit 971217
    goto wrong_length;
Packit 971217
Packit 971217
  /* check version */
Packit 971217
  version = (data[0] & 0xc0);
Packit 971217
  if (G_UNLIKELY (version != (GST_RTP_VERSION << 6)))
Packit 971217
    goto wrong_version;
Packit 971217
Packit 971217
  /* check reserved PT and marker bit, this is to check for RTCP
Packit 971217
   * packets. We do a relaxed check, you can still use 72-76 as long
Packit 971217
   * as the marker bit is cleared. */
Packit 971217
  pt = data[1];
Packit 971217
  if (G_UNLIKELY (pt >= 200 && pt <= 204))
Packit 971217
    goto reserved_pt;
Packit 971217
Packit 971217
  /* calc header length with csrc */
Packit 971217
  csrc_count = (data[0] & 0x0f);
Packit 971217
  header_len += csrc_count * sizeof (guint32);
Packit 971217
Packit 971217
  rtp->size[0] = header_len;
Packit 971217
Packit 971217
  bufsize = gst_buffer_get_size (buffer);
Packit 971217
Packit 971217
  /* calc extension length when present. */
Packit 971217
  if (data[0] & 0x10) {
Packit 971217
    guint8 *extdata;
Packit 971217
    guint16 extlen;
Packit 971217
Packit 971217
    /* find memory for the extension bits, we find the block for the first 4
Packit 971217
     * bytes, all other extension bytes should also be in this block */
Packit 971217
    if (!gst_buffer_find_memory (buffer, header_len, 4, &idx, &length, &skip))
Packit 971217
      goto wrong_length;
Packit 971217
Packit 971217
    if (!gst_buffer_map_range (buffer, idx, length, &rtp->map[1], flags))
Packit 971217
      goto map_failed;
Packit 971217
Packit 971217
    extdata = rtp->data[1] = rtp->map[1].data + skip;
Packit 971217
    /* skip id */
Packit 971217
    extdata += 2;
Packit 971217
    /* read length as the number of 32 bits words */
Packit 971217
    extlen = GST_READ_UINT16_BE (extdata);
Packit 971217
    extlen *= sizeof (guint32);
Packit 971217
    /* add id and length */
Packit 971217
    extlen += 4;
Packit 971217
Packit 971217
    /* all extension bytes must be in this block */
Packit 971217
    if (G_UNLIKELY (rtp->map[1].size < extlen))
Packit 971217
      goto wrong_length;
Packit 971217
Packit 971217
    rtp->size[1] = extlen;
Packit 971217
Packit 971217
    header_len += rtp->size[1];
Packit 971217
  } else {
Packit 971217
    rtp->data[1] = NULL;
Packit 971217
    rtp->size[1] = 0;
Packit 971217
  }
Packit 971217
Packit 971217
  /* check for padding unless flags says to skip */
Packit 971217
  if ((data[0] & 0x20) != 0 &&
Packit 971217
      (flags & GST_RTP_BUFFER_MAP_FLAG_SKIP_PADDING) == 0) {
Packit 971217
    /* find memory for the padding bits */
Packit 971217
    if (!gst_buffer_find_memory (buffer, bufsize - 1, 1, &idx, &length, &skip))
Packit 971217
      goto wrong_length;
Packit 971217
Packit 971217
    if (!gst_buffer_map_range (buffer, idx, length, &rtp->map[3], flags))
Packit 971217
      goto map_failed;
Packit 971217
Packit 971217
    padding = rtp->map[3].data[skip];
Packit 971217
    rtp->data[3] = rtp->map[3].data + skip + 1 - padding;
Packit 971217
    rtp->size[3] = padding;
Packit 971217
Packit 971217
    if (skip + 1 < padding)
Packit 971217
      goto wrong_length;
Packit 971217
  } else {
Packit 971217
    rtp->data[3] = NULL;
Packit 971217
    rtp->size[3] = 0;
Packit 971217
    padding = 0;
Packit 971217
  }
Packit 971217
Packit 971217
  /* check if padding and header not bigger than packet length */
Packit 971217
  if (G_UNLIKELY (bufsize < padding + header_len))
Packit 971217
    goto wrong_padding;
Packit 971217
Packit 971217
  rtp->buffer = buffer;
Packit 971217
Packit 971217
  if (n_mem == 1) {
Packit 971217
    /* we have mapped the buffer already, so might just as well fill in the
Packit 971217
     * payload pointer and size and avoid another buffer map/unmap later */
Packit 971217
    rtp->data[2] = rtp->map[0].data + header_len;
Packit 971217
    rtp->size[2] = bufsize - header_len - padding;
Packit 971217
  } else {
Packit 971217
    /* we have not yet mapped the payload */
Packit 971217
    rtp->data[2] = NULL;
Packit 971217
    rtp->size[2] = 0;
Packit 971217
  }
Packit 971217
Packit 971217
  /* rtp->state = 0; *//* unused */
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
no_memory:
Packit 971217
  {
Packit 971217
    GST_ERROR ("buffer without memory");
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
map_failed:
Packit 971217
  {
Packit 971217
    GST_ERROR ("failed to map memory");
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
wrong_length:
Packit 971217
  {
Packit 971217
    GST_DEBUG ("length check failed");
Packit 971217
    goto dump_packet;
Packit 971217
  }
Packit 971217
wrong_version:
Packit 971217
  {
Packit 971217
    GST_DEBUG ("version check failed (%d != %d)", version, GST_RTP_VERSION);
Packit 971217
    goto dump_packet;
Packit 971217
  }
Packit 971217
reserved_pt:
Packit 971217
  {
Packit 971217
    GST_DEBUG ("reserved PT %d found", pt);
Packit 971217
    goto dump_packet;
Packit 971217
  }
Packit 971217
wrong_padding:
Packit 971217
  {
Packit 971217
    GST_DEBUG ("padding check failed (%" G_GSIZE_FORMAT " - %d < %d)", bufsize,
Packit 971217
        header_len, padding);
Packit 971217
    goto dump_packet;
Packit 971217
  }
Packit 971217
dump_packet:
Packit 971217
  {
Packit 971217
    gint i;
Packit 971217
Packit 971217
    GST_MEMDUMP ("buffer", data, size);
Packit 971217
Packit 971217
    for (i = 0; i < G_N_ELEMENTS (rtp->map); ++i) {
Packit 971217
      if (rtp->map[i].memory != NULL)
Packit 971217
        gst_buffer_unmap (buffer, &rtp->map[i]);
Packit 971217
    }
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_unmap:
Packit 971217
 * @rtp: a #GstRTPBuffer
Packit 971217
 *
Packit 971217
 * Unmap @rtp previously mapped with gst_rtp_buffer_map().
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_unmap (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  gint i;
Packit 971217
Packit 971217
  g_return_if_fail (rtp != NULL);
Packit 971217
  g_return_if_fail (rtp->buffer != NULL);
Packit 971217
Packit 971217
  for (i = 0; i < 4; i++) {
Packit 971217
    if (rtp->map[i].memory != NULL) {
Packit 971217
      gst_buffer_unmap (rtp->buffer, &rtp->map[i]);
Packit 971217
      rtp->map[i].memory = NULL;
Packit 971217
    }
Packit 971217
    rtp->data[i] = NULL;
Packit 971217
    rtp->size[i] = 0;
Packit 971217
  }
Packit 971217
  rtp->buffer = NULL;
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_packet_len:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @len: the new packet length
Packit 971217
 *
Packit 971217
 * Set the total @rtp size to @len. The data in the buffer will be made
Packit 971217
 * larger if needed. Any padding will be removed from the packet.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_packet_len (GstRTPBuffer * rtp, guint len)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  data = rtp->data[0];
Packit 971217
Packit 971217
  /* FIXME */
Packit 971217
Packit 971217
  if (rtp->map[0].maxsize <= len) {
Packit 971217
    /* FIXME, realloc bigger space */
Packit 971217
    g_warning ("not implemented");
Packit 971217
  }
Packit 971217
Packit 971217
  gst_buffer_set_size (rtp->buffer, len);
Packit 971217
  rtp->map[0].size = len;
Packit 971217
Packit 971217
  /* remove any padding */
Packit 971217
  GST_RTP_HEADER_PADDING (data) = FALSE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_packet_len:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Return the total length of the packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: The total length of the packet in @buffer.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtp_buffer_get_packet_len (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return gst_buffer_get_size (rtp->buffer);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_header_len:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Return the total length of the header in @buffer. This include the length of
Packit 971217
 * the fixed header, the CSRC list and the extension header.
Packit 971217
 *
Packit 971217
 * Returns: The total length of the header in @buffer.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtp_buffer_get_header_len (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return rtp->size[0] + rtp->size[1];
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_version:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Get the version number of the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: The version of @buffer.
Packit 971217
 */
Packit 971217
guint8
Packit 971217
gst_rtp_buffer_get_version (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return GST_RTP_HEADER_VERSION (rtp->data[0]);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_version:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @version: the new version
Packit 971217
 *
Packit 971217
 * Set the version of the RTP packet in @buffer to @version.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_version (GstRTPBuffer * rtp, guint8 version)
Packit 971217
{
Packit 971217
  g_return_if_fail (version < 0x04);
Packit 971217
Packit 971217
  GST_RTP_HEADER_VERSION (rtp->data[0]) = version;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_padding:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Check if the padding bit is set on the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @buffer has the padding bit set.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_get_padding (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return GST_RTP_HEADER_PADDING (rtp->data[0]);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_padding:
Packit 971217
 * @rtp: the buffer
Packit 971217
 * @padding: the new padding
Packit 971217
 *
Packit 971217
 * Set the padding bit on the RTP packet in @buffer to @padding.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_padding (GstRTPBuffer * rtp, gboolean padding)
Packit 971217
{
Packit 971217
  GST_RTP_HEADER_PADDING (rtp->data[0]) = padding;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_pad_to:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @len: the new amount of padding
Packit 971217
 *
Packit 971217
 * Set the amount of padding in the RTP packet in @buffer to
Packit 971217
 * @len. If @len is 0, the padding is removed.
Packit 971217
 *
Packit 971217
 * NOTE: This function does not work correctly.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_pad_to (GstRTPBuffer * rtp, guint len)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  data = rtp->data[0];
Packit 971217
Packit 971217
  if (len > 0)
Packit 971217
    GST_RTP_HEADER_PADDING (data) = TRUE;
Packit 971217
  else
Packit 971217
    GST_RTP_HEADER_PADDING (data) = FALSE;
Packit 971217
Packit 971217
  /* FIXME, set the padding byte at the end of the payload data */
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_extension:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Check if the extension bit is set on the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @buffer has the extension bit set.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_get_extension (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return GST_RTP_HEADER_EXTENSION (rtp->data[0]);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_extension:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @extension: the new extension
Packit 971217
 *
Packit 971217
 * Set the extension bit on the RTP packet in @buffer to @extension.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_extension (GstRTPBuffer * rtp, gboolean extension)
Packit 971217
{
Packit 971217
  GST_RTP_HEADER_EXTENSION (rtp->data[0]) = extension;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_extension_data: (skip)
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @bits: (out): location for result bits
Packit 971217
 * @data: (out) (array) (element-type guint8) (transfer none): location for data
Packit 971217
 * @wordlen: (out): location for length of @data in 32 bits words
Packit 971217
 *
Packit 971217
 * Get the extension data. @bits will contain the extension 16 bits of custom
Packit 971217
 * data. @data will point to the data in the extension and @wordlen will contain
Packit 971217
 * the length of @data in 32 bits words.
Packit 971217
 *
Packit 971217
 * If @buffer did not contain an extension, this function will return %FALSE
Packit 971217
 * with @bits, @data and @wordlen unchanged.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @buffer had the extension bit set.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_get_extension_data (GstRTPBuffer * rtp, guint16 * bits,
Packit 971217
    gpointer * data, guint * wordlen)
Packit 971217
{
Packit 971217
  guint8 *pdata;
Packit 971217
Packit 971217
  /* move to the extension */
Packit 971217
  pdata = rtp->data[1];
Packit 971217
  if (!pdata)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if (bits)
Packit 971217
    *bits = GST_READ_UINT16_BE (pdata);
Packit 971217
  if (wordlen)
Packit 971217
    *wordlen = GST_READ_UINT16_BE (pdata + 2);
Packit 971217
  pdata += 4;
Packit 971217
  if (data)
Packit 971217
    *data = (gpointer *) pdata;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_extension_bytes: (rename-to gst_rtp_buffer_get_extension_data)
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @bits: (out): location for header bits
Packit 971217
 *
Packit 971217
 * Similar to gst_rtp_buffer_get_extension_data, but more suitable for language
Packit 971217
 * bindings usage. @bits will contain the extension 16 bits of custom data and
Packit 971217
 * the extension data (not including the extension header) is placed in a new
Packit 971217
 * #GBytes structure.
Packit 971217
 *
Packit 971217
 * If @rtp did not contain an extension, this function will return %NULL, with
Packit 971217
 * @bits unchanged. If there is an extension header but no extension data then
Packit 971217
 * an empty #GBytes will be returned.
Packit 971217
 *
Packit 971217
 * Returns: (transfer full): A new #GBytes if an extension header was present
Packit 971217
 * and %NULL otherwise.
Packit 971217
 *
Packit 971217
 * Since: 1.2
Packit 971217
 */
Packit 971217
GBytes *
Packit 971217
gst_rtp_buffer_get_extension_bytes (GstRTPBuffer * rtp, guint16 * bits)
Packit 971217
{
Packit 971217
  gpointer buf_data = NULL;
Packit 971217
  guint buf_len;
Packit 971217
Packit 971217
  g_return_val_if_fail (rtp != NULL, FALSE);
Packit 971217
Packit 971217
  if (!gst_rtp_buffer_get_extension_data (rtp, bits, &buf_data, &buf_len))
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  if (buf_len == 0) {
Packit 971217
    /* if no extension data is present return an empty GBytes */
Packit 971217
    buf_data = NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  /* multiply length with 4 to get length in bytes */
Packit 971217
  return g_bytes_new (buf_data, 4 * buf_len);
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_rtp_buffer_map_payload (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  guint hlen, plen;
Packit 971217
  guint idx, length;
Packit 971217
  gsize skip;
Packit 971217
Packit 971217
  if (rtp->map[2].memory != NULL)
Packit 971217
    return TRUE;
Packit 971217
Packit 971217
  hlen = gst_rtp_buffer_get_header_len (rtp);
Packit 971217
  plen = gst_buffer_get_size (rtp->buffer) - hlen - rtp->size[3];
Packit 971217
Packit 971217
  if (!gst_buffer_find_memory (rtp->buffer, hlen, plen, &idx, &length, &skip))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if (!gst_buffer_map_range (rtp->buffer, idx, length, &rtp->map[2],
Packit 971217
          rtp->map[0].flags))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  rtp->data[2] = rtp->map[2].data + skip;
Packit 971217
  rtp->size[2] = plen;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/* ensure header, payload and padding are in separate buffers */
Packit 971217
static void
Packit 971217
ensure_buffers (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  guint i, pos;
Packit 971217
  gboolean changed = FALSE;
Packit 971217
Packit 971217
  /* make sure payload is mapped */
Packit 971217
  gst_rtp_buffer_map_payload (rtp);
Packit 971217
Packit 971217
  for (i = 0, pos = 0; i < 4; i++) {
Packit 971217
    if (rtp->size[i]) {
Packit 971217
      gsize offset = (guint8 *) rtp->data[i] - rtp->map[i].data;
Packit 971217
Packit 971217
      if (offset != 0 || rtp->map[i].size != rtp->size[i]) {
Packit 971217
        GstMemory *mem;
Packit 971217
Packit 971217
        /* make copy */
Packit 971217
        mem = gst_memory_copy (rtp->map[i].memory, offset, rtp->size[i]);
Packit 971217
Packit 971217
        /* insert new memory */
Packit 971217
        gst_buffer_insert_memory (rtp->buffer, pos, mem);
Packit 971217
Packit 971217
        changed = TRUE;
Packit 971217
      }
Packit 971217
      pos++;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if (changed) {
Packit 971217
    GstBuffer *buf = rtp->buffer;
Packit 971217
Packit 971217
    gst_rtp_buffer_unmap (rtp);
Packit 971217
    gst_buffer_remove_memory_range (buf, pos, -1);
Packit 971217
    gst_rtp_buffer_map (buf, GST_MAP_READWRITE, rtp);
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_extension_data:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @bits: the bits specific for the extension
Packit 971217
 * @length: the length that counts the number of 32-bit words in
Packit 971217
 * the extension, excluding the extension header ( therefore zero is a valid length)
Packit 971217
 *
Packit 971217
 * Set the extension bit of the rtp buffer and fill in the @bits and @length of the
Packit 971217
 * extension header. If the existing extension data is not large enough, it will
Packit 971217
 * be made larger.
Packit 971217
 *
Packit 971217
 * Returns: True if done.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_set_extension_data (GstRTPBuffer * rtp, guint16 bits,
Packit 971217
    guint16 length)
Packit 971217
{
Packit 971217
  guint32 min_size = 0;
Packit 971217
  guint8 *data;
Packit 971217
  GstMemory *mem = NULL;
Packit 971217
Packit 971217
  ensure_buffers (rtp);
Packit 971217
Packit 971217
  /* this is the size of the extension data we need */
Packit 971217
  min_size = 4 + length * sizeof (guint32);
Packit 971217
Packit 971217
  /* we should allocate and map the extension data */
Packit 971217
  if (rtp->data[1] == NULL || min_size > rtp->size[1]) {
Packit 971217
    GstMapInfo map;
Packit 971217
Packit 971217
    /* we don't have (enough) extension data, make some */
Packit 971217
    mem = gst_allocator_alloc (NULL, min_size, NULL);
Packit 971217
Packit 971217
    if (rtp->data[1]) {
Packit 971217
      /* copy old data */
Packit 971217
      gst_memory_map (mem, &map, GST_MAP_WRITE);
Packit 971217
      memcpy (map.data, rtp->data[1], rtp->size[1]);
Packit 971217
      gst_memory_unmap (mem, &map);
Packit 971217
Packit 971217
      /* unmap old */
Packit 971217
      gst_buffer_unmap (rtp->buffer, &rtp->map[1]);
Packit 971217
      gst_buffer_replace_memory (rtp->buffer, 1, mem);
Packit 971217
    } else {
Packit 971217
      /* we didn't have extension data, add */
Packit 971217
      gst_buffer_insert_memory (rtp->buffer, 1, mem);
Packit 971217
    }
Packit 971217
Packit 971217
    /* map new */
Packit 971217
    gst_memory_map (mem, &rtp->map[1], GST_MAP_READWRITE);
Packit 971217
    gst_memory_ref (mem);
Packit 971217
    rtp->data[1] = rtp->map[1].data;
Packit 971217
    rtp->size[1] = rtp->map[1].size;
Packit 971217
  }
Packit 971217
Packit 971217
  /* now we can set the extension bit */
Packit 971217
  data = rtp->data[0];
Packit 971217
  GST_RTP_HEADER_EXTENSION (data) = TRUE;
Packit 971217
Packit 971217
  data = rtp->data[1];
Packit 971217
  GST_WRITE_UINT16_BE (data, bits);
Packit 971217
  GST_WRITE_UINT16_BE (data + 2, length);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_ssrc:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Get the SSRC of the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: the SSRC of @buffer in host order.
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtp_buffer_get_ssrc (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return g_ntohl (GST_RTP_HEADER_SSRC (rtp->data[0]));
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_ssrc:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @ssrc: the new SSRC
Packit 971217
 *
Packit 971217
 * Set the SSRC on the RTP packet in @buffer to @ssrc.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_ssrc (GstRTPBuffer * rtp, guint32 ssrc)
Packit 971217
{
Packit 971217
  GST_RTP_HEADER_SSRC (rtp->data[0]) = g_htonl (ssrc);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_csrc_count:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Get the CSRC count of the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: the CSRC count of @buffer.
Packit 971217
 */
Packit 971217
guint8
Packit 971217
gst_rtp_buffer_get_csrc_count (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return GST_RTP_HEADER_CSRC_COUNT (rtp->data[0]);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_csrc:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @idx: the index of the CSRC to get
Packit 971217
 *
Packit 971217
 * Get the CSRC at index @idx in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: the CSRC at index @idx in host order.
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtp_buffer_get_csrc (GstRTPBuffer * rtp, guint8 idx)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  data = rtp->data[0];
Packit 971217
Packit 971217
  g_return_val_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data), 0);
Packit 971217
Packit 971217
  return GST_READ_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx));
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_csrc:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @idx: the CSRC index to set
Packit 971217
 * @csrc: the CSRC in host order to set at @idx
Packit 971217
 *
Packit 971217
 * Modify the CSRC at index @idx in @buffer to @csrc.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_csrc (GstRTPBuffer * rtp, guint8 idx, guint32 csrc)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  data = rtp->data[0];
Packit 971217
Packit 971217
  g_return_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data));
Packit 971217
Packit 971217
  GST_WRITE_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx), csrc);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_marker:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Check if the marker bit is set on the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @buffer has the marker bit set.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_get_marker (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return GST_RTP_HEADER_MARKER (rtp->data[0]);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_marker:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @marker: the new marker
Packit 971217
 *
Packit 971217
 * Set the marker bit on the RTP packet in @buffer to @marker.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_marker (GstRTPBuffer * rtp, gboolean marker)
Packit 971217
{
Packit 971217
  GST_RTP_HEADER_MARKER (rtp->data[0]) = marker;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_payload_type:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Get the payload type of the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: The payload type.
Packit 971217
 */
Packit 971217
guint8
Packit 971217
gst_rtp_buffer_get_payload_type (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return GST_RTP_HEADER_PAYLOAD_TYPE (rtp->data[0]);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_payload_type:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @payload_type: the new type
Packit 971217
 *
Packit 971217
 * Set the payload type of the RTP packet in @buffer to @payload_type.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_payload_type (GstRTPBuffer * rtp, guint8 payload_type)
Packit 971217
{
Packit 971217
  g_return_if_fail (payload_type < 0x80);
Packit 971217
Packit 971217
  GST_RTP_HEADER_PAYLOAD_TYPE (rtp->data[0]) = payload_type;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_seq:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Get the sequence number of the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: The sequence number in host order.
Packit 971217
 */
Packit 971217
guint16
Packit 971217
gst_rtp_buffer_get_seq (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return g_ntohs (GST_RTP_HEADER_SEQ (rtp->data[0]));
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_seq:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @seq: the new sequence number
Packit 971217
 *
Packit 971217
 * Set the sequence number of the RTP packet in @buffer to @seq.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_seq (GstRTPBuffer * rtp, guint16 seq)
Packit 971217
{
Packit 971217
  GST_RTP_HEADER_SEQ (rtp->data[0]) = g_htons (seq);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_timestamp:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Get the timestamp of the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: The timestamp in host order.
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtp_buffer_get_timestamp (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return g_ntohl (GST_RTP_HEADER_TIMESTAMP (rtp->data[0]));
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_set_timestamp:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @timestamp: the new timestamp
Packit 971217
 *
Packit 971217
 * Set the timestamp of the RTP packet in @buffer to @timestamp.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtp_buffer_set_timestamp (GstRTPBuffer * rtp, guint32 timestamp)
Packit 971217
{
Packit 971217
  GST_RTP_HEADER_TIMESTAMP (rtp->data[0]) = g_htonl (timestamp);
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_payload_subbuffer:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @offset: the offset in the payload
Packit 971217
 * @len: the length in the payload
Packit 971217
 *
Packit 971217
 * Create a subbuffer of the payload of the RTP packet in @buffer. @offset bytes
Packit 971217
 * are skipped in the payload and the subbuffer will be of size @len.
Packit 971217
 * If @len is -1 the total payload starting from @offset is subbuffered.
Packit 971217
 *
Packit 971217
 * Returns: A new buffer with the specified data of the payload.
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_rtp_buffer_get_payload_subbuffer (GstRTPBuffer * rtp, guint offset,
Packit 971217
    guint len)
Packit 971217
{
Packit 971217
  guint poffset, plen;
Packit 971217
Packit 971217
  plen = gst_rtp_buffer_get_payload_len (rtp);
Packit 971217
  /* we can't go past the length */
Packit 971217
  if (G_UNLIKELY (offset > plen))
Packit 971217
    goto wrong_offset;
Packit 971217
Packit 971217
  /* apply offset */
Packit 971217
  poffset = gst_rtp_buffer_get_header_len (rtp) + offset;
Packit 971217
  plen -= offset;
Packit 971217
Packit 971217
  /* see if we need to shrink the buffer based on @len */
Packit 971217
  if (len != -1 && len < plen)
Packit 971217
    plen = len;
Packit 971217
Packit 971217
  return gst_buffer_copy_region (rtp->buffer, GST_BUFFER_COPY_ALL, poffset,
Packit 971217
      plen);
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
wrong_offset:
Packit 971217
  {
Packit 971217
    g_warning ("offset=%u should be less than plen=%u", offset, plen);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_payload_buffer:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Create a buffer of the payload of the RTP packet in @buffer. This function
Packit 971217
 * will internally create a subbuffer of @buffer so that a memcpy can be
Packit 971217
 * avoided.
Packit 971217
 *
Packit 971217
 * Returns: A new buffer with the data of the payload.
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_rtp_buffer_get_payload_buffer (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return gst_rtp_buffer_get_payload_subbuffer (rtp, 0, -1);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_payload_len:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Get the length of the payload of the RTP packet in @buffer.
Packit 971217
 *
Packit 971217
 * Returns: The length of the payload in @buffer.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtp_buffer_get_payload_len (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  return gst_buffer_get_size (rtp->buffer) - gst_rtp_buffer_get_header_len (rtp)
Packit 971217
      - rtp->size[3];
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_payload: (skip)
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Get a pointer to the payload data in @buffer. This pointer is valid as long
Packit 971217
 * as a reference to @buffer is held.
Packit 971217
 *
Packit 971217
 * Returns: (array) (element-type guint8) (transfer none): A pointer
Packit 971217
 * to the payload data in @buffer.
Packit 971217
 */
Packit 971217
gpointer
Packit 971217
gst_rtp_buffer_get_payload (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  if (rtp->data[2])
Packit 971217
    return rtp->data[2];
Packit 971217
Packit 971217
  if (!gst_rtp_buffer_map_payload (rtp))
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  return rtp->data[2];
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_payload_bytes: (rename-to gst_rtp_buffer_get_payload)
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 *
Packit 971217
 * Similar to gst_rtp_buffer_get_payload, but more suitable for language
Packit 971217
 * bindings usage. The return value is a pointer to a #GBytes structure
Packit 971217
 * containing the payload data in @rtp.
Packit 971217
 *
Packit 971217
 * Returns: (transfer full): A new #GBytes containing the payload data in @rtp.
Packit 971217
 *
Packit 971217
 * Since: 1.2
Packit 971217
 */
Packit 971217
GBytes *
Packit 971217
gst_rtp_buffer_get_payload_bytes (GstRTPBuffer * rtp)
Packit 971217
{
Packit 971217
  gpointer data;
Packit 971217
Packit 971217
  g_return_val_if_fail (rtp != NULL, NULL);
Packit 971217
Packit 971217
  data = gst_rtp_buffer_get_payload (rtp);
Packit 971217
  if (data == NULL)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  return g_bytes_new (data, gst_rtp_buffer_get_payload_len (rtp));
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_default_clock_rate:
Packit 971217
 * @payload_type: the static payload type
Packit 971217
 *
Packit 971217
 * Get the default clock-rate for the static payload type @payload_type.
Packit 971217
 *
Packit 971217
 * Returns: the default clock rate or -1 if the payload type is not static or
Packit 971217
 * the clock-rate is undefined.
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtp_buffer_default_clock_rate (guint8 payload_type)
Packit 971217
{
Packit 971217
  const GstRTPPayloadInfo *info;
Packit 971217
  guint32 res;
Packit 971217
Packit 971217
  info = gst_rtp_payload_info_for_pt (payload_type);
Packit 971217
  if (!info)
Packit 971217
    return -1;
Packit 971217
Packit 971217
  res = info->clock_rate;
Packit 971217
  /* 0 means unknown so we have to return -1 from this function */
Packit 971217
  if (res == 0)
Packit 971217
    res = -1;
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_compare_seqnum:
Packit 971217
 * @seqnum1: a sequence number
Packit 971217
 * @seqnum2: a sequence number
Packit 971217
 *
Packit 971217
 * Compare two sequence numbers, taking care of wraparounds. This function
Packit 971217
 * returns the difference between @seqnum1 and @seqnum2.
Packit 971217
 *
Packit 971217
 * Returns: a negative value if @seqnum1 is bigger than @seqnum2, 0 if they
Packit 971217
 * are equal or a positive value if @seqnum1 is smaller than @segnum2.
Packit 971217
 */
Packit 971217
gint
Packit 971217
gst_rtp_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2)
Packit 971217
{
Packit 971217
  /* See http://en.wikipedia.org/wiki/Serial_number_arithmetic
Packit 971217
   * for an explanation why this does the right thing even for
Packit 971217
   * wraparounds, under the assumption that the difference is
Packit 971217
   * never bigger than 2**15 sequence numbers
Packit 971217
   */
Packit 971217
  return (gint16) (seqnum2 - seqnum1);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_ext_timestamp:
Packit 971217
 * @exttimestamp: (inout): a previous extended timestamp
Packit 971217
 * @timestamp: a new timestamp
Packit 971217
 *
Packit 971217
 * Update the @exttimestamp field with the extended timestamp of @timestamp
Packit 971217
 * For the first call of the method, @exttimestamp should point to a location
Packit 971217
 * with a value of -1.
Packit 971217
 *
Packit 971217
 * This function is able to handle both forward and backward timestamps taking
Packit 971217
 * into account:
Packit 971217
 *   - timestamp wraparound making sure that the returned value is properly increased.
Packit 971217
 *   - timestamp unwraparound making sure that the returned value is properly decreased.
Packit 971217
 *
Packit 971217
 * Returns: The extended timestamp of @timestamp or 0 if the result can't go anywhere backwards.
Packit 971217
 */
Packit 971217
guint64
Packit 971217
gst_rtp_buffer_ext_timestamp (guint64 * exttimestamp, guint32 timestamp)
Packit 971217
{
Packit 971217
  guint64 result, ext;
Packit 971217
Packit 971217
  g_return_val_if_fail (exttimestamp != NULL, -1);
Packit 971217
Packit 971217
  ext = *exttimestamp;
Packit 971217
Packit 971217
  if (ext == -1) {
Packit 971217
    result = timestamp;
Packit 971217
  } else {
Packit 971217
    /* pick wraparound counter from previous timestamp and add to new timestamp */
Packit 971217
    result = timestamp + (ext & ~(G_GUINT64_CONSTANT (0xffffffff)));
Packit 971217
Packit 971217
    /* check for timestamp wraparound */
Packit 971217
    if (result < ext) {
Packit 971217
      guint64 diff = ext - result;
Packit 971217
Packit 971217
      if (diff > G_MAXINT32) {
Packit 971217
        /* timestamp went backwards more than allowed, we wrap around and get
Packit 971217
         * updated extended timestamp. */
Packit 971217
        result += (G_GUINT64_CONSTANT (1) << 32);
Packit 971217
      }
Packit 971217
    } else {
Packit 971217
      guint64 diff = result - ext;
Packit 971217
Packit 971217
      if (diff > G_MAXINT32) {
Packit 971217
        if (result < (G_GUINT64_CONSTANT (1) << 32)) {
Packit 971217
          GST_WARNING
Packit 971217
              ("Cannot unwrap, any wrapping took place yet. Returning 0 without updating extended timestamp.");
Packit 971217
          return 0;
Packit 971217
        } else {
Packit 971217
          /* timestamp went forwards more than allowed, we unwrap around and get
Packit 971217
           * updated extended timestamp. */
Packit 971217
          result -= (G_GUINT64_CONSTANT (1) << 32);
Packit 971217
          /* We don't want the extended timestamp storage to go back, ever */
Packit 971217
          return result;
Packit 971217
        }
Packit 971217
      }
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  *exttimestamp = result;
Packit 971217
Packit 971217
  return result;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_extension_onebyte_header:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @id: The ID of the header extension to be read (between 1 and 14).
Packit 971217
 * @nth: Read the nth extension packet with the requested ID
Packit 971217
 * @data: (out) (array length=size) (element-type guint8) (transfer none):
Packit 971217
 *   location for data
Packit 971217
 * @size: (out): the size of the data in bytes
Packit 971217
 *
Packit 971217
 * Parses RFC 5285 style header extensions with a one byte header. It will
Packit 971217
 * return the nth extension with the requested id.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @buffer had the requested header extension
Packit 971217
 */
Packit 971217
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_get_extension_onebyte_header (GstRTPBuffer * rtp, guint8 id,
Packit 971217
    guint nth, gpointer * data, guint * size)
Packit 971217
{
Packit 971217
  guint16 bits;
Packit 971217
  guint8 *pdata;
Packit 971217
  guint wordlen;
Packit 971217
  gulong offset = 0;
Packit 971217
  guint count = 0;
Packit 971217
Packit 971217
  g_return_val_if_fail (id > 0 && id < 15, FALSE);
Packit 971217
Packit 971217
  if (!gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer) & pdata,
Packit 971217
          &wordlen))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if (bits != 0xBEDE)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  for (;;) {
Packit 971217
    guint8 read_id, read_len;
Packit 971217
Packit 971217
    if (offset + 1 >= wordlen * 4)
Packit 971217
      break;
Packit 971217
Packit 971217
    read_id = GST_READ_UINT8 (pdata + offset) >> 4;
Packit 971217
    read_len = (GST_READ_UINT8 (pdata + offset) & 0x0F) + 1;
Packit 971217
    offset += 1;
Packit 971217
Packit 971217
    /* ID 0 means its padding, skip */
Packit 971217
    if (read_id == 0)
Packit 971217
      continue;
Packit 971217
Packit 971217
    /* ID 15 is special and means we should stop parsing */
Packit 971217
    if (read_id == 15)
Packit 971217
      break;
Packit 971217
Packit 971217
    /* Ignore extension headers where the size does not fit */
Packit 971217
    if (offset + read_len > wordlen * 4)
Packit 971217
      break;
Packit 971217
Packit 971217
    /* If we have the right one */
Packit 971217
    if (id == read_id) {
Packit 971217
      if (nth == count) {
Packit 971217
        if (data)
Packit 971217
          *data = pdata + offset;
Packit 971217
        if (size)
Packit 971217
          *size = read_len;
Packit 971217
Packit 971217
        return TRUE;
Packit 971217
      }
Packit 971217
Packit 971217
      count++;
Packit 971217
    }
Packit 971217
    offset += read_len;
Packit 971217
Packit 971217
    if (offset >= wordlen * 4)
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_get_extension_twobytes_header:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @appbits: (out): Application specific bits
Packit 971217
 * @id: The ID of the header extension to be read (between 1 and 14).
Packit 971217
 * @nth: Read the nth extension packet with the requested ID
Packit 971217
 * @data: (out) (array length=size) (element-type guint8) (transfer none):
Packit 971217
 *   location for data
Packit 971217
 * @size: (out): the size of the data in bytes
Packit 971217
 *
Packit 971217
 * Parses RFC 5285 style header extensions with a two bytes header. It will
Packit 971217
 * return the nth extension with the requested id.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @buffer had the requested header extension
Packit 971217
 */
Packit 971217
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_get_extension_twobytes_header (GstRTPBuffer * rtp,
Packit 971217
    guint8 * appbits, guint8 id, guint nth, gpointer * data, guint * size)
Packit 971217
{
Packit 971217
  guint16 bits;
Packit 971217
  guint8 *pdata = NULL;
Packit 971217
  guint wordlen;
Packit 971217
  guint bytelen;
Packit 971217
  gulong offset = 0;
Packit 971217
  guint count = 0;
Packit 971217
Packit 971217
  if (!gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer *) & pdata,
Packit 971217
          &wordlen))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if (bits >> 4 != 0x100)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  bytelen = wordlen * 4;
Packit 971217
Packit 971217
  for (;;) {
Packit 971217
    guint8 read_id, read_len;
Packit 971217
Packit 971217
    if (offset + 2 >= bytelen)
Packit 971217
      break;
Packit 971217
Packit 971217
    read_id = GST_READ_UINT8 (pdata + offset);
Packit 971217
    offset += 1;
Packit 971217
Packit 971217
    if (read_id == 0)
Packit 971217
      continue;
Packit 971217
Packit 971217
    read_len = GST_READ_UINT8 (pdata + offset);
Packit 971217
    offset += 1;
Packit 971217
Packit 971217
    /* Ignore extension headers where the size does not fit */
Packit 971217
    if (offset + read_len > bytelen)
Packit 971217
      break;
Packit 971217
Packit 971217
    /* If we have the right one, return it */
Packit 971217
    if (id == read_id) {
Packit 971217
      if (nth == count) {
Packit 971217
        if (data)
Packit 971217
          *data = pdata + offset;
Packit 971217
        if (size)
Packit 971217
          *size = read_len;
Packit 971217
        if (appbits)
Packit 971217
          *appbits = bits;
Packit 971217
Packit 971217
        return TRUE;
Packit 971217
      }
Packit 971217
Packit 971217
      count++;
Packit 971217
    }
Packit 971217
    offset += read_len;
Packit 971217
  }
Packit 971217
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static guint
Packit 971217
get_onebyte_header_end_offset (guint8 * pdata, guint wordlen)
Packit 971217
{
Packit 971217
  guint offset = 0;
Packit 971217
  guint bytelen = wordlen * 4;
Packit 971217
  guint paddingcount = 0;
Packit 971217
Packit 971217
  while (offset + 1 < bytelen) {
Packit 971217
    guint8 read_id, read_len;
Packit 971217
Packit 971217
    read_id = GST_READ_UINT8 (pdata + offset) >> 4;
Packit 971217
    read_len = (GST_READ_UINT8 (pdata + offset) & 0x0F) + 1;
Packit 971217
    offset += 1;
Packit 971217
Packit 971217
    /* ID 0 means its padding, skip */
Packit 971217
    if (read_id == 0) {
Packit 971217
      paddingcount++;
Packit 971217
      continue;
Packit 971217
    }
Packit 971217
Packit 971217
    paddingcount = 0;
Packit 971217
Packit 971217
    /* ID 15 is special and means we should stop parsing */
Packit 971217
    /* It also means we can't add an extra packet */
Packit 971217
    if (read_id == 15)
Packit 971217
      return 0;
Packit 971217
Packit 971217
    /* Ignore extension headers where the size does not fit */
Packit 971217
    if (offset + read_len > bytelen)
Packit 971217
      return 0;
Packit 971217
Packit 971217
    offset += read_len;
Packit 971217
  }
Packit 971217
Packit 971217
  return offset - paddingcount;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_add_extension_onebyte_header:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @id: The ID of the header extension (between 1 and 14).
Packit 971217
 * @data: (array length=size) (element-type guint8): location for data
Packit 971217
 * @size: the size of the data in bytes
Packit 971217
 *
Packit 971217
 * Adds a RFC 5285 header extension with a one byte header to the end of the
Packit 971217
 * RTP header. If there is already a RFC 5285 header extension with a one byte
Packit 971217
 * header, the new extension will be appended.
Packit 971217
 * It will not work if there is already a header extension that does not follow
Packit 971217
 * the mecanism described in RFC 5285 or if there is a header extension with
Packit 971217
 * a two bytes header as described in RFC 5285. In that case, use
Packit 971217
 * gst_rtp_buffer_add_extension_twobytes_header()
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if header extension could be added
Packit 971217
 */
Packit 971217
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_add_extension_onebyte_header (GstRTPBuffer * rtp, guint8 id,
Packit 971217
    gconstpointer data, guint size)
Packit 971217
{
Packit 971217
  guint16 bits;
Packit 971217
  guint8 *pdata = 0;
Packit 971217
  guint wordlen;
Packit 971217
  gboolean has_bit;
Packit 971217
  guint extlen, offset = 0;
Packit 971217
Packit 971217
  g_return_val_if_fail (id > 0 && id < 15, FALSE);
Packit 971217
  g_return_val_if_fail (size >= 1 && size <= 16, FALSE);
Packit 971217
  g_return_val_if_fail (gst_buffer_is_writable (rtp->buffer), FALSE);
Packit 971217
Packit 971217
  has_bit = gst_rtp_buffer_get_extension_data (rtp, &bits,
Packit 971217
      (gpointer) & pdata, &wordlen);
Packit 971217
Packit 971217
  if (has_bit) {
Packit 971217
    if (bits != 0xBEDE)
Packit 971217
      return FALSE;
Packit 971217
Packit 971217
    offset = get_onebyte_header_end_offset (pdata, wordlen);
Packit 971217
    if (offset == 0)
Packit 971217
      return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  /* the required size of the new extension data */
Packit 971217
  extlen = offset + size + 1;
Packit 971217
  /* calculate amount of words */
Packit 971217
  wordlen = extlen / 4 + ((extlen % 4) ? 1 : 0);
Packit 971217
Packit 971217
  gst_rtp_buffer_set_extension_data (rtp, 0xBEDE, wordlen);
Packit 971217
  gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer) & pdata, &wordlen);
Packit 971217
Packit 971217
  pdata += offset;
Packit 971217
Packit 971217
  pdata[0] = (id << 4) | (0x0F & (size - 1));
Packit 971217
  memcpy (pdata + 1, data, size);
Packit 971217
Packit 971217
  if (extlen % 4)
Packit 971217
    memset (pdata + 1 + size, 0, 4 - (extlen % 4));
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
static guint
Packit 971217
get_twobytes_header_end_offset (const guint8 * pdata, guint wordlen)
Packit 971217
{
Packit 971217
  guint offset = 0;
Packit 971217
  guint bytelen = wordlen * 4;
Packit 971217
  guint paddingcount = 0;
Packit 971217
Packit 971217
  while (offset + 2 < bytelen) {
Packit 971217
    guint8 read_id, read_len;
Packit 971217
Packit 971217
    read_id = GST_READ_UINT8 (pdata + offset);
Packit 971217
    offset += 1;
Packit 971217
Packit 971217
    /* ID 0 means its padding, skip */
Packit 971217
    if (read_id == 0) {
Packit 971217
      paddingcount++;
Packit 971217
      continue;
Packit 971217
    }
Packit 971217
Packit 971217
    paddingcount = 0;
Packit 971217
Packit 971217
    read_len = GST_READ_UINT8 (pdata + offset);
Packit 971217
    offset += 1;
Packit 971217
Packit 971217
    /* Ignore extension headers where the size does not fit */
Packit 971217
    if (offset + read_len > bytelen)
Packit 971217
      return 0;
Packit 971217
Packit 971217
    offset += read_len;
Packit 971217
  }
Packit 971217
Packit 971217
  return offset - paddingcount;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtp_buffer_add_extension_twobytes_header:
Packit 971217
 * @rtp: the RTP packet
Packit 971217
 * @appbits: Application specific bits
Packit 971217
 * @id: The ID of the header extension
Packit 971217
 * @data: (array length=size) (element-type guint8): location for data
Packit 971217
 * @size: the size of the data in bytes
Packit 971217
 *
Packit 971217
 * Adds a RFC 5285 header extension with a two bytes header to the end of the
Packit 971217
 * RTP header. If there is already a RFC 5285 header extension with a two bytes
Packit 971217
 * header, the new extension will be appended.
Packit 971217
 * It will not work if there is already a header extension that does not follow
Packit 971217
 * the mecanism described in RFC 5285 or if there is a header extension with
Packit 971217
 * a one byte header as described in RFC 5285. In that case, use
Packit 971217
 * gst_rtp_buffer_add_extension_onebyte_header()
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if header extension could be added
Packit 971217
 */
Packit 971217
Packit 971217
gboolean
Packit 971217
gst_rtp_buffer_add_extension_twobytes_header (GstRTPBuffer * rtp,
Packit 971217
    guint8 appbits, guint8 id, gconstpointer data, guint size)
Packit 971217
{
Packit 971217
  guint16 bits;
Packit 971217
  guint8 *pdata = 0;
Packit 971217
  guint wordlen;
Packit 971217
  gboolean has_bit;
Packit 971217
  gulong offset = 0;
Packit 971217
  guint extlen;
Packit 971217
Packit 971217
  g_return_val_if_fail ((appbits & 0xF0) == 0, FALSE);
Packit 971217
  g_return_val_if_fail (size < 256, FALSE);
Packit 971217
  g_return_val_if_fail (gst_buffer_is_writable (rtp->buffer), FALSE);
Packit 971217
Packit 971217
  has_bit = gst_rtp_buffer_get_extension_data (rtp, &bits,
Packit 971217
      (gpointer) & pdata, &wordlen);
Packit 971217
Packit 971217
  if (has_bit) {
Packit 971217
    if (bits != ((0x100 << 4) | (appbits & 0x0f)))
Packit 971217
      return FALSE;
Packit 971217
Packit 971217
    offset = get_twobytes_header_end_offset (pdata, wordlen);
Packit 971217
    if (offset == 0)
Packit 971217
      return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  /* the required size of the new extension data */
Packit 971217
  extlen = offset + size + 2;
Packit 971217
  /* calculate amount of words */
Packit 971217
  wordlen = extlen / 4 + ((extlen % 4) ? 1 : 0);
Packit 971217
Packit 971217
  gst_rtp_buffer_set_extension_data (rtp, (0x100 << 4) | (appbits & 0x0F),
Packit 971217
      wordlen);
Packit 971217
  gst_rtp_buffer_get_extension_data (rtp, &bits, (gpointer) & pdata, &wordlen);
Packit 971217
Packit 971217
  pdata += offset;
Packit 971217
Packit 971217
  pdata[0] = id;
Packit 971217
  pdata[1] = size;
Packit 971217
  memcpy (pdata + 2, data, size);
Packit 971217
  if (extlen % 4)
Packit 971217
    memset (pdata + 2 + size, 0, 4 - (extlen % 4));
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}