freeswitch/libs/spandsp/tests/t4_tests.c
Michael Jerris da557fd631 update to snapshot spandsp-20090220
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@12190 d0543943-73ff-0310-b7d9-9358b9ac24b2
2009-02-20 18:30:05 +00:00

605 lines
22 KiB
C

/*
* SpanDSP - a series of DSP components for telephony
*
* t4_tests.c - ITU T.4 FAX image to and from TIFF file tests
*
* Written by Steve Underwood <steveu@coppice.org>
*
* Copyright (C) 2003 Steve Underwood
*
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: t4_tests.c,v 1.67 2009/02/20 12:34:20 steveu Exp $
*/
/*! \file */
/*! \page t4_tests_page T.4 tests
\section t4_tests_page_sec_1 What does it do
These tests exercise the image compression and decompression methods defined
in ITU specifications T.4 and T.6.
*/
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <memory.h>
//#if defined(WITH_SPANDSP_INTERNALS)
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
//#endif
#include "spandsp.h"
#define IN_FILE_NAME "../test-data/itu/fax/itutests.tif"
#define OUT_FILE_NAME "t4_tests_receive.tif"
#define XSIZE 1728
t4_state_t send_state;
t4_state_t receive_state;
/* The following are some test cases from T.4 */
#define FILL_70 " "
#define FILL_80 " "
#define FILL_100 " "
#define FILL_670 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_70
#define FILL_980 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_100 FILL_80
static const char t4_test_patterns[][1728 + 1] =
{
"XXXXXX " FILL_980 " XXX XXX X " FILL_670 " XXXX",
"XXXXXX " FILL_980 " XXX X " FILL_670 " XXXX",
/* Line start should code to V(0). Line middle codes to VR(3) VL(2) V(0). Line end should code to V(0) V(0). */
" XXXX " FILL_980 " XXXXXXX " FILL_670 " XX ",
"XXXXX " FILL_980 "XX XX " FILL_670 " XXXX",
/* Line start should code to VL(1). Line middle codes to H(7,2). Line end should code to V(0) VR(2) */
"XXX " FILL_980 " XX XX XX XXX " FILL_670 " X ",
" " FILL_980 " X XXX XXXX " FILL_670 " X XX",
/* Line start should code to P. Line middle codes to P VL(1) V(0) H(3,4) P. Line end codes to V(0) VL(2) V(0). */
"XXXXX " FILL_980 " " FILL_670 " XXXX",
" XXX " FILL_980 " " FILL_670 " XX ",
/* Line start should code to VR(2). Line end codes to V(0) VL(2) V(0). */
" XX " FILL_980 " " FILL_670 " X XXX",
"XXX X " FILL_980 " " FILL_670 " X ",
/* Line start should code to H(0,3) VR(1). Line end codes to V(0) VR(3). */
" " FILL_980 " " FILL_670 " XX ",
" " FILL_980 " " FILL_670 " ",
/* Line end codes to P V(0) a'0. */
" " FILL_980 " " FILL_670 " XXXXXXXXXX",
" " FILL_980 " " FILL_670 " XXXXXX XXXXXX",
/* Line end codes to H(2,6). */
" " FILL_980 " " FILL_670 " XX XXXXX",
" " FILL_980 " " FILL_670 " XX ",
/* Line end codes to V(0) H(7,0). */
};
static void dump_image_as_xxx(t4_state_t *state)
{
uint8_t *s;
int i;
int j;
int k;
/* Dump the entire image as text 'X's and spaces */
printf("Image (%d x %d):\n", receive_state.image_width, receive_state.image_length);
s = state->image_buffer;
for (i = 0; i < state->image_length; i++)
{
for (j = 0; j < state->bytes_per_row; j++)
{
for (k = 0; k < 8; k++)
{
printf((state->image_buffer[i*state->bytes_per_row + j] & (0x80 >> k)) ? "X" : " ");
}
}
printf("\n");
}
}
/*- End of function --------------------------------------------------------*/
static void display_page_stats(t4_state_t *s)
{
t4_stats_t stats;
t4_get_transfer_statistics(s, &stats);
printf("Pages = %d\n", stats.pages_transferred);
printf("Image size = %d x %d pixels\n", stats.width, stats.length);
printf("Image resolution = %d/m x %d/m\n", stats.x_resolution, stats.y_resolution);
printf("Bad rows = %d\n", stats.bad_rows);
printf("Longest bad row run = %d\n", stats.longest_bad_row_run);
printf("Bits per row - min %d, max %d\n", s->min_row_bits, s->max_row_bits);
}
/*- End of function --------------------------------------------------------*/
#if 0
static int row_read_handler(void *user_data, uint8_t buf[], size_t len)
{
int i;
int j;
const char *s;
static int row = 0;
s = t4_test_patterns[row++];
if (row >= 16)
return 0;
memset(buf, 0, len);
for (i = 0; i < len; i++)
{
for (j = 0; j < 8; j++)
{
if (*s++ != ' ')
buf[i] |= (0x80 >> j);
}
}
if (*s)
printf("Oops - '%c' at end of row %d\n", *s, row);
return len;
}
/*- End of function --------------------------------------------------------*/
static int row_write_handler(void *user_data, const uint8_t buf[], size_t len)
{
int i;
int j;
const char *s;
static int row = 0;
uint8_t ref[8192];
if (len == 0)
return 0;
s = t4_test_patterns[row++];
if (row >= 16)
row = 0;
memset(ref, 0, len);
for (i = 0; i < len; i++)
{
for (j = 0; j < 8; j++)
{
if (*s++ != ' ')
ref[i] |= (0x80 >> j);
}
}
if (*s)
printf("Oops - '%c' at end of row %d\n", *s, row);
if (memcmp(buf, ref, len))
{
printf("Failed at row %d\n", row);
exit(2);
}
return len;
}
/*- End of function --------------------------------------------------------*/
#endif
int main(int argc, char *argv[])
{
int sends;
int page_no;
int bit;
int end_of_page;
int end_marks;
int decode_test;
int compression;
int compression_step;
int add_page_headers;
int min_row_bits;
int restart_pages;
int block_size;
char buf[1024];
uint8_t block[1024];
const char *in_file_name;
int opt;
int i;
int bit_error_rate;
int dump_as_xxx;
int tests_failed;
unsigned int last_pkt_no;
unsigned int pkt_no;
tests_failed = 0;
decode_test = FALSE;
compression = -1;
add_page_headers = FALSE;
restart_pages = FALSE;
in_file_name = IN_FILE_NAME;
min_row_bits = 0;
block_size = 0;
bit_error_rate = 0;
dump_as_xxx = FALSE;
while ((opt = getopt(argc, argv, "126b:dehri:m:x")) != -1)
{
switch (opt)
{
case '1':
compression = T4_COMPRESSION_ITU_T4_1D;
break;
case '2':
compression = T4_COMPRESSION_ITU_T4_2D;
break;
case '6':
compression = T4_COMPRESSION_ITU_T6;
break;
case 'b':
block_size = atoi(optarg);
if (block_size > 1024)
block_size = 1024;
break;
case 'd':
decode_test = TRUE;
break;
case 'e':
bit_error_rate = 0x3FF;
break;
case 'h':
add_page_headers = TRUE;
break;
case 'r':
restart_pages = TRUE;
break;
case 'i':
in_file_name = optarg;
break;
case 'm':
min_row_bits = atoi(optarg);
break;
case 'x':
dump_as_xxx = TRUE;
break;
default:
//usage();
exit(2);
break;
}
}
/* Create a send and a receive end */
memset(&send_state, 0, sizeof(send_state));
memset(&receive_state, 0, sizeof(receive_state));
end_of_page = FALSE;
if (decode_test)
{
if (compression < 0)
compression = T4_COMPRESSION_ITU_T4_1D;
/* Receive end puts TIFF to a new file. We assume the receive width here. */
if (t4_rx_init(&receive_state, OUT_FILE_NAME, T4_COMPRESSION_ITU_T4_2D) == NULL)
{
printf("Failed to init T.4 rx\n");
exit(2);
}
span_log_set_level(&receive_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
t4_rx_set_rx_encoding(&receive_state, compression);
t4_rx_set_x_resolution(&receive_state, T4_X_RESOLUTION_R8);
//t4_rx_set_y_resolution(&receive_state, T4_Y_RESOLUTION_FINE);
t4_rx_set_y_resolution(&receive_state, T4_Y_RESOLUTION_STANDARD);
t4_rx_set_image_width(&receive_state, XSIZE);
page_no = 1;
t4_rx_start_page(&receive_state);
last_pkt_no = 0;
while (fgets(buf, 1024, stdin))
{
if (sscanf(buf, "HDLC: FCD: 06 %x", &pkt_no) == 1)
{
/* Useful for breaking up T.38 ECM logs */
for (i = 0; i < 256; i++)
{
if (sscanf(&buf[18 + 3*i], "%x", (unsigned int *) &bit) != 1)
break;
if ((end_of_page = t4_rx_put_byte(&receive_state, bit)))
break;
}
}
else if (sscanf(buf, "HDLC: %x", &pkt_no) == 1)
{
/* Useful for breaking up HDLC decodes of ECM logs */
for (i = 0; i < 256; i++)
{
if (sscanf(&buf[19 + 3*i], "%x", (unsigned int *) &bit) != 1)
break;
if ((end_of_page = t4_rx_put_byte(&receive_state, bit)))
break;
}
}
else if (strlen(buf) > 62 && sscanf(buf + 57, "Rx %d: IFP %x %x", &pkt_no, (unsigned int *) &bit, (unsigned int *) &bit) == 3)
{
/* Useful for breaking up T.38 non-ECM logs */
if (pkt_no != last_pkt_no + 1)
printf("Packet %u\n", pkt_no);
last_pkt_no = pkt_no;
for (i = 0; i < 256; i++)
{
if (sscanf(&buf[57 + 29 + 3*i], "%x", (unsigned int *) &bit) != 1)
break;
bit = bit_reverse8(bit);
if ((end_of_page = t4_rx_put_byte(&receive_state, bit)))
break;
}
}
else if (sscanf(buf, "Rx bit %*d - %d", &bit) == 1)
{
if ((end_of_page = t4_rx_put_bit(&receive_state, bit)))
{
printf("End of page detected\n");
break;
}
}
}
if (dump_as_xxx)
dump_image_as_xxx(&receive_state);
t4_rx_end_page(&receive_state);
display_page_stats(&receive_state);
t4_rx_release(&receive_state);
}
else
{
#if 1
/* Send end gets TIFF from a file */
if (t4_tx_init(&send_state, in_file_name, -1, -1) == NULL)
{
printf("Failed to init T.4 send\n");
exit(2);
}
span_log_set_level(&send_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
t4_tx_set_min_row_bits(&send_state, min_row_bits);
t4_tx_set_local_ident(&send_state, "111 2222 3333");
/* Receive end puts TIFF to a new file. */
if (t4_rx_init(&receive_state, OUT_FILE_NAME, T4_COMPRESSION_ITU_T4_2D) == NULL)
{
printf("Failed to init T.4 rx\n");
exit(2);
}
span_log_set_level(&receive_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
t4_rx_set_x_resolution(&receive_state, t4_tx_get_x_resolution(&send_state));
t4_rx_set_y_resolution(&receive_state, t4_tx_get_y_resolution(&send_state));
t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state));
/* Now send and receive all the pages in the source TIFF file */
page_no = 1;
sends = 0;
/* Select whether we step round the compression schemes, or use a single specified one. */
compression_step = (compression < 0) ? 0 : -1;
for (;;)
{
end_marks = 0;
/* Add a header line to alternate pages, if required */
if (add_page_headers && (sends & 2))
t4_tx_set_header_info(&send_state, "Header");
else
t4_tx_set_header_info(&send_state, NULL);
if (restart_pages && (sends & 1))
{
/* Use restart, to send the page a second time */
if (t4_tx_restart_page(&send_state))
break;
}
else
{
switch (compression_step)
{
case 0:
compression = T4_COMPRESSION_ITU_T4_1D;
compression_step++;
break;
case 1:
compression = T4_COMPRESSION_ITU_T4_2D;
compression_step++;
break;
case 2:
compression = T4_COMPRESSION_ITU_T6;
compression_step = 0;
break;
}
t4_tx_set_tx_encoding(&send_state, compression);
t4_rx_set_rx_encoding(&receive_state, compression);
if (t4_tx_start_page(&send_state))
break;
}
t4_rx_start_page(&receive_state);
if (block_size == 0)
{
do
{
bit = t4_tx_get_bit(&send_state);
if (bit == SIG_STATUS_END_OF_DATA)
{
/* T.6 data does not contain an image termination sequence.
T.4 1D and 2D do, and should locate that sequence. */
if (compression == T4_COMPRESSION_ITU_T6)
break;
if (++end_marks > 50)
{
printf("Receiver missed the end of page mark\n");
tests_failed++;
break;
}
}
if (bit_error_rate)
{
if ((rand() % bit_error_rate) == 0)
bit ^= 1;
}
end_of_page = t4_rx_put_bit(&receive_state, bit & 1);
}
while (!end_of_page);
}
else if (block_size == 1)
{
do
{
bit = t4_tx_get_byte(&send_state);
if ((bit & 0x100))
{
/* T.6 data does not contain an image termination sequence.
T.4 1D and 2D do, and should locate that sequence. */
if (compression == T4_COMPRESSION_ITU_T6)
break;
if (++end_marks > 50)
{
printf("Receiver missed the end of page mark\n");
tests_failed++;
break;
}
}
end_of_page = t4_rx_put_byte(&receive_state, bit & 0xFF);
}
while (!end_of_page);
}
else
{
do
{
bit = t4_tx_get_chunk(&send_state, block, block_size);
if (bit > 0)
end_of_page = t4_rx_put_chunk(&receive_state, block, bit);
if (bit < block_size)
{
/* T.6 data does not contain an image termination sequence.
T.4 1D and 2D do, and should locate that sequence. */
if (compression == T4_COMPRESSION_ITU_T6)
break;
if (++end_marks > 50)
{
printf("Receiver missed the end of page mark\n");
tests_failed++;
break;
}
}
}
while (!end_of_page);
}
if (dump_as_xxx)
dump_image_as_xxx(&receive_state);
display_page_stats(&receive_state);
if (!restart_pages || (sends & 1))
t4_tx_end_page(&send_state);
t4_rx_end_page(&receive_state);
sends++;
}
t4_tx_release(&send_state);
t4_rx_release(&receive_state);
/* And we should now have a matching received TIFF file. Note this will only match
at the image level. TIFF files allow a lot of ways to express the same thing,
so bit matching of the files is not the normal case. */
fflush(stdout);
sprintf(buf, "tiffcmp -t %s " OUT_FILE_NAME, in_file_name);
if (tests_failed)// || system(buf))
{
printf("Tests failed\n");
exit(2);
}
#endif
#if 0
/* Send end gets TIFF from a function */
if (t4_tx_init(&send_state, in_file_name, -1, -1) == NULL)
{
printf("Failed to init T.4 tx\n");
exit(2);
}
span_log_set_level(&send_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
t4_tx_set_row_read_handler(&send_state, row_read_handler, NULL);
t4_tx_set_min_row_bits(&send_state, min_row_bits);
t4_tx_set_local_ident(&send_state, "111 2222 3333");
/* Receive end puts TIFF to a function. */
if (t4_rx_init(&receive_state, OUT_FILE_NAME, T4_COMPRESSION_ITU_T4_2D) == NULL)
{
printf("Failed to init T.4 rx\n");
exit(2);
}
span_log_set_level(&receive_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW);
t4_rx_set_row_write_handler(&receive_state, row_write_handler, NULL);
t4_rx_set_x_resolution(&receive_state, t4_tx_get_x_resolution(&send_state));
t4_rx_set_y_resolution(&receive_state, t4_tx_get_y_resolution(&send_state));
t4_rx_set_image_width(&receive_state, t4_tx_get_image_width(&send_state));
/* Now send and receive all the pages in the source TIFF file */
page_no = 1;
/* Select whether we step round the compression schemes, or use a single specified one. */
compression_step = (compression < 0) ? 0 : -1;
for (;;)
{
end_marks = 0;
/* Add a header line to alternate pages, if required */
switch (compression_step)
{
case 0:
compression = T4_COMPRESSION_ITU_T4_1D;
compression_step++;
break;
case 1:
compression = T4_COMPRESSION_ITU_T4_2D;
compression_step++;
break;
case 2:
compression = T4_COMPRESSION_ITU_T6;
compression_step = 0;
break;
}
t4_tx_set_tx_encoding(&send_state, compression);
t4_rx_set_rx_encoding(&receive_state, compression);
if (t4_tx_start_page(&send_state))
break;
t4_rx_start_page(&receive_state);
do
{
bit = t4_tx_get_bit(&send_state);
if (bit == SIG_STATUS_END_OF_DATA)
{
/* T.6 data does not contain an image termination sequence.
T.4 1D and 2D do, and should locate that sequence. */
if (compression == T4_COMPRESSION_ITU_T6)
break;
if (++end_marks > 50)
{
printf("Receiver missed the end of page mark\n");
tests_failed++;
break;
}
}
end_of_page = t4_rx_put_bit(&receive_state, bit & 1);
}
while (!end_of_page);
t4_tx_end_page(&send_state);
t4_rx_end_page(&receive_state);
break;
}
t4_tx_release(&send_state);
t4_rx_release(&receive_state);
#endif
printf("Tests passed\n");
}
return 0;
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/