8ea8833979
It has various benefits such as allowing some refactoring, clarifying the code in the inclusion part, and making the template understandable in standalone. This commit is based on the templating method used by Justin Ruggles for libavresample.
219 lines
7.1 KiB
C
219 lines
7.1 KiB
C
/*
|
|
* audio resampling
|
|
* Copyright (c) 2004-2012 Michael Niedermayer <michaelni@gmx.at>
|
|
*
|
|
* This file is part of FFmpeg.
|
|
*
|
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
|
*
|
|
* FFmpeg is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with FFmpeg; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* audio resampling
|
|
* @author Michael Niedermayer <michaelni@gmx.at>
|
|
*/
|
|
|
|
#if defined(TEMPLATE_RESAMPLE_DBL)
|
|
# define RENAME(N) N ## _double
|
|
# define FILTER_SHIFT 0
|
|
# define DELEM double
|
|
# define FELEM double
|
|
# define FELEM2 double
|
|
# define FELEML double
|
|
# define OUT(d, v) d = v
|
|
|
|
#elif defined(TEMPLATE_RESAMPLE_FLT)
|
|
# define RENAME(N) N ## _float
|
|
# define FILTER_SHIFT 0
|
|
# define DELEM float
|
|
# define FELEM float
|
|
# define FELEM2 float
|
|
# define FELEML float
|
|
# define OUT(d, v) d = v
|
|
|
|
#elif defined(TEMPLATE_RESAMPLE_S32)
|
|
# define RENAME(N) N ## _int32
|
|
# define FILTER_SHIFT 30
|
|
# define DELEM int32_t
|
|
# define FELEM int32_t
|
|
# define FELEM2 int64_t
|
|
# define FELEML int64_t
|
|
# define FELEM_MAX INT32_MAX
|
|
# define FELEM_MIN INT32_MIN
|
|
# define OUT(d, v) v = (v + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;\
|
|
d = (uint64_t)(v + 0x80000000) > 0xFFFFFFFF ? (v>>63) ^ 0x7FFFFFFF : v
|
|
|
|
#elif defined(TEMPLATE_RESAMPLE_S16) \
|
|
|| defined(TEMPLATE_RESAMPLE_S16_MMX2) \
|
|
|| defined(TEMPLATE_RESAMPLE_S16_SSSE3)
|
|
|
|
# define FILTER_SHIFT 15
|
|
# define DELEM int16_t
|
|
# define FELEM int16_t
|
|
# define FELEM2 int32_t
|
|
# define FELEML int64_t
|
|
# define FELEM_MAX INT16_MAX
|
|
# define FELEM_MIN INT16_MIN
|
|
# define OUT(d, v) v = (v + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT;\
|
|
d = (unsigned)(v + 32768) > 65535 ? (v>>31) ^ 32767 : v
|
|
|
|
# if defined(TEMPLATE_RESAMPLE_S16)
|
|
# define RENAME(N) N ## _int16
|
|
# elif defined(TEMPLATE_RESAMPLE_S16_MMX2)
|
|
# define COMMON_CORE COMMON_CORE_INT16_MMX2
|
|
# define RENAME(N) N ## _int16_mmx2
|
|
# elif defined(TEMPLATE_RESAMPLE_S16_SSSE3)
|
|
# define COMMON_CORE COMMON_CORE_INT16_SSSE3
|
|
# define RENAME(N) N ## _int16_ssse3
|
|
# endif
|
|
|
|
#endif
|
|
|
|
int RENAME(swri_resample)(ResampleContext *c, DELEM *dst, const DELEM *src, int *consumed, int src_size, int dst_size, int update_ctx){
|
|
int dst_index, i;
|
|
int index= c->index;
|
|
int frac= c->frac;
|
|
int dst_incr_frac= c->dst_incr % c->src_incr;
|
|
int dst_incr= c->dst_incr / c->src_incr;
|
|
int compensation_distance= c->compensation_distance;
|
|
|
|
av_assert1(c->filter_shift == FILTER_SHIFT);
|
|
av_assert1(c->felem_size == sizeof(FELEM));
|
|
|
|
if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){
|
|
int64_t index2= ((int64_t)index)<<32;
|
|
int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr;
|
|
dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr);
|
|
|
|
for(dst_index=0; dst_index < dst_size; dst_index++){
|
|
dst[dst_index] = src[index2>>32];
|
|
index2 += incr;
|
|
}
|
|
index += dst_index * dst_incr;
|
|
index += (frac + dst_index * (int64_t)dst_incr_frac) / c->src_incr;
|
|
frac = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr;
|
|
av_assert2(index >= 0);
|
|
*consumed= index >> c->phase_shift;
|
|
index &= c->phase_mask;
|
|
}else if(compensation_distance == 0 && !c->linear && index >= 0){
|
|
int sample_index = 0;
|
|
for(dst_index=0; dst_index < dst_size; dst_index++){
|
|
FELEM *filter;
|
|
sample_index += index >> c->phase_shift;
|
|
index &= c->phase_mask;
|
|
filter= ((FELEM*)c->filter_bank) + c->filter_alloc*index;
|
|
|
|
if(sample_index + c->filter_length > src_size){
|
|
break;
|
|
}else{
|
|
#ifdef COMMON_CORE
|
|
COMMON_CORE
|
|
#else
|
|
FELEM2 val=0;
|
|
for(i=0; i<c->filter_length; i++){
|
|
val += src[sample_index + i] * (FELEM2)filter[i];
|
|
}
|
|
OUT(dst[dst_index], val);
|
|
#endif
|
|
}
|
|
|
|
frac += dst_incr_frac;
|
|
index += dst_incr;
|
|
if(frac >= c->src_incr){
|
|
frac -= c->src_incr;
|
|
index++;
|
|
}
|
|
}
|
|
*consumed = sample_index;
|
|
}else{
|
|
int sample_index = 0;
|
|
for(dst_index=0; dst_index < dst_size; dst_index++){
|
|
FELEM *filter;
|
|
FELEM2 val=0;
|
|
|
|
sample_index += index >> c->phase_shift;
|
|
index &= c->phase_mask;
|
|
filter = ((FELEM*)c->filter_bank) + c->filter_alloc*index;
|
|
|
|
if(sample_index + c->filter_length > src_size || -sample_index >= src_size){
|
|
break;
|
|
}else if(sample_index < 0){
|
|
for(i=0; i<c->filter_length; i++)
|
|
val += src[FFABS(sample_index + i)] * filter[i];
|
|
}else if(c->linear){
|
|
FELEM2 v2=0;
|
|
for(i=0; i<c->filter_length; i++){
|
|
val += src[sample_index + i] * (FELEM2)filter[i];
|
|
v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_alloc];
|
|
}
|
|
val+=(v2-val)*(FELEML)frac / c->src_incr;
|
|
}else{
|
|
for(i=0; i<c->filter_length; i++){
|
|
val += src[sample_index + i] * (FELEM2)filter[i];
|
|
}
|
|
}
|
|
|
|
OUT(dst[dst_index], val);
|
|
|
|
frac += dst_incr_frac;
|
|
index += dst_incr;
|
|
if(frac >= c->src_incr){
|
|
frac -= c->src_incr;
|
|
index++;
|
|
}
|
|
|
|
if(dst_index + 1 == compensation_distance){
|
|
compensation_distance= 0;
|
|
dst_incr_frac= c->ideal_dst_incr % c->src_incr;
|
|
dst_incr= c->ideal_dst_incr / c->src_incr;
|
|
}
|
|
}
|
|
*consumed= FFMAX(sample_index, 0);
|
|
index += FFMIN(sample_index, 0) << c->phase_shift;
|
|
|
|
if(compensation_distance){
|
|
compensation_distance -= dst_index;
|
|
av_assert1(compensation_distance > 0);
|
|
}
|
|
}
|
|
|
|
if(update_ctx){
|
|
c->frac= frac;
|
|
c->index= index;
|
|
c->dst_incr= dst_incr_frac + c->src_incr*dst_incr;
|
|
c->compensation_distance= compensation_distance;
|
|
}
|
|
#if 0
|
|
if(update_ctx && !c->compensation_distance){
|
|
#undef rand
|
|
av_resample_compensate(c, rand() % (8000*2) - 8000, 8000*2);
|
|
av_log(NULL, AV_LOG_DEBUG, "%d %d %d\n", c->dst_incr, c->ideal_dst_incr, c->compensation_distance);
|
|
}
|
|
#endif
|
|
|
|
return dst_index;
|
|
}
|
|
|
|
#undef COMMON_CORE
|
|
#undef RENAME
|
|
#undef FILTER_SHIFT
|
|
#undef DELEM
|
|
#undef FELEM
|
|
#undef FELEM2
|
|
#undef FELEML
|
|
#undef FELEM_MAX
|
|
#undef FELEM_MIN
|
|
#undef OUT
|