You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	lavfi/aresample: use libswresample.
This commit is contained in:
		
							
								
								
									
										1
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -1649,6 +1649,7 @@ udp_protocol_deps="network" | |||||||
|  |  | ||||||
| # filters | # filters | ||||||
| amovie_filter_deps="avcodec avformat" | amovie_filter_deps="avcodec avformat" | ||||||
|  | aresample_filter_deps="swresample" | ||||||
| ass_filter_deps="libass" | ass_filter_deps="libass" | ||||||
| blackframe_filter_deps="gpl" | blackframe_filter_deps="gpl" | ||||||
| boxblur_filter_deps="gpl" | boxblur_filter_deps="gpl" | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ FFLIBS = avutil | |||||||
|  |  | ||||||
| FFLIBS-$(CONFIG_ACONVERT_FILTER)             += avcodec | FFLIBS-$(CONFIG_ACONVERT_FILTER)             += avcodec | ||||||
| FFLIBS-$(CONFIG_AMOVIE_FILTER)               += avformat avcodec | FFLIBS-$(CONFIG_AMOVIE_FILTER)               += avformat avcodec | ||||||
| FFLIBS-$(CONFIG_ARESAMPLE_FILTER)            += avcodec | FFLIBS-$(CONFIG_ARESAMPLE_FILTER)            += swresample | ||||||
| FFLIBS-$(CONFIG_MOVIE_FILTER)                += avformat avcodec | FFLIBS-$(CONFIG_MOVIE_FILTER)                += avformat avcodec | ||||||
| FFLIBS-$(CONFIG_PAN_FILTER)                  += swresample | FFLIBS-$(CONFIG_PAN_FILTER)                  += swresample | ||||||
| FFLIBS-$(CONFIG_SCALE_FILTER)                += swscale | FFLIBS-$(CONFIG_SCALE_FILTER)                += swscale | ||||||
|   | |||||||
| @@ -24,20 +24,14 @@ | |||||||
|  * resampling audio filter |  * resampling audio filter | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "libavutil/eval.h" | #include "libswresample/swresample.h" | ||||||
| #include "libavcodec/avcodec.h" |  | ||||||
| #include "avfilter.h" | #include "avfilter.h" | ||||||
| #include "internal.h" | #include "internal.h" | ||||||
|  |  | ||||||
| typedef struct { | typedef struct { | ||||||
|     struct AVResampleContext *resample; |  | ||||||
|     int out_rate; |     int out_rate; | ||||||
|     double ratio; |     double ratio; | ||||||
|     AVFilterBufferRef *outsamplesref; |     struct SwrContext *swr; | ||||||
|     int unconsumed_nb_samples, |  | ||||||
|         max_cached_nb_samples; |  | ||||||
|     int16_t *cached_data[8], |  | ||||||
|             *resampled_data[8]; |  | ||||||
| } AResampleContext; | } AResampleContext; | ||||||
|  |  | ||||||
| static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) | static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) | ||||||
| @@ -58,23 +52,12 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) | |||||||
| static av_cold void uninit(AVFilterContext *ctx) | static av_cold void uninit(AVFilterContext *ctx) | ||||||
| { | { | ||||||
|     AResampleContext *aresample = ctx->priv; |     AResampleContext *aresample = ctx->priv; | ||||||
|     if (aresample->outsamplesref) { |     swr_free(&aresample->swr); | ||||||
|         int nb_channels = |  | ||||||
|             av_get_channel_layout_nb_channels( |  | ||||||
|                 aresample->outsamplesref->audio->channel_layout); |  | ||||||
|         avfilter_unref_buffer(aresample->outsamplesref); |  | ||||||
|         while (nb_channels--) { |  | ||||||
|             av_freep(&(aresample->cached_data[nb_channels])); |  | ||||||
|             av_freep(&(aresample->resampled_data[nb_channels])); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (aresample->resample) |  | ||||||
|         av_resample_close(aresample->resample); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int config_output(AVFilterLink *outlink) | static int config_output(AVFilterLink *outlink) | ||||||
| { | { | ||||||
|  |     int ret; | ||||||
|     AVFilterContext *ctx = outlink->src; |     AVFilterContext *ctx = outlink->src; | ||||||
|     AVFilterLink *inlink = ctx->inputs[0]; |     AVFilterLink *inlink = ctx->inputs[0]; | ||||||
|     AResampleContext *aresample = ctx->priv; |     AResampleContext *aresample = ctx->priv; | ||||||
| @@ -85,9 +68,16 @@ static int config_output(AVFilterLink *outlink) | |||||||
|         outlink->sample_rate = aresample->out_rate; |         outlink->sample_rate = aresample->out_rate; | ||||||
|     outlink->time_base = (AVRational) {1, aresample->out_rate}; |     outlink->time_base = (AVRational) {1, aresample->out_rate}; | ||||||
|  |  | ||||||
|     //TODO: make the resampling parameters configurable |     //TODO: make the resampling parameters (filter size, phrase shift, linear, cutoff) configurable | ||||||
|     aresample->resample = av_resample_init(aresample->out_rate, inlink->sample_rate, |     aresample->swr = swr_alloc_set_opts(aresample->swr, | ||||||
|                                            16, 10, 0, 0.8); |                                         inlink->channel_layout, inlink->format, aresample->out_rate, | ||||||
|  |                                         inlink->channel_layout, inlink->format, inlink->sample_rate, | ||||||
|  |                                         0, ctx); | ||||||
|  |     if (!aresample->swr) | ||||||
|  |         return AVERROR(ENOMEM); | ||||||
|  |     ret = swr_init(aresample->swr); | ||||||
|  |     if (ret < 0) | ||||||
|  |         return ret; | ||||||
|  |  | ||||||
|     aresample->ratio = (double)outlink->sample_rate / inlink->sample_rate; |     aresample->ratio = (double)outlink->sample_rate / inlink->sample_rate; | ||||||
|  |  | ||||||
| @@ -96,235 +86,24 @@ static int config_output(AVFilterLink *outlink) | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int query_formats(AVFilterContext *ctx) |  | ||||||
| { |  | ||||||
|     AVFilterFormats *formats = NULL; |  | ||||||
|  |  | ||||||
|     avfilter_add_format(&formats, AV_SAMPLE_FMT_S16); |  | ||||||
|     if (!formats) |  | ||||||
|         return AVERROR(ENOMEM); |  | ||||||
|     avfilter_set_common_sample_formats(ctx, formats); |  | ||||||
|  |  | ||||||
|     formats = avfilter_make_all_channel_layouts(); |  | ||||||
|     if (!formats) |  | ||||||
|         return AVERROR(ENOMEM); |  | ||||||
|     avfilter_set_common_channel_layouts(ctx, formats); |  | ||||||
|  |  | ||||||
|     formats = avfilter_make_all_packing_formats(); |  | ||||||
|     if (!formats) |  | ||||||
|         return AVERROR(ENOMEM); |  | ||||||
|     avfilter_set_common_packing_formats(ctx, formats); |  | ||||||
|  |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void deinterleave(int16_t **outp, int16_t *in, |  | ||||||
|                          int nb_channels, int nb_samples) |  | ||||||
| { |  | ||||||
|     int16_t *out[8]; |  | ||||||
|     memcpy(out, outp, nb_channels * sizeof(int16_t*)); |  | ||||||
|  |  | ||||||
|     switch (nb_channels) { |  | ||||||
|     case 2: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out[0]++ = *in++; |  | ||||||
|             *out[1]++ = *in++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 3: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out[0]++ = *in++; |  | ||||||
|             *out[1]++ = *in++; |  | ||||||
|             *out[2]++ = *in++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 4: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out[0]++ = *in++; |  | ||||||
|             *out[1]++ = *in++; |  | ||||||
|             *out[2]++ = *in++; |  | ||||||
|             *out[3]++ = *in++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 5: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out[0]++ = *in++; |  | ||||||
|             *out[1]++ = *in++; |  | ||||||
|             *out[2]++ = *in++; |  | ||||||
|             *out[3]++ = *in++; |  | ||||||
|             *out[4]++ = *in++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 6: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out[0]++ = *in++; |  | ||||||
|             *out[1]++ = *in++; |  | ||||||
|             *out[2]++ = *in++; |  | ||||||
|             *out[3]++ = *in++; |  | ||||||
|             *out[4]++ = *in++; |  | ||||||
|             *out[5]++ = *in++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 8: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out[0]++ = *in++; |  | ||||||
|             *out[1]++ = *in++; |  | ||||||
|             *out[2]++ = *in++; |  | ||||||
|             *out[3]++ = *in++; |  | ||||||
|             *out[4]++ = *in++; |  | ||||||
|             *out[5]++ = *in++; |  | ||||||
|             *out[6]++ = *in++; |  | ||||||
|             *out[7]++ = *in++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void interleave(int16_t *out, int16_t **inp, |  | ||||||
|         int nb_channels, int nb_samples) |  | ||||||
| { |  | ||||||
|     int16_t *in[8]; |  | ||||||
|     memcpy(in, inp, nb_channels * sizeof(int16_t*)); |  | ||||||
|  |  | ||||||
|     switch (nb_channels) { |  | ||||||
|     case 2: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out++ = *in[0]++; |  | ||||||
|             *out++ = *in[1]++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 3: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out++ = *in[0]++; |  | ||||||
|             *out++ = *in[1]++; |  | ||||||
|             *out++ = *in[2]++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 4: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out++ = *in[0]++; |  | ||||||
|             *out++ = *in[1]++; |  | ||||||
|             *out++ = *in[2]++; |  | ||||||
|             *out++ = *in[3]++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 5: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out++ = *in[0]++; |  | ||||||
|             *out++ = *in[1]++; |  | ||||||
|             *out++ = *in[2]++; |  | ||||||
|             *out++ = *in[3]++; |  | ||||||
|             *out++ = *in[4]++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 6: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out++ = *in[0]++; |  | ||||||
|             *out++ = *in[1]++; |  | ||||||
|             *out++ = *in[2]++; |  | ||||||
|             *out++ = *in[3]++; |  | ||||||
|             *out++ = *in[4]++; |  | ||||||
|             *out++ = *in[5]++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     case 8: |  | ||||||
|         while (nb_samples--) { |  | ||||||
|             *out++ = *in[0]++; |  | ||||||
|             *out++ = *in[1]++; |  | ||||||
|             *out++ = *in[2]++; |  | ||||||
|             *out++ = *in[3]++; |  | ||||||
|             *out++ = *in[4]++; |  | ||||||
|             *out++ = *in[5]++; |  | ||||||
|             *out++ = *in[6]++; |  | ||||||
|             *out++ = *in[7]++; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref) | static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref) | ||||||
| { | { | ||||||
|     AResampleContext *aresample  = inlink->dst->priv; |     AResampleContext *aresample = inlink->dst->priv; | ||||||
|     AVFilterLink * const outlink = inlink->dst->outputs[0]; |     const int n_in  = insamplesref->audio->nb_samples; | ||||||
|     int i, |     int n_out       = n_in * aresample->ratio; | ||||||
|         in_nb_samples            = insamplesref->audio->nb_samples, |     AVFilterLink *const outlink = inlink->dst->outputs[0]; | ||||||
|         cached_nb_samples        = in_nb_samples + aresample->unconsumed_nb_samples, |     AVFilterBufferRef *outsamplesref = avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, n_out); | ||||||
|         requested_out_nb_samples = aresample->ratio * cached_nb_samples, |  | ||||||
|         nb_channels              = |  | ||||||
|             av_get_channel_layout_nb_channels(inlink->channel_layout); |  | ||||||
|  |  | ||||||
|     if (cached_nb_samples > aresample->max_cached_nb_samples) { |     n_out = swr_convert(aresample->swr, outsamplesref->data, n_out, | ||||||
|         for (i = 0; i < nb_channels; i++) { |                                  (void *)insamplesref->data, n_in); | ||||||
|             aresample->cached_data[i]    = |  | ||||||
|                 av_realloc(aresample->cached_data[i], cached_nb_samples * sizeof(int16_t)); |  | ||||||
|             aresample->resampled_data[i] = |  | ||||||
|                 av_realloc(aresample->resampled_data[i], |  | ||||||
|                            FFALIGN(sizeof(int16_t) * requested_out_nb_samples, 16)); |  | ||||||
|  |  | ||||||
|             if (aresample->cached_data[i] == NULL || aresample->resampled_data[i] == NULL) |     avfilter_copy_buffer_ref_props(outsamplesref, insamplesref); | ||||||
|                 return; |     outsamplesref->audio->sample_rate = outlink->sample_rate; | ||||||
|         } |     outsamplesref->audio->nb_samples  = n_out; | ||||||
|         aresample->max_cached_nb_samples = cached_nb_samples; |     outsamplesref->pts = av_rescale(outlink->sample_rate, insamplesref->pts, | ||||||
|  |                                     inlink ->sample_rate); | ||||||
|  |  | ||||||
|         if (aresample->outsamplesref) |     avfilter_filter_samples(outlink, outsamplesref); | ||||||
|             avfilter_unref_buffer(aresample->outsamplesref); |  | ||||||
|  |  | ||||||
|         aresample->outsamplesref = |  | ||||||
|             avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, requested_out_nb_samples); |  | ||||||
|         outlink->out_buf = aresample->outsamplesref; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     avfilter_copy_buffer_ref_props(aresample->outsamplesref, insamplesref); |  | ||||||
|     aresample->outsamplesref->audio->sample_rate = outlink->sample_rate; |  | ||||||
|     aresample->outsamplesref->pts = |  | ||||||
|         av_rescale(outlink->sample_rate, insamplesref->pts, inlink->sample_rate); |  | ||||||
|  |  | ||||||
|     /* av_resample() works with planar audio buffers */ |  | ||||||
|     if (!inlink->planar && nb_channels > 1) { |  | ||||||
|         int16_t *out[8]; |  | ||||||
|         for (i = 0; i < nb_channels; i++) |  | ||||||
|             out[i] = aresample->cached_data[i] + aresample->unconsumed_nb_samples; |  | ||||||
|  |  | ||||||
|         deinterleave(out, (int16_t *)insamplesref->data[0], |  | ||||||
|                      nb_channels, in_nb_samples); |  | ||||||
|     } else { |  | ||||||
|         for (i = 0; i < nb_channels; i++) |  | ||||||
|             memcpy(aresample->cached_data[i] + aresample->unconsumed_nb_samples, |  | ||||||
|                    insamplesref->data[i], |  | ||||||
|                    in_nb_samples * sizeof(int16_t)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     for (i = 0; i < nb_channels; i++) { |  | ||||||
|         int consumed_nb_samples; |  | ||||||
|         const int is_last = i+1 == nb_channels; |  | ||||||
|  |  | ||||||
|         aresample->outsamplesref->audio->nb_samples = |  | ||||||
|             av_resample(aresample->resample, |  | ||||||
|                         aresample->resampled_data[i], aresample->cached_data[i], |  | ||||||
|                         &consumed_nb_samples, |  | ||||||
|                         cached_nb_samples, |  | ||||||
|                         requested_out_nb_samples, is_last); |  | ||||||
|  |  | ||||||
|         /* move unconsumed data back to the beginning of the cache */ |  | ||||||
|         aresample->unconsumed_nb_samples = cached_nb_samples - consumed_nb_samples; |  | ||||||
|         memmove(aresample->cached_data[i], |  | ||||||
|                 aresample->cached_data[i] + consumed_nb_samples, |  | ||||||
|                 aresample->unconsumed_nb_samples * sizeof(int16_t)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     /* copy resampled data to the output samplesref */ |  | ||||||
|     if (!inlink->planar && nb_channels > 1) { |  | ||||||
|         interleave((int16_t *)aresample->outsamplesref->data[0], |  | ||||||
|                    aresample->resampled_data, |  | ||||||
|                    nb_channels, aresample->outsamplesref->audio->nb_samples); |  | ||||||
|     } else { |  | ||||||
|         for (i = 0; i < nb_channels; i++) |  | ||||||
|             memcpy(aresample->outsamplesref->data[i], aresample->resampled_data[i], |  | ||||||
|                    aresample->outsamplesref->audio->nb_samples * sizeof(int16_t)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     avfilter_filter_samples(outlink, avfilter_ref_buffer(aresample->outsamplesref, ~0)); |  | ||||||
|     avfilter_unref_buffer(insamplesref); |     avfilter_unref_buffer(insamplesref); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -333,7 +112,6 @@ AVFilter avfilter_af_aresample = { | |||||||
|     .description   = NULL_IF_CONFIG_SMALL("Resample audio data."), |     .description   = NULL_IF_CONFIG_SMALL("Resample audio data."), | ||||||
|     .init          = init, |     .init          = init, | ||||||
|     .uninit        = uninit, |     .uninit        = uninit, | ||||||
|     .query_formats = query_formats, |  | ||||||
|     .priv_size     = sizeof(AResampleContext), |     .priv_size     = sizeof(AResampleContext), | ||||||
|  |  | ||||||
|     .inputs    = (const AVFilterPad[]) {{ .name      = "default", |     .inputs    = (const AVFilterPad[]) {{ .name      = "default", | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user