tests/onvif: improve robustness

The previous iteration of the code was inferring the type of the
frame by looking at the overall size of the gst-payloaded packet.

It is more robust to actually parse the payload and look at the
actual data buffers it contains.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2303>
This commit is contained in:
Mathieu Duponchelle 2022-04-27 01:13:11 +02:00 committed by GStreamer Marge Bot
parent 9689693534
commit 4cd3830bc8

View file

@ -154,8 +154,8 @@ test_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
duration =
MAX (duration * 10,
duration * ROUND_UP_TO_10 (src->trickmode_interval));
} else if ((src->segment->
flags & GST_SEGMENT_FLAG_TRICKMODE_FORWARD_PREDICTED)) {
} else if ((src->
segment->flags & GST_SEGMENT_FLAG_TRICKMODE_FORWARD_PREDICTED)) {
duration *= 5;
}
@ -571,6 +571,219 @@ typedef struct
#define EXTENSION_ID 0xABAC
#define EXTENSION_SIZE 3
static gboolean
read_length (guint8 * data, guint size, guint * length, guint * skip)
{
guint b, len, offset;
/* start reading the length, we need this to skip to the data later */
len = offset = 0;
do {
if (offset >= size)
return FALSE;
b = data[offset++];
len = (len << 7) | (b & 0x7f);
} while (b & 0x80);
/* check remaining buffer size */
if (size - offset < len)
return FALSE;
*length = len;
*skip = offset;
return TRUE;
}
static GstCaps *
read_caps (GstBuffer * buf, guint * skip)
{
guint offset, length;
GstCaps *caps;
GstMapInfo map;
gst_buffer_map (buf, &map, GST_MAP_READ);
if (!read_length (map.data, map.size, &length, &offset))
goto too_small;
if (length == 0 || map.data[offset + length - 1] != '\0')
goto invalid_buffer;
/* parse and store in cache */
caps = gst_caps_from_string ((gchar *) & map.data[offset]);
gst_buffer_unmap (buf, &map);
*skip = length + offset;
return caps;
too_small:
{
gst_buffer_unmap (buf, &map);
return NULL;
}
invalid_buffer:
{
gst_buffer_unmap (buf, &map);
return NULL;
}
}
static GstEvent *
read_event (guint type, GstBuffer * buf, guint * skip)
{
guint offset, length;
GstStructure *s;
GstEvent *event;
GstEventType etype;
gchar *end;
GstMapInfo map;
gst_buffer_map (buf, &map, GST_MAP_READ);
if (!read_length (map.data, map.size, &length, &offset))
goto too_small;
if (length == 0)
goto invalid_buffer;
/* backward compat, old payloader did not put 0-byte at the end */
if (map.data[offset + length - 1] != '\0'
&& map.data[offset + length - 1] != ';')
goto invalid_buffer;
/* parse */
s = gst_structure_from_string ((gchar *) & map.data[offset], &end);
gst_buffer_unmap (buf, &map);
if (s == NULL)
goto parse_failed;
switch (type) {
case 1:
etype = GST_EVENT_TAG;
break;
case 2:
etype = GST_EVENT_CUSTOM_DOWNSTREAM;
break;
case 3:
etype = GST_EVENT_CUSTOM_BOTH;
break;
case 4:
etype = GST_EVENT_STREAM_START;
break;
default:
goto unknown_event;
}
event = gst_event_new_custom (etype, s);
*skip = length + offset;
return event;
too_small:
{
gst_buffer_unmap (buf, &map);
return NULL;
}
invalid_buffer:
{
gst_buffer_unmap (buf, &map);
return NULL;
}
parse_failed:
{
return NULL;
}
unknown_event:
{
gst_structure_free (s);
return NULL;
}
}
static gboolean
parse_gstpay_payload (GstRTPBuffer * rtp, GstEvent ** event, GstCaps ** caps,
GstBuffer ** outbuf)
{
gint payload_len;
guint8 *payload;
guint avail, offset;
payload_len = gst_rtp_buffer_get_payload_len (rtp);
if (payload_len <= 8)
goto empty_packet;
/* We don't need to deal with fragmentation */
fail_unless (gst_rtp_buffer_get_marker (rtp));
payload = gst_rtp_buffer_get_payload (rtp);
*outbuf = gst_rtp_buffer_get_payload_subbuffer (rtp, 8, -1);
avail = gst_buffer_get_size (*outbuf);
offset = 0;
if (payload[0] & 0x80) {
guint size;
/* C bit, we have inline caps */
*caps = read_caps (*outbuf, &size);
if (*caps == NULL)
goto no_caps;
/* skip caps */
offset += size;
avail -= size;
}
if (payload[1]) {
guint size;
/* we have an event */
*event = read_event (payload[1], *outbuf, &size);
if (*event == NULL)
goto no_event;
/* no buffer after event */
avail = 0;
}
if (avail) {
if (offset != 0) {
GstBuffer *temp;
temp =
gst_buffer_copy_region (*outbuf, GST_BUFFER_COPY_ALL, offset, avail);
gst_buffer_unref (*outbuf);
*outbuf = temp;
}
if (payload[0] & 0x8)
GST_BUFFER_FLAG_SET (*outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
} else {
gst_buffer_unref (*outbuf);
*outbuf = NULL;
}
return TRUE;
empty_packet:
return FALSE;
no_caps:
{
gst_buffer_unref (*outbuf);
return FALSE;
}
no_event:
{
gst_buffer_unref (*outbuf);
return FALSE;
}
}
static gboolean
test_play_response_200_and_check_data (GstRTSPClient * client,
GstRTSPMessage * response, gboolean close, gpointer user_data)
@ -600,37 +813,55 @@ test_play_response_200_and_check_data (GstRTSPClient * client,
guint16 bits;
guint wordlen;
guint8 flags;
gint32 expected_interval;
gboolean is_custom_event = FALSE;
gint32 expected_interval = 0;
GstBuffer *outbuf = NULL;
GstCaps *outcaps = NULL;
GstEvent *outevent = NULL;
fail_unless (gst_rtsp_message_get_body (response, &body,
&body_size) == GST_RTSP_OK);
buf = gst_rtp_buffer_new_copy_data (body, body_size);
switch (body_size) {
case 120: /* Ignore our serialized custom events */
is_custom_event = TRUE;
break;
case 56:
expected_interval = check->expected_i_frame_ts_interval;
check->n_i_frames += 1;
break;
case 46:
expected_interval = check->expected_ts_interval;
check->n_p_frames += 1;
break;
case 41:
expected_interval = check->expected_ts_interval;
check->n_b_frames += 1;
break;
default:
fail ("Invalid body size %u", body_size);
fail_unless (gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp));
fail_unless (parse_gstpay_payload (&rtp, &outevent, &outcaps, &outbuf));
if (outbuf) {
switch (gst_buffer_get_size (outbuf)) {
case 20:
expected_interval = check->expected_i_frame_ts_interval;
check->n_i_frames += 1;
break;
case 10:
expected_interval = check->expected_ts_interval;
check->n_p_frames += 1;
break;
case 5:
expected_interval = check->expected_ts_interval;
check->n_b_frames += 1;
break;
default:
fail ("Invalid payload size %u", gst_buffer_get_size (outbuf));
}
gst_buffer_unref (outbuf);
}
if (!is_custom_event) {
fail_unless (gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp));
if (outcaps) {
gst_caps_unref (outcaps);
}
if (outevent) {
const GstStructure *s;
fail_unless (GST_EVENT_TYPE (outevent) == GST_EVENT_CUSTOM_DOWNSTREAM);
s = gst_event_get_structure (outevent);
fail_unless (gst_structure_has_name (s, "GstOnvifTimestamp"));
gst_event_unref (outevent);
}
if (expected_interval) {
if (check->previous_ts) {
fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp) -
check->previous_ts, expected_interval);
@ -646,8 +877,6 @@ test_play_response_200_and_check_data (GstRTSPClient * client,
flags = GST_READ_UINT8 (data + 8);
gst_rtp_buffer_unmap (&rtp);
if (flags & (1 << 7)) {
check->n_clean_points += 1;
}
@ -669,6 +898,7 @@ test_play_response_200_and_check_data (GstRTSPClient * client,
}
}
gst_rtp_buffer_unmap (&rtp);
gst_buffer_unref (buf);
} else if (channel == 1) { /* RTCP */
GstBuffer *buf;