| 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); |
| 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) { |
| 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 */ |
| 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 */ |
| 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 | } |