diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-04-07 16:01:41 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-04-07 16:01:41 +0000 |
commit | 0c4b2974931a0f030c81647c65058fd22108495b (patch) | |
tree | 5461e272d2f4cdf39935d7277c56b654dd848f32 /pjmedia | |
parent | ca07a9833149d270d1e5b44cfa381ac6ac03e39c (diff) |
Changed resample to use speex (for now)
git-svn-id: http://svn.pjsip.org/repos/pjproject/branches/split-3rd-party@1171 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r-- | pjmedia/build/pjmedia.dsp | 12 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/resample.h | 9 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/conference.c | 2 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/resample.c | 271 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/resample_port.c | 12 |
5 files changed, 93 insertions, 213 deletions
diff --git a/pjmedia/build/pjmedia.dsp b/pjmedia/build/pjmedia.dsp index 37b66488..3105cd54 100644 --- a/pjmedia/build/pjmedia.dsp +++ b/pjmedia/build/pjmedia.dsp @@ -429,17 +429,5 @@ SOURCE=..\include\pjmedia\wav_port.h SOURCE=..\include\pjmedia\wave.h
# End Source File
# End Group
-# Begin Group "Resample Files"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\src\pjmedia\largefilter.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjmedia\smallfilter.h
-# End Source File
-# End Group
# End Target
# End Project
diff --git a/pjmedia/include/pjmedia/resample.h b/pjmedia/include/pjmedia/resample.h index 4f17d8d2..8aad5087 100644 --- a/pjmedia/include/pjmedia/resample.h +++ b/pjmedia/include/pjmedia/resample.h @@ -66,6 +66,7 @@ typedef struct pjmedia_resample pjmedia_resample; * used, at the expense of more CPU and memory, * because temporary buffer needs to be created. * @param large_filter If true, large filter size will be used. + * @param channel_count Number of channels. * @param rate_in Clock rate of the input samples. * @param rate_out Clock rate of the output samples. * @param samples_per_frame Number of samples per frame in the input. @@ -76,6 +77,7 @@ typedef struct pjmedia_resample pjmedia_resample; PJ_DECL(pj_status_t) pjmedia_resample_create(pj_pool_t *pool, pj_bool_t high_quality, pj_bool_t large_filter, + unsigned channel_count, unsigned rate_in, unsigned rate_out, unsigned samples_per_frame, @@ -107,6 +109,13 @@ PJ_DECL(unsigned) pjmedia_resample_get_input_size(pjmedia_resample *resample); /** + * Destroy the resample. + * + * @param resample The resample session. + */ +PJ_DECL(void) pjmedia_resample_destroy(pjmedia_resample *resample); + +/** * @} */ diff --git a/pjmedia/src/pjmedia/conference.c b/pjmedia/src/pjmedia/conference.c index e540b881..b3619d58 100644 --- a/pjmedia/src/pjmedia/conference.c +++ b/pjmedia/src/pjmedia/conference.c @@ -298,6 +298,7 @@ static pj_status_t create_conf_port( pj_pool_t *pool, status = pjmedia_resample_create( pool, high_quality, large_filter, + conf->channel_count, conf_port->clock_rate,/* Rate in */ conf->clock_rate, /* Rate out */ conf->samples_per_frame * @@ -312,6 +313,7 @@ static pj_status_t create_conf_port( pj_pool_t *pool, status = pjmedia_resample_create(pool, high_quality, large_filter, + conf->channel_count, conf->clock_rate, /* Rate in */ conf_port->clock_rate, /* Rate out */ conf->samples_per_frame, diff --git a/pjmedia/src/pjmedia/resample.c b/pjmedia/src/pjmedia/resample.c index 499f2bc5..85849466 100644 --- a/pjmedia/src/pjmedia/resample.c +++ b/pjmedia/src/pjmedia/resample.c @@ -23,254 +23,125 @@ #include <pj/log.h> #include <pj/pool.h> -#include "../../third_party/build/resample/resamplesubs.h" +#include <speex/speex_resampler.h> #define THIS_FILE "resample.c" struct pjmedia_resample { - double factor; /* Conversion factor = rate_out / rate_in. */ - pj_bool_t large_filter; /* Large filter? */ - pj_bool_t high_quality; /* Not fast? */ - unsigned xoff; /* History and lookahead size, in samples */ - unsigned frame_size; /* Samples per frame. */ - pj_int16_t *buffer; /* Input buffer. */ -}; - - -#ifndef MAX -# define MAX(a,b) ((a) >= (b) ? (a) : (b)) + SpeexResamplerState *state; +#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT != 0 + float *in_buffer; + float *out_buffer; #endif + unsigned in_samples_per_frame; + unsigned out_samples_per_frame; +}; PJ_DEF(pj_status_t) pjmedia_resample_create( pj_pool_t *pool, pj_bool_t high_quality, pj_bool_t large_filter, + unsigned channel_count, unsigned rate_in, unsigned rate_out, unsigned samples_per_frame, pjmedia_resample **p_resample) { pjmedia_resample *resample; + int quality; + int err; PJ_ASSERT_RETURN(pool && p_resample && rate_in && rate_out && samples_per_frame, PJ_EINVAL); - resample = pj_pool_alloc(pool, sizeof(pjmedia_resample)); + resample = PJ_POOL_ZALLOC_T(pool, pjmedia_resample); PJ_ASSERT_RETURN(resample, PJ_ENOMEM); - /* - * If we're downsampling, always use the fast algorithm since it seems - * to yield the same quality. - */ - if (rate_out < rate_in) { - //no this is not a good idea. It sounds pretty good with speech, - //but very poor with background noise etc. - //high_quality = 0; - } - -#if !defined(PJMEDIA_HAS_LARGE_FILTER) || PJMEDIA_HAS_LARGE_FILTER==0 - /* - * If large filter is excluded in the build, then prevent application - * from using it. - */ - if (high_quality && large_filter) { - large_filter = PJ_FALSE; - PJ_LOG(5,(THIS_FILE, - "Resample uses small filter because large filter is " - "disabled")); - } -#endif - -#if !defined(PJMEDIA_HAS_SMALL_FILTER) || PJMEDIA_HAS_SMALL_FILTER==0 - /* - * If small filter is excluded in the build and application wants to - * use it, then drop to linear conversion. - */ - if (high_quality && large_filter == 0) { - high_quality = PJ_FALSE; - PJ_LOG(4,(THIS_FILE, - "Resample uses linear because small filter is disabled")); - } -#endif - - resample->factor = rate_out * 1.0 / rate_in; - resample->large_filter = large_filter; - resample->high_quality = high_quality; - resample->frame_size = samples_per_frame; - if (high_quality) { - unsigned size; - - /* This is a bug in xoff calculation, thanks Stephane Lussier - * of Macadamian dot com. - * resample->xoff = large_filter ? 32 : 6; - */ if (large_filter) - resample->xoff = (unsigned) - ((resample_LARGE_FILTER_NMULT + 1) / 2.0 * - MAX(1.0, 1.0/resample->factor)); + quality = 8; else - resample->xoff = (unsigned) - ((resample_SMALL_FILTER_NMULT + 1) / 2.0 * - MAX(1.0, 1.0/resample->factor)); - - - size = (samples_per_frame + 2*resample->xoff) * sizeof(pj_int16_t); - resample->buffer = pj_pool_alloc(pool, size); - PJ_ASSERT_RETURN(resample->buffer, PJ_ENOMEM); - - pjmedia_zero_samples(resample->buffer, resample->xoff*2); - - + quality = 7; } else { - resample->xoff = 0; + quality = 3; } + resample->in_samples_per_frame = samples_per_frame; + resample->out_samples_per_frame = rate_out / (rate_in / samples_per_frame); + resample->state = speex_resampler_init(channel_count, rate_in, rate_out, + quality, &err); + if (resample->state == NULL || err != RESAMPLER_ERR_SUCCESS) + return PJ_ENOMEM; + +#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT != 0 + resample->in_buffer = pj_pool_calloc(pool, resample->in_samples_per_frame, + sizeof(float)); + resample->out_buffer=pj_pool_calloc(pool, resample->out_samples_per_frame, + sizeof(float)); +#endif + *p_resample = resample; - PJ_LOG(5,(THIS_FILE, "resample created: %s qualiy, %s filter, in/out " - "rate=%d/%d", - (high_quality?"high":"low"), - (large_filter?"large":"small"), - rate_in, rate_out)); + PJ_LOG(5,(THIS_FILE, + "resample created: quality=%d, ch=%d, in/out rate=%d/%d", + quality, channel_count, rate_in, rate_out)); return PJ_SUCCESS; } - PJ_DEF(void) pjmedia_resample_run( pjmedia_resample *resample, const pj_int16_t *input, pj_int16_t *output ) { - PJ_ASSERT_ON_FAIL(resample, return); - - if (resample->high_quality) { - pj_int16_t *dst_buf; - const pj_int16_t *src_buf; - - /* Okay chaps, here's how we do resampling. - * - * The original resample algorithm requires xoff samples *before* the - * input buffer as history, and another xoff samples *after* the - * end of the input buffer as lookahead. Since application can only - * supply framesize buffer on each run, PJMEDIA needs to arrange the - * buffer to meet these requirements. - * - * So here comes the trick. - * - * First of all, because of the history and lookahead requirement, - * resample->buffer need to accomodate framesize+2*xoff samples in its - * buffer. This is done when the buffer is created. - * - * On the first run, the input frame (supplied by application) is - * copied to resample->buffer at 2*xoff position. The first 2*xoff - * samples are initially zeroed (in the initialization). The resample - * algorithm then invoked at resample->buffer+xoff ONLY, thus giving - * it one xoff at the beginning as zero, and one xoff at the end - * as the end of the original input. The resample algorithm will see - * that the first xoff samples in the input as zero. - * - * So here's the layout of resample->buffer on the first run. - * - * run 0 - * +------+------+--------------+ - * | 0000 | 0000 | frame0... | - * +------+------+--------------+ - * ^ ^ ^ ^ - * 0 xoff 2*xoff size+2*xoff - * - * (Note again: resample algorithm is called at resample->buffer+xoff) - * - * At the end of the run, 2*xoff samples from the end of - * resample->buffer are copied to the beginning of resample->buffer. - * The first xoff part of this will be used as history for the next - * run, and the second xoff part of this is actually the start of - * resampling for the next run. - * - * And the first run completes, the function returns. - * - * - * On the next run, the input frame supplied by application is again - * copied at 2*xoff position in the resample->buffer, and the - * resample algorithm is again invoked at resample->buffer+xoff - * position. So effectively, the resample algorithm will start its - * operation on the last xoff from the previous frame, and gets the - * history from the last 2*xoff of the previous frame, and the look- - * ahead from the last xoff of current frame. - * - * So on this run, the buffer layout is: - * - * run 1 - * +------+------+--------------+ - * | frm0 | frm0 | frame1... | - * +------+------+--------------+ - * ^ ^ ^ ^ - * 0 xoff 2*xoff size+2*xoff - * - * As you can see from above diagram, the resampling algorithm is - * actually called from the last xoff part of previous frame (frm0). - * - * And so on the process continues for the next frame, and the next, - * and the next, ... - * - */ - dst_buf = resample->buffer + resample->xoff*2; - pjmedia_copy_samples(dst_buf, input, resample->frame_size); - - if (resample->factor >= 1) { - - if (resample->large_filter) { - SrcUp(resample->buffer + resample->xoff, output, - resample->factor, resample->frame_size, - resample_LARGE_FILTER_NWING, resample_LARGE_FILTER_SCALE, - resample_LARGE_FILTER_IMP, resample_LARGE_FILTER_IMPD, - PJ_TRUE); - } else { - SrcUp(resample->buffer + resample->xoff, output, - resample->factor, resample->frame_size, - resample_SMALL_FILTER_NWING, resample_SMALL_FILTER_SCALE, - resample_SMALL_FILTER_IMP, resample_SMALL_FILTER_IMPD, - PJ_TRUE); - } - - } else { - - if (resample->large_filter) { + spx_uint32_t in_length, out_length; + float *fp; + unsigned i; - SrcUD( resample->buffer + resample->xoff, output, - resample->factor, resample->frame_size, - resample_LARGE_FILTER_NWING, - resample_LARGE_FILTER_SCALE * resample->factor + 0.5, - resample_LARGE_FILTER_IMP, resample_LARGE_FILTER_IMPD, - PJ_TRUE); - - } else { - - SrcUD( resample->buffer + resample->xoff, output, - resample->factor, resample->frame_size, - resample_SMALL_FILTER_NWING, - resample_SMALL_FILTER_SCALE * resample->factor + 0.5, - resample_SMALL_FILTER_IMP, resample_SMALL_FILTER_IMPD, - PJ_TRUE); - - } - - } + PJ_ASSERT_ON_FAIL(resample, return); - dst_buf = resample->buffer; - src_buf = input + resample->frame_size - resample->xoff*2; - pjmedia_copy_samples(dst_buf, src_buf, resample->xoff * 2); + in_length = resample->in_samples_per_frame; + out_length = resample->out_samples_per_frame; - } else { - SrcLinear( input, output, resample->factor, resample->frame_size); +#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT != 0 + fp = resample->in_buffer; + for (i=0; i<in_length; ++i) { + fp[i] = input[i]; + } + speex_resampler_process_interleaved_float(resample->state, + resample->in_buffer, &in_length, + resample->out_buffer, &out_length); + fp = resample->out_buffer; + for (i=0; i<out_length; ++i) { + output[i] = (pj_int16_t)fp[i]; } +#else + PJ_UNUSED_ARG(dst); + PJ_UNUSED_ARG(i); + speex_resampler_process_interleaved_int(resample->state, + (const __int16 *)input, &in_length, + (__int16 *)output, &out_length); +#endif + + pj_assert(in_length == resample->in_samples_per_frame); + pj_assert(out_length == resample->out_samples_per_frame); } + PJ_DEF(unsigned) pjmedia_resample_get_input_size(pjmedia_resample *resample) { PJ_ASSERT_RETURN(resample != NULL, 0); - return resample->frame_size; + return resample->in_samples_per_frame; +} + + +PJ_DEF(void) pjmedia_resample_destroy(pjmedia_resample *resample) +{ + PJ_ASSERT_ON_FAIL(resample, return); + if (resample->state) { + speex_resampler_destroy(resample->state); + resample->state = NULL; + } } diff --git a/pjmedia/src/pjmedia/resample_port.c b/pjmedia/src/pjmedia/resample_port.c index cb95a24a..913f150c 100644 --- a/pjmedia/src/pjmedia/resample_port.c +++ b/pjmedia/src/pjmedia/resample_port.c @@ -95,6 +95,7 @@ PJ_DEF(pj_status_t) pjmedia_resample_port_create( pj_pool_t *pool, status = pjmedia_resample_create(pool, (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0, (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0, + dn_port->info.channel_count, dn_port->info.clock_rate, rport->base.info.clock_rate, dn_port->info.samples_per_frame, @@ -106,6 +107,7 @@ PJ_DEF(pj_status_t) pjmedia_resample_port_create( pj_pool_t *pool, status = pjmedia_resample_create(pool, (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0, (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0, + dn_port->info.channel_count, rport->base.info.clock_rate, dn_port->info.clock_rate, rport->base.info.samples_per_frame, @@ -204,7 +206,15 @@ static pj_status_t resample_destroy(pjmedia_port *this_port) rport->dn_port = NULL; } - /* Nothing else to do */ + if (rport->resample_get) { + pjmedia_resample_destroy(rport->resample_get); + rport->resample_get = NULL; + } + + if (rport->resample_put) { + pjmedia_resample_destroy(rport->resample_put); + rport->resample_put = NULL; + } return PJ_SUCCESS; } |