blob: 9ded9906d48fd72d27c19ee067814eecf9bb1b22 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id: encdec.c 3664 2011-07-19 03:42:28Z nanang $ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 /**
22 * \page page_pjmedia_samples_encdec_c Samples: Encoding and Decoding
23 *
24 * This sample shows how to use codec.
25 *
26 * This file is pjsip-apps/src/samples/encdec.c
27 *
28 * \includelineno encdec.c
29 */
30
31#include <pjlib.h>
32#include <pjmedia.h>
33#include <pjmedia-codec.h>
34
35#define THIS_FILE "encdec.c"
36
37static const char *desc =
38 " encdec \n"
39 " \n"
40 " PURPOSE: \n"
41 " Encode input WAV with a codec, and decode the result to another WAV \n"
42 "\n"
43 "\n"
44 " USAGE: \n"
45 " encdec codec input.wav output.wav \n"
46 "\n"
47 "\n"
48 " where:\n"
49 " codec Set the codec name. \n"
50 " input.wav Set the input WAV filename. \n"
51 " output.wav Set the output WAV filename. \n"
52
53 "\n"
54;
55
56//#undef PJ_TRACE
57//#define PJ_TRACE 1
58
59#ifndef PJ_TRACE
60# define PJ_TRACE 0
61#endif
62
63#if PJ_TRACE
64# define TRACE_(expr) PJ_LOG(4,expr)
65#else
66# define TRACE_(expr)
67#endif
68
69
70static void err(const char *op, pj_status_t status)
71{
72 char errmsg[PJ_ERR_MSG_SIZE];
73 pj_strerror(status, errmsg, sizeof(errmsg));
74 PJ_LOG(3,("", "%s error: %s", op, errmsg));
75}
76
77#define CHECK(op) do { \
78 status = op; \
79 if (status != PJ_SUCCESS) { \
80 err(#op, status); \
81 return status; \
82 } \
83 } \
84 while (0)
85
86static pjmedia_endpt *mept;
87static unsigned file_msec_duration;
88
89static pj_status_t enc_dec_test(const char *codec_id,
90 const char *filein,
91 const char *fileout)
92{
93 pj_pool_t *pool;
94 pjmedia_codec_mgr *cm;
95 pjmedia_codec *codec;
96 const pjmedia_codec_info *pci;
97 pjmedia_codec_param param;
98 unsigned cnt, samples_per_frame;
99 pj_str_t tmp;
100 pjmedia_port *wavin, *wavout;
101 unsigned lost_pct;
102 pj_status_t status;
103
104#define T file_msec_duration/1000, file_msec_duration%1000
105
106 pool = pjmedia_endpt_create_pool(mept, "encdec", 1000, 1000);
107
108 cm = pjmedia_endpt_get_codec_mgr(mept);
109
110#ifdef LOST_PCT
111 lost_pct = LOST_PCT;
112#else
113 lost_pct = 0;
114#endif
115
116 cnt = 1;
117 CHECK( pjmedia_codec_mgr_find_codecs_by_id(cm, pj_cstr(&tmp, codec_id),
118 &cnt, &pci, NULL) );
119 CHECK( pjmedia_codec_mgr_get_default_param(cm, pci, &param) );
120
121 samples_per_frame = param.info.clock_rate * param.info.frm_ptime / 1000;
122
123 /* Control VAD */
124 param.setting.vad = 1;
125
126 /* Open wav for reading */
127 CHECK( pjmedia_wav_player_port_create(pool, filein,
128 param.info.frm_ptime,
129 PJMEDIA_FILE_NO_LOOP, 0, &wavin) );
130
131 /* Open wav for writing */
132 CHECK( pjmedia_wav_writer_port_create(pool, fileout,
133 param.info.clock_rate,
134 param.info.channel_cnt,
135 samples_per_frame,
136 16, 0, 0, &wavout) );
137
138 /* Alloc codec */
139 CHECK( pjmedia_codec_mgr_alloc_codec(cm, pci, &codec) );
140 CHECK( pjmedia_codec_init(codec, pool) );
141 CHECK( pjmedia_codec_open(codec, &param) );
142
143 for (;;) {
144 pjmedia_frame frm_pcm, frm_bit, out_frm, frames[4];
145 pj_int16_t pcmbuf[320];
146 pj_timestamp ts;
147 pj_uint8_t bitstream[160];
148
149 frm_pcm.buf = (char*)pcmbuf;
150 frm_pcm.size = samples_per_frame * 2;
151
152 /* Read from WAV */
153 if (pjmedia_port_get_frame(wavin, &frm_pcm) != PJ_SUCCESS)
154 break;
155 if (frm_pcm.type != PJMEDIA_FRAME_TYPE_AUDIO)
156 break;;
157
158 /* Update duration */
159 file_msec_duration += samples_per_frame * 1000 /
160 param.info.clock_rate;
161
162 /* Encode */
163 frm_bit.buf = bitstream;
164 frm_bit.size = sizeof(bitstream);
165 CHECK(pjmedia_codec_encode(codec, &frm_pcm, sizeof(bitstream),
166 &frm_bit));
167
168 /* On DTX, write zero frame to wavout to maintain duration */
169 if (frm_bit.size == 0 || frm_bit.type != PJMEDIA_FRAME_TYPE_AUDIO) {
170 out_frm.buf = (char*)pcmbuf;
171 out_frm.size = 160;
172 CHECK( pjmedia_port_put_frame(wavout, &out_frm) );
173 TRACE_((THIS_FILE, "%d.%03d read: %u, enc: %u",
174 T, frm_pcm.size, frm_bit.size));
175 continue;
176 }
177
178 /* Parse the bitstream (not really necessary for this case
179 * since we always decode 1 frame, but it's still good
180 * for testing)
181 */
182 ts.u64 = 0;
183 cnt = PJ_ARRAY_SIZE(frames);
184 CHECK( pjmedia_codec_parse(codec, bitstream, frm_bit.size, &ts, &cnt,
185 frames) );
186 CHECK( (cnt==1 ? PJ_SUCCESS : -1) );
187
188 /* Decode or simulate packet loss */
189 out_frm.buf = (char*)pcmbuf;
190 out_frm.size = sizeof(pcmbuf);
191
192 if ((pj_rand() % 100) < (int)lost_pct) {
193 /* Simulate loss */
194 CHECK( pjmedia_codec_recover(codec, sizeof(pcmbuf), &out_frm) );
195 TRACE_((THIS_FILE, "%d.%03d Packet lost", T));
196 } else {
197 /* Decode */
198 CHECK( pjmedia_codec_decode(codec, &frames[0], sizeof(pcmbuf),
199 &out_frm) );
200 }
201
202 /* Write to WAV */
203 CHECK( pjmedia_port_put_frame(wavout, &out_frm) );
204
205 TRACE_((THIS_FILE, "%d.%03d read: %u, enc: %u, dec/write: %u",
206 T, frm_pcm.size, frm_bit.size, out_frm.size));
207 }
208
209 /* Close wavs */
210 pjmedia_port_destroy(wavout);
211 pjmedia_port_destroy(wavin);
212
213 /* Close codec */
214 pjmedia_codec_close(codec);
215 pjmedia_codec_mgr_dealloc_codec(cm, codec);
216
217 /* Release pool */
218 pj_pool_release(pool);
219
220 return PJ_SUCCESS;
221}
222
223
224int main(int argc, char *argv[])
225{
226 pj_caching_pool cp;
227 pj_time_val t0, t1;
228 pj_status_t status;
229
230 if (argc != 4) {
231 puts(desc);
232 return 1;
233 }
234
235 CHECK( pj_init() );
236
237 pj_caching_pool_init(&cp, NULL, 0);
238
239 CHECK( pjmedia_endpt_create(&cp.factory, NULL, 1, &mept) );
240
241 /* Register all codecs */
242 CHECK( pjmedia_codec_register_audio_codecs(mept, NULL) );
243
244 pj_gettimeofday(&t0);
245 status = enc_dec_test(argv[1], argv[2], argv[3]);
246 pj_gettimeofday(&t1);
247 PJ_TIME_VAL_SUB(t1, t0);
248
249 pjmedia_endpt_destroy(mept);
250 pj_caching_pool_destroy(&cp);
251 pj_shutdown();
252
253 if (status == PJ_SUCCESS) {
254 puts("");
255 puts("Success");
256 printf("Duration: %ds.%03d\n", file_msec_duration/1000,
257 file_msec_duration%1000);
258 printf("Time: %lds.%03ld\n", t1.sec, t1.msec);
259 }
260
261 return 0;
262}
263