2011-09-19 07:13:30 +03:00
/*
2013-01-09 20:30:01 +03:00
* Copyright ( C ) 2011 - 2013 Michael Niedermayer ( michaelni @ gmx . at )
2011-09-19 07:13:30 +03:00
*
* This file is part of libswresample
*
* libswresample 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 .
*
* libswresample 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 libswresample ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2024-03-25 02:30:37 +02:00
# include "libavutil/mem.h"
2011-09-19 07:13:30 +03:00
# include "libavutil/opt.h"
# include "swresample_internal.h"
# include "audioconvert.h"
# include "libavutil/avassert.h"
2012-11-13 16:16:48 +03:00
# include "libavutil/channel_layout.h"
2015-05-13 18:31:27 +02:00
# include "libavutil/internal.h"
2011-09-19 07:13:30 +03:00
2012-05-19 19:44:34 +03:00
# include <float.h>
2012-05-19 18:45:12 +03:00
# define ALIGN 32
2011-09-19 07:13:30 +03:00
2011-11-17 17:06:35 +03:00
int swr_set_channel_mapping ( struct SwrContext * s , const int * channel_map ) {
if ( ! s | | s - > in_convert ) // s needs to be allocated but not initialized
return AVERROR ( EINVAL ) ;
s - > channel_map = channel_map ;
return 0 ;
}
2021-08-27 05:37:53 +02:00
int swr_alloc_set_opts2 ( struct SwrContext * * ps ,
2022-08-05 22:57:31 +02:00
const AVChannelLayout * out_ch_layout , enum AVSampleFormat out_sample_fmt , int out_sample_rate ,
const AVChannelLayout * in_ch_layout , enum AVSampleFormat in_sample_fmt , int in_sample_rate ,
2021-08-27 05:37:53 +02:00
int log_offset , void * log_ctx ) {
struct SwrContext * s = * ps ;
int ret ;
if ( ! s ) s = swr_alloc ( ) ;
if ( ! s ) return AVERROR ( ENOMEM ) ;
* ps = s ;
s - > log_level_offset = log_offset ;
s - > log_ctx = log_ctx ;
if ( ( ret = av_opt_set_chlayout ( s , " ochl " , out_ch_layout , 0 ) ) < 0 )
goto fail ;
if ( ( ret = av_opt_set_int ( s , " osf " , out_sample_fmt , 0 ) ) < 0 )
goto fail ;
if ( ( ret = av_opt_set_int ( s , " osr " , out_sample_rate , 0 ) ) < 0 )
goto fail ;
if ( ( ret = av_opt_set_chlayout ( s , " ichl " , in_ch_layout , 0 ) ) < 0 )
goto fail ;
if ( ( ret = av_opt_set_int ( s , " isf " , in_sample_fmt , 0 ) ) < 0 )
goto fail ;
if ( ( ret = av_opt_set_int ( s , " isr " , in_sample_rate , 0 ) ) < 0 )
goto fail ;
av_opt_set_int ( s , " uch " , 0 , 0 ) ;
return 0 ;
fail :
av_log ( s , AV_LOG_ERROR , " Failed to set option \n " ) ;
swr_free ( ps ) ;
return ret ;
}
2011-09-19 07:13:30 +03:00
2012-04-29 16:29:28 +03:00
static void set_audiodata_fmt ( AudioData * a , enum AVSampleFormat fmt ) {
2012-04-29 16:30:07 +03:00
a - > fmt = fmt ;
2012-04-29 16:29:28 +03:00
a - > bps = av_get_bytes_per_sample ( fmt ) ;
a - > planar = av_sample_fmt_is_planar ( fmt ) ;
2014-08-04 04:05:05 +03:00
if ( a - > ch_count = = 1 )
a - > planar = 1 ;
2012-04-29 16:29:28 +03:00
}
2011-09-19 07:13:30 +03:00
static void free_temp ( AudioData * a ) {
av_free ( a - > data ) ;
memset ( a , 0 , sizeof ( * a ) ) ;
}
2014-02-22 23:36:30 +03:00
static void clear_context ( SwrContext * s ) {
2011-09-19 07:13:30 +03:00
s - > in_buffer_index = 0 ;
s - > in_buffer_count = 0 ;
s - > resample_in_constraint = 0 ;
2014-02-22 23:36:30 +03:00
memset ( s - > in . ch , 0 , sizeof ( s - > in . ch ) ) ;
memset ( s - > out . ch , 0 , sizeof ( s - > out . ch ) ) ;
2011-09-19 07:13:30 +03:00
free_temp ( & s - > postin ) ;
free_temp ( & s - > midbuf ) ;
free_temp ( & s - > preout ) ;
free_temp ( & s - > in_buffer ) ;
2013-01-13 17:26:04 +03:00
free_temp ( & s - > silence ) ;
2013-01-13 17:21:33 +03:00
free_temp ( & s - > drop_temp ) ;
2013-01-09 20:41:12 +03:00
free_temp ( & s - > dither . noise ) ;
2013-01-10 20:51:30 +03:00
free_temp ( & s - > dither . temp ) ;
2021-08-27 05:37:53 +02:00
av_channel_layout_uninit ( & s - > in_ch_layout ) ;
av_channel_layout_uninit ( & s - > out_ch_layout ) ;
2023-02-17 20:41:56 +02:00
av_channel_layout_uninit ( & s - > used_ch_layout ) ;
2011-11-16 10:00:31 +03:00
swri_audio_convert_free ( & s - > in_convert ) ;
swri_audio_convert_free ( & s - > out_convert ) ;
swri_audio_convert_free ( & s - > full_convert ) ;
2012-05-01 21:19:28 +03:00
swri_rematrix_free ( s ) ;
2011-09-19 07:13:30 +03:00
2015-06-22 18:23:44 +02:00
s - > delayed_samples_fixup = 0 ;
2012-03-25 06:58:31 +03:00
s - > flushed = 0 ;
2014-02-22 23:36:30 +03:00
}
av_cold void swr_free ( SwrContext * * ss ) {
SwrContext * s = * ss ;
if ( s ) {
clear_context ( s ) ;
2021-08-27 05:37:53 +02:00
av_channel_layout_uninit ( & s - > user_in_chlayout ) ;
av_channel_layout_uninit ( & s - > user_out_chlayout ) ;
2023-02-17 20:41:56 +02:00
av_channel_layout_uninit ( & s - > user_used_chlayout ) ;
2021-08-27 05:37:53 +02:00
2014-02-22 23:36:30 +03:00
if ( s - > resampler )
s - > resampler - > free ( & s - > resample ) ;
}
av_freep ( ss ) ;
}
2014-05-15 19:27:23 +03:00
av_cold void swr_close ( SwrContext * s ) {
clear_context ( s ) ;
}
2014-02-22 23:36:30 +03:00
av_cold int swr_init ( struct SwrContext * s ) {
int ret ;
2015-04-12 21:08:09 +02:00
char l1 [ 1024 ] , l2 [ 1024 ] ;
2014-02-22 23:36:30 +03:00
clear_context ( s ) ;
2012-03-25 06:58:31 +03:00
2023-08-02 14:14:10 +02:00
if ( ( unsigned ) s - > in_sample_fmt > = AV_SAMPLE_FMT_NB ) {
2011-11-24 18:05:14 +03:00
av_log ( s , AV_LOG_ERROR , " Requested input sample format %d is invalid \n " , s - > in_sample_fmt ) ;
2011-10-01 02:39:17 +03:00
return AVERROR ( EINVAL ) ;
}
2023-08-02 14:14:10 +02:00
if ( ( unsigned ) s - > out_sample_fmt > = AV_SAMPLE_FMT_NB ) {
2011-11-24 18:05:14 +03:00
av_log ( s , AV_LOG_ERROR , " Requested output sample format %d is invalid \n " , s - > out_sample_fmt ) ;
2011-10-01 02:39:17 +03:00
return AVERROR ( EINVAL ) ;
}
2019-05-24 18:04:50 +02:00
if ( s - > in_sample_rate < = 0 ) {
av_log ( s , AV_LOG_ERROR , " Requested input sample rate %d is invalid \n " , s - > in_sample_rate ) ;
return AVERROR ( EINVAL ) ;
}
if ( s - > out_sample_rate < = 0 ) {
av_log ( s , AV_LOG_ERROR , " Requested output sample rate %d is invalid \n " , s - > out_sample_rate ) ;
return AVERROR ( EINVAL ) ;
}
2022-09-09 00:43:03 +02:00
2021-08-27 05:37:53 +02:00
s - > out . ch_count = s - > user_out_chlayout . nb_channels ;
s - > in . ch_count = s - > user_in_chlayout . nb_channels ;
2022-09-09 00:43:03 +02:00
if ( ! ( ret = av_channel_layout_check ( & s - > user_in_chlayout ) ) | | s - > user_in_chlayout . nb_channels > SWR_CH_MAX ) {
if ( ret )
av_channel_layout_describe ( & s - > user_in_chlayout , l1 , sizeof ( l1 ) ) ;
av_log ( s , AV_LOG_WARNING , " Input channel layout \" %s \" is invalid or unsupported. \n " , ret ? l1 : " " ) ;
return AVERROR ( EINVAL ) ;
}
if ( ! ( ret = av_channel_layout_check ( & s - > user_out_chlayout ) ) | | s - > user_out_chlayout . nb_channels > SWR_CH_MAX ) {
if ( ret )
av_channel_layout_describe ( & s - > user_out_chlayout , l2 , sizeof ( l2 ) ) ;
av_log ( s , AV_LOG_WARNING , " Output channel layout \" %s \" is invalid or unsupported. \n " , ret ? l2 : " " ) ;
return AVERROR ( EINVAL ) ;
}
2021-08-27 05:37:53 +02:00
ret = av_channel_layout_copy ( & s - > in_ch_layout , & s - > user_in_chlayout ) ;
ret | = av_channel_layout_copy ( & s - > out_ch_layout , & s - > user_out_chlayout ) ;
2023-02-17 20:41:56 +02:00
ret | = av_channel_layout_copy ( & s - > used_ch_layout , & s - > user_used_chlayout ) ;
2021-08-27 05:37:53 +02:00
if ( ret < 0 )
return ret ;
2015-04-12 20:50:53 +02:00
2015-06-22 18:27:27 +02:00
s - > int_sample_fmt = s - > user_int_sample_fmt ;
2016-08-18 11:52:11 +02:00
s - > dither . method = s - > user_dither_method ;
2013-02-04 06:00:12 +03:00
switch ( s - > engine ) {
# if CONFIG_LIBSOXR
2015-02-27 20:20:43 +02:00
case SWR_ENGINE_SOXR : s - > resampler = & swri_soxr_resampler ; break ;
2013-02-04 06:00:12 +03:00
# endif
case SWR_ENGINE_SWR : s - > resampler = & swri_resampler ; break ;
default :
av_log ( s , AV_LOG_ERROR , " Requested resampling engine is unavailable \n " ) ;
return AVERROR ( EINVAL ) ;
}
2023-02-17 20:41:56 +02:00
if ( ! av_channel_layout_check ( & s - > used_ch_layout ) )
av_channel_layout_default ( & s - > used_ch_layout , s - > in . ch_count ) ;
2013-02-04 06:00:12 +03:00
2023-02-17 20:41:56 +02:00
if ( s - > used_ch_layout . nb_channels ! = s - > in_ch_layout . nb_channels )
2021-08-27 05:37:53 +02:00
av_channel_layout_uninit ( & s - > in_ch_layout ) ;
2013-02-04 06:00:12 +03:00
2023-02-17 20:41:56 +02:00
if ( s - > used_ch_layout . order = = AV_CHANNEL_ORDER_UNSPEC )
av_channel_layout_default ( & s - > used_ch_layout , s - > used_ch_layout . nb_channels ) ;
if ( s - > in_ch_layout . order = = AV_CHANNEL_ORDER_UNSPEC ) {
ret = av_channel_layout_copy ( & s - > in_ch_layout , & s - > used_ch_layout ) ;
if ( ret < 0 )
return ret ;
}
2022-09-09 00:43:03 +02:00
if ( s - > out_ch_layout . order = = AV_CHANNEL_ORDER_UNSPEC )
2021-08-27 05:37:53 +02:00
av_channel_layout_default ( & s - > out_ch_layout , s - > out . ch_count ) ;
2013-02-04 06:00:12 +03:00
2021-08-27 05:37:53 +02:00
s - > rematrix = av_channel_layout_compare ( & s - > out_ch_layout , & s - > in_ch_layout ) | |
s - > rematrix_volume ! = 1.0 | |
2013-02-04 06:00:12 +03:00
s - > rematrix_custom ;
2012-05-02 01:51:06 +03:00
if ( s - > int_sample_fmt = = AV_SAMPLE_FMT_NONE ) {
2023-01-05 14:40:12 +02:00
// 16bit or less to 16bit or less with the same sample rate
2016-03-22 15:11:03 +02:00
if ( av_get_bytes_per_sample ( s - > in_sample_fmt ) < = 2
2023-01-05 14:40:12 +02:00
& & av_get_bytes_per_sample ( s - > out_sample_fmt ) < = 2
& & s - > out_sample_rate = = s - > in_sample_rate ) {
s - > int_sample_fmt = AV_SAMPLE_FMT_S16P ;
// 8 -> 8, 16->8, 8->16bit
} else if ( av_get_bytes_per_sample ( s - > in_sample_fmt )
+ av_get_bytes_per_sample ( s - > out_sample_fmt ) < = 3 ) {
2015-06-21 16:29:09 +02:00
s - > int_sample_fmt = AV_SAMPLE_FMT_S16P ;
2016-03-22 15:11:03 +02:00
} else if ( av_get_bytes_per_sample ( s - > in_sample_fmt ) < = 2
2015-06-21 16:29:09 +02:00
& & ! s - > rematrix
& & s - > out_sample_rate = = s - > in_sample_rate
& & ! ( s - > flags & SWR_FLAG_RESAMPLE ) ) {
2012-05-02 01:51:06 +03:00
s - > int_sample_fmt = AV_SAMPLE_FMT_S16P ;
2013-02-04 04:36:33 +03:00
} else if ( av_get_planar_sample_fmt ( s - > in_sample_fmt ) = = AV_SAMPLE_FMT_S32P
& & av_get_planar_sample_fmt ( s - > out_sample_fmt ) = = AV_SAMPLE_FMT_S32P
& & ! s - > rematrix
2017-03-16 07:35:11 +02:00
& & s - > out_sample_rate = = s - > in_sample_rate
& & ! ( s - > flags & SWR_FLAG_RESAMPLE )
2013-02-04 04:36:33 +03:00
& & s - > engine ! = SWR_ENGINE_SOXR ) {
s - > int_sample_fmt = AV_SAMPLE_FMT_S32P ;
2016-03-22 15:11:03 +02:00
} else if ( av_get_bytes_per_sample ( s - > in_sample_fmt ) < = 4 ) {
2012-05-02 01:51:06 +03:00
s - > int_sample_fmt = AV_SAMPLE_FMT_FLTP ;
} else {
s - > int_sample_fmt = AV_SAMPLE_FMT_DBLP ;
}
}
2015-06-21 18:08:19 +02:00
av_log ( s , AV_LOG_DEBUG , " Using %s internally between filters \n " , av_get_sample_fmt_name ( s - > int_sample_fmt ) ) ;
2011-09-19 07:13:30 +03:00
2012-04-28 12:19:22 +03:00
if ( s - > int_sample_fmt ! = AV_SAMPLE_FMT_S16P
& & s - > int_sample_fmt ! = AV_SAMPLE_FMT_S32P
2016-08-17 19:08:43 +02:00
& & s - > int_sample_fmt ! = AV_SAMPLE_FMT_S64P
2012-05-02 01:50:00 +03:00
& & s - > int_sample_fmt ! = AV_SAMPLE_FMT_FLTP
& & s - > int_sample_fmt ! = AV_SAMPLE_FMT_DBLP ) {
2017-10-26 16:52:22 +02:00
av_log ( s , AV_LOG_ERROR , " Requested sample format %s is not supported internally, s16p/s32p/s64p/fltp/dblp are supported \n " , av_get_sample_fmt_name ( s - > int_sample_fmt ) ) ;
2012-04-10 14:19:29 +03:00
return AVERROR ( EINVAL ) ;
}
2011-09-19 07:13:30 +03:00
2012-04-29 16:29:28 +03:00
set_audiodata_fmt ( & s - > in , s - > in_sample_fmt ) ;
set_audiodata_fmt ( & s - > out , s - > out_sample_fmt ) ;
2013-01-21 02:52:14 +03:00
if ( s - > firstpts_in_samples ! = AV_NOPTS_VALUE ) {
if ( ! s - > async & & s - > min_compensation > = FLT_MAX / 2 )
s - > async = 1 ;
2023-12-15 08:46:39 +02:00
if ( s - > firstpts = = AV_NOPTS_VALUE )
s - > firstpts =
s - > outpts = s - > firstpts_in_samples * s - > out_sample_rate ;
2013-02-25 05:04:03 +03:00
} else
s - > firstpts = AV_NOPTS_VALUE ;
2013-01-21 02:52:14 +03:00
2012-12-23 01:53:45 +03:00
if ( s - > async ) {
if ( s - > min_compensation > = FLT_MAX / 2 )
s - > min_compensation = 0.001 ;
if ( s - > async > 1.0001 ) {
s - > max_soft_compensation = s - > async / ( double ) s - > in_sample_rate ;
}
}
2011-09-19 07:13:30 +03:00
if ( s - > out_sample_rate ! = s - > in_sample_rate | | ( s - > flags & SWR_FLAG_RESAMPLE ) ) {
2016-06-12 00:19:20 +02:00
s - > resample = s - > resampler - > init ( s - > resample , s - > out_sample_rate , s - > in_sample_rate , s - > filter_size , s - > phase_shift , s - > linear_interp , s - > cutoff , s - > int_sample_fmt , s - > filter_type , s - > kaiser_beta , s - > precision , s - > cheby , s - > exact_rational ) ;
2015-06-03 00:48:29 +02:00
if ( ! s - > resample ) {
2015-06-06 12:16:18 +02:00
av_log ( s , AV_LOG_ERROR , " Failed to initialize resampler \n " ) ;
2015-06-03 00:48:29 +02:00
return AVERROR ( ENOMEM ) ;
}
2011-09-19 07:13:30 +03:00
} else
2012-12-11 20:36:58 +03:00
s - > resampler - > free ( & s - > resample ) ;
2012-04-28 12:19:22 +03:00
if ( s - > int_sample_fmt ! = AV_SAMPLE_FMT_S16P
& & s - > int_sample_fmt ! = AV_SAMPLE_FMT_S32P
& & s - > int_sample_fmt ! = AV_SAMPLE_FMT_FLTP
2012-05-02 01:48:44 +03:00
& & s - > int_sample_fmt ! = AV_SAMPLE_FMT_DBLP
2012-04-10 14:19:29 +03:00
& & s - > resample ) {
2017-10-26 16:52:22 +02:00
av_log ( s , AV_LOG_ERROR , " Resampling only supported with internal s16p/s32p/fltp/dblp \n " ) ;
2015-06-04 03:47:55 +02:00
ret = AVERROR ( EINVAL ) ;
goto fail ;
2011-09-19 07:13:30 +03:00
}
# define RSC 1 //FIXME finetune
if ( ! s - > in . ch_count )
2021-08-27 05:37:53 +02:00
s - > in . ch_count = s - > in_ch_layout . nb_channels ;
2023-02-17 20:41:56 +02:00
if ( ! av_channel_layout_check ( & s - > used_ch_layout ) )
av_channel_layout_default ( & s - > used_ch_layout , s - > in . ch_count ) ;
2011-09-19 07:13:30 +03:00
if ( ! s - > out . ch_count )
2021-08-27 05:37:53 +02:00
s - > out . ch_count = s - > out_ch_layout . nb_channels ;
2011-09-19 07:13:30 +03:00
2011-12-20 13:23:46 +03:00
if ( ! s - > in . ch_count ) {
2021-08-27 05:37:53 +02:00
av_assert0 ( s - > in_ch_layout . order = = AV_CHANNEL_ORDER_UNSPEC ) ;
2011-12-20 13:23:46 +03:00
av_log ( s , AV_LOG_ERROR , " Input channel count and layout are unset \n " ) ;
2015-06-04 03:47:55 +02:00
ret = AVERROR ( EINVAL ) ;
goto fail ;
2011-12-20 13:23:46 +03:00
}
2022-08-21 22:46:36 +02:00
av_channel_layout_describe ( & s - > out_ch_layout , l2 , sizeof ( l2 ) ) ;
2021-08-27 05:37:53 +02:00
av_channel_layout_describe ( & s - > in_ch_layout , l1 , sizeof ( l1 ) ) ;
2023-02-17 20:41:56 +02:00
if ( s - > in_ch_layout . order ! = AV_CHANNEL_ORDER_UNSPEC & & s - > used_ch_layout . nb_channels ! = s - > in_ch_layout . nb_channels ) {
av_log ( s , AV_LOG_ERROR , " Input channel layout %s mismatches specified channel count %d \n " , l1 , s - > used_ch_layout . nb_channels ) ;
2015-06-04 03:47:55 +02:00
ret = AVERROR ( EINVAL ) ;
goto fail ;
2015-04-12 21:08:09 +02:00
}
2021-08-27 05:37:53 +02:00
if ( ( s - > out_ch_layout . order = = AV_CHANNEL_ORDER_UNSPEC
2023-02-17 20:41:56 +02:00
| | s - > in_ch_layout . order = = AV_CHANNEL_ORDER_UNSPEC ) & & s - > used_ch_layout . nb_channels ! = s - > out . ch_count & & ! s - > rematrix_custom ) {
2012-12-31 14:12:23 +03:00
av_log ( s , AV_LOG_ERROR , " Rematrix is needed between %s and %s "
" but there is not enough information to do it \n " , l1 , l2 ) ;
2015-06-04 03:47:55 +02:00
ret = AVERROR ( EINVAL ) ;
goto fail ;
2012-03-23 14:10:08 +03:00
}
2023-02-17 20:41:56 +02:00
av_assert0 ( s - > used_ch_layout . nb_channels ) ;
2011-09-19 07:13:30 +03:00
av_assert0 ( s - > out . ch_count ) ;
2023-02-17 20:41:56 +02:00
s - > resample_first = RSC * s - > out . ch_count / s - > used_ch_layout . nb_channels - RSC < s - > out_sample_rate / ( float ) s - > in_sample_rate - 1.0 ;
2011-09-19 07:13:30 +03:00
2012-03-25 22:04:48 +03:00
s - > in_buffer = s - > in ;
2013-01-13 17:26:04 +03:00
s - > silence = s - > in ;
2013-01-13 17:21:33 +03:00
s - > drop_temp = s - > out ;
2011-09-19 07:13:30 +03:00
2016-08-18 11:44:42 +02:00
if ( ( ret = swri_dither_init ( s , s - > out_sample_fmt , s - > int_sample_fmt ) ) < 0 )
goto fail ;
2013-01-09 20:41:12 +03:00
if ( ! s - > resample & & ! s - > rematrix & & ! s - > channel_map & & ! s - > dither . method ) {
2011-11-16 10:00:31 +03:00
s - > full_convert = swri_audio_convert_alloc ( s - > out_sample_fmt ,
s - > in_sample_fmt , s - > in . ch_count , NULL , 0 ) ;
2011-10-06 00:46:50 +03:00
return 0 ;
}
2011-11-16 10:00:31 +03:00
s - > in_convert = swri_audio_convert_alloc ( s - > int_sample_fmt ,
2023-02-17 20:41:56 +02:00
s - > in_sample_fmt , s - > used_ch_layout . nb_channels , s - > channel_map , 0 ) ;
2011-11-16 10:00:31 +03:00
s - > out_convert = swri_audio_convert_alloc ( s - > out_sample_fmt ,
s - > int_sample_fmt , s - > out . ch_count , NULL , 0 ) ;
2011-09-19 07:13:30 +03:00
2015-06-04 03:47:55 +02:00
if ( ! s - > in_convert | | ! s - > out_convert ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
2011-09-19 07:13:30 +03:00
s - > postin = s - > in ;
s - > preout = s - > out ;
s - > midbuf = s - > in ;
2012-03-25 22:04:48 +03:00
2011-11-04 20:54:01 +03:00
if ( s - > channel_map ) {
s - > postin . ch_count =
2023-02-17 20:41:56 +02:00
s - > midbuf . ch_count = s - > used_ch_layout . nb_channels ;
2012-03-25 22:04:48 +03:00
if ( s - > resample )
2023-02-17 20:41:56 +02:00
s - > in_buffer . ch_count = s - > used_ch_layout . nb_channels ;
2011-11-04 20:54:01 +03:00
}
2011-09-19 07:13:30 +03:00
if ( ! s - > resample_first ) {
s - > midbuf . ch_count = s - > out . ch_count ;
2012-03-25 22:04:48 +03:00
if ( s - > resample )
s - > in_buffer . ch_count = s - > out . ch_count ;
2011-09-19 07:13:30 +03:00
}
2012-04-29 16:29:28 +03:00
set_audiodata_fmt ( & s - > postin , s - > int_sample_fmt ) ;
set_audiodata_fmt ( & s - > midbuf , s - > int_sample_fmt ) ;
set_audiodata_fmt ( & s - > preout , s - > int_sample_fmt ) ;
2011-09-19 07:13:30 +03:00
2012-03-25 22:04:48 +03:00
if ( s - > resample ) {
2012-04-29 16:29:28 +03:00
set_audiodata_fmt ( & s - > in_buffer , s - > int_sample_fmt ) ;
2012-03-25 22:04:48 +03:00
}
2011-09-19 07:13:30 +03:00
2016-08-18 11:44:42 +02:00
av_assert0 ( ! s - > preout . count ) ;
s - > dither . noise = s - > preout ;
s - > dither . temp = s - > preout ;
if ( s - > dither . method > SWR_DITHER_NS ) {
s - > dither . noise . bps = 4 ;
s - > dither . noise . fmt = AV_SAMPLE_FMT_FLTP ;
s - > dither . noise_scale = 1 ;
}
2012-04-10 20:52:42 +03:00
2015-06-04 03:47:55 +02:00
if ( s - > rematrix | | s - > dither . method ) {
ret = swri_rematrix_init ( s ) ;
if ( ret < 0 )
goto fail ;
}
2011-09-19 07:13:30 +03:00
return 0 ;
2015-06-04 03:47:55 +02:00
fail :
swr_close ( s ) ;
return ret ;
2011-09-19 07:13:30 +03:00
}
2012-12-11 23:15:19 +03:00
int swri_realloc_audio ( AudioData * a , int count ) {
2011-09-19 07:13:30 +03:00
int i , countb ;
AudioData old ;
2012-05-22 18:15:07 +03:00
if ( count < 0 | | count > INT_MAX / 2 / a - > bps / a - > ch_count )
return AVERROR ( EINVAL ) ;
2011-09-19 07:13:30 +03:00
if ( a - > count > = count )
return 0 ;
count * = 2 ;
2012-05-19 18:45:12 +03:00
countb = FFALIGN ( count * a - > bps , ALIGN ) ;
2011-09-19 07:13:30 +03:00
old = * a ;
av_assert0 ( a - > bps ) ;
av_assert0 ( a - > ch_count ) ;
2021-09-14 21:31:53 +02:00
a - > data = av_calloc ( countb , a - > ch_count ) ;
2011-09-19 07:13:30 +03:00
if ( ! a - > data )
return AVERROR ( ENOMEM ) ;
for ( i = 0 ; i < a - > ch_count ; i + + ) {
a - > ch [ i ] = a - > data + i * ( a - > planar ? countb : a - > bps ) ;
2016-12-10 02:52:56 +02:00
if ( a - > count & & a - > planar ) memcpy ( a - > ch [ i ] , old . ch [ i ] , a - > count * a - > bps ) ;
2011-09-19 07:13:30 +03:00
}
2016-12-10 02:52:56 +02:00
if ( a - > count & & ! a - > planar ) memcpy ( a - > ch [ 0 ] , old . ch [ 0 ] , a - > count * a - > ch_count * a - > bps ) ;
2013-09-16 23:44:15 +03:00
av_freep ( & old . data ) ;
2011-09-19 07:13:30 +03:00
a - > count = count ;
return 1 ;
}
static void copy ( AudioData * out , AudioData * in ,
int count ) {
av_assert0 ( out - > planar = = in - > planar ) ;
av_assert0 ( out - > bps = = in - > bps ) ;
av_assert0 ( out - > ch_count = = in - > ch_count ) ;
if ( out - > planar ) {
int ch ;
for ( ch = 0 ; ch < out - > ch_count ; ch + + )
memcpy ( out - > ch [ ch ] , in - > ch [ ch ] , count * out - > bps ) ;
} else
memcpy ( out - > ch [ 0 ] , in - > ch [ 0 ] , count * out - > ch_count * out - > bps ) ;
}
2024-02-28 20:58:41 +02:00
static void fill_audiodata ( AudioData * out , uint8_t * const in_arg [ SWR_CH_MAX ] )
{
2011-09-29 05:53:50 +03:00
int i ;
2012-05-19 18:44:40 +03:00
if ( ! in_arg ) {
memset ( out - > ch , 0 , sizeof ( out - > ch ) ) ;
} else if ( out - > planar ) {
2011-09-29 05:53:50 +03:00
for ( i = 0 ; i < out - > ch_count ; i + + )
out - > ch [ i ] = in_arg [ i ] ;
} else {
for ( i = 0 ; i < out - > ch_count ; i + + )
out - > ch [ i ] = in_arg [ 0 ] + i * out - > bps ;
}
}
2012-05-19 18:46:41 +03:00
static void reversefill_audiodata ( AudioData * out , uint8_t * in_arg [ SWR_CH_MAX ] ) {
int i ;
if ( out - > planar ) {
for ( i = 0 ; i < out - > ch_count ; i + + )
in_arg [ i ] = out - > ch [ i ] ;
} else {
in_arg [ 0 ] = out - > ch [ 0 ] ;
}
}
2011-11-17 17:09:52 +03:00
/**
*
* out may be equal in .
*/
static void buf_set ( AudioData * out , AudioData * in , int count ) {
2012-04-21 00:06:25 +03:00
int ch ;
2011-11-17 17:09:52 +03:00
if ( in - > planar ) {
for ( ch = 0 ; ch < out - > ch_count ; ch + + )
out - > ch [ ch ] = in - > ch [ ch ] + count * out - > bps ;
2012-04-21 00:06:25 +03:00
} else {
2012-05-19 18:45:41 +03:00
for ( ch = out - > ch_count - 1 ; ch > = 0 ; ch - - )
2012-04-21 00:06:25 +03:00
out - > ch [ ch ] = in - > ch [ 0 ] + ( ch + count * out - > ch_count ) * out - > bps ;
}
2011-11-17 17:09:52 +03:00
}
/**
*
* @ 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 ;
2013-12-04 22:25:43 +03:00
int padless = ARCH_X86 & & s - > engine = = SWR_ENGINE_SWR ? 7 : 0 ;
2011-11-17 17:09:52 +03:00
2012-05-19 18:47:06 +03:00
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 ) ;
2011-11-17 17:09:52 +03:00
tmp = out = * out_param ;
in = * in_param ;
2014-06-14 02:06:30 +03:00
border = s - > resampler - > invert_initial_buffer ( s - > resample , & s - > in_buffer ,
& in , in_count , & s - > in_buffer_index , & s - > in_buffer_count ) ;
2014-10-16 19:18:40 +03:00
if ( border = = INT_MAX ) {
return 0 ;
} else if ( border < 0 ) {
return border ;
} else if ( border ) {
buf_set ( & in , & in , border ) ;
in_count - = border ;
s - > resample_in_constraint = 0 ;
}
2014-06-14 02:06:30 +03:00
2011-11-17 17:09:52 +03:00
do {
int ret , size , consumed ;
if ( ! s - > resample_in_constraint & & s - > in_buffer_count ) {
buf_set ( & tmp , & s - > in_buffer , s - > in_buffer_index ) ;
2012-12-11 20:36:58 +03:00
ret = s - > resampler - > multiple_resample ( s - > resample , & out , out_count , & tmp , s - > in_buffer_count , & consumed ) ;
2011-11-17 17:09:52 +03:00
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 ;
}
}
2013-12-04 22:25:43 +03:00
if ( ( s - > flushed | | in_count > padless ) & & ! s - > in_buffer_count ) {
2011-11-17 17:09:52 +03:00
s - > in_buffer_index = 0 ;
2013-12-04 22:25:43 +03:00
ret = s - > resampler - > multiple_resample ( s - > resample , & out , out_count , & in , FFMAX ( in_count - padless , 0 ) , & consumed ) ;
2011-11-17 17:09:52 +03:00
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
2012-12-11 23:15:19 +03:00
if ( ( ret = swri_realloc_audio ( & s - > in_buffer , size ) ) < 0 )
2011-11-17 17:09:52 +03:00
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 ;
2013-12-04 22:25:43 +03:00
if ( padless ) {
padless = 0 ;
continue ;
}
2011-11-17 17:09:52 +03:00
}
break ;
} while ( 1 ) ;
s - > resample_in_constraint = ! ! out_count ;
return ret_sum ;
}
2012-04-01 23:10:40 +03:00
static int swr_convert_internal ( struct SwrContext * s , AudioData * out , int out_count ,
AudioData * in , int in_count ) {
2011-09-19 07:13:30 +03:00
AudioData * postin , * midbuf , * preout ;
2011-10-21 01:34:37 +03:00
int ret /*, in_max*/ ;
2011-09-19 07:13:30 +03:00
AudioData preout_tmp , midbuf_tmp ;
2011-10-06 00:46:50 +03:00
if ( s - > full_convert ) {
av_assert0 ( ! s - > resample ) ;
2011-11-16 10:00:31 +03:00
swri_audio_convert ( s - > full_convert , out , in , in_count ) ;
2011-10-06 00:46:50 +03:00
return out_count ;
}
2011-09-19 07:13:30 +03:00
// in_max= out_count*(int64_t)s->in_sample_rate / s->out_sample_rate + resample_filter_taps;
// in_count= FFMIN(in_count, in_in + 2 - s->hist_buffer_count);
2012-12-11 23:15:19 +03:00
if ( ( ret = swri_realloc_audio ( & s - > postin , in_count ) ) < 0 )
2011-09-19 07:13:30 +03:00
return ret ;
if ( s - > resample_first ) {
2023-02-17 20:41:56 +02:00
av_assert0 ( s - > midbuf . ch_count = = s - > used_ch_layout . nb_channels ) ;
2012-12-11 23:15:19 +03:00
if ( ( ret = swri_realloc_audio ( & s - > midbuf , out_count ) ) < 0 )
2011-09-19 07:13:30 +03:00
return ret ;
} else {
av_assert0 ( s - > midbuf . ch_count = = s - > out . ch_count ) ;
2012-12-11 23:15:19 +03:00
if ( ( ret = swri_realloc_audio ( & s - > midbuf , in_count ) ) < 0 )
2011-09-19 07:13:30 +03:00
return ret ;
}
2012-12-11 23:15:19 +03:00
if ( ( ret = swri_realloc_audio ( & s - > preout , out_count ) ) < 0 )
2011-09-19 07:13:30 +03:00
return ret ;
postin = & s - > postin ;
midbuf_tmp = s - > midbuf ;
midbuf = & midbuf_tmp ;
preout_tmp = s - > preout ;
preout = & preout_tmp ;
2012-07-16 15:18:19 +03:00
if ( s - > int_sample_fmt = = s - > in_sample_fmt & & s - > in . planar & & ! s - > channel_map )
2011-09-19 07:13:30 +03:00
postin = in ;
if ( s - > resample_first ? ! s - > resample : ! s - > rematrix )
midbuf = postin ;
if ( s - > resample_first ? ! s - > rematrix : ! s - > resample )
preout = midbuf ;
2013-06-05 03:49:00 +03:00
if ( s - > int_sample_fmt = = s - > out_sample_fmt & & s - > out . planar
& & ! ( s - > out_sample_fmt = = AV_SAMPLE_FMT_S32P & & ( s - > dither . output_sample_bits & 31 ) ) ) {
2011-09-19 07:13:30 +03:00
if ( preout = = in ) {
2012-03-13 01:30:13 +03:00
out_count = FFMIN ( out_count , in_count ) ; //TODO check at the end if this is needed or redundant
2011-09-19 07:13:30 +03:00
av_assert0 ( s - > in . planar ) ; //we only support planar internally so it has to be, we support copying non planar though
copy ( out , in , out_count ) ;
return out_count ;
}
else if ( preout = = postin ) preout = midbuf = postin = out ;
else if ( preout = = midbuf ) preout = midbuf = out ;
else preout = out ;
}
if ( in ! = postin ) {
2011-11-16 10:00:31 +03:00
swri_audio_convert ( s - > in_convert , postin , in , in_count ) ;
2011-09-19 07:13:30 +03:00
}
if ( s - > resample_first ) {
if ( postin ! = midbuf )
2021-12-08 05:17:13 +02:00
if ( ( out_count = resample ( s , midbuf , out_count , postin , in_count ) ) < 0 )
return out_count ;
2011-09-19 07:13:30 +03:00
if ( midbuf ! = preout )
2011-11-16 10:12:48 +03:00
swri_rematrix ( s , preout , midbuf , out_count , preout = = out ) ;
2011-09-19 07:13:30 +03:00
} else {
if ( postin ! = midbuf )
2011-11-16 10:12:48 +03:00
swri_rematrix ( s , midbuf , postin , in_count , midbuf = = out ) ;
2011-09-19 07:13:30 +03:00
if ( midbuf ! = preout )
2021-12-08 05:17:13 +02:00
if ( ( out_count = resample ( s , preout , out_count , midbuf , in_count ) ) < 0 )
return out_count ;
2011-09-19 07:13:30 +03:00
}
2012-03-25 12:48:09 +03:00
if ( preout ! = out & & out_count ) {
2013-01-10 20:51:30 +03:00
AudioData * conv_src = preout ;
2013-01-09 20:41:12 +03:00
if ( s - > dither . method ) {
2013-01-09 20:41:40 +03:00
int ch ;
2012-04-11 14:26:32 +03:00
int dither_count = FFMAX ( out_count , 1 < < 16 ) ;
2013-01-10 20:51:30 +03:00
if ( preout = = in ) {
conv_src = & s - > dither . temp ;
if ( ( ret = swri_realloc_audio ( & s - > dither . temp , dither_count ) ) < 0 )
return ret ;
}
2012-04-10 20:52:42 +03:00
2013-01-09 20:41:12 +03:00
if ( ( ret = swri_realloc_audio ( & s - > dither . noise , dither_count ) ) < 0 )
2012-04-10 20:52:42 +03:00
return ret ;
if ( ret )
2013-01-09 20:41:12 +03:00
for ( ch = 0 ; ch < s - > dither . noise . ch_count ; ch + + )
2015-09-03 09:22:31 +02:00
if ( ( ret = swri_get_dither ( s , s - > dither . noise . ch [ ch ] , s - > dither . noise . count , ( 12345678913579ULL * ch + 3141592 ) % 2718281828U , s - > dither . noise . fmt ) ) < 0 )
2015-06-03 05:17:48 +02:00
return ret ;
2013-01-09 20:41:12 +03:00
av_assert0 ( s - > dither . noise . ch_count = = preout - > ch_count ) ;
2012-04-10 20:52:42 +03:00
2013-01-10 20:01:26 +03:00
if ( s - > dither . noise_pos + out_count > s - > dither . noise . count )
s - > dither . noise_pos = 0 ;
2012-05-01 21:20:21 +03:00
2013-01-09 20:41:12 +03:00
if ( s - > dither . method < SWR_DITHER_NS ) {
2013-01-09 20:03:49 +03:00
if ( s - > mix_2_1_simd ) {
int len1 = out_count & ~ 15 ;
int off = len1 * preout - > bps ;
if ( len1 )
for ( ch = 0 ; ch < preout - > ch_count ; ch + + )
2013-06-05 00:38:28 +03:00
s - > mix_2_1_simd ( conv_src - > ch [ ch ] , preout - > ch [ ch ] , s - > dither . noise . ch [ ch ] + s - > dither . noise . bps * s - > dither . noise_pos , s - > native_simd_one , 0 , 0 , len1 ) ;
2013-01-09 20:03:49 +03:00
if ( out_count ! = len1 )
for ( ch = 0 ; ch < preout - > ch_count ; ch + + )
2018-04-05 13:58:37 +02:00
s - > mix_2_1_f ( conv_src - > ch [ ch ] + off , preout - > ch [ ch ] + off , s - > dither . noise . ch [ ch ] + s - > dither . noise . bps * s - > dither . noise_pos + off , s - > native_one , 0 , 0 , out_count - len1 ) ;
2013-01-09 20:03:49 +03:00
} else {
2013-01-09 04:05:35 +03:00
for ( ch = 0 ; ch < preout - > ch_count ; ch + + )
2013-01-10 20:51:30 +03:00
s - > mix_2_1_f ( conv_src - > ch [ ch ] , preout - > ch [ ch ] , s - > dither . noise . ch [ ch ] + s - > dither . noise . bps * s - > dither . noise_pos , s - > native_one , 0 , 0 , out_count ) ;
2013-01-09 20:03:49 +03:00
}
2013-01-09 04:05:35 +03:00
} else {
2013-01-09 20:03:49 +03:00
switch ( s - > int_sample_fmt ) {
2013-01-10 20:51:30 +03:00
case AV_SAMPLE_FMT_S16P : swri_noise_shaping_int16 ( s , conv_src , preout , & s - > dither . noise , out_count ) ; break ;
case AV_SAMPLE_FMT_S32P : swri_noise_shaping_int32 ( s , conv_src , preout , & s - > dither . noise , out_count ) ; break ;
case AV_SAMPLE_FMT_FLTP : swri_noise_shaping_float ( s , conv_src , preout , & s - > dither . noise , out_count ) ; break ;
case AV_SAMPLE_FMT_DBLP : swri_noise_shaping_double ( s , conv_src , preout , & s - > dither . noise , out_count ) ; break ;
2013-01-09 20:03:49 +03:00
}
2013-01-09 04:05:35 +03:00
}
2013-01-10 20:01:26 +03:00
s - > dither . noise_pos + = out_count ;
2012-04-10 20:52:42 +03:00
}
2013-06-29 03:24:26 +03:00
//FIXME packed doesn't need more than 1 chan here!
2013-01-10 20:51:30 +03:00
swri_audio_convert ( s - > out_convert , out , conv_src , out_count ) ;
2011-09-19 07:13:30 +03:00
}
return out_count ;
}
2014-02-23 00:28:24 +03:00
int swr_is_initialized ( struct SwrContext * s ) {
return ! ! s - > in_buffer . ch_count ;
}
2021-11-30 13:24:10 +02:00
int attribute_align_arg swr_convert ( struct SwrContext * s ,
2024-02-28 20:58:41 +02:00
uint8_t * const * out_arg , int out_count ,
const uint8_t * const * in_arg , int in_count )
2021-11-30 13:24:10 +02:00
{
2012-03-25 22:04:48 +03:00
AudioData * in = & s - > in ;
AudioData * out = & s - > out ;
2015-06-03 01:22:25 +02:00
int av_unused max_output ;
2012-03-25 22:04:48 +03:00
2014-02-23 00:29:51 +03:00
if ( ! swr_is_initialized ( s ) ) {
av_log ( s , AV_LOG_ERROR , " Context has not been initialized \n " ) ;
return AVERROR ( EINVAL ) ;
}
2015-06-08 20:16:06 +02:00
# if defined(ASSERT_LEVEL) && ASSERT_LEVEL >1
2015-06-03 01:22:25 +02:00
max_output = swr_get_out_samples ( s , in_count ) ;
# endif
2014-02-23 00:29:51 +03:00
2013-01-13 17:53:01 +03:00
while ( s - > drop_output > 0 ) {
2012-05-19 19:42:11 +03:00
int ret ;
uint8_t * tmp_arg [ SWR_CH_MAX ] ;
2013-01-13 17:53:01 +03:00
# define MAX_DROP_STEP 16384
if ( ( ret = swri_realloc_audio ( & s - > drop_temp , FFMIN ( s - > drop_output , MAX_DROP_STEP ) ) ) < 0 )
2012-05-19 19:42:11 +03:00
return ret ;
2013-01-13 17:21:33 +03:00
reversefill_audiodata ( & s - > drop_temp , tmp_arg ) ;
2012-05-19 19:42:11 +03:00
s - > drop_output * = - 1 ; //FIXME find a less hackish solution
2013-06-29 03:24:26 +03:00
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 doesn't matter
2012-05-19 19:42:11 +03:00
s - > drop_output * = - 1 ;
2013-01-13 17:53:01 +03:00
in_count = 0 ;
if ( ret > 0 ) {
2012-05-19 19:42:11 +03:00
s - > drop_output - = ret ;
2014-10-06 02:08:20 +03:00
if ( ! s - > drop_output & & ! out_arg )
return 0 ;
2013-01-13 17:53:01 +03:00
continue ;
}
2012-05-19 19:42:11 +03:00
2014-10-06 02:29:15 +03:00
av_assert0 ( s - > drop_output ) ;
return 0 ;
2012-05-19 19:42:11 +03:00
}
2012-03-25 22:04:48 +03:00
if ( ! in_arg ) {
2012-12-11 23:19:39 +03:00
if ( s - > resample ) {
if ( ! s - > flushed )
s - > resampler - > flush ( s ) ;
s - > resample_in_constraint = 0 ;
s - > flushed = 1 ;
} else if ( ! s - > in_buffer_count ) {
2012-03-25 22:04:48 +03:00
return 0 ;
}
} else
fill_audiodata ( in , ( void * ) in_arg ) ;
fill_audiodata ( out , out_arg ) ;
if ( s - > resample ) {
2012-05-19 19:44:34 +03:00
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 ;
2015-06-03 01:22:25 +02:00
2021-12-08 05:17:13 +02:00
av_assert2 ( max_output < 0 | | ret < = max_output ) ;
2015-06-03 01:22:25 +02:00
2012-05-19 19:44:34 +03:00
return ret ;
2012-03-25 22:04:48 +03:00
} 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
2012-12-11 23:15:19 +03:00
if ( ( ret = swri_realloc_audio ( & s - > in_buffer , size ) ) < 0 )
2012-03-25 22:04:48 +03:00
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 ) {
2012-05-19 19:37:12 +03:00
buf_set ( & tmp , & s - > in_buffer , s - > in_buffer_index + s - > in_buffer_count ) ;
2012-03-25 22:04:48 +03:00
copy ( & tmp , in , in_count ) ;
s - > in_buffer_count + = in_count ;
}
}
2012-05-19 19:44:34 +03:00
if ( ret2 > 0 & & ! s - > drop_output )
s - > outpts + = ret2 * ( int64_t ) s - > in_sample_rate ;
2015-06-03 01:22:25 +02:00
av_assert2 ( max_output < 0 | | ret2 < 0 | | ret2 < = max_output ) ;
2012-03-25 22:04:48 +03:00
return ret2 ;
}
}
2012-05-19 19:42:11 +03:00
int swr_drop_output ( struct SwrContext * s , int count ) {
2014-11-04 17:54:14 +02:00
const uint8_t * tmp_arg [ SWR_CH_MAX ] ;
2012-05-19 19:42:11 +03:00
s - > drop_output + = count ;
if ( s - > drop_output < = 0 )
return 0 ;
av_log ( s , AV_LOG_VERBOSE , " discarding %d audio samples \n " , count ) ;
2014-11-04 17:54:14 +02:00
return swr_convert ( s , NULL , s - > drop_output , tmp_arg , 0 ) ;
2012-05-19 19:42:11 +03:00
}
2012-05-19 19:39:12 +03:00
int swr_inject_silence ( struct SwrContext * s , int count ) {
int ret , i ;
uint8_t * tmp_arg [ SWR_CH_MAX ] ;
if ( count < = 0 )
return 0 ;
2013-01-13 17:57:56 +03:00
# define MAX_SILENCE_STEP 16384
while ( count > MAX_SILENCE_STEP ) {
if ( ( ret = swr_inject_silence ( s , MAX_SILENCE_STEP ) ) < 0 )
return ret ;
count - = MAX_SILENCE_STEP ;
}
2013-01-13 17:26:04 +03:00
if ( ( ret = swri_realloc_audio ( & s - > silence , count ) ) < 0 )
2012-05-19 19:39:12 +03:00
return ret ;
2013-01-13 17:26:04 +03:00
if ( s - > silence . planar ) for ( i = 0 ; i < s - > silence . ch_count ; i + + ) {
memset ( s - > silence . ch [ i ] , s - > silence . bps = = 1 ? 0x80 : 0 , count * s - > silence . bps ) ;
2012-05-19 19:39:12 +03:00
} else
2013-01-13 17:26:04 +03:00
memset ( s - > silence . ch [ 0 ] , s - > silence . bps = = 1 ? 0x80 : 0 , count * s - > silence . bps * s - > silence . ch_count ) ;
2012-05-19 19:39:12 +03:00
2013-01-13 17:26:04 +03:00
reversefill_audiodata ( & s - > silence , tmp_arg ) ;
2012-05-19 19:39:12 +03:00
av_log ( s , AV_LOG_VERBOSE , " adding %d audio samples of silence \n " , count ) ;
ret = swr_convert ( s , NULL , 0 , ( const uint8_t * * ) tmp_arg , count ) ;
return ret ;
}
2012-05-19 19:44:34 +03:00
2012-12-11 20:36:58 +03:00
int64_t swr_get_delay ( struct SwrContext * s , int64_t base ) {
if ( s - > resampler & & s - > resample ) {
return s - > resampler - > get_delay ( s , base ) ;
} else {
return ( s - > in_buffer_count * base + ( s - > in_sample_rate > > 1 ) ) / s - > in_sample_rate ;
}
}
2015-06-03 01:22:25 +02:00
int swr_get_out_samples ( struct SwrContext * s , int in_samples )
{
int64_t out_samples ;
if ( in_samples < 0 )
return AVERROR ( EINVAL ) ;
if ( s - > resampler & & s - > resample ) {
if ( ! s - > resampler - > get_out_samples )
return AVERROR ( ENOSYS ) ;
out_samples = s - > resampler - > get_out_samples ( s , in_samples ) ;
} else {
out_samples = s - > in_buffer_count + in_samples ;
av_assert0 ( s - > out_sample_rate = = s - > in_sample_rate ) ;
}
if ( out_samples > INT_MAX )
return AVERROR ( EINVAL ) ;
return out_samples ;
}
2012-12-11 20:36:58 +03:00
int swr_set_compensation ( struct SwrContext * s , int sample_delta , int compensation_distance ) {
int ret ;
if ( ! s | | compensation_distance < 0 )
return AVERROR ( EINVAL ) ;
if ( ! compensation_distance & & sample_delta )
return AVERROR ( EINVAL ) ;
if ( ! s - > resample ) {
s - > flags | = SWR_FLAG_RESAMPLE ;
ret = swr_init ( s ) ;
if ( ret < 0 )
return ret ;
}
if ( ! s - > resampler - > set_compensation ) {
return AVERROR ( EINVAL ) ;
} else {
return s - > resampler - > set_compensation ( s - > resample , sample_delta , compensation_distance ) ;
}
}
2012-05-19 19:44:34 +03:00
int64_t swr_next_pts ( struct SwrContext * s , int64_t pts ) {
if ( pts = = INT64_MIN )
return s - > outpts ;
2013-02-25 05:04:03 +03:00
if ( s - > firstpts = = AV_NOPTS_VALUE )
s - > outpts = s - > firstpts = pts ;
2012-05-19 19:44:34 +03:00
if ( s - > min_compensation > = FLT_MAX ) {
return ( s - > outpts = pts - swr_get_delay ( s , s - > in_sample_rate * ( int64_t ) s - > out_sample_rate ) ) ;
} else {
2013-01-13 20:39:06 +03:00
int64_t delta = pts - swr_get_delay ( s , s - > in_sample_rate * ( int64_t ) s - > out_sample_rate ) - s - > outpts + s - > drop_output * ( int64_t ) s - > in_sample_rate ;
2012-05-19 19:44:34 +03:00
double fdelta = delta / ( double ) ( s - > in_sample_rate * ( int64_t ) s - > out_sample_rate ) ;
if ( fabs ( fdelta ) > s - > min_compensation ) {
2013-01-21 02:52:14 +03:00
if ( s - > outpts = = s - > firstpts | | fabs ( fdelta ) > s - > min_hard_compensation ) {
2012-05-22 19:54:38 +03:00
int ret ;
if ( delta > 0 ) ret = swr_inject_silence ( s , delta / s - > out_sample_rate ) ;
else ret = swr_drop_output ( s , - delta / s - > in_sample_rate ) ;
if ( ret < 0 ) {
av_log ( s , AV_LOG_ERROR , " Failed to compensate for timestamp delta of %f \n " , fdelta ) ;
}
2012-05-19 23:42:32 +03:00
} else if ( s - > soft_compensation_duration & & s - > max_soft_compensation ) {
2012-05-19 19:44:34 +03:00
int duration = s - > out_sample_rate * s - > soft_compensation_duration ;
2012-05-30 04:32:32 +03:00
double max_soft_compensation = s - > max_soft_compensation / ( s - > max_soft_compensation < 0 ? - s - > in_sample_rate : 1 ) ;
int comp = av_clipf ( fdelta , - max_soft_compensation , max_soft_compensation ) * duration ;
2012-05-19 19:44:34 +03:00
av_log ( s , AV_LOG_VERBOSE , " compensating audio timestamp drift:%f compensation:%d in:%d \n " , fdelta , comp , duration ) ;
swr_set_compensation ( s , comp , duration ) ;
}
}
return s - > outpts ;
}
}