mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-10 03:19:40 +00:00
d5ad50bd61
We expose a set of new elements: * ULPFEC encoder / decoder * A storage element, which should be placed before jitterbuffers, and is used to store packets in order to attempt reconstruction after the jitterbuffer has sent PacketLost events * RED encoder / decoder (RFC 2198), these are necessary to use FEC in webrtc, as browsers will propose and expect ulpfec packets to be wrapped in red packets With contributions from: Mathieu Duponchelle <mathieu@centricular.com> Sebastian Dröge <sebastian@centricular.com> https://bugzilla.gnome.org/show_bug.cgi?id=792696
839 lines
32 KiB
C
839 lines
32 KiB
C
/* GStreamer plugin for forward error correction
|
|
* Copyright (C) 2017 Pexip
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Author: Mikhail Fludkov <misha@pexip.com>
|
|
*/
|
|
|
|
#include <gst/check/gstharness.h>
|
|
#include <gst/rtp/gstrtpbuffer.h>
|
|
#include <gst/check/gstcheck.h>
|
|
|
|
#define PT_RED 100
|
|
#define PT_MEDIA 96
|
|
#define CLOCKRATE 8000
|
|
#define TIMESTAMP_BASE (1000)
|
|
#define TIMESTAMP_DIFF (40 * CLOCKRATE / 1000)
|
|
#define TIMESTAMP_NTH(i) (TIMESTAMP_BASE + (i) * TIMESTAMP_DIFF)
|
|
#define xstr(s) str(s)
|
|
#define str(s) #s
|
|
#define GST_RTP_RED_ENC_CAPS_STR "application/x-rtp, payload=" xstr(PT_MEDIA)
|
|
|
|
#define _check_red_received(h, expected) \
|
|
G_STMT_START { \
|
|
guint received; \
|
|
g_object_get ((h)->element, "received", &received, NULL);\
|
|
fail_unless_equals_int (expected, received); \
|
|
} G_STMT_END
|
|
|
|
#define _check_red_sent(h, expected) \
|
|
G_STMT_START { \
|
|
guint sent; \
|
|
g_object_get ((h)->element, "sent", &sent, NULL);\
|
|
fail_unless_equals_int (expected, sent); \
|
|
} G_STMT_END
|
|
|
|
#define _check_caps(_h_, _nth_, _expected_payload_) \
|
|
G_STMT_START { \
|
|
GstEvent *_ev_; \
|
|
gint _pt_ = -1; \
|
|
GstCaps *_caps_ = NULL; \
|
|
\
|
|
for (gint _i_ = 0; _i_ < _nth_; ++_i_) \
|
|
gst_event_unref (gst_harness_pull_event (_h_)); \
|
|
\
|
|
_ev_ = gst_harness_pull_event (_h_); \
|
|
fail_unless (NULL != _ev_); \
|
|
fail_unless_equals_string ("caps", GST_EVENT_TYPE_NAME(_ev_));\
|
|
\
|
|
gst_event_parse_caps (_ev_, &_caps_); \
|
|
\
|
|
gst_structure_get_int ( \
|
|
gst_caps_get_structure (_caps_, 0), "payload", &_pt_); \
|
|
fail_unless_equals_int (_expected_payload_, _pt_); \
|
|
gst_event_unref (_ev_); \
|
|
} G_STMT_END
|
|
|
|
#define _check_nocaps(_h_) \
|
|
G_STMT_START { \
|
|
GstEvent *_ev_; \
|
|
while (NULL != (_ev_ = gst_harness_try_pull_event (_h_))) {\
|
|
fail_unless (GST_EVENT_TYPE (_ev_) != GST_EVENT_CAPS, \
|
|
"Don't expect to receive caps event"); \
|
|
gst_event_unref (_ev_); \
|
|
} \
|
|
} G_STMT_END
|
|
|
|
static GstBuffer *
|
|
_new_rtp_buffer (gboolean marker, guint8 csrc_count, guint8 pt, guint16 seqnum,
|
|
guint32 timestamp, guint32 ssrc, guint payload_len)
|
|
{
|
|
GstBuffer *buf = gst_rtp_buffer_new_allocate (payload_len, 0, csrc_count);
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
|
|
fail_unless (gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp));
|
|
gst_rtp_buffer_set_marker (&rtp, marker);
|
|
gst_rtp_buffer_set_payload_type (&rtp, pt);
|
|
gst_rtp_buffer_set_seq (&rtp, seqnum);
|
|
gst_rtp_buffer_set_timestamp (&rtp, timestamp);
|
|
gst_rtp_buffer_set_ssrc (&rtp, ssrc);
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
|
|
return buf;
|
|
}
|
|
|
|
GST_START_TEST (rtpreddec_passthrough)
|
|
{
|
|
GstBuffer *bufinp, *bufout;
|
|
GstHarness *h = gst_harness_new ("rtpreddec");
|
|
gst_harness_set_src_caps_str (h, "application/x-rtp");
|
|
|
|
/* Passthrough when pt is not set */
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 0, TIMESTAMP_NTH (0), 0xabe2b0b, 0);
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
fail_unless (bufout == bufinp);
|
|
fail_unless (gst_buffer_is_writable (bufout));
|
|
gst_buffer_unref (bufout);
|
|
|
|
/* Now pt is set */
|
|
g_object_set (h->element, "pt", PT_RED, NULL);
|
|
|
|
/* Passthrough when not RED. RED pt = 100, pushing pt 99 */
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_MEDIA, 1, TIMESTAMP_NTH (1), 0xabe2b0b, 0);
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
fail_unless (bufout == bufinp);
|
|
fail_unless (gst_buffer_is_writable (bufout));
|
|
gst_buffer_unref (bufout);
|
|
|
|
/* Passthrough when not RTP buffer */
|
|
bufinp = gst_buffer_new_wrapped (g_strdup ("hello"), 5);
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
fail_unless (bufout == bufinp);
|
|
fail_unless (gst_buffer_is_writable (bufout));
|
|
gst_buffer_unref (bufout);
|
|
|
|
_check_red_received (h, 0);
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (rtpreddec_main_block)
|
|
{
|
|
GstHarness *h = gst_harness_new ("rtpreddec");
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
guint8 out_data[] = { 0xa, 0xa, 0xa, 0xa, 0xa };
|
|
guint8 red_in[] = { PT_MEDIA, 0xa, 0xa, 0xa, 0xa, 0xa };
|
|
guint gst_ts = 3454679;
|
|
guint csrc_count = 2;
|
|
guint seq = 549;
|
|
GstBuffer *bufinp, *bufout;
|
|
guint bufinp_flags;
|
|
|
|
g_object_set (h->element, "pt", PT_RED, NULL);
|
|
gst_harness_set_src_caps_str (h, "application/x-rtp");
|
|
|
|
/* RED buffer has Marker bit set, has CSRCS and flags */
|
|
bufinp =
|
|
_new_rtp_buffer (TRUE, csrc_count, PT_RED, seq, TIMESTAMP_NTH (0),
|
|
0xabe2b0b, sizeof (red_in));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &red_in, sizeof (red_in));
|
|
gst_rtp_buffer_set_csrc (&rtp, 0, 0x1abe2b0b);
|
|
gst_rtp_buffer_set_csrc (&rtp, 1, 0x2abe2b0b);
|
|
GST_BUFFER_TIMESTAMP (bufinp) = gst_ts;
|
|
GST_BUFFER_FLAG_SET (bufinp, GST_RTP_BUFFER_FLAG_RETRANSMISSION);
|
|
GST_BUFFER_FLAG_SET (bufinp, GST_BUFFER_FLAG_DISCONT);
|
|
bufinp_flags = GST_BUFFER_FLAGS (bufinp);
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
|
|
/* Checking that pulled buffer has keeps everything from RED buffer */
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
fail_unless (gst_rtp_buffer_map (bufout, GST_MAP_READ, &rtp));
|
|
fail_unless_equals_int (GST_BUFFER_TIMESTAMP (bufout), gst_ts);
|
|
fail_unless_equals_int (GST_BUFFER_FLAGS (bufout), bufinp_flags);
|
|
fail_unless_equals_int (gst_buffer_get_size (bufout),
|
|
gst_rtp_buffer_calc_packet_len (sizeof (out_data), 0, csrc_count));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp),
|
|
TIMESTAMP_NTH (0));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), PT_MEDIA);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp), seq);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp), csrc_count);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), 0x0abe2b0b);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_csrc (&rtp, 0), 0x1abe2b0b);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_csrc (&rtp, 1), 0x2abe2b0b);
|
|
fail_unless (gst_rtp_buffer_get_marker (&rtp));
|
|
fail_unless (!memcmp (gst_rtp_buffer_get_payload (&rtp), out_data,
|
|
sizeof (out_data)));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
gst_buffer_unref (bufout);
|
|
|
|
_check_red_received (h, 1);
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static void
|
|
_push_and_check_didnt_go_through (GstHarness * h, GstBuffer * bufinp)
|
|
{
|
|
gst_harness_push (h, bufinp);
|
|
/* Making sure it didn't go through */
|
|
fail_unless_equals_int (gst_harness_buffers_received (h), 0);
|
|
}
|
|
|
|
static void
|
|
_push_and_check_cant_pull_twice (GstHarness * h,
|
|
GstBuffer * bufinp, guint buffers_received)
|
|
{
|
|
gst_buffer_unref (gst_harness_push_and_pull (h, bufinp));
|
|
/* Making sure only one buffer was pushed through */
|
|
fail_unless_equals_int (gst_harness_buffers_received (h), buffers_received);
|
|
}
|
|
|
|
static void
|
|
_push_and_check_redundant_packet (GstHarness * h, GstBuffer * bufinp,
|
|
guint seq, guint timestamp, guint payload_len, gconstpointer payload)
|
|
{
|
|
GstBuffer *bufout = gst_harness_push_and_pull (h, bufinp);
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
|
|
fail_unless (gst_rtp_buffer_map (bufout, GST_MAP_READ, &rtp));
|
|
fail_unless (GST_BUFFER_FLAG_IS_SET (bufout, GST_RTP_BUFFER_FLAG_REDUNDANT));
|
|
fail_unless_equals_int (gst_buffer_get_size (bufout),
|
|
gst_rtp_buffer_calc_packet_len (payload_len, 0, 0));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp), timestamp);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), PT_MEDIA);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp), seq);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), 0x0abe2b0b);
|
|
fail_unless (!memcmp (gst_rtp_buffer_get_payload (&rtp), payload,
|
|
payload_len));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
gst_buffer_unref (bufout);
|
|
gst_buffer_unref (gst_harness_pull (h));
|
|
}
|
|
|
|
GST_START_TEST (rtpreddec_redundant_block_not_pushed)
|
|
{
|
|
GstHarness *h = gst_harness_new ("rtpreddec");
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
|
|
/* Redundant block has valid tsoffset but we have not seen any buffers before */
|
|
guint16 ts_offset = TIMESTAMP_DIFF;
|
|
guint8 red_in[] = {
|
|
0x80 | PT_MEDIA,
|
|
(guint8) (ts_offset >> 6),
|
|
(guint8) (ts_offset & 0x3f) << 2, 1, /* Redundant block size = 1 */
|
|
PT_MEDIA, 0xa, 0xa /* Main block size = 1 */
|
|
};
|
|
GstBuffer *bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 2, TIMESTAMP_NTH (2), 0xabe2b0b,
|
|
sizeof (red_in));
|
|
|
|
g_object_set (h->element, "pt", PT_RED, NULL);
|
|
gst_harness_set_src_caps_str (h, "application/x-rtp");
|
|
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &red_in, sizeof (red_in));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_cant_pull_twice (h, bufinp, 1);
|
|
|
|
/* Redundant block has too large tsoffset */
|
|
ts_offset = TIMESTAMP_DIFF * 4;
|
|
red_in[1] = ts_offset >> 6;
|
|
red_in[2] = (ts_offset & 0x3f) << 2;
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 3, TIMESTAMP_NTH (3), 0xabe2b0b,
|
|
sizeof (red_in));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &red_in, sizeof (red_in));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_cant_pull_twice (h, bufinp, 2);
|
|
|
|
/* TS offset is too small */
|
|
ts_offset = TIMESTAMP_DIFF / 2;
|
|
red_in[1] = ts_offset >> 6;
|
|
red_in[2] = (ts_offset & 0x3f) << 2;
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 4, TIMESTAMP_NTH (4), 0xabe2b0b,
|
|
sizeof (red_in));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &red_in, sizeof (red_in));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_cant_pull_twice (h, bufinp, 3);
|
|
|
|
/* Now we ts_offset points to the previous buffer we didnt loose */
|
|
ts_offset = TIMESTAMP_DIFF;
|
|
red_in[1] = ts_offset >> 6;
|
|
red_in[2] = (ts_offset & 0x3f) << 2;
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 5, TIMESTAMP_NTH (5), 0xabe2b0b,
|
|
sizeof (red_in));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &red_in, sizeof (red_in));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_cant_pull_twice (h, bufinp, 4);
|
|
|
|
_check_red_received (h, 4);
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (rtpreddec_redundant_block_pushed)
|
|
{
|
|
GstHarness *h = gst_harness_new ("rtpreddec");
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
guint16 ts_offset = TIMESTAMP_DIFF;
|
|
guint8 red_in[] = {
|
|
0x80 | PT_MEDIA,
|
|
(guint8) (ts_offset >> 6),
|
|
(guint8) (ts_offset & 0x3f) << 2, 5, /* Redundant block size = 5 */
|
|
PT_MEDIA, 0x01, 0x02, 0x03, 0x4, 0x5, 0xa /* Main block size = 1 */
|
|
};
|
|
GstBuffer *bufinp;
|
|
|
|
g_object_set (h->element, "pt", PT_RED, NULL);
|
|
gst_harness_set_src_caps_str (h, "application/x-rtp");
|
|
|
|
/* Pushing seq=0 */
|
|
gst_buffer_unref (gst_harness_push_and_pull (h, _new_rtp_buffer (FALSE, 0,
|
|
PT_MEDIA, 0, TIMESTAMP_NTH (0), 0xabe2b0b, 0)));
|
|
|
|
/* Pushing seq=2, recovering seq=1 (fec distance 1) */
|
|
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 2, TIMESTAMP_NTH (2), 0xabe2b0b,
|
|
sizeof (red_in));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &red_in, sizeof (red_in));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_redundant_packet (h, bufinp, 1, TIMESTAMP_NTH (1), 5,
|
|
red_in + 5);
|
|
|
|
/* Pushing seq=5, recovering seq=3 (fec distance 2) */
|
|
ts_offset = TIMESTAMP_DIFF * 2;
|
|
red_in[1] = ts_offset >> 6;
|
|
red_in[2] = (ts_offset & 0x3f) << 2;
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 5, TIMESTAMP_NTH (5), 0xabe2b0b,
|
|
sizeof (red_in));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &red_in, sizeof (red_in));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_redundant_packet (h, bufinp, 3, TIMESTAMP_NTH (3), 5,
|
|
red_in + 5);
|
|
|
|
/* Pushing seq=9, recovering seq=6 (fec distance 3) */
|
|
ts_offset = TIMESTAMP_DIFF * 3;
|
|
red_in[1] = ts_offset >> 6;
|
|
red_in[2] = (ts_offset & 0x3f) << 2;
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 9, TIMESTAMP_NTH (9), 0xabe2b0b,
|
|
sizeof (red_in));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &red_in, sizeof (red_in));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_redundant_packet (h, bufinp, 6, TIMESTAMP_NTH (6), 5,
|
|
red_in + 5);
|
|
|
|
/* Pushing seq=14, recovering seq=10 (fec distance 4) */
|
|
ts_offset = TIMESTAMP_DIFF * 4;
|
|
red_in[1] = ts_offset >> 6;
|
|
red_in[2] = (ts_offset & 0x3f) << 2;
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 14, TIMESTAMP_NTH (14), 0xabe2b0b,
|
|
sizeof (red_in));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &red_in, sizeof (red_in));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_redundant_packet (h, bufinp, 10, TIMESTAMP_NTH (10), 5,
|
|
red_in + 5);
|
|
|
|
_check_red_received (h, 4);
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (rtpreddec_invalid)
|
|
{
|
|
GstBuffer *bufinp;
|
|
GstHarness *h = gst_harness_new ("rtpreddec");
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
/* 2 block RED packets should have at least 4 bytes for redundant block
|
|
* header and 1 byte for the main block header. */
|
|
guint8 data[] = {
|
|
0x80 | PT_MEDIA, 0, 0, 1, /* 1st block header (redundant block) size=1, timestmapoffset=0 */
|
|
PT_MEDIA, /* 2nd block header (main block) size=0 */
|
|
};
|
|
|
|
g_object_set (h->element, "pt", PT_RED, NULL);
|
|
gst_harness_set_src_caps_str (h, "application/x-rtp");
|
|
|
|
/* Single block RED packets should have at least 1 byte of payload to be
|
|
* considered valid. This buffer does not have any payload */
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 0, TIMESTAMP_NTH (0), 0xabe2b0b, 0);
|
|
_push_and_check_didnt_go_through (h, bufinp);
|
|
|
|
/* Only the first byte with F bit set (indication of redundant block) */
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 1, TIMESTAMP_NTH (1), 0xabe2b0b, 1);
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &data, sizeof (data));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_didnt_go_through (h, bufinp);
|
|
|
|
/* Full 1st block header only */
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 2, TIMESTAMP_NTH (2), 0xabe2b0b, 4);
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &data, sizeof (data));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_didnt_go_through (h, bufinp);
|
|
|
|
/* Both blocks, missing 1 byte of payload for redundant block */
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_RED, 3, TIMESTAMP_NTH (3), 0xabe2b0b, 5);
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &data, sizeof (data));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
_push_and_check_didnt_go_through (h, bufinp);
|
|
|
|
_check_red_received (h, 4);
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (rtpredenc_passthrough)
|
|
{
|
|
GstBuffer *bufinp, *bufout;
|
|
GstHarness *h = gst_harness_new ("rtpredenc");
|
|
gst_harness_set_src_caps_str (h, GST_RTP_RED_ENC_CAPS_STR);
|
|
|
|
/* Passthrough by default */
|
|
bufinp =
|
|
_new_rtp_buffer (FALSE, 0, PT_MEDIA, 0, TIMESTAMP_NTH (0), 0xabe2b0b, 0);
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
|
|
_check_caps (h, 1, PT_MEDIA);
|
|
fail_unless (bufout == bufinp);
|
|
fail_unless (gst_buffer_is_writable (bufout));
|
|
gst_buffer_unref (bufout);
|
|
|
|
/* Setting pt and allowing RED packets without redundant blocks */
|
|
g_object_set (h->element, "pt", PT_RED, "allow-no-red-blocks", TRUE, NULL);
|
|
|
|
/* Passthrough when not RTP buffer */
|
|
bufinp = gst_buffer_new_wrapped (g_strdup ("hello"), 5);
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
|
|
_check_nocaps (h);
|
|
fail_unless (bufout == bufinp);
|
|
fail_unless (gst_buffer_is_writable (bufout));
|
|
gst_buffer_unref (bufout);
|
|
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (rtpredenc_payloadless_rtp)
|
|
{
|
|
GstHarness *h = gst_harness_new ("rtpredenc");
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
guint8 out_data[] = { PT_MEDIA };
|
|
GstBuffer *bufout;
|
|
|
|
g_object_set (h->element, "pt", PT_RED, "allow-no-red-blocks", TRUE, NULL);
|
|
gst_harness_set_src_caps_str (h, GST_RTP_RED_ENC_CAPS_STR);
|
|
|
|
bufout =
|
|
gst_harness_push_and_pull (h, _new_rtp_buffer (TRUE, 0, PT_MEDIA, 0,
|
|
TIMESTAMP_NTH (0), 0xabe2b0b, 0));
|
|
|
|
_check_caps (h, 1, PT_RED);
|
|
fail_unless (gst_rtp_buffer_map (bufout, GST_MAP_READ, &rtp));
|
|
fail_unless_equals_int (gst_buffer_get_size (bufout),
|
|
gst_rtp_buffer_calc_packet_len (sizeof (out_data), 0, 0));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp),
|
|
TIMESTAMP_NTH (0));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), PT_RED);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp), 0);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp), 0);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), 0x0abe2b0b);
|
|
fail_unless (gst_rtp_buffer_get_marker (&rtp));
|
|
fail_unless (!memcmp (gst_rtp_buffer_get_payload (&rtp), out_data,
|
|
sizeof (out_data)));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
gst_buffer_unref (bufout);
|
|
|
|
_check_red_sent (h, 1);
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (rtpredenc_without_redundant_block)
|
|
{
|
|
GstHarness *h = gst_harness_new ("rtpredenc");
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
guint8 in_data[] = { 0xa, 0xa, 0xa, 0xa, 0xa };
|
|
guint8 out_data[] = { PT_MEDIA, 0xa, 0xa, 0xa, 0xa, 0xa };
|
|
guint gst_ts = 3454679;
|
|
guint csrc_count = 2;
|
|
guint seq = 549;
|
|
guint bufinp_flags;
|
|
GstBuffer *bufinp, *bufout;
|
|
|
|
g_object_set (h->element, "pt", PT_RED, "allow-no-red-blocks", TRUE, NULL);
|
|
gst_harness_set_src_caps_str (h, GST_RTP_RED_ENC_CAPS_STR);
|
|
|
|
/* Media buffer has Marker bit set, has CSRCS and flags */
|
|
bufinp =
|
|
_new_rtp_buffer (TRUE, csrc_count, PT_MEDIA, seq, TIMESTAMP_NTH (0),
|
|
0xabe2b0b, sizeof (in_data));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data, sizeof (in_data));
|
|
gst_rtp_buffer_set_csrc (&rtp, 0, 0x1abe2b0b);
|
|
gst_rtp_buffer_set_csrc (&rtp, 1, 0x2abe2b0b);
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
GST_BUFFER_TIMESTAMP (bufinp) = gst_ts;
|
|
GST_BUFFER_FLAG_SET (bufinp, GST_RTP_BUFFER_FLAG_RETRANSMISSION);
|
|
GST_BUFFER_FLAG_SET (bufinp, GST_BUFFER_FLAG_DISCONT);
|
|
bufinp_flags = GST_BUFFER_FLAGS (bufinp);
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
|
|
/* Checking that pulled buffer has keeps everything from Media buffer */
|
|
_check_caps (h, 1, PT_RED);
|
|
fail_unless (gst_rtp_buffer_map (bufout, GST_MAP_READ, &rtp));
|
|
fail_unless_equals_int (GST_BUFFER_TIMESTAMP (bufout), gst_ts);
|
|
fail_unless_equals_int (GST_BUFFER_FLAGS (bufout), bufinp_flags);
|
|
fail_unless_equals_int (gst_buffer_get_size (bufout),
|
|
gst_rtp_buffer_calc_packet_len (sizeof (out_data), 0, csrc_count));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp),
|
|
TIMESTAMP_NTH (0));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), PT_RED);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp), seq);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp), csrc_count);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), 0x0abe2b0b);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_csrc (&rtp, 0), 0x1abe2b0b);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_csrc (&rtp, 1), 0x2abe2b0b);
|
|
fail_unless (gst_rtp_buffer_get_marker (&rtp));
|
|
fail_unless (!memcmp (gst_rtp_buffer_get_payload (&rtp), out_data,
|
|
sizeof (out_data)));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
gst_buffer_unref (bufout);
|
|
|
|
_check_red_sent (h, 1);
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (rtpredenc_with_redundant_block)
|
|
{
|
|
GstHarness *h = gst_harness_new ("rtpredenc");
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
guint8 in_data0[] = { 0xa, 0xa, 0xa, 0xa, 0xa };
|
|
guint8 in_data1[] = { 0xb, 0xb, 0xb, 0xb, 0xb };
|
|
guint8 in_data2[] = { 0xc, 0xc, 0xc, 0xc, 0xc };
|
|
guint timestmapoffset0 = TIMESTAMP_NTH (1) - TIMESTAMP_NTH (0);
|
|
guint timestmapoffset1 = TIMESTAMP_NTH (2) - TIMESTAMP_NTH (0);
|
|
guint8 out_data0[] = {
|
|
/* Redundant block header */
|
|
0x80 | PT_MEDIA, /* F=1 | pt=PT_MEDIA */
|
|
timestmapoffset0 >> 6, /* timestamp hi 8 bits */
|
|
timestmapoffset0 & 0x3f, /* timestamp lo 6 bits | length hi = 0 */
|
|
sizeof (in_data0), /* length lo 8 bits */
|
|
/* Main block header */
|
|
PT_MEDIA, /* F=0 | pt=PT_MEDIA */
|
|
/* Redundant block data */
|
|
0xa, 0xa, 0xa, 0xa, 0xa,
|
|
/* Main block data */
|
|
0xb, 0xb, 0xb, 0xb, 0xb
|
|
};
|
|
|
|
guint8 out_data1[] = {
|
|
/* Redundant block header */
|
|
0x80 | PT_MEDIA, /* F=1 | pt=PT_MEDIA */
|
|
timestmapoffset1 >> 6, /* timestamp hi 8 bits */
|
|
timestmapoffset1 & 0x3f, /* timestamp lo 6 bits | length hi = 0 */
|
|
sizeof (in_data0), /* length lo 8 bits */
|
|
/* Main block header */
|
|
PT_MEDIA, /* F=0 | pt=PT_MEDIA */
|
|
/* Redundant block data */
|
|
0xa, 0xa, 0xa, 0xa, 0xa,
|
|
/* Main block data */
|
|
0xc, 0xc, 0xc, 0xc, 0xc
|
|
};
|
|
guint seq = 549;
|
|
GstBuffer *bufinp, *bufout;
|
|
|
|
g_object_set (h->element,
|
|
"pt", PT_RED, "distance", 2, "allow-no-red-blocks", FALSE, NULL);
|
|
gst_harness_set_src_caps_str (h, GST_RTP_RED_ENC_CAPS_STR);
|
|
|
|
bufinp =
|
|
_new_rtp_buffer (TRUE, 0, PT_MEDIA, seq, TIMESTAMP_NTH (0), 0xabe2b0b,
|
|
sizeof (in_data0));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data0, sizeof (in_data0));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
|
|
/* The first buffer should go through,
|
|
* there were no redundant data to create RED packet */
|
|
_check_caps (h, 1, PT_MEDIA);
|
|
fail_unless (bufout == bufinp);
|
|
fail_unless (gst_buffer_is_writable (bufout));
|
|
fail_unless (gst_rtp_buffer_map (bufout, GST_MAP_READ, &rtp));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), PT_MEDIA);
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
gst_buffer_unref (bufout);
|
|
|
|
bufinp =
|
|
_new_rtp_buffer (TRUE, 0, PT_MEDIA, seq + 1, TIMESTAMP_NTH (1), 0xabe2b0b,
|
|
sizeof (in_data1));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data1, sizeof (in_data1));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
|
|
/* The next buffer is RED referencing previous packet */
|
|
_check_caps (h, 1, PT_RED);
|
|
fail_unless (gst_rtp_buffer_map (bufout, GST_MAP_READ, &rtp));
|
|
fail_unless_equals_int (gst_buffer_get_size (bufout),
|
|
gst_rtp_buffer_calc_packet_len (sizeof (out_data0), 0, 0));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp),
|
|
TIMESTAMP_NTH (1));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), PT_RED);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp), seq + 1);
|
|
fail_unless (gst_rtp_buffer_get_marker (&rtp));
|
|
fail_unless (!memcmp (gst_rtp_buffer_get_payload (&rtp), out_data0,
|
|
sizeof (out_data0)));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
gst_buffer_unref (bufout);
|
|
|
|
bufinp =
|
|
_new_rtp_buffer (TRUE, 0, PT_MEDIA, seq + 2, TIMESTAMP_NTH (2), 0xabe2b0b,
|
|
sizeof (in_data2));
|
|
fail_unless (gst_rtp_buffer_map (bufinp, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data2, sizeof (in_data2));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
bufout = gst_harness_push_and_pull (h, bufinp);
|
|
|
|
/* The next buffer is RED referencing the packet before the previous */
|
|
_check_nocaps (h);
|
|
fail_unless (gst_rtp_buffer_map (bufout, GST_MAP_READ, &rtp));
|
|
fail_unless_equals_int (gst_buffer_get_size (bufout),
|
|
gst_rtp_buffer_calc_packet_len (sizeof (out_data1), 0, 0));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_timestamp (&rtp),
|
|
TIMESTAMP_NTH (2));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), PT_RED);
|
|
fail_unless_equals_int (gst_rtp_buffer_get_seq (&rtp), seq + 2);
|
|
fail_unless (gst_rtp_buffer_get_marker (&rtp));
|
|
fail_unless (!memcmp (gst_rtp_buffer_get_payload (&rtp), out_data1,
|
|
sizeof (out_data1)));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
gst_buffer_unref (bufout);
|
|
|
|
_check_red_sent (h, 2);
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static void
|
|
rtpredenc_cant_create_red_packet_base_test (GstBuffer * buffer0,
|
|
GstBuffer * buffer1)
|
|
{
|
|
/* The test configures PexRtpRedEnc to produce RED packets only with redundant
|
|
* blocks. The first packet we pull should not be RED just because it is the
|
|
* very first one. The second should not be RED because it was impossible
|
|
* to create a RED packet for varios reasons:
|
|
* - too large redundant block size
|
|
* - too large timestamp offset
|
|
* - negative timestamp offset */
|
|
GstBuffer *bufout;
|
|
GstHarness *h = gst_harness_new ("rtpredenc");
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
g_object_set (h->element,
|
|
"pt", PT_RED, "distance", 1, "allow-no-red-blocks", FALSE, NULL);
|
|
gst_harness_set_src_caps_str (h, GST_RTP_RED_ENC_CAPS_STR);
|
|
|
|
/* Checking the first pulled buffer is media packet */
|
|
bufout = gst_harness_push_and_pull (h, buffer0);
|
|
_check_caps (h, 1, PT_MEDIA);
|
|
fail_unless (gst_rtp_buffer_map (bufout, GST_MAP_READ, &rtp));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), PT_MEDIA);
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
gst_buffer_unref (bufout);
|
|
|
|
/* The next buffer should be media packet too */
|
|
bufout = gst_harness_push_and_pull (h, buffer1);
|
|
_check_nocaps (h);
|
|
fail_unless (gst_rtp_buffer_map (bufout, GST_MAP_READ, &rtp));
|
|
fail_unless_equals_int (gst_rtp_buffer_get_payload_type (&rtp), PT_MEDIA);
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
gst_buffer_unref (bufout);
|
|
|
|
_check_red_sent (h, 0);
|
|
gst_harness_teardown (h);
|
|
}
|
|
|
|
GST_START_TEST (rtpredenc_negative_timestamp_offset)
|
|
{
|
|
gboolean with_warping;
|
|
guint16 seq0, seq1;
|
|
guint32 timestamp0, timestamp1;
|
|
GstBuffer *buffer0, *buffer1;
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
guint8 in_data[] = { 0xa, 0xa, 0xa, 0xa, 0xa };
|
|
|
|
with_warping = __i__ != 0;
|
|
timestamp0 =
|
|
with_warping ? (0xffffffff - TIMESTAMP_DIFF / 2) : TIMESTAMP_BASE;
|
|
timestamp1 = timestamp0 + TIMESTAMP_DIFF;
|
|
seq0 = with_warping ? 0xffff : 0;
|
|
seq1 = seq0 + 1;
|
|
|
|
/* Two buffers have negative timestamp difference */
|
|
buffer0 =
|
|
_new_rtp_buffer (TRUE, 0, PT_MEDIA, seq0, timestamp1, 0xabe2b0b,
|
|
sizeof (in_data));
|
|
buffer1 =
|
|
_new_rtp_buffer (TRUE, 0, PT_MEDIA, seq1, timestamp0, 0xabe2b0b,
|
|
sizeof (in_data));
|
|
|
|
fail_unless (gst_rtp_buffer_map (buffer0, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data, sizeof (in_data));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
|
|
fail_unless (gst_rtp_buffer_map (buffer1, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data, sizeof (in_data));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
|
|
rtpredenc_cant_create_red_packet_base_test (buffer0, buffer1);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (rtpredenc_too_large_timestamp_offset)
|
|
{
|
|
gboolean with_warping;
|
|
guint16 seq0, seq1;
|
|
guint32 timestamp0, timestamp1, timestamp_diff;
|
|
GstBuffer *buffer0, *buffer1;
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
guint8 in_data[] = { 0xa, 0xa, 0xa, 0xa, 0xa };
|
|
|
|
with_warping = __i__ != 0;
|
|
timestamp_diff = 0x4000;
|
|
timestamp0 =
|
|
with_warping ? (0xffffffff - timestamp_diff / 2) : TIMESTAMP_BASE;
|
|
timestamp1 = timestamp0 + timestamp_diff;
|
|
|
|
seq0 = with_warping ? 0xffff : 0;
|
|
seq1 = seq0 + 1;
|
|
|
|
/* Two buffers have timestamp difference > 14bit long */
|
|
buffer0 =
|
|
_new_rtp_buffer (TRUE, 0, PT_MEDIA, seq0, timestamp0, 0xabe2b0b,
|
|
sizeof (in_data));
|
|
buffer1 =
|
|
_new_rtp_buffer (TRUE, 0, PT_MEDIA, seq1, timestamp1, 0xabe2b0b,
|
|
sizeof (in_data));
|
|
fail_unless (gst_rtp_buffer_map (buffer0, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data, sizeof (in_data));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
|
|
fail_unless (gst_rtp_buffer_map (buffer1, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data, sizeof (in_data));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
|
|
rtpredenc_cant_create_red_packet_base_test (buffer0, buffer1);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
GST_START_TEST (rtpredenc_too_large_length)
|
|
{
|
|
gboolean with_warping;
|
|
guint16 seq0, seq1;
|
|
guint32 timestamp0, timestamp1;
|
|
GstBuffer *buffer0, *buffer1;
|
|
GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
|
|
guint8 in_data0[1024] = { 0, };
|
|
guint8 in_data1[] = { 0xa, 0xa, 0xa, 0xa, 0xa };
|
|
|
|
with_warping = __i__ != 0;
|
|
timestamp0 =
|
|
with_warping ? (0xffffffff - TIMESTAMP_DIFF / 2) : TIMESTAMP_BASE;
|
|
timestamp1 = timestamp0 + TIMESTAMP_DIFF;
|
|
seq0 = with_warping ? 0xffff : 0;
|
|
seq1 = seq0 + 1;
|
|
|
|
/* The first buffer is too large to use as a redundant block */
|
|
buffer0 =
|
|
_new_rtp_buffer (TRUE, 0, PT_MEDIA, seq0, timestamp0, 0xabe2b0b,
|
|
sizeof (in_data0));
|
|
buffer1 =
|
|
_new_rtp_buffer (TRUE, 0, PT_MEDIA, seq1, timestamp1, 0xabe2b0b,
|
|
sizeof (in_data1));
|
|
fail_unless (gst_rtp_buffer_map (buffer0, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data0, sizeof (in_data0));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
|
|
fail_unless (gst_rtp_buffer_map (buffer1, GST_MAP_WRITE, &rtp));
|
|
memcpy (gst_rtp_buffer_get_payload (&rtp), &in_data1, sizeof (in_data1));
|
|
gst_rtp_buffer_unmap (&rtp);
|
|
|
|
rtpredenc_cant_create_red_packet_base_test (buffer0, buffer1);
|
|
}
|
|
|
|
GST_END_TEST;
|
|
|
|
static Suite *
|
|
rtpred_suite (void)
|
|
{
|
|
Suite *s = suite_create ("rtpred");
|
|
TCase *tc_chain = tcase_create ("decoder");
|
|
suite_add_tcase (s, tc_chain);
|
|
tcase_add_test (tc_chain, rtpreddec_passthrough);
|
|
tcase_add_test (tc_chain, rtpreddec_main_block);
|
|
tcase_add_test (tc_chain, rtpreddec_redundant_block_not_pushed);
|
|
tcase_add_test (tc_chain, rtpreddec_redundant_block_pushed);
|
|
tcase_add_test (tc_chain, rtpreddec_invalid);
|
|
|
|
tc_chain = tcase_create ("encoder");
|
|
suite_add_tcase (s, tc_chain);
|
|
tcase_add_test (tc_chain, rtpredenc_passthrough);
|
|
tcase_add_test (tc_chain, rtpredenc_payloadless_rtp);
|
|
tcase_add_test (tc_chain, rtpredenc_without_redundant_block);
|
|
tcase_add_test (tc_chain, rtpredenc_with_redundant_block);
|
|
tcase_add_loop_test (tc_chain, rtpredenc_negative_timestamp_offset, 0, 2);
|
|
tcase_add_loop_test (tc_chain, rtpredenc_too_large_timestamp_offset, 0, 2);
|
|
tcase_add_loop_test (tc_chain, rtpredenc_too_large_length, 0, 2);
|
|
|
|
return s;
|
|
}
|
|
|
|
GST_CHECK_MAIN (rtpred)
|