Changeset 2228


Ignore:
Timestamp:
Aug 20, 2008 11:19:43 AM (11 years ago)
Author:
nanang
Message:

Ticket #596: Updated resample with backend libresample to process multichannel resampling properly (deinterleave, resample per channel, reinterleave).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/resample_resample.c

    r2039 r2228  
    4141    unsigned     xoff;          /* History and lookahead size, in samples   */ 
    4242    unsigned     frame_size;    /* Samples per frame.                       */ 
     43    unsigned     channel_cnt;   /* Channel count.                           */ 
     44 
     45    /* Buffer for monochannel */ 
    4346    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.  */ 
    4451}; 
    4552 
     
    5966                     rate_out && samples_per_frame, PJ_EINVAL); 
    6067 
    61     resample = PJ_POOL_ALLOC_T(pool, pjmedia_resample); 
     68    resample = PJ_POOL_ZALLOC_T(pool, pjmedia_resample); 
    6269    PJ_ASSERT_RETURN(resample, PJ_ENOMEM); 
    63  
    64     PJ_UNUSED_ARG(channel_count); 
    6570 
    6671    /* 
     
    7782    resample->large_filter = large_filter; 
    7883    resample->high_quality = high_quality; 
     84    resample->channel_cnt = channel_count; 
    7985    resample->frame_size = samples_per_frame; 
    8086 
    8187    if (high_quality) { 
    82         unsigned size; 
    83  
    8488        /* This is a bug in xoff calculation, thanks Stephane Lussier 
    8589         * of Macadamian dot com. 
     
    8791         */ 
    8892        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 */ 
    90101        size = (samples_per_frame + 2*resample->xoff) * sizeof(pj_int16_t); 
    91102        resample->buffer = (pj_int16_t*) pj_pool_alloc(pool, size); 
     
    94105        pjmedia_zero_samples(resample->buffer, resample->xoff*2); 
    95106 
    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); 
    99128    } 
    100129 
     
    117146    PJ_ASSERT_ON_FAIL(resample, return); 
    118147 
    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) { 
    120215        pj_int16_t *dst_buf; 
    121216        const pj_int16_t *src_buf; 
    122217 
    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 */ 
    189219        dst_buf = resample->buffer + resample->xoff*2; 
    190220        pjmedia_copy_samples(dst_buf, input, resample->frame_size); 
    191221 
    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 */ 
    196233        dst_buf = resample->buffer; 
    197234        src_buf = input + resample->frame_size - resample->xoff*2; 
    198235        pjmedia_copy_samples(dst_buf, src_buf, resample->xoff * 2); 
    199236 
    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        } 
    203283    } 
    204284} 
Note: See TracChangeset for help on using the changeset viewer.