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 | ||||
| amovie_filter_deps="avcodec avformat" | ||||
| aresample_filter_deps="swresample" | ||||
| ass_filter_deps="libass" | ||||
| blackframe_filter_deps="gpl" | ||||
| boxblur_filter_deps="gpl" | ||||
|   | ||||
| @@ -5,7 +5,7 @@ FFLIBS = avutil | ||||
|  | ||||
| FFLIBS-$(CONFIG_ACONVERT_FILTER)             += 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_PAN_FILTER)                  += swresample | ||||
| FFLIBS-$(CONFIG_SCALE_FILTER)                += swscale | ||||
|   | ||||
| @@ -24,20 +24,14 @@ | ||||
|  * resampling audio filter | ||||
|  */ | ||||
|  | ||||
| #include "libavutil/eval.h" | ||||
| #include "libavcodec/avcodec.h" | ||||
| #include "libswresample/swresample.h" | ||||
| #include "avfilter.h" | ||||
| #include "internal.h" | ||||
|  | ||||
| typedef struct { | ||||
|     struct AVResampleContext *resample; | ||||
|     int out_rate; | ||||
|     double ratio; | ||||
|     AVFilterBufferRef *outsamplesref; | ||||
|     int unconsumed_nb_samples, | ||||
|         max_cached_nb_samples; | ||||
|     int16_t *cached_data[8], | ||||
|             *resampled_data[8]; | ||||
|     struct SwrContext *swr; | ||||
| } AResampleContext; | ||||
|  | ||||
| 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) | ||||
| { | ||||
|     AResampleContext *aresample = ctx->priv; | ||||
|     if (aresample->outsamplesref) { | ||||
|         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); | ||||
|     swr_free(&aresample->swr); | ||||
| } | ||||
|  | ||||
| static int config_output(AVFilterLink *outlink) | ||||
| { | ||||
|     int ret; | ||||
|     AVFilterContext *ctx = outlink->src; | ||||
|     AVFilterLink *inlink = ctx->inputs[0]; | ||||
|     AResampleContext *aresample = ctx->priv; | ||||
| @@ -85,9 +68,16 @@ static int config_output(AVFilterLink *outlink) | ||||
|         outlink->sample_rate = aresample->out_rate; | ||||
|     outlink->time_base = (AVRational) {1, aresample->out_rate}; | ||||
|  | ||||
|     //TODO: make the resampling parameters configurable | ||||
|     aresample->resample = av_resample_init(aresample->out_rate, inlink->sample_rate, | ||||
|                                            16, 10, 0, 0.8); | ||||
|     //TODO: make the resampling parameters (filter size, phrase shift, linear, cutoff) configurable | ||||
|     aresample->swr = swr_alloc_set_opts(aresample->swr, | ||||
|                                         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; | ||||
|  | ||||
| @@ -96,235 +86,24 @@ static int config_output(AVFilterLink *outlink) | ||||
|     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) | ||||
| { | ||||
|     AResampleContext *aresample = inlink->dst->priv; | ||||
|     AVFilterLink * const outlink = inlink->dst->outputs[0]; | ||||
|     int i, | ||||
|         in_nb_samples            = insamplesref->audio->nb_samples, | ||||
|         cached_nb_samples        = in_nb_samples + aresample->unconsumed_nb_samples, | ||||
|         requested_out_nb_samples = aresample->ratio * cached_nb_samples, | ||||
|         nb_channels              = | ||||
|             av_get_channel_layout_nb_channels(inlink->channel_layout); | ||||
|     const int n_in  = insamplesref->audio->nb_samples; | ||||
|     int n_out       = n_in * aresample->ratio; | ||||
|     AVFilterLink *const outlink = inlink->dst->outputs[0]; | ||||
|     AVFilterBufferRef *outsamplesref = avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, n_out); | ||||
|  | ||||
|     if (cached_nb_samples > aresample->max_cached_nb_samples) { | ||||
|         for (i = 0; i < nb_channels; i++) { | ||||
|             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)); | ||||
|     n_out = swr_convert(aresample->swr, outsamplesref->data, n_out, | ||||
|                                  (void *)insamplesref->data, n_in); | ||||
|  | ||||
|             if (aresample->cached_data[i] == NULL || aresample->resampled_data[i] == NULL) | ||||
|                 return; | ||||
|         } | ||||
|         aresample->max_cached_nb_samples = cached_nb_samples; | ||||
|     avfilter_copy_buffer_ref_props(outsamplesref, insamplesref); | ||||
|     outsamplesref->audio->sample_rate = outlink->sample_rate; | ||||
|     outsamplesref->audio->nb_samples  = n_out; | ||||
|     outsamplesref->pts = av_rescale(outlink->sample_rate, insamplesref->pts, | ||||
|                                     inlink ->sample_rate); | ||||
|  | ||||
|         if (aresample->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_filter_samples(outlink, outsamplesref); | ||||
|     avfilter_unref_buffer(insamplesref); | ||||
| } | ||||
|  | ||||
| @@ -333,7 +112,6 @@ AVFilter avfilter_af_aresample = { | ||||
|     .description   = NULL_IF_CONFIG_SMALL("Resample audio data."), | ||||
|     .init          = init, | ||||
|     .uninit        = uninit, | ||||
|     .query_formats = query_formats, | ||||
|     .priv_size     = sizeof(AResampleContext), | ||||
|  | ||||
|     .inputs    = (const AVFilterPad[]) {{ .name      = "default", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user