/** * * @return number of samples output per channel */ static int resample(SwrContext *s, AudioData *out_param, int out_count, const AudioData * in_param, int in_count){ AudioData in, out, tmp; int ret_sum=0; int border=0; av_assert1(s->in_buffer.ch_count == in_param->ch_count); av_assert1(s->in_buffer.planar == in_param->planar); av_assert1(s->in_buffer.fmt == in_param->fmt); tmp=out=*out_param; in = *in_param; do{ int ret, size, consumed; if(!s->resample_in_constraint && s->in_buffer_count){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); ret= s->resampler->multiple_resample(s->resample, &out, out_count, &tmp, s->in_buffer_count, &consumed); out_count -= ret; ret_sum += ret; buf_set(&out, &out, ret); s->in_buffer_count -= consumed; s->in_buffer_index += consumed; if(!in_count) break; if(s->in_buffer_count <= border){ buf_set(&in, &in, -s->in_buffer_count); in_count += s->in_buffer_count; s->in_buffer_count=0; s->in_buffer_index=0; border = 0; } } if((s->flushed || in_count) && !s->in_buffer_count){ s->in_buffer_index=0; ret= s->resampler->multiple_resample(s->resample, &out, out_count, &in, in_count, &consumed); out_count -= ret; ret_sum += ret; buf_set(&out, &out, ret); in_count -= consumed; buf_set(&in, &in, consumed); } //TODO is this check sane considering the advanced copy avoidance below size= s->in_buffer_index + s->in_buffer_count + in_count; if( size > s->in_buffer.count && s->in_buffer_count + in_count <= s->in_buffer_index){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); copy(&s->in_buffer, &tmp, s->in_buffer_count); s->in_buffer_index=0; }else if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0) return ret; if(in_count){ int count= in_count; if(s->in_buffer_count && s->in_buffer_count+2 < count && out_count) count= s->in_buffer_count+2; buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); copy(&tmp, &in, /*in_*/count); s->in_buffer_count += count; in_count -= count; border += count; buf_set(&in, &in, count); s->resample_in_constraint= 0; if(s->in_buffer_count != count || in_count) continue; } break; }while(1); s->resample_in_constraint= !!out_count; return ret_sum; }
int swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_CH_MAX], int out_count, const uint8_t *in_arg [SWR_CH_MAX], int in_count){ AudioData * in= &s->in; AudioData *out= &s->out; while(s->drop_output > 0){ int ret; uint8_t *tmp_arg[SWR_CH_MAX]; #define MAX_DROP_STEP 16384 if((ret=swri_realloc_audio(&s->drop_temp, FFMIN(s->drop_output, MAX_DROP_STEP)))<0) return ret; reversefill_audiodata(&s->drop_temp, tmp_arg); s->drop_output *= -1; //FIXME find a less hackish solution ret = swr_convert(s, tmp_arg, FFMIN(-s->drop_output, MAX_DROP_STEP), in_arg, in_count); //FIXME optimize but this is as good as never called so maybe it doesnt matter s->drop_output *= -1; in_count = 0; if(ret>0) { s->drop_output -= ret; continue; } if(s->drop_output || !out_arg) return 0; } if(!in_arg){ if(s->resample){ if (!s->flushed) s->resampler->flush(s); s->resample_in_constraint = 0; s->flushed = 1; }else if(!s->in_buffer_count){ return 0; } }else fill_audiodata(in , (void*)in_arg); fill_audiodata(out, out_arg); if(s->resample){ int ret = swr_convert_internal(s, out, out_count, in, in_count); if(ret>0 && !s->drop_output) s->outpts += ret * (int64_t)s->in_sample_rate; return ret; }else{ AudioData tmp= *in; int ret2=0; int ret, size; size = FFMIN(out_count, s->in_buffer_count); if(size){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); ret= swr_convert_internal(s, out, size, &tmp, size); if(ret<0) return ret; ret2= ret; s->in_buffer_count -= ret; s->in_buffer_index += ret; buf_set(out, out, ret); out_count -= ret; if(!s->in_buffer_count) s->in_buffer_index = 0; } if(in_count){ size= s->in_buffer_index + s->in_buffer_count + in_count - out_count; if(in_count > out_count) { //FIXME move after swr_convert_internal if( size > s->in_buffer.count && s->in_buffer_count + in_count - out_count <= s->in_buffer_index){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); copy(&s->in_buffer, &tmp, s->in_buffer_count); s->in_buffer_index=0; }else if((ret=swri_realloc_audio(&s->in_buffer, size)) < 0) return ret; } if(out_count){ size = FFMIN(in_count, out_count); ret= swr_convert_internal(s, out, size, in, size); if(ret<0) return ret; buf_set(in, in, ret); in_count -= ret; ret2 += ret; } if(in_count){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index + s->in_buffer_count); copy(&tmp, in, in_count); s->in_buffer_count += in_count; } } if(ret2>0 && !s->drop_output) s->outpts += ret2 * (int64_t)s->in_sample_rate; return ret2; } }
int swr_convert(struct SwrContext *s, uint8_t *out_arg[SWR_CH_MAX], int out_count, const uint8_t *in_arg [SWR_CH_MAX], int in_count){ AudioData * in= &s->in; AudioData *out= &s->out; if(!in_arg){ if(s->in_buffer_count){ if (s->resample && !s->flushed) { AudioData *a= &s->in_buffer; int i, j, ret; if((ret=realloc_audio(a, s->in_buffer_index + 2*s->in_buffer_count)) < 0) return ret; av_assert0(a->planar); for(i=0; i<a->ch_count; i++){ for(j=0; j<s->in_buffer_count; j++){ memcpy(a->ch[i] + (s->in_buffer_index+s->in_buffer_count+j )*a->bps, a->ch[i] + (s->in_buffer_index+s->in_buffer_count-j-1)*a->bps, a->bps); } } s->in_buffer_count += (s->in_buffer_count+1)/2; s->resample_in_constraint = 0; s->flushed = 1; } }else{ return 0; } }else fill_audiodata(in , (void*)in_arg); fill_audiodata(out, out_arg); if(s->resample){ return swr_convert_internal(s, out, out_count, in, in_count); }else{ AudioData tmp= *in; int ret2=0; int ret, size; size = FFMIN(out_count, s->in_buffer_count); if(size){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); ret= swr_convert_internal(s, out, size, &tmp, size); if(ret<0) return ret; ret2= ret; s->in_buffer_count -= ret; s->in_buffer_index += ret; buf_set(out, out, ret); out_count -= ret; if(!s->in_buffer_count) s->in_buffer_index = 0; } if(in_count){ size= s->in_buffer_index + s->in_buffer_count + in_count - out_count; if(in_count > out_count) { //FIXME move after swr_convert_internal if( size > s->in_buffer.count && s->in_buffer_count + in_count - out_count <= s->in_buffer_index){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); copy(&s->in_buffer, &tmp, s->in_buffer_count); s->in_buffer_index=0; }else if((ret=realloc_audio(&s->in_buffer, size)) < 0) return ret; } if(out_count){ size = FFMIN(in_count, out_count); ret= swr_convert_internal(s, out, size, in, size); if(ret<0) return ret; buf_set(in, in, ret); in_count -= ret; ret2 += ret; } if(in_count){ buf_set(&tmp, &s->in_buffer, s->in_buffer_index); copy(&tmp, in, in_count); s->in_buffer_count += in_count; } } return ret2; } }