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;
}
#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)
{
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);
flags = GST_READ_UINT8 (data + 8);
- gst_rtp_buffer_unmap (&rtp);
-
if (flags & (1 << 7)) {
check->n_clean_points += 1;
}
}
}
+ gst_rtp_buffer_unmap (&rtp);
gst_buffer_unref (buf);
} else if (channel == 1) { /* RTCP */
GstBuffer *buf;