X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/d7a0876d7ffdac7e48b0664c20408fd429b41d06..dcd4a73df94b0e9083f72d79f81083961bd15746:/src/pulsecore/resampler.c diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index 5bbc6bf4..17fb8480 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -7,7 +5,7 @@ PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, + by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but @@ -27,10 +25,12 @@ #include -#if HAVE_LIBSAMPLERATE +#ifdef HAVE_LIBSAMPLERATE #include #endif +#include + #include #include @@ -38,18 +38,19 @@ #include #include #include - -#include "speexwrap.h" +#include #include "ffmpeg/avcodec.h" #include "resampler.h" /* Number of samples of extra space we allow the resamplers to return */ -#define EXTRA_SAMPLES 128 +#define EXTRA_FRAMES 128 struct pa_resampler { - pa_resample_method_t resample_method; + pa_resample_method_t method; + pa_resample_flags_t flags; + pa_sample_spec i_ss, o_ss; pa_channel_map i_cm, o_cm; size_t i_fz, o_fz, w_sz; @@ -63,18 +64,28 @@ struct pa_resampler { pa_convert_func_t to_work_format_func; pa_convert_func_t from_work_format_func; - int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; - int map_required; + float map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + pa_bool_t map_required; void (*impl_free)(pa_resampler *r); void (*impl_update_rates)(pa_resampler *r); void (*impl_resample)(pa_resampler *r, const pa_memchunk *in, unsigned in_samples, pa_memchunk *out, unsigned *out_samples); + void (*impl_reset)(pa_resampler *r); struct { /* data specific to the trivial resampler */ unsigned o_counter; unsigned i_counter; } trivial; + struct { /* data specific to the peak finder pseudo resampler */ + unsigned o_counter; + unsigned i_counter; + + float max_f[PA_CHANNELS_MAX]; + int16_t max_i[PA_CHANNELS_MAX]; + + } peaks; + #ifdef HAVE_LIBSAMPLERATE struct { /* data specific to libsamplerate */ SRC_STATE *state; @@ -95,6 +106,7 @@ static int copy_init(pa_resampler *r); static int trivial_init(pa_resampler*r); static int speex_init(pa_resampler*r); static int ffmpeg_init(pa_resampler*r); +static int peaks_init(pa_resampler*r); #ifdef HAVE_LIBSAMPLERATE static int libsamplerate_init(pa_resampler*r); #endif @@ -140,27 +152,18 @@ static int (* const init_table[])(pa_resampler*r) = { [PA_RESAMPLER_SPEEX_FIXED_BASE+10] = speex_init, [PA_RESAMPLER_FFMPEG] = ffmpeg_init, [PA_RESAMPLER_AUTO] = NULL, - [PA_RESAMPLER_COPY] = copy_init + [PA_RESAMPLER_COPY] = copy_init, + [PA_RESAMPLER_PEAKS] = peaks_init, }; -static inline size_t sample_size(pa_sample_format_t f) { - pa_sample_spec ss = { - .format = f, - .rate = 0, - .channels = 1 - }; - - return pa_sample_size(&ss); -} - pa_resampler* pa_resampler_new( pa_mempool *pool, const pa_sample_spec *a, const pa_channel_map *am, const pa_sample_spec *b, const pa_channel_map *bm, - pa_resample_method_t resample_method, - int variable_rate) { + pa_resample_method_t method, + pa_resample_flags_t flags) { pa_resampler *r = NULL; @@ -169,41 +172,43 @@ pa_resampler* pa_resampler_new( pa_assert(b); pa_assert(pa_sample_spec_valid(a)); pa_assert(pa_sample_spec_valid(b)); - pa_assert(resample_method >= 0); - pa_assert(resample_method < PA_RESAMPLER_MAX); + pa_assert(method >= 0); + pa_assert(method < PA_RESAMPLER_MAX); /* Fix method */ - if (!variable_rate && a->rate == b->rate) { + if (!(flags & PA_RESAMPLER_VARIABLE_RATE) && a->rate == b->rate) { pa_log_info("Forcing resampler 'copy', because of fixed, identical sample rates."); - resample_method = PA_RESAMPLER_COPY; + method = PA_RESAMPLER_COPY; } - if (!pa_resample_method_supported(resample_method)) { - pa_log_warn("Support for resampler '%s' not compiled in, reverting to 'auto'.", pa_resample_method_to_string(resample_method)); - resample_method = PA_RESAMPLER_AUTO; + if (!pa_resample_method_supported(method)) { + pa_log_warn("Support for resampler '%s' not compiled in, reverting to 'auto'.", pa_resample_method_to_string(method)); + method = PA_RESAMPLER_AUTO; } - if (resample_method == PA_RESAMPLER_FFMPEG && variable_rate) { + if (method == PA_RESAMPLER_FFMPEG && (flags & PA_RESAMPLER_VARIABLE_RATE)) { pa_log_info("Resampler 'ffmpeg' cannot do variable rate, reverting to resampler 'auto'."); - resample_method = PA_RESAMPLER_AUTO; + method = PA_RESAMPLER_AUTO; } - if (resample_method == PA_RESAMPLER_COPY && (variable_rate || a->rate != b->rate)) { + if (method == PA_RESAMPLER_COPY && ((flags & PA_RESAMPLER_VARIABLE_RATE) || a->rate != b->rate)) { pa_log_info("Resampler 'copy' cannot change sampling rate, reverting to resampler 'auto'."); - resample_method = PA_RESAMPLER_AUTO; + method = PA_RESAMPLER_AUTO; } - if (resample_method == PA_RESAMPLER_AUTO) - resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 0; + if (method == PA_RESAMPLER_AUTO) + method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 3; r = pa_xnew(pa_resampler, 1); r->mempool = pool; - r->resample_method = resample_method; + r->method = method; + r->flags = flags; r->impl_free = NULL; r->impl_update_rates = NULL; r->impl_resample = NULL; + r->impl_reset = NULL; /* Fill sample specs */ r->i_ss = *a; @@ -211,13 +216,13 @@ pa_resampler* pa_resampler_new( if (am) r->i_cm = *am; - else - pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels, PA_CHANNEL_MAP_DEFAULT); + else if (!pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels, PA_CHANNEL_MAP_DEFAULT)) + goto fail; if (bm) r->o_cm = *bm; - else - pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels, PA_CHANNEL_MAP_DEFAULT); + else if (!pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels, PA_CHANNEL_MAP_DEFAULT)) + goto fail; r->i_fz = pa_frame_size(a); r->o_fz = pa_frame_size(b); @@ -231,17 +236,23 @@ pa_resampler* pa_resampler_new( calc_map_table(r); - pa_log_info("Using resampler '%s'", pa_resample_method_to_string(resample_method)); + pa_log_info("Using resampler '%s'", pa_resample_method_to_string(method)); - if ((resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) || - (resample_method == PA_RESAMPLER_FFMPEG)) + if ((method >= PA_RESAMPLER_SPEEX_FIXED_BASE && method <= PA_RESAMPLER_SPEEX_FIXED_MAX) || + (method == PA_RESAMPLER_FFMPEG)) r->work_format = PA_SAMPLE_S16NE; - else if (resample_method == PA_RESAMPLER_TRIVIAL || resample_method == PA_RESAMPLER_COPY) { - - if (r->map_required || a->format != b->format) { - - if (a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE || - b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE) + else if (method == PA_RESAMPLER_TRIVIAL || method == PA_RESAMPLER_COPY || method == PA_RESAMPLER_PEAKS) { + + if (r->map_required || a->format != b->format || method == PA_RESAMPLER_PEAKS) { + + if (a->format == PA_SAMPLE_S32NE || a->format == PA_SAMPLE_S32RE || + a->format == PA_SAMPLE_FLOAT32NE || a->format == PA_SAMPLE_FLOAT32RE || + a->format == PA_SAMPLE_S24NE || a->format == PA_SAMPLE_S24RE || + a->format == PA_SAMPLE_S24_32NE || a->format == PA_SAMPLE_S24_32RE || + b->format == PA_SAMPLE_S32NE || b->format == PA_SAMPLE_S32RE || + b->format == PA_SAMPLE_FLOAT32NE || b->format == PA_SAMPLE_FLOAT32RE || + b->format == PA_SAMPLE_S24NE || b->format == PA_SAMPLE_S24RE || + b->format == PA_SAMPLE_S24_32NE || b->format == PA_SAMPLE_S24_32RE) r->work_format = PA_SAMPLE_FLOAT32NE; else r->work_format = PA_SAMPLE_S16NE; @@ -254,7 +265,7 @@ pa_resampler* pa_resampler_new( pa_log_info("Using %s as working format.", pa_sample_format_to_string(r->work_format)); - r->w_sz = sample_size(r->work_format); + r->w_sz = pa_sample_size_of_format(r->work_format); if (r->i_ss.format == r->work_format) r->to_work_format_func = NULL; @@ -279,7 +290,7 @@ pa_resampler* pa_resampler_new( } /* initialize implementation */ - if (init_table[resample_method](r) < 0) + if (init_table[method](r) < 0) goto fail; return r; @@ -339,6 +350,12 @@ size_t pa_resampler_request(pa_resampler *r, size_t out_length) { return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; } +size_t pa_resampler_result(pa_resampler *r, size_t in_length) { + pa_assert(r); + + return (((in_length / r->i_fz)*r->o_ss.rate)/r->i_ss.rate) * r->o_fz; +} + size_t pa_resampler_max_block_size(pa_resampler *r) { size_t block_size_max; pa_sample_spec ss; @@ -350,28 +367,54 @@ size_t pa_resampler_max_block_size(pa_resampler *r) { /* We deduce the "largest" sample spec we're using during the * conversion */ - ss = r->i_ss; - if (r->o_ss.channels > ss.channels) - ss.channels = r->o_ss.channels; + ss.channels = (uint8_t) (PA_MAX(r->i_ss.channels, r->o_ss.channels)); /* We silently assume that the format enum is ordered by size */ - if (r->o_ss.format > ss.format) - ss.format = r->o_ss.format; - if (r->work_format > ss.format) - ss.format = r->work_format; + ss.format = PA_MAX(r->i_ss.format, r->o_ss.format); + ss.format = PA_MAX(ss.format, r->work_format); - if (r->o_ss.rate > ss.rate) - ss.rate = r->o_ss.rate; + ss.rate = PA_MAX(r->i_ss.rate, r->o_ss.rate); fs = pa_frame_size(&ss); - return (((block_size_max/fs + EXTRA_SAMPLES)*r->i_ss.rate)/ss.rate)*r->i_fz; + return (((block_size_max/fs - EXTRA_FRAMES)*r->i_ss.rate)/ss.rate)*r->i_fz; +} + +void pa_resampler_reset(pa_resampler *r) { + pa_assert(r); + + if (r->impl_reset) + r->impl_reset(r); } pa_resample_method_t pa_resampler_get_method(pa_resampler *r) { pa_assert(r); - return r->resample_method; + return r->method; +} + +const pa_channel_map* pa_resampler_input_channel_map(pa_resampler *r) { + pa_assert(r); + + return &r->i_cm; +} + +const pa_sample_spec* pa_resampler_input_sample_spec(pa_resampler *r) { + pa_assert(r); + + return &r->i_ss; +} + +const pa_channel_map* pa_resampler_output_channel_map(pa_resampler *r) { + pa_assert(r); + + return &r->o_cm; +} + +const pa_sample_spec* pa_resampler_output_sample_spec(pa_resampler *r) { + pa_assert(r); + + return &r->o_ss; } static const char * const resample_methods[] = { @@ -405,7 +448,8 @@ static const char * const resample_methods[] = { "speex-fixed-10", "ffmpeg", "auto", - "copy" + "copy", + "peaks" }; const char *pa_resample_method_to_string(pa_resample_method_t m) { @@ -439,44 +483,525 @@ pa_resample_method_t pa_parse_resample_method(const char *string) { return m; if (!strcmp(string, "speex-fixed")) - return PA_RESAMPLER_SPEEX_FIXED_BASE + 0; + return PA_RESAMPLER_SPEEX_FIXED_BASE + 3; if (!strcmp(string, "speex-float")) - return PA_RESAMPLER_SPEEX_FLOAT_BASE + 0; + return PA_RESAMPLER_SPEEX_FLOAT_BASE + 3; return PA_RESAMPLER_INVALID; } +static pa_bool_t on_left(pa_channel_position_t p) { + + return + p == PA_CHANNEL_POSITION_FRONT_LEFT || + p == PA_CHANNEL_POSITION_REAR_LEFT || + p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER || + p == PA_CHANNEL_POSITION_SIDE_LEFT || + p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT || + p == PA_CHANNEL_POSITION_TOP_REAR_LEFT; +} + +static pa_bool_t on_right(pa_channel_position_t p) { + + return + p == PA_CHANNEL_POSITION_FRONT_RIGHT || + p == PA_CHANNEL_POSITION_REAR_RIGHT || + p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER || + p == PA_CHANNEL_POSITION_SIDE_RIGHT || + p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT || + p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT; +} + +static pa_bool_t on_center(pa_channel_position_t p) { + + return + p == PA_CHANNEL_POSITION_FRONT_CENTER || + p == PA_CHANNEL_POSITION_REAR_CENTER || + p == PA_CHANNEL_POSITION_TOP_CENTER || + p == PA_CHANNEL_POSITION_TOP_FRONT_CENTER || + p == PA_CHANNEL_POSITION_TOP_REAR_CENTER; +} + +static pa_bool_t on_lfe(pa_channel_position_t p) { + return + p == PA_CHANNEL_POSITION_LFE; +} + +static pa_bool_t on_front(pa_channel_position_t p) { + return + p == PA_CHANNEL_POSITION_FRONT_LEFT || + p == PA_CHANNEL_POSITION_FRONT_RIGHT || + p == PA_CHANNEL_POSITION_FRONT_CENTER || + p == PA_CHANNEL_POSITION_TOP_FRONT_LEFT || + p == PA_CHANNEL_POSITION_TOP_FRONT_RIGHT || + p == PA_CHANNEL_POSITION_TOP_FRONT_CENTER || + p == PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER || + p == PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; +} + +static pa_bool_t on_rear(pa_channel_position_t p) { + return + p == PA_CHANNEL_POSITION_REAR_LEFT || + p == PA_CHANNEL_POSITION_REAR_RIGHT || + p == PA_CHANNEL_POSITION_REAR_CENTER || + p == PA_CHANNEL_POSITION_TOP_REAR_LEFT || + p == PA_CHANNEL_POSITION_TOP_REAR_RIGHT || + p == PA_CHANNEL_POSITION_TOP_REAR_CENTER; +} + +static pa_bool_t on_side(pa_channel_position_t p) { + return + p == PA_CHANNEL_POSITION_SIDE_LEFT || + p == PA_CHANNEL_POSITION_SIDE_RIGHT || + p == PA_CHANNEL_POSITION_TOP_CENTER; +} + +enum { + ON_FRONT, + ON_REAR, + ON_SIDE, + ON_OTHER +}; + +static int front_rear_side(pa_channel_position_t p) { + if (on_front(p)) + return ON_FRONT; + if (on_rear(p)) + return ON_REAR; + if (on_side(p)) + return ON_SIDE; + return ON_OTHER; +} + static void calc_map_table(pa_resampler *r) { - unsigned oc; + unsigned oc, ic; + pa_bool_t ic_connected[PA_CHANNELS_MAX]; + pa_bool_t remix; + pa_strbuf *s; + char *t; pa_assert(r); - if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || !pa_channel_map_equal(&r->i_cm, &r->o_cm)))) + if (!(r->map_required = (r->i_ss.channels != r->o_ss.channels || (!(r->flags & PA_RESAMPLER_NO_REMAP) && !pa_channel_map_equal(&r->i_cm, &r->o_cm))))) return; + memset(r->map_table, 0, sizeof(r->map_table)); + memset(ic_connected, 0, sizeof(ic_connected)); + remix = (r->flags & (PA_RESAMPLER_NO_REMAP|PA_RESAMPLER_NO_REMIX)) == 0; + for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned ic, i = 0; + pa_bool_t oc_connected = FALSE; + pa_channel_position_t b = r->o_cm.map[oc]; for (ic = 0; ic < r->i_ss.channels; ic++) { - pa_channel_position_t a, b; + pa_channel_position_t a = r->i_cm.map[ic]; + + if (r->flags & PA_RESAMPLER_NO_REMAP) { + /* We shall not do any remapping. Hence, just check by index */ + + if (ic == oc) + r->map_table[oc][ic] = 1.0; + + continue; + } + + if (r->flags & PA_RESAMPLER_NO_REMIX) { + /* We shall not do any remixing. Hence, just check by name */ + + if (a == b) + r->map_table[oc][ic] = 1.0; + + continue; + } + + pa_assert(remix); + + /* OK, we shall do the full monty: upmixing and + * downmixing. Our algorithm is relatively simple, does + * not do spacialization, delay elements or apply lowpass + * filters for LFE. Patches are always welcome, + * though. Oh, and it doesn't do any matrix + * decoding. (Which probably wouldn't make any sense + * anyway.) + * + * This code is not idempotent: downmixing an upmixed + * stereo stream is not identical to the original. The + * volume will not match, and the two channels will be a + * linear combination of both. + * + * This is losely based on random suggestions found on the + * Internet, such as this: + * http://www.halfgaar.net/surround-sound-in-linux and the + * alsa upmix plugin. + * + * The algorithm works basically like this: + * + * 1) Connect all channels with matching names. + * + * 2) Mono Handling: + * S:Mono: Copy into all D:channels + * D:Mono: Copy in all S:channels + * + * 3) Mix D:Left, D:Right: + * D:Left: If not connected, avg all S:Left + * D:Right: If not connected, avg all S:Right + * + * 4) Mix D:Center + * If not connected, avg all S:Center + * If still not connected, avg all S:Left, S:Right + * + * 5) Mix D:LFE + * If not connected, avg all S:* + * + * 6) Make sure S:Left/S:Right is used: S:Left/S:Right: If + * not connected, mix into all D:left and all D:right + * channels. Gain is 0.1, the current left and right + * should be multiplied by 0.9. + * + * 7) Make sure S:Center, S:LFE is used: + * + * S:Center, S:LFE: If not connected, mix into all + * D:left, all D:right, all D:center channels, gain is + * 0.375. The current (as result of 1..6) factors + * should be multiplied by 0.75. (Alt. suggestion: 0.25 + * vs. 0.5) If C-front is only mixed into + * L-front/R-front if available, otherwise into all L/R + * channels. Similarly for C-rear. + * + * S: and D: shall relate to the source resp. destination channels. + * + * Rationale: 1, 2 are probably obvious. For 3: this + * copies front to rear if needed. For 4: we try to find + * some suitable C source for C, if we don't find any, we + * avg L and R. For 5: LFE is mixed from all channels. For + * 6: the rear channels should not be dropped entirely, + * however have only minimal impact. For 7: movies usually + * encode speech on the center channel. Thus we have to + * make sure this channel is distributed to L and R if not + * available in the output. Also, LFE is used to achieve a + * greater dynamic range, and thus we should try to do our + * best to pass it to L+R. + */ + + if (a == b || a == PA_CHANNEL_POSITION_MONO || b == PA_CHANNEL_POSITION_MONO) { + r->map_table[oc][ic] = 1.0; + + oc_connected = TRUE; + ic_connected[ic] = TRUE; + } + } + + if (!oc_connected && remix) { + /* OK, we shall remix */ + + /* Try to find matching input ports for this output port */ + + if (on_left(b)) { + unsigned n = 0; + + /* We are not connected and on the left side, let's + * average all left side input channels. */ + + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_left(r->i_cm.map[ic])) + n++; + + if (n > 0) + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_left(r->i_cm.map[ic])) { + r->map_table[oc][ic] = 1.0f / (float) n; + ic_connected[ic] = TRUE; + } + + /* We ignore the case where there is no left input + * channel. Something is really wrong in this case + * anyway. */ + + } else if (on_right(b)) { + unsigned n = 0; + + /* We are not connected and on the right side, let's + * average all right side input channels. */ + + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_right(r->i_cm.map[ic])) + n++; + + if (n > 0) + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_right(r->i_cm.map[ic])) { + r->map_table[oc][ic] = 1.0f / (float) n; + ic_connected[ic] = TRUE; + } + + /* We ignore the case where there is no right input + * channel. Something is really wrong in this case + * anyway. */ + + } else if (on_center(b)) { + unsigned n = 0; + + /* We are not connected and at the center. Let's + * average all center input channels. */ + + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_center(r->i_cm.map[ic])) + n++; + + if (n > 0) { + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_center(r->i_cm.map[ic])) { + r->map_table[oc][ic] = 1.0f / (float) n; + ic_connected[ic] = TRUE; + } + } else { + + /* Hmm, no center channel around, let's synthesize + * it by mixing L and R.*/ + + n = 0; + + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) + n++; + + if (n > 0) + for (ic = 0; ic < r->i_ss.channels; ic++) + if (on_left(r->i_cm.map[ic]) || on_right(r->i_cm.map[ic])) { + r->map_table[oc][ic] = 1.0f / (float) n; + ic_connected[ic] = TRUE; + } + + /* We ignore the case where there is not even a + * left or right input channel. Something is + * really wrong in this case anyway. */ + } + + } else if (on_lfe(b)) { + + /* We are not connected and an LFE. Let's average all + * channels for LFE. */ + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (!(r->flags & PA_RESAMPLER_NO_LFE)) + r->map_table[oc][ic] = 1.0f / (float) r->i_ss.channels; + else + r->map_table[oc][ic] = 0; + + /* Please note that a channel connected to LFE + * doesn't really count as connected. */ + } + } + } + } + + if (remix) { + unsigned + ic_unconnected_left = 0, + ic_unconnected_right = 0, + ic_unconnected_center = 0, + ic_unconnected_lfe = 0; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + pa_channel_position_t a = r->i_cm.map[ic]; + + if (ic_connected[ic]) + continue; + + if (on_left(a)) + ic_unconnected_left++; + else if (on_right(a)) + ic_unconnected_right++; + else if (on_center(a)) + ic_unconnected_center++; + else if (on_lfe(a)) + ic_unconnected_lfe++; + } + + if (ic_unconnected_left > 0) { + + /* OK, so there are unconnected input channels on the + * left. Let's multiply all already connected channels on + * the left side by .9 and add in our averaged unconnected + * channels multplied by .1 */ + + for (oc = 0; oc < r->o_ss.channels; oc++) { + + if (!on_left(r->o_cm.map[oc])) + continue; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (ic_connected[ic]) { + r->map_table[oc][ic] *= .9f; + continue; + } + + if (on_left(r->i_cm.map[ic])) + r->map_table[oc][ic] = .1f / (float) ic_unconnected_left; + } + } + } + + if (ic_unconnected_right > 0) { + + /* OK, so there are unconnected input channels on the + * right. Let's multiply all already connected channels on + * the right side by .9 and add in our averaged unconnected + * channels multplied by .1 */ + + for (oc = 0; oc < r->o_ss.channels; oc++) { + + if (!on_right(r->o_cm.map[oc])) + continue; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (ic_connected[ic]) { + r->map_table[oc][ic] *= .9f; + continue; + } + + if (on_right(r->i_cm.map[ic])) + r->map_table[oc][ic] = .1f / (float) ic_unconnected_right; + } + } + } + + if (ic_unconnected_center > 0) { + pa_bool_t mixed_in = FALSE; + + /* OK, so there are unconnected input channels on the + * center. Let's multiply all already connected channels on + * the center side by .9 and add in our averaged unconnected + * channels multplied by .1 */ + + for (oc = 0; oc < r->o_ss.channels; oc++) { + + if (!on_center(r->o_cm.map[oc])) + continue; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (ic_connected[ic]) { + r->map_table[oc][ic] *= .9f; + continue; + } + + if (on_center(r->i_cm.map[ic])) { + r->map_table[oc][ic] = .1f / (float) ic_unconnected_center; + mixed_in = TRUE; + } + } + } - a = r->i_cm.map[ic]; - b = r->o_cm.map[oc]; + if (!mixed_in) { + unsigned ncenter[PA_CHANNELS_MAX]; + pa_bool_t found_frs[PA_CHANNELS_MAX]; - if (a == b || - (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) || - (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) || - (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || - (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) + memset(ncenter, 0, sizeof(ncenter)); + memset(found_frs, 0, sizeof(found_frs)); - r->map_table[oc][i++] = ic; + /* Hmm, as it appears there was no center channel we + could mix our center channel in. In this case, mix + it into left and right. Using .375 and 0.75 as + factors. */ + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (ic_connected[ic]) + continue; + + if (!on_center(r->i_cm.map[ic])) + continue; + + for (oc = 0; oc < r->o_ss.channels; oc++) { + + if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc])) + continue; + + if (front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc])) { + found_frs[ic] = TRUE; + break; + } + } + + for (oc = 0; oc < r->o_ss.channels; oc++) { + + if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc])) + continue; + + if (!found_frs[ic] || front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc])) + ncenter[oc]++; + } + } + + for (oc = 0; oc < r->o_ss.channels; oc++) { + + if (!on_left(r->o_cm.map[oc]) && !on_right(r->o_cm.map[oc])) + continue; + + if (ncenter[oc] <= 0) + continue; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (ic_connected[ic]) { + r->map_table[oc][ic] *= .75f; + continue; + } + + if (!on_center(r->i_cm.map[ic])) + continue; + + if (!found_frs[ic] || front_rear_side(r->i_cm.map[ic]) == front_rear_side(r->o_cm.map[oc])) + r->map_table[oc][ic] = .375f / (float) ncenter[oc]; + } + } + } } - /* Add an end marker */ - if (i < PA_CHANNELS_MAX) - r->map_table[oc][i] = -1; + if (ic_unconnected_lfe > 0 && !(r->flags & PA_RESAMPLER_NO_LFE)) { + + /* OK, so there is an unconnected LFE channel. Let's mix + * it into all channels, with factor 0.375 */ + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (!on_lfe(r->i_cm.map[ic])) + continue; + + for (oc = 0; oc < r->o_ss.channels; oc++) + r->map_table[oc][ic] = 0.375f / (float) ic_unconnected_lfe; + } + } } + + + s = pa_strbuf_new(); + + pa_strbuf_printf(s, " "); + for (ic = 0; ic < r->i_ss.channels; ic++) + pa_strbuf_printf(s, " I%02u ", ic); + pa_strbuf_puts(s, "\n +"); + + for (ic = 0; ic < r->i_ss.channels; ic++) + pa_strbuf_printf(s, "------"); + pa_strbuf_puts(s, "\n"); + + for (oc = 0; oc < r->o_ss.channels; oc++) { + pa_strbuf_printf(s, "O%02u |", oc); + + for (ic = 0; ic < r->i_ss.channels; ic++) + pa_strbuf_printf(s, " %1.3f", r->map_table[oc][ic]); + + pa_strbuf_puts(s, "\n"); + } + + pa_log_debug("Channel matrix:\n%s", t = pa_strbuf_tostring_free(s)); + pa_xfree(t); } static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) { @@ -492,7 +1017,7 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) if (!r->to_work_format_func || !input->length) return input; - n_samples = (input->length / r->i_fz) * r->i_ss.channels; + n_samples = (unsigned) ((input->length / r->i_fz) * r->i_ss.channels); r->buf1.index = 0; r->buf1.length = r->w_sz * n_samples; @@ -516,6 +1041,36 @@ static pa_memchunk* convert_to_work_format(pa_resampler *r, pa_memchunk *input) return &r->buf1; } +static void vectoradd_s16_with_fraction( + int16_t *d, int dstr, + const int16_t *s1, int sstr1, + const int16_t *s2, int sstr2, + int n, + float s3, float s4) { + + int32_t i3, i4; + + i3 = (int32_t) (s3 * 0x10000); + i4 = (int32_t) (s4 * 0x10000); + + for (; n > 0; n--) { + int32_t a, b; + + a = *s1; + b = *s2; + + a = (a * i3) / 0x10000; + b = (b * i4) / 0x10000; + + *d = (int16_t) (a + b); + + s1 = (const int16_t*) ((const uint8_t*) s1 + sstr1); + s2 = (const int16_t*) ((const uint8_t*) s2 + sstr2); + d = (int16_t*) ((uint8_t*) d + dstr); + + } +} + static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { unsigned in_n_samples, out_n_samples, n_frames; int i_skip, o_skip; @@ -531,7 +1086,7 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { if (!r->map_required || !input->length) return input; - in_n_samples = input->length / r->w_sz; + in_n_samples = (unsigned) (input->length / r->w_sz); n_frames = in_n_samples / r->i_ss.channels; out_n_samples = n_frames * r->o_ss.channels; @@ -551,23 +1106,28 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { memset(dst, 0, r->buf2.length); - o_skip = r->w_sz * r->o_ss.channels; - i_skip = r->w_sz * r->i_ss.channels; + o_skip = (int) (r->w_sz * r->o_ss.channels); + i_skip = (int) (r->w_sz * r->i_ss.channels); switch (r->work_format) { case PA_SAMPLE_FLOAT32NE: for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned i; + unsigned ic; static const float one = 1.0; - for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++) + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (r->map_table[oc][ic] <= 0.0) + continue; + oil_vectoradd_f32( (float*) dst + oc, o_skip, (float*) dst + oc, o_skip, - (float*) src + r->map_table[oc][i], i_skip, - n_frames, - &one, &one); + (float*) src + ic, i_skip, + (int) n_frames, + &one, &r->map_table[oc][ic]); + } } break; @@ -575,16 +1135,32 @@ static pa_memchunk *remap_channels(pa_resampler *r, pa_memchunk *input) { case PA_SAMPLE_S16NE: for (oc = 0; oc < r->o_ss.channels; oc++) { - unsigned i; - static const int16_t one = 1; - - for (i = 0; i < PA_CHANNELS_MAX && r->map_table[oc][i] >= 0; i++) - oil_vectoradd_s16( - (int16_t*) dst + oc, o_skip, - (int16_t*) dst + oc, o_skip, - (int16_t*) src + r->map_table[oc][i], i_skip, - n_frames, - &one, &one); + unsigned ic; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + + if (r->map_table[oc][ic] <= 0.0) + continue; + + if (r->map_table[oc][ic] >= 1.0) { + static const int16_t one = 1; + + oil_vectoradd_s16( + (int16_t*) dst + oc, o_skip, + (int16_t*) dst + oc, o_skip, + (int16_t*) src + ic, i_skip, + (int) n_frames, + &one, &one); + + } else + + vectoradd_s16_with_fraction( + (int16_t*) dst + oc, o_skip, + (int16_t*) dst + oc, o_skip, + (int16_t*) src + ic, i_skip, + (int) n_frames, + 1.0f, r->map_table[oc][ic]); + } } break; @@ -613,10 +1189,10 @@ static pa_memchunk *resample(pa_resampler *r, pa_memchunk *input) { if (!r->impl_resample || !input->length) return input; - in_n_samples = input->length / r->w_sz; - in_n_frames = in_n_samples / r->o_ss.channels; + in_n_samples = (unsigned) (input->length / r->w_sz); + in_n_frames = (unsigned) (in_n_samples / r->o_ss.channels); - out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+EXTRA_SAMPLES; + out_n_frames = ((in_n_frames*r->o_ss.rate)/r->i_ss.rate)+EXTRA_FRAMES; out_n_samples = out_n_frames * r->o_ss.channels; r->buf3.index = 0; @@ -648,8 +1224,8 @@ static pa_memchunk *convert_from_work_format(pa_resampler *r, pa_memchunk *input if (!r->from_work_format_func || !input->length) return input; - n_samples = input->length / r->w_sz; - n_frames = n_samples / r->o_ss.channels; + n_samples = (unsigned) (input->length / r->w_sz); + n_frames = n_samples / r->o_ss.channels; r->buf4.index = 0; r->buf4.length = r->o_fz * n_frames; @@ -714,10 +1290,10 @@ static void libsamplerate_resample(pa_resampler *r, const pa_memchunk *input, un memset(&data, 0, sizeof(data)); data.data_in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); - data.input_frames = in_n_frames; + data.input_frames = (long int) in_n_frames; data.data_out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index); - data.output_frames = *out_n_frames; + data.output_frames = (long int) *out_n_frames; data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; data.end_of_input = 0; @@ -728,7 +1304,7 @@ static void libsamplerate_resample(pa_resampler *r, const pa_memchunk *input, un pa_memblock_release(input->memblock); pa_memblock_release(output->memblock); - *out_n_frames = data.output_frames_gen; + *out_n_frames = (unsigned) data.output_frames_gen; } static void libsamplerate_update_rates(pa_resampler *r) { @@ -737,6 +1313,12 @@ static void libsamplerate_update_rates(pa_resampler *r) { pa_assert_se(src_set_ratio(r->src.state, (double) r->o_ss.rate / r->i_ss.rate) == 0); } +static void libsamplerate_reset(pa_resampler *r) { + pa_assert(r); + + pa_assert_se(src_reset(r->src.state) == 0); +} + static void libsamplerate_free(pa_resampler *r) { pa_assert(r); @@ -749,12 +1331,13 @@ static int libsamplerate_init(pa_resampler *r) { pa_assert(r); - if (!(r->src.state = src_new(r->resample_method, r->o_ss.channels, &err))) + if (!(r->src.state = src_new(r->method, r->o_ss.channels, &err))) return -1; r->impl_free = libsamplerate_free; r->impl_update_rates = libsamplerate_update_rates; r->impl_resample = libsamplerate_resample; + r->impl_reset = libsamplerate_reset; return 0; } @@ -774,7 +1357,7 @@ static void speex_resample_float(pa_resampler *r, const pa_memchunk *input, unsi in = (float*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); out = (float*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index); - pa_assert_se(paspfl_resampler_process_interleaved_float(r->speex.state, in, &inf, out, &outf) == 0); + pa_assert_se(speex_resampler_process_interleaved_float(r->speex.state, in, &inf, out, &outf) == 0); pa_memblock_release(input->memblock); pa_memblock_release(output->memblock); @@ -795,7 +1378,7 @@ static void speex_resample_int(pa_resampler *r, const pa_memchunk *input, unsign in = (int16_t*) ((uint8_t*) pa_memblock_acquire(input->memblock) + input->index); out = (int16_t*) ((uint8_t*) pa_memblock_acquire(output->memblock) + output->index); - pa_assert_se(paspfx_resampler_process_interleaved_int(r->speex.state, in, &inf, out, &outf) == 0); + pa_assert_se(speex_resampler_process_interleaved_int(r->speex.state, in, &inf, out, &outf) == 0); pa_memblock_release(input->memblock); pa_memblock_release(output->memblock); @@ -807,12 +1390,13 @@ static void speex_resample_int(pa_resampler *r, const pa_memchunk *input, unsign static void speex_update_rates(pa_resampler *r) { pa_assert(r); - if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) - pa_assert_se(paspfx_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0); - else { - pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); - pa_assert_se(paspfl_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0); - } + pa_assert_se(speex_resampler_set_rate(r->speex.state, r->i_ss.rate, r->o_ss.rate) == 0); +} + +static void speex_reset(pa_resampler *r) { + pa_assert(r); + + pa_assert_se(speex_resampler_reset_mem(r->speex.state) == 0); } static void speex_free(pa_resampler *r) { @@ -821,12 +1405,7 @@ static void speex_free(pa_resampler *r) { if (!r->speex.state) return; - if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) - paspfx_resampler_destroy(r->speex.state); - else { - pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); - paspfl_resampler_destroy(r->speex.state); - } + speex_resampler_destroy(r->speex.state); } static int speex_init(pa_resampler *r) { @@ -836,28 +1415,25 @@ static int speex_init(pa_resampler *r) { r->impl_free = speex_free; r->impl_update_rates = speex_update_rates; + r->impl_reset = speex_reset; - if (r->resample_method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FIXED_MAX) { - q = r->resample_method - PA_RESAMPLER_SPEEX_FIXED_BASE; - - pa_log_info("Choosing speex quality setting %i.", q); - - if (!(r->speex.state = paspfx_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err))) - return -1; + if (r->method >= PA_RESAMPLER_SPEEX_FIXED_BASE && r->method <= PA_RESAMPLER_SPEEX_FIXED_MAX) { + q = r->method - PA_RESAMPLER_SPEEX_FIXED_BASE; r->impl_resample = speex_resample_int; - } else { - pa_assert(r->resample_method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->resample_method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); - q = r->resample_method - PA_RESAMPLER_SPEEX_FLOAT_BASE; - pa_log_info("Choosing speex quality setting %i.", q); - - if (!(r->speex.state = paspfl_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err))) - return -1; + } else { + pa_assert(r->method >= PA_RESAMPLER_SPEEX_FLOAT_BASE && r->method <= PA_RESAMPLER_SPEEX_FLOAT_MAX); + q = r->method - PA_RESAMPLER_SPEEX_FLOAT_BASE; r->impl_resample = speex_resample_float; } + pa_log_info("Choosing speex quality setting %i.", q); + + if (!(r->speex.state = speex_resampler_init(r->o_ss.channels, r->i_ss.rate, r->o_ss.rate, q, &err))) + return -1; + return 0; } @@ -890,7 +1466,7 @@ static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned pa_assert(o_index * fz < pa_memblock_get_length(output->memblock)); oil_memcpy((uint8_t*) dst + fz * o_index, - (uint8_t*) src + fz * j, fz); + (uint8_t*) src + fz * j, (int) fz); } pa_memblock_release(input->memblock); @@ -909,7 +1485,7 @@ static void trivial_resample(pa_resampler *r, const pa_memchunk *input, unsigned } } -static void trivial_update_rates(pa_resampler *r) { +static void trivial_update_rates_or_reset(pa_resampler *r) { pa_assert(r); r->trivial.i_counter = 0; @@ -922,8 +1498,126 @@ static int trivial_init(pa_resampler*r) { r->trivial.o_counter = r->trivial.i_counter = 0; r->impl_resample = trivial_resample; - r->impl_update_rates = trivial_update_rates; - r->impl_free = NULL; + r->impl_update_rates = trivial_update_rates_or_reset; + r->impl_reset = trivial_update_rates_or_reset; + + return 0; +} + +/* Peak finder implementation */ + +static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned in_n_frames, pa_memchunk *output, unsigned *out_n_frames) { + size_t fz; + unsigned o_index; + void *src, *dst; + unsigned start = 0; + + pa_assert(r); + pa_assert(input); + pa_assert(output); + pa_assert(out_n_frames); + + fz = r->w_sz * r->o_ss.channels; + + src = (uint8_t*) pa_memblock_acquire(input->memblock) + input->index; + dst = (uint8_t*) pa_memblock_acquire(output->memblock) + output->index; + + for (o_index = 0;; o_index++, r->peaks.o_counter++) { + unsigned j; + + j = ((r->peaks.o_counter * r->i_ss.rate) / r->o_ss.rate); + + if (j > r->peaks.i_counter) + j -= r->peaks.i_counter; + else + j = 0; + + pa_assert(o_index * fz < pa_memblock_get_length(output->memblock)); + + if (r->work_format == PA_SAMPLE_S16NE) { + unsigned i, c; + int16_t *s = (int16_t*) ((uint8_t*) src + fz * start); + int16_t *d = (int16_t*) ((uint8_t*) dst + fz * o_index); + + for (i = start; i <= j && i < in_n_frames; i++) + + for (c = 0; c < r->o_ss.channels; c++, s++) { + int16_t n; + + n = (int16_t) (*s < 0 ? -*s : *s); + + if (PA_UNLIKELY(n > r->peaks.max_i[c])) + r->peaks.max_i[c] = n; + } + + if (i >= in_n_frames) + break; + + for (c = 0; c < r->o_ss.channels; c++, d++) { + *d = r->peaks.max_i[c]; + r->peaks.max_i[c] = 0; + } + + } else { + unsigned i, c; + float *s = (float*) ((uint8_t*) src + fz * start); + float *d = (float*) ((uint8_t*) dst + fz * o_index); + + pa_assert(r->work_format == PA_SAMPLE_FLOAT32NE); + + for (i = start; i <= j && i < in_n_frames; i++) + for (c = 0; c < r->o_ss.channels; c++, s++) { + float n = fabsf(*s); + + if (n > r->peaks.max_f[c]) + r->peaks.max_f[c] = n; + } + + if (i >= in_n_frames) + break; + + for (c = 0; c < r->o_ss.channels; c++, d++) { + *d = r->peaks.max_f[c]; + r->peaks.max_f[c] = 0; + } + } + + start = j; + } + + pa_memblock_release(input->memblock); + pa_memblock_release(output->memblock); + + *out_n_frames = o_index; + + r->peaks.i_counter += in_n_frames; + + /* Normalize counters */ + while (r->peaks.i_counter >= r->i_ss.rate) { + pa_assert(r->peaks.o_counter >= r->o_ss.rate); + + r->peaks.i_counter -= r->i_ss.rate; + r->peaks.o_counter -= r->o_ss.rate; + } +} + +static void peaks_update_rates_or_reset(pa_resampler *r) { + pa_assert(r); + + r->peaks.i_counter = 0; + r->peaks.o_counter = 0; +} + +static int peaks_init(pa_resampler*r) { + pa_assert(r); + + r->peaks.o_counter = r->peaks.i_counter = 0; + memset(r->peaks.max_i, 0, sizeof(r->peaks.max_i)); + memset(r->peaks.max_f, 0, sizeof(r->peaks.max_f)); + + r->impl_resample = peaks_resample; + r->impl_update_rates = peaks_update_rates_or_reset; + r->impl_reset = peaks_update_rates_or_reset; return 0; } @@ -950,7 +1644,7 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned p = pa_memblock_acquire(b); /* Copy the remaining data into it */ - l = r->ffmpeg.buf[c].length; + l = (unsigned) r->ffmpeg.buf[c].length; if (r->ffmpeg.buf[c].memblock) { t = (int16_t*) ((uint8_t*) pa_memblock_acquire(r->ffmpeg.buf[c].memblock) + r->ffmpeg.buf[c].index); memcpy(p, t, l); @@ -970,18 +1664,18 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned pa_memblock_release(input->memblock); /* Calculate the resulting number of frames */ - in = in_n_frames + l / sizeof(int16_t); + in = (unsigned) in_n_frames + l / (unsigned) sizeof(int16_t); /* Allocate buffer for the result */ w = pa_memblock_new(r->mempool, *out_n_frames * sizeof(int16_t)); q = pa_memblock_acquire(w); /* Now, resample */ - used_frames = av_resample(r->ffmpeg.state, - q, p, - &consumed_frames, - in, *out_n_frames, - c >= (unsigned) r->o_ss.channels-1); + used_frames = (unsigned) av_resample(r->ffmpeg.state, + q, p, + &consumed_frames, + (int) in, (int) *out_n_frames, + c >= (unsigned) (r->o_ss.channels-1)); pa_memblock_release(b); @@ -989,8 +1683,8 @@ static void ffmpeg_resample(pa_resampler *r, const pa_memchunk *input, unsigned pa_assert(consumed_frames <= (int) in); if (consumed_frames < (int) in) { r->ffmpeg.buf[c].memblock = b; - r->ffmpeg.buf[c].index = consumed_frames * sizeof(int16_t); - r->ffmpeg.buf[c].length = (in - consumed_frames) * sizeof(int16_t); + r->ffmpeg.buf[c].index = (size_t) consumed_frames * sizeof(int16_t); + r->ffmpeg.buf[c].length = (size_t) (in - (unsigned) consumed_frames) * sizeof(int16_t); } else pa_memblock_unref(b); @@ -1032,7 +1726,7 @@ static int ffmpeg_init(pa_resampler *r) { * internally only uses these hardcoded values, so let's use them * here for now as well until ffmpeg makes this configurable. */ - if (!(r->ffmpeg.state = av_resample_init(r->o_ss.rate, r->i_ss.rate, 16, 10, 0, 0.8))) + if (!(r->ffmpeg.state = av_resample_init((int) r->o_ss.rate, (int) r->i_ss.rate, 16, 10, 0, 0.8))) return -1; r->impl_free = ffmpeg_free; @@ -1051,9 +1745,5 @@ static int copy_init(pa_resampler *r) { pa_assert(r->o_ss.rate == r->i_ss.rate); - r->impl_free = NULL; - r->impl_resample = NULL; - r->impl_update_rates = NULL; - return 0; }