summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-04-07 16:01:41 +0000
committerBenny Prijono <bennylp@teluu.com>2007-04-07 16:01:41 +0000
commit0c4b2974931a0f030c81647c65058fd22108495b (patch)
tree5461e272d2f4cdf39935d7277c56b654dd848f32 /pjmedia
parentca07a9833149d270d1e5b44cfa381ac6ac03e39c (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.dsp12
-rw-r--r--pjmedia/include/pjmedia/resample.h9
-rw-r--r--pjmedia/src/pjmedia/conference.c2
-rw-r--r--pjmedia/src/pjmedia/resample.c271
-rw-r--r--pjmedia/src/pjmedia/resample_port.c12
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;
}