- Timestamp:
- Aug 20, 2008 11:19:43 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/resample_resample.c
r2039 r2228 41 41 unsigned xoff; /* History and lookahead size, in samples */ 42 42 unsigned frame_size; /* Samples per frame. */ 43 unsigned channel_cnt; /* Channel count. */ 44 45 /* Buffer for monochannel */ 43 46 pj_int16_t *buffer; /* Input buffer. */ 47 48 /* Buffer for multichannel */ 49 pj_int16_t **in_buffer; /* Array of input buffer for each channel. */ 50 pj_int16_t *tmp_buffer; /* Temporary output buffer for processing. */ 44 51 }; 45 52 … … 59 66 rate_out && samples_per_frame, PJ_EINVAL); 60 67 61 resample = PJ_POOL_ ALLOC_T(pool, pjmedia_resample);68 resample = PJ_POOL_ZALLOC_T(pool, pjmedia_resample); 62 69 PJ_ASSERT_RETURN(resample, PJ_ENOMEM); 63 64 PJ_UNUSED_ARG(channel_count);65 70 66 71 /* … … 77 82 resample->large_filter = large_filter; 78 83 resample->high_quality = high_quality; 84 resample->channel_cnt = channel_count; 79 85 resample->frame_size = samples_per_frame; 80 86 81 87 if (high_quality) { 82 unsigned size;83 84 88 /* This is a bug in xoff calculation, thanks Stephane Lussier 85 89 * of Macadamian dot com. … … 87 91 */ 88 92 resample->xoff = res_GetXOFF(resample->factor, (char)large_filter); 89 93 } else { 94 resample->xoff = 1; 95 } 96 97 if (channel_count == 1) { 98 unsigned size; 99 100 /* Allocate input buffer */ 90 101 size = (samples_per_frame + 2*resample->xoff) * sizeof(pj_int16_t); 91 102 resample->buffer = (pj_int16_t*) pj_pool_alloc(pool, size); … … 94 105 pjmedia_zero_samples(resample->buffer, resample->xoff*2); 95 106 96 97 } else { 98 resample->xoff = 0; 107 } else if (channel_count > 1) { 108 unsigned i, size; 109 110 /* Allocate input buffer table */ 111 size = channel_count * sizeof(pj_int16_t*); 112 resample->in_buffer = (pj_int16_t**)pj_pool_alloc(pool, size); 113 114 /* Allocate input buffer */ 115 size = (samples_per_frame/channel_count + 2*resample->xoff) * 116 sizeof(pj_int16_t); 117 for (i = 0; i < channel_count; ++i) { 118 resample->in_buffer[i] = (pj_int16_t*)pj_pool_alloc(pool, size); 119 PJ_ASSERT_RETURN(resample->in_buffer, PJ_ENOMEM); 120 pjmedia_zero_samples(resample->in_buffer[i], resample->xoff*2); 121 } 122 123 /* Allocate temporary output buffer */ 124 size = (unsigned) (resample->frame_size * sizeof(pj_int16_t) * 125 resample->factor / channel_count); 126 resample->tmp_buffer = (pj_int16_t*) pj_pool_alloc(pool, size); 127 PJ_ASSERT_RETURN(resample->tmp_buffer, PJ_ENOMEM); 99 128 } 100 129 … … 117 146 PJ_ASSERT_ON_FAIL(resample, return); 118 147 119 if (resample->high_quality) { 148 /* Okay chaps, here's how we do resampling. 149 * 150 * The original resample algorithm requires xoff samples *before* the 151 * input buffer as history, and another xoff samples *after* the 152 * end of the input buffer as lookahead. Since application can only 153 * supply framesize buffer on each run, PJMEDIA needs to arrange the 154 * buffer to meet these requirements. 155 * 156 * So here comes the trick. 157 * 158 * First of all, because of the history and lookahead requirement, 159 * resample->buffer need to accomodate framesize+2*xoff samples in its 160 * buffer. This is done when the buffer is created. 161 * 162 * On the first run, the input frame (supplied by application) is 163 * copied to resample->buffer at 2*xoff position. The first 2*xoff 164 * samples are initially zeroed (in the initialization). The resample 165 * algorithm then invoked at resample->buffer+xoff ONLY, thus giving 166 * it one xoff at the beginning as zero, and one xoff at the end 167 * as the end of the original input. The resample algorithm will see 168 * that the first xoff samples in the input as zero. 169 * 170 * So here's the layout of resample->buffer on the first run. 171 * 172 * run 0 173 * +------+------+--------------+ 174 * | 0000 | 0000 | frame0... | 175 * +------+------+--------------+ 176 * ^ ^ ^ ^ 177 * 0 xoff 2*xoff size+2*xoff 178 * 179 * (Note again: resample algorithm is called at resample->buffer+xoff) 180 * 181 * At the end of the run, 2*xoff samples from the end of 182 * resample->buffer are copied to the beginning of resample->buffer. 183 * The first xoff part of this will be used as history for the next 184 * run, and the second xoff part of this is actually the start of 185 * resampling for the next run. 186 * 187 * And the first run completes, the function returns. 188 * 189 * 190 * On the next run, the input frame supplied by application is again 191 * copied at 2*xoff position in the resample->buffer, and the 192 * resample algorithm is again invoked at resample->buffer+xoff 193 * position. So effectively, the resample algorithm will start its 194 * operation on the last xoff from the previous frame, and gets the 195 * history from the last 2*xoff of the previous frame, and the look- 196 * ahead from the last xoff of current frame. 197 * 198 * So on this run, the buffer layout is: 199 * 200 * run 1 201 * +------+------+--------------+ 202 * | frm0 | frm0 | frame1... | 203 * +------+------+--------------+ 204 * ^ ^ ^ ^ 205 * 0 xoff 2*xoff size+2*xoff 206 * 207 * As you can see from above diagram, the resampling algorithm is 208 * actually called from the last xoff part of previous frame (frm0). 209 * 210 * And so on the process continues for the next frame, and the next, 211 * and the next, ... 212 * 213 */ 214 if (resample->channel_cnt == 1) { 120 215 pj_int16_t *dst_buf; 121 216 const pj_int16_t *src_buf; 122 217 123 /* Okay chaps, here's how we do resampling. 124 * 125 * The original resample algorithm requires xoff samples *before* the 126 * input buffer as history, and another xoff samples *after* the 127 * end of the input buffer as lookahead. Since application can only 128 * supply framesize buffer on each run, PJMEDIA needs to arrange the 129 * buffer to meet these requirements. 130 * 131 * So here comes the trick. 132 * 133 * First of all, because of the history and lookahead requirement, 134 * resample->buffer need to accomodate framesize+2*xoff samples in its 135 * buffer. This is done when the buffer is created. 136 * 137 * On the first run, the input frame (supplied by application) is 138 * copied to resample->buffer at 2*xoff position. The first 2*xoff 139 * samples are initially zeroed (in the initialization). The resample 140 * algorithm then invoked at resample->buffer+xoff ONLY, thus giving 141 * it one xoff at the beginning as zero, and one xoff at the end 142 * as the end of the original input. The resample algorithm will see 143 * that the first xoff samples in the input as zero. 144 * 145 * So here's the layout of resample->buffer on the first run. 146 * 147 * run 0 148 * +------+------+--------------+ 149 * | 0000 | 0000 | frame0... | 150 * +------+------+--------------+ 151 * ^ ^ ^ ^ 152 * 0 xoff 2*xoff size+2*xoff 153 * 154 * (Note again: resample algorithm is called at resample->buffer+xoff) 155 * 156 * At the end of the run, 2*xoff samples from the end of 157 * resample->buffer are copied to the beginning of resample->buffer. 158 * The first xoff part of this will be used as history for the next 159 * run, and the second xoff part of this is actually the start of 160 * resampling for the next run. 161 * 162 * And the first run completes, the function returns. 163 * 164 * 165 * On the next run, the input frame supplied by application is again 166 * copied at 2*xoff position in the resample->buffer, and the 167 * resample algorithm is again invoked at resample->buffer+xoff 168 * position. So effectively, the resample algorithm will start its 169 * operation on the last xoff from the previous frame, and gets the 170 * history from the last 2*xoff of the previous frame, and the look- 171 * ahead from the last xoff of current frame. 172 * 173 * So on this run, the buffer layout is: 174 * 175 * run 1 176 * +------+------+--------------+ 177 * | frm0 | frm0 | frame1... | 178 * +------+------+--------------+ 179 * ^ ^ ^ ^ 180 * 0 xoff 2*xoff size+2*xoff 181 * 182 * As you can see from above diagram, the resampling algorithm is 183 * actually called from the last xoff part of previous frame (frm0). 184 * 185 * And so on the process continues for the next frame, and the next, 186 * and the next, ... 187 * 188 */ 218 /* Prepare input frame */ 189 219 dst_buf = resample->buffer + resample->xoff*2; 190 220 pjmedia_copy_samples(dst_buf, input, resample->frame_size); 191 221 192 res_Resample(resample->buffer + resample->xoff, output, 193 resample->factor, (pj_uint16_t)resample->frame_size, 194 (char)resample->large_filter, (char)PJ_TRUE); 195 222 /* Resample */ 223 if (resample->high_quality) { 224 res_Resample(resample->buffer + resample->xoff, output, 225 resample->factor, (pj_uint16_t)resample->frame_size, 226 (char)resample->large_filter, (char)PJ_TRUE); 227 } else { 228 res_SrcLinear(resample->buffer + resample->xoff, output, 229 resample->factor, (pj_uint16_t)resample->frame_size); 230 } 231 232 /* Update history */ 196 233 dst_buf = resample->buffer; 197 234 src_buf = input + resample->frame_size - resample->xoff*2; 198 235 pjmedia_copy_samples(dst_buf, src_buf, resample->xoff * 2); 199 236 200 } else { 201 res_SrcLinear( input, output, resample->factor, 202 (pj_uint16_t)resample->frame_size); 237 } else { /* Multichannel */ 238 unsigned i, j; 239 240 for (i = 0; i < resample->channel_cnt; ++i) { 241 pj_int16_t *dst_buf; 242 const pj_int16_t *src_buf; 243 unsigned mono_frm_sz_in; 244 unsigned mono_frm_sz_out; 245 246 mono_frm_sz_in = resample->frame_size / resample->channel_cnt; 247 mono_frm_sz_out = (unsigned)(mono_frm_sz_in * resample->factor); 248 249 /* Deinterleave input */ 250 dst_buf = resample->in_buffer[i] + resample->xoff*2; 251 src_buf = input + i; 252 for (j = 0; j < mono_frm_sz_in; ++j) { 253 *dst_buf++ = *src_buf; 254 src_buf += resample->channel_cnt; 255 } 256 257 /* Resample this channel */ 258 if (resample->high_quality) { 259 res_Resample(resample->in_buffer[i] + resample->xoff, 260 resample->tmp_buffer, resample->factor, 261 (pj_uint16_t)mono_frm_sz_in, 262 (char)resample->large_filter, (char)PJ_TRUE); 263 } else { 264 res_SrcLinear( resample->in_buffer[i], 265 resample->tmp_buffer, 266 resample->factor, 267 (pj_uint16_t)mono_frm_sz_in); 268 } 269 270 /* Update history */ 271 dst_buf = resample->in_buffer[i]; 272 src_buf = resample->in_buffer[i] + mono_frm_sz_in; 273 pjmedia_copy_samples(dst_buf, src_buf, resample->xoff * 2); 274 275 /* Reinterleave output */ 276 dst_buf = output + i; 277 src_buf = resample->tmp_buffer; 278 for (j = 0; j < mono_frm_sz_out; ++j) { 279 *dst_buf = *src_buf++; 280 dst_buf += resample->channel_cnt; 281 } 282 } 203 283 } 204 284 }
Note: See TracChangeset
for help on using the changeset viewer.