blob: 823d4cffd8efbd0398f5c71e7cdec83f1bb94c1e [file] [log] [blame]
Alexandre Lision67916dd2014-01-24 13:33:04 -05001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 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
25/*
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 */
29static int codec_test_encode(pjmedia_codec_mgr *mgr,
30 char *codec_name,
31 unsigned bitrate,
32 const char *wav_file,
33 const char *ref_encoded_file)
34{
35 pj_str_t codec_id = pj_str(codec_name);
36 pj_pool_t *pool = NULL;
37 unsigned count, samples_per_frame;
38 pj_size_t encoded_frame_len = 0, pos;
39 pjmedia_codec *codec = NULL;
40 const pjmedia_codec_info *ci[1];
41 pjmedia_codec_param codec_param;
42 pjmedia_port *wav_port = NULL;
43 pjmedia_frame in_frame, out_frame;
44 FILE *output = NULL, *fref = NULL;
45 int rc = 0;
46 pj_status_t status;
47
48 pool = pj_pool_create(mem, "codec-vectors", 512, 512, NULL);
49 if (!pool) {
50 rc = -20;
51 goto on_return;
52 }
53
54 /* Find and open the codec */
55 count = 1;
56 status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id, &count, ci, NULL);
57 if (status != PJ_SUCCESS) {
58 rc = -30;
59 goto on_return;
60 }
61
62 status = pjmedia_codec_mgr_alloc_codec(mgr, ci[0], &codec);
63 if (status != PJ_SUCCESS) {
64 rc = -40;
65 goto on_return;
66 }
67
68 status = pjmedia_codec_mgr_get_default_param(mgr, ci[0], &codec_param);
69 if (status != PJ_SUCCESS) {
70 rc = -50;
71 goto on_return;
72 }
73
74 codec_param.info.avg_bps = bitrate;
75 codec_param.setting.vad = 0;
76
77 status = pjmedia_codec_init(codec, pool);
78 if (status != PJ_SUCCESS) {
79 rc = -60;
80 goto on_return;
81 }
82
83 status = pjmedia_codec_open(codec, &codec_param);
84 if (status != PJ_SUCCESS) {
85 rc = -70;
86 goto on_return;
87 }
88
89 /* Open WAV file */
90 status = pjmedia_wav_player_port_create(pool, wav_file,
91 codec_param.info.frm_ptime,
92 PJMEDIA_FILE_NO_LOOP, 0,
93 &wav_port);
94 if (status != PJ_SUCCESS) {
95 rc = -80;
96 goto on_return;
97 }
98
99 /* Open output file */
100 output = fopen(TMP_OUT, "wb");
101 if (!output) {
102 rc = -90;
103 goto on_return;
104 }
105
106 /* Allocate buffer for PCM and encoded frames */
107 samples_per_frame = codec_param.info.clock_rate * codec_param.info.frm_ptime / 1000;
108 in_frame.buf = pj_pool_alloc(pool, samples_per_frame * 2);
109 out_frame.buf = (pj_uint8_t*) pj_pool_alloc(pool, samples_per_frame);
110
111 /* Loop read WAV file and encode and write to output file */
112 for (;;) {
113 in_frame.size = samples_per_frame * 2;
114 in_frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
115
116 status = pjmedia_port_get_frame(wav_port, &in_frame);
117 if (status != PJ_SUCCESS || in_frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
118 break;
119
120 out_frame.size = samples_per_frame;
121 status = pjmedia_codec_encode(codec, &in_frame, samples_per_frame,
122 &out_frame);
123 if (status != PJ_SUCCESS) {
124 rc = -95;
125 goto on_return;
126 }
127
128 if (out_frame.size) {
129 pj_size_t cnt;
130
131 cnt = fwrite(out_frame.buf, out_frame.size, 1, output);
132
133 if (encoded_frame_len == 0)
134 encoded_frame_len = out_frame.size;
135 }
136 }
137
138 fclose(output);
139 output = NULL;
140
141 /* Compare encoded files */
142 fref = fopen(ref_encoded_file, "rb");
143 if (!fref) {
144 rc = -100;
145 goto on_return;
146 }
147
148 output = fopen(TMP_OUT, "rb");
149 if (!output) {
150 rc = -110;
151 goto on_return;
152 }
153
154 pos = 0;
155 for (;;) {
156 pj_size_t count;
157
158 count = fread(in_frame.buf, encoded_frame_len, 1, fref);
159 if (count != 1)
160 break;
161
162 count = fread(out_frame.buf, encoded_frame_len, 1, output);
163 if (count != 1)
164 break;
165
166 if (memcmp(in_frame.buf, out_frame.buf, encoded_frame_len)) {
167 unsigned i;
168 pj_uint8_t *in = (pj_uint8_t*)in_frame.buf;
169 pj_uint8_t *out = (pj_uint8_t*)out_frame.buf;
170
171 for (i=0; i<encoded_frame_len; ++i) {
172 if (in[i] != out[i])
173 break;
174 }
175
176 PJ_LOG(1,(THIS_FILE," failed: mismatch at pos %d", pos+i));
177 rc = -200;
178 break;
179 }
180
181 pos += encoded_frame_len;
182 }
183
184on_return:
185 if (output)
186 fclose(output);
187
188 if (fref)
189 fclose(fref);
190
191 if (codec) {
192 pjmedia_codec_close(codec);
193 pjmedia_codec_mgr_dealloc_codec(mgr, codec);
194 }
195
196 if (wav_port)
197 pjmedia_port_destroy(wav_port);
198
199 if (pool)
200 pj_pool_release(pool);
201
202 return rc;
203}
204
205
206/*
207 * Read file in ITU format (".itu" extension).
208 *
209 * Set swap_endian to TRUE if the ITU file is stored in little
210 * endian format (normally true).
211 */
212static int read_ITU_format(FILE *fp_bitstream,
213 short *out_words,
214 short *p_frame_error_flag,
215 int number_of_16bit_words_per_frame,
216 pj_bool_t swap_endian)
217{
218 enum { MAX_BITS_PER_FRAME = 160*8 };
219 short i,j;
220 short nsamp;
221 short packed_word;
222 short bit_count;
223 short bit;
224 short in_array[MAX_BITS_PER_FRAME+2];
225 short one = 0x0081;
226 short zero = 0x007f;
227 short frame_start = 0x6b21;
228
229 nsamp = (short)fread(in_array, 2, 2 + 16*number_of_16bit_words_per_frame,
230 fp_bitstream);
231
232 j = 0;
233 bit = in_array[j++];
234 if (bit != frame_start) {
235 *p_frame_error_flag = 1;
236 } else {
237 *p_frame_error_flag = 0;
238
239 /* increment j to skip over the number of bits in frame */
240 j++;
241
242 for (i=0; i<number_of_16bit_words_per_frame; i++) {
243 packed_word = 0;
244 bit_count = 15;
245 while (bit_count >= 0) {
246 bit = in_array[j++];
247 if (bit == zero)
248 bit = 0;
249 else if (bit == one)
250 bit = 1;
251 else
252 *p_frame_error_flag = 1;
253
254 packed_word <<= 1;
255 packed_word = (short )(packed_word + bit);
256 bit_count--;
257 }
258
259 if (swap_endian)
260 out_words[i] = pj_ntohs(packed_word);
261 else
262 out_words[i] = packed_word;
263 }
264 }
265 return (nsamp-1)/16;
266}
267
268
269/*
270 * Decode test
271 *
272 * Decode the specified encoded file in "in_encoded_file" into temporary
273 * PCM output file, and compare the temporary PCM output file with
274 * the PCM reference file.
275 *
276 * Some reference file requires manipulation to the PCM output
277 * before comparison, such manipulation can be done by supplying
278 * this function with the "manip" function.
279 */
280static int codec_test_decode(pjmedia_codec_mgr *mgr,
281 char *codec_name,
282 unsigned bitrate,
283 unsigned encoded_len,
284 const char *in_encoded_file,
285 const char *ref_pcm_file,
286 void (*manip)(short *pcm, unsigned count))
287{
288 pj_str_t codec_id = pj_str(codec_name);
289 pj_pool_t *pool = NULL;
290 unsigned count, samples_per_frame, pos;
291 pjmedia_codec *codec = NULL;
292 const pjmedia_codec_info *ci[1];
293 pjmedia_codec_param codec_param;
294 pjmedia_frame out_frame;
295 void *pkt;
296 FILE *input = NULL, *output = NULL, *fref = NULL;
297 pj_bool_t is_itu_format = PJ_FALSE;
298 int rc = 0;
299 pj_status_t status;
300
301 pool = pj_pool_create(mem, "codec-vectors", 512, 512, NULL);
302 if (!pool) {
303 rc = -20;
304 goto on_return;
305 }
306
307 /* Find and open the codec */
308 count = 1;
309 status = pjmedia_codec_mgr_find_codecs_by_id(mgr, &codec_id, &count, ci, NULL);
310 if (status != PJ_SUCCESS) {
311 rc = -30;
312 goto on_return;
313 }
314
315 status = pjmedia_codec_mgr_alloc_codec(mgr, ci[0], &codec);
316 if (status != PJ_SUCCESS) {
317 rc = -40;
318 goto on_return;
319 }
320
321 status = pjmedia_codec_mgr_get_default_param(mgr, ci[0], &codec_param);
322 if (status != PJ_SUCCESS) {
323 rc = -50;
324 goto on_return;
325 }
326
327 codec_param.info.avg_bps = bitrate;
328 codec_param.setting.vad = 0;
329
330 status = pjmedia_codec_init(codec, pool);
331 if (status != PJ_SUCCESS) {
332 rc = -60;
333 goto on_return;
334 }
335
336 status = pjmedia_codec_open(codec, &codec_param);
337 if (status != PJ_SUCCESS) {
338 rc = -70;
339 goto on_return;
340 }
341
342 /* Open input file */
343 input = fopen(in_encoded_file, "rb");
344 if (!input) {
345 rc = -80;
346 goto on_return;
347 }
348
349 /* Is the file in ITU format? */
350 is_itu_format = pj_ansi_stricmp(in_encoded_file+strlen(in_encoded_file)-4,
351 ".itu")==0;
352
353 /* Open output file */
354 output = fopen(TMP_OUT, "wb");
355 if (!output) {
356 rc = -90;
357 goto on_return;
358 }
359
360 /* Allocate buffer for PCM and encoded frames */
361 samples_per_frame = codec_param.info.clock_rate * codec_param.info.frm_ptime / 1000;
362 pkt = pj_pool_alloc(pool, samples_per_frame * 2);
363 out_frame.buf = (pj_uint8_t*) pj_pool_alloc(pool, samples_per_frame * 2);
364
365 /* Loop read WAV file and encode and write to output file */
366 for (;;) {
367 pjmedia_frame in_frame[2];
368 pj_timestamp ts;
369 unsigned count;
370 pj_bool_t has_frame;
371
372 if (is_itu_format) {
373 int nsamp;
374 short frame_err = 0;
375
376 nsamp = read_ITU_format(input, (short*)pkt, &frame_err,
377 encoded_len / 2, PJ_TRUE);
378 if (nsamp != (int)encoded_len / 2)
379 break;
380
381 has_frame = !frame_err;
382 } else {
383 if (fread(pkt, encoded_len, 1, input) != 1)
384 break;
385
386 has_frame = PJ_TRUE;
387 }
388
389 if (has_frame) {
390 count = 2;
391 if (pjmedia_codec_parse(codec, pkt, encoded_len, &ts,
392 &count, in_frame) != PJ_SUCCESS)
393 {
394 rc = -100;
395 goto on_return;
396 }
397
398 if (count != 1) {
399 rc = -110;
400 goto on_return;
401 }
402
403 if (pjmedia_codec_decode(codec, &in_frame[0], samples_per_frame*2,
404 &out_frame) != PJ_SUCCESS)
405 {
406 rc = -120;
407 goto on_return;
408 }
409 } else {
410 if (pjmedia_codec_recover(codec, samples_per_frame*2,
411 &out_frame) != PJ_SUCCESS)
412 {
413 rc = -125;
414 goto on_return;
415 }
416 }
417
418 if (manip)
419 manip((short*)out_frame.buf, samples_per_frame);
420
421 if (fwrite(out_frame.buf, out_frame.size, 1, output) != 1) {
422 rc = -130;
423 goto on_return;
424 }
425 }
426
427 fclose(input);
428 input = NULL;
429
430 fclose(output);
431 output = NULL;
432
433 /* Compare encoded files */
434 fref = fopen(ref_pcm_file, "rb");
435 if (!fref) {
436 rc = -140;
437 goto on_return;
438 }
439
440 output = fopen(TMP_OUT, "rb");
441 if (!output) {
442 rc = -110;
443 goto on_return;
444 }
445
446 pos = 0;
447 for (;;) {
448 pj_size_t count;
449
450 count = fread(pkt, samples_per_frame*2, 1, fref);
451 if (count != 1)
452 break;
453
454 count = fread(out_frame.buf, samples_per_frame*2, 1, output);
455 if (count != 1)
456 break;
457
458 if (memcmp(pkt, out_frame.buf, samples_per_frame*2)) {
459 unsigned i;
460 pj_int16_t *in = (pj_int16_t*)pkt;
461 pj_int16_t *out = (pj_int16_t*)out_frame.buf;
462
463 for (i=0; i<samples_per_frame; ++i) {
464 if (in[i] != out[i])
465 break;
466 }
467
468 PJ_LOG(1,(THIS_FILE," failed: mismatch at samples %d", pos+i));
469 rc = -200;
470 break;
471 }
472
473 pos += samples_per_frame;
474 }
475
476on_return:
477 if (output)
478 fclose(output);
479
480 if (fref)
481 fclose(fref);
482
483 if (input)
484 fclose(input);
485
486 if (codec) {
487 pjmedia_codec_close(codec);
488 pjmedia_codec_mgr_dealloc_codec(mgr, codec);
489 }
490
491 if (pool)
492 pj_pool_release(pool);
493
494 return rc;
495}
496
497#if PJMEDIA_HAS_G7221_CODEC
498/* For ITU testing, off the 2 lsbs. */
499static void g7221_pcm_manip(short *pcm, unsigned count)
500{
501 unsigned i;
502 for (i=0; i<count; i++)
503 pcm[i] &= 0xfffc;
504
505}
506#endif /* PJMEDIA_HAS_G7221_CODEC */
507
508int codec_test_vectors(void)
509{
510 pjmedia_endpt *endpt;
511 pjmedia_codec_mgr *mgr;
512 int rc, rc_final = 0;
513 struct enc_vectors {
514 char *codec_name;
515 unsigned bit_rate;
516 const char *wav_file;
517 const char *ref_encoded_file;
518 } enc_vectors[] =
519 {
520#if PJMEDIA_HAS_G7221_CODEC
521 { "G7221/16000/1", 24000,
522 "../src/test/vectors/g722_1_enc_in.wav",
523 "../src/test/vectors/g722_1_enc_out_24000_be.pak"
524 },
525 { "G7221/16000/1", 32000,
526 "../src/test/vectors/g722_1_enc_in.wav",
527 "../src/test/vectors/g722_1_enc_out_32000_be.pak"
528 },
529#endif
530 { NULL }
531 };
532 struct dec_vectors {
533 char *codec_name;
534 unsigned bit_rate;
535 unsigned encoded_frame_len;
536 void (*manip)(short *pcm, unsigned count);
537 const char *enc_file;
538 const char *ref_pcm_file;
539 } dec_vectors[] =
540 {
541#if PJMEDIA_HAS_G7221_CODEC
542 { "G7221/16000/1", 24000, 60,
543 &g7221_pcm_manip,
544 "../src/test/vectors/g722_1_enc_out_24000_be.pak",
545 "../src/test/vectors/g722_1_dec_out_24000.pcm"
546 },
547 { "G7221/16000/1", 32000, 80,
548 &g7221_pcm_manip,
549 "../src/test/vectors/g722_1_enc_out_32000_be.pak",
550 "../src/test/vectors/g722_1_dec_out_32000.pcm"
551 },
552 { "G7221/16000/1", 24000, 60,
553 &g7221_pcm_manip,
554 "../src/test/vectors/g722_1_dec_in_24000_fe.itu",
555 "../src/test/vectors/g722_1_dec_out_24000_fe.pcm"
556 },
557 { "G7221/16000/1", 32000, 80,
558 &g7221_pcm_manip,
559 "../src/test/vectors/g722_1_dec_in_32000_fe.itu",
560 "../src/test/vectors/g722_1_dec_out_32000_fe.pcm"
561 },
562#endif
563 { NULL }
564 };
565 unsigned i;
566 pj_status_t status;
567
568 status = pjmedia_endpt_create(mem, NULL, 0, &endpt);
569 if (status != PJ_SUCCESS)
570 return -5;
571
572 mgr = pjmedia_endpt_get_codec_mgr(endpt);
573
574#if PJMEDIA_HAS_G7221_CODEC
575 status = pjmedia_codec_g7221_init(endpt);
576 if (status != PJ_SUCCESS) {
577 pjmedia_endpt_destroy(endpt);
578 return -7;
579 }
580
581 /* Set shift value to zero for the test vectors */
582 pjmedia_codec_g7221_set_pcm_shift(0);
583#endif
584
585 PJ_LOG(3,(THIS_FILE," encode tests:"));
586 for (i=0; i<PJ_ARRAY_SIZE(enc_vectors); ++i) {
587 if (!enc_vectors[i].codec_name)
588 continue;
589 PJ_LOG(3,(THIS_FILE," %s @%d bps %s ==> %s",
590 enc_vectors[i].codec_name,
591 enc_vectors[i].bit_rate,
592 enc_vectors[i].wav_file,
593 enc_vectors[i].ref_encoded_file));
594 rc = codec_test_encode(mgr, enc_vectors[i].codec_name,
595 enc_vectors[i].bit_rate,
596 enc_vectors[i].wav_file,
597 enc_vectors[i].ref_encoded_file);
598 if (rc != 0)
599 rc_final = rc;
600 }
601
602 PJ_LOG(3,(THIS_FILE," decode tests:"));
603 for (i=0; i<PJ_ARRAY_SIZE(dec_vectors); ++i) {
604 if (!dec_vectors[i].codec_name)
605 continue;
606 PJ_LOG(3,(THIS_FILE," %s @%d bps %s ==> %s",
607 dec_vectors[i].codec_name,
608 dec_vectors[i].bit_rate,
609 dec_vectors[i].enc_file,
610 dec_vectors[i].ref_pcm_file));
611 rc = codec_test_decode(mgr, dec_vectors[i].codec_name,
612 dec_vectors[i].bit_rate,
613 dec_vectors[i].encoded_frame_len,
614 dec_vectors[i].enc_file,
615 dec_vectors[i].ref_pcm_file,
616 dec_vectors[i].manip);
617 if (rc != 0)
618 rc_final = rc;
619 }
620
621 if (pj_file_exists(TMP_OUT))
622 pj_file_delete(TMP_OUT);
623
624 pjmedia_endpt_destroy(endpt);
625 return rc_final;
626}
627