mirror of
https://github.com/xenia-project/FFmpeg.git
synced 2025-01-11 14:17:03 +00:00
swr: move dither related fields to their own context
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
parent
ba1314c2ef
commit
3ab1970612
@ -41,35 +41,35 @@ void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSa
|
|||||||
if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<24;
|
if(in_fmt == AV_SAMPLE_FMT_S32 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<24;
|
||||||
if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<8;
|
if(in_fmt == AV_SAMPLE_FMT_S16 && out_fmt == AV_SAMPLE_FMT_U8 ) scale = 1L<<8;
|
||||||
|
|
||||||
scale *= s->dither_scale;
|
scale *= s->dither.scale;
|
||||||
|
|
||||||
s->ns_pos = 0;
|
s->dither.ns_pos = 0;
|
||||||
s->ns_scale = scale;
|
s->dither.ns_scale = scale;
|
||||||
s->ns_scale_1 = 1/scale;
|
s->dither.ns_scale_1 = 1/scale;
|
||||||
memset(s->ns_errors, 0, sizeof(s->ns_errors));
|
memset(s->dither.ns_errors, 0, sizeof(s->dither.ns_errors));
|
||||||
for (i=0; filters[i].coefs; i++) {
|
for (i=0; filters[i].coefs; i++) {
|
||||||
const filter_t *f = &filters[i];
|
const filter_t *f = &filters[i];
|
||||||
if (fabs(s->out_sample_rate - f->rate) / f->rate <= .05 && f->name == s->dither_method) {
|
if (fabs(s->out_sample_rate - f->rate) / f->rate <= .05 && f->name == s->dither.method) {
|
||||||
int j;
|
int j;
|
||||||
s->ns_taps = f->len;
|
s->dither.ns_taps = f->len;
|
||||||
for (j=0; j<f->len; j++)
|
for (j=0; j<f->len; j++)
|
||||||
s->ns_coeffs[j] = f->coefs[j];
|
s->dither.ns_coeffs[j] = f->coefs[j];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!filters[i].coefs && s->dither_method > SWR_DITHER_NS) {
|
if (!filters[i].coefs && s->dither.method > SWR_DITHER_NS) {
|
||||||
av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n");
|
av_log(s, AV_LOG_WARNING, "Requested noise shaping dither not available at this sampling rate, using triangular hp dither\n");
|
||||||
s->dither_method = SWR_DITHER_TRIANGULAR_HIGHPASS;
|
s->dither.method = SWR_DITHER_TRIANGULAR_HIGHPASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0; i<len + TMP_EXTRA; i++){
|
for(i=0; i<len + TMP_EXTRA; i++){
|
||||||
double v;
|
double v;
|
||||||
seed = seed* 1664525 + 1013904223;
|
seed = seed* 1664525 + 1013904223;
|
||||||
|
|
||||||
switch(s->dither_method){
|
switch(s->dither.method){
|
||||||
case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break;
|
case SWR_DITHER_RECTANGULAR: v= ((double)seed) / UINT_MAX - 0.5; break;
|
||||||
default:
|
default:
|
||||||
av_assert0(s->dither_method < SWR_DITHER_NB);
|
av_assert0(s->dither.method < SWR_DITHER_NB);
|
||||||
v = ((double)seed) / UINT_MAX;
|
v = ((double)seed) / UINT_MAX;
|
||||||
seed = seed*1664525 + 1013904223;
|
seed = seed*1664525 + 1013904223;
|
||||||
v-= ((double)seed) / UINT_MAX;
|
v-= ((double)seed) / UINT_MAX;
|
||||||
@ -81,9 +81,9 @@ void swri_get_dither(SwrContext *s, void *dst, int len, unsigned seed, enum AVSa
|
|||||||
for(i=0; i<len; i++){
|
for(i=0; i<len; i++){
|
||||||
double v;
|
double v;
|
||||||
|
|
||||||
switch(s->dither_method){
|
switch(s->dither.method){
|
||||||
default:
|
default:
|
||||||
av_assert0(s->dither_method < SWR_DITHER_NB);
|
av_assert0(s->dither.method < SWR_DITHER_NB);
|
||||||
v = tmp[i];
|
v = tmp[i];
|
||||||
break;
|
break;
|
||||||
case SWR_DITHER_TRIANGULAR_HIGHPASS :
|
case SWR_DITHER_TRIANGULAR_HIGHPASS :
|
||||||
|
@ -25,27 +25,27 @@ ERROR
|
|||||||
|
|
||||||
void RENAME(swri_noise_shaping)(SwrContext *s, AudioData *srcs, AudioData *noises, int count){
|
void RENAME(swri_noise_shaping)(SwrContext *s, AudioData *srcs, AudioData *noises, int count){
|
||||||
int i, j, pos, ch;
|
int i, j, pos, ch;
|
||||||
int taps = s->ns_taps;
|
int taps = s->dither.ns_taps;
|
||||||
float S = s->ns_scale;
|
float S = s->dither.ns_scale;
|
||||||
float S_1 = s->ns_scale_1;
|
float S_1 = s->dither.ns_scale_1;
|
||||||
|
|
||||||
for (ch=0; ch<srcs->ch_count; ch++) {
|
for (ch=0; ch<srcs->ch_count; ch++) {
|
||||||
const float *noise = ((const float *)noises->ch[ch]) + s->dither_pos;
|
const float *noise = ((const float *)noises->ch[ch]) + s->dither.dither_pos;
|
||||||
DELEM *data = (DELEM*)srcs->ch[ch];
|
DELEM *data = (DELEM*)srcs->ch[ch];
|
||||||
pos = s->ns_pos;
|
pos = s->dither.ns_pos;
|
||||||
for (i=0; i<count; i++) {
|
for (i=0; i<count; i++) {
|
||||||
double d1, d = data[i];
|
double d1, d = data[i];
|
||||||
for(j=0; j<taps; j++)
|
for(j=0; j<taps; j++)
|
||||||
d -= s->ns_coeffs[j] * s->ns_errors[ch][pos + j];
|
d -= s->dither.ns_coeffs[j] * s->dither.ns_errors[ch][pos + j];
|
||||||
pos = pos ? pos - 1 : pos - 1 + taps;
|
pos = pos ? pos - 1 : pos - 1 + taps;
|
||||||
d1 = rint((d + noise[i]) * S_1)*S;
|
d1 = rint((d + noise[i]) * S_1)*S;
|
||||||
s->ns_errors[ch][pos + taps] = s->ns_errors[ch][pos] = d1 - d;
|
s->dither.ns_errors[ch][pos + taps] = s->dither.ns_errors[ch][pos] = d1 - d;
|
||||||
CLIP(d1);
|
CLIP(d1);
|
||||||
data[i] = d1;
|
data[i] = d1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s->ns_pos = pos;
|
s->dither.ns_pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef RENAME
|
#undef RENAME
|
||||||
|
@ -73,9 +73,9 @@ static const AVOption options[]={
|
|||||||
{"swr_flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, "flags"},
|
{"swr_flags" , "set flags" , OFFSET(flags ), AV_OPT_TYPE_FLAGS, {.i64=0 }, 0 , UINT_MAX , PARAM, "flags"},
|
||||||
{"res" , "force resampling" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_FLAG_RESAMPLE }, INT_MIN, INT_MAX , PARAM, "flags"},
|
{"res" , "force resampling" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_FLAG_RESAMPLE }, INT_MIN, INT_MAX , PARAM, "flags"},
|
||||||
|
|
||||||
{"dither_scale" , "set dither scale" , OFFSET(dither_scale ), AV_OPT_TYPE_FLOAT, {.dbl=1 }, 0 , INT_MAX , PARAM},
|
{"dither_scale" , "set dither scale" , OFFSET(dither.scale ), AV_OPT_TYPE_FLOAT, {.dbl=1 }, 0 , INT_MAX , PARAM},
|
||||||
|
|
||||||
{"dither_method" , "set dither method" , OFFSET(dither_method ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_DITHER_NB-1, PARAM, "dither_method"},
|
{"dither_method" , "set dither method" , OFFSET(dither.method ), AV_OPT_TYPE_INT , {.i64=0 }, 0 , SWR_DITHER_NB-1, PARAM, "dither_method"},
|
||||||
{"rectangular" , "select rectangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_RECTANGULAR}, INT_MIN, INT_MAX , PARAM, "dither_method"},
|
{"rectangular" , "select rectangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_RECTANGULAR}, INT_MIN, INT_MAX , PARAM, "dither_method"},
|
||||||
{"triangular" , "select triangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR }, INT_MIN, INT_MAX , PARAM, "dither_method"},
|
{"triangular" , "select triangular dither" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR }, INT_MIN, INT_MAX , PARAM, "dither_method"},
|
||||||
{"triangular_hp" , "select triangular dither with high pass" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR_HIGHPASS }, INT_MIN, INT_MAX, PARAM, "dither_method"},
|
{"triangular_hp" , "select triangular dither with high pass" , 0 , AV_OPT_TYPE_CONST, {.i64=SWR_DITHER_TRIANGULAR_HIGHPASS }, INT_MIN, INT_MAX, PARAM, "dither_method"},
|
||||||
@ -217,7 +217,7 @@ av_cold void swr_free(SwrContext **ss){
|
|||||||
free_temp(&s->midbuf);
|
free_temp(&s->midbuf);
|
||||||
free_temp(&s->preout);
|
free_temp(&s->preout);
|
||||||
free_temp(&s->in_buffer);
|
free_temp(&s->in_buffer);
|
||||||
free_temp(&s->dither);
|
free_temp(&s->dither.noise);
|
||||||
swri_audio_convert_free(&s-> in_convert);
|
swri_audio_convert_free(&s-> in_convert);
|
||||||
swri_audio_convert_free(&s->out_convert);
|
swri_audio_convert_free(&s->out_convert);
|
||||||
swri_audio_convert_free(&s->full_convert);
|
swri_audio_convert_free(&s->full_convert);
|
||||||
@ -237,7 +237,7 @@ av_cold int swr_init(struct SwrContext *s){
|
|||||||
free_temp(&s->midbuf);
|
free_temp(&s->midbuf);
|
||||||
free_temp(&s->preout);
|
free_temp(&s->preout);
|
||||||
free_temp(&s->in_buffer);
|
free_temp(&s->in_buffer);
|
||||||
free_temp(&s->dither);
|
free_temp(&s->dither.noise);
|
||||||
memset(s->in.ch, 0, sizeof(s->in.ch));
|
memset(s->in.ch, 0, sizeof(s->in.ch));
|
||||||
memset(s->out.ch, 0, sizeof(s->out.ch));
|
memset(s->out.ch, 0, sizeof(s->out.ch));
|
||||||
swri_audio_convert_free(&s-> in_convert);
|
swri_audio_convert_free(&s-> in_convert);
|
||||||
@ -355,7 +355,7 @@ av_assert0(s->out.ch_count);
|
|||||||
|
|
||||||
s->in_buffer= s->in;
|
s->in_buffer= s->in;
|
||||||
|
|
||||||
if(!s->resample && !s->rematrix && !s->channel_map && !s->dither_method){
|
if(!s->resample && !s->rematrix && !s->channel_map && !s->dither.method){
|
||||||
s->full_convert = swri_audio_convert_alloc(s->out_sample_fmt,
|
s->full_convert = swri_audio_convert_alloc(s->out_sample_fmt,
|
||||||
s-> in_sample_fmt, s-> in.ch_count, NULL, 0);
|
s-> in_sample_fmt, s-> in.ch_count, NULL, 0);
|
||||||
return 0;
|
return 0;
|
||||||
@ -391,9 +391,9 @@ av_assert0(s->out.ch_count);
|
|||||||
set_audiodata_fmt(&s->in_buffer, s->int_sample_fmt);
|
set_audiodata_fmt(&s->in_buffer, s->int_sample_fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->dither = s->preout;
|
s->dither.noise = s->preout;
|
||||||
|
|
||||||
if(s->rematrix || s->dither_method)
|
if(s->rematrix || s->dither.method)
|
||||||
return swri_rematrix_init(s);
|
return swri_rematrix_init(s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -609,7 +609,7 @@ static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_co
|
|||||||
if(s->resample_first ? !s->rematrix : !s->resample)
|
if(s->resample_first ? !s->rematrix : !s->resample)
|
||||||
preout= midbuf;
|
preout= midbuf;
|
||||||
|
|
||||||
if (preout == in && s->dither_method) {
|
if (preout == in && s->dither.method) {
|
||||||
av_assert1(postin == midbuf && midbuf == preout);
|
av_assert1(postin == midbuf && midbuf == preout);
|
||||||
postin = midbuf = preout = &preout_tmp;
|
postin = midbuf = preout = &preout_tmp;
|
||||||
}
|
}
|
||||||
@ -643,45 +643,45 @@ static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_co
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(preout != out && out_count){
|
if(preout != out && out_count){
|
||||||
if(s->dither_method){
|
if(s->dither.method){
|
||||||
int ch, len1;
|
int ch, len1;
|
||||||
int dither_count= FFMAX(out_count, 1<<16);
|
int dither_count= FFMAX(out_count, 1<<16);
|
||||||
av_assert0(preout != in);
|
av_assert0(preout != in);
|
||||||
|
|
||||||
if((ret=swri_realloc_audio(&s->dither, dither_count))<0)
|
if((ret=swri_realloc_audio(&s->dither.noise, dither_count))<0)
|
||||||
return ret;
|
return ret;
|
||||||
if(ret)
|
if(ret)
|
||||||
for(ch=0; ch<s->dither.ch_count; ch++)
|
for(ch=0; ch<s->dither.noise.ch_count; ch++)
|
||||||
swri_get_dither(s, s->dither.ch[ch], s->dither.count, 12345678913579<<ch, s->out_sample_fmt, s->int_sample_fmt);
|
swri_get_dither(s, s->dither.noise.ch[ch], s->dither.noise.count, 12345678913579<<ch, s->out_sample_fmt, s->int_sample_fmt);
|
||||||
av_assert0(s->dither.ch_count == preout->ch_count);
|
av_assert0(s->dither.noise.ch_count == preout->ch_count);
|
||||||
|
|
||||||
if(s->dither_pos + out_count > s->dither.count)
|
if(s->dither.dither_pos + out_count > s->dither.noise.count)
|
||||||
s->dither_pos = 0;
|
s->dither.dither_pos = 0;
|
||||||
|
|
||||||
if (s->dither_method < SWR_DITHER_NS){
|
if (s->dither.method < SWR_DITHER_NS){
|
||||||
if (s->mix_2_1_simd) {
|
if (s->mix_2_1_simd) {
|
||||||
int len1= out_count&~15;
|
int len1= out_count&~15;
|
||||||
int off = len1 * preout->bps;
|
int off = len1 * preout->bps;
|
||||||
|
|
||||||
if(len1)
|
if(len1)
|
||||||
for(ch=0; ch<preout->ch_count; ch++)
|
for(ch=0; ch<preout->ch_count; ch++)
|
||||||
s->mix_2_1_simd(preout->ch[ch], preout->ch[ch], s->dither.ch[ch] + s->dither.bps * s->dither_pos, s->native_one, 0, 0, len1);
|
s->mix_2_1_simd(preout->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.dither_pos, s->native_one, 0, 0, len1);
|
||||||
if(out_count != len1)
|
if(out_count != len1)
|
||||||
for(ch=0; ch<preout->ch_count; ch++)
|
for(ch=0; ch<preout->ch_count; ch++)
|
||||||
s->mix_2_1_f(preout->ch[ch] + off, preout->ch[ch] + off, s->dither.ch[ch] + s->dither.bps * s->dither_pos + off + len1, s->native_one, 0, 0, out_count - len1);
|
s->mix_2_1_f(preout->ch[ch] + off, preout->ch[ch] + off, s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.dither_pos + off + len1, s->native_one, 0, 0, out_count - len1);
|
||||||
} else {
|
} else {
|
||||||
for(ch=0; ch<preout->ch_count; ch++)
|
for(ch=0; ch<preout->ch_count; ch++)
|
||||||
s->mix_2_1_f(preout->ch[ch], preout->ch[ch], s->dither.ch[ch] + s->dither.bps * s->dither_pos, s->native_one, 0, 0, out_count);
|
s->mix_2_1_f(preout->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.dither_pos, s->native_one, 0, 0, out_count);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch(s->int_sample_fmt) {
|
switch(s->int_sample_fmt) {
|
||||||
case AV_SAMPLE_FMT_S16P :swri_noise_shaping_int16(s, preout, &s->dither, out_count); break;
|
case AV_SAMPLE_FMT_S16P :swri_noise_shaping_int16(s, preout, &s->dither.noise, out_count); break;
|
||||||
case AV_SAMPLE_FMT_S32P :swri_noise_shaping_int32(s, preout, &s->dither, out_count); break;
|
case AV_SAMPLE_FMT_S32P :swri_noise_shaping_int32(s, preout, &s->dither.noise, out_count); break;
|
||||||
case AV_SAMPLE_FMT_FLTP :swri_noise_shaping_float(s, preout, &s->dither, out_count); break;
|
case AV_SAMPLE_FMT_FLTP :swri_noise_shaping_float(s, preout, &s->dither.noise, out_count); break;
|
||||||
case AV_SAMPLE_FMT_DBLP :swri_noise_shaping_double(s,preout, &s->dither, out_count); break;
|
case AV_SAMPLE_FMT_DBLP :swri_noise_shaping_double(s,preout, &s->dither.noise, out_count); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s->dither_pos += out_count;
|
s->dither.dither_pos += out_count;
|
||||||
}
|
}
|
||||||
//FIXME packed doesnt need more than 1 chan here!
|
//FIXME packed doesnt need more than 1 chan here!
|
||||||
swri_audio_convert(s->out_convert, out, preout, out_count);
|
swri_audio_convert(s->out_convert, out, preout, out_count);
|
||||||
|
@ -50,6 +50,19 @@ typedef struct AudioData{
|
|||||||
enum AVSampleFormat fmt; ///< sample format
|
enum AVSampleFormat fmt; ///< sample format
|
||||||
} AudioData;
|
} AudioData;
|
||||||
|
|
||||||
|
struct DitherContext {
|
||||||
|
enum SwrDitherType method;
|
||||||
|
int dither_pos;
|
||||||
|
float scale;
|
||||||
|
int ns_taps; ///< Noise shaping dither taps
|
||||||
|
float ns_scale; ///< Noise shaping dither scale
|
||||||
|
float ns_scale_1; ///< Noise shaping dither scale^-1
|
||||||
|
int ns_pos; ///< Noise shaping dither position
|
||||||
|
float ns_coeffs[NS_TAPS]; ///< Noise shaping filter coefficients
|
||||||
|
float ns_errors[SWR_CH_MAX][2*NS_TAPS];
|
||||||
|
AudioData noise; ///< noise used for dithering
|
||||||
|
};
|
||||||
|
|
||||||
struct SwrContext {
|
struct SwrContext {
|
||||||
const AVClass *av_class; ///< AVClass used for AVOption and av_log()
|
const AVClass *av_class; ///< AVClass used for AVOption and av_log()
|
||||||
int log_level_offset; ///< logging level offset
|
int log_level_offset; ///< logging level offset
|
||||||
@ -70,15 +83,8 @@ struct SwrContext {
|
|||||||
const int *channel_map; ///< channel index (or -1 if muted channel) map
|
const int *channel_map; ///< channel index (or -1 if muted channel) map
|
||||||
int used_ch_count; ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count)
|
int used_ch_count; ///< number of used input channels (mapped channel count if channel_map, otherwise in.ch_count)
|
||||||
enum SwrEngine engine;
|
enum SwrEngine engine;
|
||||||
enum SwrDitherType dither_method;
|
|
||||||
int dither_pos;
|
struct DitherContext dither;
|
||||||
float dither_scale;
|
|
||||||
int ns_taps; ///< Noise shaping dither taps
|
|
||||||
float ns_scale; ///< Noise shaping dither scale
|
|
||||||
float ns_scale_1; ///< Noise shaping dither scale^-1
|
|
||||||
int ns_pos; ///< Noise shaping dither position
|
|
||||||
float ns_coeffs[NS_TAPS]; ///< Noise shaping filter coefficients
|
|
||||||
float ns_errors[SWR_CH_MAX][2*NS_TAPS];
|
|
||||||
|
|
||||||
int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */
|
int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */
|
||||||
int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */
|
int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */
|
||||||
@ -105,7 +111,6 @@ struct SwrContext {
|
|||||||
AudioData preout; ///< pre-output audio data: used for rematrix/resample
|
AudioData preout; ///< pre-output audio data: used for rematrix/resample
|
||||||
AudioData out; ///< converted output audio data
|
AudioData out; ///< converted output audio data
|
||||||
AudioData in_buffer; ///< cached audio data (convert and resample purpose)
|
AudioData in_buffer; ///< cached audio data (convert and resample purpose)
|
||||||
AudioData dither; ///< noise used for dithering
|
|
||||||
int in_buffer_index; ///< cached buffer position
|
int in_buffer_index; ///< cached buffer position
|
||||||
int in_buffer_count; ///< cached buffer length
|
int in_buffer_count; ///< cached buffer length
|
||||||
int resample_in_constraint; ///< 1 if the input end was reach before the output end, 0 otherwise
|
int resample_in_constraint; ///< 1 if the input end was reach before the output end, 0 otherwise
|
||||||
|
Loading…
x
Reference in New Issue
Block a user