示例#1
0
/**
 * @brief Store the new TS, calculate new values and update the state
 *
 * @param ts_sc        The ts_sc_comp object
 * @param ts           The timestamp to add
 * @param sn           The sequence number of the RTP packet
 */
void c_add_ts(struct ts_sc_comp *const ts_sc,
              const uint32_t ts,
              const uint16_t sn)
{
	uint16_t sn_delta;

	assert(ts_sc != NULL);

	ts_debug(ts_sc, "Timestamp = %u", ts);

	/* consider that TS bits are not deducible by default */
	ts_sc->is_deducible = false;

	/* we save the old value */
	ts_sc->old_ts = ts_sc->ts;
	ts_sc->old_sn = ts_sc->sn;

	/* we store the new value */
	ts_sc->ts = ts;
	ts_sc->sn = sn;

	/* if we had no old values, TS_STRIDE cannot be computed yet */
	if(!ts_sc->are_old_val_init)
	{
		assert(ts_sc->state == INIT_TS);
		ts_debug(ts_sc, "TS_STRIDE cannot be computed, stay in INIT_TS state");
		ts_sc->are_old_val_init = true;
		return;
	}

	/* compute the absolute delta between new and old SN */
	/* abs() on unsigned 16-bit values seems to be a problem sometimes */
	if(ts_sc->sn >= ts_sc->old_sn)
	{
		sn_delta = ts_sc->sn - ts_sc->old_sn;
	}
	else
	{
		sn_delta = ts_sc->old_sn - ts_sc->sn;
	}
	ts_debug(ts_sc, "SN delta = %u", sn_delta);

	/* compute the absolute delta between new and old TS */
	/* abs() on unsigned 32-bit values seems to be a problem sometimes */
	if(ts_sc->ts >= ts_sc->old_ts)
	{
		ts_sc->ts_delta = ts_sc->ts - ts_sc->old_ts;
	}
	else
	{
		ts_sc->ts_delta = ts_sc->old_ts - ts_sc->ts;
	}
	ts_debug(ts_sc, "TS delta = %u", ts_sc->ts_delta);

	/* go back to INIT_TS state if TS is constant */
	if(ts_sc->ts_delta == 0)
	{
		ts_debug(ts_sc, "TS is constant, go in INIT_TS state");
		ts_sc->state = INIT_TS;
		return;
	}

	/* go back to INIT_TS state if TS_STRIDE cannot be SDVL-encoded */
	if(!sdvl_can_value_be_encoded(ts_sc->ts_delta))
	{
		/* TS_STRIDE is too large for SDVL encoding */
		ts_debug(ts_sc, "TS_STRIDE is too large for SDVL encoding, "
		         "go in INIT_TS state");
		ts_sc->state = INIT_TS;
		return;
	}

	/* TS_STRIDE can be computed, so leave INIT_TS state */
	if(ts_sc->state == INIT_TS)
	{
		ts_debug(ts_sc, "TS_STRIDE can be computed, go to INIT_STRIDE state");
		ts_sc->state = INIT_STRIDE;
		ts_sc->nr_init_stride_packets = 0;
	}

	if(ts_sc->state == INIT_STRIDE)
	{
		/* TS is changing and TS_STRIDE can be computed but TS_STRIDE was
		 * not transmitted enough times to the decompressor to be used */
		ts_debug(ts_sc, "state INIT_STRIDE");

		/* reset INIT_STRIDE counter if TS_STRIDE/TS_OFFSET changed */
		if(ts_sc->ts_delta != ts_sc->ts_stride ||
		   (ts_sc->ts % ts_sc->ts_delta) != ts_sc->ts_offset)
		{
			ts_debug(ts_sc, "TS_STRIDE and/or TS_OFFSET changed");
			ts_sc->nr_init_stride_packets = 0;
		}

		/* compute TS_STRIDE, TS_OFFSET and TS_SCALED */
		ts_sc->ts_stride = ts_sc->ts_delta;
		ts_debug(ts_sc, "TS_STRIDE = %u", ts_sc->ts_stride);
		assert(ts_sc->ts_stride != 0);
		ts_sc->ts_offset = ts_sc->ts % ts_sc->ts_stride;
		ts_debug(ts_sc, "TS_OFFSET = %u modulo %u = %u",
		         ts_sc->ts, ts_sc->ts_stride, ts_sc->ts_offset);
		assert(ts_sc->ts_stride != 0);
		ts_sc->ts_scaled = (ts_sc->ts - ts_sc->ts_offset) / ts_sc->ts_stride;
		ts_debug(ts_sc, "TS_SCALED = (%u - %u) / %u = %u", ts_sc->ts,
		         ts_sc->ts_offset, ts_sc->ts_stride, ts_sc->ts_scaled);
	}
	else if(ts_sc->state == SEND_SCALED)
	{
		const uint32_t old_scaled = ts_sc->ts_scaled;
		const uint32_t old_offset = ts_sc->ts_offset;

		/* TS is changing, TS_STRIDE can be computed, and TS_STRIDE was
		 * transmitted enough times to the decompressor to be used */
		ts_debug(ts_sc, "state SEND_SCALED");

		/* does TS_STRIDE changed? */
		ts_debug(ts_sc, "TS_STRIDE calculated = %u", ts_sc->ts_delta);
		ts_debug(ts_sc, "previous TS_STRIDE = %u", ts_sc->ts_stride);
		if(ts_sc->ts_delta != ts_sc->ts_stride)
		{
			assert(ts_sc->ts_stride != 0);
			if((ts_sc->ts_delta % ts_sc->ts_stride) != 0)
			{
				/* TS delta changed and is not a multiple of previous TS_STRIDE:
				 * record the new value as TS_STRIDE and transmit it several
				 * times for robustness purposes */
				ts_debug(ts_sc, "/!\\ TS_STRIDE changed and is not a multiple "
				         "of previous TS_STRIDE, so change TS_STRIDE and "
				         "transmit it several times along all TS bits "
				         "(probably a clock resync at source)");
				ts_sc->state = INIT_STRIDE;
				ts_sc->nr_init_stride_packets = 0;
				ts_debug(ts_sc, "state -> INIT_STRIDE");
				ts_sc->ts_stride = ts_sc->ts_delta;
			}
			else if((ts_sc->ts_delta / ts_sc->ts_stride) != sn_delta)
			{
				/* TS delta changed but is a multiple of previous TS_STRIDE:
				 * do not change TS_STRIDE, but transmit all TS bits several
				 * times for robustness purposes */
				ts_debug(ts_sc, "/!\\ TS delta changed but is a multiple of "
				         "previous TS_STRIDE, so do not change TS_STRIDE, but "
				         "retransmit it several times along all TS bits "
				         "(probably a RTP TS jump at source)");
				ts_sc->state = INIT_STRIDE;
				ts_sc->nr_init_stride_packets = 0;
				ts_debug(ts_sc, "state -> INIT_STRIDE");
			}
			else
			{
				/* do not change TS_STRIDE, probably a packet loss */
				ts_debug(ts_sc, "/!\\ TS delta changed, is a multiple of "
				         "previous TS_STRIDE and follows SN changes, so do "
				         "not change TS_STRIDE (probably a packet loss)");
			}
		}
		ts_debug(ts_sc, "TS_STRIDE = %u", ts_sc->ts_stride);

		/* update TS_OFFSET is needed */
		assert(ts_sc->ts_stride != 0);
		ts_sc->ts_offset = ts_sc->ts % ts_sc->ts_stride;
		ts_debug(ts_sc, "TS_OFFSET = %u modulo %u = %u",
		         ts_sc->ts, ts_sc->ts_stride, ts_sc->ts_offset);

		/* compute TS_SCALED */
		assert(ts_sc->ts_stride != 0);
		ts_sc->ts_scaled = (ts_sc->ts - ts_sc->ts_offset) / ts_sc->ts_stride;
		ts_debug(ts_sc, "TS_SCALED = (%u - %u) / %u = %u", ts_sc->ts,
		         ts_sc->ts_offset, ts_sc->ts_stride, ts_sc->ts_scaled);

		/* could TS_SCALED be deduced from SN? */
		if(ts_sc->state != SEND_SCALED)
		{
			ts_sc->is_deducible = false;
		}
		else
		{
			uint32_t ts_scaled_delta;

			/* be cautious with positive and negative deltas */
			if(ts_sc->ts_scaled >= old_scaled)
			{
				ts_scaled_delta = ts_sc->ts_scaled - old_scaled;

				if(ts_sc->sn >= ts_sc->old_sn)
				{
					ts_sc->is_deducible = (ts_scaled_delta == sn_delta);
				}
				else
				{
					ts_sc->is_deducible = false;
				}
			}
			else
			{
				ts_scaled_delta = old_scaled - ts_sc->ts_scaled;

				if(ts_sc->old_sn >= ts_sc->sn)
				{
					ts_sc->is_deducible = (ts_scaled_delta == sn_delta);
				}
				else
				{
					ts_sc->is_deducible = false;
				}
			}
		}
		if(ts_sc->is_deducible)
		{
			ts_debug(ts_sc, "TS can be deducted from SN (old TS_SCALED = %u, "
			         "new TS_SCALED = %u, old SN = %u, new SN = %u)",
			         old_scaled, ts_sc->ts_scaled, ts_sc->old_sn, ts_sc->sn);
		}
		else
		{
			ts_debug(ts_sc, "TS can not be deducted from SN (old TS_SCALED = %u, "
			         "new TS_SCALED = %u, old SN = %u, new SN = %u)",
			         old_scaled, ts_sc->ts_scaled, ts_sc->old_sn, ts_sc->sn);
		}

		/* Wraparound (See RFC 4815 Section 4.4.3) */
		if(ts_sc->ts < ts_sc->old_ts)
		{
			ts_debug(ts_sc, "TS wraparound detected");
			if(old_offset != ts_sc->ts_offset)
			{
				ts_debug(ts_sc, "TS_OFFSET changed, re-initialize TS_STRIDE");
				ts_sc->state = INIT_STRIDE;
				ts_sc->nr_init_stride_packets = 0;
			}
			else
			{
				ts_debug(ts_sc, "TS_OFFSET is unchanged");
			}
		}
	}
	else
	{
		/* invalid state, should not happen */
		ts_debug(ts_sc, "invalid state (%d), should not happen", ts_sc->state);
		assert(0);
		return;
	}
}
示例#2
0
/**
 * @brief Test the SDVL compression scheme
 *
 * @param argc  The number of command line arguments
 * @param argv  The command line arguments
 * @return      0 if test succeeds, non-zero if test fails
 */
int main(int argc, char *argv[])
{
	bool verbose; /* whether to run in verbose mode or not */
	int is_failure = 1; /* test fails by default */

	/* do we run in verbose mode ? */
	if(argc == 1)
	{
		/* no argument, run in silent mode */
		verbose = false;
	}
	else if(argc == 2 && strcmp(argv[1], "verbose") == 0)
	{
		/* run in verbose mode */
		verbose = true;
	}
	else
	{
		/* invalid usage */
		printf("test the SDVL compression scheme\n");
		printf("usage: %s [verbose]\n", argv[0]);
		goto error;
	}

	/* sdvl_can_value_be_encoded() */
	CHECK(sdvl_can_value_be_encoded(0U) == true);
	CHECK(sdvl_can_value_be_encoded(1U) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 5) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 6) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 7) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 12) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 13) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 14) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 19) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 20) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 21) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 27) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 28) == true);
	CHECK(sdvl_can_value_be_encoded(1U << 29) == false);
	CHECK(sdvl_can_value_be_encoded(1U << 30) == false);
	CHECK(sdvl_can_value_be_encoded(1U << 31) == false);
	CHECK(sdvl_can_value_be_encoded(UINT32_MAX) == false);

	/* sdvl_can_length_be_encoded() */
	CHECK(sdvl_can_length_be_encoded(0) == true);
	CHECK(sdvl_can_length_be_encoded(1) == true);
	CHECK(sdvl_can_length_be_encoded(6) == true);
	CHECK(sdvl_can_length_be_encoded(7) == true);
	CHECK(sdvl_can_length_be_encoded(8) == true);
	CHECK(sdvl_can_length_be_encoded(13) == true);
	CHECK(sdvl_can_length_be_encoded(14) == true);
	CHECK(sdvl_can_length_be_encoded(15) == true);
	CHECK(sdvl_can_length_be_encoded(20) == true);
	CHECK(sdvl_can_length_be_encoded(21) == true);
	CHECK(sdvl_can_length_be_encoded(22) == true);
	CHECK(sdvl_can_length_be_encoded(28) == true);
	CHECK(sdvl_can_length_be_encoded(29) == true);
	CHECK(sdvl_can_length_be_encoded(30) == false);
	CHECK(sdvl_can_length_be_encoded(31) == false);
	CHECK(sdvl_can_length_be_encoded(32) == false);

	/* sdvl_get_min_len() */
	CHECK(sdvl_get_min_len(0, 0) == 0);
	CHECK(sdvl_get_min_len(1, 0) == 7);
	CHECK(sdvl_get_min_len(6, 0) == 7);
	CHECK(sdvl_get_min_len(7, 0) == 7);
	CHECK(sdvl_get_min_len(8, 0) == 14);
	CHECK(sdvl_get_min_len(13, 0) == 14);
	CHECK(sdvl_get_min_len(14, 0) == 14);
	CHECK(sdvl_get_min_len(15, 0) == 21);
	CHECK(sdvl_get_min_len(20, 0) == 21);
	CHECK(sdvl_get_min_len(21, 0) == 21);
	CHECK(sdvl_get_min_len(22, 0) == 29);
	CHECK(sdvl_get_min_len(28, 0) == 29);
	CHECK(sdvl_get_min_len(29, 0) == 29);
	CHECK(sdvl_get_min_len(0, 1) == 0);
	CHECK(sdvl_get_min_len(1, 1) == 0);
	CHECK(sdvl_get_min_len(6, 1) == 7);
	CHECK(sdvl_get_min_len(7, 1) == 7);
	CHECK(sdvl_get_min_len(8, 1) == 7);
	CHECK(sdvl_get_min_len(13, 1) == 14);
	CHECK(sdvl_get_min_len(14, 1) == 14);
	CHECK(sdvl_get_min_len(15, 1) == 14);
	CHECK(sdvl_get_min_len(20, 1) == 21);
	CHECK(sdvl_get_min_len(21, 1) == 21);
	CHECK(sdvl_get_min_len(22, 1) == 21);
	CHECK(sdvl_get_min_len(28, 1) == 29);
	CHECK(sdvl_get_min_len(29, 1) == 29);
	CHECK(sdvl_get_min_len(0, 21) == 0);
	CHECK(sdvl_get_min_len(1, 21) == 0);
	CHECK(sdvl_get_min_len(6, 21) == 0);
	CHECK(sdvl_get_min_len(7, 21) == 0);
	CHECK(sdvl_get_min_len(8, 21) == 0);
	CHECK(sdvl_get_min_len(13, 21) == 0);
	CHECK(sdvl_get_min_len(14, 21) == 0);
	CHECK(sdvl_get_min_len(15, 21) == 0);
	CHECK(sdvl_get_min_len(20, 21) == 0);
	CHECK(sdvl_get_min_len(21, 21) == 0);
	CHECK(sdvl_get_min_len(22, 21) == 7);
	CHECK(sdvl_get_min_len(28, 21) == 7);
	CHECK(sdvl_get_min_len(29, 21) == 14);
	CHECK(sdvl_get_min_len(0, 32) == 0);
	CHECK(sdvl_get_min_len(1, 32) == 0);
	CHECK(sdvl_get_min_len(6, 32) == 0);
	CHECK(sdvl_get_min_len(7, 32) == 0);
	CHECK(sdvl_get_min_len(8, 32) == 0);
	CHECK(sdvl_get_min_len(13, 32) == 0);
	CHECK(sdvl_get_min_len(14, 32) == 0);
	CHECK(sdvl_get_min_len(15, 32) == 0);
	CHECK(sdvl_get_min_len(20, 32) == 0);
	CHECK(sdvl_get_min_len(21, 32) == 0);
	CHECK(sdvl_get_min_len(22, 32) == 0);
	CHECK(sdvl_get_min_len(28, 32) == 0);
	CHECK(sdvl_get_min_len(29, 32) == 0);

	/* sdvl_get_encoded_len() */
	CHECK(sdvl_get_encoded_len(0U) == 1);
	CHECK(sdvl_get_encoded_len(1U) == 1);
	CHECK(sdvl_get_encoded_len(1U << 5) == 1);
	CHECK(sdvl_get_encoded_len(1U << 6) == 1);
	CHECK(sdvl_get_encoded_len(1U << 7) == 2);
	CHECK(sdvl_get_encoded_len(1U << 12) == 2);
	CHECK(sdvl_get_encoded_len(1U << 13) == 2);
	CHECK(sdvl_get_encoded_len(1U << 14) == 3);
	CHECK(sdvl_get_encoded_len(1U << 19) == 3);
	CHECK(sdvl_get_encoded_len(1U << 20) == 3);
	CHECK(sdvl_get_encoded_len(1U << 21) == 4);
	CHECK(sdvl_get_encoded_len(1U << 27) == 4);
	CHECK(sdvl_get_encoded_len(1U << 28) == 4);
	CHECK(sdvl_get_encoded_len(1U << 29) == 5);
	CHECK(sdvl_get_encoded_len(1U << 30) == 5);
	CHECK(sdvl_get_encoded_len(1U << 31) == 5);

	/* sdvl_encode() / sdvl_encode_full() / sdvl_decode() */
	{
		const uint32_t values[] =  { 1, 6, 7,  8, 13, 14, 15, 20, 21, 22, 28, 29, 30, 31, 32 };
		const size_t values_nr = sizeof(values) / sizeof(uint32_t);
		const size_t exp_bytes[] = { 1, 1, 1,  2,  2,  2,  3,  3,  3,  4,  4,  4,  5,  5,  5 };
		const size_t exp_bytes_nr = sizeof(exp_bytes) / sizeof(size_t);
		const size_t exp_bits[] =  { 7, 7, 7, 14, 14, 14, 21, 21, 21, 29, 29, 29, 32, 32, 32 };
		const size_t exp_bits_nr = sizeof(exp_bits) / sizeof(size_t);
		size_t sdvl_bytes_max_nr;
#define sdvl_bytes_max_buf_size 4U

		CHECK(values_nr == exp_bytes_nr);
		CHECK(values_nr == exp_bits_nr);

		for(sdvl_bytes_max_nr = 0; sdvl_bytes_max_nr <= 4; sdvl_bytes_max_nr++)
		{
			size_t i;

			for(i = 0; i < values_nr; i++)
			{
				const uint32_t value = (values[i] == 32 ? UINT32_MAX : ((1U << values[i]) - 1U));
				uint8_t sdvl_bytes[sdvl_bytes_max_buf_size];
				size_t sdvl_bytes_nr;
				uint32_t decoded_value;
				size_t useful_bits_nr;

				/* sdvl_encode_full() */
				const bool exp_status = (exp_bytes[i] <= 4 && exp_bytes[i] <= sdvl_bytes_max_nr);
				CHECK(sdvl_encode_full(sdvl_bytes, sdvl_bytes_max_nr, &sdvl_bytes_nr,
				                       value) == exp_status);
				if(exp_status)
				{
					printf("sdvl_encode_full(%u) = ", value);
					for(size_t j = 0; j < sdvl_bytes_nr; j++)
					{
						printf("0x%02x ", sdvl_bytes[j]);
					}
					printf("\n");
					CHECK(sdvl_bytes_nr == exp_bytes[i]);

					/* sdvl_decode() */
					for(size_t j = 0; j <= sdvl_bytes_nr; j++)
					{
						const size_t exp_result = (j < sdvl_bytes_nr ? 0 : exp_bytes[i]);
						CHECK(sdvl_decode(sdvl_bytes, j, &decoded_value,
						                  &useful_bits_nr) == exp_result);
						if(exp_result > 0)
						{
							CHECK(decoded_value == value);
							CHECK(useful_bits_nr == exp_bits[i]);
						}
					}
				}

				/* sdvl_encode() */
				{
					uint8_t sdvl_bytes2[sdvl_bytes_max_buf_size];
					size_t sdvl_bytes2_nr;
					CHECK(sdvl_encode(sdvl_bytes2, sdvl_bytes_max_nr, &sdvl_bytes2_nr,
					                  value, exp_bits[i]) == exp_status);
					if(exp_status)
					{
						printf("sdvl_encode(%u) = ", value);
						for(size_t j = 0; j < sdvl_bytes_nr; j++)
						{
							printf("0x%02x ", sdvl_bytes[j]);
						}
						printf("\n");
						CHECK(sdvl_bytes2_nr == sdvl_bytes_nr);
						CHECK(memcmp(sdvl_bytes2, sdvl_bytes, sdvl_bytes2_nr) == 0);
					}
				}
			}
		}
	}

	/* test succeeds */
	trace(verbose, "all tests are successful\n");
	is_failure = 0;

error:
	return is_failure;
}