/* * 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; /* For G7221, the bitrate is set via param.setting.dec_fmtp, if it has * no info about bitrate, the codec will check info.avg_bps. So, let's * just clear the SDP fmtp. */ if (pj_ansi_strstr(codec_name, "G7221/")) { codec_param.setting.dec_fmtp.cnt = 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 (;;) { pj_size_t 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; }
static void pcap2wav(const pj_str_t *codec, const pj_str_t *wav_filename, pjmedia_aud_dev_index dev_id, const pj_str_t *srtp_crypto, const pj_str_t *srtp_key) { const pj_str_t WAV = {".wav", 4}; struct pkt { pj_uint8_t buffer[320]; pjmedia_rtp_hdr *rtp; pj_uint8_t *payload; unsigned payload_len; } pkt0; pjmedia_codec_mgr *cmgr; const pjmedia_codec_info *ci; pjmedia_codec_param param; unsigned samples_per_frame; pj_status_t status; /* Initialize all codecs */ T( pjmedia_codec_register_audio_codecs(app.mept, NULL) ); /* Create SRTP transport is needed */ #if PJMEDIA_HAS_SRTP if (srtp_crypto->slen) { pjmedia_srtp_crypto crypto; pj_bzero(&crypto, sizeof(crypto)); crypto.key = *srtp_key; crypto.name = *srtp_crypto; T( pjmedia_transport_srtp_create(app.mept, NULL, NULL, &app.srtp) ); T( pjmedia_transport_srtp_start(app.srtp, &crypto, &crypto) ); } #else PJ_UNUSED_ARG(srtp_crypto); PJ_UNUSED_ARG(srtp_key); #endif /* Read first packet */ read_rtp(pkt0.buffer, sizeof(pkt0.buffer), &pkt0.rtp, &pkt0.payload, &pkt0.payload_len, PJ_FALSE); cmgr = pjmedia_endpt_get_codec_mgr(app.mept); /* Get codec info and param for the specified payload type */ app.pt = pkt0.rtp->pt; if (app.pt >=0 && app.pt < 96) { T( pjmedia_codec_mgr_get_codec_info(cmgr, pkt0.rtp->pt, &ci) ); } else { unsigned cnt = 2; const pjmedia_codec_info *info[2]; T( pjmedia_codec_mgr_find_codecs_by_id(cmgr, codec, &cnt, info, NULL) ); if (cnt != 1) err_exit("Codec ID must be specified and unique!", 0); ci = info[0]; } T( pjmedia_codec_mgr_get_default_param(cmgr, ci, ¶m) ); /* Alloc and init codec */ T( pjmedia_codec_mgr_alloc_codec(cmgr, ci, &app.codec) ); T( pjmedia_codec_init(app.codec, app.pool) ); T( pjmedia_codec_open(app.codec, ¶m) ); /* Init audio device or WAV file */ samples_per_frame = ci->clock_rate * param.info.frm_ptime / 1000; if (pj_strcmp2(wav_filename, "-") == 0) { pjmedia_aud_param aud_param; /* Open audio device */ T( pjmedia_aud_dev_default_param(dev_id, &aud_param) ); aud_param.dir = PJMEDIA_DIR_PLAYBACK; aud_param.channel_count = ci->channel_cnt; aud_param.clock_rate = ci->clock_rate; aud_param.samples_per_frame = samples_per_frame; T( pjmedia_aud_stream_create(&aud_param, NULL, &play_cb, NULL, &app.aud_strm) ); T( pjmedia_aud_stream_start(app.aud_strm) ); } else if (pj_stristr(wav_filename, &WAV)) { /* Open WAV file */ T( pjmedia_wav_writer_port_create(app.pool, wav_filename->ptr, ci->clock_rate, ci->channel_cnt, samples_per_frame, param.info.pcm_bits_per_sample, 0, 0, &app.wav) ); } else { err_exit("invalid output file", PJ_EINVAL); } /* Loop reading PCAP and writing WAV file */ for (;;) { struct pkt pkt1; pj_timestamp ts; pjmedia_frame frames[16], pcm_frame; short pcm[320]; unsigned i, frame_cnt; long samples_cnt, ts_gap; pj_assert(sizeof(pcm) >= samples_per_frame); /* Parse first packet */ ts.u64 = 0; frame_cnt = PJ_ARRAY_SIZE(frames); T( pjmedia_codec_parse(app.codec, pkt0.payload, pkt0.payload_len, &ts, &frame_cnt, frames) ); /* Decode and write to WAV file */ samples_cnt = 0; for (i=0; i<frame_cnt; ++i) { pjmedia_frame pcm_frame; pcm_frame.buf = pcm; pcm_frame.size = samples_per_frame * 2; T( pjmedia_codec_decode(app.codec, &frames[i], (unsigned)pcm_frame.size, &pcm_frame) ); if (app.wav) { T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); } if (app.aud_strm) { T( wait_play(&pcm_frame) ); } samples_cnt += samples_per_frame; } /* Read next packet */ read_rtp(pkt1.buffer, sizeof(pkt1.buffer), &pkt1.rtp, &pkt1.payload, &pkt1.payload_len, PJ_TRUE); /* Fill in the gap (if any) between pkt0 and pkt1 */ ts_gap = pj_ntohl(pkt1.rtp->ts) - pj_ntohl(pkt0.rtp->ts) - samples_cnt; while (ts_gap >= (long)samples_per_frame) { pcm_frame.buf = pcm; pcm_frame.size = samples_per_frame * 2; if (app.codec->op->recover) { T( pjmedia_codec_recover(app.codec, (unsigned)pcm_frame.size, &pcm_frame) ); } else { pj_bzero(pcm_frame.buf, pcm_frame.size); } if (app.wav) { T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); } if (app.aud_strm) { T( wait_play(&pcm_frame) ); } ts_gap -= samples_per_frame; } /* Next */ pkt0 = pkt1; pkt0.rtp = (pjmedia_rtp_hdr*)pkt0.buffer; pkt0.payload = pkt0.buffer + (pkt1.payload - pkt1.buffer); } }
/* * 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; pj_size_t 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; /* For G7221, the bitrate is set via param.setting.dec_fmtp, if it has * no info about bitrate, the codec will check info.avg_bps. So, let's * just clear the SDP fmtp. */ if (pj_ansi_strstr(codec_name, "G7221/")) { codec_param.setting.dec_fmtp.cnt = 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) { 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 (;;) { pj_size_t 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; }