blob: 0c4b81ca2e350621920fc96b27a9d135d54f8ef9 [file] [log] [blame]
Benny Prijono1dc0da72009-04-18 00:12:13 +00001/* $Id$ */
2/*
3 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include "test.h"
20#include <pjmedia-codec.h>
21
22#define THIS_FILE "codec_vectors.c"
23#define TMP_OUT "output.tmp"
24
Benny Prijono8604b142009-04-18 11:49:54 +000025/*
26 * Encode test. Read input from WAV file, encode to temporary output file,
27 * and compare the temporary output file to the reference file.
28 */
Benny Prijono1dc0da72009-04-18 00:12:13 +000029static int codec_test_encode(pjmedia_codec_mgr *mgr,
30 char *codec_name,
31 unsigned bitrate,
32 const char *wav_file,
Benny Prijono8604b142009-04-18 11:49:54 +000033 const char *ref_encoded_file)
Benny Prijono1dc0da72009-04-18 00:12:13 +000034{
35 pj_str_t codec_id = pj_str(codec_name);
36 pj_pool_t *pool = NULL;
37 unsigned count, samples_per_frame, encoded_frame_len = 0, pos;
38 pjmedia_codec *codec = NULL;
39 const pjmedia_codec_info *ci[1];
40 pjmedia_codec_param codec_param;
41 pjmedia_port *wav_port = NULL;
42 pjmedia_frame in_frame, out_frame;
43 FILE *output = NULL, *fref = NULL;
44 int rc = 0;
45 pj_status_t status;
46
47 pool = pj_pool_create(mem, "codec-vectors", 512, 512, NULL);
48 if (!pool) {
49 rc = -20;
50 goto on_return;
51 }
52
53 /* Find and open the codec */
54 count = 1;
55 status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id, &count, ci, NULL);
56 if (status != PJ_SUCCESS) {
57 rc = -30;
58 goto on_return;
59 }
60
61 status = pjmedia_codec_mgr_alloc_codec(mgr, ci[0], &codec);
62 if (status != PJ_SUCCESS) {
63 rc = -40;
64 goto on_return;
65 }
66
67 status = pjmedia_codec_mgr_get_default_param(mgr, ci[0], &codec_param);
68 if (status != PJ_SUCCESS) {
69 rc = -50;
70 goto on_return;
71 }
72
73 codec_param.info.avg_bps = bitrate;
74 codec_param.setting.vad = 0;
75
76 status = codec->op->init(codec, pool);
77 if (status != PJ_SUCCESS) {
78 rc = -60;
79 goto on_return;
80 }
81
82 status = codec->op->open(codec, &codec_param);
83 if (status != PJ_SUCCESS) {
84 rc = -70;
85 goto on_return;
86 }
87
88 /* Open WAV file */
89 status = pjmedia_wav_player_port_create(pool, wav_file,
90 codec_param.info.frm_ptime,
91 PJMEDIA_FILE_NO_LOOP, 0,
92 &wav_port);
93 if (status != PJ_SUCCESS) {
94 rc = -80;
95 goto on_return;
96 }
97
98 /* Open output file */
99 output = fopen(TMP_OUT, "wb");
100 if (!output) {
101 rc = -90;
102 goto on_return;
103 }
104
105 /* Allocate buffer for PCM and encoded frames */
106 samples_per_frame = codec_param.info.clock_rate * codec_param.info.frm_ptime / 1000;
107 in_frame.buf = pj_pool_alloc(pool, samples_per_frame * 2);
108 out_frame.buf = (pj_uint8_t*) pj_pool_alloc(pool, samples_per_frame);
109
110 /* Loop read WAV file and encode and write to output file */
111 for (;;) {
112 in_frame.size = samples_per_frame * 2;
113 in_frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
114
115 status = pjmedia_port_get_frame(wav_port, &in_frame);
116 if (status != PJ_SUCCESS || in_frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
117 break;
118
119 out_frame.size = samples_per_frame;
120 status = codec->op->encode(codec, &in_frame, samples_per_frame,
121 &out_frame);
122 if (status != PJ_SUCCESS) {
123 rc = -95;
124 goto on_return;
125 }
126
127 if (out_frame.size) {
128 fwrite(out_frame.buf, out_frame.size, 1, output);
129
130 if (encoded_frame_len == 0)
131 encoded_frame_len = out_frame.size;
132 } }
133
134 fclose(output);
135 output = NULL;
136
137 /* Compare encoded files */
Benny Prijono8604b142009-04-18 11:49:54 +0000138 fref = fopen(ref_encoded_file, "rb");
Benny Prijono1dc0da72009-04-18 00:12:13 +0000139 if (!fref) {
140 rc = -100;
141 goto on_return;
142 }
143
144 output = fopen(TMP_OUT, "rb");
145 if (!output) {
146 rc = -110;
147 goto on_return;
148 }
149
150 pos = 0;
151 for (;;) {
152 int count;
153
154 count = fread(in_frame.buf, encoded_frame_len, 1, fref);
155 if (count != 1)
156 break;
157
158 count = fread(out_frame.buf, encoded_frame_len, 1, output);
159 if (count != 1)
160 break;
161
162 if (memcmp(in_frame.buf, out_frame.buf, encoded_frame_len)) {
163 unsigned i;
164 pj_uint8_t *in = (pj_uint8_t*)in_frame.buf;
165 pj_uint8_t *out = (pj_uint8_t*)out_frame.buf;
166
167 for (i=0; i<encoded_frame_len; ++i) {
168 if (in[i] != out[i])
169 break;
170 }
171
172 PJ_LOG(1,(THIS_FILE," failed: mismatch at pos %d", pos+i));
173 rc = -200;
174 break;
175 }
176
177 pos += encoded_frame_len;
178 }
179
180on_return:
181 if (output)
182 fclose(output);
183
184 if (fref)
185 fclose(fref);
186
187 if (codec) {
188 codec->op->close(codec);
189 pjmedia_codec_mgr_dealloc_codec(mgr, codec);
190 }
191
192 if (wav_port)
193 pjmedia_port_destroy(wav_port);
194
195 if (pool)
196 pj_pool_release(pool);
197
198 return rc;
199}
200
201
Benny Prijono8604b142009-04-18 11:49:54 +0000202/*
203 * Read file in ITU format (".itu" extension).
204 *
205 * Set swap_endian to TRUE if the ITU file is stored in little
206 * endian format (normally true).
207 */
208static int read_ITU_format(FILE *fp_bitstream,
209 short *out_words,
210 short *p_frame_error_flag,
211 int number_of_16bit_words_per_frame,
212 pj_bool_t swap_endian)
213{
214 enum { MAX_BITS_PER_FRAME = 160*8 };
215 short i,j;
216 short nsamp;
217 short packed_word;
218 short bit_count;
219 short bit;
220 short in_array[MAX_BITS_PER_FRAME+2];
221 short one = 0x0081;
222 short zero = 0x007f;
223 short frame_start = 0x6b21;
Benny Prijono1dc0da72009-04-18 00:12:13 +0000224
Benny Prijono8604b142009-04-18 11:49:54 +0000225 nsamp = fread(in_array, 2, 2 + 16*number_of_16bit_words_per_frame,
226 fp_bitstream);
227
228 j = 0;
229 bit = in_array[j++];
230 if (bit != frame_start) {
231 *p_frame_error_flag = 1;
232 } else {
233 *p_frame_error_flag = 0;
234
235 /* increment j to skip over the number of bits in frame */
236 j++;
237
238 for (i=0; i<number_of_16bit_words_per_frame; i++) {
239 packed_word = 0;
240 bit_count = 15;
241 while (bit_count >= 0) {
242 bit = in_array[j++];
243 if (bit == zero)
244 bit = 0;
245 else if (bit == one)
246 bit = 1;
247 else
248 *p_frame_error_flag = 1;
249
250 packed_word <<= 1;
251 packed_word = (short )(packed_word + bit);
252 bit_count--;
253 }
254
255 if (swap_endian)
256 out_words[i] = pj_ntohs(packed_word);
257 else
258 out_words[i] = packed_word;
259 }
260 }
261 return (nsamp-1)/16;
262}
263
264
265/*
266 * Decode test
267 *
268 * Decode the specified encoded file in "in_encoded_file" into temporary
269 * PCM output file, and compare the temporary PCM output file with
270 * the PCM reference file.
271 *
272 * Some reference file requires manipulation to the PCM output
273 * before comparison, such manipulation can be done by supplying
274 * this function with the "manip" function.
275 */
Benny Prijono1dc0da72009-04-18 00:12:13 +0000276static int codec_test_decode(pjmedia_codec_mgr *mgr,
277 char *codec_name,
278 unsigned bitrate,
279 unsigned encoded_len,
Benny Prijono8604b142009-04-18 11:49:54 +0000280 const char *in_encoded_file,
281 const char *ref_pcm_file,
Benny Prijono1dc0da72009-04-18 00:12:13 +0000282 void (*manip)(short *pcm, unsigned count))
283{
284 pj_str_t codec_id = pj_str(codec_name);
285 pj_pool_t *pool = NULL;
286 unsigned count, samples_per_frame, pos;
287 pjmedia_codec *codec = NULL;
288 const pjmedia_codec_info *ci[1];
289 pjmedia_codec_param codec_param;
290 pjmedia_frame out_frame;
291 void *pkt;
292 FILE *input = NULL, *output = NULL, *fref = NULL;
Benny Prijono8604b142009-04-18 11:49:54 +0000293 pj_bool_t is_itu_format = PJ_FALSE;
Benny Prijono1dc0da72009-04-18 00:12:13 +0000294 int rc = 0;
295 pj_status_t status;
296
297 pool = pj_pool_create(mem, "codec-vectors", 512, 512, NULL);
298 if (!pool) {
299 rc = -20;
300 goto on_return;
301 }
302
303 /* Find and open the codec */
304 count = 1;
305 status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id, &count, ci, NULL);
306 if (status != PJ_SUCCESS) {
307 rc = -30;
308 goto on_return;
309 }
310
311 status = pjmedia_codec_mgr_alloc_codec(mgr, ci[0], &codec);
312 if (status != PJ_SUCCESS) {
313 rc = -40;
314 goto on_return;
315 }
316
317 status = pjmedia_codec_mgr_get_default_param(mgr, ci[0], &codec_param);
318 if (status != PJ_SUCCESS) {
319 rc = -50;
320 goto on_return;
321 }
322
323 codec_param.info.avg_bps = bitrate;
324 codec_param.setting.vad = 0;
325
326 status = codec->op->init(codec, pool);
327 if (status != PJ_SUCCESS) {
328 rc = -60;
329 goto on_return;
330 }
331
332 status = codec->op->open(codec, &codec_param);
333 if (status != PJ_SUCCESS) {
334 rc = -70;
335 goto on_return;
336 }
337
338 /* Open input file */
Benny Prijono8604b142009-04-18 11:49:54 +0000339 input = fopen(in_encoded_file, "rb");
Benny Prijono1dc0da72009-04-18 00:12:13 +0000340 if (!input) {
341 rc = -80;
342 goto on_return;
343 }
344
Benny Prijono8604b142009-04-18 11:49:54 +0000345 /* Is the file in ITU format? */
346 is_itu_format = pj_ansi_stricmp(in_encoded_file+strlen(in_encoded_file)-4,
347 ".itu")==0;
348
Benny Prijono1dc0da72009-04-18 00:12:13 +0000349 /* Open output file */
350 output = fopen(TMP_OUT, "wb");
351 if (!output) {
352 rc = -90;
353 goto on_return;
354 }
355
356 /* Allocate buffer for PCM and encoded frames */
357 samples_per_frame = codec_param.info.clock_rate * codec_param.info.frm_ptime / 1000;
358 pkt = pj_pool_alloc(pool, samples_per_frame * 2);
359 out_frame.buf = (pj_uint8_t*) pj_pool_alloc(pool, samples_per_frame * 2);
360
361 /* Loop read WAV file and encode and write to output file */
362 for (;;) {
363 pjmedia_frame in_frame[2];
364 pj_timestamp ts;
365 unsigned count;
Benny Prijono8604b142009-04-18 11:49:54 +0000366 pj_bool_t has_frame;
Benny Prijono1dc0da72009-04-18 00:12:13 +0000367
Benny Prijono8604b142009-04-18 11:49:54 +0000368 if (is_itu_format) {
369 int nsamp;
370 short frame_err = 0;
Benny Prijono1dc0da72009-04-18 00:12:13 +0000371
Benny Prijono8604b142009-04-18 11:49:54 +0000372 nsamp = read_ITU_format(input, (short*)pkt, &frame_err,
373 encoded_len / 2, PJ_TRUE);
374 if (nsamp != (int)encoded_len / 2)
375 break;
376
377 has_frame = !frame_err;
378 } else {
379 if (fread(pkt, encoded_len, 1, input) != 1)
380 break;
381
382 has_frame = PJ_TRUE;
Benny Prijono1dc0da72009-04-18 00:12:13 +0000383 }
384
Benny Prijono8604b142009-04-18 11:49:54 +0000385 if (has_frame) {
386 count = 2;
387 if (codec->op->parse(codec, pkt, encoded_len, &ts,
388 &count, in_frame) != PJ_SUCCESS)
389 {
390 rc = -100;
391 goto on_return;
392 }
Benny Prijono1dc0da72009-04-18 00:12:13 +0000393
Benny Prijono8604b142009-04-18 11:49:54 +0000394 if (count != 1) {
395 rc = -110;
396 goto on_return;
397 }
398
399 if (codec->op->decode(codec, &in_frame[0], samples_per_frame*2,
400 &out_frame) != PJ_SUCCESS)
401 {
402 rc = -120;
403 goto on_return;
404 }
405 } else {
406 if (codec->op->recover(codec, samples_per_frame*2,
407 &out_frame) != PJ_SUCCESS)
408 {
409 rc = -125;
410 goto on_return;
411 }
Benny Prijono1dc0da72009-04-18 00:12:13 +0000412 }
413
414 if (manip)
415 manip((short*)out_frame.buf, samples_per_frame);
416
417 if (fwrite(out_frame.buf, out_frame.size, 1, output) != 1) {
418 rc = -130;
419 goto on_return;
420 }
421 }
422
423 fclose(input);
424 input = NULL;
425
426 fclose(output);
427 output = NULL;
428
429 /* Compare encoded files */
Benny Prijono8604b142009-04-18 11:49:54 +0000430 fref = fopen(ref_pcm_file, "rb");
Benny Prijono1dc0da72009-04-18 00:12:13 +0000431 if (!fref) {
432 rc = -140;
433 goto on_return;
434 }
435
436 output = fopen(TMP_OUT, "rb");
437 if (!output) {
438 rc = -110;
439 goto on_return;
440 }
441
442 pos = 0;
443 for (;;) {
444 int count;
445
446 count = fread(pkt, samples_per_frame*2, 1, fref);
447 if (count != 1)
448 break;
449
450 count = fread(out_frame.buf, samples_per_frame*2, 1, output);
451 if (count != 1)
452 break;
453
454 if (memcmp(pkt, out_frame.buf, samples_per_frame*2)) {
455 unsigned i;
456 pj_int16_t *in = (pj_int16_t*)pkt;
457 pj_int16_t *out = (pj_int16_t*)out_frame.buf;
458
459 for (i=0; i<samples_per_frame; ++i) {
460 if (in[i] != out[i])
461 break;
462 }
463
464 PJ_LOG(1,(THIS_FILE," failed: mismatch at samples %d", pos+i));
465 rc = -200;
466 break;
467 }
468
469 pos += samples_per_frame;
470 }
471
472on_return:
473 if (output)
474 fclose(output);
475
476 if (fref)
477 fclose(fref);
478
479 if (input)
480 fclose(input);
481
482 if (codec) {
483 codec->op->close(codec);
484 pjmedia_codec_mgr_dealloc_codec(mgr, codec);
485 }
486
487 if (pool)
488 pj_pool_release(pool);
489
490 return rc;
491}
492
493
494/* For ITU testing, off the 2 lsbs. */
495static void g7221_pcm_manip(short *pcm, unsigned count)
496{
497 unsigned i;
498 for (i=0; i<count; i++)
499 pcm[i] &= 0xfffc;
500
501}
502
503int codec_test_vectors(void)
504{
505 pjmedia_endpt *endpt;
506 pjmedia_codec_mgr *mgr;
507 int rc, rc_final = 0;
508 struct enc_vectors {
509 char *codec_name;
510 unsigned bit_rate;
511 const char *wav_file;
Benny Prijono8604b142009-04-18 11:49:54 +0000512 const char *ref_encoded_file;
Benny Prijono1dc0da72009-04-18 00:12:13 +0000513 } enc_vectors[] =
514 {
515#if PJMEDIA_HAS_G7221_CODEC
516 { "G7221/16000/1", 24000,
517 "../src/test/vectors/g722_1_enc_in.wav",
518 "../src/test/vectors/g722_1_enc_out_24000_be.pak"
519 },
520 { "G7221/16000/1", 32000,
521 "../src/test/vectors/g722_1_enc_in.wav",
522 "../src/test/vectors/g722_1_enc_out_32000_be.pak"
523 },
524#endif
Benny Prijonod4c751e2009-04-18 00:34:45 +0000525 { NULL }
Benny Prijono1dc0da72009-04-18 00:12:13 +0000526 };
527 struct dec_vectors {
528 char *codec_name;
529 unsigned bit_rate;
530 unsigned encoded_frame_len;
531 void (*manip)(short *pcm, unsigned count);
532 const char *enc_file;
Benny Prijono8604b142009-04-18 11:49:54 +0000533 const char *ref_pcm_file;
Benny Prijono1dc0da72009-04-18 00:12:13 +0000534 } dec_vectors[] =
535 {
536#if PJMEDIA_HAS_G7221_CODEC
537 { "G7221/16000/1", 24000, 60,
538 &g7221_pcm_manip,
539 "../src/test/vectors/g722_1_enc_out_24000_be.pak",
540 "../src/test/vectors/g722_1_dec_out_24000.pcm"
541 },
542 { "G7221/16000/1", 32000, 80,
543 &g7221_pcm_manip,
544 "../src/test/vectors/g722_1_enc_out_32000_be.pak",
545 "../src/test/vectors/g722_1_dec_out_32000.pcm"
546 },
Benny Prijono8604b142009-04-18 11:49:54 +0000547 { "G7221/16000/1", 24000, 60,
548 &g7221_pcm_manip,
549 "../src/test/vectors/g722_1_dec_in_24000_fe.itu",
550 "../src/test/vectors/g722_1_dec_out_24000_fe.pcm"
551 },
552 { "G7221/16000/1", 32000, 80,
553 &g7221_pcm_manip,
554 "../src/test/vectors/g722_1_dec_in_32000_fe.itu",
555 "../src/test/vectors/g722_1_dec_out_32000_fe.pcm"
556 },
Benny Prijono1dc0da72009-04-18 00:12:13 +0000557#endif
Benny Prijonod4c751e2009-04-18 00:34:45 +0000558 { NULL }
Benny Prijono1dc0da72009-04-18 00:12:13 +0000559 };
560 unsigned i;
561 pj_status_t status;
562
563 status = pjmedia_endpt_create(mem, NULL, 0, &endpt);
564 if (status != PJ_SUCCESS)
565 return -5;
566
567 mgr = pjmedia_endpt_get_codec_mgr(endpt);
568
569#if PJMEDIA_HAS_G7221_CODEC
570 status = pjmedia_codec_g7221_init(endpt);
571 if (status != PJ_SUCCESS) {
572 pjmedia_endpt_destroy(endpt);
573 return -7;
574 }
Benny Prijono8496b932009-04-20 14:19:11 +0000575
576 /* Set shift value to zero for the test vectors */
577 pjmedia_codec_g7221_set_pcm_shift(0);
Benny Prijono1dc0da72009-04-18 00:12:13 +0000578#endif
579
580 PJ_LOG(3,(THIS_FILE," encode tests:"));
581 for (i=0; i<PJ_ARRAY_SIZE(enc_vectors); ++i) {
Benny Prijonod4c751e2009-04-18 00:34:45 +0000582 if (!enc_vectors[i].codec_name)
583 continue;
Benny Prijono8604b142009-04-18 11:49:54 +0000584 PJ_LOG(3,(THIS_FILE," %s @%d bps %s ==> %s",
585 enc_vectors[i].codec_name,
586 enc_vectors[i].bit_rate,
587 enc_vectors[i].wav_file,
588 enc_vectors[i].ref_encoded_file));
Benny Prijono1dc0da72009-04-18 00:12:13 +0000589 rc = codec_test_encode(mgr, enc_vectors[i].codec_name,
590 enc_vectors[i].bit_rate,
591 enc_vectors[i].wav_file,
Benny Prijono8604b142009-04-18 11:49:54 +0000592 enc_vectors[i].ref_encoded_file);
Benny Prijono1dc0da72009-04-18 00:12:13 +0000593 if (rc != 0)
594 rc_final = rc;
595 }
596
597 PJ_LOG(3,(THIS_FILE," decode tests:"));
598 for (i=0; i<PJ_ARRAY_SIZE(dec_vectors); ++i) {
Benny Prijonod4c751e2009-04-18 00:34:45 +0000599 if (!dec_vectors[i].codec_name)
600 continue;
Benny Prijono8604b142009-04-18 11:49:54 +0000601 PJ_LOG(3,(THIS_FILE," %s @%d bps %s ==> %s",
602 dec_vectors[i].codec_name,
603 dec_vectors[i].bit_rate,
604 dec_vectors[i].enc_file,
605 dec_vectors[i].ref_pcm_file));
Benny Prijono1dc0da72009-04-18 00:12:13 +0000606 rc = codec_test_decode(mgr, dec_vectors[i].codec_name,
607 dec_vectors[i].bit_rate,
608 dec_vectors[i].encoded_frame_len,
609 dec_vectors[i].enc_file,
Benny Prijono8604b142009-04-18 11:49:54 +0000610 dec_vectors[i].ref_pcm_file,
Benny Prijono1dc0da72009-04-18 00:12:13 +0000611 dec_vectors[i].manip);
612 if (rc != 0)
613 rc_final = rc;
614 }
615
616 if (pj_file_exists(TMP_OUT))
617 pj_file_delete(TMP_OUT);
618
619 pjmedia_endpt_destroy(endpt);
620 return rc_final;
621}
622