mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-30 12:10:37 +00:00
477 lines
11 KiB
C
477 lines
11 KiB
C
/* GStreamer
|
|
* Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* 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., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
#include <string.h>
|
|
|
|
#include "gstrdtbuffer.h"
|
|
|
|
gboolean
|
|
gst_rdt_buffer_validate_data (guint8 * data, guint len)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_rdt_buffer_validate (GstBuffer * buffer)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
guint
|
|
gst_rdt_buffer_get_packet_count (GstBuffer * buffer)
|
|
{
|
|
GstRDTPacket packet;
|
|
guint count;
|
|
|
|
g_return_val_if_fail (GST_IS_BUFFER (buffer), 0);
|
|
|
|
count = 0;
|
|
if (gst_rdt_buffer_get_first_packet (buffer, &packet)) {
|
|
do {
|
|
count++;
|
|
} while (gst_rdt_packet_move_to_next (&packet));
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static gboolean
|
|
read_packet_header (GstRDTPacket * packet)
|
|
{
|
|
GstMapInfo map;
|
|
guint8 *data;
|
|
gsize size;
|
|
guint offset;
|
|
guint length;
|
|
guint length_offset;
|
|
|
|
g_return_val_if_fail (packet != NULL, FALSE);
|
|
g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
|
|
|
|
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
|
data = map.data;
|
|
size = map.size;
|
|
|
|
offset = packet->offset;
|
|
|
|
/* check if we are at the end of the buffer, we add 3 because we also want to
|
|
* ensure we can read the type, which is always at offset 1 and 2 bytes long. */
|
|
if (offset + 3 > size)
|
|
goto packet_end;
|
|
|
|
/* read type */
|
|
packet->type = GST_READ_UINT16_BE (&data[offset + 1]);
|
|
|
|
length = -1;
|
|
length_offset = -1;
|
|
|
|
/* figure out the length of the packet, this depends on the type */
|
|
if (GST_RDT_IS_DATA_TYPE (packet->type)) {
|
|
if (data[offset] & 0x80)
|
|
/* length is present */
|
|
length_offset = 3;
|
|
} else {
|
|
switch (packet->type) {
|
|
case GST_RDT_TYPE_ASMACTION:
|
|
if (data[offset] & 0x80)
|
|
length_offset = 5;
|
|
break;
|
|
case GST_RDT_TYPE_BWREPORT:
|
|
if (data[offset] & 0x80)
|
|
length_offset = 3;
|
|
break;
|
|
case GST_RDT_TYPE_ACK:
|
|
if (data[offset] & 0x80)
|
|
length_offset = 3;
|
|
break;
|
|
case GST_RDT_TYPE_RTTREQ:
|
|
length = 3;
|
|
break;
|
|
case GST_RDT_TYPE_RTTRESP:
|
|
length = 11;
|
|
break;
|
|
case GST_RDT_TYPE_CONGESTION:
|
|
length = 11;
|
|
break;
|
|
case GST_RDT_TYPE_STREAMEND:
|
|
length = 9;
|
|
/* total_reliable */
|
|
if (data[offset] & 0x80)
|
|
length += 2;
|
|
/* stream_id_expansion */
|
|
if ((data[offset] & 0x7c) == 0x7c)
|
|
length += 2;
|
|
/* ext_flag, FIXME, get string length */
|
|
if ((data[offset] & 0x1) == 0x1)
|
|
length += 7;
|
|
break;
|
|
case GST_RDT_TYPE_REPORT:
|
|
if (data[offset] & 0x80)
|
|
length_offset = 3;
|
|
break;
|
|
case GST_RDT_TYPE_LATENCY:
|
|
if (data[offset] & 0x80)
|
|
length_offset = 3;
|
|
break;
|
|
case GST_RDT_TYPE_INFOREQ:
|
|
length = 3;
|
|
/* request_time_ms */
|
|
if (data[offset] & 0x2)
|
|
length += 2;
|
|
break;
|
|
case GST_RDT_TYPE_INFORESP:
|
|
length = 3;
|
|
/* has_rtt_info */
|
|
if (data[offset] & 0x4) {
|
|
length += 4;
|
|
/* is_delayed */
|
|
if (data[offset] & 0x2) {
|
|
length += 4;
|
|
}
|
|
}
|
|
if (data[offset] & 0x1) {
|
|
/* buffer_info_count, FIXME read and skip */
|
|
length += 2;
|
|
}
|
|
break;
|
|
case GST_RDT_TYPE_AUTOBW:
|
|
if (data[offset] & 0x80)
|
|
length_offset = 3;
|
|
break;
|
|
case GST_RDT_TYPE_INVALID:
|
|
default:
|
|
goto unknown_packet;
|
|
}
|
|
}
|
|
|
|
if (length != -1) {
|
|
/* we have a fixed length */
|
|
packet->length = length;
|
|
} else if (length_offset != -1) {
|
|
/* we can read the length from an offset */
|
|
packet->length = GST_READ_UINT16_BE (&data[length_offset]);
|
|
} else {
|
|
/* length is remainder of packet */
|
|
packet->length = size - offset;
|
|
}
|
|
gst_buffer_unmap (packet->buffer, &map);
|
|
|
|
/* the length should be smaller than the remaining size */
|
|
if (packet->length + offset > size)
|
|
goto invalid_length;
|
|
|
|
return TRUE;
|
|
|
|
/* ERRORS */
|
|
packet_end:
|
|
{
|
|
gst_buffer_unmap (packet->buffer, &map);
|
|
return FALSE;
|
|
}
|
|
unknown_packet:
|
|
{
|
|
packet->type = GST_RDT_TYPE_INVALID;
|
|
gst_buffer_unmap (packet->buffer, &map);
|
|
return FALSE;
|
|
}
|
|
invalid_length:
|
|
{
|
|
packet->type = GST_RDT_TYPE_INVALID;
|
|
packet->length = 0;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
gboolean
|
|
gst_rdt_buffer_get_first_packet (GstBuffer * buffer, GstRDTPacket * packet)
|
|
{
|
|
g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
|
|
g_return_val_if_fail (packet != NULL, FALSE);
|
|
|
|
/* init to 0 */
|
|
packet->buffer = buffer;
|
|
packet->offset = 0;
|
|
packet->type = GST_RDT_TYPE_INVALID;
|
|
memset (&packet->map, 0, sizeof (GstMapInfo));
|
|
|
|
if (!read_packet_header (packet))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gst_rdt_packet_move_to_next (GstRDTPacket * packet)
|
|
{
|
|
g_return_val_if_fail (packet != NULL, FALSE);
|
|
g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, FALSE);
|
|
g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE);
|
|
|
|
/* if we have an invalid packet, it must be the last,
|
|
* return FALSE */
|
|
if (packet->type == GST_RDT_TYPE_INVALID)
|
|
goto end;
|
|
|
|
/* move to next packet */
|
|
packet->offset += packet->length;
|
|
|
|
/* try to read new header */
|
|
if (!read_packet_header (packet))
|
|
goto end;
|
|
|
|
return TRUE;
|
|
|
|
/* ERRORS */
|
|
end:
|
|
{
|
|
packet->type = GST_RDT_TYPE_INVALID;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
GstRDTType
|
|
gst_rdt_packet_get_type (GstRDTPacket * packet)
|
|
{
|
|
g_return_val_if_fail (packet != NULL, GST_RDT_TYPE_INVALID);
|
|
g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID,
|
|
GST_RDT_TYPE_INVALID);
|
|
|
|
return packet->type;
|
|
}
|
|
|
|
guint16
|
|
gst_rdt_packet_get_length (GstRDTPacket * packet)
|
|
{
|
|
g_return_val_if_fail (packet != NULL, 0);
|
|
g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, 0);
|
|
|
|
return packet->length;
|
|
}
|
|
|
|
GstBuffer *
|
|
gst_rdt_packet_to_buffer (GstRDTPacket * packet)
|
|
{
|
|
GstBuffer *result;
|
|
|
|
g_return_val_if_fail (packet != NULL, NULL);
|
|
g_return_val_if_fail (packet->type != GST_RDT_TYPE_INVALID, NULL);
|
|
|
|
result =
|
|
gst_buffer_copy_region (packet->buffer, GST_BUFFER_COPY_ALL,
|
|
packet->offset, packet->length);
|
|
/* timestamp applies to all packets in this buffer */
|
|
GST_BUFFER_TIMESTAMP (result) = GST_BUFFER_TIMESTAMP (packet->buffer);
|
|
|
|
return result;
|
|
}
|
|
|
|
gint
|
|
gst_rdt_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2)
|
|
{
|
|
return (gint16) (seqnum2 - seqnum1);
|
|
}
|
|
|
|
guint16
|
|
gst_rdt_packet_data_get_seq (GstRDTPacket * packet)
|
|
{
|
|
GstMapInfo map;
|
|
guint header;
|
|
guint16 result;
|
|
|
|
g_return_val_if_fail (packet != NULL, FALSE);
|
|
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), FALSE);
|
|
|
|
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
|
|
|
/* skip header bits */
|
|
header = packet->offset + 1;
|
|
|
|
/* read seq_no */
|
|
result = GST_READ_UINT16_BE (&map.data[header]);
|
|
|
|
gst_buffer_unmap (packet->buffer, &map);
|
|
|
|
return result;
|
|
}
|
|
|
|
guint8 *
|
|
gst_rdt_packet_data_map (GstRDTPacket * packet, guint * size)
|
|
{
|
|
GstMapInfo map;
|
|
guint header;
|
|
gboolean length_included_flag;
|
|
gboolean need_reliable_flag;
|
|
guint8 stream_id;
|
|
guint8 asm_rule_number;
|
|
|
|
g_return_val_if_fail (packet != NULL, NULL);
|
|
g_return_val_if_fail (packet->map.data == NULL, NULL);
|
|
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), NULL);
|
|
|
|
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
|
|
|
header = packet->offset;
|
|
|
|
length_included_flag = (map.data[header] & 0x80) == 0x80;
|
|
need_reliable_flag = (map.data[header] & 0x40) == 0x40;
|
|
stream_id = (map.data[header] & 0x3e) >> 1;
|
|
|
|
/* skip seq_no and header bits */
|
|
header += 3;
|
|
|
|
if (length_included_flag) {
|
|
/* skip length */
|
|
header += 2;
|
|
}
|
|
asm_rule_number = (map.data[header] & 0x3f);
|
|
|
|
/* skip timestamp and asm_rule_number */
|
|
header += 5;
|
|
|
|
if (stream_id == 0x1f) {
|
|
/* skip stream_id_expansion */
|
|
header += 2;
|
|
}
|
|
if (need_reliable_flag) {
|
|
/* skip total_reliable */
|
|
header += 2;
|
|
}
|
|
if (asm_rule_number == 63) {
|
|
/* skip asm_rule_number_expansion */
|
|
header += 2;
|
|
}
|
|
|
|
if (size)
|
|
*size = packet->length - (header - packet->offset);
|
|
|
|
packet->map = map;
|
|
|
|
return &map.data[header];
|
|
}
|
|
|
|
gboolean
|
|
gst_rdt_packet_data_unmap (GstRDTPacket * packet)
|
|
{
|
|
g_return_val_if_fail (packet != NULL, FALSE);
|
|
g_return_val_if_fail (packet->map.data != NULL, FALSE);
|
|
|
|
gst_buffer_unmap (packet->buffer, &packet->map);
|
|
packet->map.data = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
guint16
|
|
gst_rdt_packet_data_get_stream_id (GstRDTPacket * packet)
|
|
{
|
|
GstMapInfo map;
|
|
guint16 result;
|
|
guint header;
|
|
gboolean length_included_flag;
|
|
|
|
g_return_val_if_fail (packet != NULL, 0);
|
|
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0);
|
|
|
|
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
|
|
|
header = packet->offset;
|
|
|
|
length_included_flag = (map.data[header] & 0x80) == 0x80;
|
|
result = (map.data[header] & 0x3e) >> 1;
|
|
if (result == 31) {
|
|
/* skip seq_no and header bits */
|
|
header += 3;
|
|
|
|
if (length_included_flag) {
|
|
/* skip length */
|
|
header += 2;
|
|
}
|
|
/* skip asm_rule_number and timestamp */
|
|
header += 5;
|
|
|
|
/* stream_id_expansion */
|
|
result = GST_READ_UINT16_BE (&map.data[header]);
|
|
}
|
|
gst_buffer_unmap (packet->buffer, &map);
|
|
|
|
return result;
|
|
}
|
|
|
|
guint32
|
|
gst_rdt_packet_data_get_timestamp (GstRDTPacket * packet)
|
|
{
|
|
GstMapInfo map;
|
|
guint header;
|
|
gboolean length_included_flag;
|
|
guint32 result;
|
|
|
|
g_return_val_if_fail (packet != NULL, 0);
|
|
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0);
|
|
|
|
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
|
|
|
header = packet->offset;
|
|
|
|
length_included_flag = (map.data[header] & 0x80) == 0x80;
|
|
|
|
/* skip seq_no and header bits */
|
|
header += 3;
|
|
|
|
if (length_included_flag) {
|
|
/* skip length */
|
|
header += 2;
|
|
}
|
|
/* skip asm_rule_number */
|
|
header += 1;
|
|
|
|
/* get timestamp */
|
|
result = GST_READ_UINT32_BE (&map.data[header]);
|
|
gst_buffer_unmap (packet->buffer, &map);
|
|
|
|
return result;
|
|
}
|
|
|
|
guint8
|
|
gst_rdt_packet_data_get_flags (GstRDTPacket * packet)
|
|
{
|
|
GstMapInfo map;
|
|
guint8 result;
|
|
guint header;
|
|
gboolean length_included_flag;
|
|
|
|
g_return_val_if_fail (packet != NULL, 0);
|
|
g_return_val_if_fail (GST_RDT_IS_DATA_TYPE (packet->type), 0);
|
|
|
|
gst_buffer_map (packet->buffer, &map, GST_MAP_READ);
|
|
|
|
header = packet->offset;
|
|
|
|
length_included_flag = (map.data[header] & 0x80) == 0x80;
|
|
|
|
/* skip seq_no and header bits */
|
|
header += 3;
|
|
|
|
if (length_included_flag) {
|
|
/* skip length */
|
|
header += 2;
|
|
}
|
|
/* get flags */
|
|
result = map.data[header];
|
|
gst_buffer_unmap (packet->buffer, &map);
|
|
|
|
return result;
|
|
}
|