diff options
author | David M. Lee <dlee@digium.com> | 2013-01-07 14:24:28 -0600 |
---|---|---|
committer | David M. Lee <dlee@digium.com> | 2013-01-07 14:24:28 -0600 |
commit | f3ab456a17af1c89a6e3be4d20c5944853df1cb0 (patch) | |
tree | d00e1a332cd038a6d906a1ea0ac91e1a4458e617 /pjmedia/src/test/codec_vectors.c |
Import pjproject-2.0.1
Diffstat (limited to 'pjmedia/src/test/codec_vectors.c')
-rw-r--r-- | pjmedia/src/test/codec_vectors.c | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/pjmedia/src/test/codec_vectors.c b/pjmedia/src/test/codec_vectors.c new file mode 100644 index 0000000..71962f4 --- /dev/null +++ b/pjmedia/src/test/codec_vectors.c @@ -0,0 +1,626 @@ +/* $Id: codec_vectors.c 3664 2011-07-19 03:42:28Z nanang $ */ +/* + * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "test.h" +#include <pjmedia-codec.h> + +#define THIS_FILE "codec_vectors.c" +#define TMP_OUT "output.tmp" + +/* + * Encode test. Read input from WAV file, encode to temporary output file, + * and compare the temporary output file to the reference file. + */ +static int codec_test_encode(pjmedia_codec_mgr *mgr, + char *codec_name, + unsigned bitrate, + const char *wav_file, + const char *ref_encoded_file) +{ + pj_str_t codec_id = pj_str(codec_name); + pj_pool_t *pool = NULL; + unsigned count, samples_per_frame, encoded_frame_len = 0, pos; + pjmedia_codec *codec = NULL; + const pjmedia_codec_info *ci[1]; + pjmedia_codec_param codec_param; + pjmedia_port *wav_port = NULL; + pjmedia_frame in_frame, out_frame; + FILE *output = NULL, *fref = NULL; + int rc = 0; + pj_status_t status; + + pool = pj_pool_create(mem, "codec-vectors", 512, 512, NULL); + if (!pool) { + rc = -20; + goto on_return; + } + + /* Find and open the codec */ + count = 1; + status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id, &count, ci, NULL); + if (status != PJ_SUCCESS) { + rc = -30; + goto on_return; + } + + status = pjmedia_codec_mgr_alloc_codec(mgr, ci[0], &codec); + if (status != PJ_SUCCESS) { + rc = -40; + goto on_return; + } + + status = pjmedia_codec_mgr_get_default_param(mgr, ci[0], &codec_param); + if (status != PJ_SUCCESS) { + rc = -50; + goto on_return; + } + + codec_param.info.avg_bps = bitrate; + codec_param.setting.vad = 0; + + status = pjmedia_codec_init(codec, pool); + if (status != PJ_SUCCESS) { + rc = -60; + goto on_return; + } + + status = pjmedia_codec_open(codec, &codec_param); + if (status != PJ_SUCCESS) { + rc = -70; + goto on_return; + } + + /* Open WAV file */ + status = pjmedia_wav_player_port_create(pool, wav_file, + codec_param.info.frm_ptime, + PJMEDIA_FILE_NO_LOOP, 0, + &wav_port); + if (status != PJ_SUCCESS) { + rc = -80; + goto on_return; + } + + /* Open output file */ + output = fopen(TMP_OUT, "wb"); + if (!output) { + rc = -90; + goto on_return; + } + + /* Allocate buffer for PCM and encoded frames */ + samples_per_frame = codec_param.info.clock_rate * codec_param.info.frm_ptime / 1000; + in_frame.buf = pj_pool_alloc(pool, samples_per_frame * 2); + out_frame.buf = (pj_uint8_t*) pj_pool_alloc(pool, samples_per_frame); + + /* Loop read WAV file and encode and write to output file */ + for (;;) { + in_frame.size = samples_per_frame * 2; + in_frame.type = PJMEDIA_FRAME_TYPE_AUDIO; + + status = pjmedia_port_get_frame(wav_port, &in_frame); + if (status != PJ_SUCCESS || in_frame.type != PJMEDIA_FRAME_TYPE_AUDIO) + break; + + out_frame.size = samples_per_frame; + status = pjmedia_codec_encode(codec, &in_frame, samples_per_frame, + &out_frame); + if (status != PJ_SUCCESS) { + rc = -95; + goto on_return; + } + + if (out_frame.size) { + int cnt; + + cnt = fwrite(out_frame.buf, out_frame.size, 1, output); + + if (encoded_frame_len == 0) + encoded_frame_len = out_frame.size; + } + } + + fclose(output); + output = NULL; + + /* Compare encoded files */ + fref = fopen(ref_encoded_file, "rb"); + if (!fref) { + rc = -100; + goto on_return; + } + + output = fopen(TMP_OUT, "rb"); + if (!output) { + rc = -110; + goto on_return; + } + + pos = 0; + for (;;) { + int count; + + count = fread(in_frame.buf, encoded_frame_len, 1, fref); + if (count != 1) + break; + + count = fread(out_frame.buf, encoded_frame_len, 1, output); + if (count != 1) + break; + + if (memcmp(in_frame.buf, out_frame.buf, encoded_frame_len)) { + unsigned i; + pj_uint8_t *in = (pj_uint8_t*)in_frame.buf; + pj_uint8_t *out = (pj_uint8_t*)out_frame.buf; + + for (i=0; i<encoded_frame_len; ++i) { + if (in[i] != out[i]) + break; + } + + PJ_LOG(1,(THIS_FILE," failed: mismatch at pos %d", pos+i)); + rc = -200; + break; + } + + pos += encoded_frame_len; + } + +on_return: + if (output) + fclose(output); + + if (fref) + fclose(fref); + + if (codec) { + pjmedia_codec_close(codec); + pjmedia_codec_mgr_dealloc_codec(mgr, codec); + } + + if (wav_port) + pjmedia_port_destroy(wav_port); + + if (pool) + pj_pool_release(pool); + + return rc; +} + + +/* + * Read file in ITU format (".itu" extension). + * + * Set swap_endian to TRUE if the ITU file is stored in little + * endian format (normally true). + */ +static int read_ITU_format(FILE *fp_bitstream, + short *out_words, + short *p_frame_error_flag, + int number_of_16bit_words_per_frame, + pj_bool_t swap_endian) +{ + enum { MAX_BITS_PER_FRAME = 160*8 }; + short i,j; + short nsamp; + short packed_word; + short bit_count; + short bit; + short in_array[MAX_BITS_PER_FRAME+2]; + short one = 0x0081; + short zero = 0x007f; + short frame_start = 0x6b21; + + nsamp = (short)fread(in_array, 2, 2 + 16*number_of_16bit_words_per_frame, + fp_bitstream); + + j = 0; + bit = in_array[j++]; + if (bit != frame_start) { + *p_frame_error_flag = 1; + } else { + *p_frame_error_flag = 0; + + /* increment j to skip over the number of bits in frame */ + j++; + + for (i=0; i<number_of_16bit_words_per_frame; i++) { + packed_word = 0; + bit_count = 15; + while (bit_count >= 0) { + bit = in_array[j++]; + if (bit == zero) + bit = 0; + else if (bit == one) + bit = 1; + else + *p_frame_error_flag = 1; + + packed_word <<= 1; + packed_word = (short )(packed_word + bit); + bit_count--; + } + + if (swap_endian) + out_words[i] = pj_ntohs(packed_word); + else + out_words[i] = packed_word; + } + } + return (nsamp-1)/16; +} + + +/* + * Decode test + * + * Decode the specified encoded file in "in_encoded_file" into temporary + * PCM output file, and compare the temporary PCM output file with + * the PCM reference file. + * + * Some reference file requires manipulation to the PCM output + * before comparison, such manipulation can be done by supplying + * this function with the "manip" function. + */ +static int codec_test_decode(pjmedia_codec_mgr *mgr, + char *codec_name, + unsigned bitrate, + unsigned encoded_len, + const char *in_encoded_file, + const char *ref_pcm_file, + void (*manip)(short *pcm, unsigned count)) +{ + pj_str_t codec_id = pj_str(codec_name); + pj_pool_t *pool = NULL; + unsigned count, samples_per_frame, pos; + pjmedia_codec *codec = NULL; + const pjmedia_codec_info *ci[1]; + pjmedia_codec_param codec_param; + pjmedia_frame out_frame; + void *pkt; + FILE *input = NULL, *output = NULL, *fref = NULL; + pj_bool_t is_itu_format = PJ_FALSE; + int rc = 0; + pj_status_t status; + + pool = pj_pool_create(mem, "codec-vectors", 512, 512, NULL); + if (!pool) { + rc = -20; + goto on_return; + } + + /* Find and open the codec */ + count = 1; + status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id, &count, ci, NULL); + if (status != PJ_SUCCESS) { + rc = -30; + goto on_return; + } + + status = pjmedia_codec_mgr_alloc_codec(mgr, ci[0], &codec); + if (status != PJ_SUCCESS) { + rc = -40; + goto on_return; + } + + status = pjmedia_codec_mgr_get_default_param(mgr, ci[0], &codec_param); + if (status != PJ_SUCCESS) { + rc = -50; + goto on_return; + } + + codec_param.info.avg_bps = bitrate; + codec_param.setting.vad = 0; + + status = pjmedia_codec_init(codec, pool); + if (status != PJ_SUCCESS) { + rc = -60; + goto on_return; + } + + status = pjmedia_codec_open(codec, &codec_param); + if (status != PJ_SUCCESS) { + rc = -70; + goto on_return; + } + + /* Open input file */ + input = fopen(in_encoded_file, "rb"); + if (!input) { + rc = -80; + goto on_return; + } + + /* Is the file in ITU format? */ + is_itu_format = pj_ansi_stricmp(in_encoded_file+strlen(in_encoded_file)-4, + ".itu")==0; + + /* Open output file */ + output = fopen(TMP_OUT, "wb"); + if (!output) { + rc = -90; + goto on_return; + } + + /* Allocate buffer for PCM and encoded frames */ + samples_per_frame = codec_param.info.clock_rate * codec_param.info.frm_ptime / 1000; + pkt = pj_pool_alloc(pool, samples_per_frame * 2); + out_frame.buf = (pj_uint8_t*) pj_pool_alloc(pool, samples_per_frame * 2); + + /* Loop read WAV file and encode and write to output file */ + for (;;) { + pjmedia_frame in_frame[2]; + pj_timestamp ts; + unsigned count; + pj_bool_t has_frame; + + if (is_itu_format) { + int nsamp; + short frame_err = 0; + + nsamp = read_ITU_format(input, (short*)pkt, &frame_err, + encoded_len / 2, PJ_TRUE); + if (nsamp != (int)encoded_len / 2) + break; + + has_frame = !frame_err; + } else { + if (fread(pkt, encoded_len, 1, input) != 1) + break; + + has_frame = PJ_TRUE; + } + + if (has_frame) { + count = 2; + if (pjmedia_codec_parse(codec, pkt, encoded_len, &ts, + &count, in_frame) != PJ_SUCCESS) + { + rc = -100; + goto on_return; + } + + if (count != 1) { + rc = -110; + goto on_return; + } + + if (pjmedia_codec_decode(codec, &in_frame[0], samples_per_frame*2, + &out_frame) != PJ_SUCCESS) + { + rc = -120; + goto on_return; + } + } else { + if (pjmedia_codec_recover(codec, samples_per_frame*2, + &out_frame) != PJ_SUCCESS) + { + rc = -125; + goto on_return; + } + } + + if (manip) + manip((short*)out_frame.buf, samples_per_frame); + + if (fwrite(out_frame.buf, out_frame.size, 1, output) != 1) { + rc = -130; + goto on_return; + } + } + + fclose(input); + input = NULL; + + fclose(output); + output = NULL; + + /* Compare encoded files */ + fref = fopen(ref_pcm_file, "rb"); + if (!fref) { + rc = -140; + goto on_return; + } + + output = fopen(TMP_OUT, "rb"); + if (!output) { + rc = -110; + goto on_return; + } + + pos = 0; + for (;;) { + int count; + + count = fread(pkt, samples_per_frame*2, 1, fref); + if (count != 1) + break; + + count = fread(out_frame.buf, samples_per_frame*2, 1, output); + if (count != 1) + break; + + if (memcmp(pkt, out_frame.buf, samples_per_frame*2)) { + unsigned i; + pj_int16_t *in = (pj_int16_t*)pkt; + pj_int16_t *out = (pj_int16_t*)out_frame.buf; + + for (i=0; i<samples_per_frame; ++i) { + if (in[i] != out[i]) + break; + } + + PJ_LOG(1,(THIS_FILE," failed: mismatch at samples %d", pos+i)); + rc = -200; + break; + } + + pos += samples_per_frame; + } + +on_return: + if (output) + fclose(output); + + if (fref) + fclose(fref); + + if (input) + fclose(input); + + if (codec) { + pjmedia_codec_close(codec); + pjmedia_codec_mgr_dealloc_codec(mgr, codec); + } + + if (pool) + pj_pool_release(pool); + + return rc; +} + +#if PJMEDIA_HAS_G7221_CODEC +/* For ITU testing, off the 2 lsbs. */ +static void g7221_pcm_manip(short *pcm, unsigned count) +{ + unsigned i; + for (i=0; i<count; i++) + pcm[i] &= 0xfffc; + +} +#endif /* PJMEDIA_HAS_G7221_CODEC */ + +int codec_test_vectors(void) +{ + pjmedia_endpt *endpt; + pjmedia_codec_mgr *mgr; + int rc, rc_final = 0; + struct enc_vectors { + char *codec_name; + unsigned bit_rate; + const char *wav_file; + const char *ref_encoded_file; + } enc_vectors[] = + { +#if PJMEDIA_HAS_G7221_CODEC + { "G7221/16000/1", 24000, + "../src/test/vectors/g722_1_enc_in.wav", + "../src/test/vectors/g722_1_enc_out_24000_be.pak" + }, + { "G7221/16000/1", 32000, + "../src/test/vectors/g722_1_enc_in.wav", + "../src/test/vectors/g722_1_enc_out_32000_be.pak" + }, +#endif + { NULL } + }; + struct dec_vectors { + char *codec_name; + unsigned bit_rate; + unsigned encoded_frame_len; + void (*manip)(short *pcm, unsigned count); + const char *enc_file; + const char *ref_pcm_file; + } dec_vectors[] = + { +#if PJMEDIA_HAS_G7221_CODEC + { "G7221/16000/1", 24000, 60, + &g7221_pcm_manip, + "../src/test/vectors/g722_1_enc_out_24000_be.pak", + "../src/test/vectors/g722_1_dec_out_24000.pcm" + }, + { "G7221/16000/1", 32000, 80, + &g7221_pcm_manip, + "../src/test/vectors/g722_1_enc_out_32000_be.pak", + "../src/test/vectors/g722_1_dec_out_32000.pcm" + }, + { "G7221/16000/1", 24000, 60, + &g7221_pcm_manip, + "../src/test/vectors/g722_1_dec_in_24000_fe.itu", + "../src/test/vectors/g722_1_dec_out_24000_fe.pcm" + }, + { "G7221/16000/1", 32000, 80, + &g7221_pcm_manip, + "../src/test/vectors/g722_1_dec_in_32000_fe.itu", + "../src/test/vectors/g722_1_dec_out_32000_fe.pcm" + }, +#endif + { NULL } + }; + unsigned i; + pj_status_t status; + + status = pjmedia_endpt_create(mem, NULL, 0, &endpt); + if (status != PJ_SUCCESS) + return -5; + + mgr = pjmedia_endpt_get_codec_mgr(endpt); + +#if PJMEDIA_HAS_G7221_CODEC + status = pjmedia_codec_g7221_init(endpt); + if (status != PJ_SUCCESS) { + pjmedia_endpt_destroy(endpt); + return -7; + } + + /* Set shift value to zero for the test vectors */ + pjmedia_codec_g7221_set_pcm_shift(0); +#endif + + PJ_LOG(3,(THIS_FILE," encode tests:")); + for (i=0; i<PJ_ARRAY_SIZE(enc_vectors); ++i) { + if (!enc_vectors[i].codec_name) + continue; + PJ_LOG(3,(THIS_FILE," %s @%d bps %s ==> %s", + enc_vectors[i].codec_name, + enc_vectors[i].bit_rate, + enc_vectors[i].wav_file, + enc_vectors[i].ref_encoded_file)); + rc = codec_test_encode(mgr, enc_vectors[i].codec_name, + enc_vectors[i].bit_rate, + enc_vectors[i].wav_file, + enc_vectors[i].ref_encoded_file); + if (rc != 0) + rc_final = rc; + } + + PJ_LOG(3,(THIS_FILE," decode tests:")); + for (i=0; i<PJ_ARRAY_SIZE(dec_vectors); ++i) { + if (!dec_vectors[i].codec_name) + continue; + PJ_LOG(3,(THIS_FILE," %s @%d bps %s ==> %s", + dec_vectors[i].codec_name, + dec_vectors[i].bit_rate, + dec_vectors[i].enc_file, + dec_vectors[i].ref_pcm_file)); + rc = codec_test_decode(mgr, dec_vectors[i].codec_name, + dec_vectors[i].bit_rate, + dec_vectors[i].encoded_frame_len, + dec_vectors[i].enc_file, + dec_vectors[i].ref_pcm_file, + dec_vectors[i].manip); + if (rc != 0) + rc_final = rc; + } + + if (pj_file_exists(TMP_OUT)) + pj_file_delete(TMP_OUT); + + pjmedia_endpt_destroy(endpt); + return rc_final; +} + |