| /* $Id$ */ |
| /* |
| * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) |
| * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> |
| * |
| * 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 |
| */ |
| |
| /** |
| * \page page_pjmedia_samples_encdec_c Samples: Encoding and Decoding |
| * |
| * This sample shows how to use codec. |
| * |
| * This file is pjsip-apps/src/samples/encdec.c |
| * |
| * \includelineno encdec.c |
| */ |
| |
| #include <pjlib.h> |
| #include <pjmedia.h> |
| #include <pjmedia-codec.h> |
| |
| #define THIS_FILE "encdec.c" |
| |
| static const char *desc = |
| " encdec \n" |
| " \n" |
| " PURPOSE: \n" |
| " Encode input WAV with a codec, and decode the result to another WAV \n" |
| "\n" |
| "\n" |
| " USAGE: \n" |
| " encdec codec input.wav output.wav \n" |
| "\n" |
| "\n" |
| " where:\n" |
| " codec Set the codec name. \n" |
| " input.wav Set the input WAV filename. \n" |
| " output.wav Set the output WAV filename. \n" |
| |
| "\n" |
| ; |
| |
| //#undef PJ_TRACE |
| //#define PJ_TRACE 1 |
| |
| #ifndef PJ_TRACE |
| # define PJ_TRACE 0 |
| #endif |
| |
| #if PJ_TRACE |
| # define TRACE_(expr) PJ_LOG(4,expr) |
| #else |
| # define TRACE_(expr) |
| #endif |
| |
| |
| static void err(const char *op, pj_status_t status) |
| { |
| char errmsg[PJ_ERR_MSG_SIZE]; |
| pj_strerror(status, errmsg, sizeof(errmsg)); |
| PJ_LOG(3,("", "%s error: %s", op, errmsg)); |
| } |
| |
| #define CHECK(op) do { \ |
| status = op; \ |
| if (status != PJ_SUCCESS) { \ |
| err(#op, status); \ |
| return status; \ |
| } \ |
| } \ |
| while (0) |
| |
| static pjmedia_endpt *mept; |
| static unsigned file_msec_duration; |
| |
| static pj_status_t enc_dec_test(const char *codec_id, |
| const char *filein, |
| const char *fileout) |
| { |
| pj_pool_t *pool; |
| pjmedia_codec_mgr *cm; |
| pjmedia_codec *codec; |
| const pjmedia_codec_info *pci; |
| pjmedia_codec_param param; |
| unsigned cnt, samples_per_frame; |
| pj_str_t tmp; |
| pjmedia_port *wavin, *wavout; |
| unsigned lost_pct; |
| pj_status_t status; |
| |
| #define T file_msec_duration/1000, file_msec_duration%1000 |
| |
| pool = pjmedia_endpt_create_pool(mept, "encdec", 1000, 1000); |
| |
| cm = pjmedia_endpt_get_codec_mgr(mept); |
| |
| #ifdef LOST_PCT |
| lost_pct = LOST_PCT; |
| #else |
| lost_pct = 0; |
| #endif |
| |
| cnt = 1; |
| CHECK( pjmedia_codec_mgr_find_codecs_by_id(cm, pj_cstr(&tmp, codec_id), |
| &cnt, &pci, NULL) ); |
| CHECK( pjmedia_codec_mgr_get_default_param(cm, pci, ¶m) ); |
| |
| samples_per_frame = param.info.clock_rate * param.info.frm_ptime / 1000; |
| |
| /* Control VAD */ |
| param.setting.vad = 1; |
| |
| /* Open wav for reading */ |
| CHECK( pjmedia_wav_player_port_create(pool, filein, |
| param.info.frm_ptime, |
| PJMEDIA_FILE_NO_LOOP, 0, &wavin) ); |
| |
| /* Open wav for writing */ |
| CHECK( pjmedia_wav_writer_port_create(pool, fileout, |
| param.info.clock_rate, |
| param.info.channel_cnt, |
| samples_per_frame, |
| 16, 0, 0, &wavout) ); |
| |
| /* Alloc codec */ |
| CHECK( pjmedia_codec_mgr_alloc_codec(cm, pci, &codec) ); |
| CHECK( pjmedia_codec_init(codec, pool) ); |
| CHECK( pjmedia_codec_open(codec, ¶m) ); |
| |
| for (;;) { |
| pjmedia_frame frm_pcm, frm_bit, out_frm, frames[4]; |
| pj_int16_t pcmbuf[320]; |
| pj_timestamp ts; |
| pj_uint8_t bitstream[160]; |
| |
| frm_pcm.buf = (char*)pcmbuf; |
| frm_pcm.size = samples_per_frame * 2; |
| |
| /* Read from WAV */ |
| if (pjmedia_port_get_frame(wavin, &frm_pcm) != PJ_SUCCESS) |
| break; |
| if (frm_pcm.type != PJMEDIA_FRAME_TYPE_AUDIO) |
| break;; |
| |
| /* Update duration */ |
| file_msec_duration += samples_per_frame * 1000 / |
| param.info.clock_rate; |
| |
| /* Encode */ |
| frm_bit.buf = bitstream; |
| frm_bit.size = sizeof(bitstream); |
| CHECK(pjmedia_codec_encode(codec, &frm_pcm, sizeof(bitstream), |
| &frm_bit)); |
| |
| /* On DTX, write zero frame to wavout to maintain duration */ |
| if (frm_bit.size == 0 || frm_bit.type != PJMEDIA_FRAME_TYPE_AUDIO) { |
| out_frm.buf = (char*)pcmbuf; |
| out_frm.size = 160; |
| CHECK( pjmedia_port_put_frame(wavout, &out_frm) ); |
| TRACE_((THIS_FILE, "%d.%03d read: %u, enc: %u", |
| T, frm_pcm.size, frm_bit.size)); |
| continue; |
| } |
| |
| /* Parse the bitstream (not really necessary for this case |
| * since we always decode 1 frame, but it's still good |
| * for testing) |
| */ |
| ts.u64 = 0; |
| cnt = PJ_ARRAY_SIZE(frames); |
| CHECK( pjmedia_codec_parse(codec, bitstream, frm_bit.size, &ts, &cnt, |
| frames) ); |
| CHECK( (cnt==1 ? PJ_SUCCESS : -1) ); |
| |
| /* Decode or simulate packet loss */ |
| out_frm.buf = (char*)pcmbuf; |
| out_frm.size = sizeof(pcmbuf); |
| |
| if ((pj_rand() % 100) < (int)lost_pct) { |
| /* Simulate loss */ |
| CHECK( pjmedia_codec_recover(codec, sizeof(pcmbuf), &out_frm) ); |
| TRACE_((THIS_FILE, "%d.%03d Packet lost", T)); |
| } else { |
| /* Decode */ |
| CHECK( pjmedia_codec_decode(codec, &frames[0], sizeof(pcmbuf), |
| &out_frm) ); |
| } |
| |
| /* Write to WAV */ |
| CHECK( pjmedia_port_put_frame(wavout, &out_frm) ); |
| |
| TRACE_((THIS_FILE, "%d.%03d read: %u, enc: %u, dec/write: %u", |
| T, frm_pcm.size, frm_bit.size, out_frm.size)); |
| } |
| |
| /* Close wavs */ |
| pjmedia_port_destroy(wavout); |
| pjmedia_port_destroy(wavin); |
| |
| /* Close codec */ |
| pjmedia_codec_close(codec); |
| pjmedia_codec_mgr_dealloc_codec(cm, codec); |
| |
| /* Release pool */ |
| pj_pool_release(pool); |
| |
| return PJ_SUCCESS; |
| } |
| |
| |
| int main(int argc, char *argv[]) |
| { |
| pj_caching_pool cp; |
| pj_time_val t0, t1; |
| pj_status_t status; |
| |
| if (argc != 4) { |
| puts(desc); |
| return 1; |
| } |
| |
| CHECK( pj_init() ); |
| |
| pj_caching_pool_init(&cp, NULL, 0); |
| |
| CHECK( pjmedia_endpt_create(&cp.factory, NULL, 1, &mept) ); |
| |
| /* Register all codecs */ |
| CHECK( pjmedia_codec_register_audio_codecs(mept, NULL) ); |
| |
| pj_gettimeofday(&t0); |
| status = enc_dec_test(argv[1], argv[2], argv[3]); |
| pj_gettimeofday(&t1); |
| PJ_TIME_VAL_SUB(t1, t0); |
| |
| pjmedia_endpt_destroy(mept); |
| pj_caching_pool_destroy(&cp); |
| pj_shutdown(); |
| |
| if (status == PJ_SUCCESS) { |
| puts(""); |
| puts("Success"); |
| printf("Duration: %ds.%03d\n", file_msec_duration/1000, |
| file_msec_duration%1000); |
| printf("Time: %lds.%03ld\n", t1.sec, t1.msec); |
| } |
| |
| return 0; |
| } |
| |