Deprecated in c29038f3041a4080342b2e333c1967d136749c0f. The resample filter based upon this library has been removed as well.
Unified · Split
| @@ -23,7 +23,6 @@ FFLIBS-$(CONFIG_AVDEVICE) += avdevice · 22 unmodified lines | |||
| 23 | FFLIBS-$(CONFIG_AVFILTER) += avfilter | 23 | FFLIBS-$(CONFIG_AVFILTER) += avfilter |
| 24 | FFLIBS-$(CONFIG_AVFORMAT) += avformat | 24 | FFLIBS-$(CONFIG_AVFORMAT) += avformat |
| 25 | FFLIBS-$(CONFIG_AVCODEC) += avcodec | 25 | FFLIBS-$(CONFIG_AVCODEC) += avcodec |
| 26 | FFLIBS-$(CONFIG_AVRESAMPLE) += avresample | ||
| 27 | FFLIBS-$(CONFIG_POSTPROC) += postproc | 26 | FFLIBS-$(CONFIG_POSTPROC) += postproc |
| 28 | FFLIBS-$(CONFIG_SWRESAMPLE) += swresample | 27 | FFLIBS-$(CONFIG_SWRESAMPLE) += swresample |
| 29 | FFLIBS-$(CONFIG_SWSCALE) += swscale | 28 | FFLIBS-$(CONFIG_SWSCALE) += swscale |
| @@ -132,7 +132,6 @@ Component options: · 131 unmodified lines | |||
| 132 | --disable-swscale disable libswscale build | 132 | --disable-swscale disable libswscale build |
| 133 | --disable-postproc disable libpostproc build | 133 | --disable-postproc disable libpostproc build |
| 134 | --disable-avfilter disable libavfilter build | 134 | --disable-avfilter disable libavfilter build |
| 135 | --enable-avresample enable libavresample build (deprecated) [no] | ||
| 136 | --disable-pthreads disable pthreads [autodetect] | 135 | --disable-pthreads disable pthreads [autodetect] |
| 137 | --disable-w32threads disable Win32 threads [autodetect] | 136 | --disable-w32threads disable Win32 threads [autodetect] |
| 138 | --disable-os2threads disable OS/2 threads [autodetect] | 137 | --disable-os2threads disable OS/2 threads [autodetect] |
| @@ -1901,7 +1900,6 @@ LIBRARY_LIST=" · 1762 unmodified lines | |||
| 1901 | avformat | 1900 | avformat |
| 1902 | avcodec | 1901 | avcodec |
| 1903 | swresample | 1902 | swresample |
| 1904 | avresample | ||
| 1905 | avutil | 1903 | avutil |
| 1906 | " | 1904 | " |
| 1907 | 1905 | ||
| @@ -3609,7 +3607,6 @@ program_opencl_filter_deps="opencl" · 1701 unmodified lines | |||
| 3609 | pullup_filter_deps="gpl" | 3607 | pullup_filter_deps="gpl" |
| 3610 | removelogo_filter_deps="avcodec avformat swscale" | 3608 | removelogo_filter_deps="avcodec avformat swscale" |
| 3611 | repeatfields_filter_deps="gpl" | 3609 | repeatfields_filter_deps="gpl" |
| 3612 | resample_filter_deps="avresample" | ||
| 3613 | roberts_opencl_filter_deps="opencl" | 3610 | roberts_opencl_filter_deps="opencl" |
| 3614 | rubberband_filter_deps="librubberband" | 3611 | rubberband_filter_deps="librubberband" |
| 3615 | sab_filter_deps="gpl swscale" | 3612 | sab_filter_deps="gpl swscale" |
| @@ -3711,8 +3708,6 @@ avfilter_deps="avutil" · 95 unmodified lines | |||
| 3711 | avfilter_suggest="libm" | 3708 | avfilter_suggest="libm" |
| 3712 | avformat_deps="avcodec avutil" | 3709 | avformat_deps="avcodec avutil" |
| 3713 | avformat_suggest="libm network zlib" | 3710 | avformat_suggest="libm network zlib" |
| 3714 | avresample_deps="avutil" | ||
| 3715 | avresample_suggest="libm" | ||
| 3716 | avutil_suggest="clock_gettime ffnvcodec libm libdrm libmfx opencl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt" | 3711 | avutil_suggest="clock_gettime ffnvcodec libm libdrm libmfx opencl user32 vaapi vulkan videotoolbox corefoundation corevideo coremedia bcrypt" |
| 3717 | postproc_deps="avutil gpl" | 3712 | postproc_deps="avutil gpl" |
| 3718 | postproc_suggest="libm" | 3713 | postproc_suggest="libm" |
| @@ -3795,7 +3790,7 @@ intrinsics="none" · 76 unmodified lines | |||
| 3795 | enable $PROGRAM_LIST | 3790 | enable $PROGRAM_LIST |
| 3796 | enable $DOCUMENT_LIST | 3791 | enable $DOCUMENT_LIST |
| 3797 | enable $EXAMPLE_LIST | 3792 | enable $EXAMPLE_LIST |
| 3798 | enable $(filter_out avresample $LIBRARY_LIST) | 3793 | enable $LIBRARY_LIST |
| 3799 | enable stripping | 3794 | enable stripping |
| 3800 | 3795 | ||
| 3801 | enable asm | 3796 | enable asm |
| @@ -6845,7 +6840,7 @@ EOF · 3043 unmodified lines | |||
| 6845 | 6840 | ||
| 6846 | # add some linker flags | 6841 | # add some linker flags |
| 6847 | check_ldflags -Wl,--warn-common | 6842 | check_ldflags -Wl,--warn-common |
| 6848 | check_ldflags -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample | 6843 | check_ldflags -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil |
| 6849 | enabled rpath && add_ldexeflags -Wl,-rpath,$libdir && add_ldsoflags -Wl,-rpath,$libdir | 6844 | enabled rpath && add_ldexeflags -Wl,-rpath,$libdir && add_ldsoflags -Wl,-rpath,$libdir |
| 6850 | test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic | 6845 | test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic |
| 6851 | 6846 | ||
| @@ -6860,8 +6855,7 @@ enabled neon_clobber_test && · 8 unmodified lines | |||
| 6860 | -Wl,--wrap,avcodec_receive_packet \ | 6855 | -Wl,--wrap,avcodec_receive_packet \ |
| 6861 | -Wl,--wrap,avcodec_send_frame \ | 6856 | -Wl,--wrap,avcodec_send_frame \ |
| 6862 | -Wl,--wrap,avcodec_receive_frame \ | 6857 | -Wl,--wrap,avcodec_receive_frame \ |
| 6863 | -Wl,--wrap,swr_convert \ | 6858 | -Wl,--wrap,swr_convert || |
| 6864 | -Wl,--wrap,avresample_convert || | ||
| 6865 | disable neon_clobber_test | 6859 | disable neon_clobber_test |
| 6866 | 6860 | ||
| 6867 | enabled xmm_clobber_test && | 6861 | enabled xmm_clobber_test && |
| @@ -6873,7 +6867,6 @@ enabled xmm_clobber_test && · 5 unmodified lines | |||
| 6873 | -Wl,--wrap,avcodec_send_frame \ | 6867 | -Wl,--wrap,avcodec_send_frame \ |
| 6874 | -Wl,--wrap,avcodec_receive_frame \ | 6868 | -Wl,--wrap,avcodec_receive_frame \ |
| 6875 | -Wl,--wrap,swr_convert \ | 6869 | -Wl,--wrap,swr_convert \ |
| 6876 | -Wl,--wrap,avresample_convert \ | ||
| 6877 | -Wl,--wrap,sws_scale || | 6870 | -Wl,--wrap,sws_scale || |
| 6878 | disable xmm_clobber_test | 6871 | disable xmm_clobber_test |
| 6879 | 6872 | ||
| @@ -7098,7 +7091,6 @@ check_deps $CONFIG_LIST \ · 218 unmodified lines | |||
| 7098 | $ALL_COMPONENTS \ | 7091 | $ALL_COMPONENTS \ |
| 7099 | 7092 | ||
| 7100 | enabled threads && ! enabled pthreads && ! enabled atomics_native && die "non pthread threading without atomics not supported, try adding --enable-pthreads or --cpu=i486 or higher if you are on x86" | 7093 | enabled threads && ! enabled pthreads && ! enabled atomics_native && die "non pthread threading without atomics not supported, try adding --enable-pthreads or --cpu=i486 or higher if you are on x86" |
| 7101 | enabled avresample && warn "Building with deprecated library libavresample" | ||
| 7102 | 7094 | ||
| 7103 | case $target_os in | 7095 | case $target_os in |
| 7104 | haiku) | 7096 | haiku) |
| @@ -7214,7 +7206,6 @@ enabled movie_filter && prepend avfilter_deps "avformat avcodec" · 109 unmodified lines | |||
| 7214 | enabled pan_filter && prepend avfilter_deps "swresample" | 7206 | enabled pan_filter && prepend avfilter_deps "swresample" |
| 7215 | enabled pp_filter && prepend avfilter_deps "postproc" | 7207 | enabled pp_filter && prepend avfilter_deps "postproc" |
| 7216 | enabled removelogo_filter && prepend avfilter_deps "avformat avcodec swscale" | 7208 | enabled removelogo_filter && prepend avfilter_deps "avformat avcodec swscale" |
| 7217 | enabled resample_filter && prepend avfilter_deps "avresample" | ||
| 7218 | enabled sab_filter && prepend avfilter_deps "swscale" | 7209 | enabled sab_filter && prepend avfilter_deps "swscale" |
| 7219 | enabled scale_filter && prepend avfilter_deps "swscale" | 7210 | enabled scale_filter && prepend avfilter_deps "swscale" |
| 7220 | enabled scale2ref_filter && prepend avfilter_deps "swscale" | 7211 | enabled scale2ref_filter && prepend avfilter_deps "swscale" |
| @@ -7707,7 +7698,6 @@ extralibs_avcodec="$avcodec_extralibs" · 486 unmodified lines | |||
| 7707 | extralibs_avformat="$avformat_extralibs" | 7698 | extralibs_avformat="$avformat_extralibs" |
| 7708 | extralibs_avdevice="$avdevice_extralibs" | 7699 | extralibs_avdevice="$avdevice_extralibs" |
| 7709 | extralibs_avfilter="$avfilter_extralibs" | 7700 | extralibs_avfilter="$avfilter_extralibs" |
| 7710 | extralibs_avresample="$avresample_extralibs" | ||
| 7711 | extralibs_postproc="$postproc_extralibs" | 7701 | extralibs_postproc="$postproc_extralibs" |
| 7712 | extralibs_swscale="$swscale_extralibs" | 7702 | extralibs_swscale="$swscale_extralibs" |
| 7713 | extralibs_swresample="$swresample_extralibs" | 7703 | extralibs_swresample="$swresample_extralibs" |
| @@ -6,7 +6,6 @@ libavcodec: 2017-10-21 · 5 unmodified lines | |||
| 6 | libavdevice: 2017-10-21 | 6 | libavdevice: 2017-10-21 |
| 7 | libavfilter: 2017-10-21 | 7 | libavfilter: 2017-10-21 |
| 8 | libavformat: 2017-10-21 | 8 | libavformat: 2017-10-21 |
| 9 | libavresample: 2017-10-21 | ||
| 10 | libpostproc: 2017-10-21 | 9 | libpostproc: 2017-10-21 |
| 11 | libswresample: 2017-10-21 | 10 | libswresample: 2017-10-21 |
| 12 | libswscale: 2017-10-21 | 11 | libswscale: 2017-10-21 |
| @@ -26,7 +26,7 @@ $(foreach VAR,$(SILENT),$(eval override $(VAR) = @$($(VAR)))) · 25 unmodified lines | |||
| 26 | $(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) | 26 | $(eval INSTALL = @$(call ECHO,INSTALL,$$(^:$(SRC_DIR)/%=%)); $(INSTALL)) |
| 27 | endif | 27 | endif |
| 28 | 28 | ||
| 29 | ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample | 29 | ALLFFLIBS = avcodec avdevice avfilter avformat avutil postproc swscale swresample |
| 30 | 30 | ||
| 31 | # NASM requires -I path terminated with / | 31 | # NASM requires -I path terminated with / |
| 32 | IFLAGS := -I. -I$(SRC_LINK)/ | 32 | IFLAGS := -I. -I$(SRC_LINK)/ |
| @@ -34,7 +34,6 @@ · 33 unmodified lines | |||
| 34 | #include "libavformat/avformat.h" | 34 | #include "libavformat/avformat.h" |
| 35 | #include "libavfilter/avfilter.h" | 35 | #include "libavfilter/avfilter.h" |
| 36 | #include "libavdevice/avdevice.h" | 36 | #include "libavdevice/avdevice.h" |
| 37 | #include "libavresample/avresample.h" | ||
| 38 | #include "libswscale/swscale.h" | 37 | #include "libswscale/swscale.h" |
| 39 | #include "libswresample/swresample.h" | 38 | #include "libswresample/swresample.h" |
| 40 | #include "libpostproc/postprocess.h" | 39 | #include "libpostproc/postprocess.h" |
| @@ -545,9 +544,6 @@ int opt_default(void *optctx, const char *opt, const char *arg) · 504 unmodified lines | |||
| 545 | char opt_stripped[128]; | 544 | char opt_stripped[128]; |
| 546 | const char *p; | 545 | const char *p; |
| 547 | const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class(); | 546 | const AVClass *cc = avcodec_get_class(), *fc = avformat_get_class(); |
| 548 | #if CONFIG_AVRESAMPLE | ||
| 549 | const AVClass *rc = avresample_get_class(); | ||
| 550 | #endif | ||
| 551 | #if CONFIG_SWSCALE | 547 | #if CONFIG_SWSCALE |
| 552 | const AVClass *sc = sws_get_class(); | 548 | const AVClass *sc = sws_get_class(); |
| 553 | #endif | 549 | #endif |
| @@ -617,13 +613,6 @@ int opt_default(void *optctx, const char *opt, const char *arg) · 63 unmodified lines | |||
| 617 | consumed = 1; | 613 | consumed = 1; |
| 618 | } | 614 | } |
| 619 | #endif | 615 | #endif |
| 620 | #if CONFIG_AVRESAMPLE | ||
| 621 | if ((o=opt_find(&rc, opt, NULL, 0, | ||
| 622 | AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) { | ||
| 623 | av_dict_set(&resample_opts, opt, arg, FLAGS); | ||
| 624 | consumed = 1; | ||
| 625 | } | ||
| 626 | #endif | ||
| 627 | 616 | ||
| 628 | if (consumed) | 617 | if (consumed) |
| 629 | return 0; | 618 | return 0; |
| @@ -1134,7 +1123,6 @@ static void print_all_libs_info(int flags, int level) · 504 unmodified lines | |||
| 1134 | PRINT_LIB_INFO(avformat, AVFORMAT, flags, level); | 1123 | PRINT_LIB_INFO(avformat, AVFORMAT, flags, level); |
| 1135 | PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level); | 1124 | PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level); |
| 1136 | PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); | 1125 | PRINT_LIB_INFO(avfilter, AVFILTER, flags, level); |
| 1137 | PRINT_LIB_INFO(avresample, AVRESAMPLE, flags, level); | ||
| 1138 | PRINT_LIB_INFO(swscale, SWSCALE, flags, level); | 1126 | PRINT_LIB_INFO(swscale, SWSCALE, flags, level); |
| 1139 | PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level); | 1127 | PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level); |
| 1140 | PRINT_LIB_INFO(postproc, POSTPROC, flags, level); | 1128 | PRINT_LIB_INFO(postproc, POSTPROC, flags, level); |
| @@ -26,8 +26,6 @@ · 25 unmodified lines | |||
| 26 | #include "libavfilter/buffersink.h" | 26 | #include "libavfilter/buffersink.h" |
| 27 | #include "libavfilter/buffersrc.h" | 27 | #include "libavfilter/buffersrc.h" |
| 28 | 28 | ||
| 29 | #include "libavresample/avresample.h" | ||
| 30 | |||
| 31 | #include "libavutil/avassert.h" | 29 | #include "libavutil/avassert.h" |
| 32 | #include "libavutil/avstring.h" | 30 | #include "libavutil/avstring.h" |
| 33 | #include "libavutil/bprint.h" | 31 | #include "libavutil/bprint.h" |
| @@ -135,7 +135,6 @@ OBJS-$(CONFIG_LV2_FILTER) += af_lv2.o · 134 unmodified lines | |||
| 135 | OBJS-$(CONFIG_MCOMPAND_FILTER) += af_mcompand.o | 135 | OBJS-$(CONFIG_MCOMPAND_FILTER) += af_mcompand.o |
| 136 | OBJS-$(CONFIG_PAN_FILTER) += af_pan.o | 136 | OBJS-$(CONFIG_PAN_FILTER) += af_pan.o |
| 137 | OBJS-$(CONFIG_REPLAYGAIN_FILTER) += af_replaygain.o | 137 | OBJS-$(CONFIG_REPLAYGAIN_FILTER) += af_replaygain.o |
| 138 | OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o | ||
| 139 | OBJS-$(CONFIG_RUBBERBAND_FILTER) += af_rubberband.o | 138 | OBJS-$(CONFIG_RUBBERBAND_FILTER) += af_rubberband.o |
| 140 | OBJS-$(CONFIG_SIDECHAINCOMPRESS_FILTER) += af_sidechaincompress.o | 139 | OBJS-$(CONFIG_SIDECHAINCOMPRESS_FILTER) += af_sidechaincompress.o |
| 141 | OBJS-$(CONFIG_SIDECHAINGATE_FILTER) += af_agate.o | 140 | OBJS-$(CONFIG_SIDECHAINGATE_FILTER) += af_agate.o |
| @@ -1,369 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | /** | ||
| 20 | * @file | ||
| 21 | * sample format and channel layout conversion audio filter | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include "libavutil/avassert.h" | ||
| 25 | #include "libavutil/avstring.h" | ||
| 26 | #include "libavutil/common.h" | ||
| 27 | #include "libavutil/dict.h" | ||
| 28 | #include "libavutil/mathematics.h" | ||
| 29 | #include "libavutil/opt.h" | ||
| 30 | |||
| 31 | #include "libavresample/avresample.h" | ||
| 32 | |||
| 33 | #include "audio.h" | ||
| 34 | #include "avfilter.h" | ||
| 35 | #include "formats.h" | ||
| 36 | #include "internal.h" | ||
| 37 | |||
| 38 | typedef struct ResampleContext { | ||
| 39 | const AVClass *class; | ||
| 40 | AVAudioResampleContext *avr; | ||
| 41 | AVDictionary *options; | ||
| 42 | |||
| 43 | int resampling; | ||
| 44 | int64_t next_pts; | ||
| 45 | int64_t next_in_pts; | ||
| 46 | |||
| 47 | /* set by filter_frame() to signal an output frame to request_frame() */ | ||
| 48 | int got_output; | ||
| 49 | } ResampleContext; | ||
| 50 | |||
| 51 | static av_cold int init(AVFilterContext *ctx, AVDictionary **opts) | ||
| 52 | { | ||
| 53 | ResampleContext *s = ctx->priv; | ||
| 54 | const AVClass *avr_class = avresample_get_class(); | ||
| 55 | AVDictionaryEntry *e = NULL; | ||
| 56 | |||
| 57 | while ((e = av_dict_get(*opts, "", e, AV_DICT_IGNORE_SUFFIX))) { | ||
| 58 | if (av_opt_find(&avr_class, e->key, NULL, 0, | ||
| 59 | AV_OPT_SEARCH_FAKE_OBJ | AV_OPT_SEARCH_CHILDREN)) | ||
| 60 | av_dict_set(&s->options, e->key, e->value, 0); | ||
| 61 | } | ||
| 62 | |||
| 63 | e = NULL; | ||
| 64 | while ((e = av_dict_get(s->options, "", e, AV_DICT_IGNORE_SUFFIX))) | ||
| 65 | av_dict_set(opts, e->key, NULL, 0); | ||
| 66 | |||
| 67 | /* do not allow the user to override basic format options */ | ||
| 68 | av_dict_set(&s->options, "in_channel_layout", NULL, 0); | ||
| 69 | av_dict_set(&s->options, "out_channel_layout", NULL, 0); | ||
| 70 | av_dict_set(&s->options, "in_sample_fmt", NULL, 0); | ||
| 71 | av_dict_set(&s->options, "out_sample_fmt", NULL, 0); | ||
| 72 | av_dict_set(&s->options, "in_sample_rate", NULL, 0); | ||
| 73 | av_dict_set(&s->options, "out_sample_rate", NULL, 0); | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | static av_cold void uninit(AVFilterContext *ctx) | ||
| 79 | { | ||
| 80 | ResampleContext *s = ctx->priv; | ||
| 81 | |||
| 82 | if (s->avr) { | ||
| 83 | avresample_close(s->avr); | ||
| 84 | avresample_free(&s->avr); | ||
| 85 | } | ||
| 86 | av_dict_free(&s->options); | ||
| 87 | } | ||
| 88 | |||
| 89 | static int query_formats(AVFilterContext *ctx) | ||
| 90 | { | ||
| 91 | AVFilterLink *inlink = ctx->inputs[0]; | ||
| 92 | AVFilterLink *outlink = ctx->outputs[0]; | ||
| 93 | AVFilterFormats *in_formats, *out_formats, *in_samplerates, *out_samplerates; | ||
| 94 | AVFilterChannelLayouts *in_layouts, *out_layouts; | ||
| 95 | int ret; | ||
| 96 | |||
| 97 | if (!(in_formats = ff_all_formats (AVMEDIA_TYPE_AUDIO)) || | ||
| 98 | !(out_formats = ff_all_formats (AVMEDIA_TYPE_AUDIO)) || | ||
| 99 | !(in_samplerates = ff_all_samplerates ( )) || | ||
| 100 | !(out_samplerates = ff_all_samplerates ( )) || | ||
| 101 | !(in_layouts = ff_all_channel_layouts ( )) || | ||
| 102 | !(out_layouts = ff_all_channel_layouts ( ))) | ||
| 103 | return AVERROR(ENOMEM); | ||
| 104 | |||
| 105 | if ((ret = ff_formats_ref (in_formats, &inlink->outcfg.formats )) < 0 || | ||
| 106 | (ret = ff_formats_ref (out_formats, &outlink->incfg.formats )) < 0 || | ||
| 107 | (ret = ff_formats_ref (in_samplerates, &inlink->outcfg.samplerates )) < 0 || | ||
| 108 | (ret = ff_formats_ref (out_samplerates, &outlink->incfg.samplerates )) < 0 || | ||
| 109 | (ret = ff_channel_layouts_ref (in_layouts, &inlink->outcfg.channel_layouts)) < 0 || | ||
| 110 | (ret = ff_channel_layouts_ref (out_layouts, &outlink->incfg.channel_layouts)) < 0) | ||
| 111 | return ret; | ||
| 112 | |||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | static int config_output(AVFilterLink *outlink) | ||
| 117 | { | ||
| 118 | AVFilterContext *ctx = outlink->src; | ||
| 119 | AVFilterLink *inlink = ctx->inputs[0]; | ||
| 120 | ResampleContext *s = ctx->priv; | ||
| 121 | char buf1[64], buf2[64]; | ||
| 122 | int ret; | ||
| 123 | |||
| 124 | int64_t resampling_forced; | ||
| 125 | |||
| 126 | if (s->avr) { | ||
| 127 | avresample_close(s->avr); | ||
| 128 | avresample_free(&s->avr); | ||
| 129 | } | ||
| 130 | |||
| 131 | if (inlink->channel_layout == outlink->channel_layout && | ||
| 132 | inlink->sample_rate == outlink->sample_rate && | ||
| 133 | (inlink->format == outlink->format || | ||
| 134 | (av_get_channel_layout_nb_channels(inlink->channel_layout) == 1 && | ||
| 135 | av_get_channel_layout_nb_channels(outlink->channel_layout) == 1 && | ||
| 136 | av_get_planar_sample_fmt(inlink->format) == | ||
| 137 | av_get_planar_sample_fmt(outlink->format)))) | ||
| 138 | return 0; | ||
| 139 | |||
| 140 | if (!(s->avr = avresample_alloc_context())) | ||
| 141 | return AVERROR(ENOMEM); | ||
| 142 | |||
| 143 | if (s->options) { | ||
| 144 | int ret; | ||
| 145 | AVDictionaryEntry *e = NULL; | ||
| 146 | while ((e = av_dict_get(s->options, "", e, AV_DICT_IGNORE_SUFFIX))) | ||
| 147 | av_log(ctx, AV_LOG_VERBOSE, "lavr option: %s=%s\n", e->key, e->value); | ||
| 148 | |||
| 149 | ret = av_opt_set_dict(s->avr, &s->options); | ||
| 150 | if (ret < 0) | ||
| 151 | return ret; | ||
| 152 | } | ||
| 153 | |||
| 154 | av_opt_set_int(s->avr, "in_channel_layout", inlink ->channel_layout, 0); | ||
| 155 | av_opt_set_int(s->avr, "out_channel_layout", outlink->channel_layout, 0); | ||
| 156 | av_opt_set_int(s->avr, "in_sample_fmt", inlink ->format, 0); | ||
| 157 | av_opt_set_int(s->avr, "out_sample_fmt", outlink->format, 0); | ||
| 158 | av_opt_set_int(s->avr, "in_sample_rate", inlink ->sample_rate, 0); | ||
| 159 | av_opt_set_int(s->avr, "out_sample_rate", outlink->sample_rate, 0); | ||
| 160 | |||
| 161 | if ((ret = avresample_open(s->avr)) < 0) | ||
| 162 | return ret; | ||
| 163 | |||
| 164 | av_opt_get_int(s->avr, "force_resampling", 0, &resampling_forced); | ||
| 165 | s->resampling = resampling_forced || (inlink->sample_rate != outlink->sample_rate); | ||
| 166 | |||
| 167 | if (s->resampling) { | ||
| 168 | outlink->time_base = (AVRational){ 1, outlink->sample_rate }; | ||
| 169 | s->next_pts = AV_NOPTS_VALUE; | ||
| 170 | s->next_in_pts = AV_NOPTS_VALUE; | ||
| 171 | } else | ||
| 172 | outlink->time_base = inlink->time_base; | ||
| 173 | |||
| 174 | av_get_channel_layout_string(buf1, sizeof(buf1), | ||
| 175 | -1, inlink ->channel_layout); | ||
| 176 | av_get_channel_layout_string(buf2, sizeof(buf2), | ||
| 177 | -1, outlink->channel_layout); | ||
| 178 | av_log(ctx, AV_LOG_VERBOSE, | ||
| 179 | "fmt:%s srate:%d cl:%s -> fmt:%s srate:%d cl:%s\n", | ||
| 180 | av_get_sample_fmt_name(inlink ->format), inlink ->sample_rate, buf1, | ||
| 181 | av_get_sample_fmt_name(outlink->format), outlink->sample_rate, buf2); | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | static int request_frame(AVFilterLink *outlink) | ||
| 187 | { | ||
| 188 | AVFilterContext *ctx = outlink->src; | ||
| 189 | ResampleContext *s = ctx->priv; | ||
| 190 | int ret = 0; | ||
| 191 | |||
| 192 | s->got_output = 0; | ||
| 193 | while (ret >= 0 && !s->got_output) | ||
| 194 | ret = ff_request_frame(ctx->inputs[0]); | ||
| 195 | |||
| 196 | /* flush the lavr delay buffer */ | ||
| 197 | if (ret == AVERROR_EOF && s->avr) { | ||
| 198 | AVFrame *frame; | ||
| 199 | int nb_samples = avresample_get_out_samples(s->avr, 0); | ||
| 200 | |||
| 201 | if (!nb_samples) | ||
| 202 | return ret; | ||
| 203 | |||
| 204 | frame = ff_get_audio_buffer(outlink, nb_samples); | ||
| 205 | if (!frame) | ||
| 206 | return AVERROR(ENOMEM); | ||
| 207 | |||
| 208 | ret = avresample_convert(s->avr, frame->extended_data, | ||
| 209 | frame->linesize[0], nb_samples, | ||
| 210 | NULL, 0, 0); | ||
| 211 | if (ret <= 0) { | ||
| 212 | av_frame_free(&frame); | ||
| 213 | return (ret == 0) ? AVERROR_EOF : ret; | ||
| 214 | } | ||
| 215 | |||
| 216 | frame->nb_samples = ret; | ||
| 217 | frame->pts = s->next_pts; | ||
| 218 | return ff_filter_frame(outlink, frame); | ||
| 219 | } | ||
| 220 | return ret; | ||
| 221 | } | ||
| 222 | |||
| 223 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) | ||
| 224 | { | ||
| 225 | AVFilterContext *ctx = inlink->dst; | ||
| 226 | ResampleContext *s = ctx->priv; | ||
| 227 | AVFilterLink *outlink = ctx->outputs[0]; | ||
| 228 | int ret; | ||
| 229 | |||
| 230 | if (s->avr) { | ||
| 231 | AVFrame *out; | ||
| 232 | int delay, nb_samples; | ||
| 233 | |||
| 234 | /* maximum possible samples lavr can output */ | ||
| 235 | delay = avresample_get_delay(s->avr); | ||
| 236 | nb_samples = avresample_get_out_samples(s->avr, in->nb_samples); | ||
| 237 | |||
| 238 | out = ff_get_audio_buffer(outlink, nb_samples); | ||
| 239 | if (!out) { | ||
| 240 | ret = AVERROR(ENOMEM); | ||
| 241 | goto fail; | ||
| 242 | } | ||
| 243 | |||
| 244 | ret = avresample_convert(s->avr, out->extended_data, out->linesize[0], | ||
| 245 | nb_samples, in->extended_data, in->linesize[0], | ||
| 246 | in->nb_samples); | ||
| 247 | if (ret <= 0) { | ||
| 248 | av_frame_free(&out); | ||
| 249 | if (ret < 0) | ||
| 250 | goto fail; | ||
| 251 | } | ||
| 252 | |||
| 253 | av_assert0(!avresample_available(s->avr)); | ||
| 254 | |||
| 255 | if (s->resampling && s->next_pts == AV_NOPTS_VALUE) { | ||
| 256 | if (in->pts == AV_NOPTS_VALUE) { | ||
| 257 | av_log(ctx, AV_LOG_WARNING, "First timestamp is missing, " | ||
| 258 | "assuming 0.\n"); | ||
| 259 | s->next_pts = 0; | ||
| 260 | } else | ||
| 261 | s->next_pts = av_rescale_q(in->pts, inlink->time_base, | ||
| 262 | outlink->time_base); | ||
| 263 | } | ||
| 264 | |||
| 265 | if (ret > 0) { | ||
| 266 | out->nb_samples = ret; | ||
| 267 | |||
| 268 | ret = av_frame_copy_props(out, in); | ||
| 269 | if (ret < 0) { | ||
| 270 | av_frame_free(&out); | ||
| 271 | goto fail; | ||
| 272 | } | ||
| 273 | |||
| 274 | if (s->resampling) { | ||
| 275 | out->sample_rate = outlink->sample_rate; | ||
| 276 | /* Only convert in->pts if there is a discontinuous jump. | ||
| 277 | This ensures that out->pts tracks the number of samples actually | ||
| 278 | output by the resampler in the absence of such a jump. | ||
| 279 | Otherwise, the rounding in av_rescale_q() and av_rescale() | ||
| 280 | causes off-by-1 errors. */ | ||
| 281 | if (in->pts != AV_NOPTS_VALUE && in->pts != s->next_in_pts) { | ||
| 282 | out->pts = av_rescale_q(in->pts, inlink->time_base, | ||
| 283 | outlink->time_base) - | ||
| 284 | av_rescale(delay, outlink->sample_rate, | ||
| 285 | inlink->sample_rate); | ||
| 286 | } else | ||
| 287 | out->pts = s->next_pts; | ||
| 288 | |||
| 289 | s->next_pts = out->pts + out->nb_samples; | ||
| 290 | s->next_in_pts = in->pts + in->nb_samples; | ||
| 291 | } else | ||
| 292 | out->pts = in->pts; | ||
| 293 | |||
| 294 | ret = ff_filter_frame(outlink, out); | ||
| 295 | s->got_output = 1; | ||
| 296 | } | ||
| 297 | |||
| 298 | fail: | ||
| 299 | av_frame_free(&in); | ||
| 300 | } else { | ||
| 301 | in->format = outlink->format; | ||
| 302 | ret = ff_filter_frame(outlink, in); | ||
| 303 | s->got_output = 1; | ||
| 304 | } | ||
| 305 | |||
| 306 | return ret; | ||
| 307 | } | ||
| 308 | |||
| 309 | #if FF_API_CHILD_CLASS_NEXT | ||
| 310 | static const AVClass *resample_child_class_next(const AVClass *prev) | ||
| 311 | { | ||
| 312 | return prev ? NULL : avresample_get_class(); | ||
| 313 | } | ||
| 314 | #endif | ||
| 315 | |||
| 316 | static const AVClass *resample_child_class_iterate(void **iter) | ||
| 317 | { | ||
| 318 | const AVClass *c = *iter ? NULL : avresample_get_class(); | ||
| 319 | *iter = (void*)(uintptr_t)c; | ||
| 320 | return c; | ||
| 321 | } | ||
| 322 | |||
| 323 | static void *resample_child_next(void *obj, void *prev) | ||
| 324 | { | ||
| 325 | ResampleContext *s = obj; | ||
| 326 | return prev ? NULL : s->avr; | ||
| 327 | } | ||
| 328 | |||
| 329 | static const AVClass resample_class = { | ||
| 330 | .class_name = "resample", | ||
| 331 | .item_name = av_default_item_name, | ||
| 332 | .version = LIBAVUTIL_VERSION_INT, | ||
| 333 | #if FF_API_CHILD_CLASS_NEXT | ||
| 334 | .child_class_next = resample_child_class_next, | ||
| 335 | #endif | ||
| 336 | .child_class_iterate = resample_child_class_iterate, | ||
| 337 | .child_next = resample_child_next, | ||
| 338 | }; | ||
| 339 | |||
| 340 | static const AVFilterPad avfilter_af_resample_inputs[] = { | ||
| 341 | { | ||
| 342 | .name = "default", | ||
| 343 | .type = AVMEDIA_TYPE_AUDIO, | ||
| 344 | .filter_frame = filter_frame, | ||
| 345 | }, | ||
| 346 | { NULL } | ||
| 347 | }; | ||
| 348 | |||
| 349 | static const AVFilterPad avfilter_af_resample_outputs[] = { | ||
| 350 | { | ||
| 351 | .name = "default", | ||
| 352 | .type = AVMEDIA_TYPE_AUDIO, | ||
| 353 | .config_props = config_output, | ||
| 354 | .request_frame = request_frame | ||
| 355 | }, | ||
| 356 | { NULL } | ||
| 357 | }; | ||
| 358 | |||
| 359 | AVFilter ff_af_resample = { | ||
| 360 | .name = "resample", | ||
| 361 | .description = NULL_IF_CONFIG_SMALL("Audio resampling and conversion."), | ||
| 362 | .priv_size = sizeof(ResampleContext), | ||
| 363 | .priv_class = &resample_class, | ||
| 364 | .init_dict = init, | ||
| 365 | .uninit = uninit, | ||
| 366 | .query_formats = query_formats, | ||
| 367 | .inputs = avfilter_af_resample_inputs, | ||
| 368 | .outputs = avfilter_af_resample_outputs, | ||
| 369 | }; | ||
| @@ -129,7 +129,6 @@ extern AVFilter ff_af_lv2; · 128 unmodified lines | |||
| 129 | extern AVFilter ff_af_mcompand; | 129 | extern AVFilter ff_af_mcompand; |
| 130 | extern AVFilter ff_af_pan; | 130 | extern AVFilter ff_af_pan; |
| 131 | extern AVFilter ff_af_replaygain; | 131 | extern AVFilter ff_af_replaygain; |
| 132 | extern AVFilter ff_af_resample; | ||
| 133 | extern AVFilter ff_af_rubberband; | 132 | extern AVFilter ff_af_rubberband; |
| 134 | extern AVFilter ff_af_sidechaincompress; | 133 | extern AVFilter ff_af_sidechaincompress; |
| 135 | extern AVFilter ff_af_sidechaingate; | 134 | extern AVFilter ff_af_sidechaingate; |
| @@ -1,19 +0,0 @@ | |||
| 1 | NAME = avresample | ||
| 2 | DESC = Libav audio resampling library | ||
| 3 | |||
| 4 | HEADERS = avresample.h \ | ||
| 5 | version.h \ | ||
| 6 | |||
| 7 | OBJS = audio_convert.o \ | ||
| 8 | audio_data.o \ | ||
| 9 | audio_mix.o \ | ||
| 10 | audio_mix_matrix.o \ | ||
| 11 | dither.o \ | ||
| 12 | options.o \ | ||
| 13 | resample.o \ | ||
| 14 | utils.o \ | ||
| 15 | |||
| 16 | # Windows resource file | ||
| 17 | SLIBOBJS-$(HAVE_GNU_WINDRES) += avresampleres.o | ||
| 18 | |||
| 19 | TESTPROGS = avresample | ||
| @@ -1,7 +0,0 @@ | |||
| 1 | OBJS += aarch64/audio_convert_init.o \ | ||
| 2 | aarch64/resample_init.o \ | ||
| 3 | |||
| 4 | OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o | ||
| 5 | |||
| 6 | NEON-OBJS += aarch64/audio_convert_neon.o \ | ||
| 7 | aarch64/resample_neon.o \ | ||
| @@ -1,28 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef AVRESAMPLE_AARCH64_ASM_OFFSETS_H | ||
| 20 | #define AVRESAMPLE_AARCH64_ASM_OFFSETS_H | ||
| 21 | |||
| 22 | /* struct ResampleContext */ | ||
| 23 | #define FILTER_BANK 0x10 | ||
| 24 | #define FILTER_LENGTH 0x18 | ||
| 25 | #define PHASE_SHIFT 0x34 | ||
| 26 | #define PHASE_MASK (PHASE_SHIFT + 0x04) // loaded as pair | ||
| 27 | |||
| 28 | #endif /* AVRESAMPLE_AARCH64_ASM_OFFSETS_H */ | ||
| @@ -1,49 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <stdint.h> | ||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | #include "libavutil/attributes.h" | ||
| 23 | #include "libavutil/cpu.h" | ||
| 24 | #include "libavutil/aarch64/cpu.h" | ||
| 25 | #include "libavutil/samplefmt.h" | ||
| 26 | #include "libavresample/audio_convert.h" | ||
| 27 | |||
| 28 | void ff_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len); | ||
| 29 | void ff_conv_fltp_to_s16_neon(int16_t *dst, float *const *src, | ||
| 30 | int len, int channels); | ||
| 31 | void ff_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, | ||
| 32 | int len, int channels); | ||
| 33 | |||
| 34 | av_cold void ff_audio_convert_init_aarch64(AudioConvert *ac) | ||
| 35 | { | ||
| 36 | int cpu_flags = av_get_cpu_flags(); | ||
| 37 | |||
| 38 | if (have_neon(cpu_flags)) { | ||
| 39 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT, | ||
| 40 | 0, 16, 8, "NEON", | ||
| 41 | ff_conv_flt_to_s16_neon); | ||
| 42 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, | ||
| 43 | 2, 16, 8, "NEON", | ||
| 44 | ff_conv_fltp_to_s16_2ch_neon); | ||
| 45 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, | ||
| 46 | 0, 16, 8, "NEON", | ||
| 47 | ff_conv_fltp_to_s16_neon); | ||
| 48 | } | ||
| 49 | } | ||
| @@ -1,363 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2008 Mans Rullgard <mans@mansr.com> | ||
| 3 | * Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net> | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "config.h" | ||
| 23 | #include "libavutil/aarch64/asm.S" | ||
| 24 | |||
| 25 | function ff_conv_flt_to_s16_neon, export=1 | ||
| 26 | subs x2, x2, #8 | ||
| 27 | ld1 {v0.4s}, [x1], #16 | ||
| 28 | fcvtzs v4.4s, v0.4s, #31 | ||
| 29 | ld1 {v1.4s}, [x1], #16 | ||
| 30 | fcvtzs v5.4s, v1.4s, #31 | ||
| 31 | b.eq 3f | ||
| 32 | ands x12, x2, #~15 | ||
| 33 | b.eq 2f | ||
| 34 | 1: subs x12, x12, #16 | ||
| 35 | sqrshrn v4.4h, v4.4s, #16 | ||
| 36 | ld1 {v2.4s}, [x1], #16 | ||
| 37 | fcvtzs v6.4s, v2.4s, #31 | ||
| 38 | sqrshrn2 v4.8h, v5.4s, #16 | ||
| 39 | ld1 {v3.4s}, [x1], #16 | ||
| 40 | fcvtzs v7.4s, v3.4s, #31 | ||
| 41 | sqrshrn v6.4h, v6.4s, #16 | ||
| 42 | st1 {v4.8h}, [x0], #16 | ||
| 43 | sqrshrn2 v6.8h, v7.4s, #16 | ||
| 44 | ld1 {v0.4s}, [x1], #16 | ||
| 45 | fcvtzs v4.4s, v0.4s, #31 | ||
| 46 | ld1 {v1.4s}, [x1], #16 | ||
| 47 | fcvtzs v5.4s, v1.4s, #31 | ||
| 48 | st1 {v6.8h}, [x0], #16 | ||
| 49 | b.ne 1b | ||
| 50 | ands x2, x2, #15 | ||
| 51 | b.eq 3f | ||
| 52 | 2: ld1 {v2.4s}, [x1], #16 | ||
| 53 | sqrshrn v4.4h, v4.4s, #16 | ||
| 54 | fcvtzs v6.4s, v2.4s, #31 | ||
| 55 | ld1 {v3.4s}, [x1], #16 | ||
| 56 | sqrshrn2 v4.8h, v5.4s, #16 | ||
| 57 | fcvtzs v7.4s, v3.4s, #31 | ||
| 58 | sqrshrn v6.4h, v6.4s, #16 | ||
| 59 | st1 {v4.8h}, [x0], #16 | ||
| 60 | sqrshrn2 v6.8h, v7.4s, #16 | ||
| 61 | st1 {v6.8h}, [x0] | ||
| 62 | ret | ||
| 63 | 3: sqrshrn v4.4h, v4.4s, #16 | ||
| 64 | sqrshrn2 v4.8h, v5.4s, #16 | ||
| 65 | st1 {v4.8h}, [x0] | ||
| 66 | ret | ||
| 67 | endfunc | ||
| 68 | |||
| 69 | function ff_conv_fltp_to_s16_2ch_neon, export=1 | ||
| 70 | ldp x4, x5, [x1] | ||
| 71 | subs x2, x2, #8 | ||
| 72 | ld1 {v0.4s}, [x4], #16 | ||
| 73 | fcvtzs v4.4s, v0.4s, #31 | ||
| 74 | ld1 {v1.4s}, [x4], #16 | ||
| 75 | fcvtzs v5.4s, v1.4s, #31 | ||
| 76 | ld1 {v2.4s}, [x5], #16 | ||
| 77 | fcvtzs v6.4s, v2.4s, #31 | ||
| 78 | ld1 {v3.4s}, [x5], #16 | ||
| 79 | fcvtzs v7.4s, v3.4s, #31 | ||
| 80 | b.eq 3f | ||
| 81 | ands x12, x2, #~15 | ||
| 82 | b.eq 2f | ||
| 83 | 1: subs x12, x12, #16 | ||
| 84 | ld1 {v16.4s}, [x4], #16 | ||
| 85 | fcvtzs v20.4s, v16.4s, #31 | ||
| 86 | sri v6.4s, v4.4s, #16 | ||
| 87 | ld1 {v17.4s}, [x4], #16 | ||
| 88 | fcvtzs v21.4s, v17.4s, #31 | ||
| 89 | ld1 {v18.4s}, [x5], #16 | ||
| 90 | fcvtzs v22.4s, v18.4s, #31 | ||
| 91 | ld1 {v19.4s}, [x5], #16 | ||
| 92 | sri v7.4s, v5.4s, #16 | ||
| 93 | st1 {v6.4s}, [x0], #16 | ||
| 94 | fcvtzs v23.4s, v19.4s, #31 | ||
| 95 | st1 {v7.4s}, [x0], #16 | ||
| 96 | sri v22.4s, v20.4s, #16 | ||
| 97 | ld1 {v0.4s}, [x4], #16 | ||
| 98 | sri v23.4s, v21.4s, #16 | ||
| 99 | st1 {v22.4s}, [x0], #16 | ||
| 100 | fcvtzs v4.4s, v0.4s, #31 | ||
| 101 | ld1 {v1.4s}, [x4], #16 | ||
| 102 | fcvtzs v5.4s, v1.4s, #31 | ||
| 103 | ld1 {v2.4s}, [x5], #16 | ||
| 104 | fcvtzs v6.4s, v2.4s, #31 | ||
| 105 | ld1 {v3.4s}, [x5], #16 | ||
| 106 | fcvtzs v7.4s, v3.4s, #31 | ||
| 107 | st1 {v23.4s}, [x0], #16 | ||
| 108 | b.ne 1b | ||
| 109 | ands x2, x2, #15 | ||
| 110 | b.eq 3f | ||
| 111 | 2: sri v6.4s, v4.4s, #16 | ||
| 112 | ld1 {v0.4s}, [x4], #16 | ||
| 113 | fcvtzs v0.4s, v0.4s, #31 | ||
| 114 | ld1 {v1.4s}, [x4], #16 | ||
| 115 | fcvtzs v1.4s, v1.4s, #31 | ||
| 116 | ld1 {v2.4s}, [x5], #16 | ||
| 117 | fcvtzs v2.4s, v2.4s, #31 | ||
| 118 | sri v7.4s, v5.4s, #16 | ||
| 119 | ld1 {v3.4s}, [x5], #16 | ||
| 120 | fcvtzs v3.4s, v3.4s, #31 | ||
| 121 | sri v2.4s, v0.4s, #16 | ||
| 122 | st1 {v6.4s,v7.4s}, [x0], #32 | ||
| 123 | sri v3.4s, v1.4s, #16 | ||
| 124 | st1 {v2.4s,v3.4s}, [x0], #32 | ||
| 125 | ret | ||
| 126 | 3: sri v6.4s, v4.4s, #16 | ||
| 127 | sri v7.4s, v5.4s, #16 | ||
| 128 | st1 {v6.4s,v7.4s}, [x0] | ||
| 129 | ret | ||
| 130 | endfunc | ||
| 131 | |||
| 132 | function ff_conv_fltp_to_s16_neon, export=1 | ||
| 133 | cmp w3, #2 | ||
| 134 | b.eq X(ff_conv_fltp_to_s16_2ch_neon) | ||
| 135 | b.gt 1f | ||
| 136 | ldr x1, [x1] | ||
| 137 | b X(ff_conv_flt_to_s16_neon) | ||
| 138 | 1: | ||
| 139 | cmp w3, #4 | ||
| 140 | lsl x12, x3, #1 | ||
| 141 | b.lt 4f | ||
| 142 | |||
| 143 | 5: // 4 channels | ||
| 144 | ldp x4, x5, [x1], #16 | ||
| 145 | ldp x6, x7, [x1], #16 | ||
| 146 | mov w9, w2 | ||
| 147 | mov x8, x0 | ||
| 148 | ld1 {v4.4s}, [x4], #16 | ||
| 149 | fcvtzs v4.4s, v4.4s, #31 | ||
| 150 | ld1 {v5.4s}, [x5], #16 | ||
| 151 | fcvtzs v5.4s, v5.4s, #31 | ||
| 152 | ld1 {v6.4s}, [x6], #16 | ||
| 153 | fcvtzs v6.4s, v6.4s, #31 | ||
| 154 | ld1 {v7.4s}, [x7], #16 | ||
| 155 | fcvtzs v7.4s, v7.4s, #31 | ||
| 156 | 6: | ||
| 157 | subs w9, w9, #8 | ||
| 158 | ld1 {v0.4s}, [x4], #16 | ||
| 159 | fcvtzs v0.4s, v0.4s, #31 | ||
| 160 | sri v5.4s, v4.4s, #16 | ||
| 161 | ld1 {v1.4s}, [x5], #16 | ||
| 162 | fcvtzs v1.4s, v1.4s, #31 | ||
| 163 | sri v7.4s, v6.4s, #16 | ||
| 164 | ld1 {v2.4s}, [x6], #16 | ||
| 165 | fcvtzs v2.4s, v2.4s, #31 | ||
| 166 | zip1 v16.4s, v5.4s, v7.4s | ||
| 167 | ld1 {v3.4s}, [x7], #16 | ||
| 168 | fcvtzs v3.4s, v3.4s, #31 | ||
| 169 | zip2 v17.4s, v5.4s, v7.4s | ||
| 170 | st1 {v16.d}[0], [x8], x12 | ||
| 171 | sri v1.4s, v0.4s, #16 | ||
| 172 | st1 {v16.d}[1], [x8], x12 | ||
| 173 | sri v3.4s, v2.4s, #16 | ||
| 174 | st1 {v17.d}[0], [x8], x12 | ||
| 175 | zip1 v18.4s, v1.4s, v3.4s | ||
| 176 | st1 {v17.d}[1], [x8], x12 | ||
| 177 | zip2 v19.4s, v1.4s, v3.4s | ||
| 178 | b.eq 7f | ||
| 179 | ld1 {v4.4s}, [x4], #16 | ||
| 180 | fcvtzs v4.4s, v4.4s, #31 | ||
| 181 | st1 {v18.d}[0], [x8], x12 | ||
| 182 | ld1 {v5.4s}, [x5], #16 | ||
| 183 | fcvtzs v5.4s, v5.4s, #31 | ||
| 184 | st1 {v18.d}[1], [x8], x12 | ||
| 185 | ld1 {v6.4s}, [x6], #16 | ||
| 186 | fcvtzs v6.4s, v6.4s, #31 | ||
| 187 | st1 {v19.d}[0], [x8], x12 | ||
| 188 | ld1 {v7.4s}, [x7], #16 | ||
| 189 | fcvtzs v7.4s, v7.4s, #31 | ||
| 190 | st1 {v19.d}[1], [x8], x12 | ||
| 191 | b 6b | ||
| 192 | 7: | ||
| 193 | st1 {v18.d}[0], [x8], x12 | ||
| 194 | st1 {v18.d}[1], [x8], x12 | ||
| 195 | st1 {v19.d}[0], [x8], x12 | ||
| 196 | st1 {v19.d}[1], [x8], x12 | ||
| 197 | subs w3, w3, #4 | ||
| 198 | b.eq end | ||
| 199 | cmp w3, #4 | ||
| 200 | add x0, x0, #8 | ||
| 201 | b.ge 5b | ||
| 202 | |||
| 203 | 4: // 2 channels | ||
| 204 | cmp w3, #2 | ||
| 205 | b.lt 4f | ||
| 206 | ldp x4, x5, [x1], #16 | ||
| 207 | mov w9, w2 | ||
| 208 | mov x8, x0 | ||
| 209 | tst w9, #8 | ||
| 210 | ld1 {v4.4s}, [x4], #16 | ||
| 211 | fcvtzs v4.4s, v4.4s, #31 | ||
| 212 | ld1 {v5.4s}, [x5], #16 | ||
| 213 | fcvtzs v5.4s, v5.4s, #31 | ||
| 214 | ld1 {v6.4s}, [x4], #16 | ||
| 215 | fcvtzs v6.4s, v6.4s, #31 | ||
| 216 | ld1 {v7.4s}, [x5], #16 | ||
| 217 | fcvtzs v7.4s, v7.4s, #31 | ||
| 218 | b.eq 6f | ||
| 219 | subs w9, w9, #8 | ||
| 220 | b.eq 7f | ||
| 221 | sri v5.4s, v4.4s, #16 | ||
| 222 | ld1 {v4.4s}, [x4], #16 | ||
| 223 | fcvtzs v4.4s, v4.4s, #31 | ||
| 224 | st1 {v5.s}[0], [x8], x12 | ||
| 225 | sri v7.4s, v6.4s, #16 | ||
| 226 | st1 {v5.s}[1], [x8], x12 | ||
| 227 | ld1 {v6.4s}, [x4], #16 | ||
| 228 | fcvtzs v6.4s, v6.4s, #31 | ||
| 229 | st1 {v5.s}[2], [x8], x12 | ||
| 230 | st1 {v5.s}[3], [x8], x12 | ||
| 231 | st1 {v7.s}[0], [x8], x12 | ||
| 232 | st1 {v7.s}[1], [x8], x12 | ||
| 233 | ld1 {v5.4s}, [x5], #16 | ||
| 234 | fcvtzs v5.4s, v5.4s, #31 | ||
| 235 | st1 {v7.s}[2], [x8], x12 | ||
| 236 | st1 {v7.s}[3], [x8], x12 | ||
| 237 | ld1 {v7.4s}, [x5], #16 | ||
| 238 | fcvtzs v7.4s, v7.4s, #31 | ||
| 239 | 6: | ||
| 240 | subs w9, w9, #16 | ||
| 241 | ld1 {v0.4s}, [x4], #16 | ||
| 242 | sri v5.4s, v4.4s, #16 | ||
| 243 | fcvtzs v0.4s, v0.4s, #31 | ||
| 244 | ld1 {v1.4s}, [x5], #16 | ||
| 245 | sri v7.4s, v6.4s, #16 | ||
| 246 | st1 {v5.s}[0], [x8], x12 | ||
| 247 | st1 {v5.s}[1], [x8], x12 | ||
| 248 | fcvtzs v1.4s, v1.4s, #31 | ||
| 249 | st1 {v5.s}[2], [x8], x12 | ||
| 250 | st1 {v5.s}[3], [x8], x12 | ||
| 251 | ld1 {v2.4s}, [x4], #16 | ||
| 252 | st1 {v7.s}[0], [x8], x12 | ||
| 253 | fcvtzs v2.4s, v2.4s, #31 | ||
| 254 | st1 {v7.s}[1], [x8], x12 | ||
| 255 | ld1 {v3.4s}, [x5], #16 | ||
| 256 | st1 {v7.s}[2], [x8], x12 | ||
| 257 | fcvtzs v3.4s, v3.4s, #31 | ||
| 258 | st1 {v7.s}[3], [x8], x12 | ||
| 259 | sri v1.4s, v0.4s, #16 | ||
| 260 | sri v3.4s, v2.4s, #16 | ||
| 261 | b.eq 6f | ||
| 262 | ld1 {v4.4s}, [x4], #16 | ||
| 263 | st1 {v1.s}[0], [x8], x12 | ||
| 264 | fcvtzs v4.4s, v4.4s, #31 | ||
| 265 | st1 {v1.s}[1], [x8], x12 | ||
| 266 | ld1 {v5.4s}, [x5], #16 | ||
| 267 | st1 {v1.s}[2], [x8], x12 | ||
| 268 | fcvtzs v5.4s, v5.4s, #31 | ||
| 269 | st1 {v1.s}[3], [x8], x12 | ||
| 270 | ld1 {v6.4s}, [x4], #16 | ||
| 271 | st1 {v3.s}[0], [x8], x12 | ||
| 272 | fcvtzs v6.4s, v6.4s, #31 | ||
| 273 | st1 {v3.s}[1], [x8], x12 | ||
| 274 | ld1 {v7.4s}, [x5], #16 | ||
| 275 | st1 {v3.s}[2], [x8], x12 | ||
| 276 | fcvtzs v7.4s, v7.4s, #31 | ||
| 277 | st1 {v3.s}[3], [x8], x12 | ||
| 278 | b.gt 6b | ||
| 279 | 6: | ||
| 280 | st1 {v1.s}[0], [x8], x12 | ||
| 281 | st1 {v1.s}[1], [x8], x12 | ||
| 282 | st1 {v1.s}[2], [x8], x12 | ||
| 283 | st1 {v1.s}[3], [x8], x12 | ||
| 284 | st1 {v3.s}[0], [x8], x12 | ||
| 285 | st1 {v3.s}[1], [x8], x12 | ||
| 286 | st1 {v3.s}[2], [x8], x12 | ||
| 287 | st1 {v3.s}[3], [x8], x12 | ||
| 288 | b 8f | ||
| 289 | 7: | ||
| 290 | sri v5.4s, v4.4s, #16 | ||
| 291 | sri v7.4s, v6.4s, #16 | ||
| 292 | st1 {v5.s}[0], [x8], x12 | ||
| 293 | st1 {v5.s}[1], [x8], x12 | ||
| 294 | st1 {v5.s}[2], [x8], x12 | ||
| 295 | st1 {v5.s}[3], [x8], x12 | ||
| 296 | st1 {v7.s}[0], [x8], x12 | ||
| 297 | st1 {v7.s}[1], [x8], x12 | ||
| 298 | st1 {v7.s}[2], [x8], x12 | ||
| 299 | st1 {v7.s}[3], [x8], x12 | ||
| 300 | 8: | ||
| 301 | subs w3, w3, #2 | ||
| 302 | add x0, x0, #4 | ||
| 303 | b.eq end | ||
| 304 | |||
| 305 | 4: // 1 channel | ||
| 306 | ldr x4, [x1] | ||
| 307 | tst w2, #8 | ||
| 308 | mov w9, w2 | ||
| 309 | mov x5, x0 | ||
| 310 | ld1 {v0.4s}, [x4], #16 | ||
| 311 | fcvtzs v0.4s, v0.4s, #31 | ||
| 312 | ld1 {v1.4s}, [x4], #16 | ||
| 313 | fcvtzs v1.4s, v1.4s, #31 | ||
| 314 | b.ne 8f | ||
| 315 | 6: | ||
| 316 | subs w9, w9, #16 | ||
| 317 | ld1 {v2.4s}, [x4], #16 | ||
| 318 | fcvtzs v2.4s, v2.4s, #31 | ||
| 319 | ld1 {v3.4s}, [x4], #16 | ||
| 320 | fcvtzs v3.4s, v3.4s, #31 | ||
| 321 | st1 {v0.h}[1], [x5], x12 | ||
| 322 | st1 {v0.h}[3], [x5], x12 | ||
| 323 | st1 {v0.h}[5], [x5], x12 | ||
| 324 | st1 {v0.h}[7], [x5], x12 | ||
| 325 | st1 {v1.h}[1], [x5], x12 | ||
| 326 | st1 {v1.h}[3], [x5], x12 | ||
| 327 | st1 {v1.h}[5], [x5], x12 | ||
| 328 | st1 {v1.h}[7], [x5], x12 | ||
| 329 | b.eq 7f | ||
| 330 | ld1 {v0.4s}, [x4], #16 | ||
| 331 | fcvtzs v0.4s, v0.4s, #31 | ||
| 332 | ld1 {v1.4s}, [x4], #16 | ||
| 333 | fcvtzs v1.4s, v1.4s, #31 | ||
| 334 | 7: | ||
| 335 | st1 {v2.h}[1], [x5], x12 | ||
| 336 | st1 {v2.h}[3], [x5], x12 | ||
| 337 | st1 {v2.h}[5], [x5], x12 | ||
| 338 | st1 {v2.h}[7], [x5], x12 | ||
| 339 | st1 {v3.h}[1], [x5], x12 | ||
| 340 | st1 {v3.h}[3], [x5], x12 | ||
| 341 | st1 {v3.h}[5], [x5], x12 | ||
| 342 | st1 {v3.h}[7], [x5], x12 | ||
| 343 | b.gt 6b | ||
| 344 | ret | ||
| 345 | 8: | ||
| 346 | subs w9, w9, #8 | ||
| 347 | st1 {v0.h}[1], [x5], x12 | ||
| 348 | st1 {v0.h}[3], [x5], x12 | ||
| 349 | st1 {v0.h}[5], [x5], x12 | ||
| 350 | st1 {v0.h}[7], [x5], x12 | ||
| 351 | st1 {v1.h}[1], [x5], x12 | ||
| 352 | st1 {v1.h}[3], [x5], x12 | ||
| 353 | st1 {v1.h}[5], [x5], x12 | ||
| 354 | st1 {v1.h}[7], [x5], x12 | ||
| 355 | b.eq end | ||
| 356 | ld1 {v0.4s}, [x4], #16 | ||
| 357 | fcvtzs v0.4s, v0.4s, #31 | ||
| 358 | ld1 {v1.4s}, [x4], #16 | ||
| 359 | fcvtzs v1.4s, v1.4s, #31 | ||
| 360 | b 6b | ||
| 361 | end: | ||
| 362 | ret | ||
| 363 | endfunc | ||
| @@ -1,31 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * check NEON registers for clobbers | ||
| 3 | * Copyright (c) 2013 Martin Storsjo | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "libavresample/avresample.h" | ||
| 23 | #include "libavutil/aarch64/neontest.h" | ||
| 24 | |||
| 25 | wrap(avresample_convert(AVAudioResampleContext *avr, uint8_t **output, | ||
| 26 | int out_plane_size, int out_samples, uint8_t **input, | ||
| 27 | int in_plane_size, int in_samples)) | ||
| 28 | { | ||
| 29 | testneonclobbers(avresample_convert, avr, output, out_plane_size, | ||
| 30 | out_samples, input, in_plane_size, in_samples); | ||
| 31 | } | ||
| @@ -1,71 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <stdint.h> | ||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | #include "libavutil/cpu.h" | ||
| 23 | #include "libavutil/aarch64/cpu.h" | ||
| 24 | #include "libavutil/internal.h" | ||
| 25 | #include "libavutil/samplefmt.h" | ||
| 26 | #include "libavresample/resample.h" | ||
| 27 | |||
| 28 | #include "asm-offsets.h" | ||
| 29 | |||
| 30 | AV_CHECK_OFFSET(struct ResampleContext, filter_bank, FILTER_BANK); | ||
| 31 | AV_CHECK_OFFSET(struct ResampleContext, filter_length, FILTER_LENGTH); | ||
| 32 | AV_CHECK_OFFSET(struct ResampleContext, phase_shift, PHASE_SHIFT); | ||
| 33 | AV_CHECK_OFFSET(struct ResampleContext, phase_mask, PHASE_MASK); | ||
| 34 | |||
| 35 | void ff_resample_one_dbl_neon(struct ResampleContext *c, void *dst0, | ||
| 36 | int dst_index, const void *src0, | ||
| 37 | unsigned int index, int frac); | ||
| 38 | void ff_resample_one_flt_neon(struct ResampleContext *c, void *dst0, | ||
| 39 | int dst_index, const void *src0, | ||
| 40 | unsigned int index, int frac); | ||
| 41 | void ff_resample_one_s16_neon(struct ResampleContext *c, void *dst0, | ||
| 42 | int dst_index, const void *src0, | ||
| 43 | unsigned int index, int frac); | ||
| 44 | void ff_resample_one_s32_neon(struct ResampleContext *c, void *dst0, | ||
| 45 | int dst_index, const void *src0, | ||
| 46 | unsigned int index, int frac); | ||
| 47 | |||
| 48 | av_cold void ff_audio_resample_init_aarch64(ResampleContext *c, | ||
| 49 | enum AVSampleFormat sample_fmt) | ||
| 50 | { | ||
| 51 | int cpu_flags = av_get_cpu_flags(); | ||
| 52 | |||
| 53 | if (have_neon(cpu_flags)) { | ||
| 54 | if (!c->linear) { | ||
| 55 | switch (sample_fmt) { | ||
| 56 | case AV_SAMPLE_FMT_DBLP: | ||
| 57 | c->resample_one = ff_resample_one_dbl_neon; | ||
| 58 | break; | ||
| 59 | case AV_SAMPLE_FMT_FLTP: | ||
| 60 | c->resample_one = ff_resample_one_flt_neon; | ||
| 61 | break; | ||
| 62 | case AV_SAMPLE_FMT_S16P: | ||
| 63 | c->resample_one = ff_resample_one_s16_neon; | ||
| 64 | break; | ||
| 65 | case AV_SAMPLE_FMT_S32P: | ||
| 66 | c->resample_one = ff_resample_one_s32_neon; | ||
| 67 | break; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| @@ -1,233 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Janne Grunau <janne-libav@jannau.net> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "libavutil/aarch64/asm.S" | ||
| 22 | #include "asm-offsets.h" | ||
| 23 | |||
| 24 | .macro resample_one fmt, es=2 | ||
| 25 | .ifnc \fmt, dbl | ||
| 26 | .macro M_MUL2 x:vararg | ||
| 27 | .endm | ||
| 28 | .macro M_MLA2 x:vararg | ||
| 29 | .endm | ||
| 30 | .endif | ||
| 31 | function ff_resample_one_\fmt\()_neon, export=1 | ||
| 32 | sxtw x2, w2 | ||
| 33 | ldr x9, [x0, #FILTER_BANK] | ||
| 34 | ldr w6, [x0, #FILTER_LENGTH] | ||
| 35 | ldp w7, w8, [x0, #PHASE_SHIFT] // and phase_mask | ||
| 36 | lsr x10, x4, x7 // sample_index | ||
| 37 | and x4, x4, x8 | ||
| 38 | lsl x11, x6, #\es // filter_length * elem_size | ||
| 39 | add x3, x3, x10, lsl #\es // src[sample_index] | ||
| 40 | madd x9, x11, x4, x9 // filter | ||
| 41 | cmp w6, #16 | ||
| 42 | b.lt 5f | ||
| 43 | 8: // remaining filter_length at least 16 | ||
| 44 | subs w6, w6, #16 | ||
| 45 | LOAD8 v4, v5, v6, v7, x3 | ||
| 46 | LOAD8 v16, v17, v18, v19, x9 | ||
| 47 | M_MUL v0, v4, v16, v1 | ||
| 48 | M_MUL2 v1, v6, v18 | ||
| 49 | 7: | ||
| 50 | LOAD8 v20, v21, v22, v23, x3 | ||
| 51 | M_MLA v0, v5, v17, v1 | ||
| 52 | M_MLA2 v1, v7, v19 | ||
| 53 | LOAD8 v24, v25, v26, v27, x9 | ||
| 54 | M_MLA v0, v20, v24, v1 | ||
| 55 | M_MLA2 v1, v22, v26 | ||
| 56 | b.eq 6f | ||
| 57 | cmp w6, #16 | ||
| 58 | M_MLA v0, v21, v25, v1 | ||
| 59 | M_MLA2 v1, v23, v27 | ||
| 60 | b.lt 4f | ||
| 61 | subs w6, w6, #16 | ||
| 62 | LOAD8 v4, v5, v6, v7, x3 | ||
| 63 | LOAD8 v16, v17, v18, v19, x9 | ||
| 64 | M_MLA v0, v4, v16, v1 | ||
| 65 | M_MLA2 v1, v6, v18 | ||
| 66 | b 7b | ||
| 67 | 6: | ||
| 68 | M_MLA v0, v21, v25, v1 | ||
| 69 | M_MLA2 v1, v23, v27 | ||
| 70 | STORE_ONE 0, x1, x2, v1 | ||
| 71 | ret | ||
| 72 | 5: | ||
| 73 | movi v0.16b, #0 | ||
| 74 | movi v1.16b, #0 | ||
| 75 | 4: // remaining filter_length 1-15 | ||
| 76 | cmp w6, #4 | ||
| 77 | b.lt 2f | ||
| 78 | subs w6, w6, #4 | ||
| 79 | LOAD4 v4, v5, x3 | ||
| 80 | LOAD4 v6, v7, x9 | ||
| 81 | M_MLA v0, v4, v6, v1 | ||
| 82 | M_MLA2 v1, v5, v7 | ||
| 83 | b.eq 0f | ||
| 84 | b 4b | ||
| 85 | 2: // remaining filter_length 1-3 | ||
| 86 | cmp w6, #2 | ||
| 87 | b.lt 1f | ||
| 88 | LOAD2 2, x3 | ||
| 89 | LOAD2 3, x9 | ||
| 90 | subs w6, w6, #2 | ||
| 91 | M_MLA v0, v2, v3 | ||
| 92 | b.eq 0f | ||
| 93 | 1: // remaining filter_length 1 | ||
| 94 | LOAD1 6, x3 | ||
| 95 | LOAD1 7, x9 | ||
| 96 | M_MLA v0, v6, v7 | ||
| 97 | 0: | ||
| 98 | STORE_ONE 0, x1, x2, v1 | ||
| 99 | ret | ||
| 100 | endfunc | ||
| 101 | |||
| 102 | .purgem LOAD1 | ||
| 103 | .purgem LOAD2 | ||
| 104 | .purgem LOAD4 | ||
| 105 | .purgem LOAD8 | ||
| 106 | .purgem M_MLA | ||
| 107 | .purgem M_MLA2 | ||
| 108 | .purgem M_MUL | ||
| 109 | .purgem M_MUL2 | ||
| 110 | .purgem STORE_ONE | ||
| 111 | .endm | ||
| 112 | |||
| 113 | |||
| 114 | .macro LOAD1 d1, addr | ||
| 115 | ldr d\d1, [\addr], #8 | ||
| 116 | .endm | ||
| 117 | .macro LOAD2 d1, addr | ||
| 118 | ld1 {v\d1\().2d}, [\addr], #16 | ||
| 119 | .endm | ||
| 120 | .macro LOAD4 d1, d2, addr | ||
| 121 | ld1 {\d1\().2d,\d2\().2d}, [\addr], #32 | ||
| 122 | .endm | ||
| 123 | .macro LOAD8 d1, d2, d3, d4, addr | ||
| 124 | ld1 {\d1\().2d,\d2\().2d,\d3\().2d,\d4\().2d}, [\addr], #64 | ||
| 125 | .endm | ||
| 126 | .macro M_MLA d, r0, r1, d2:vararg | ||
| 127 | fmla \d\().2d, \r0\().2d, \r1\().2d | ||
| 128 | .endm | ||
| 129 | .macro M_MLA2 second:vararg | ||
| 130 | M_MLA \second | ||
| 131 | .endm | ||
| 132 | .macro M_MUL d, r0, r1, d2:vararg | ||
| 133 | fmul \d\().2d, \r0\().2d, \r1\().2d | ||
| 134 | .endm | ||
| 135 | .macro M_MUL2 second:vararg | ||
| 136 | M_MUL \second | ||
| 137 | .endm | ||
| 138 | .macro STORE_ONE rn, addr, idx, d2 | ||
| 139 | fadd v\rn\().2d, v\rn\().2d, \d2\().2d | ||
| 140 | faddp d\rn\(), v\rn\().2d | ||
| 141 | str d\rn\(), [\addr, \idx, lsl #3] | ||
| 142 | .endm | ||
| 143 | |||
| 144 | resample_one dbl, 3 | ||
| 145 | |||
| 146 | |||
| 147 | .macro LOAD1 d1, addr | ||
| 148 | ldr s\d1, [\addr], #4 | ||
| 149 | .endm | ||
| 150 | .macro LOAD2 d1, addr | ||
| 151 | ld1 {v\d1\().2s}, [\addr], #8 | ||
| 152 | .endm | ||
| 153 | .macro LOAD4 d1, d2, addr | ||
| 154 | ld1 {\d1\().4s}, [\addr], #16 | ||
| 155 | .endm | ||
| 156 | .macro LOAD8 d1, d2, d3, d4, addr | ||
| 157 | ld1 {\d1\().4s,\d2\().4s}, [\addr], #32 | ||
| 158 | .endm | ||
| 159 | .macro M_MLA d, r0, r1, d2:vararg | ||
| 160 | fmla \d\().4s, \r0\().4s, \r1\().4s | ||
| 161 | .endm | ||
| 162 | .macro M_MUL d, r0, r1, d2:vararg | ||
| 163 | fmul \d\().4s, \r0\().4s, \r1\().4s | ||
| 164 | .endm | ||
| 165 | .macro STORE_ONE rn, addr, idx, d2 | ||
| 166 | faddp v\rn\().4s, v\rn\().4s, v\rn\().4s | ||
| 167 | faddp s\rn\(), v\rn\().2s | ||
| 168 | str s\rn\(), [\addr, \idx, lsl #2] | ||
| 169 | .endm | ||
| 170 | |||
| 171 | resample_one flt | ||
| 172 | |||
| 173 | |||
| 174 | .macro LOAD1 d1, addr | ||
| 175 | ldr h\d1, [\addr], #2 | ||
| 176 | .endm | ||
| 177 | .macro LOAD2 d1, addr | ||
| 178 | ldr s\d1, [\addr], #4 | ||
| 179 | .endm | ||
| 180 | .macro LOAD4 d1, d2, addr | ||
| 181 | ld1 {\d1\().4h}, [\addr], #8 | ||
| 182 | .endm | ||
| 183 | .macro LOAD8 d1, d2, d3, d4, addr | ||
| 184 | ld1 {\d1\().4h,\d2\().4h}, [\addr], #16 | ||
| 185 | .endm | ||
| 186 | .macro M_MLA d, r0, r1, d2:vararg | ||
| 187 | smlal \d\().4s, \r0\().4h, \r1\().4h | ||
| 188 | .endm | ||
| 189 | .macro M_MUL d, r0, r1, d2:vararg | ||
| 190 | smull \d\().4s, \r0\().4h, \r1\().4h | ||
| 191 | .endm | ||
| 192 | .macro STORE_ONE rn, addr, idx, d2 | ||
| 193 | addp v\rn\().4s, v\rn\().4s, v\rn\().4s | ||
| 194 | addp v\rn\().4s, v\rn\().4s, v\rn\().4s | ||
| 195 | sqrshrn v\rn\().4h, v\rn\().4s, #15 | ||
| 196 | str h\rn\(), [\addr, \idx, lsl #1] | ||
| 197 | .endm | ||
| 198 | |||
| 199 | resample_one s16, 1 | ||
| 200 | |||
| 201 | |||
| 202 | .macro LOAD1 d1, addr | ||
| 203 | ldr s\d1, [\addr], #4 | ||
| 204 | .endm | ||
| 205 | .macro LOAD2 d1, addr | ||
| 206 | ld1 {v\d1\().2s}, [\addr], #8 | ||
| 207 | .endm | ||
| 208 | .macro LOAD4 d1, d2, addr | ||
| 209 | ld1 {\d1\().4s}, [\addr], #16 | ||
| 210 | .endm | ||
| 211 | .macro LOAD8 d1, d2, d3, d4, addr | ||
| 212 | ld1 {\d1\().4s,\d2\().4s}, [\addr], #32 | ||
| 213 | .endm | ||
| 214 | .macro M_MLA d1, r0, r1, d2:vararg | ||
| 215 | smlal \d1\().2d, \r0\().2s, \r1\().2s | ||
| 216 | .ifnb \d2 | ||
| 217 | smlal2 \d2\().2d, \r0\().4s, \r1\().4s | ||
| 218 | .endif | ||
| 219 | .endm | ||
| 220 | .macro M_MUL d1, r0, r1, d2:vararg | ||
| 221 | smull \d1\().2d, \r0\().2s, \r1\().2s | ||
| 222 | .ifnb \d2 | ||
| 223 | smull2 \d2\().2d, \r0\().4s, \r1\().4s | ||
| 224 | .endif | ||
| 225 | .endm | ||
| 226 | .macro STORE_ONE rn, addr, idx, d2 | ||
| 227 | add v\rn\().2d, v\rn\().2d, \d2\().2d | ||
| 228 | addp d\rn\(), v\rn\().2d | ||
| 229 | sqrshrn v\rn\().2s, v\rn\().2d, #30 | ||
| 230 | str s\rn\(), [\addr, \idx, lsl #2] | ||
| 231 | .endm | ||
| 232 | |||
| 233 | resample_one s32 | ||
| @@ -1,7 +0,0 @@ | |||
| 1 | OBJS += arm/audio_convert_init.o \ | ||
| 2 | arm/resample_init.o | ||
| 3 | |||
| 4 | OBJS-$(CONFIG_NEON_CLOBBER_TEST) += arm/neontest.o | ||
| 5 | |||
| 6 | NEON-OBJS += arm/audio_convert_neon.o \ | ||
| 7 | arm/resample_neon.o | ||
| @@ -1,29 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef AVRESAMPLE_ARM_ASM_OFFSETS_H | ||
| 20 | #define AVRESAMPLE_ARM_ASM_OFFSETS_H | ||
| 21 | |||
| 22 | /* struct ResampleContext */ | ||
| 23 | #define FILTER_BANK 0x08 | ||
| 24 | #define FILTER_LENGTH 0x0c | ||
| 25 | #define SRC_INCR 0x20 | ||
| 26 | #define PHASE_SHIFT 0x28 | ||
| 27 | #define PHASE_MASK (PHASE_SHIFT + 0x04) | ||
| 28 | |||
| 29 | #endif /* AVRESAMPLE_ARM_ASM_OFFSETS_H */ | ||
| @@ -1,49 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <stdint.h> | ||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | #include "libavutil/attributes.h" | ||
| 23 | #include "libavutil/cpu.h" | ||
| 24 | #include "libavutil/arm/cpu.h" | ||
| 25 | #include "libavutil/samplefmt.h" | ||
| 26 | #include "libavresample/audio_convert.h" | ||
| 27 | |||
| 28 | void ff_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len); | ||
| 29 | void ff_conv_fltp_to_s16_neon(int16_t *dst, float *const *src, | ||
| 30 | int len, int channels); | ||
| 31 | void ff_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, | ||
| 32 | int len, int channels); | ||
| 33 | |||
| 34 | av_cold void ff_audio_convert_init_arm(AudioConvert *ac) | ||
| 35 | { | ||
| 36 | int cpu_flags = av_get_cpu_flags(); | ||
| 37 | |||
| 38 | if (have_neon(cpu_flags)) { | ||
| 39 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT, | ||
| 40 | 0, 16, 8, "NEON", | ||
| 41 | ff_conv_flt_to_s16_neon); | ||
| 42 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, | ||
| 43 | 0, 16, 8, "NEON", | ||
| 44 | ff_conv_fltp_to_s16_neon); | ||
| 45 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, | ||
| 46 | 2, 16, 8, "NEON", | ||
| 47 | ff_conv_fltp_to_s16_2ch_neon); | ||
| 48 | } | ||
| 49 | } | ||
| @@ -1,363 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2008 Mans Rullgard <mans@mansr.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | #include "libavutil/arm/asm.S" | ||
| 23 | |||
| 24 | function ff_conv_flt_to_s16_neon, export=1 | ||
| 25 | subs r2, r2, #8 | ||
| 26 | vld1.32 {q0}, [r1,:128]! | ||
| 27 | vcvt.s32.f32 q8, q0, #31 | ||
| 28 | vld1.32 {q1}, [r1,:128]! | ||
| 29 | vcvt.s32.f32 q9, q1, #31 | ||
| 30 | beq 3f | ||
| 31 | bics r12, r2, #15 | ||
| 32 | beq 2f | ||
| 33 | 1: subs r12, r12, #16 | ||
| 34 | vqrshrn.s32 d4, q8, #16 | ||
| 35 | vld1.32 {q0}, [r1,:128]! | ||
| 36 | vcvt.s32.f32 q0, q0, #31 | ||
| 37 | vqrshrn.s32 d5, q9, #16 | ||
| 38 | vld1.32 {q1}, [r1,:128]! | ||
| 39 | vcvt.s32.f32 q1, q1, #31 | ||
| 40 | vqrshrn.s32 d6, q0, #16 | ||
| 41 | vst1.16 {q2}, [r0,:128]! | ||
| 42 | vqrshrn.s32 d7, q1, #16 | ||
| 43 | vld1.32 {q8}, [r1,:128]! | ||
| 44 | vcvt.s32.f32 q8, q8, #31 | ||
| 45 | vld1.32 {q9}, [r1,:128]! | ||
| 46 | vcvt.s32.f32 q9, q9, #31 | ||
| 47 | vst1.16 {q3}, [r0,:128]! | ||
| 48 | bne 1b | ||
| 49 | ands r2, r2, #15 | ||
| 50 | beq 3f | ||
| 51 | 2: vld1.32 {q0}, [r1,:128]! | ||
| 52 | vqrshrn.s32 d4, q8, #16 | ||
| 53 | vcvt.s32.f32 q0, q0, #31 | ||
| 54 | vld1.32 {q1}, [r1,:128]! | ||
| 55 | vqrshrn.s32 d5, q9, #16 | ||
| 56 | vcvt.s32.f32 q1, q1, #31 | ||
| 57 | vqrshrn.s32 d6, q0, #16 | ||
| 58 | vst1.16 {q2}, [r0,:128]! | ||
| 59 | vqrshrn.s32 d7, q1, #16 | ||
| 60 | vst1.16 {q3}, [r0,:128]! | ||
| 61 | bx lr | ||
| 62 | 3: vqrshrn.s32 d4, q8, #16 | ||
| 63 | vqrshrn.s32 d5, q9, #16 | ||
| 64 | vst1.16 {q2}, [r0,:128]! | ||
| 65 | bx lr | ||
| 66 | endfunc | ||
| 67 | |||
| 68 | function ff_conv_fltp_to_s16_2ch_neon, export=1 | ||
| 69 | ldm r1, {r1, r3} | ||
| 70 | subs r2, r2, #8 | ||
| 71 | vld1.32 {q0}, [r1,:128]! | ||
| 72 | vcvt.s32.f32 q8, q0, #31 | ||
| 73 | vld1.32 {q1}, [r1,:128]! | ||
| 74 | vcvt.s32.f32 q9, q1, #31 | ||
| 75 | vld1.32 {q10}, [r3,:128]! | ||
| 76 | vcvt.s32.f32 q10, q10, #31 | ||
| 77 | vld1.32 {q11}, [r3,:128]! | ||
| 78 | vcvt.s32.f32 q11, q11, #31 | ||
| 79 | beq 3f | ||
| 80 | bics r12, r2, #15 | ||
| 81 | beq 2f | ||
| 82 | 1: subs r12, r12, #16 | ||
| 83 | vld1.32 {q0}, [r1,:128]! | ||
| 84 | vcvt.s32.f32 q0, q0, #31 | ||
| 85 | vsri.32 q10, q8, #16 | ||
| 86 | vld1.32 {q1}, [r1,:128]! | ||
| 87 | vcvt.s32.f32 q1, q1, #31 | ||
| 88 | vld1.32 {q12}, [r3,:128]! | ||
| 89 | vcvt.s32.f32 q12, q12, #31 | ||
| 90 | vld1.32 {q13}, [r3,:128]! | ||
| 91 | vsri.32 q11, q9, #16 | ||
| 92 | vst1.16 {q10}, [r0,:128]! | ||
| 93 | vcvt.s32.f32 q13, q13, #31 | ||
| 94 | vst1.16 {q11}, [r0,:128]! | ||
| 95 | vsri.32 q12, q0, #16 | ||
| 96 | vld1.32 {q8}, [r1,:128]! | ||
| 97 | vsri.32 q13, q1, #16 | ||
| 98 | vst1.16 {q12}, [r0,:128]! | ||
| 99 | vcvt.s32.f32 q8, q8, #31 | ||
| 100 | vld1.32 {q9}, [r1,:128]! | ||
| 101 | vcvt.s32.f32 q9, q9, #31 | ||
| 102 | vld1.32 {q10}, [r3,:128]! | ||
| 103 | vcvt.s32.f32 q10, q10, #31 | ||
| 104 | vld1.32 {q11}, [r3,:128]! | ||
| 105 | vcvt.s32.f32 q11, q11, #31 | ||
| 106 | vst1.16 {q13}, [r0,:128]! | ||
| 107 | bne 1b | ||
| 108 | ands r2, r2, #15 | ||
| 109 | beq 3f | ||
| 110 | 2: vsri.32 q10, q8, #16 | ||
| 111 | vld1.32 {q0}, [r1,:128]! | ||
| 112 | vcvt.s32.f32 q0, q0, #31 | ||
| 113 | vld1.32 {q1}, [r1,:128]! | ||
| 114 | vcvt.s32.f32 q1, q1, #31 | ||
| 115 | vld1.32 {q12}, [r3,:128]! | ||
| 116 | vcvt.s32.f32 q12, q12, #31 | ||
| 117 | vsri.32 q11, q9, #16 | ||
| 118 | vld1.32 {q13}, [r3,:128]! | ||
| 119 | vcvt.s32.f32 q13, q13, #31 | ||
| 120 | vst1.16 {q10}, [r0,:128]! | ||
| 121 | vsri.32 q12, q0, #16 | ||
| 122 | vst1.16 {q11}, [r0,:128]! | ||
| 123 | vsri.32 q13, q1, #16 | ||
| 124 | vst1.16 {q12-q13},[r0,:128]! | ||
| 125 | bx lr | ||
| 126 | 3: vsri.32 q10, q8, #16 | ||
| 127 | vsri.32 q11, q9, #16 | ||
| 128 | vst1.16 {q10-q11},[r0,:128]! | ||
| 129 | bx lr | ||
| 130 | endfunc | ||
| 131 | |||
| 132 | function ff_conv_fltp_to_s16_neon, export=1 | ||
| 133 | cmp r3, #2 | ||
| 134 | itt lt | ||
| 135 | ldrlt r1, [r1] | ||
| 136 | blt X(ff_conv_flt_to_s16_neon) | ||
| 137 | beq X(ff_conv_fltp_to_s16_2ch_neon) | ||
| 138 | |||
| 139 | push {r4-r8, lr} | ||
| 140 | cmp r3, #4 | ||
| 141 | lsl r12, r3, #1 | ||
| 142 | blt 4f | ||
| 143 | |||
| 144 | @ 4 channels | ||
| 145 | 5: ldm r1!, {r4-r7} | ||
| 146 | mov lr, r2 | ||
| 147 | mov r8, r0 | ||
| 148 | vld1.32 {q8}, [r4,:128]! | ||
| 149 | vcvt.s32.f32 q8, q8, #31 | ||
| 150 | vld1.32 {q9}, [r5,:128]! | ||
| 151 | vcvt.s32.f32 q9, q9, #31 | ||
| 152 | vld1.32 {q10}, [r6,:128]! | ||
| 153 | vcvt.s32.f32 q10, q10, #31 | ||
| 154 | vld1.32 {q11}, [r7,:128]! | ||
| 155 | vcvt.s32.f32 q11, q11, #31 | ||
| 156 | 6: subs lr, lr, #8 | ||
| 157 | vld1.32 {q0}, [r4,:128]! | ||
| 158 | vcvt.s32.f32 q0, q0, #31 | ||
| 159 | vsri.32 q9, q8, #16 | ||
| 160 | vld1.32 {q1}, [r5,:128]! | ||
| 161 | vcvt.s32.f32 q1, q1, #31 | ||
| 162 | vsri.32 q11, q10, #16 | ||
| 163 | vld1.32 {q2}, [r6,:128]! | ||
| 164 | vcvt.s32.f32 q2, q2, #31 | ||
| 165 | vzip.32 d18, d22 | ||
| 166 | vld1.32 {q3}, [r7,:128]! | ||
| 167 | vcvt.s32.f32 q3, q3, #31 | ||
| 168 | vzip.32 d19, d23 | ||
| 169 | vst1.16 {d18}, [r8], r12 | ||
| 170 | vsri.32 q1, q0, #16 | ||
| 171 | vst1.16 {d22}, [r8], r12 | ||
| 172 | vsri.32 q3, q2, #16 | ||
| 173 | vst1.16 {d19}, [r8], r12 | ||
| 174 | vzip.32 d2, d6 | ||
| 175 | vst1.16 {d23}, [r8], r12 | ||
| 176 | vzip.32 d3, d7 | ||
| 177 | beq 7f | ||
| 178 | vld1.32 {q8}, [r4,:128]! | ||
| 179 | vcvt.s32.f32 q8, q8, #31 | ||
| 180 | vst1.16 {d2}, [r8], r12 | ||
| 181 | vld1.32 {q9}, [r5,:128]! | ||
| 182 | vcvt.s32.f32 q9, q9, #31 | ||
| 183 | vst1.16 {d6}, [r8], r12 | ||
| 184 | vld1.32 {q10}, [r6,:128]! | ||
| 185 | vcvt.s32.f32 q10, q10, #31 | ||
| 186 | vst1.16 {d3}, [r8], r12 | ||
| 187 | vld1.32 {q11}, [r7,:128]! | ||
| 188 | vcvt.s32.f32 q11, q11, #31 | ||
| 189 | vst1.16 {d7}, [r8], r12 | ||
| 190 | b 6b | ||
| 191 | 7: vst1.16 {d2}, [r8], r12 | ||
| 192 | vst1.16 {d6}, [r8], r12 | ||
| 193 | vst1.16 {d3}, [r8], r12 | ||
| 194 | vst1.16 {d7}, [r8], r12 | ||
| 195 | subs r3, r3, #4 | ||
| 196 | it eq | ||
| 197 | popeq {r4-r8, pc} | ||
| 198 | cmp r3, #4 | ||
| 199 | add r0, r0, #8 | ||
| 200 | bge 5b | ||
| 201 | |||
| 202 | @ 2 channels | ||
| 203 | 4: cmp r3, #2 | ||
| 204 | blt 4f | ||
| 205 | ldm r1!, {r4-r5} | ||
| 206 | mov lr, r2 | ||
| 207 | mov r8, r0 | ||
| 208 | tst lr, #8 | ||
| 209 | vld1.32 {q8}, [r4,:128]! | ||
| 210 | vcvt.s32.f32 q8, q8, #31 | ||
| 211 | vld1.32 {q9}, [r5,:128]! | ||
| 212 | vcvt.s32.f32 q9, q9, #31 | ||
| 213 | vld1.32 {q10}, [r4,:128]! | ||
| 214 | vcvt.s32.f32 q10, q10, #31 | ||
| 215 | vld1.32 {q11}, [r5,:128]! | ||
| 216 | vcvt.s32.f32 q11, q11, #31 | ||
| 217 | beq 6f | ||
| 218 | subs lr, lr, #8 | ||
| 219 | beq 7f | ||
| 220 | vsri.32 d18, d16, #16 | ||
| 221 | vsri.32 d19, d17, #16 | ||
| 222 | vld1.32 {q8}, [r4,:128]! | ||
| 223 | vcvt.s32.f32 q8, q8, #31 | ||
| 224 | vst1.32 {d18[0]}, [r8], r12 | ||
| 225 | vsri.32 d22, d20, #16 | ||
| 226 | vst1.32 {d18[1]}, [r8], r12 | ||
| 227 | vsri.32 d23, d21, #16 | ||
| 228 | vst1.32 {d19[0]}, [r8], r12 | ||
| 229 | vst1.32 {d19[1]}, [r8], r12 | ||
| 230 | vld1.32 {q9}, [r5,:128]! | ||
| 231 | vcvt.s32.f32 q9, q9, #31 | ||
| 232 | vst1.32 {d22[0]}, [r8], r12 | ||
| 233 | vst1.32 {d22[1]}, [r8], r12 | ||
| 234 | vld1.32 {q10}, [r4,:128]! | ||
| 235 | vcvt.s32.f32 q10, q10, #31 | ||
| 236 | vst1.32 {d23[0]}, [r8], r12 | ||
| 237 | vst1.32 {d23[1]}, [r8], r12 | ||
| 238 | vld1.32 {q11}, [r5,:128]! | ||
| 239 | vcvt.s32.f32 q11, q11, #31 | ||
| 240 | 6: subs lr, lr, #16 | ||
| 241 | vld1.32 {q0}, [r4,:128]! | ||
| 242 | vcvt.s32.f32 q0, q0, #31 | ||
| 243 | vsri.32 d18, d16, #16 | ||
| 244 | vld1.32 {q1}, [r5,:128]! | ||
| 245 | vcvt.s32.f32 q1, q1, #31 | ||
| 246 | vsri.32 d19, d17, #16 | ||
| 247 | vld1.32 {q2}, [r4,:128]! | ||
| 248 | vcvt.s32.f32 q2, q2, #31 | ||
| 249 | vld1.32 {q3}, [r5,:128]! | ||
| 250 | vcvt.s32.f32 q3, q3, #31 | ||
| 251 | vst1.32 {d18[0]}, [r8], r12 | ||
| 252 | vsri.32 d22, d20, #16 | ||
| 253 | vst1.32 {d18[1]}, [r8], r12 | ||
| 254 | vsri.32 d23, d21, #16 | ||
| 255 | vst1.32 {d19[0]}, [r8], r12 | ||
| 256 | vsri.32 d2, d0, #16 | ||
| 257 | vst1.32 {d19[1]}, [r8], r12 | ||
| 258 | vsri.32 d3, d1, #16 | ||
| 259 | vst1.32 {d22[0]}, [r8], r12 | ||
| 260 | vsri.32 d6, d4, #16 | ||
| 261 | vst1.32 {d22[1]}, [r8], r12 | ||
| 262 | vsri.32 d7, d5, #16 | ||
| 263 | vst1.32 {d23[0]}, [r8], r12 | ||
| 264 | vst1.32 {d23[1]}, [r8], r12 | ||
| 265 | beq 6f | ||
| 266 | vld1.32 {q8}, [r4,:128]! | ||
| 267 | vcvt.s32.f32 q8, q8, #31 | ||
| 268 | vst1.32 {d2[0]}, [r8], r12 | ||
| 269 | vst1.32 {d2[1]}, [r8], r12 | ||
| 270 | vld1.32 {q9}, [r5,:128]! | ||
| 271 | vcvt.s32.f32 q9, q9, #31 | ||
| 272 | vst1.32 {d3[0]}, [r8], r12 | ||
| 273 | vst1.32 {d3[1]}, [r8], r12 | ||
| 274 | vld1.32 {q10}, [r4,:128]! | ||
| 275 | vcvt.s32.f32 q10, q10, #31 | ||
| 276 | vst1.32 {d6[0]}, [r8], r12 | ||
| 277 | vst1.32 {d6[1]}, [r8], r12 | ||
| 278 | vld1.32 {q11}, [r5,:128]! | ||
| 279 | vcvt.s32.f32 q11, q11, #31 | ||
| 280 | vst1.32 {d7[0]}, [r8], r12 | ||
| 281 | vst1.32 {d7[1]}, [r8], r12 | ||
| 282 | bgt 6b | ||
| 283 | 6: vst1.32 {d2[0]}, [r8], r12 | ||
| 284 | vst1.32 {d2[1]}, [r8], r12 | ||
| 285 | vst1.32 {d3[0]}, [r8], r12 | ||
| 286 | vst1.32 {d3[1]}, [r8], r12 | ||
| 287 | vst1.32 {d6[0]}, [r8], r12 | ||
| 288 | vst1.32 {d6[1]}, [r8], r12 | ||
| 289 | vst1.32 {d7[0]}, [r8], r12 | ||
| 290 | vst1.32 {d7[1]}, [r8], r12 | ||
| 291 | b 8f | ||
| 292 | 7: vsri.32 d18, d16, #16 | ||
| 293 | vsri.32 d19, d17, #16 | ||
| 294 | vst1.32 {d18[0]}, [r8], r12 | ||
| 295 | vsri.32 d22, d20, #16 | ||
| 296 | vst1.32 {d18[1]}, [r8], r12 | ||
| 297 | vsri.32 d23, d21, #16 | ||
| 298 | vst1.32 {d19[0]}, [r8], r12 | ||
| 299 | vst1.32 {d19[1]}, [r8], r12 | ||
| 300 | vst1.32 {d22[0]}, [r8], r12 | ||
| 301 | vst1.32 {d22[1]}, [r8], r12 | ||
| 302 | vst1.32 {d23[0]}, [r8], r12 | ||
| 303 | vst1.32 {d23[1]}, [r8], r12 | ||
| 304 | 8: subs r3, r3, #2 | ||
| 305 | add r0, r0, #4 | ||
| 306 | it eq | ||
| 307 | popeq {r4-r8, pc} | ||
| 308 | |||
| 309 | @ 1 channel | ||
| 310 | 4: ldr r4, [r1] | ||
| 311 | tst r2, #8 | ||
| 312 | mov lr, r2 | ||
| 313 | mov r5, r0 | ||
| 314 | vld1.32 {q0}, [r4,:128]! | ||
| 315 | vcvt.s32.f32 q0, q0, #31 | ||
| 316 | vld1.32 {q1}, [r4,:128]! | ||
| 317 | vcvt.s32.f32 q1, q1, #31 | ||
| 318 | bne 8f | ||
| 319 | 6: subs lr, lr, #16 | ||
| 320 | vld1.32 {q2}, [r4,:128]! | ||
| 321 | vcvt.s32.f32 q2, q2, #31 | ||
| 322 | vld1.32 {q3}, [r4,:128]! | ||
| 323 | vcvt.s32.f32 q3, q3, #31 | ||
| 324 | vst1.16 {d0[1]}, [r5,:16], r12 | ||
| 325 | vst1.16 {d0[3]}, [r5,:16], r12 | ||
| 326 | vst1.16 {d1[1]}, [r5,:16], r12 | ||
| 327 | vst1.16 {d1[3]}, [r5,:16], r12 | ||
| 328 | vst1.16 {d2[1]}, [r5,:16], r12 | ||
| 329 | vst1.16 {d2[3]}, [r5,:16], r12 | ||
| 330 | vst1.16 {d3[1]}, [r5,:16], r12 | ||
| 331 | vst1.16 {d3[3]}, [r5,:16], r12 | ||
| 332 | beq 7f | ||
| 333 | vld1.32 {q0}, [r4,:128]! | ||
| 334 | vcvt.s32.f32 q0, q0, #31 | ||
| 335 | vld1.32 {q1}, [r4,:128]! | ||
| 336 | vcvt.s32.f32 q1, q1, #31 | ||
| 337 | 7: vst1.16 {d4[1]}, [r5,:16], r12 | ||
| 338 | vst1.16 {d4[3]}, [r5,:16], r12 | ||
| 339 | vst1.16 {d5[1]}, [r5,:16], r12 | ||
| 340 | vst1.16 {d5[3]}, [r5,:16], r12 | ||
| 341 | vst1.16 {d6[1]}, [r5,:16], r12 | ||
| 342 | vst1.16 {d6[3]}, [r5,:16], r12 | ||
| 343 | vst1.16 {d7[1]}, [r5,:16], r12 | ||
| 344 | vst1.16 {d7[3]}, [r5,:16], r12 | ||
| 345 | bgt 6b | ||
| 346 | pop {r4-r8, pc} | ||
| 347 | 8: subs lr, lr, #8 | ||
| 348 | vst1.16 {d0[1]}, [r5,:16], r12 | ||
| 349 | vst1.16 {d0[3]}, [r5,:16], r12 | ||
| 350 | vst1.16 {d1[1]}, [r5,:16], r12 | ||
| 351 | vst1.16 {d1[3]}, [r5,:16], r12 | ||
| 352 | vst1.16 {d2[1]}, [r5,:16], r12 | ||
| 353 | vst1.16 {d2[3]}, [r5,:16], r12 | ||
| 354 | vst1.16 {d3[1]}, [r5,:16], r12 | ||
| 355 | vst1.16 {d3[3]}, [r5,:16], r12 | ||
| 356 | it eq | ||
| 357 | popeq {r4-r8, pc} | ||
| 358 | vld1.32 {q0}, [r4,:128]! | ||
| 359 | vcvt.s32.f32 q0, q0, #31 | ||
| 360 | vld1.32 {q1}, [r4,:128]! | ||
| 361 | vcvt.s32.f32 q1, q1, #31 | ||
| 362 | b 6b | ||
| 363 | endfunc | ||
| @@ -1,31 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * check NEON registers for clobbers | ||
| 3 | * Copyright (c) 2013 Martin Storsjo | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "libavresample/avresample.h" | ||
| 23 | #include "libavutil/arm/neontest.h" | ||
| 24 | |||
| 25 | wrap(avresample_convert(AVAudioResampleContext *avr, uint8_t **output, | ||
| 26 | int out_plane_size, int out_samples, uint8_t **input, | ||
| 27 | int in_plane_size, int in_samples)) | ||
| 28 | { | ||
| 29 | testneonclobbers(avresample_convert, avr, output, out_plane_size, | ||
| 30 | out_samples, input, in_plane_size, in_samples); | ||
| 31 | } | ||
| @@ -1,74 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | |||
| 23 | #include "libavutil/cpu.h" | ||
| 24 | #include "libavutil/arm/cpu.h" | ||
| 25 | #include "libavutil/internal.h" | ||
| 26 | #include "libavutil/samplefmt.h" | ||
| 27 | |||
| 28 | #include "libavresample/resample.h" | ||
| 29 | |||
| 30 | #include "asm-offsets.h" | ||
| 31 | |||
| 32 | AV_CHECK_OFFSET(struct ResampleContext, filter_bank, FILTER_BANK); | ||
| 33 | AV_CHECK_OFFSET(struct ResampleContext, filter_length, FILTER_LENGTH); | ||
| 34 | AV_CHECK_OFFSET(struct ResampleContext, src_incr, SRC_INCR); | ||
| 35 | AV_CHECK_OFFSET(struct ResampleContext, phase_shift, PHASE_SHIFT); | ||
| 36 | AV_CHECK_OFFSET(struct ResampleContext, phase_mask, PHASE_MASK); | ||
| 37 | |||
| 38 | void ff_resample_one_flt_neon(struct ResampleContext *c, void *dst0, | ||
| 39 | int dst_index, const void *src0, | ||
| 40 | unsigned int index, int frac); | ||
| 41 | void ff_resample_one_s16_neon(struct ResampleContext *c, void *dst0, | ||
| 42 | int dst_index, const void *src0, | ||
| 43 | unsigned int index, int frac); | ||
| 44 | void ff_resample_one_s32_neon(struct ResampleContext *c, void *dst0, | ||
| 45 | int dst_index, const void *src0, | ||
| 46 | unsigned int index, int frac); | ||
| 47 | |||
| 48 | void ff_resample_linear_flt_neon(struct ResampleContext *c, void *dst0, | ||
| 49 | int dst_index, const void *src0, | ||
| 50 | unsigned int index, int frac); | ||
| 51 | |||
| 52 | av_cold void ff_audio_resample_init_arm(ResampleContext *c, | ||
| 53 | enum AVSampleFormat sample_fmt) | ||
| 54 | { | ||
| 55 | int cpu_flags = av_get_cpu_flags(); | ||
| 56 | if (have_neon(cpu_flags)) { | ||
| 57 | switch (sample_fmt) { | ||
| 58 | case AV_SAMPLE_FMT_FLTP: | ||
| 59 | if (c->linear) | ||
| 60 | c->resample_one = ff_resample_linear_flt_neon; | ||
| 61 | else | ||
| 62 | c->resample_one = ff_resample_one_flt_neon; | ||
| 63 | break; | ||
| 64 | case AV_SAMPLE_FMT_S16P: | ||
| 65 | if (!c->linear) | ||
| 66 | c->resample_one = ff_resample_one_s16_neon; | ||
| 67 | break; | ||
| 68 | case AV_SAMPLE_FMT_S32P: | ||
| 69 | if (!c->linear) | ||
| 70 | c->resample_one = ff_resample_one_s32_neon; | ||
| 71 | break; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| @@ -1,358 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "libavutil/arm/asm.S" | ||
| 22 | |||
| 23 | #include "asm-offsets.h" | ||
| 24 | |||
| 25 | .macro resample_one fmt, es=2 | ||
| 26 | function ff_resample_one_\fmt\()_neon, export=1 | ||
| 27 | push {r4, r5} | ||
| 28 | add r1, r1, r2, lsl #\es | ||
| 29 | |||
| 30 | ldr r2, [r0, #PHASE_SHIFT+4] /* phase_mask */ | ||
| 31 | ldr ip, [sp, #8] /* index */ | ||
| 32 | ldr r5, [r0, #FILTER_LENGTH] | ||
| 33 | and r2, ip, r2 /* (index & phase_mask) */ | ||
| 34 | ldr r4, [r0, #PHASE_SHIFT] | ||
| 35 | lsr r4, ip, r4 /* compute sample_index */ | ||
| 36 | mul r2, r2, r5 | ||
| 37 | |||
| 38 | ldr ip, [r0, #FILTER_BANK] | ||
| 39 | add r3, r3, r4, lsl #\es /* &src[sample_index] */ | ||
| 40 | |||
| 41 | cmp r5, #8 | ||
| 42 | add r0, ip, r2, lsl #\es /* filter = &filter_bank[...] */ | ||
| 43 | |||
| 44 | blt 5f | ||
| 45 | 8: | ||
| 46 | subs r5, r5, #8 | ||
| 47 | LOAD4 | ||
| 48 | MUL4 | ||
| 49 | 7: | ||
| 50 | LOAD4 | ||
| 51 | beq 6f | ||
| 52 | cmp r5, #8 | ||
| 53 | MLA4 | ||
| 54 | blt 4f | ||
| 55 | subs r5, r5, #8 | ||
| 56 | LOAD4 | ||
| 57 | MLA4 | ||
| 58 | b 7b | ||
| 59 | 6: | ||
| 60 | MLA4 | ||
| 61 | STORE | ||
| 62 | pop {r4, r5} | ||
| 63 | bx lr | ||
| 64 | 5: | ||
| 65 | INIT4 | ||
| 66 | 4: /* remaining filter_length 1 to 7 */ | ||
| 67 | cmp r5, #4 | ||
| 68 | blt 2f | ||
| 69 | subs r5, r5, #4 | ||
| 70 | LOAD4 | ||
| 71 | MLA4 | ||
| 72 | beq 0f | ||
| 73 | 2: /* remaining filter_length 1 to 3 */ | ||
| 74 | cmp r5, #2 | ||
| 75 | blt 1f | ||
| 76 | subs r5, r5, #2 | ||
| 77 | LOAD2 | ||
| 78 | MLA2 | ||
| 79 | beq 0f | ||
| 80 | 1: /* remaining filter_length 1 */ | ||
| 81 | LOAD1 | ||
| 82 | MLA1 | ||
| 83 | 0: | ||
| 84 | STORE | ||
| 85 | pop {r4, r5} | ||
| 86 | bx lr | ||
| 87 | endfunc | ||
| 88 | |||
| 89 | .purgem LOAD1 | ||
| 90 | .purgem LOAD2 | ||
| 91 | .purgem LOAD4 | ||
| 92 | .purgem MLA1 | ||
| 93 | .purgem MLA2 | ||
| 94 | .purgem MLA4 | ||
| 95 | .purgem MUL4 | ||
| 96 | .purgem INIT4 | ||
| 97 | .purgem STORE | ||
| 98 | .endm | ||
| 99 | |||
| 100 | |||
| 101 | /* float32 */ | ||
| 102 | .macro LOAD1 | ||
| 103 | veor.32 d0, d0 | ||
| 104 | vld1.32 {d0[0]}, [r0]! /* load filter */ | ||
| 105 | vld1.32 {d4[0]}, [r3]! /* load src */ | ||
| 106 | .endm | ||
| 107 | .macro LOAD2 | ||
| 108 | vld1.32 {d0}, [r0]! /* load filter */ | ||
| 109 | vld1.32 {d4}, [r3]! /* load src */ | ||
| 110 | .endm | ||
| 111 | .macro LOAD4 | ||
| 112 | vld1.32 {d0,d1}, [r0]! /* load filter */ | ||
| 113 | vld1.32 {d4,d5}, [r3]! /* load src */ | ||
| 114 | .endm | ||
| 115 | .macro MLA1 | ||
| 116 | vmla.f32 d16, d0, d4[0] | ||
| 117 | .endm | ||
| 118 | .macro MLA2 | ||
| 119 | vmla.f32 d16, d0, d4 | ||
| 120 | .endm | ||
| 121 | .macro MLA4 | ||
| 122 | vmla.f32 d16, d0, d4 | ||
| 123 | vmla.f32 d17, d1, d5 | ||
| 124 | .endm | ||
| 125 | .macro MUL4 | ||
| 126 | vmul.f32 d16, d0, d4 | ||
| 127 | vmul.f32 d17, d1, d5 | ||
| 128 | .endm | ||
| 129 | .macro INIT4 | ||
| 130 | veor.f32 q8, q8 | ||
| 131 | .endm | ||
| 132 | .macro STORE | ||
| 133 | vpadd.f32 d16, d16, d17 | ||
| 134 | vpadd.f32 d16, d16, d16 | ||
| 135 | vst1.32 d16[0], [r1] | ||
| 136 | .endm | ||
| 137 | |||
| 138 | resample_one flt, 2 | ||
| 139 | |||
| 140 | |||
| 141 | /* s32 */ | ||
| 142 | .macro LOAD1 | ||
| 143 | veor.32 d0, d0 | ||
| 144 | vld1.32 {d0[0]}, [r0]! /* load filter */ | ||
| 145 | vld1.32 {d4[0]}, [r3]! /* load src */ | ||
| 146 | .endm | ||
| 147 | .macro LOAD2 | ||
| 148 | vld1.32 {d0}, [r0]! /* load filter */ | ||
| 149 | vld1.32 {d4}, [r3]! /* load src */ | ||
| 150 | .endm | ||
| 151 | .macro LOAD4 | ||
| 152 | vld1.32 {d0,d1}, [r0]! /* load filter */ | ||
| 153 | vld1.32 {d4,d5}, [r3]! /* load src */ | ||
| 154 | .endm | ||
| 155 | .macro MLA1 | ||
| 156 | vmlal.s32 q8, d0, d4[0] | ||
| 157 | .endm | ||
| 158 | .macro MLA2 | ||
| 159 | vmlal.s32 q8, d0, d4 | ||
| 160 | .endm | ||
| 161 | .macro MLA4 | ||
| 162 | vmlal.s32 q8, d0, d4 | ||
| 163 | vmlal.s32 q9, d1, d5 | ||
| 164 | .endm | ||
| 165 | .macro MUL4 | ||
| 166 | vmull.s32 q8, d0, d4 | ||
| 167 | vmull.s32 q9, d1, d5 | ||
| 168 | .endm | ||
| 169 | .macro INIT4 | ||
| 170 | veor.s64 q8, q8 | ||
| 171 | veor.s64 q9, q9 | ||
| 172 | .endm | ||
| 173 | .macro STORE | ||
| 174 | vadd.s64 q8, q8, q9 | ||
| 175 | vadd.s64 d16, d16, d17 | ||
| 176 | vqrshrn.s64 d16, q8, #30 | ||
| 177 | vst1.32 d16[0], [r1] | ||
| 178 | .endm | ||
| 179 | |||
| 180 | resample_one s32, 2 | ||
| 181 | |||
| 182 | |||
| 183 | /* s16 */ | ||
| 184 | .macro LOAD1 | ||
| 185 | veor.16 d0, d0 | ||
| 186 | vld1.16 {d0[0]}, [r0]! /* load filter */ | ||
| 187 | vld1.16 {d4[0]}, [r3]! /* load src */ | ||
| 188 | .endm | ||
| 189 | .macro LOAD2 | ||
| 190 | veor.16 d0, d0 | ||
| 191 | vld1.32 {d0[0]}, [r0]! /* load filter */ | ||
| 192 | veor.16 d4, d4 | ||
| 193 | vld1.32 {d4[0]}, [r3]! /* load src */ | ||
| 194 | .endm | ||
| 195 | .macro LOAD4 | ||
| 196 | vld1.16 {d0}, [r0]! /* load filter */ | ||
| 197 | vld1.16 {d4}, [r3]! /* load src */ | ||
| 198 | .endm | ||
| 199 | .macro MLA1 | ||
| 200 | vmlal.s16 q8, d0, d4[0] | ||
| 201 | .endm | ||
| 202 | .macro MLA2 | ||
| 203 | vmlal.s16 q8, d0, d4 | ||
| 204 | .endm | ||
| 205 | .macro MLA4 | ||
| 206 | vmlal.s16 q8, d0, d4 | ||
| 207 | .endm | ||
| 208 | .macro MUL4 | ||
| 209 | vmull.s16 q8, d0, d4 | ||
| 210 | .endm | ||
| 211 | .macro INIT4 | ||
| 212 | veor.s32 q8, q8 | ||
| 213 | .endm | ||
| 214 | .macro STORE | ||
| 215 | vpadd.s32 d16, d16, d17 | ||
| 216 | vpadd.s32 d16, d16, d16 | ||
| 217 | vqrshrn.s32 d16, q8, #15 | ||
| 218 | vst1.16 d16[0], [r1] | ||
| 219 | .endm | ||
| 220 | |||
| 221 | resample_one s16, 1 | ||
| 222 | |||
| 223 | |||
| 224 | .macro resample_linear fmt, es=2 | ||
| 225 | function ff_resample_linear_\fmt\()_neon, export=1 | ||
| 226 | push {r4, r5} | ||
| 227 | add r1, r1, r2, lsl #\es | ||
| 228 | |||
| 229 | ldr r2, [r0, #PHASE_SHIFT+4] /* phase_mask */ | ||
| 230 | ldr ip, [sp, #8] /* index */ | ||
| 231 | ldr r5, [r0, #FILTER_LENGTH] | ||
| 232 | and r2, ip, r2 /* (index & phase_mask) */ | ||
| 233 | ldr r4, [r0, #PHASE_SHIFT] | ||
| 234 | lsr r4, ip, r4 /* compute sample_index */ | ||
| 235 | mul r2, r2, r5 | ||
| 236 | |||
| 237 | ldr ip, [r0, #FILTER_BANK] | ||
| 238 | add r3, r3, r4, lsl #\es /* &src[sample_index] */ | ||
| 239 | |||
| 240 | cmp r5, #8 | ||
| 241 | ldr r4, [r0, #SRC_INCR] | ||
| 242 | add r0, ip, r2, lsl #\es /* filter = &filter_bank[...] */ | ||
| 243 | add r2, r0, r5, lsl #\es /* filter[... + c->filter_length] */ | ||
| 244 | |||
| 245 | blt 5f | ||
| 246 | 8: | ||
| 247 | subs r5, r5, #8 | ||
| 248 | LOAD4 | ||
| 249 | MUL4 | ||
| 250 | 7: | ||
| 251 | LOAD4 | ||
| 252 | beq 6f | ||
| 253 | cmp r5, #8 | ||
| 254 | MLA4 | ||
| 255 | blt 4f | ||
| 256 | subs r5, r5, #8 | ||
| 257 | LOAD4 | ||
| 258 | MLA4 | ||
| 259 | b 7b | ||
| 260 | 6: | ||
| 261 | MLA4 | ||
| 262 | STORE | ||
| 263 | pop {r4, r5} | ||
| 264 | bx lr | ||
| 265 | 5: | ||
| 266 | INIT4 | ||
| 267 | 4: /* remaining filter_length 1 to 7 */ | ||
| 268 | cmp r5, #4 | ||
| 269 | blt 2f | ||
| 270 | subs r5, r5, #4 | ||
| 271 | LOAD4 | ||
| 272 | MLA4 | ||
| 273 | beq 0f | ||
| 274 | 2: /* remaining filter_length 1 to 3 */ | ||
| 275 | cmp r5, #2 | ||
| 276 | blt 1f | ||
| 277 | subs r5, r5, #2 | ||
| 278 | LOAD2 | ||
| 279 | MLA2 | ||
| 280 | beq 0f | ||
| 281 | 1: /* remaining filter_length 1 */ | ||
| 282 | LOAD1 | ||
| 283 | MLA1 | ||
| 284 | 0: | ||
| 285 | STORE | ||
| 286 | pop {r4, r5} | ||
| 287 | bx lr | ||
| 288 | endfunc | ||
| 289 | |||
| 290 | .purgem LOAD1 | ||
| 291 | .purgem LOAD2 | ||
| 292 | .purgem LOAD4 | ||
| 293 | .purgem MLA1 | ||
| 294 | .purgem MLA2 | ||
| 295 | .purgem MLA4 | ||
| 296 | .purgem MUL4 | ||
| 297 | .purgem INIT4 | ||
| 298 | .purgem STORE | ||
| 299 | .endm | ||
| 300 | |||
| 301 | |||
| 302 | /* float32 linear */ | ||
| 303 | .macro LOAD1 | ||
| 304 | veor.32 d0, d0 | ||
| 305 | veor.32 d2, d2 | ||
| 306 | vld1.32 {d0[0]}, [r0]! /* load filter */ | ||
| 307 | vld1.32 {d2[0]}, [r2]! /* load filter */ | ||
| 308 | vld1.32 {d4[0]}, [r3]! /* load src */ | ||
| 309 | .endm | ||
| 310 | .macro LOAD2 | ||
| 311 | vld1.32 {d0}, [r0]! /* load filter */ | ||
| 312 | vld1.32 {d2}, [r2]! /* load filter */ | ||
| 313 | vld1.32 {d4}, [r3]! /* load src */ | ||
| 314 | .endm | ||
| 315 | .macro LOAD4 | ||
| 316 | vld1.32 {d0,d1}, [r0]! /* load filter */ | ||
| 317 | vld1.32 {d2,d3}, [r2]! /* load filter */ | ||
| 318 | vld1.32 {d4,d5}, [r3]! /* load src */ | ||
| 319 | .endm | ||
| 320 | .macro MLA1 | ||
| 321 | vmla.f32 d18, d0, d4[0] | ||
| 322 | vmla.f32 d16, d2, d4[0] | ||
| 323 | .endm | ||
| 324 | .macro MLA2 | ||
| 325 | vmla.f32 d18, d0, d4 | ||
| 326 | vmla.f32 d16, d2, d4 | ||
| 327 | .endm | ||
| 328 | .macro MLA4 | ||
| 329 | vmla.f32 q9, q0, q2 | ||
| 330 | vmla.f32 q8, q1, q2 | ||
| 331 | .endm | ||
| 332 | .macro MUL4 | ||
| 333 | vmul.f32 q9, q0, q2 | ||
| 334 | vmul.f32 q8, q1, q2 | ||
| 335 | .endm | ||
| 336 | .macro INIT4 | ||
| 337 | veor.f32 q9, q9 | ||
| 338 | veor.f32 q8, q8 | ||
| 339 | .endm | ||
| 340 | .macro STORE | ||
| 341 | vldr s0, [sp, #12] /* frac */ | ||
| 342 | vmov s1, r4 | ||
| 343 | vcvt.f32.s32 d0, d0 | ||
| 344 | |||
| 345 | vsub.f32 q8, q8, q9 /* v2 - val */ | ||
| 346 | vpadd.f32 d18, d18, d19 | ||
| 347 | vpadd.f32 d16, d16, d17 | ||
| 348 | vpadd.f32 d2, d18, d18 | ||
| 349 | vpadd.f32 d1, d16, d16 | ||
| 350 | |||
| 351 | vmul.f32 s2, s2, s0 /* (v2 - val) * frac */ | ||
| 352 | vdiv.f32 s2, s2, s1 /* / c->src_incr */ | ||
| 353 | vadd.f32 s4, s4, s2 | ||
| 354 | |||
| 355 | vstr s4, [r1] | ||
| 356 | .endm | ||
| 357 | |||
| 358 | resample_linear flt, 2 | ||
| @@ -1,416 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> | ||
| 3 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <stdint.h> | ||
| 23 | |||
| 24 | #include "config.h" | ||
| 25 | #include "libavutil/common.h" | ||
| 26 | #include "libavutil/libm.h" | ||
| 27 | #include "libavutil/log.h" | ||
| 28 | #include "libavutil/mem.h" | ||
| 29 | #include "libavutil/samplefmt.h" | ||
| 30 | #include "audio_convert.h" | ||
| 31 | #include "audio_data.h" | ||
| 32 | #include "dither.h" | ||
| 33 | |||
| 34 | enum ConvFuncType { | ||
| 35 | CONV_FUNC_TYPE_FLAT, | ||
| 36 | CONV_FUNC_TYPE_INTERLEAVE, | ||
| 37 | CONV_FUNC_TYPE_DEINTERLEAVE, | ||
| 38 | }; | ||
| 39 | |||
| 40 | typedef void (conv_func_flat)(uint8_t *out, const uint8_t *in, int len); | ||
| 41 | |||
| 42 | typedef void (conv_func_interleave)(uint8_t *out, uint8_t *const *in, | ||
| 43 | int len, int channels); | ||
| 44 | |||
| 45 | typedef void (conv_func_deinterleave)(uint8_t **out, const uint8_t *in, int len, | ||
| 46 | int channels); | ||
| 47 | |||
| 48 | struct AudioConvert { | ||
| 49 | AVAudioResampleContext *avr; | ||
| 50 | DitherContext *dc; | ||
| 51 | enum AVSampleFormat in_fmt; | ||
| 52 | enum AVSampleFormat out_fmt; | ||
| 53 | int apply_map; | ||
| 54 | int channels; | ||
| 55 | int planes; | ||
| 56 | int ptr_align; | ||
| 57 | int samples_align; | ||
| 58 | int has_optimized_func; | ||
| 59 | const char *func_descr; | ||
| 60 | const char *func_descr_generic; | ||
| 61 | enum ConvFuncType func_type; | ||
| 62 | conv_func_flat *conv_flat; | ||
| 63 | conv_func_flat *conv_flat_generic; | ||
| 64 | conv_func_interleave *conv_interleave; | ||
| 65 | conv_func_interleave *conv_interleave_generic; | ||
| 66 | conv_func_deinterleave *conv_deinterleave; | ||
| 67 | conv_func_deinterleave *conv_deinterleave_generic; | ||
| 68 | }; | ||
| 69 | |||
| 70 | void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt, | ||
| 71 | enum AVSampleFormat in_fmt, int channels, | ||
| 72 | int ptr_align, int samples_align, | ||
| 73 | const char *descr, void *conv) | ||
| 74 | { | ||
| 75 | int found = 0; | ||
| 76 | |||
| 77 | switch (ac->func_type) { | ||
| 78 | case CONV_FUNC_TYPE_FLAT: | ||
| 79 | if (av_get_packed_sample_fmt(ac->in_fmt) == in_fmt && | ||
| 80 | av_get_packed_sample_fmt(ac->out_fmt) == out_fmt) { | ||
| 81 | ac->conv_flat = conv; | ||
| 82 | ac->func_descr = descr; | ||
| 83 | ac->ptr_align = ptr_align; | ||
| 84 | ac->samples_align = samples_align; | ||
| 85 | if (ptr_align == 1 && samples_align == 1) { | ||
| 86 | ac->conv_flat_generic = conv; | ||
| 87 | ac->func_descr_generic = descr; | ||
| 88 | } else { | ||
| 89 | ac->has_optimized_func = 1; | ||
| 90 | } | ||
| 91 | found = 1; | ||
| 92 | } | ||
| 93 | break; | ||
| 94 | case CONV_FUNC_TYPE_INTERLEAVE: | ||
| 95 | if (ac->in_fmt == in_fmt && ac->out_fmt == out_fmt && | ||
| 96 | (!channels || ac->channels == channels)) { | ||
| 97 | ac->conv_interleave = conv; | ||
| 98 | ac->func_descr = descr; | ||
| 99 | ac->ptr_align = ptr_align; | ||
| 100 | ac->samples_align = samples_align; | ||
| 101 | if (ptr_align == 1 && samples_align == 1) { | ||
| 102 | ac->conv_interleave_generic = conv; | ||
| 103 | ac->func_descr_generic = descr; | ||
| 104 | } else { | ||
| 105 | ac->has_optimized_func = 1; | ||
| 106 | } | ||
| 107 | found = 1; | ||
| 108 | } | ||
| 109 | break; | ||
| 110 | case CONV_FUNC_TYPE_DEINTERLEAVE: | ||
| 111 | if (ac->in_fmt == in_fmt && ac->out_fmt == out_fmt && | ||
| 112 | (!channels || ac->channels == channels)) { | ||
| 113 | ac->conv_deinterleave = conv; | ||
| 114 | ac->func_descr = descr; | ||
| 115 | ac->ptr_align = ptr_align; | ||
| 116 | ac->samples_align = samples_align; | ||
| 117 | if (ptr_align == 1 && samples_align == 1) { | ||
| 118 | ac->conv_deinterleave_generic = conv; | ||
| 119 | ac->func_descr_generic = descr; | ||
| 120 | } else { | ||
| 121 | ac->has_optimized_func = 1; | ||
| 122 | } | ||
| 123 | found = 1; | ||
| 124 | } | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | if (found) { | ||
| 128 | av_log(ac->avr, AV_LOG_DEBUG, "audio_convert: found function: %-4s " | ||
| 129 | "to %-4s (%s)\n", av_get_sample_fmt_name(ac->in_fmt), | ||
| 130 | av_get_sample_fmt_name(ac->out_fmt), descr); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 134 | #define CONV_FUNC_NAME(dst_fmt, src_fmt) conv_ ## src_fmt ## _to_ ## dst_fmt | ||
| 135 | |||
| 136 | #define CONV_LOOP(otype, expr) \ | ||
| 137 | do { \ | ||
| 138 | *(otype *)po = expr; \ | ||
| 139 | pi += is; \ | ||
| 140 | po += os; \ | ||
| 141 | } while (po < end); \ | ||
| 142 | |||
| 143 | #define CONV_FUNC_FLAT(ofmt, otype, ifmt, itype, expr) \ | ||
| 144 | static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *out, const uint8_t *in, \ | ||
| 145 | int len) \ | ||
| 146 | { \ | ||
| 147 | int is = sizeof(itype); \ | ||
| 148 | int os = sizeof(otype); \ | ||
| 149 | const uint8_t *pi = in; \ | ||
| 150 | uint8_t *po = out; \ | ||
| 151 | uint8_t *end = out + os * len; \ | ||
| 152 | CONV_LOOP(otype, expr) \ | ||
| 153 | } | ||
| 154 | |||
| 155 | #define CONV_FUNC_INTERLEAVE(ofmt, otype, ifmt, itype, expr) \ | ||
| 156 | static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t *out, const uint8_t **in, \ | ||
| 157 | int len, int channels) \ | ||
| 158 | { \ | ||
| 159 | int ch; \ | ||
| 160 | int out_bps = sizeof(otype); \ | ||
| 161 | int is = sizeof(itype); \ | ||
| 162 | int os = channels * out_bps; \ | ||
| 163 | for (ch = 0; ch < channels; ch++) { \ | ||
| 164 | const uint8_t *pi = in[ch]; \ | ||
| 165 | uint8_t *po = out + ch * out_bps; \ | ||
| 166 | uint8_t *end = po + os * len; \ | ||
| 167 | CONV_LOOP(otype, expr) \ | ||
| 168 | } \ | ||
| 169 | } | ||
| 170 | |||
| 171 | #define CONV_FUNC_DEINTERLEAVE(ofmt, otype, ifmt, itype, expr) \ | ||
| 172 | static void CONV_FUNC_NAME(ofmt, ifmt)(uint8_t **out, const uint8_t *in, \ | ||
| 173 | int len, int channels) \ | ||
| 174 | { \ | ||
| 175 | int ch; \ | ||
| 176 | int in_bps = sizeof(itype); \ | ||
| 177 | int is = channels * in_bps; \ | ||
| 178 | int os = sizeof(otype); \ | ||
| 179 | for (ch = 0; ch < channels; ch++) { \ | ||
| 180 | const uint8_t *pi = in + ch * in_bps; \ | ||
| 181 | uint8_t *po = out[ch]; \ | ||
| 182 | uint8_t *end = po + os * len; \ | ||
| 183 | CONV_LOOP(otype, expr) \ | ||
| 184 | } \ | ||
| 185 | } | ||
| 186 | |||
| 187 | #define CONV_FUNC_GROUP(ofmt, otype, ifmt, itype, expr) \ | ||
| 188 | CONV_FUNC_FLAT( ofmt, otype, ifmt, itype, expr) \ | ||
| 189 | CONV_FUNC_INTERLEAVE( ofmt, otype, ifmt ## P, itype, expr) \ | ||
| 190 | CONV_FUNC_DEINTERLEAVE(ofmt ## P, otype, ifmt, itype, expr) | ||
| 191 | |||
| 192 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_U8, uint8_t, *(const uint8_t *)pi) | ||
| 193 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) << 8) | ||
| 194 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) << 24) | ||
| 195 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) * (1.0f / (1 << 7))) | ||
| 196 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t, (*(const uint8_t *)pi - 0x80) * (1.0 / (1 << 7))) | ||
| 197 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t, (*(const int16_t *)pi >> 8) + 0x80) | ||
| 198 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi) | ||
| 199 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi << 16) | ||
| 200 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi * (1.0f / (1 << 15))) | ||
| 201 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *)pi * (1.0 / (1 << 15))) | ||
| 202 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t, (*(const int32_t *)pi >> 24) + 0x80) | ||
| 203 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi >> 16) | ||
| 204 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi) | ||
| 205 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi * (1.0f / (1U << 31))) | ||
| 206 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *)pi * (1.0 / (1U << 31))) | ||
| 207 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8( lrintf(*(const float *)pi * (1 << 7)) + 0x80)) | ||
| 208 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16( lrintf(*(const float *)pi * (1 << 15)))) | ||
| 209 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *)pi * (1U << 31)))) | ||
| 210 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_FLT, float, *(const float *)pi) | ||
| 211 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_FLT, float, *(const float *)pi) | ||
| 212 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8( lrint(*(const double *)pi * (1 << 7)) + 0x80)) | ||
| 213 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16( lrint(*(const double *)pi * (1 << 15)))) | ||
| 214 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *)pi * (1U << 31)))) | ||
| 215 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_DBL, double, *(const double *)pi) | ||
| 216 | CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_DBL, double, *(const double *)pi) | ||
| 217 | |||
| 218 | #define SET_CONV_FUNC_GROUP(ofmt, ifmt) \ | ||
| 219 | ff_audio_convert_set_func(ac, ofmt, ifmt, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt, ifmt)); \ | ||
| 220 | ff_audio_convert_set_func(ac, ofmt ## P, ifmt, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt ## P, ifmt)); \ | ||
| 221 | ff_audio_convert_set_func(ac, ofmt, ifmt ## P, 0, 1, 1, "C", CONV_FUNC_NAME(ofmt, ifmt ## P)); | ||
| 222 | |||
| 223 | static void set_generic_function(AudioConvert *ac) | ||
| 224 | { | ||
| 225 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_U8) | ||
| 226 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_U8) | ||
| 227 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_U8) | ||
| 228 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_U8) | ||
| 229 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_U8) | ||
| 230 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S16) | ||
| 231 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16) | ||
| 232 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16) | ||
| 233 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16) | ||
| 234 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S16) | ||
| 235 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_S32) | ||
| 236 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32) | ||
| 237 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S32) | ||
| 238 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32) | ||
| 239 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_S32) | ||
| 240 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_FLT) | ||
| 241 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT) | ||
| 242 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT) | ||
| 243 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLT) | ||
| 244 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_FLT) | ||
| 245 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_DBL) | ||
| 246 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_DBL) | ||
| 247 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_DBL) | ||
| 248 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_DBL) | ||
| 249 | SET_CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBL) | ||
| 250 | } | ||
| 251 | |||
| 252 | void ff_audio_convert_free(AudioConvert **ac) | ||
| 253 | { | ||
| 254 | if (!*ac) | ||
| 255 | return; | ||
| 256 | ff_dither_free(&(*ac)->dc); | ||
| 257 | av_freep(ac); | ||
| 258 | } | ||
| 259 | |||
| 260 | AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, | ||
| 261 | enum AVSampleFormat out_fmt, | ||
| 262 | enum AVSampleFormat in_fmt, | ||
| 263 | int channels, int sample_rate, | ||
| 264 | int apply_map) | ||
| 265 | { | ||
| 266 | AudioConvert *ac; | ||
| 267 | int in_planar, out_planar; | ||
| 268 | |||
| 269 | ac = av_mallocz(sizeof(*ac)); | ||
| 270 | if (!ac) | ||
| 271 | return NULL; | ||
| 272 | |||
| 273 | ac->avr = avr; | ||
| 274 | ac->out_fmt = out_fmt; | ||
| 275 | ac->in_fmt = in_fmt; | ||
| 276 | ac->channels = channels; | ||
| 277 | ac->apply_map = apply_map; | ||
| 278 | |||
| 279 | if (avr->dither_method != AV_RESAMPLE_DITHER_NONE && | ||
| 280 | av_get_packed_sample_fmt(out_fmt) == AV_SAMPLE_FMT_S16 && | ||
| 281 | av_get_bytes_per_sample(in_fmt) > 2) { | ||
| 282 | ac->dc = ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, | ||
| 283 | apply_map); | ||
| 284 | if (!ac->dc) { | ||
| 285 | av_free(ac); | ||
| 286 | return NULL; | ||
| 287 | } | ||
| 288 | return ac; | ||
| 289 | } | ||
| 290 | |||
| 291 | in_planar = ff_sample_fmt_is_planar(in_fmt, channels); | ||
| 292 | out_planar = ff_sample_fmt_is_planar(out_fmt, channels); | ||
| 293 | |||
| 294 | if (in_planar == out_planar) { | ||
| 295 | ac->func_type = CONV_FUNC_TYPE_FLAT; | ||
| 296 | ac->planes = in_planar ? ac->channels : 1; | ||
| 297 | } else if (in_planar) | ||
| 298 | ac->func_type = CONV_FUNC_TYPE_INTERLEAVE; | ||
| 299 | else | ||
| 300 | ac->func_type = CONV_FUNC_TYPE_DEINTERLEAVE; | ||
| 301 | |||
| 302 | set_generic_function(ac); | ||
| 303 | |||
| 304 | if (ARCH_AARCH64) | ||
| 305 | ff_audio_convert_init_aarch64(ac); | ||
| 306 | if (ARCH_ARM) | ||
| 307 | ff_audio_convert_init_arm(ac); | ||
| 308 | if (ARCH_X86) | ||
| 309 | ff_audio_convert_init_x86(ac); | ||
| 310 | |||
| 311 | return ac; | ||
| 312 | } | ||
| 313 | |||
| 314 | int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) | ||
| 315 | { | ||
| 316 | int use_generic = 1; | ||
| 317 | int len = in->nb_samples; | ||
| 318 | int p; | ||
| 319 | |||
| 320 | if (ac->dc) { | ||
| 321 | /* dithered conversion */ | ||
| 322 | av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (dithered)\n", | ||
| 323 | len, av_get_sample_fmt_name(ac->in_fmt), | ||
| 324 | av_get_sample_fmt_name(ac->out_fmt)); | ||
| 325 | |||
| 326 | return ff_convert_dither(ac->dc, out, in); | ||
| 327 | } | ||
| 328 | |||
| 329 | /* determine whether to use the optimized function based on pointer and | ||
| 330 | samples alignment in both the input and output */ | ||
| 331 | if (ac->has_optimized_func) { | ||
| 332 | int ptr_align = FFMIN(in->ptr_align, out->ptr_align); | ||
| 333 | int samples_align = FFMIN(in->samples_align, out->samples_align); | ||
| 334 | int aligned_len = FFALIGN(len, ac->samples_align); | ||
| 335 | if (!(ptr_align % ac->ptr_align) && samples_align >= aligned_len) { | ||
| 336 | len = aligned_len; | ||
| 337 | use_generic = 0; | ||
| 338 | } | ||
| 339 | } | ||
| 340 | av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (%s)\n", len, | ||
| 341 | av_get_sample_fmt_name(ac->in_fmt), | ||
| 342 | av_get_sample_fmt_name(ac->out_fmt), | ||
| 343 | use_generic ? ac->func_descr_generic : ac->func_descr); | ||
| 344 | |||
| 345 | if (ac->apply_map) { | ||
| 346 | ChannelMapInfo *map = &ac->avr->ch_map_info; | ||
| 347 | |||
| 348 | if (!ff_sample_fmt_is_planar(ac->out_fmt, ac->channels)) { | ||
| 349 | av_log(ac->avr, AV_LOG_ERROR, "cannot remap packed format during conversion\n"); | ||
| 350 | return AVERROR(EINVAL); | ||
| 351 | } | ||
| 352 | |||
| 353 | if (map->do_remap) { | ||
| 354 | if (ff_sample_fmt_is_planar(ac->in_fmt, ac->channels)) { | ||
| 355 | conv_func_flat *convert = use_generic ? ac->conv_flat_generic : | ||
| 356 | ac->conv_flat; | ||
| 357 | |||
| 358 | for (p = 0; p < ac->planes; p++) | ||
| 359 | if (map->channel_map[p] >= 0) | ||
| 360 | convert(out->data[p], in->data[map->channel_map[p]], len); | ||
| 361 | } else { | ||
| 362 | uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; | ||
| 363 | conv_func_deinterleave *convert = use_generic ? | ||
| 364 | ac->conv_deinterleave_generic : | ||
| 365 | ac->conv_deinterleave; | ||
| 366 | |||
| 367 | for (p = 0; p < ac->channels; p++) | ||
| 368 | data[map->input_map[p]] = out->data[p]; | ||
| 369 | |||
| 370 | convert(data, in->data[0], len, ac->channels); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | if (map->do_copy || map->do_zero) { | ||
| 374 | for (p = 0; p < ac->planes; p++) { | ||
| 375 | if (map->channel_copy[p]) | ||
| 376 | memcpy(out->data[p], out->data[map->channel_copy[p]], | ||
| 377 | len * out->stride); | ||
| 378 | else if (map->channel_zero[p]) | ||
| 379 | av_samples_set_silence(&out->data[p], 0, len, 1, ac->out_fmt); | ||
| 380 | } | ||
| 381 | } | ||
| 382 | } else { | ||
| 383 | switch (ac->func_type) { | ||
| 384 | case CONV_FUNC_TYPE_FLAT: { | ||
| 385 | if (!in->is_planar) | ||
| 386 | len *= in->channels; | ||
| 387 | if (use_generic) { | ||
| 388 | for (p = 0; p < ac->planes; p++) | ||
| 389 | ac->conv_flat_generic(out->data[p], in->data[p], len); | ||
| 390 | } else { | ||
| 391 | for (p = 0; p < ac->planes; p++) | ||
| 392 | ac->conv_flat(out->data[p], in->data[p], len); | ||
| 393 | } | ||
| 394 | break; | ||
| 395 | } | ||
| 396 | case CONV_FUNC_TYPE_INTERLEAVE: | ||
| 397 | if (use_generic) | ||
| 398 | ac->conv_interleave_generic(out->data[0], in->data, len, | ||
| 399 | ac->channels); | ||
| 400 | else | ||
| 401 | ac->conv_interleave(out->data[0], in->data, len, ac->channels); | ||
| 402 | break; | ||
| 403 | case CONV_FUNC_TYPE_DEINTERLEAVE: | ||
| 404 | if (use_generic) | ||
| 405 | ac->conv_deinterleave_generic(out->data, in->data[0], len, | ||
| 406 | ac->channels); | ||
| 407 | else | ||
| 408 | ac->conv_deinterleave(out->data, in->data[0], len, | ||
| 409 | ac->channels); | ||
| 410 | break; | ||
| 411 | } | ||
| 412 | } | ||
| 413 | |||
| 414 | out->nb_samples = in->nb_samples; | ||
| 415 | return 0; | ||
| 416 | } | ||
| @@ -1,103 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef AVRESAMPLE_AUDIO_CONVERT_H | ||
| 22 | #define AVRESAMPLE_AUDIO_CONVERT_H | ||
| 23 | |||
| 24 | #include "libavutil/samplefmt.h" | ||
| 25 | #include "avresample.h" | ||
| 26 | #include "internal.h" | ||
| 27 | #include "audio_data.h" | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Set conversion function if the parameters match. | ||
| 31 | * | ||
| 32 | * This compares the parameters of the conversion function to the parameters | ||
| 33 | * in the AudioConvert context. If the parameters do not match, no changes are | ||
| 34 | * made to the active functions. If the parameters do match and the alignment | ||
| 35 | * is not constrained, the function is set as the generic conversion function. | ||
| 36 | * If the parameters match and the alignment is constrained, the function is | ||
| 37 | * set as the optimized conversion function. | ||
| 38 | * | ||
| 39 | * @param ac AudioConvert context | ||
| 40 | * @param out_fmt output sample format | ||
| 41 | * @param in_fmt input sample format | ||
| 42 | * @param channels number of channels, or 0 for any number of channels | ||
| 43 | * @param ptr_align buffer pointer alignment, in bytes | ||
| 44 | * @param samples_align buffer size alignment, in samples | ||
| 45 | * @param descr function type description (e.g. "C" or "SSE") | ||
| 46 | * @param conv conversion function pointer | ||
| 47 | */ | ||
| 48 | void ff_audio_convert_set_func(AudioConvert *ac, enum AVSampleFormat out_fmt, | ||
| 49 | enum AVSampleFormat in_fmt, int channels, | ||
| 50 | int ptr_align, int samples_align, | ||
| 51 | const char *descr, void *conv); | ||
| 52 | |||
| 53 | /** | ||
| 54 | * Allocate and initialize AudioConvert context for sample format conversion. | ||
| 55 | * | ||
| 56 | * @param avr AVAudioResampleContext | ||
| 57 | * @param out_fmt output sample format | ||
| 58 | * @param in_fmt input sample format | ||
| 59 | * @param channels number of channels | ||
| 60 | * @param sample_rate sample rate (used for dithering) | ||
| 61 | * @param apply_map apply channel map during conversion | ||
| 62 | * @return newly-allocated AudioConvert context | ||
| 63 | */ | ||
| 64 | AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, | ||
| 65 | enum AVSampleFormat out_fmt, | ||
| 66 | enum AVSampleFormat in_fmt, | ||
| 67 | int channels, int sample_rate, | ||
| 68 | int apply_map); | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Free AudioConvert. | ||
| 72 | * | ||
| 73 | * The AudioConvert must have been previously allocated with ff_audio_convert_alloc(). | ||
| 74 | * | ||
| 75 | * @param ac AudioConvert struct | ||
| 76 | */ | ||
| 77 | void ff_audio_convert_free(AudioConvert **ac); | ||
| 78 | |||
| 79 | /** | ||
| 80 | * Convert audio data from one sample format to another. | ||
| 81 | * | ||
| 82 | * For each call, the alignment of the input and output AudioData buffers are | ||
| 83 | * examined to determine whether to use the generic or optimized conversion | ||
| 84 | * function (when available). | ||
| 85 | * | ||
| 86 | * The number of samples to convert is determined by in->nb_samples. The output | ||
| 87 | * buffer must be large enough to handle this many samples. out->nb_samples is | ||
| 88 | * set by this function before a successful return. | ||
| 89 | * | ||
| 90 | * @param ac AudioConvert context | ||
| 91 | * @param out output audio data | ||
| 92 | * @param in input audio data | ||
| 93 | * @return 0 on success, negative AVERROR code on failure | ||
| 94 | */ | ||
| 95 | int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in); | ||
| 96 | |||
| 97 | /* arch-specific initialization functions */ | ||
| 98 | |||
| 99 | void ff_audio_convert_init_aarch64(AudioConvert *ac); | ||
| 100 | void ff_audio_convert_init_arm(AudioConvert *ac); | ||
| 101 | void ff_audio_convert_init_x86(AudioConvert *ac); | ||
| 102 | |||
| 103 | #endif /* AVRESAMPLE_AUDIO_CONVERT_H */ | ||
| @@ -1,381 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <stdint.h> | ||
| 22 | #include <string.h> | ||
| 23 | |||
| 24 | #include "libavutil/mem.h" | ||
| 25 | #include "audio_data.h" | ||
| 26 | |||
| 27 | static const AVClass audio_data_class = { | ||
| 28 | .class_name = "AudioData", | ||
| 29 | .item_name = av_default_item_name, | ||
| 30 | .version = LIBAVUTIL_VERSION_INT, | ||
| 31 | }; | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Calculate alignment for data pointers. | ||
| 35 | */ | ||
| 36 | static void calc_ptr_alignment(AudioData *a) | ||
| 37 | { | ||
| 38 | int p; | ||
| 39 | int min_align = 128; | ||
| 40 | |||
| 41 | for (p = 0; p < a->planes; p++) { | ||
| 42 | int cur_align = 128; | ||
| 43 | while ((intptr_t)a->data[p] % cur_align) | ||
| 44 | cur_align >>= 1; | ||
| 45 | if (cur_align < min_align) | ||
| 46 | min_align = cur_align; | ||
| 47 | } | ||
| 48 | a->ptr_align = min_align; | ||
| 49 | } | ||
| 50 | |||
| 51 | int ff_sample_fmt_is_planar(enum AVSampleFormat sample_fmt, int channels) | ||
| 52 | { | ||
| 53 | if (channels == 1) | ||
| 54 | return 1; | ||
| 55 | else | ||
| 56 | return av_sample_fmt_is_planar(sample_fmt); | ||
| 57 | } | ||
| 58 | |||
| 59 | int ff_audio_data_set_channels(AudioData *a, int channels) | ||
| 60 | { | ||
| 61 | if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS || | ||
| 62 | channels > a->allocated_channels) | ||
| 63 | return AVERROR(EINVAL); | ||
| 64 | |||
| 65 | a->channels = channels; | ||
| 66 | a->planes = a->is_planar ? channels : 1; | ||
| 67 | |||
| 68 | calc_ptr_alignment(a); | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | int ff_audio_data_init(AudioData *a, uint8_t * const *src, int plane_size, | ||
| 74 | int channels, int nb_samples, | ||
| 75 | enum AVSampleFormat sample_fmt, int read_only, | ||
| 76 | const char *name) | ||
| 77 | { | ||
| 78 | int p; | ||
| 79 | |||
| 80 | memset(a, 0, sizeof(*a)); | ||
| 81 | a->class = &audio_data_class; | ||
| 82 | |||
| 83 | if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) { | ||
| 84 | av_log(a, AV_LOG_ERROR, "invalid channel count: %d\n", channels); | ||
| 85 | return AVERROR(EINVAL); | ||
| 86 | } | ||
| 87 | |||
| 88 | a->sample_size = av_get_bytes_per_sample(sample_fmt); | ||
| 89 | if (!a->sample_size) { | ||
| 90 | av_log(a, AV_LOG_ERROR, "invalid sample format\n"); | ||
| 91 | return AVERROR(EINVAL); | ||
| 92 | } | ||
| 93 | a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels); | ||
| 94 | a->planes = a->is_planar ? channels : 1; | ||
| 95 | a->stride = a->sample_size * (a->is_planar ? 1 : channels); | ||
| 96 | |||
| 97 | for (p = 0; p < (a->is_planar ? channels : 1); p++) { | ||
| 98 | if (!src[p]) { | ||
| 99 | av_log(a, AV_LOG_ERROR, "invalid NULL pointer for src[%d]\n", p); | ||
| 100 | return AVERROR(EINVAL); | ||
| 101 | } | ||
| 102 | a->data[p] = src[p]; | ||
| 103 | } | ||
| 104 | a->allocated_samples = nb_samples * !read_only; | ||
| 105 | a->nb_samples = nb_samples; | ||
| 106 | a->sample_fmt = sample_fmt; | ||
| 107 | a->channels = channels; | ||
| 108 | a->allocated_channels = channels; | ||
| 109 | a->read_only = read_only; | ||
| 110 | a->allow_realloc = 0; | ||
| 111 | a->name = name ? name : "{no name}"; | ||
| 112 | |||
| 113 | calc_ptr_alignment(a); | ||
| 114 | a->samples_align = plane_size / a->stride; | ||
| 115 | |||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | AudioData *ff_audio_data_alloc(int channels, int nb_samples, | ||
| 120 | enum AVSampleFormat sample_fmt, const char *name) | ||
| 121 | { | ||
| 122 | AudioData *a; | ||
| 123 | int ret; | ||
| 124 | |||
| 125 | if (channels < 1 || channels > AVRESAMPLE_MAX_CHANNELS) | ||
| 126 | return NULL; | ||
| 127 | |||
| 128 | a = av_mallocz(sizeof(*a)); | ||
| 129 | if (!a) | ||
| 130 | return NULL; | ||
| 131 | |||
| 132 | a->sample_size = av_get_bytes_per_sample(sample_fmt); | ||
| 133 | if (!a->sample_size) { | ||
| 134 | av_free(a); | ||
| 135 | return NULL; | ||
| 136 | } | ||
| 137 | a->is_planar = ff_sample_fmt_is_planar(sample_fmt, channels); | ||
| 138 | a->planes = a->is_planar ? channels : 1; | ||
| 139 | a->stride = a->sample_size * (a->is_planar ? 1 : channels); | ||
| 140 | |||
| 141 | a->class = &audio_data_class; | ||
| 142 | a->sample_fmt = sample_fmt; | ||
| 143 | a->channels = channels; | ||
| 144 | a->allocated_channels = channels; | ||
| 145 | a->read_only = 0; | ||
| 146 | a->allow_realloc = 1; | ||
| 147 | a->name = name ? name : "{no name}"; | ||
| 148 | |||
| 149 | if (nb_samples > 0) { | ||
| 150 | ret = ff_audio_data_realloc(a, nb_samples); | ||
| 151 | if (ret < 0) { | ||
| 152 | av_free(a); | ||
| 153 | return NULL; | ||
| 154 | } | ||
| 155 | return a; | ||
| 156 | } else { | ||
| 157 | calc_ptr_alignment(a); | ||
| 158 | return a; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | int ff_audio_data_realloc(AudioData *a, int nb_samples) | ||
| 163 | { | ||
| 164 | int ret, new_buf_size, plane_size, p; | ||
| 165 | |||
| 166 | /* check if buffer is already large enough */ | ||
| 167 | if (a->allocated_samples >= nb_samples) | ||
| 168 | return 0; | ||
| 169 | |||
| 170 | /* validate that the output is not read-only and realloc is allowed */ | ||
| 171 | if (a->read_only || !a->allow_realloc) | ||
| 172 | return AVERROR(EINVAL); | ||
| 173 | |||
| 174 | new_buf_size = av_samples_get_buffer_size(&plane_size, | ||
| 175 | a->allocated_channels, nb_samples, | ||
| 176 | a->sample_fmt, 0); | ||
| 177 | if (new_buf_size < 0) | ||
| 178 | return new_buf_size; | ||
| 179 | |||
| 180 | /* if there is already data in the buffer and the sample format is planar, | ||
| 181 | allocate a new buffer and copy the data, otherwise just realloc the | ||
| 182 | internal buffer and set new data pointers */ | ||
| 183 | if (a->nb_samples > 0 && a->is_planar) { | ||
| 184 | uint8_t *new_data[AVRESAMPLE_MAX_CHANNELS] = { NULL }; | ||
| 185 | |||
| 186 | ret = av_samples_alloc(new_data, &plane_size, a->allocated_channels, | ||
| 187 | nb_samples, a->sample_fmt, 0); | ||
| 188 | if (ret < 0) | ||
| 189 | return ret; | ||
| 190 | |||
| 191 | for (p = 0; p < a->planes; p++) | ||
| 192 | memcpy(new_data[p], a->data[p], a->nb_samples * a->stride); | ||
| 193 | |||
| 194 | av_freep(&a->buffer); | ||
| 195 | memcpy(a->data, new_data, sizeof(new_data)); | ||
| 196 | a->buffer = a->data[0]; | ||
| 197 | } else { | ||
| 198 | av_freep(&a->buffer); | ||
| 199 | a->buffer = av_malloc(new_buf_size); | ||
| 200 | if (!a->buffer) | ||
| 201 | return AVERROR(ENOMEM); | ||
| 202 | ret = av_samples_fill_arrays(a->data, &plane_size, a->buffer, | ||
| 203 | a->allocated_channels, nb_samples, | ||
| 204 | a->sample_fmt, 0); | ||
| 205 | if (ret < 0) | ||
| 206 | return ret; | ||
| 207 | } | ||
| 208 | a->buffer_size = new_buf_size; | ||
| 209 | a->allocated_samples = nb_samples; | ||
| 210 | |||
| 211 | calc_ptr_alignment(a); | ||
| 212 | a->samples_align = plane_size / a->stride; | ||
| 213 | |||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 217 | void ff_audio_data_free(AudioData **a) | ||
| 218 | { | ||
| 219 | if (!*a) | ||
| 220 | return; | ||
| 221 | av_free((*a)->buffer); | ||
| 222 | av_freep(a); | ||
| 223 | } | ||
| 224 | |||
| 225 | int ff_audio_data_copy(AudioData *dst, AudioData *src, ChannelMapInfo *map) | ||
| 226 | { | ||
| 227 | int ret, p; | ||
| 228 | |||
| 229 | /* validate input/output compatibility */ | ||
| 230 | if (dst->sample_fmt != src->sample_fmt || dst->channels < src->channels) | ||
| 231 | return AVERROR(EINVAL); | ||
| 232 | |||
| 233 | if (map && !src->is_planar) { | ||
| 234 | av_log(src, AV_LOG_ERROR, "cannot remap packed format during copy\n"); | ||
| 235 | return AVERROR(EINVAL); | ||
| 236 | } | ||
| 237 | |||
| 238 | /* if the input is empty, just empty the output */ | ||
| 239 | if (!src->nb_samples) { | ||
| 240 | dst->nb_samples = 0; | ||
| 241 | return 0; | ||
| 242 | } | ||
| 243 | |||
| 244 | /* reallocate output if necessary */ | ||
| 245 | ret = ff_audio_data_realloc(dst, src->nb_samples); | ||
| 246 | if (ret < 0) | ||
| 247 | return ret; | ||
| 248 | |||
| 249 | /* copy data */ | ||
| 250 | if (map) { | ||
| 251 | if (map->do_remap) { | ||
| 252 | for (p = 0; p < src->planes; p++) { | ||
| 253 | if (map->channel_map[p] >= 0) | ||
| 254 | memcpy(dst->data[p], src->data[map->channel_map[p]], | ||
| 255 | src->nb_samples * src->stride); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | if (map->do_copy || map->do_zero) { | ||
| 259 | for (p = 0; p < src->planes; p++) { | ||
| 260 | if (map->channel_copy[p]) | ||
| 261 | memcpy(dst->data[p], dst->data[map->channel_copy[p]], | ||
| 262 | src->nb_samples * src->stride); | ||
| 263 | else if (map->channel_zero[p]) | ||
| 264 | av_samples_set_silence(&dst->data[p], 0, src->nb_samples, | ||
| 265 | 1, dst->sample_fmt); | ||
| 266 | } | ||
| 267 | } | ||
| 268 | } else { | ||
| 269 | for (p = 0; p < src->planes; p++) | ||
| 270 | memcpy(dst->data[p], src->data[p], src->nb_samples * src->stride); | ||
| 271 | } | ||
| 272 | |||
| 273 | dst->nb_samples = src->nb_samples; | ||
| 274 | |||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src, | ||
| 279 | int src_offset, int nb_samples) | ||
| 280 | { | ||
| 281 | int ret, p, dst_offset2, dst_move_size; | ||
| 282 | |||
| 283 | /* validate input/output compatibility */ | ||
| 284 | if (dst->sample_fmt != src->sample_fmt || dst->channels != src->channels) { | ||
| 285 | av_log(src, AV_LOG_ERROR, "sample format mismatch\n"); | ||
| 286 | return AVERROR(EINVAL); | ||
| 287 | } | ||
| 288 | |||
| 289 | /* validate offsets are within the buffer bounds */ | ||
| 290 | if (dst_offset < 0 || dst_offset > dst->nb_samples || | ||
| 291 | src_offset < 0 || src_offset > src->nb_samples) { | ||
| 292 | av_log(src, AV_LOG_ERROR, "offset out-of-bounds: src=%d dst=%d\n", | ||
| 293 | src_offset, dst_offset); | ||
| 294 | return AVERROR(EINVAL); | ||
| 295 | } | ||
| 296 | |||
| 297 | /* check offsets and sizes to see if we can just do nothing and return */ | ||
| 298 | if (nb_samples > src->nb_samples - src_offset) | ||
| 299 | nb_samples = src->nb_samples - src_offset; | ||
| 300 | if (nb_samples <= 0) | ||
| 301 | return 0; | ||
| 302 | |||
| 303 | /* validate that the output is not read-only */ | ||
| 304 | if (dst->read_only) { | ||
| 305 | av_log(dst, AV_LOG_ERROR, "dst is read-only\n"); | ||
| 306 | return AVERROR(EINVAL); | ||
| 307 | } | ||
| 308 | |||
| 309 | /* reallocate output if necessary */ | ||
| 310 | ret = ff_audio_data_realloc(dst, dst->nb_samples + nb_samples); | ||
| 311 | if (ret < 0) { | ||
| 312 | av_log(dst, AV_LOG_ERROR, "error reallocating dst\n"); | ||
| 313 | return ret; | ||
| 314 | } | ||
| 315 | |||
| 316 | dst_offset2 = dst_offset + nb_samples; | ||
| 317 | dst_move_size = dst->nb_samples - dst_offset; | ||
| 318 | |||
| 319 | for (p = 0; p < src->planes; p++) { | ||
| 320 | if (dst_move_size > 0) { | ||
| 321 | memmove(dst->data[p] + dst_offset2 * dst->stride, | ||
| 322 | dst->data[p] + dst_offset * dst->stride, | ||
| 323 | dst_move_size * dst->stride); | ||
| 324 | } | ||
| 325 | memcpy(dst->data[p] + dst_offset * dst->stride, | ||
| 326 | src->data[p] + src_offset * src->stride, | ||
| 327 | nb_samples * src->stride); | ||
| 328 | } | ||
| 329 | dst->nb_samples += nb_samples; | ||
| 330 | |||
| 331 | return 0; | ||
| 332 | } | ||
| 333 | |||
| 334 | void ff_audio_data_drain(AudioData *a, int nb_samples) | ||
| 335 | { | ||
| 336 | if (a->nb_samples <= nb_samples) { | ||
| 337 | /* drain the whole buffer */ | ||
| 338 | a->nb_samples = 0; | ||
| 339 | } else { | ||
| 340 | int p; | ||
| 341 | int move_offset = a->stride * nb_samples; | ||
| 342 | int move_size = a->stride * (a->nb_samples - nb_samples); | ||
| 343 | |||
| 344 | for (p = 0; p < a->planes; p++) | ||
| 345 | memmove(a->data[p], a->data[p] + move_offset, move_size); | ||
| 346 | |||
| 347 | a->nb_samples -= nb_samples; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | |||
| 351 | int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset, | ||
| 352 | int nb_samples) | ||
| 353 | { | ||
| 354 | uint8_t *offset_data[AVRESAMPLE_MAX_CHANNELS]; | ||
| 355 | int offset_size, p; | ||
| 356 | |||
| 357 | if (offset >= a->nb_samples) | ||
| 358 | return 0; | ||
| 359 | offset_size = offset * a->stride; | ||
| 360 | for (p = 0; p < a->planes; p++) | ||
| 361 | offset_data[p] = a->data[p] + offset_size; | ||
| 362 | |||
| 363 | return av_audio_fifo_write(af, (void **)offset_data, nb_samples); | ||
| 364 | } | ||
| 365 | |||
| 366 | int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples) | ||
| 367 | { | ||
| 368 | int ret; | ||
| 369 | |||
| 370 | if (a->read_only) | ||
| 371 | return AVERROR(EINVAL); | ||
| 372 | |||
| 373 | ret = ff_audio_data_realloc(a, nb_samples); | ||
| 374 | if (ret < 0) | ||
| 375 | return ret; | ||
| 376 | |||
| 377 | ret = av_audio_fifo_read(af, (void **)a->data, nb_samples); | ||
| 378 | if (ret >= 0) | ||
| 379 | a->nb_samples = ret; | ||
| 380 | return ret; | ||
| 381 | } | ||
| @@ -1,178 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef AVRESAMPLE_AUDIO_DATA_H | ||
| 22 | #define AVRESAMPLE_AUDIO_DATA_H | ||
| 23 | |||
| 24 | #include <stdint.h> | ||
| 25 | |||
| 26 | #include "libavutil/audio_fifo.h" | ||
| 27 | #include "libavutil/log.h" | ||
| 28 | #include "libavutil/samplefmt.h" | ||
| 29 | #include "avresample.h" | ||
| 30 | #include "internal.h" | ||
| 31 | |||
| 32 | int ff_sample_fmt_is_planar(enum AVSampleFormat sample_fmt, int channels); | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Audio buffer used for intermediate storage between conversion phases. | ||
| 36 | */ | ||
| 37 | struct AudioData { | ||
| 38 | const AVClass *class; /**< AVClass for logging */ | ||
| 39 | uint8_t *data[AVRESAMPLE_MAX_CHANNELS]; /**< data plane pointers */ | ||
| 40 | uint8_t *buffer; /**< data buffer */ | ||
| 41 | unsigned int buffer_size; /**< allocated buffer size */ | ||
| 42 | int allocated_samples; /**< number of samples the buffer can hold */ | ||
| 43 | int nb_samples; /**< current number of samples */ | ||
| 44 | enum AVSampleFormat sample_fmt; /**< sample format */ | ||
| 45 | int channels; /**< channel count */ | ||
| 46 | int allocated_channels; /**< allocated channel count */ | ||
| 47 | int is_planar; /**< sample format is planar */ | ||
| 48 | int planes; /**< number of data planes */ | ||
| 49 | int sample_size; /**< bytes per sample */ | ||
| 50 | int stride; /**< sample byte offset within a plane */ | ||
| 51 | int read_only; /**< data is read-only */ | ||
| 52 | int allow_realloc; /**< realloc is allowed */ | ||
| 53 | int ptr_align; /**< minimum data pointer alignment */ | ||
| 54 | int samples_align; /**< allocated samples alignment */ | ||
| 55 | const char *name; /**< name for debug logging */ | ||
| 56 | }; | ||
| 57 | |||
| 58 | int ff_audio_data_set_channels(AudioData *a, int channels); | ||
| 59 | |||
| 60 | /** | ||
| 61 | * Initialize AudioData using a given source. | ||
| 62 | * | ||
| 63 | * This does not allocate an internal buffer. It only sets the data pointers | ||
| 64 | * and audio parameters. | ||
| 65 | * | ||
| 66 | * @param a AudioData struct | ||
| 67 | * @param src source data pointers | ||
| 68 | * @param plane_size plane size, in bytes. | ||
| 69 | * This can be 0 if unknown, but that will lead to | ||
| 70 | * optimized functions not being used in many cases, | ||
| 71 | * which could slow down some conversions. | ||
| 72 | * @param channels channel count | ||
| 73 | * @param nb_samples number of samples in the source data | ||
| 74 | * @param sample_fmt sample format | ||
| 75 | * @param read_only indicates if buffer is read only or read/write | ||
| 76 | * @param name name for debug logging (can be NULL) | ||
| 77 | * @return 0 on success, negative AVERROR value on error | ||
| 78 | */ | ||
| 79 | int ff_audio_data_init(AudioData *a, uint8_t * const *src, int plane_size, | ||
| 80 | int channels, int nb_samples, | ||
| 81 | enum AVSampleFormat sample_fmt, int read_only, | ||
| 82 | const char *name); | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Allocate AudioData. | ||
| 86 | * | ||
| 87 | * This allocates an internal buffer and sets audio parameters. | ||
| 88 | * | ||
| 89 | * @param channels channel count | ||
| 90 | * @param nb_samples number of samples to allocate space for | ||
| 91 | * @param sample_fmt sample format | ||
| 92 | * @param name name for debug logging (can be NULL) | ||
| 93 | * @return newly allocated AudioData struct, or NULL on error | ||
| 94 | */ | ||
| 95 | AudioData *ff_audio_data_alloc(int channels, int nb_samples, | ||
| 96 | enum AVSampleFormat sample_fmt, | ||
| 97 | const char *name); | ||
| 98 | |||
| 99 | /** | ||
| 100 | * Reallocate AudioData. | ||
| 101 | * | ||
| 102 | * The AudioData must have been previously allocated with ff_audio_data_alloc(). | ||
| 103 | * | ||
| 104 | * @param a AudioData struct | ||
| 105 | * @param nb_samples number of samples to allocate space for | ||
| 106 | * @return 0 on success, negative AVERROR value on error | ||
| 107 | */ | ||
| 108 | int ff_audio_data_realloc(AudioData *a, int nb_samples); | ||
| 109 | |||
| 110 | /** | ||
| 111 | * Free AudioData. | ||
| 112 | * | ||
| 113 | * The AudioData must have been previously allocated with ff_audio_data_alloc(). | ||
| 114 | * | ||
| 115 | * @param a AudioData struct | ||
| 116 | */ | ||
| 117 | void ff_audio_data_free(AudioData **a); | ||
| 118 | |||
| 119 | /** | ||
| 120 | * Copy data from one AudioData to another. | ||
| 121 | * | ||
| 122 | * @param out output AudioData | ||
| 123 | * @param in input AudioData | ||
| 124 | * @param map channel map, NULL if not remapping | ||
| 125 | * @return 0 on success, negative AVERROR value on error | ||
| 126 | */ | ||
| 127 | int ff_audio_data_copy(AudioData *out, AudioData *in, ChannelMapInfo *map); | ||
| 128 | |||
| 129 | /** | ||
| 130 | * Append data from one AudioData to the end of another. | ||
| 131 | * | ||
| 132 | * @param dst destination AudioData | ||
| 133 | * @param dst_offset offset, in samples, to start writing, relative to the | ||
| 134 | * start of dst | ||
| 135 | * @param src source AudioData | ||
| 136 | * @param src_offset offset, in samples, to start copying, relative to the | ||
| 137 | * start of the src | ||
| 138 | * @param nb_samples number of samples to copy | ||
| 139 | * @return 0 on success, negative AVERROR value on error | ||
| 140 | */ | ||
| 141 | int ff_audio_data_combine(AudioData *dst, int dst_offset, AudioData *src, | ||
| 142 | int src_offset, int nb_samples); | ||
| 143 | |||
| 144 | /** | ||
| 145 | * Drain samples from the start of the AudioData. | ||
| 146 | * | ||
| 147 | * Remaining samples are shifted to the start of the AudioData. | ||
| 148 | * | ||
| 149 | * @param a AudioData struct | ||
| 150 | * @param nb_samples number of samples to drain | ||
| 151 | */ | ||
| 152 | void ff_audio_data_drain(AudioData *a, int nb_samples); | ||
| 153 | |||
| 154 | /** | ||
| 155 | * Add samples in AudioData to an AVAudioFifo. | ||
| 156 | * | ||
| 157 | * @param af Audio FIFO Buffer | ||
| 158 | * @param a AudioData struct | ||
| 159 | * @param offset number of samples to skip from the start of the data | ||
| 160 | * @param nb_samples number of samples to add to the FIFO | ||
| 161 | * @return number of samples actually added to the FIFO, or | ||
| 162 | * negative AVERROR code on error | ||
| 163 | */ | ||
| 164 | int ff_audio_data_add_to_fifo(AVAudioFifo *af, AudioData *a, int offset, | ||
| 165 | int nb_samples); | ||
| 166 | |||
| 167 | /** | ||
| 168 | * Read samples from an AVAudioFifo to AudioData. | ||
| 169 | * | ||
| 170 | * @param af Audio FIFO Buffer | ||
| 171 | * @param a AudioData struct | ||
| 172 | * @param nb_samples number of samples to read from the FIFO | ||
| 173 | * @return number of samples actually read from the FIFO, or | ||
| 174 | * negative AVERROR code on error | ||
| 175 | */ | ||
| 176 | int ff_audio_data_read_from_fifo(AVAudioFifo *af, AudioData *a, int nb_samples); | ||
| 177 | |||
| 178 | #endif /* AVRESAMPLE_AUDIO_DATA_H */ | ||
| @@ -1,742 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <stdint.h> | ||
| 22 | |||
| 23 | #include "libavutil/common.h" | ||
| 24 | #include "libavutil/libm.h" | ||
| 25 | #include "libavutil/samplefmt.h" | ||
| 26 | #include "avresample.h" | ||
| 27 | #include "internal.h" | ||
| 28 | #include "audio_data.h" | ||
| 29 | #include "audio_mix.h" | ||
| 30 | |||
| 31 | static const char * const coeff_type_names[] = { "q8", "q15", "flt" }; | ||
| 32 | |||
| 33 | struct AudioMix { | ||
| 34 | AVAudioResampleContext *avr; | ||
| 35 | enum AVSampleFormat fmt; | ||
| 36 | enum AVMixCoeffType coeff_type; | ||
| 37 | uint64_t in_layout; | ||
| 38 | uint64_t out_layout; | ||
| 39 | int in_channels; | ||
| 40 | int out_channels; | ||
| 41 | |||
| 42 | int ptr_align; | ||
| 43 | int samples_align; | ||
| 44 | int has_optimized_func; | ||
| 45 | const char *func_descr; | ||
| 46 | const char *func_descr_generic; | ||
| 47 | mix_func *mix; | ||
| 48 | mix_func *mix_generic; | ||
| 49 | |||
| 50 | int in_matrix_channels; | ||
| 51 | int out_matrix_channels; | ||
| 52 | int output_zero[AVRESAMPLE_MAX_CHANNELS]; | ||
| 53 | int input_skip[AVRESAMPLE_MAX_CHANNELS]; | ||
| 54 | int output_skip[AVRESAMPLE_MAX_CHANNELS]; | ||
| 55 | int16_t *matrix_q8[AVRESAMPLE_MAX_CHANNELS]; | ||
| 56 | int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS]; | ||
| 57 | float *matrix_flt[AVRESAMPLE_MAX_CHANNELS]; | ||
| 58 | void **matrix; | ||
| 59 | }; | ||
| 60 | |||
| 61 | void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, | ||
| 62 | enum AVMixCoeffType coeff_type, int in_channels, | ||
| 63 | int out_channels, int ptr_align, int samples_align, | ||
| 64 | const char *descr, void *mix_func) | ||
| 65 | { | ||
| 66 | if (fmt == am->fmt && coeff_type == am->coeff_type && | ||
| 67 | ( in_channels == am->in_matrix_channels || in_channels == 0) && | ||
| 68 | (out_channels == am->out_matrix_channels || out_channels == 0)) { | ||
| 69 | char chan_str[16]; | ||
| 70 | am->mix = mix_func; | ||
| 71 | am->func_descr = descr; | ||
| 72 | am->ptr_align = ptr_align; | ||
| 73 | am->samples_align = samples_align; | ||
| 74 | if (ptr_align == 1 && samples_align == 1) { | ||
| 75 | am->mix_generic = mix_func; | ||
| 76 | am->func_descr_generic = descr; | ||
| 77 | } else { | ||
| 78 | am->has_optimized_func = 1; | ||
| 79 | } | ||
| 80 | if (in_channels) { | ||
| 81 | if (out_channels) | ||
| 82 | snprintf(chan_str, sizeof(chan_str), "[%d to %d] ", | ||
| 83 | in_channels, out_channels); | ||
| 84 | else | ||
| 85 | snprintf(chan_str, sizeof(chan_str), "[%d to any] ", | ||
| 86 | in_channels); | ||
| 87 | } else if (out_channels) { | ||
| 88 | snprintf(chan_str, sizeof(chan_str), "[any to %d] ", | ||
| 89 | out_channels); | ||
| 90 | } else { | ||
| 91 | snprintf(chan_str, sizeof(chan_str), "[any to any] "); | ||
| 92 | } | ||
| 93 | av_log(am->avr, AV_LOG_DEBUG, "audio_mix: found function: [fmt=%s] " | ||
| 94 | "[c=%s] %s(%s)\n", av_get_sample_fmt_name(fmt), | ||
| 95 | coeff_type_names[coeff_type], chan_str, descr); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | #define MIX_FUNC_NAME(fmt, cfmt) mix_any_ ## fmt ##_## cfmt ##_c | ||
| 100 | |||
| 101 | #define MIX_FUNC_GENERIC(fmt, cfmt, stype, ctype, sumtype, expr) \ | ||
| 102 | static void MIX_FUNC_NAME(fmt, cfmt)(stype **samples, ctype **matrix, \ | ||
| 103 | int len, int out_ch, int in_ch) \ | ||
| 104 | { \ | ||
| 105 | int i, in, out; \ | ||
| 106 | stype temp[AVRESAMPLE_MAX_CHANNELS]; \ | ||
| 107 | for (i = 0; i < len; i++) { \ | ||
| 108 | for (out = 0; out < out_ch; out++) { \ | ||
| 109 | sumtype sum = 0; \ | ||
| 110 | for (in = 0; in < in_ch; in++) \ | ||
| 111 | sum += samples[in][i] * matrix[out][in]; \ | ||
| 112 | temp[out] = expr; \ | ||
| 113 | } \ | ||
| 114 | for (out = 0; out < out_ch; out++) \ | ||
| 115 | samples[out][i] = temp[out]; \ | ||
| 116 | } \ | ||
| 117 | } | ||
| 118 | |||
| 119 | MIX_FUNC_GENERIC(FLTP, FLT, float, float, float, sum) | ||
| 120 | MIX_FUNC_GENERIC(S16P, FLT, int16_t, float, float, av_clip_int16(lrintf(sum))) | ||
| 121 | MIX_FUNC_GENERIC(S16P, Q15, int16_t, int32_t, int64_t, av_clip_int16(sum >> 15)) | ||
| 122 | MIX_FUNC_GENERIC(S16P, Q8, int16_t, int16_t, int32_t, av_clip_int16(sum >> 8)) | ||
| 123 | |||
| 124 | /* TODO: templatize the channel-specific C functions */ | ||
| 125 | |||
| 126 | static void mix_2_to_1_fltp_flt_c(float **samples, float **matrix, int len, | ||
| 127 | int out_ch, int in_ch) | ||
| 128 | { | ||
| 129 | float *src0 = samples[0]; | ||
| 130 | float *src1 = samples[1]; | ||
| 131 | float *dst = src0; | ||
| 132 | float m0 = matrix[0][0]; | ||
| 133 | float m1 = matrix[0][1]; | ||
| 134 | |||
| 135 | while (len > 4) { | ||
| 136 | *dst++ = *src0++ * m0 + *src1++ * m1; | ||
| 137 | *dst++ = *src0++ * m0 + *src1++ * m1; | ||
| 138 | *dst++ = *src0++ * m0 + *src1++ * m1; | ||
| 139 | *dst++ = *src0++ * m0 + *src1++ * m1; | ||
| 140 | len -= 4; | ||
| 141 | } | ||
| 142 | while (len > 0) { | ||
| 143 | *dst++ = *src0++ * m0 + *src1++ * m1; | ||
| 144 | len--; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | static void mix_2_to_1_s16p_flt_c(int16_t **samples, float **matrix, int len, | ||
| 149 | int out_ch, int in_ch) | ||
| 150 | { | ||
| 151 | int16_t *src0 = samples[0]; | ||
| 152 | int16_t *src1 = samples[1]; | ||
| 153 | int16_t *dst = src0; | ||
| 154 | float m0 = matrix[0][0]; | ||
| 155 | float m1 = matrix[0][1]; | ||
| 156 | |||
| 157 | while (len > 4) { | ||
| 158 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | ||
| 159 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | ||
| 160 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | ||
| 161 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | ||
| 162 | len -= 4; | ||
| 163 | } | ||
| 164 | while (len > 0) { | ||
| 165 | *dst++ = av_clip_int16(lrintf(*src0++ * m0 + *src1++ * m1)); | ||
| 166 | len--; | ||
| 167 | } | ||
| 168 | } | ||
| 169 | |||
| 170 | static void mix_2_to_1_s16p_q8_c(int16_t **samples, int16_t **matrix, int len, | ||
| 171 | int out_ch, int in_ch) | ||
| 172 | { | ||
| 173 | int16_t *src0 = samples[0]; | ||
| 174 | int16_t *src1 = samples[1]; | ||
| 175 | int16_t *dst = src0; | ||
| 176 | int16_t m0 = matrix[0][0]; | ||
| 177 | int16_t m1 = matrix[0][1]; | ||
| 178 | |||
| 179 | while (len > 4) { | ||
| 180 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | ||
| 181 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | ||
| 182 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | ||
| 183 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | ||
| 184 | len -= 4; | ||
| 185 | } | ||
| 186 | while (len > 0) { | ||
| 187 | *dst++ = (*src0++ * m0 + *src1++ * m1) >> 8; | ||
| 188 | len--; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | static void mix_1_to_2_fltp_flt_c(float **samples, float **matrix, int len, | ||
| 193 | int out_ch, int in_ch) | ||
| 194 | { | ||
| 195 | float v; | ||
| 196 | float *dst0 = samples[0]; | ||
| 197 | float *dst1 = samples[1]; | ||
| 198 | float *src = dst0; | ||
| 199 | float m0 = matrix[0][0]; | ||
| 200 | float m1 = matrix[1][0]; | ||
| 201 | |||
| 202 | while (len > 4) { | ||
| 203 | v = *src++; | ||
| 204 | *dst0++ = v * m0; | ||
| 205 | *dst1++ = v * m1; | ||
| 206 | v = *src++; | ||
| 207 | *dst0++ = v * m0; | ||
| 208 | *dst1++ = v * m1; | ||
| 209 | v = *src++; | ||
| 210 | *dst0++ = v * m0; | ||
| 211 | *dst1++ = v * m1; | ||
| 212 | v = *src++; | ||
| 213 | *dst0++ = v * m0; | ||
| 214 | *dst1++ = v * m1; | ||
| 215 | len -= 4; | ||
| 216 | } | ||
| 217 | while (len > 0) { | ||
| 218 | v = *src++; | ||
| 219 | *dst0++ = v * m0; | ||
| 220 | *dst1++ = v * m1; | ||
| 221 | len--; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | static void mix_6_to_2_fltp_flt_c(float **samples, float **matrix, int len, | ||
| 226 | int out_ch, int in_ch) | ||
| 227 | { | ||
| 228 | float v0, v1; | ||
| 229 | float *src0 = samples[0]; | ||
| 230 | float *src1 = samples[1]; | ||
| 231 | float *src2 = samples[2]; | ||
| 232 | float *src3 = samples[3]; | ||
| 233 | float *src4 = samples[4]; | ||
| 234 | float *src5 = samples[5]; | ||
| 235 | float *dst0 = src0; | ||
| 236 | float *dst1 = src1; | ||
| 237 | float *m0 = matrix[0]; | ||
| 238 | float *m1 = matrix[1]; | ||
| 239 | |||
| 240 | while (len > 0) { | ||
| 241 | v0 = *src0++; | ||
| 242 | v1 = *src1++; | ||
| 243 | *dst0++ = v0 * m0[0] + | ||
| 244 | v1 * m0[1] + | ||
| 245 | *src2 * m0[2] + | ||
| 246 | *src3 * m0[3] + | ||
| 247 | *src4 * m0[4] + | ||
| 248 | *src5 * m0[5]; | ||
| 249 | *dst1++ = v0 * m1[0] + | ||
| 250 | v1 * m1[1] + | ||
| 251 | *src2++ * m1[2] + | ||
| 252 | *src3++ * m1[3] + | ||
| 253 | *src4++ * m1[4] + | ||
| 254 | *src5++ * m1[5]; | ||
| 255 | len--; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | static void mix_2_to_6_fltp_flt_c(float **samples, float **matrix, int len, | ||
| 260 | int out_ch, int in_ch) | ||
| 261 | { | ||
| 262 | float v0, v1; | ||
| 263 | float *dst0 = samples[0]; | ||
| 264 | float *dst1 = samples[1]; | ||
| 265 | float *dst2 = samples[2]; | ||
| 266 | float *dst3 = samples[3]; | ||
| 267 | float *dst4 = samples[4]; | ||
| 268 | float *dst5 = samples[5]; | ||
| 269 | float *src0 = dst0; | ||
| 270 | float *src1 = dst1; | ||
| 271 | |||
| 272 | while (len > 0) { | ||
| 273 | v0 = *src0++; | ||
| 274 | v1 = *src1++; | ||
| 275 | *dst0++ = v0 * matrix[0][0] + v1 * matrix[0][1]; | ||
| 276 | *dst1++ = v0 * matrix[1][0] + v1 * matrix[1][1]; | ||
| 277 | *dst2++ = v0 * matrix[2][0] + v1 * matrix[2][1]; | ||
| 278 | *dst3++ = v0 * matrix[3][0] + v1 * matrix[3][1]; | ||
| 279 | *dst4++ = v0 * matrix[4][0] + v1 * matrix[4][1]; | ||
| 280 | *dst5++ = v0 * matrix[5][0] + v1 * matrix[5][1]; | ||
| 281 | len--; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | static av_cold int mix_function_init(AudioMix *am) | ||
| 286 | { | ||
| 287 | am->func_descr = am->func_descr_generic = "n/a"; | ||
| 288 | am->mix = am->mix_generic = NULL; | ||
| 289 | |||
| 290 | /* no need to set a mix function when we're skipping mixing */ | ||
| 291 | if (!am->in_matrix_channels || !am->out_matrix_channels) | ||
| 292 | return 0; | ||
| 293 | |||
| 294 | /* any-to-any C versions */ | ||
| 295 | |||
| 296 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||
| 297 | 0, 0, 1, 1, "C", MIX_FUNC_NAME(FLTP, FLT)); | ||
| 298 | |||
| 299 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | ||
| 300 | 0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, FLT)); | ||
| 301 | |||
| 302 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q15, | ||
| 303 | 0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q15)); | ||
| 304 | |||
| 305 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8, | ||
| 306 | 0, 0, 1, 1, "C", MIX_FUNC_NAME(S16P, Q8)); | ||
| 307 | |||
| 308 | /* channel-specific C versions */ | ||
| 309 | |||
| 310 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||
| 311 | 2, 1, 1, 1, "C", mix_2_to_1_fltp_flt_c); | ||
| 312 | |||
| 313 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | ||
| 314 | 2, 1, 1, 1, "C", mix_2_to_1_s16p_flt_c); | ||
| 315 | |||
| 316 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8, | ||
| 317 | 2, 1, 1, 1, "C", mix_2_to_1_s16p_q8_c); | ||
| 318 | |||
| 319 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||
| 320 | 1, 2, 1, 1, "C", mix_1_to_2_fltp_flt_c); | ||
| 321 | |||
| 322 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||
| 323 | 6, 2, 1, 1, "C", mix_6_to_2_fltp_flt_c); | ||
| 324 | |||
| 325 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||
| 326 | 2, 6, 1, 1, "C", mix_2_to_6_fltp_flt_c); | ||
| 327 | |||
| 328 | if (ARCH_X86) | ||
| 329 | ff_audio_mix_init_x86(am); | ||
| 330 | |||
| 331 | if (!am->mix) { | ||
| 332 | av_log(am->avr, AV_LOG_ERROR, "audio_mix: NO FUNCTION FOUND: [fmt=%s] " | ||
| 333 | "[c=%s] [%d to %d]\n", av_get_sample_fmt_name(am->fmt), | ||
| 334 | coeff_type_names[am->coeff_type], am->in_channels, | ||
| 335 | am->out_channels); | ||
| 336 | return AVERROR_PATCHWELCOME; | ||
| 337 | } | ||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | |||
| 341 | AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr) | ||
| 342 | { | ||
| 343 | AudioMix *am; | ||
| 344 | int ret; | ||
| 345 | |||
| 346 | am = av_mallocz(sizeof(*am)); | ||
| 347 | if (!am) | ||
| 348 | return NULL; | ||
| 349 | am->avr = avr; | ||
| 350 | |||
| 351 | if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && | ||
| 352 | avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) { | ||
| 353 | av_log(avr, AV_LOG_ERROR, "Unsupported internal format for " | ||
| 354 | "mixing: %s\n", | ||
| 355 | av_get_sample_fmt_name(avr->internal_sample_fmt)); | ||
| 356 | goto error; | ||
| 357 | } | ||
| 358 | |||
| 359 | am->fmt = avr->internal_sample_fmt; | ||
| 360 | am->coeff_type = avr->mix_coeff_type; | ||
| 361 | am->in_layout = avr->in_channel_layout; | ||
| 362 | am->out_layout = avr->out_channel_layout; | ||
| 363 | am->in_channels = avr->in_channels; | ||
| 364 | am->out_channels = avr->out_channels; | ||
| 365 | |||
| 366 | /* build matrix if the user did not already set one */ | ||
| 367 | if (avr->mix_matrix) { | ||
| 368 | ret = ff_audio_mix_set_matrix(am, avr->mix_matrix, avr->in_channels); | ||
| 369 | if (ret < 0) | ||
| 370 | goto error; | ||
| 371 | av_freep(&avr->mix_matrix); | ||
| 372 | } else { | ||
| 373 | double *matrix_dbl = av_mallocz(avr->out_channels * avr->in_channels * | ||
| 374 | sizeof(*matrix_dbl)); | ||
| 375 | if (!matrix_dbl) | ||
| 376 | goto error; | ||
| 377 | |||
| 378 | ret = avresample_build_matrix(avr->in_channel_layout, | ||
| 379 | avr->out_channel_layout, | ||
| 380 | avr->center_mix_level, | ||
| 381 | avr->surround_mix_level, | ||
| 382 | avr->lfe_mix_level, | ||
| 383 | avr->normalize_mix_level, | ||
| 384 | matrix_dbl, | ||
| 385 | avr->in_channels, | ||
| 386 | avr->matrix_encoding); | ||
| 387 | if (ret < 0) { | ||
| 388 | av_free(matrix_dbl); | ||
| 389 | goto error; | ||
| 390 | } | ||
| 391 | |||
| 392 | ret = ff_audio_mix_set_matrix(am, matrix_dbl, avr->in_channels); | ||
| 393 | if (ret < 0) { | ||
| 394 | av_log(avr, AV_LOG_ERROR, "error setting mix matrix\n"); | ||
| 395 | av_free(matrix_dbl); | ||
| 396 | goto error; | ||
| 397 | } | ||
| 398 | |||
| 399 | av_free(matrix_dbl); | ||
| 400 | } | ||
| 401 | |||
| 402 | return am; | ||
| 403 | |||
| 404 | error: | ||
| 405 | av_free(am); | ||
| 406 | return NULL; | ||
| 407 | } | ||
| 408 | |||
| 409 | void ff_audio_mix_free(AudioMix **am_p) | ||
| 410 | { | ||
| 411 | AudioMix *am; | ||
| 412 | |||
| 413 | if (!*am_p) | ||
| 414 | return; | ||
| 415 | am = *am_p; | ||
| 416 | |||
| 417 | if (am->matrix) { | ||
| 418 | av_free(am->matrix[0]); | ||
| 419 | am->matrix = NULL; | ||
| 420 | } | ||
| 421 | memset(am->matrix_q8, 0, sizeof(am->matrix_q8 )); | ||
| 422 | memset(am->matrix_q15, 0, sizeof(am->matrix_q15)); | ||
| 423 | memset(am->matrix_flt, 0, sizeof(am->matrix_flt)); | ||
| 424 | |||
| 425 | av_freep(am_p); | ||
| 426 | } | ||
| 427 | |||
| 428 | int ff_audio_mix(AudioMix *am, AudioData *src) | ||
| 429 | { | ||
| 430 | int use_generic = 1; | ||
| 431 | int len = src->nb_samples; | ||
| 432 | int i, j; | ||
| 433 | |||
| 434 | /* determine whether to use the optimized function based on pointer and | ||
| 435 | samples alignment in both the input and output */ | ||
| 436 | if (am->has_optimized_func) { | ||
| 437 | int aligned_len = FFALIGN(len, am->samples_align); | ||
| 438 | if (!(src->ptr_align % am->ptr_align) && | ||
| 439 | src->samples_align >= aligned_len) { | ||
| 440 | len = aligned_len; | ||
| 441 | use_generic = 0; | ||
| 442 | } | ||
| 443 | } | ||
| 444 | av_log(am->avr, AV_LOG_TRACE, "audio_mix: %d samples - %d to %d channels (%s)\n", | ||
| 445 | src->nb_samples, am->in_channels, am->out_channels, | ||
| 446 | use_generic ? am->func_descr_generic : am->func_descr); | ||
| 447 | |||
| 448 | if (am->in_matrix_channels && am->out_matrix_channels) { | ||
| 449 | uint8_t **data; | ||
| 450 | uint8_t *data0[AVRESAMPLE_MAX_CHANNELS] = { NULL }; | ||
| 451 | |||
| 452 | if (am->out_matrix_channels < am->out_channels || | ||
| 453 | am->in_matrix_channels < am->in_channels) { | ||
| 454 | for (i = 0, j = 0; i < FFMAX(am->in_channels, am->out_channels); i++) { | ||
| 455 | if (am->input_skip[i] || am->output_skip[i] || am->output_zero[i]) | ||
| 456 | continue; | ||
| 457 | data0[j++] = src->data[i]; | ||
| 458 | } | ||
| 459 | data = data0; | ||
| 460 | } else { | ||
| 461 | data = src->data; | ||
| 462 | } | ||
| 463 | |||
| 464 | if (use_generic) | ||
| 465 | am->mix_generic(data, am->matrix, len, am->out_matrix_channels, | ||
| 466 | am->in_matrix_channels); | ||
| 467 | else | ||
| 468 | am->mix(data, am->matrix, len, am->out_matrix_channels, | ||
| 469 | am->in_matrix_channels); | ||
| 470 | } | ||
| 471 | |||
| 472 | if (am->out_matrix_channels < am->out_channels) { | ||
| 473 | for (i = 0; i < am->out_channels; i++) | ||
| 474 | if (am->output_zero[i]) | ||
| 475 | av_samples_set_silence(&src->data[i], 0, len, 1, am->fmt); | ||
| 476 | } | ||
| 477 | |||
| 478 | ff_audio_data_set_channels(src, am->out_channels); | ||
| 479 | |||
| 480 | return 0; | ||
| 481 | } | ||
| 482 | |||
| 483 | int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride) | ||
| 484 | { | ||
| 485 | int i, o, i0, o0; | ||
| 486 | |||
| 487 | if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS || | ||
| 488 | am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) { | ||
| 489 | av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n"); | ||
| 490 | return AVERROR(EINVAL); | ||
| 491 | } | ||
| 492 | |||
| 493 | #define GET_MATRIX_CONVERT(suffix, scale) \ | ||
| 494 | if (!am->matrix_ ## suffix[0]) { \ | ||
| 495 | av_log(am->avr, AV_LOG_ERROR, "matrix is not set\n"); \ | ||
| 496 | return AVERROR(EINVAL); \ | ||
| 497 | } \ | ||
| 498 | for (o = 0, o0 = 0; o < am->out_channels; o++) { \ | ||
| 499 | for (i = 0, i0 = 0; i < am->in_channels; i++) { \ | ||
| 500 | if (am->input_skip[i] || am->output_zero[o]) \ | ||
| 501 | matrix[o * stride + i] = 0.0; \ | ||
| 502 | else \ | ||
| 503 | matrix[o * stride + i] = am->matrix_ ## suffix[o0][i0] * \ | ||
| 504 | (scale); \ | ||
| 505 | if (!am->input_skip[i]) \ | ||
| 506 | i0++; \ | ||
| 507 | } \ | ||
| 508 | if (!am->output_zero[o]) \ | ||
| 509 | o0++; \ | ||
| 510 | } | ||
| 511 | |||
| 512 | switch (am->coeff_type) { | ||
| 513 | case AV_MIX_COEFF_TYPE_Q8: | ||
| 514 | GET_MATRIX_CONVERT(q8, 1.0 / 256.0); | ||
| 515 | break; | ||
| 516 | case AV_MIX_COEFF_TYPE_Q15: | ||
| 517 | GET_MATRIX_CONVERT(q15, 1.0 / 32768.0); | ||
| 518 | break; | ||
| 519 | case AV_MIX_COEFF_TYPE_FLT: | ||
| 520 | GET_MATRIX_CONVERT(flt, 1.0); | ||
| 521 | break; | ||
| 522 | default: | ||
| 523 | av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); | ||
| 524 | return AVERROR(EINVAL); | ||
| 525 | } | ||
| 526 | |||
| 527 | return 0; | ||
| 528 | } | ||
| 529 | |||
| 530 | static void reduce_matrix(AudioMix *am, const double *matrix, int stride) | ||
| 531 | { | ||
| 532 | int i, o; | ||
| 533 | |||
| 534 | memset(am->output_zero, 0, sizeof(am->output_zero)); | ||
| 535 | memset(am->input_skip, 0, sizeof(am->input_skip)); | ||
| 536 | memset(am->output_skip, 0, sizeof(am->output_skip)); | ||
| 537 | |||
| 538 | /* exclude output channels if they can be zeroed instead of mixed */ | ||
| 539 | for (o = 0; o < am->out_channels; o++) { | ||
| 540 | int zero = 1; | ||
| 541 | |||
| 542 | /* check if the output is always silent */ | ||
| 543 | for (i = 0; i < am->in_channels; i++) { | ||
| 544 | if (matrix[o * stride + i] != 0.0) { | ||
| 545 | zero = 0; | ||
| 546 | break; | ||
| 547 | } | ||
| 548 | } | ||
| 549 | /* check if the corresponding input channel makes a contribution to | ||
| 550 | any output channel */ | ||
| 551 | if (o < am->in_channels) { | ||
| 552 | for (i = 0; i < am->out_channels; i++) { | ||
| 553 | if (matrix[i * stride + o] != 0.0) { | ||
| 554 | zero = 0; | ||
| 555 | break; | ||
| 556 | } | ||
| 557 | } | ||
| 558 | } | ||
| 559 | if (zero) { | ||
| 560 | am->output_zero[o] = 1; | ||
| 561 | am->out_matrix_channels--; | ||
| 562 | if (o < am->in_channels) | ||
| 563 | am->in_matrix_channels--; | ||
| 564 | } | ||
| 565 | } | ||
| 566 | if (am->out_matrix_channels == 0 || am->in_matrix_channels == 0) { | ||
| 567 | am->out_matrix_channels = 0; | ||
| 568 | am->in_matrix_channels = 0; | ||
| 569 | return; | ||
| 570 | } | ||
| 571 | |||
| 572 | /* skip input channels that contribute fully only to the corresponding | ||
| 573 | output channel */ | ||
| 574 | for (i = 0; i < FFMIN(am->in_channels, am->out_channels); i++) { | ||
| 575 | int skip = 1; | ||
| 576 | |||
| 577 | for (o = 0; o < am->out_channels; o++) { | ||
| 578 | int i0; | ||
| 579 | if ((o != i && matrix[o * stride + i] != 0.0) || | ||
| 580 | (o == i && matrix[o * stride + i] != 1.0)) { | ||
| 581 | skip = 0; | ||
| 582 | break; | ||
| 583 | } | ||
| 584 | /* if the input contributes fully to the output, also check that no | ||
| 585 | other inputs contribute to this output */ | ||
| 586 | if (o == i) { | ||
| 587 | for (i0 = 0; i0 < am->in_channels; i0++) { | ||
| 588 | if (i0 != i && matrix[o * stride + i0] != 0.0) { | ||
| 589 | skip = 0; | ||
| 590 | break; | ||
| 591 | } | ||
| 592 | } | ||
| 593 | } | ||
| 594 | } | ||
| 595 | if (skip) { | ||
| 596 | am->input_skip[i] = 1; | ||
| 597 | am->in_matrix_channels--; | ||
| 598 | } | ||
| 599 | } | ||
| 600 | /* skip input channels that do not contribute to any output channel */ | ||
| 601 | for (; i < am->in_channels; i++) { | ||
| 602 | int contrib = 0; | ||
| 603 | |||
| 604 | for (o = 0; o < am->out_channels; o++) { | ||
| 605 | if (matrix[o * stride + i] != 0.0) { | ||
| 606 | contrib = 1; | ||
| 607 | break; | ||
| 608 | } | ||
| 609 | } | ||
| 610 | if (!contrib) { | ||
| 611 | am->input_skip[i] = 1; | ||
| 612 | am->in_matrix_channels--; | ||
| 613 | } | ||
| 614 | } | ||
| 615 | if (am->in_matrix_channels == 0) { | ||
| 616 | am->out_matrix_channels = 0; | ||
| 617 | return; | ||
| 618 | } | ||
| 619 | |||
| 620 | /* skip output channels that only get full contribution from the | ||
| 621 | corresponding input channel */ | ||
| 622 | for (o = 0; o < FFMIN(am->in_channels, am->out_channels); o++) { | ||
| 623 | int skip = 1; | ||
| 624 | int o0; | ||
| 625 | |||
| 626 | for (i = 0; i < am->in_channels; i++) { | ||
| 627 | if ((o != i && matrix[o * stride + i] != 0.0) || | ||
| 628 | (o == i && matrix[o * stride + i] != 1.0)) { | ||
| 629 | skip = 0; | ||
| 630 | break; | ||
| 631 | } | ||
| 632 | } | ||
| 633 | /* check if the corresponding input channel makes a contribution to | ||
| 634 | any other output channel */ | ||
| 635 | i = o; | ||
| 636 | for (o0 = 0; o0 < am->out_channels; o0++) { | ||
| 637 | if (o0 != i && matrix[o0 * stride + i] != 0.0) { | ||
| 638 | skip = 0; | ||
| 639 | break; | ||
| 640 | } | ||
| 641 | } | ||
| 642 | if (skip) { | ||
| 643 | am->output_skip[o] = 1; | ||
| 644 | am->out_matrix_channels--; | ||
| 645 | } | ||
| 646 | } | ||
| 647 | if (am->out_matrix_channels == 0) { | ||
| 648 | am->in_matrix_channels = 0; | ||
| 649 | return; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride) | ||
| 654 | { | ||
| 655 | int i, o, i0, o0, ret; | ||
| 656 | char in_layout_name[128]; | ||
| 657 | char out_layout_name[128]; | ||
| 658 | |||
| 659 | if ( am->in_channels <= 0 || am->in_channels > AVRESAMPLE_MAX_CHANNELS || | ||
| 660 | am->out_channels <= 0 || am->out_channels > AVRESAMPLE_MAX_CHANNELS) { | ||
| 661 | av_log(am->avr, AV_LOG_ERROR, "Invalid channel counts\n"); | ||
| 662 | return AVERROR(EINVAL); | ||
| 663 | } | ||
| 664 | |||
| 665 | if (am->matrix) { | ||
| 666 | av_free(am->matrix[0]); | ||
| 667 | am->matrix = NULL; | ||
| 668 | } | ||
| 669 | |||
| 670 | am->in_matrix_channels = am->in_channels; | ||
| 671 | am->out_matrix_channels = am->out_channels; | ||
| 672 | |||
| 673 | reduce_matrix(am, matrix, stride); | ||
| 674 | |||
| 675 | #define CONVERT_MATRIX(type, expr) \ | ||
| 676 | am->matrix_## type[0] = av_mallocz(am->out_matrix_channels * \ | ||
| 677 | am->in_matrix_channels * \ | ||
| 678 | sizeof(*am->matrix_## type[0])); \ | ||
| 679 | if (!am->matrix_## type[0]) \ | ||
| 680 | return AVERROR(ENOMEM); \ | ||
| 681 | for (o = 0, o0 = 0; o < am->out_channels; o++) { \ | ||
| 682 | if (am->output_zero[o] || am->output_skip[o]) \ | ||
| 683 | continue; \ | ||
| 684 | if (o0 > 0) \ | ||
| 685 | am->matrix_## type[o0] = am->matrix_## type[o0 - 1] + \ | ||
| 686 | am->in_matrix_channels; \ | ||
| 687 | for (i = 0, i0 = 0; i < am->in_channels; i++) { \ | ||
| 688 | double v; \ | ||
| 689 | if (am->input_skip[i] || am->output_zero[i]) \ | ||
| 690 | continue; \ | ||
| 691 | v = matrix[o * stride + i]; \ | ||
| 692 | am->matrix_## type[o0][i0] = expr; \ | ||
| 693 | i0++; \ | ||
| 694 | } \ | ||
| 695 | o0++; \ | ||
| 696 | } \ | ||
| 697 | am->matrix = (void **)am->matrix_## type; | ||
| 698 | |||
| 699 | if (am->in_matrix_channels && am->out_matrix_channels) { | ||
| 700 | switch (am->coeff_type) { | ||
| 701 | case AV_MIX_COEFF_TYPE_Q8: | ||
| 702 | CONVERT_MATRIX(q8, av_clip_int16(lrint(256.0 * v))) | ||
| 703 | break; | ||
| 704 | case AV_MIX_COEFF_TYPE_Q15: | ||
| 705 | CONVERT_MATRIX(q15, av_clipl_int32(llrint(32768.0 * v))) | ||
| 706 | break; | ||
| 707 | case AV_MIX_COEFF_TYPE_FLT: | ||
| 708 | CONVERT_MATRIX(flt, v) | ||
| 709 | break; | ||
| 710 | default: | ||
| 711 | av_log(am->avr, AV_LOG_ERROR, "Invalid mix coeff type\n"); | ||
| 712 | return AVERROR(EINVAL); | ||
| 713 | } | ||
| 714 | } | ||
| 715 | |||
| 716 | ret = mix_function_init(am); | ||
| 717 | if (ret < 0) | ||
| 718 | return ret; | ||
| 719 | |||
| 720 | av_get_channel_layout_string(in_layout_name, sizeof(in_layout_name), | ||
| 721 | am->in_channels, am->in_layout); | ||
| 722 | av_get_channel_layout_string(out_layout_name, sizeof(out_layout_name), | ||
| 723 | am->out_channels, am->out_layout); | ||
| 724 | av_log(am->avr, AV_LOG_DEBUG, "audio_mix: %s to %s\n", | ||
| 725 | in_layout_name, out_layout_name); | ||
| 726 | av_log(am->avr, AV_LOG_DEBUG, "matrix size: %d x %d\n", | ||
| 727 | am->in_matrix_channels, am->out_matrix_channels); | ||
| 728 | for (o = 0; o < am->out_channels; o++) { | ||
| 729 | for (i = 0; i < am->in_channels; i++) { | ||
| 730 | if (am->output_zero[o]) | ||
| 731 | av_log(am->avr, AV_LOG_DEBUG, " (ZERO)"); | ||
| 732 | else if (am->input_skip[i] || am->output_zero[i] || am->output_skip[o]) | ||
| 733 | av_log(am->avr, AV_LOG_DEBUG, " (SKIP)"); | ||
| 734 | else | ||
| 735 | av_log(am->avr, AV_LOG_DEBUG, " %0.3f ", | ||
| 736 | matrix[o * am->in_channels + i]); | ||
| 737 | } | ||
| 738 | av_log(am->avr, AV_LOG_DEBUG, "\n"); | ||
| 739 | } | ||
| 740 | |||
| 741 | return 0; | ||
| 742 | } | ||
| @@ -1,94 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef AVRESAMPLE_AUDIO_MIX_H | ||
| 22 | #define AVRESAMPLE_AUDIO_MIX_H | ||
| 23 | |||
| 24 | #include <stdint.h> | ||
| 25 | |||
| 26 | #include "libavutil/samplefmt.h" | ||
| 27 | #include "avresample.h" | ||
| 28 | #include "internal.h" | ||
| 29 | #include "audio_data.h" | ||
| 30 | |||
| 31 | typedef void (mix_func)(uint8_t **src, void **matrix, int len, int out_ch, | ||
| 32 | int in_ch); | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Set mixing function if the parameters match. | ||
| 36 | * | ||
| 37 | * This compares the parameters of the mixing function to the parameters in the | ||
| 38 | * AudioMix context. If the parameters do not match, no changes are made to the | ||
| 39 | * active functions. If the parameters do match and the alignment is not | ||
| 40 | * constrained, the function is set as the generic mixing function. If the | ||
| 41 | * parameters match and the alignment is constrained, the function is set as | ||
| 42 | * the optimized mixing function. | ||
| 43 | * | ||
| 44 | * @param am AudioMix context | ||
| 45 | * @param fmt input/output sample format | ||
| 46 | * @param coeff_type mixing coefficient type | ||
| 47 | * @param in_channels number of input channels, or 0 for any number of channels | ||
| 48 | * @param out_channels number of output channels, or 0 for any number of channels | ||
| 49 | * @param ptr_align buffer pointer alignment, in bytes | ||
| 50 | * @param samples_align buffer size alignment, in samples | ||
| 51 | * @param descr function type description (e.g. "C" or "SSE") | ||
| 52 | * @param mix_func mixing function pointer | ||
| 53 | */ | ||
| 54 | void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, | ||
| 55 | enum AVMixCoeffType coeff_type, int in_channels, | ||
| 56 | int out_channels, int ptr_align, int samples_align, | ||
| 57 | const char *descr, void *mix_func); | ||
| 58 | |||
| 59 | /** | ||
| 60 | * Allocate and initialize an AudioMix context. | ||
| 61 | * | ||
| 62 | * The parameters in the AVAudioResampleContext are used to initialize the | ||
| 63 | * AudioMix context. | ||
| 64 | * | ||
| 65 | * @param avr AVAudioResampleContext | ||
| 66 | * @return newly-allocated AudioMix context. | ||
| 67 | */ | ||
| 68 | AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr); | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Free an AudioMix context. | ||
| 72 | */ | ||
| 73 | void ff_audio_mix_free(AudioMix **am); | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Apply channel mixing to audio data using the current mixing matrix. | ||
| 77 | */ | ||
| 78 | int ff_audio_mix(AudioMix *am, AudioData *src); | ||
| 79 | |||
| 80 | /** | ||
| 81 | * Get the current mixing matrix. | ||
| 82 | */ | ||
| 83 | int ff_audio_mix_get_matrix(AudioMix *am, double *matrix, int stride); | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Set the current mixing matrix. | ||
| 87 | */ | ||
| 88 | int ff_audio_mix_set_matrix(AudioMix *am, const double *matrix, int stride); | ||
| 89 | |||
| 90 | /* arch-specific initialization functions */ | ||
| 91 | |||
| 92 | void ff_audio_mix_init_x86(AudioMix *am); | ||
| 93 | |||
| 94 | #endif /* AVRESAMPLE_AUDIO_MIX_H */ | ||
| @@ -1,294 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2011 Michael Niedermayer (michaelni@gmx.at) | ||
| 3 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <stdint.h> | ||
| 23 | |||
| 24 | #include "libavutil/common.h" | ||
| 25 | #include "libavutil/libm.h" | ||
| 26 | #include "libavutil/samplefmt.h" | ||
| 27 | #include "avresample.h" | ||
| 28 | #include "internal.h" | ||
| 29 | #include "audio_data.h" | ||
| 30 | #include "audio_mix.h" | ||
| 31 | |||
| 32 | /* channel positions */ | ||
| 33 | #define FRONT_LEFT 0 | ||
| 34 | #define FRONT_RIGHT 1 | ||
| 35 | #define FRONT_CENTER 2 | ||
| 36 | #define LOW_FREQUENCY 3 | ||
| 37 | #define BACK_LEFT 4 | ||
| 38 | #define BACK_RIGHT 5 | ||
| 39 | #define FRONT_LEFT_OF_CENTER 6 | ||
| 40 | #define FRONT_RIGHT_OF_CENTER 7 | ||
| 41 | #define BACK_CENTER 8 | ||
| 42 | #define SIDE_LEFT 9 | ||
| 43 | #define SIDE_RIGHT 10 | ||
| 44 | #define TOP_CENTER 11 | ||
| 45 | #define TOP_FRONT_LEFT 12 | ||
| 46 | #define TOP_FRONT_CENTER 13 | ||
| 47 | #define TOP_FRONT_RIGHT 14 | ||
| 48 | #define TOP_BACK_LEFT 15 | ||
| 49 | #define TOP_BACK_CENTER 16 | ||
| 50 | #define TOP_BACK_RIGHT 17 | ||
| 51 | #define STEREO_LEFT 29 | ||
| 52 | #define STEREO_RIGHT 30 | ||
| 53 | #define WIDE_LEFT 31 | ||
| 54 | #define WIDE_RIGHT 32 | ||
| 55 | #define SURROUND_DIRECT_LEFT 33 | ||
| 56 | #define SURROUND_DIRECT_RIGHT 34 | ||
| 57 | #define LOW_FREQUENCY_2 35 | ||
| 58 | |||
| 59 | #define SQRT3_2 1.22474487139158904909 /* sqrt(3/2) */ | ||
| 60 | |||
| 61 | static av_always_inline int even(uint64_t layout) | ||
| 62 | { | ||
| 63 | return (!layout || !!(layout & (layout - 1))); | ||
| 64 | } | ||
| 65 | |||
| 66 | static int sane_layout(uint64_t layout) | ||
| 67 | { | ||
| 68 | /* check that there is at least 1 front speaker */ | ||
| 69 | if (!(layout & AV_CH_LAYOUT_SURROUND)) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | /* check for left/right symmetry */ | ||
| 73 | if (!even(layout & (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT)) || | ||
| 74 | !even(layout & (AV_CH_SIDE_LEFT | AV_CH_SIDE_RIGHT)) || | ||
| 75 | !even(layout & (AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT)) || | ||
| 76 | !even(layout & (AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER)) || | ||
| 77 | !even(layout & (AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT)) || | ||
| 78 | !even(layout & (AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT)) || | ||
| 79 | !even(layout & (AV_CH_STEREO_LEFT | AV_CH_STEREO_RIGHT)) || | ||
| 80 | !even(layout & (AV_CH_WIDE_LEFT | AV_CH_WIDE_RIGHT)) || | ||
| 81 | !even(layout & (AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT))) | ||
| 82 | return 0; | ||
| 83 | |||
| 84 | return 1; | ||
| 85 | } | ||
| 86 | |||
| 87 | int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, | ||
| 88 | double center_mix_level, double surround_mix_level, | ||
| 89 | double lfe_mix_level, int normalize, | ||
| 90 | double *matrix_out, int stride, | ||
| 91 | enum AVMatrixEncoding matrix_encoding) | ||
| 92 | { | ||
| 93 | int i, j, out_i, out_j; | ||
| 94 | double matrix[64][64] = {{0}}; | ||
| 95 | int64_t unaccounted; | ||
| 96 | double maxcoef = 0; | ||
| 97 | int in_channels, out_channels; | ||
| 98 | |||
| 99 | if ((out_layout & AV_CH_LAYOUT_STEREO_DOWNMIX) == AV_CH_LAYOUT_STEREO_DOWNMIX) { | ||
| 100 | out_layout = AV_CH_LAYOUT_STEREO; | ||
| 101 | } | ||
| 102 | |||
| 103 | unaccounted = in_layout & ~out_layout; | ||
| 104 | |||
| 105 | in_channels = av_get_channel_layout_nb_channels( in_layout); | ||
| 106 | out_channels = av_get_channel_layout_nb_channels(out_layout); | ||
| 107 | |||
| 108 | memset(matrix_out, 0, out_channels * stride * sizeof(*matrix_out)); | ||
| 109 | |||
| 110 | /* check if layouts are supported */ | ||
| 111 | if (!in_layout || in_channels > AVRESAMPLE_MAX_CHANNELS) | ||
| 112 | return AVERROR(EINVAL); | ||
| 113 | if (!out_layout || out_channels > AVRESAMPLE_MAX_CHANNELS) | ||
| 114 | return AVERROR(EINVAL); | ||
| 115 | |||
| 116 | /* check if layouts are unbalanced or abnormal */ | ||
| 117 | if (!sane_layout(in_layout) || !sane_layout(out_layout)) | ||
| 118 | return AVERROR_PATCHWELCOME; | ||
| 119 | |||
| 120 | /* route matching input/output channels */ | ||
| 121 | for (i = 0; i < 64; i++) { | ||
| 122 | if (in_layout & out_layout & (1ULL << i)) | ||
| 123 | matrix[i][i] = 1.0; | ||
| 124 | } | ||
| 125 | |||
| 126 | /* mix front center to front left/right */ | ||
| 127 | if (unaccounted & AV_CH_FRONT_CENTER) { | ||
| 128 | if ((out_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) { | ||
| 129 | if ((in_layout & AV_CH_LAYOUT_STEREO) == AV_CH_LAYOUT_STEREO) { | ||
| 130 | matrix[FRONT_LEFT ][FRONT_CENTER] += center_mix_level; | ||
| 131 | matrix[FRONT_RIGHT][FRONT_CENTER] += center_mix_level; | ||
| 132 | } else { | ||
| 133 | matrix[FRONT_LEFT ][FRONT_CENTER] += M_SQRT1_2; | ||
| 134 | matrix[FRONT_RIGHT][FRONT_CENTER] += M_SQRT1_2; | ||
| 135 | } | ||
| 136 | } else | ||
| 137 | return AVERROR_PATCHWELCOME; | ||
| 138 | } | ||
| 139 | /* mix front left/right to center */ | ||
| 140 | if (unaccounted & AV_CH_LAYOUT_STEREO) { | ||
| 141 | if (out_layout & AV_CH_FRONT_CENTER) { | ||
| 142 | matrix[FRONT_CENTER][FRONT_LEFT ] += M_SQRT1_2; | ||
| 143 | matrix[FRONT_CENTER][FRONT_RIGHT] += M_SQRT1_2; | ||
| 144 | /* mix left/right/center to center */ | ||
| 145 | if (in_layout & AV_CH_FRONT_CENTER) | ||
| 146 | matrix[FRONT_CENTER][FRONT_CENTER] = center_mix_level * M_SQRT2; | ||
| 147 | } else | ||
| 148 | return AVERROR_PATCHWELCOME; | ||
| 149 | } | ||
| 150 | /* mix back center to back, side, or front */ | ||
| 151 | if (unaccounted & AV_CH_BACK_CENTER) { | ||
| 152 | if (out_layout & AV_CH_BACK_LEFT) { | ||
| 153 | matrix[BACK_LEFT ][BACK_CENTER] += M_SQRT1_2; | ||
| 154 | matrix[BACK_RIGHT][BACK_CENTER] += M_SQRT1_2; | ||
| 155 | } else if (out_layout & AV_CH_SIDE_LEFT) { | ||
| 156 | matrix[SIDE_LEFT ][BACK_CENTER] += M_SQRT1_2; | ||
| 157 | matrix[SIDE_RIGHT][BACK_CENTER] += M_SQRT1_2; | ||
| 158 | } else if (out_layout & AV_CH_FRONT_LEFT) { | ||
| 159 | if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY || | ||
| 160 | matrix_encoding == AV_MATRIX_ENCODING_DPLII) { | ||
| 161 | if (unaccounted & (AV_CH_BACK_LEFT | AV_CH_SIDE_LEFT)) { | ||
| 162 | matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level * M_SQRT1_2; | ||
| 163 | matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | ||
| 164 | } else { | ||
| 165 | matrix[FRONT_LEFT ][BACK_CENTER] -= surround_mix_level; | ||
| 166 | matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level; | ||
| 167 | } | ||
| 168 | } else { | ||
| 169 | matrix[FRONT_LEFT ][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | ||
| 170 | matrix[FRONT_RIGHT][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | ||
| 171 | } | ||
| 172 | } else if (out_layout & AV_CH_FRONT_CENTER) { | ||
| 173 | matrix[FRONT_CENTER][BACK_CENTER] += surround_mix_level * M_SQRT1_2; | ||
| 174 | } else | ||
| 175 | return AVERROR_PATCHWELCOME; | ||
| 176 | } | ||
| 177 | /* mix back left/right to back center, side, or front */ | ||
| 178 | if (unaccounted & AV_CH_BACK_LEFT) { | ||
| 179 | if (out_layout & AV_CH_BACK_CENTER) { | ||
| 180 | matrix[BACK_CENTER][BACK_LEFT ] += M_SQRT1_2; | ||
| 181 | matrix[BACK_CENTER][BACK_RIGHT] += M_SQRT1_2; | ||
| 182 | } else if (out_layout & AV_CH_SIDE_LEFT) { | ||
| 183 | /* if side channels do not exist in the input, just copy back | ||
| 184 | channels to side channels, otherwise mix back into side */ | ||
| 185 | if (in_layout & AV_CH_SIDE_LEFT) { | ||
| 186 | matrix[SIDE_LEFT ][BACK_LEFT ] += M_SQRT1_2; | ||
| 187 | matrix[SIDE_RIGHT][BACK_RIGHT] += M_SQRT1_2; | ||
| 188 | } else { | ||
| 189 | matrix[SIDE_LEFT ][BACK_LEFT ] += 1.0; | ||
| 190 | matrix[SIDE_RIGHT][BACK_RIGHT] += 1.0; | ||
| 191 | } | ||
| 192 | } else if (out_layout & AV_CH_FRONT_LEFT) { | ||
| 193 | if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { | ||
| 194 | matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * M_SQRT1_2; | ||
| 195 | matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; | ||
| 196 | matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; | ||
| 197 | matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * M_SQRT1_2; | ||
| 198 | } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { | ||
| 199 | matrix[FRONT_LEFT ][BACK_LEFT ] -= surround_mix_level * SQRT3_2; | ||
| 200 | matrix[FRONT_LEFT ][BACK_RIGHT] -= surround_mix_level * M_SQRT1_2; | ||
| 201 | matrix[FRONT_RIGHT][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; | ||
| 202 | matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level * SQRT3_2; | ||
| 203 | } else { | ||
| 204 | matrix[FRONT_LEFT ][BACK_LEFT ] += surround_mix_level; | ||
| 205 | matrix[FRONT_RIGHT][BACK_RIGHT] += surround_mix_level; | ||
| 206 | } | ||
| 207 | } else if (out_layout & AV_CH_FRONT_CENTER) { | ||
| 208 | matrix[FRONT_CENTER][BACK_LEFT ] += surround_mix_level * M_SQRT1_2; | ||
| 209 | matrix[FRONT_CENTER][BACK_RIGHT] += surround_mix_level * M_SQRT1_2; | ||
| 210 | } else | ||
| 211 | return AVERROR_PATCHWELCOME; | ||
| 212 | } | ||
| 213 | /* mix side left/right into back or front */ | ||
| 214 | if (unaccounted & AV_CH_SIDE_LEFT) { | ||
| 215 | if (out_layout & AV_CH_BACK_LEFT) { | ||
| 216 | /* if back channels do not exist in the input, just copy side | ||
| 217 | channels to back channels, otherwise mix side into back */ | ||
| 218 | if (in_layout & AV_CH_BACK_LEFT) { | ||
| 219 | matrix[BACK_LEFT ][SIDE_LEFT ] += M_SQRT1_2; | ||
| 220 | matrix[BACK_RIGHT][SIDE_RIGHT] += M_SQRT1_2; | ||
| 221 | } else { | ||
| 222 | matrix[BACK_LEFT ][SIDE_LEFT ] += 1.0; | ||
| 223 | matrix[BACK_RIGHT][SIDE_RIGHT] += 1.0; | ||
| 224 | } | ||
| 225 | } else if (out_layout & AV_CH_BACK_CENTER) { | ||
| 226 | matrix[BACK_CENTER][SIDE_LEFT ] += M_SQRT1_2; | ||
| 227 | matrix[BACK_CENTER][SIDE_RIGHT] += M_SQRT1_2; | ||
| 228 | } else if (out_layout & AV_CH_FRONT_LEFT) { | ||
| 229 | if (matrix_encoding == AV_MATRIX_ENCODING_DOLBY) { | ||
| 230 | matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * M_SQRT1_2; | ||
| 231 | matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; | ||
| 232 | matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; | ||
| 233 | matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2; | ||
| 234 | } else if (matrix_encoding == AV_MATRIX_ENCODING_DPLII) { | ||
| 235 | matrix[FRONT_LEFT ][SIDE_LEFT ] -= surround_mix_level * SQRT3_2; | ||
| 236 | matrix[FRONT_LEFT ][SIDE_RIGHT] -= surround_mix_level * M_SQRT1_2; | ||
| 237 | matrix[FRONT_RIGHT][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; | ||
| 238 | matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level * SQRT3_2; | ||
| 239 | } else { | ||
| 240 | matrix[FRONT_LEFT ][SIDE_LEFT ] += surround_mix_level; | ||
| 241 | matrix[FRONT_RIGHT][SIDE_RIGHT] += surround_mix_level; | ||
| 242 | } | ||
| 243 | } else if (out_layout & AV_CH_FRONT_CENTER) { | ||
| 244 | matrix[FRONT_CENTER][SIDE_LEFT ] += surround_mix_level * M_SQRT1_2; | ||
| 245 | matrix[FRONT_CENTER][SIDE_RIGHT] += surround_mix_level * M_SQRT1_2; | ||
| 246 | } else | ||
| 247 | return AVERROR_PATCHWELCOME; | ||
| 248 | } | ||
| 249 | /* mix left-of-center/right-of-center into front left/right or center */ | ||
| 250 | if (unaccounted & AV_CH_FRONT_LEFT_OF_CENTER) { | ||
| 251 | if (out_layout & AV_CH_FRONT_LEFT) { | ||
| 252 | matrix[FRONT_LEFT ][FRONT_LEFT_OF_CENTER ] += 1.0; | ||
| 253 | matrix[FRONT_RIGHT][FRONT_RIGHT_OF_CENTER] += 1.0; | ||
| 254 | } else if (out_layout & AV_CH_FRONT_CENTER) { | ||
| 255 | matrix[FRONT_CENTER][FRONT_LEFT_OF_CENTER ] += M_SQRT1_2; | ||
| 256 | matrix[FRONT_CENTER][FRONT_RIGHT_OF_CENTER] += M_SQRT1_2; | ||
| 257 | } else | ||
| 258 | return AVERROR_PATCHWELCOME; | ||
| 259 | } | ||
| 260 | /* mix LFE into front left/right or center */ | ||
| 261 | if (unaccounted & AV_CH_LOW_FREQUENCY) { | ||
| 262 | if (out_layout & AV_CH_FRONT_CENTER) { | ||
| 263 | matrix[FRONT_CENTER][LOW_FREQUENCY] += lfe_mix_level; | ||
| 264 | } else if (out_layout & AV_CH_FRONT_LEFT) { | ||
| 265 | matrix[FRONT_LEFT ][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; | ||
| 266 | matrix[FRONT_RIGHT][LOW_FREQUENCY] += lfe_mix_level * M_SQRT1_2; | ||
| 267 | } else | ||
| 268 | return AVERROR_PATCHWELCOME; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* transfer internal matrix to output matrix and calculate maximum | ||
| 272 | per-channel coefficient sum */ | ||
| 273 | for (out_i = i = 0; out_i < out_channels && i < 64; i++) { | ||
| 274 | double sum = 0; | ||
| 275 | for (out_j = j = 0; out_j < in_channels && j < 64; j++) { | ||
| 276 | matrix_out[out_i * stride + out_j] = matrix[i][j]; | ||
| 277 | sum += fabs(matrix[i][j]); | ||
| 278 | if (in_layout & (1ULL << j)) | ||
| 279 | out_j++; | ||
| 280 | } | ||
| 281 | maxcoef = FFMAX(maxcoef, sum); | ||
| 282 | if (out_layout & (1ULL << i)) | ||
| 283 | out_i++; | ||
| 284 | } | ||
| 285 | |||
| 286 | /* normalize */ | ||
| 287 | if (normalize && maxcoef > 1.0) { | ||
| 288 | for (i = 0; i < out_channels; i++) | ||
| 289 | for (j = 0; j < in_channels; j++) | ||
| 290 | matrix_out[i * stride + j] /= maxcoef; | ||
| 291 | } | ||
| 292 | |||
| 293 | return 0; | ||
| 294 | } | ||
| @@ -1,595 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef AVRESAMPLE_AVRESAMPLE_H | ||
| 22 | #define AVRESAMPLE_AVRESAMPLE_H | ||
| 23 | |||
| 24 | /** | ||
| 25 | * @file | ||
| 26 | * @ingroup lavr | ||
| 27 | * external API header | ||
| 28 | */ | ||
| 29 | |||
| 30 | /** | ||
| 31 | * @defgroup lavr libavresample | ||
| 32 | * @{ | ||
| 33 | * | ||
| 34 | * Libavresample (lavr) is a library that handles audio resampling, sample | ||
| 35 | * format conversion and mixing. | ||
| 36 | * | ||
| 37 | * Interaction with lavr is done through AVAudioResampleContext, which is | ||
| 38 | * allocated with avresample_alloc_context(). It is opaque, so all parameters | ||
| 39 | * must be set with the @ref avoptions API. | ||
| 40 | * | ||
| 41 | * For example the following code will setup conversion from planar float sample | ||
| 42 | * format to interleaved signed 16-bit integer, downsampling from 48kHz to | ||
| 43 | * 44.1kHz and downmixing from 5.1 channels to stereo (using the default mixing | ||
| 44 | * matrix): | ||
| 45 | * @code | ||
| 46 | * AVAudioResampleContext *avr = avresample_alloc_context(); | ||
| 47 | * av_opt_set_int(avr, "in_channel_layout", AV_CH_LAYOUT_5POINT1, 0); | ||
| 48 | * av_opt_set_int(avr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); | ||
| 49 | * av_opt_set_int(avr, "in_sample_rate", 48000, 0); | ||
| 50 | * av_opt_set_int(avr, "out_sample_rate", 44100, 0); | ||
| 51 | * av_opt_set_int(avr, "in_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); | ||
| 52 | * av_opt_set_int(avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); | ||
| 53 | * @endcode | ||
| 54 | * | ||
| 55 | * Once the context is initialized, it must be opened with avresample_open(). If | ||
| 56 | * you need to change the conversion parameters, you must close the context with | ||
| 57 | * avresample_close(), change the parameters as described above, then reopen it | ||
| 58 | * again. | ||
| 59 | * | ||
| 60 | * The conversion itself is done by repeatedly calling avresample_convert(). | ||
| 61 | * Note that the samples may get buffered in two places in lavr. The first one | ||
| 62 | * is the output FIFO, where the samples end up if the output buffer is not | ||
| 63 | * large enough. The data stored in there may be retrieved at any time with | ||
| 64 | * avresample_read(). The second place is the resampling delay buffer, | ||
| 65 | * applicable only when resampling is done. The samples in it require more input | ||
| 66 | * before they can be processed. Their current amount is returned by | ||
| 67 | * avresample_get_delay(). At the end of conversion the resampling buffer can be | ||
| 68 | * flushed by calling avresample_convert() with NULL input. | ||
| 69 | * | ||
| 70 | * The following code demonstrates the conversion loop assuming the parameters | ||
| 71 | * from above and caller-defined functions get_input() and handle_output(): | ||
| 72 | * @code | ||
| 73 | * uint8_t **input; | ||
| 74 | * int in_linesize, in_samples; | ||
| 75 | * | ||
| 76 | * while (get_input(&input, &in_linesize, &in_samples)) { | ||
| 77 | * uint8_t *output | ||
| 78 | * int out_linesize; | ||
| 79 | * int out_samples = avresample_get_out_samples(avr, in_samples); | ||
| 80 | * | ||
| 81 | * av_samples_alloc(&output, &out_linesize, 2, out_samples, | ||
| 82 | * AV_SAMPLE_FMT_S16, 0); | ||
| 83 | * out_samples = avresample_convert(avr, &output, out_linesize, out_samples, | ||
| 84 | * input, in_linesize, in_samples); | ||
| 85 | * handle_output(output, out_linesize, out_samples); | ||
| 86 | * av_freep(&output); | ||
| 87 | * } | ||
| 88 | * @endcode | ||
| 89 | * | ||
| 90 | * When the conversion is finished and the FIFOs are flushed if required, the | ||
| 91 | * conversion context and everything associated with it must be freed with | ||
| 92 | * avresample_free(). | ||
| 93 | */ | ||
| 94 | |||
| 95 | #include "libavutil/avutil.h" | ||
| 96 | #include "libavutil/channel_layout.h" | ||
| 97 | #include "libavutil/dict.h" | ||
| 98 | #include "libavutil/frame.h" | ||
| 99 | #include "libavutil/log.h" | ||
| 100 | #include "libavutil/mathematics.h" | ||
| 101 | |||
| 102 | #include "libavresample/version.h" | ||
| 103 | |||
| 104 | #define AVRESAMPLE_MAX_CHANNELS 32 | ||
| 105 | |||
| 106 | typedef struct AVAudioResampleContext AVAudioResampleContext; | ||
| 107 | |||
| 108 | /** | ||
| 109 | * @deprecated use libswresample | ||
| 110 | * | ||
| 111 | * Mixing Coefficient Types */ | ||
| 112 | enum attribute_deprecated AVMixCoeffType { | ||
| 113 | AV_MIX_COEFF_TYPE_Q8, /** 16-bit 8.8 fixed-point */ | ||
| 114 | AV_MIX_COEFF_TYPE_Q15, /** 32-bit 17.15 fixed-point */ | ||
| 115 | AV_MIX_COEFF_TYPE_FLT, /** floating-point */ | ||
| 116 | AV_MIX_COEFF_TYPE_NB, /** Number of coeff types. Not part of ABI */ | ||
| 117 | }; | ||
| 118 | |||
| 119 | /** | ||
| 120 | * @deprecated use libswresample | ||
| 121 | * | ||
| 122 | * Resampling Filter Types */ | ||
| 123 | enum attribute_deprecated AVResampleFilterType { | ||
| 124 | AV_RESAMPLE_FILTER_TYPE_CUBIC, /**< Cubic */ | ||
| 125 | AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall Windowed Sinc */ | ||
| 126 | AV_RESAMPLE_FILTER_TYPE_KAISER, /**< Kaiser Windowed Sinc */ | ||
| 127 | }; | ||
| 128 | |||
| 129 | /** | ||
| 130 | * @deprecated use libswresample | ||
| 131 | */ | ||
| 132 | enum attribute_deprecated AVResampleDitherMethod { | ||
| 133 | AV_RESAMPLE_DITHER_NONE, /**< Do not use dithering */ | ||
| 134 | AV_RESAMPLE_DITHER_RECTANGULAR, /**< Rectangular Dither */ | ||
| 135 | AV_RESAMPLE_DITHER_TRIANGULAR, /**< Triangular Dither*/ | ||
| 136 | AV_RESAMPLE_DITHER_TRIANGULAR_HP, /**< Triangular Dither with High Pass */ | ||
| 137 | AV_RESAMPLE_DITHER_TRIANGULAR_NS, /**< Triangular Dither with Noise Shaping */ | ||
| 138 | AV_RESAMPLE_DITHER_NB, /**< Number of dither types. Not part of ABI. */ | ||
| 139 | }; | ||
| 140 | |||
| 141 | /** | ||
| 142 | * | ||
| 143 | * @deprecated use libswresample | ||
| 144 | * | ||
| 145 | * Return the LIBAVRESAMPLE_VERSION_INT constant. | ||
| 146 | */ | ||
| 147 | attribute_deprecated | ||
| 148 | unsigned avresample_version(void); | ||
| 149 | |||
| 150 | /** | ||
| 151 | * | ||
| 152 | * @deprecated use libswresample | ||
| 153 | * | ||
| 154 | * Return the libavresample build-time configuration. | ||
| 155 | * @return configure string | ||
| 156 | */ | ||
| 157 | attribute_deprecated | ||
| 158 | const char *avresample_configuration(void); | ||
| 159 | |||
| 160 | /** | ||
| 161 | * | ||
| 162 | * @deprecated use libswresample | ||
| 163 | * | ||
| 164 | * Return the libavresample license. | ||
| 165 | */ | ||
| 166 | attribute_deprecated | ||
| 167 | const char *avresample_license(void); | ||
| 168 | |||
| 169 | /** | ||
| 170 | * | ||
| 171 | * @deprecated use libswresample | ||
| 172 | * | ||
| 173 | * Get the AVClass for AVAudioResampleContext. | ||
| 174 | * | ||
| 175 | * Can be used in combination with AV_OPT_SEARCH_FAKE_OBJ for examining options | ||
| 176 | * without allocating a context. | ||
| 177 | * | ||
| 178 | * @see av_opt_find(). | ||
| 179 | * | ||
| 180 | * @return AVClass for AVAudioResampleContext | ||
| 181 | */ | ||
| 182 | attribute_deprecated | ||
| 183 | const AVClass *avresample_get_class(void); | ||
| 184 | |||
| 185 | /** | ||
| 186 | * | ||
| 187 | * @deprecated use libswresample | ||
| 188 | * | ||
| 189 | * Allocate AVAudioResampleContext and set options. | ||
| 190 | * | ||
| 191 | * @return allocated audio resample context, or NULL on failure | ||
| 192 | */ | ||
| 193 | attribute_deprecated | ||
| 194 | AVAudioResampleContext *avresample_alloc_context(void); | ||
| 195 | |||
| 196 | /** | ||
| 197 | * | ||
| 198 | * @deprecated use libswresample | ||
| 199 | * | ||
| 200 | * Initialize AVAudioResampleContext. | ||
| 201 | * @note The context must be configured using the AVOption API. | ||
| 202 | * @note The fields "in_channel_layout", "out_channel_layout", | ||
| 203 | * "in_sample_rate", "out_sample_rate", "in_sample_fmt", | ||
| 204 | * "out_sample_fmt" must be set. | ||
| 205 | * | ||
| 206 | * @see av_opt_set_int() | ||
| 207 | * @see av_opt_set_dict() | ||
| 208 | * @see av_get_default_channel_layout() | ||
| 209 | * | ||
| 210 | * @param avr audio resample context | ||
| 211 | * @return 0 on success, negative AVERROR code on failure | ||
| 212 | */ | ||
| 213 | attribute_deprecated | ||
| 214 | int avresample_open(AVAudioResampleContext *avr); | ||
| 215 | |||
| 216 | /** | ||
| 217 | * | ||
| 218 | * @deprecated use libswresample | ||
| 219 | * | ||
| 220 | * Check whether an AVAudioResampleContext is open or closed. | ||
| 221 | * | ||
| 222 | * @param avr AVAudioResampleContext to check | ||
| 223 | * @return 1 if avr is open, 0 if avr is closed. | ||
| 224 | */ | ||
| 225 | attribute_deprecated | ||
| 226 | int avresample_is_open(AVAudioResampleContext *avr); | ||
| 227 | |||
| 228 | /** | ||
| 229 | * | ||
| 230 | * @deprecated use libswresample | ||
| 231 | * | ||
| 232 | * Close AVAudioResampleContext. | ||
| 233 | * | ||
| 234 | * This closes the context, but it does not change the parameters. The context | ||
| 235 | * can be reopened with avresample_open(). It does, however, clear the output | ||
| 236 | * FIFO and any remaining leftover samples in the resampling delay buffer. If | ||
| 237 | * there was a custom matrix being used, that is also cleared. | ||
| 238 | * | ||
| 239 | * @see avresample_convert() | ||
| 240 | * @see avresample_set_matrix() | ||
| 241 | * | ||
| 242 | * @param avr audio resample context | ||
| 243 | */ | ||
| 244 | attribute_deprecated | ||
| 245 | void avresample_close(AVAudioResampleContext *avr); | ||
| 246 | |||
| 247 | /** | ||
| 248 | * | ||
| 249 | * @deprecated use libswresample | ||
| 250 | * | ||
| 251 | * Free AVAudioResampleContext and associated AVOption values. | ||
| 252 | * | ||
| 253 | * This also calls avresample_close() before freeing. | ||
| 254 | * | ||
| 255 | * @param avr audio resample context | ||
| 256 | */ | ||
| 257 | attribute_deprecated | ||
| 258 | void avresample_free(AVAudioResampleContext **avr); | ||
| 259 | |||
| 260 | /** | ||
| 261 | * | ||
| 262 | * @deprecated use libswresample | ||
| 263 | * | ||
| 264 | * Generate a channel mixing matrix. | ||
| 265 | * | ||
| 266 | * This function is the one used internally by libavresample for building the | ||
| 267 | * default mixing matrix. It is made public just as a utility function for | ||
| 268 | * building custom matrices. | ||
| 269 | * | ||
| 270 | * @param in_layout input channel layout | ||
| 271 | * @param out_layout output channel layout | ||
| 272 | * @param center_mix_level mix level for the center channel | ||
| 273 | * @param surround_mix_level mix level for the surround channel(s) | ||
| 274 | * @param lfe_mix_level mix level for the low-frequency effects channel | ||
| 275 | * @param normalize if 1, coefficients will be normalized to prevent | ||
| 276 | * overflow. if 0, coefficients will not be | ||
| 277 | * normalized. | ||
| 278 | * @param[out] matrix mixing coefficients; matrix[i + stride * o] is | ||
| 279 | * the weight of input channel i in output channel o. | ||
| 280 | * @param stride distance between adjacent input channels in the | ||
| 281 | * matrix array | ||
| 282 | * @param matrix_encoding matrixed stereo downmix mode (e.g. dplii) | ||
| 283 | * @return 0 on success, negative AVERROR code on failure | ||
| 284 | */ | ||
| 285 | attribute_deprecated | ||
| 286 | int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, | ||
| 287 | double center_mix_level, double surround_mix_level, | ||
| 288 | double lfe_mix_level, int normalize, double *matrix, | ||
| 289 | int stride, enum AVMatrixEncoding matrix_encoding); | ||
| 290 | |||
| 291 | /** | ||
| 292 | * | ||
| 293 | * @deprecated use libswresample | ||
| 294 | * | ||
| 295 | * Get the current channel mixing matrix. | ||
| 296 | * | ||
| 297 | * If no custom matrix has been previously set or the AVAudioResampleContext is | ||
| 298 | * not open, an error is returned. | ||
| 299 | * | ||
| 300 | * @param avr audio resample context | ||
| 301 | * @param matrix mixing coefficients; matrix[i + stride * o] is the weight of | ||
| 302 | * input channel i in output channel o. | ||
| 303 | * @param stride distance between adjacent input channels in the matrix array | ||
| 304 | * @return 0 on success, negative AVERROR code on failure | ||
| 305 | */ | ||
| 306 | attribute_deprecated | ||
| 307 | int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, | ||
| 308 | int stride); | ||
| 309 | |||
| 310 | /** | ||
| 311 | * | ||
| 312 | * @deprecated use libswresample | ||
| 313 | * | ||
| 314 | * Set channel mixing matrix. | ||
| 315 | * | ||
| 316 | * Allows for setting a custom mixing matrix, overriding the default matrix | ||
| 317 | * generated internally during avresample_open(). This function can be called | ||
| 318 | * anytime on an allocated context, either before or after calling | ||
| 319 | * avresample_open(), as long as the channel layouts have been set. | ||
| 320 | * avresample_convert() always uses the current matrix. | ||
| 321 | * Calling avresample_close() on the context will clear the current matrix. | ||
| 322 | * | ||
| 323 | * @see avresample_close() | ||
| 324 | * | ||
| 325 | * @param avr audio resample context | ||
| 326 | * @param matrix mixing coefficients; matrix[i + stride * o] is the weight of | ||
| 327 | * input channel i in output channel o. | ||
| 328 | * @param stride distance between adjacent input channels in the matrix array | ||
| 329 | * @return 0 on success, negative AVERROR code on failure | ||
| 330 | */ | ||
| 331 | attribute_deprecated | ||
| 332 | int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, | ||
| 333 | int stride); | ||
| 334 | |||
| 335 | /** | ||
| 336 | * | ||
| 337 | * @deprecated use libswresample | ||
| 338 | * | ||
| 339 | * Set a customized input channel mapping. | ||
| 340 | * | ||
| 341 | * This function can only be called when the allocated context is not open. | ||
| 342 | * Also, the input channel layout must have already been set. | ||
| 343 | * | ||
| 344 | * Calling avresample_close() on the context will clear the channel mapping. | ||
| 345 | * | ||
| 346 | * The map for each input channel specifies the channel index in the source to | ||
| 347 | * use for that particular channel, or -1 to mute the channel. Source channels | ||
| 348 | * can be duplicated by using the same index for multiple input channels. | ||
| 349 | * | ||
| 350 | * Examples: | ||
| 351 | * | ||
| 352 | * Reordering 5.1 AAC order (C,L,R,Ls,Rs,LFE) to FFmpeg order (L,R,C,LFE,Ls,Rs): | ||
| 353 | * { 1, 2, 0, 5, 3, 4 } | ||
| 354 | * | ||
| 355 | * Muting the 3rd channel in 4-channel input: | ||
| 356 | * { 0, 1, -1, 3 } | ||
| 357 | * | ||
| 358 | * Duplicating the left channel of stereo input: | ||
| 359 | * { 0, 0 } | ||
| 360 | * | ||
| 361 | * @param avr audio resample context | ||
| 362 | * @param channel_map customized input channel mapping | ||
| 363 | * @return 0 on success, negative AVERROR code on failure | ||
| 364 | */ | ||
| 365 | attribute_deprecated | ||
| 366 | int avresample_set_channel_mapping(AVAudioResampleContext *avr, | ||
| 367 | const int *channel_map); | ||
| 368 | |||
| 369 | /** | ||
| 370 | * | ||
| 371 | * @deprecated use libswresample | ||
| 372 | * | ||
| 373 | * Set compensation for resampling. | ||
| 374 | * | ||
| 375 | * This can be called anytime after avresample_open(). If resampling is not | ||
| 376 | * automatically enabled because of a sample rate conversion, the | ||
| 377 | * "force_resampling" option must have been set to 1 when opening the context | ||
| 378 | * in order to use resampling compensation. | ||
| 379 | * | ||
| 380 | * @param avr audio resample context | ||
| 381 | * @param sample_delta compensation delta, in samples | ||
| 382 | * @param compensation_distance compensation distance, in samples | ||
| 383 | * @return 0 on success, negative AVERROR code on failure | ||
| 384 | */ | ||
| 385 | attribute_deprecated | ||
| 386 | int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, | ||
| 387 | int compensation_distance); | ||
| 388 | |||
| 389 | /** | ||
| 390 | * | ||
| 391 | * @deprecated use libswresample | ||
| 392 | * | ||
| 393 | * Provide the upper bound on the number of samples the configured | ||
| 394 | * conversion would output. | ||
| 395 | * | ||
| 396 | * @param avr audio resample context | ||
| 397 | * @param in_nb_samples number of input samples | ||
| 398 | * | ||
| 399 | * @return number of samples or AVERROR(EINVAL) if the value | ||
| 400 | * would exceed INT_MAX | ||
| 401 | */ | ||
| 402 | attribute_deprecated | ||
| 403 | int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples); | ||
| 404 | |||
| 405 | /** | ||
| 406 | * | ||
| 407 | * @deprecated use libswresample | ||
| 408 | * | ||
| 409 | * Convert input samples and write them to the output FIFO. | ||
| 410 | * | ||
| 411 | * The upper bound on the number of output samples can be obtained through | ||
| 412 | * avresample_get_out_samples(). | ||
| 413 | * | ||
| 414 | * The output data can be NULL or have fewer allocated samples than required. | ||
| 415 | * In this case, any remaining samples not written to the output will be added | ||
| 416 | * to an internal FIFO buffer, to be returned at the next call to this function | ||
| 417 | * or to avresample_read(). | ||
| 418 | * | ||
| 419 | * If converting sample rate, there may be data remaining in the internal | ||
| 420 | * resampling delay buffer. avresample_get_delay() tells the number of remaining | ||
| 421 | * samples. To get this data as output, call avresample_convert() with NULL | ||
| 422 | * input. | ||
| 423 | * | ||
| 424 | * At the end of the conversion process, there may be data remaining in the | ||
| 425 | * internal FIFO buffer. avresample_available() tells the number of remaining | ||
| 426 | * samples. To get this data as output, either call avresample_convert() with | ||
| 427 | * NULL input or call avresample_read(). | ||
| 428 | * | ||
| 429 | * @see avresample_get_out_samples() | ||
| 430 | * @see avresample_read() | ||
| 431 | * @see avresample_get_delay() | ||
| 432 | * | ||
| 433 | * @param avr audio resample context | ||
| 434 | * @param output output data pointers | ||
| 435 | * @param out_plane_size output plane size, in bytes. | ||
| 436 | * This can be 0 if unknown, but that will lead to | ||
| 437 | * optimized functions not being used directly on the | ||
| 438 | * output, which could slow down some conversions. | ||
| 439 | * @param out_samples maximum number of samples that the output buffer can hold | ||
| 440 | * @param input input data pointers | ||
| 441 | * @param in_plane_size input plane size, in bytes | ||
| 442 | * This can be 0 if unknown, but that will lead to | ||
| 443 | * optimized functions not being used directly on the | ||
| 444 | * input, which could slow down some conversions. | ||
| 445 | * @param in_samples number of input samples to convert | ||
| 446 | * @return number of samples written to the output buffer, | ||
| 447 | * not including converted samples added to the internal | ||
| 448 | * output FIFO | ||
| 449 | */ | ||
| 450 | attribute_deprecated | ||
| 451 | int avresample_convert(AVAudioResampleContext *avr, uint8_t **output, | ||
| 452 | int out_plane_size, int out_samples, | ||
| 453 | uint8_t * const *input, int in_plane_size, | ||
| 454 | int in_samples); | ||
| 455 | |||
| 456 | /** | ||
| 457 | * | ||
| 458 | * @deprecated use libswresample | ||
| 459 | * | ||
| 460 | * Return the number of samples currently in the resampling delay buffer. | ||
| 461 | * | ||
| 462 | * When resampling, there may be a delay between the input and output. Any | ||
| 463 | * unconverted samples in each call are stored internally in a delay buffer. | ||
| 464 | * This function allows the user to determine the current number of samples in | ||
| 465 | * the delay buffer, which can be useful for synchronization. | ||
| 466 | * | ||
| 467 | * @see avresample_convert() | ||
| 468 | * | ||
| 469 | * @param avr audio resample context | ||
| 470 | * @return number of samples currently in the resampling delay buffer | ||
| 471 | */ | ||
| 472 | attribute_deprecated | ||
| 473 | int avresample_get_delay(AVAudioResampleContext *avr); | ||
| 474 | |||
| 475 | /** | ||
| 476 | * | ||
| 477 | * @deprecated use libswresample | ||
| 478 | * | ||
| 479 | * Return the number of available samples in the output FIFO. | ||
| 480 | * | ||
| 481 | * During conversion, if the user does not specify an output buffer or | ||
| 482 | * specifies an output buffer that is smaller than what is needed, remaining | ||
| 483 | * samples that are not written to the output are stored to an internal FIFO | ||
| 484 | * buffer. The samples in the FIFO can be read with avresample_read() or | ||
| 485 | * avresample_convert(). | ||
| 486 | * | ||
| 487 | * @see avresample_read() | ||
| 488 | * @see avresample_convert() | ||
| 489 | * | ||
| 490 | * @param avr audio resample context | ||
| 491 | * @return number of samples available for reading | ||
| 492 | */ | ||
| 493 | attribute_deprecated | ||
| 494 | int avresample_available(AVAudioResampleContext *avr); | ||
| 495 | |||
| 496 | /** | ||
| 497 | * | ||
| 498 | * @deprecated use libswresample | ||
| 499 | * | ||
| 500 | * Read samples from the output FIFO. | ||
| 501 | * | ||
| 502 | * During conversion, if the user does not specify an output buffer or | ||
| 503 | * specifies an output buffer that is smaller than what is needed, remaining | ||
| 504 | * samples that are not written to the output are stored to an internal FIFO | ||
| 505 | * buffer. This function can be used to read samples from that internal FIFO. | ||
| 506 | * | ||
| 507 | * @see avresample_available() | ||
| 508 | * @see avresample_convert() | ||
| 509 | * | ||
| 510 | * @param avr audio resample context | ||
| 511 | * @param output output data pointers. May be NULL, in which case | ||
| 512 | * nb_samples of data is discarded from output FIFO. | ||
| 513 | * @param nb_samples number of samples to read from the FIFO | ||
| 514 | * @return the number of samples written to output | ||
| 515 | */ | ||
| 516 | attribute_deprecated | ||
| 517 | int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples); | ||
| 518 | |||
| 519 | /** | ||
| 520 | * | ||
| 521 | * @deprecated use libswresample | ||
| 522 | * | ||
| 523 | * Convert the samples in the input AVFrame and write them to the output AVFrame. | ||
| 524 | * | ||
| 525 | * Input and output AVFrames must have channel_layout, sample_rate and format set. | ||
| 526 | * | ||
| 527 | * The upper bound on the number of output samples is obtained through | ||
| 528 | * avresample_get_out_samples(). | ||
| 529 | * | ||
| 530 | * If the output AVFrame does not have the data pointers allocated the nb_samples | ||
| 531 | * field will be set using avresample_get_out_samples() and av_frame_get_buffer() | ||
| 532 | * is called to allocate the frame. | ||
| 533 | * | ||
| 534 | * The output AVFrame can be NULL or have fewer allocated samples than required. | ||
| 535 | * In this case, any remaining samples not written to the output will be added | ||
| 536 | * to an internal FIFO buffer, to be returned at the next call to this function | ||
| 537 | * or to avresample_convert() or to avresample_read(). | ||
| 538 | * | ||
| 539 | * If converting sample rate, there may be data remaining in the internal | ||
| 540 | * resampling delay buffer. avresample_get_delay() tells the number of | ||
| 541 | * remaining samples. To get this data as output, call this function or | ||
| 542 | * avresample_convert() with NULL input. | ||
| 543 | * | ||
| 544 | * At the end of the conversion process, there may be data remaining in the | ||
| 545 | * internal FIFO buffer. avresample_available() tells the number of remaining | ||
| 546 | * samples. To get this data as output, either call this function or | ||
| 547 | * avresample_convert() with NULL input or call avresample_read(). | ||
| 548 | * | ||
| 549 | * If the AVAudioResampleContext configuration does not match the output and | ||
| 550 | * input AVFrame settings the conversion does not take place and depending on | ||
| 551 | * which AVFrame is not matching AVERROR_OUTPUT_CHANGED, AVERROR_INPUT_CHANGED | ||
| 552 | * or AVERROR_OUTPUT_CHANGED|AVERROR_INPUT_CHANGED is returned. | ||
| 553 | * | ||
| 554 | * @see avresample_get_out_samples() | ||
| 555 | * @see avresample_available() | ||
| 556 | * @see avresample_convert() | ||
| 557 | * @see avresample_read() | ||
| 558 | * @see avresample_get_delay() | ||
| 559 | * | ||
| 560 | * @param avr audio resample context | ||
| 561 | * @param output output AVFrame | ||
| 562 | * @param input input AVFrame | ||
| 563 | * @return 0 on success, AVERROR on failure or nonmatching | ||
| 564 | * configuration. | ||
| 565 | */ | ||
| 566 | attribute_deprecated | ||
| 567 | int avresample_convert_frame(AVAudioResampleContext *avr, | ||
| 568 | AVFrame *output, AVFrame *input); | ||
| 569 | |||
| 570 | /** | ||
| 571 | * | ||
| 572 | * @deprecated use libswresample | ||
| 573 | * | ||
| 574 | * Configure or reconfigure the AVAudioResampleContext using the information | ||
| 575 | * provided by the AVFrames. | ||
| 576 | * | ||
| 577 | * The original resampling context is reset even on failure. | ||
| 578 | * The function calls avresample_close() internally if the context is open. | ||
| 579 | * | ||
| 580 | * @see avresample_open(); | ||
| 581 | * @see avresample_close(); | ||
| 582 | * | ||
| 583 | * @param avr audio resample context | ||
| 584 | * @param out output AVFrame | ||
| 585 | * @param in input AVFrame | ||
| 586 | * @return 0 on success, AVERROR on failure. | ||
| 587 | */ | ||
| 588 | attribute_deprecated | ||
| 589 | int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in); | ||
| 590 | |||
| 591 | /** | ||
| 592 | * @} | ||
| 593 | */ | ||
| 594 | |||
| 595 | #endif /* AVRESAMPLE_AVRESAMPLE_H */ | ||
| @@ -1,55 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Windows resource file for libavresample | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 James Almer | ||
| 5 | * Copyright (C) 2013 Tiancheng "Timothy" Gu | ||
| 6 | * | ||
| 7 | * This file is part of FFmpeg. | ||
| 8 | * | ||
| 9 | * FFmpeg is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU Lesser General Public | ||
| 11 | * License as published by the Free Software Foundation; either | ||
| 12 | * version 2.1 of the License, or (at your option) any later version. | ||
| 13 | * | ||
| 14 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * Lesser General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU Lesser General Public | ||
| 20 | * License along with FFmpeg; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <windows.h> | ||
| 25 | #include "libavresample/version.h" | ||
| 26 | #include "libavutil/ffversion.h" | ||
| 27 | #include "config.h" | ||
| 28 | |||
| 29 | 1 VERSIONINFO | ||
| 30 | FILEVERSION LIBAVRESAMPLE_VERSION_MAJOR, LIBAVRESAMPLE_VERSION_MINOR, LIBAVRESAMPLE_VERSION_MICRO, 0 | ||
| 31 | PRODUCTVERSION LIBAVRESAMPLE_VERSION_MAJOR, LIBAVRESAMPLE_VERSION_MINOR, LIBAVRESAMPLE_VERSION_MICRO, 0 | ||
| 32 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK | ||
| 33 | FILEOS VOS_NT_WINDOWS32 | ||
| 34 | FILETYPE VFT_DLL | ||
| 35 | { | ||
| 36 | BLOCK "StringFileInfo" | ||
| 37 | { | ||
| 38 | BLOCK "040904B0" | ||
| 39 | { | ||
| 40 | VALUE "CompanyName", "FFmpeg Project" | ||
| 41 | VALUE "FileDescription", "Libav audio resampling library" | ||
| 42 | VALUE "FileVersion", AV_STRINGIFY(LIBAVRESAMPLE_VERSION) | ||
| 43 | VALUE "InternalName", "libavresample" | ||
| 44 | VALUE "LegalCopyright", "Copyright (C) 2000-" AV_STRINGIFY(CONFIG_THIS_YEAR) " FFmpeg Project" | ||
| 45 | VALUE "OriginalFilename", "avresample" BUILDSUF "-" AV_STRINGIFY(LIBAVRESAMPLE_VERSION_MAJOR) SLIBSUF | ||
| 46 | VALUE "ProductName", "FFmpeg" | ||
| 47 | VALUE "ProductVersion", FFMPEG_VERSION | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | BLOCK "VarFileInfo" | ||
| 52 | { | ||
| 53 | VALUE "Translation", 0x0409, 0x04B0 | ||
| 54 | } | ||
| 55 | } | ||
| @@ -1,440 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * Triangular with Noise Shaping is based on opusfile. | ||
| 5 | * Copyright (c) 1994-2012 by the Xiph.Org Foundation and contributors | ||
| 6 | * | ||
| 7 | * This file is part of FFmpeg. | ||
| 8 | * | ||
| 9 | * FFmpeg is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU Lesser General Public | ||
| 11 | * License as published by the Free Software Foundation; either | ||
| 12 | * version 2.1 of the License, or (at your option) any later version. | ||
| 13 | * | ||
| 14 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * Lesser General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU Lesser General Public | ||
| 20 | * License along with FFmpeg; if not, write to the Free Software | ||
| 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | /** | ||
| 25 | * @file | ||
| 26 | * Dithered Audio Sample Quantization | ||
| 27 | * | ||
| 28 | * Converts from dbl, flt, or s32 to s16 using dithering. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <math.h> | ||
| 32 | #include <stdint.h> | ||
| 33 | |||
| 34 | #include "libavutil/attributes.h" | ||
| 35 | #include "libavutil/common.h" | ||
| 36 | #include "libavutil/lfg.h" | ||
| 37 | #include "libavutil/mem.h" | ||
| 38 | #include "libavutil/samplefmt.h" | ||
| 39 | #include "audio_convert.h" | ||
| 40 | #include "dither.h" | ||
| 41 | #include "internal.h" | ||
| 42 | |||
| 43 | typedef struct DitherState { | ||
| 44 | int mute; | ||
| 45 | unsigned int seed; | ||
| 46 | AVLFG lfg; | ||
| 47 | float *noise_buf; | ||
| 48 | int noise_buf_size; | ||
| 49 | int noise_buf_ptr; | ||
| 50 | float dither_a[4]; | ||
| 51 | float dither_b[4]; | ||
| 52 | } DitherState; | ||
| 53 | |||
| 54 | struct DitherContext { | ||
| 55 | DitherDSPContext ddsp; | ||
| 56 | enum AVResampleDitherMethod method; | ||
| 57 | int apply_map; | ||
| 58 | ChannelMapInfo *ch_map_info; | ||
| 59 | |||
| 60 | int mute_dither_threshold; // threshold for disabling dither | ||
| 61 | int mute_reset_threshold; // threshold for resetting noise shaping | ||
| 62 | const float *ns_coef_b; // noise shaping coeffs | ||
| 63 | const float *ns_coef_a; // noise shaping coeffs | ||
| 64 | |||
| 65 | int channels; | ||
| 66 | DitherState *state; // dither states for each channel | ||
| 67 | |||
| 68 | AudioData *flt_data; // input data in fltp | ||
| 69 | AudioData *s16_data; // dithered output in s16p | ||
| 70 | AudioConvert *ac_in; // converter for input to fltp | ||
| 71 | AudioConvert *ac_out; // converter for s16p to s16 (if needed) | ||
| 72 | |||
| 73 | void (*quantize)(int16_t *dst, const float *src, float *dither, int len); | ||
| 74 | int samples_align; | ||
| 75 | }; | ||
| 76 | |||
| 77 | /* mute threshold, in seconds */ | ||
| 78 | #define MUTE_THRESHOLD_SEC 0.000333 | ||
| 79 | |||
| 80 | /* scale factor for 16-bit output. | ||
| 81 | The signal is attenuated slightly to avoid clipping */ | ||
| 82 | #define S16_SCALE 32753.0f | ||
| 83 | |||
| 84 | /* scale to convert lfg from INT_MIN/INT_MAX to -0.5/0.5 */ | ||
| 85 | #define LFG_SCALE (1.0f / (2.0f * INT32_MAX)) | ||
| 86 | |||
| 87 | /* noise shaping coefficients */ | ||
| 88 | |||
| 89 | static const float ns_48_coef_b[4] = { | ||
| 90 | 2.2374f, -0.7339f, -0.1251f, -0.6033f | ||
| 91 | }; | ||
| 92 | |||
| 93 | static const float ns_48_coef_a[4] = { | ||
| 94 | 0.9030f, 0.0116f, -0.5853f, -0.2571f | ||
| 95 | }; | ||
| 96 | |||
| 97 | static const float ns_44_coef_b[4] = { | ||
| 98 | 2.2061f, -0.4707f, -0.2534f, -0.6213f | ||
| 99 | }; | ||
| 100 | |||
| 101 | static const float ns_44_coef_a[4] = { | ||
| 102 | 1.0587f, 0.0676f, -0.6054f, -0.2738f | ||
| 103 | }; | ||
| 104 | |||
| 105 | static void dither_int_to_float_rectangular_c(float *dst, int *src, int len) | ||
| 106 | { | ||
| 107 | int i; | ||
| 108 | for (i = 0; i < len; i++) | ||
| 109 | dst[i] = src[i] * LFG_SCALE; | ||
| 110 | } | ||
| 111 | |||
| 112 | static void dither_int_to_float_triangular_c(float *dst, int *src0, int len) | ||
| 113 | { | ||
| 114 | int i; | ||
| 115 | int *src1 = src0 + len; | ||
| 116 | |||
| 117 | for (i = 0; i < len; i++) { | ||
| 118 | float r = src0[i] * LFG_SCALE; | ||
| 119 | r += src1[i] * LFG_SCALE; | ||
| 120 | dst[i] = r; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | static void quantize_c(int16_t *dst, const float *src, float *dither, int len) | ||
| 125 | { | ||
| 126 | int i; | ||
| 127 | for (i = 0; i < len; i++) | ||
| 128 | dst[i] = av_clip_int16(lrintf(src[i] * S16_SCALE + dither[i])); | ||
| 129 | } | ||
| 130 | |||
| 131 | #define SQRT_1_6 0.40824829046386301723f | ||
| 132 | |||
| 133 | static void dither_highpass_filter(float *src, int len) | ||
| 134 | { | ||
| 135 | int i; | ||
| 136 | |||
| 137 | /* filter is from libswresample in FFmpeg */ | ||
| 138 | for (i = 0; i < len - 2; i++) | ||
| 139 | src[i] = (-src[i] + 2 * src[i + 1] - src[i + 2]) * SQRT_1_6; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int generate_dither_noise(DitherContext *c, DitherState *state, | ||
| 143 | int min_samples) | ||
| 144 | { | ||
| 145 | int i; | ||
| 146 | int nb_samples = FFALIGN(min_samples, 16) + 16; | ||
| 147 | int buf_samples = nb_samples * | ||
| 148 | (c->method == AV_RESAMPLE_DITHER_RECTANGULAR ? 1 : 2); | ||
| 149 | unsigned int *noise_buf_ui; | ||
| 150 | |||
| 151 | av_freep(&state->noise_buf); | ||
| 152 | state->noise_buf_size = state->noise_buf_ptr = 0; | ||
| 153 | |||
| 154 | state->noise_buf = av_malloc(buf_samples * sizeof(*state->noise_buf)); | ||
| 155 | if (!state->noise_buf) | ||
| 156 | return AVERROR(ENOMEM); | ||
| 157 | state->noise_buf_size = FFALIGN(min_samples, 16); | ||
| 158 | noise_buf_ui = (unsigned int *)state->noise_buf; | ||
| 159 | |||
| 160 | av_lfg_init(&state->lfg, state->seed); | ||
| 161 | for (i = 0; i < buf_samples; i++) | ||
| 162 | noise_buf_ui[i] = av_lfg_get(&state->lfg); | ||
| 163 | |||
| 164 | c->ddsp.dither_int_to_float(state->noise_buf, noise_buf_ui, nb_samples); | ||
| 165 | |||
| 166 | if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_HP) | ||
| 167 | dither_highpass_filter(state->noise_buf, nb_samples); | ||
| 168 | |||
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | static void quantize_triangular_ns(DitherContext *c, DitherState *state, | ||
| 173 | int16_t *dst, const float *src, | ||
| 174 | int nb_samples) | ||
| 175 | { | ||
| 176 | int i, j; | ||
| 177 | float *dither = &state->noise_buf[state->noise_buf_ptr]; | ||
| 178 | |||
| 179 | if (state->mute > c->mute_reset_threshold) | ||
| 180 | memset(state->dither_a, 0, sizeof(state->dither_a)); | ||
| 181 | |||
| 182 | for (i = 0; i < nb_samples; i++) { | ||
| 183 | float err = 0; | ||
| 184 | float sample = src[i] * S16_SCALE; | ||
| 185 | |||
| 186 | for (j = 0; j < 4; j++) { | ||
| 187 | err += c->ns_coef_b[j] * state->dither_b[j] - | ||
| 188 | c->ns_coef_a[j] * state->dither_a[j]; | ||
| 189 | } | ||
| 190 | for (j = 3; j > 0; j--) { | ||
| 191 | state->dither_a[j] = state->dither_a[j - 1]; | ||
| 192 | state->dither_b[j] = state->dither_b[j - 1]; | ||
| 193 | } | ||
| 194 | state->dither_a[0] = err; | ||
| 195 | sample -= err; | ||
| 196 | |||
| 197 | if (state->mute > c->mute_dither_threshold) { | ||
| 198 | dst[i] = av_clip_int16(lrintf(sample)); | ||
| 199 | state->dither_b[0] = 0; | ||
| 200 | } else { | ||
| 201 | dst[i] = av_clip_int16(lrintf(sample + dither[i])); | ||
| 202 | state->dither_b[0] = av_clipf(dst[i] - sample, -1.5f, 1.5f); | ||
| 203 | } | ||
| 204 | |||
| 205 | state->mute++; | ||
| 206 | if (src[i]) | ||
| 207 | state->mute = 0; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | static int convert_samples(DitherContext *c, int16_t **dst, float * const *src, | ||
| 212 | int channels, int nb_samples) | ||
| 213 | { | ||
| 214 | int ch, ret; | ||
| 215 | int aligned_samples = FFALIGN(nb_samples, 16); | ||
| 216 | |||
| 217 | for (ch = 0; ch < channels; ch++) { | ||
| 218 | DitherState *state = &c->state[ch]; | ||
| 219 | |||
| 220 | if (state->noise_buf_size < aligned_samples) { | ||
| 221 | ret = generate_dither_noise(c, state, nb_samples); | ||
| 222 | if (ret < 0) | ||
| 223 | return ret; | ||
| 224 | } else if (state->noise_buf_size - state->noise_buf_ptr < aligned_samples) { | ||
| 225 | state->noise_buf_ptr = 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_NS) { | ||
| 229 | quantize_triangular_ns(c, state, dst[ch], src[ch], nb_samples); | ||
| 230 | } else { | ||
| 231 | c->quantize(dst[ch], src[ch], | ||
| 232 | &state->noise_buf[state->noise_buf_ptr], | ||
| 233 | FFALIGN(nb_samples, c->samples_align)); | ||
| 234 | } | ||
| 235 | |||
| 236 | state->noise_buf_ptr += aligned_samples; | ||
| 237 | } | ||
| 238 | |||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src) | ||
| 243 | { | ||
| 244 | int ret; | ||
| 245 | AudioData *flt_data; | ||
| 246 | |||
| 247 | /* output directly to dst if it is planar */ | ||
| 248 | if (dst->sample_fmt == AV_SAMPLE_FMT_S16P) | ||
| 249 | c->s16_data = dst; | ||
| 250 | else { | ||
| 251 | /* make sure s16_data is large enough for the output */ | ||
| 252 | ret = ff_audio_data_realloc(c->s16_data, src->nb_samples); | ||
| 253 | if (ret < 0) | ||
| 254 | return ret; | ||
| 255 | } | ||
| 256 | |||
| 257 | if (src->sample_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) { | ||
| 258 | /* make sure flt_data is large enough for the input */ | ||
| 259 | ret = ff_audio_data_realloc(c->flt_data, src->nb_samples); | ||
| 260 | if (ret < 0) | ||
| 261 | return ret; | ||
| 262 | flt_data = c->flt_data; | ||
| 263 | } | ||
| 264 | |||
| 265 | if (src->sample_fmt != AV_SAMPLE_FMT_FLTP) { | ||
| 266 | /* convert input samples to fltp and scale to s16 range */ | ||
| 267 | ret = ff_audio_convert(c->ac_in, flt_data, src); | ||
| 268 | if (ret < 0) | ||
| 269 | return ret; | ||
| 270 | } else if (c->apply_map) { | ||
| 271 | ret = ff_audio_data_copy(flt_data, src, c->ch_map_info); | ||
| 272 | if (ret < 0) | ||
| 273 | return ret; | ||
| 274 | } else { | ||
| 275 | flt_data = src; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* check alignment and padding constraints */ | ||
| 279 | if (c->method != AV_RESAMPLE_DITHER_TRIANGULAR_NS) { | ||
| 280 | int ptr_align = FFMIN(flt_data->ptr_align, c->s16_data->ptr_align); | ||
| 281 | int samples_align = FFMIN(flt_data->samples_align, c->s16_data->samples_align); | ||
| 282 | int aligned_len = FFALIGN(src->nb_samples, c->ddsp.samples_align); | ||
| 283 | |||
| 284 | if (!(ptr_align % c->ddsp.ptr_align) && samples_align >= aligned_len) { | ||
| 285 | c->quantize = c->ddsp.quantize; | ||
| 286 | c->samples_align = c->ddsp.samples_align; | ||
| 287 | } else { | ||
| 288 | c->quantize = quantize_c; | ||
| 289 | c->samples_align = 1; | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | ret = convert_samples(c, (int16_t **)c->s16_data->data, | ||
| 294 | (float * const *)flt_data->data, src->channels, | ||
| 295 | src->nb_samples); | ||
| 296 | if (ret < 0) | ||
| 297 | return ret; | ||
| 298 | |||
| 299 | c->s16_data->nb_samples = src->nb_samples; | ||
| 300 | |||
| 301 | /* interleave output to dst if needed */ | ||
| 302 | if (dst->sample_fmt == AV_SAMPLE_FMT_S16) { | ||
| 303 | ret = ff_audio_convert(c->ac_out, dst, c->s16_data); | ||
| 304 | if (ret < 0) | ||
| 305 | return ret; | ||
| 306 | } else | ||
| 307 | c->s16_data = NULL; | ||
| 308 | |||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | void ff_dither_free(DitherContext **cp) | ||
| 313 | { | ||
| 314 | DitherContext *c = *cp; | ||
| 315 | int ch; | ||
| 316 | |||
| 317 | if (!c) | ||
| 318 | return; | ||
| 319 | ff_audio_data_free(&c->flt_data); | ||
| 320 | ff_audio_data_free(&c->s16_data); | ||
| 321 | ff_audio_convert_free(&c->ac_in); | ||
| 322 | ff_audio_convert_free(&c->ac_out); | ||
| 323 | for (ch = 0; ch < c->channels; ch++) | ||
| 324 | av_free(c->state[ch].noise_buf); | ||
| 325 | av_free(c->state); | ||
| 326 | av_freep(cp); | ||
| 327 | } | ||
| 328 | |||
| 329 | static av_cold void dither_init(DitherDSPContext *ddsp, | ||
| 330 | enum AVResampleDitherMethod method) | ||
| 331 | { | ||
| 332 | ddsp->quantize = quantize_c; | ||
| 333 | ddsp->ptr_align = 1; | ||
| 334 | ddsp->samples_align = 1; | ||
| 335 | |||
| 336 | if (method == AV_RESAMPLE_DITHER_RECTANGULAR) | ||
| 337 | ddsp->dither_int_to_float = dither_int_to_float_rectangular_c; | ||
| 338 | else | ||
| 339 | ddsp->dither_int_to_float = dither_int_to_float_triangular_c; | ||
| 340 | |||
| 341 | if (ARCH_X86) | ||
| 342 | ff_dither_init_x86(ddsp, method); | ||
| 343 | } | ||
| 344 | |||
| 345 | DitherContext *ff_dither_alloc(AVAudioResampleContext *avr, | ||
| 346 | enum AVSampleFormat out_fmt, | ||
| 347 | enum AVSampleFormat in_fmt, | ||
| 348 | int channels, int sample_rate, int apply_map) | ||
| 349 | { | ||
| 350 | AVLFG seed_gen; | ||
| 351 | DitherContext *c; | ||
| 352 | int ch; | ||
| 353 | |||
| 354 | if (av_get_packed_sample_fmt(out_fmt) != AV_SAMPLE_FMT_S16 || | ||
| 355 | av_get_bytes_per_sample(in_fmt) <= 2) { | ||
| 356 | av_log(avr, AV_LOG_ERROR, "dithering %s to %s is not supported\n", | ||
| 357 | av_get_sample_fmt_name(in_fmt), av_get_sample_fmt_name(out_fmt)); | ||
| 358 | return NULL; | ||
| 359 | } | ||
| 360 | |||
| 361 | c = av_mallocz(sizeof(*c)); | ||
| 362 | if (!c) | ||
| 363 | return NULL; | ||
| 364 | |||
| 365 | c->apply_map = apply_map; | ||
| 366 | if (apply_map) | ||
| 367 | c->ch_map_info = &avr->ch_map_info; | ||
| 368 | |||
| 369 | if (avr->dither_method == AV_RESAMPLE_DITHER_TRIANGULAR_NS && | ||
| 370 | sample_rate != 48000 && sample_rate != 44100) { | ||
| 371 | av_log(avr, AV_LOG_WARNING, "sample rate must be 48000 or 44100 Hz " | ||
| 372 | "for triangular_ns dither. using triangular_hp instead.\n"); | ||
| 373 | avr->dither_method = AV_RESAMPLE_DITHER_TRIANGULAR_HP; | ||
| 374 | } | ||
| 375 | c->method = avr->dither_method; | ||
| 376 | dither_init(&c->ddsp, c->method); | ||
| 377 | |||
| 378 | if (c->method == AV_RESAMPLE_DITHER_TRIANGULAR_NS) { | ||
| 379 | if (sample_rate == 48000) { | ||
| 380 | c->ns_coef_b = ns_48_coef_b; | ||
| 381 | c->ns_coef_a = ns_48_coef_a; | ||
| 382 | } else { | ||
| 383 | c->ns_coef_b = ns_44_coef_b; | ||
| 384 | c->ns_coef_a = ns_44_coef_a; | ||
| 385 | } | ||
| 386 | } | ||
| 387 | |||
| 388 | /* Either s16 or s16p output format is allowed, but s16p is used | ||
| 389 | internally, so we need to use a temp buffer and interleave if the output | ||
| 390 | format is s16 */ | ||
| 391 | if (out_fmt != AV_SAMPLE_FMT_S16P) { | ||
| 392 | c->s16_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_S16P, | ||
| 393 | "dither s16 buffer"); | ||
| 394 | if (!c->s16_data) | ||
| 395 | goto fail; | ||
| 396 | |||
| 397 | c->ac_out = ff_audio_convert_alloc(avr, out_fmt, AV_SAMPLE_FMT_S16P, | ||
| 398 | channels, sample_rate, 0); | ||
| 399 | if (!c->ac_out) | ||
| 400 | goto fail; | ||
| 401 | } | ||
| 402 | |||
| 403 | if (in_fmt != AV_SAMPLE_FMT_FLTP || c->apply_map) { | ||
| 404 | c->flt_data = ff_audio_data_alloc(channels, 1024, AV_SAMPLE_FMT_FLTP, | ||
| 405 | "dither flt buffer"); | ||
| 406 | if (!c->flt_data) | ||
| 407 | goto fail; | ||
| 408 | } | ||
| 409 | if (in_fmt != AV_SAMPLE_FMT_FLTP) { | ||
| 410 | c->ac_in = ff_audio_convert_alloc(avr, AV_SAMPLE_FMT_FLTP, in_fmt, | ||
| 411 | channels, sample_rate, c->apply_map); | ||
| 412 | if (!c->ac_in) | ||
| 413 | goto fail; | ||
| 414 | } | ||
| 415 | |||
| 416 | c->state = av_mallocz(channels * sizeof(*c->state)); | ||
| 417 | if (!c->state) | ||
| 418 | goto fail; | ||
| 419 | c->channels = channels; | ||
| 420 | |||
| 421 | /* calculate thresholds for turning off dithering during periods of | ||
| 422 | silence to avoid replacing digital silence with quiet dither noise */ | ||
| 423 | c->mute_dither_threshold = lrintf(sample_rate * MUTE_THRESHOLD_SEC); | ||
| 424 | c->mute_reset_threshold = c->mute_dither_threshold * 4; | ||
| 425 | |||
| 426 | /* initialize dither states */ | ||
| 427 | av_lfg_init(&seed_gen, 0xC0FFEE); | ||
| 428 | for (ch = 0; ch < channels; ch++) { | ||
| 429 | DitherState *state = &c->state[ch]; | ||
| 430 | state->mute = c->mute_reset_threshold + 1; | ||
| 431 | state->seed = av_lfg_get(&seed_gen); | ||
| 432 | generate_dither_noise(c, state, FFMAX(32768, sample_rate / 2)); | ||
| 433 | } | ||
| 434 | |||
| 435 | return c; | ||
| 436 | |||
| 437 | fail: | ||
| 438 | ff_dither_free(&c); | ||
| 439 | return NULL; | ||
| 440 | } | ||
| @@ -1,93 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef AVRESAMPLE_DITHER_H | ||
| 22 | #define AVRESAMPLE_DITHER_H | ||
| 23 | |||
| 24 | #include "avresample.h" | ||
| 25 | #include "audio_data.h" | ||
| 26 | |||
| 27 | typedef struct DitherContext DitherContext; | ||
| 28 | |||
| 29 | typedef struct DitherDSPContext { | ||
| 30 | /** | ||
| 31 | * Convert samples from flt to s16 with added dither noise. | ||
| 32 | * | ||
| 33 | * @param dst destination float array, range -0.5 to 0.5 | ||
| 34 | * @param src source int array, range INT_MIN to INT_MAX. | ||
| 35 | * @param dither float dither noise array | ||
| 36 | * @param len number of samples | ||
| 37 | */ | ||
| 38 | void (*quantize)(int16_t *dst, const float *src, float *dither, int len); | ||
| 39 | |||
| 40 | int ptr_align; ///< src and dst constraints for quantize() | ||
| 41 | int samples_align; ///< len constraints for quantize() | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Convert dither noise from int to float with triangular distribution. | ||
| 45 | * | ||
| 46 | * @param dst destination float array, range -0.5 to 0.5 | ||
| 47 | * constraints: 32-byte aligned | ||
| 48 | * @param src0 source int array, range INT_MIN to INT_MAX. | ||
| 49 | * the array size is len * 2 | ||
| 50 | * constraints: 32-byte aligned | ||
| 51 | * @param len number of output noise samples | ||
| 52 | * constraints: multiple of 16 | ||
| 53 | */ | ||
| 54 | void (*dither_int_to_float)(float *dst, int *src0, int len); | ||
| 55 | } DitherDSPContext; | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Allocate and initialize a DitherContext. | ||
| 59 | * | ||
| 60 | * The parameters in the AVAudioResampleContext are used to initialize the | ||
| 61 | * DitherContext. | ||
| 62 | * | ||
| 63 | * @param avr AVAudioResampleContext | ||
| 64 | * @return newly-allocated DitherContext | ||
| 65 | */ | ||
| 66 | DitherContext *ff_dither_alloc(AVAudioResampleContext *avr, | ||
| 67 | enum AVSampleFormat out_fmt, | ||
| 68 | enum AVSampleFormat in_fmt, | ||
| 69 | int channels, int sample_rate, int apply_map); | ||
| 70 | |||
| 71 | /** | ||
| 72 | * Free a DitherContext. | ||
| 73 | * | ||
| 74 | * @param c DitherContext | ||
| 75 | */ | ||
| 76 | void ff_dither_free(DitherContext **c); | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Convert audio sample format with dithering. | ||
| 80 | * | ||
| 81 | * @param c DitherContext | ||
| 82 | * @param dst destination audio data | ||
| 83 | * @param src source audio data | ||
| 84 | * @return 0 if ok, negative AVERROR code on failure | ||
| 85 | */ | ||
| 86 | int ff_convert_dither(DitherContext *c, AudioData *dst, AudioData *src); | ||
| 87 | |||
| 88 | /* arch-specific initialization functions */ | ||
| 89 | |||
| 90 | void ff_dither_init_x86(DitherDSPContext *ddsp, | ||
| 91 | enum AVResampleDitherMethod method); | ||
| 92 | |||
| 93 | #endif /* AVRESAMPLE_DITHER_H */ | ||
| @@ -1,116 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef AVRESAMPLE_INTERNAL_H | ||
| 22 | #define AVRESAMPLE_INTERNAL_H | ||
| 23 | |||
| 24 | #include "libavutil/audio_fifo.h" | ||
| 25 | #include "libavutil/log.h" | ||
| 26 | #include "libavutil/opt.h" | ||
| 27 | #include "libavutil/samplefmt.h" | ||
| 28 | #include "avresample.h" | ||
| 29 | |||
| 30 | typedef struct AudioData AudioData; | ||
| 31 | typedef struct AudioConvert AudioConvert; | ||
| 32 | typedef struct AudioMix AudioMix; | ||
| 33 | typedef struct ResampleContext ResampleContext; | ||
| 34 | |||
| 35 | enum RemapPoint { | ||
| 36 | REMAP_NONE, | ||
| 37 | REMAP_IN_COPY, | ||
| 38 | REMAP_IN_CONVERT, | ||
| 39 | REMAP_OUT_COPY, | ||
| 40 | REMAP_OUT_CONVERT, | ||
| 41 | }; | ||
| 42 | |||
| 43 | typedef struct ChannelMapInfo { | ||
| 44 | int channel_map[AVRESAMPLE_MAX_CHANNELS]; /**< source index of each output channel, -1 if not remapped */ | ||
| 45 | int do_remap; /**< remap needed */ | ||
| 46 | int channel_copy[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to copy from */ | ||
| 47 | int do_copy; /**< copy needed */ | ||
| 48 | int channel_zero[AVRESAMPLE_MAX_CHANNELS]; /**< dest index to zero */ | ||
| 49 | int do_zero; /**< zeroing needed */ | ||
| 50 | int input_map[AVRESAMPLE_MAX_CHANNELS]; /**< dest index of each input channel */ | ||
| 51 | } ChannelMapInfo; | ||
| 52 | |||
| 53 | struct AVAudioResampleContext { | ||
| 54 | const AVClass *av_class; /**< AVClass for logging and AVOptions */ | ||
| 55 | |||
| 56 | uint64_t in_channel_layout; /**< input channel layout */ | ||
| 57 | enum AVSampleFormat in_sample_fmt; /**< input sample format */ | ||
| 58 | int in_sample_rate; /**< input sample rate */ | ||
| 59 | uint64_t out_channel_layout; /**< output channel layout */ | ||
| 60 | enum AVSampleFormat out_sample_fmt; /**< output sample format */ | ||
| 61 | int out_sample_rate; /**< output sample rate */ | ||
| 62 | enum AVSampleFormat internal_sample_fmt; /**< internal sample format */ | ||
| 63 | enum AVMixCoeffType mix_coeff_type; /**< mixing coefficient type */ | ||
| 64 | double center_mix_level; /**< center mix level */ | ||
| 65 | double surround_mix_level; /**< surround mix level */ | ||
| 66 | double lfe_mix_level; /**< lfe mix level */ | ||
| 67 | int normalize_mix_level; /**< enable mix level normalization */ | ||
| 68 | int force_resampling; /**< force resampling */ | ||
| 69 | int filter_size; /**< length of each FIR filter in the resampling filterbank relative to the cutoff frequency */ | ||
| 70 | int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */ | ||
| 71 | int linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */ | ||
| 72 | double cutoff; /**< resampling cutoff frequency. 1.0 corresponds to half the output sample rate */ | ||
| 73 | enum AVResampleFilterType filter_type; /**< resampling filter type */ | ||
| 74 | int kaiser_beta; /**< beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */ | ||
| 75 | enum AVResampleDitherMethod dither_method; /**< dither method */ | ||
| 76 | |||
| 77 | int in_channels; /**< number of input channels */ | ||
| 78 | int out_channels; /**< number of output channels */ | ||
| 79 | int resample_channels; /**< number of channels used for resampling */ | ||
| 80 | int downmix_needed; /**< downmixing is needed */ | ||
| 81 | int upmix_needed; /**< upmixing is needed */ | ||
| 82 | int mixing_needed; /**< either upmixing or downmixing is needed */ | ||
| 83 | int resample_needed; /**< resampling is needed */ | ||
| 84 | int in_convert_needed; /**< input sample format conversion is needed */ | ||
| 85 | int out_convert_needed; /**< output sample format conversion is needed */ | ||
| 86 | int in_copy_needed; /**< input data copy is needed */ | ||
| 87 | |||
| 88 | AudioData *in_buffer; /**< buffer for converted input */ | ||
| 89 | AudioData *resample_out_buffer; /**< buffer for output from resampler */ | ||
| 90 | AudioData *out_buffer; /**< buffer for converted output */ | ||
| 91 | AVAudioFifo *out_fifo; /**< FIFO for output samples */ | ||
| 92 | |||
| 93 | AudioConvert *ac_in; /**< input sample format conversion context */ | ||
| 94 | AudioConvert *ac_out; /**< output sample format conversion context */ | ||
| 95 | ResampleContext *resample; /**< resampling context */ | ||
| 96 | AudioMix *am; /**< channel mixing context */ | ||
| 97 | enum AVMatrixEncoding matrix_encoding; /**< matrixed stereo encoding */ | ||
| 98 | |||
| 99 | /** | ||
| 100 | * mix matrix | ||
| 101 | * only used if avresample_set_matrix() is called before avresample_open() | ||
| 102 | */ | ||
| 103 | double *mix_matrix; | ||
| 104 | |||
| 105 | int use_channel_map; | ||
| 106 | enum RemapPoint remap_point; | ||
| 107 | ChannelMapInfo ch_map_info; | ||
| 108 | }; | ||
| 109 | |||
| 110 | |||
| 111 | void ff_audio_resample_init_aarch64(ResampleContext *c, | ||
| 112 | enum AVSampleFormat sample_fmt); | ||
| 113 | void ff_audio_resample_init_arm(ResampleContext *c, | ||
| 114 | enum AVSampleFormat sample_fmt); | ||
| 115 | |||
| 116 | #endif /* AVRESAMPLE_INTERNAL_H */ | ||
| @@ -1,6 +0,0 @@ | |||
| 1 | LIBAVRESAMPLE_MAJOR { | ||
| 2 | global: | ||
| 3 | av*; | ||
| 4 | local: | ||
| 5 | *; | ||
| 6 | }; | ||
| @@ -1,113 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <stdint.h> | ||
| 22 | |||
| 23 | #include "libavutil/mathematics.h" | ||
| 24 | #include "libavutil/mem.h" | ||
| 25 | #include "libavutil/opt.h" | ||
| 26 | #include "avresample.h" | ||
| 27 | #include "internal.h" | ||
| 28 | #include "audio_mix.h" | ||
| 29 | |||
| 30 | /** | ||
| 31 | * @file | ||
| 32 | * Options definition for AVAudioResampleContext. | ||
| 33 | */ | ||
| 34 | |||
| 35 | #define OFFSET(x) offsetof(AVAudioResampleContext, x) | ||
| 36 | #define PARAM AV_OPT_FLAG_AUDIO_PARAM | ||
| 37 | |||
| 38 | static const AVOption avresample_options[] = { | ||
| 39 | { "in_channel_layout", "Input Channel Layout", OFFSET(in_channel_layout), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, PARAM }, | ||
| 40 | { "in_sample_fmt", "Input Sample Format", OFFSET(in_sample_fmt), AV_OPT_TYPE_INT, { .i64 = AV_SAMPLE_FMT_S16 }, AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NB-1, PARAM }, | ||
| 41 | { "in_sample_rate", "Input Sample Rate", OFFSET(in_sample_rate), AV_OPT_TYPE_INT, { .i64 = 48000 }, 1, INT_MAX, PARAM }, | ||
| 42 | { "out_channel_layout", "Output Channel Layout", OFFSET(out_channel_layout), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, PARAM }, | ||
| 43 | { "out_sample_fmt", "Output Sample Format", OFFSET(out_sample_fmt), AV_OPT_TYPE_INT, { .i64 = AV_SAMPLE_FMT_S16 }, AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NB-1, PARAM }, | ||
| 44 | { "out_sample_rate", "Output Sample Rate", OFFSET(out_sample_rate), AV_OPT_TYPE_INT, { .i64 = 48000 }, 1, INT_MAX, PARAM }, | ||
| 45 | { "internal_sample_fmt", "Internal Sample Format", OFFSET(internal_sample_fmt), AV_OPT_TYPE_INT, { .i64 = AV_SAMPLE_FMT_NONE }, AV_SAMPLE_FMT_NONE, AV_SAMPLE_FMT_NB-1, PARAM, "internal_sample_fmt" }, | ||
| 46 | {"u8" , "8-bit unsigned integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_U8 }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 47 | {"s16", "16-bit signed integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S16 }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 48 | {"s32", "32-bit signed integer", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S32 }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 49 | {"flt", "32-bit float", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_FLT }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 50 | {"dbl", "64-bit double", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_DBL }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 51 | {"u8p" , "8-bit unsigned integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_U8P }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 52 | {"s16p", "16-bit signed integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S16P }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 53 | {"s32p", "32-bit signed integer planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_S32P }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 54 | {"fltp", "32-bit float planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_FLTP }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 55 | {"dblp", "64-bit double planar", 0, AV_OPT_TYPE_CONST, {.i64 = AV_SAMPLE_FMT_DBLP }, INT_MIN, INT_MAX, PARAM, "internal_sample_fmt"}, | ||
| 56 | { "mix_coeff_type", "Mixing Coefficient Type", OFFSET(mix_coeff_type), AV_OPT_TYPE_INT, { .i64 = AV_MIX_COEFF_TYPE_FLT }, AV_MIX_COEFF_TYPE_Q8, AV_MIX_COEFF_TYPE_NB-1, PARAM, "mix_coeff_type" }, | ||
| 57 | { "q8", "16-bit 8.8 Fixed-Point", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MIX_COEFF_TYPE_Q8 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, | ||
| 58 | { "q15", "32-bit 17.15 Fixed-Point", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MIX_COEFF_TYPE_Q15 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, | ||
| 59 | { "flt", "Floating-Point", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MIX_COEFF_TYPE_FLT }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, | ||
| 60 | { "center_mix_level", "Center Mix Level", OFFSET(center_mix_level), AV_OPT_TYPE_DOUBLE, { .dbl = M_SQRT1_2 }, -32.0, 32.0, PARAM }, | ||
| 61 | { "surround_mix_level", "Surround Mix Level", OFFSET(surround_mix_level), AV_OPT_TYPE_DOUBLE, { .dbl = M_SQRT1_2 }, -32.0, 32.0, PARAM }, | ||
| 62 | { "lfe_mix_level", "LFE Mix Level", OFFSET(lfe_mix_level), AV_OPT_TYPE_DOUBLE, { .dbl = 0.0 }, -32.0, 32.0, PARAM }, | ||
| 63 | { "normalize_mix_level", "Normalize Mix Level", OFFSET(normalize_mix_level), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, PARAM }, | ||
| 64 | { "force_resampling", "Force Resampling", OFFSET(force_resampling), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, PARAM }, | ||
| 65 | { "filter_size", "Resampling Filter Size", OFFSET(filter_size), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 32, /* ??? */ PARAM }, | ||
| 66 | { "phase_shift", "Resampling Phase Shift", OFFSET(phase_shift), AV_OPT_TYPE_INT, { .i64 = 10 }, 0, 30, /* ??? */ PARAM }, | ||
| 67 | { "linear_interp", "Use Linear Interpolation", OFFSET(linear_interp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, PARAM }, | ||
| 68 | { "cutoff", "Cutoff Frequency Ratio", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, { .dbl = 0.8 }, 0.0, 1.0, PARAM }, | ||
| 69 | /* duplicate option in order to work with avconv */ | ||
| 70 | { "resample_cutoff", "Cutoff Frequency Ratio", OFFSET(cutoff), AV_OPT_TYPE_DOUBLE, { .dbl = 0.8 }, 0.0, 1.0, PARAM }, | ||
| 71 | { "matrix_encoding", "Matrixed Stereo Encoding", OFFSET(matrix_encoding), AV_OPT_TYPE_INT, {.i64 = AV_MATRIX_ENCODING_NONE}, AV_MATRIX_ENCODING_NONE, AV_MATRIX_ENCODING_NB-1, PARAM, "matrix_encoding" }, | ||
| 72 | { "none", "None", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_NONE }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, | ||
| 73 | { "dolby", "Dolby", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DOLBY }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, | ||
| 74 | { "dplii", "Dolby Pro Logic II", 0, AV_OPT_TYPE_CONST, { .i64 = AV_MATRIX_ENCODING_DPLII }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, | ||
| 75 | { "filter_type", "Filter Type", OFFSET(filter_type), AV_OPT_TYPE_INT, { .i64 = AV_RESAMPLE_FILTER_TYPE_KAISER }, AV_RESAMPLE_FILTER_TYPE_CUBIC, AV_RESAMPLE_FILTER_TYPE_KAISER, PARAM, "filter_type" }, | ||
| 76 | { "cubic", "Cubic", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_FILTER_TYPE_CUBIC }, INT_MIN, INT_MAX, PARAM, "filter_type" }, | ||
| 77 | { "blackman_nuttall", "Blackman Nuttall Windowed Sinc", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, "filter_type" }, | ||
| 78 | { "kaiser", "Kaiser Windowed Sinc", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_FILTER_TYPE_KAISER }, INT_MIN, INT_MAX, PARAM, "filter_type" }, | ||
| 79 | { "kaiser_beta", "Kaiser Window Beta", OFFSET(kaiser_beta), AV_OPT_TYPE_INT, { .i64 = 9 }, 2, 16, PARAM }, | ||
| 80 | { "dither_method", "Dither Method", OFFSET(dither_method), AV_OPT_TYPE_INT, { .i64 = AV_RESAMPLE_DITHER_NONE }, 0, AV_RESAMPLE_DITHER_NB-1, PARAM, "dither_method"}, | ||
| 81 | {"none", "No Dithering", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_NONE }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | ||
| 82 | {"rectangular", "Rectangular Dither", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_RECTANGULAR }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | ||
| 83 | {"triangular", "Triangular Dither", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | ||
| 84 | {"triangular_hp", "Triangular Dither With High Pass", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR_HP }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | ||
| 85 | {"triangular_ns", "Triangular Dither With Noise Shaping", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR_NS }, INT_MIN, INT_MAX, PARAM, "dither_method"}, | ||
| 86 | { NULL }, | ||
| 87 | }; | ||
| 88 | |||
| 89 | static const AVClass av_resample_context_class = { | ||
| 90 | .class_name = "AVAudioResampleContext", | ||
| 91 | .item_name = av_default_item_name, | ||
| 92 | .option = avresample_options, | ||
| 93 | .version = LIBAVUTIL_VERSION_INT, | ||
| 94 | }; | ||
| 95 | |||
| 96 | AVAudioResampleContext *avresample_alloc_context(void) | ||
| 97 | { | ||
| 98 | AVAudioResampleContext *avr; | ||
| 99 | |||
| 100 | avr = av_mallocz(sizeof(*avr)); | ||
| 101 | if (!avr) | ||
| 102 | return NULL; | ||
| 103 | |||
| 104 | avr->av_class = &av_resample_context_class; | ||
| 105 | av_opt_set_defaults(avr); | ||
| 106 | |||
| 107 | return avr; | ||
| 108 | } | ||
| 109 | |||
| 110 | const AVClass *avresample_get_class(void) | ||
| 111 | { | ||
| 112 | return &av_resample_context_class; | ||
| 113 | } | ||
| @@ -1,446 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> | ||
| 3 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "libavutil/common.h" | ||
| 23 | #include "libavutil/libm.h" | ||
| 24 | #include "libavutil/log.h" | ||
| 25 | #include "internal.h" | ||
| 26 | #include "resample.h" | ||
| 27 | #include "audio_data.h" | ||
| 28 | |||
| 29 | |||
| 30 | /* double template */ | ||
| 31 | #define CONFIG_RESAMPLE_DBL | ||
| 32 | #include "resample_template.c" | ||
| 33 | #undef CONFIG_RESAMPLE_DBL | ||
| 34 | |||
| 35 | /* float template */ | ||
| 36 | #define CONFIG_RESAMPLE_FLT | ||
| 37 | #include "resample_template.c" | ||
| 38 | #undef CONFIG_RESAMPLE_FLT | ||
| 39 | |||
| 40 | /* s32 template */ | ||
| 41 | #define CONFIG_RESAMPLE_S32 | ||
| 42 | #include "resample_template.c" | ||
| 43 | #undef CONFIG_RESAMPLE_S32 | ||
| 44 | |||
| 45 | /* s16 template */ | ||
| 46 | #include "resample_template.c" | ||
| 47 | |||
| 48 | |||
| 49 | /* 0th order modified Bessel function of the first kind. */ | ||
| 50 | static double bessel(double x) | ||
| 51 | { | ||
| 52 | double v = 1; | ||
| 53 | double lastv = 0; | ||
| 54 | double t = 1; | ||
| 55 | int i; | ||
| 56 | |||
| 57 | x = x * x / 4; | ||
| 58 | for (i = 1; v != lastv; i++) { | ||
| 59 | lastv = v; | ||
| 60 | t *= x / (i * i); | ||
| 61 | v += t; | ||
| 62 | } | ||
| 63 | return v; | ||
| 64 | } | ||
| 65 | |||
| 66 | /* Build a polyphase filterbank. */ | ||
| 67 | static int build_filter(ResampleContext *c, double factor) | ||
| 68 | { | ||
| 69 | int ph, i; | ||
| 70 | double x, y, w; | ||
| 71 | double *tab; | ||
| 72 | int tap_count = c->filter_length; | ||
| 73 | int phase_count = 1 << c->phase_shift; | ||
| 74 | const int center = (tap_count - 1) / 2; | ||
| 75 | |||
| 76 | tab = av_malloc(tap_count * sizeof(*tab)); | ||
| 77 | if (!tab) | ||
| 78 | return AVERROR(ENOMEM); | ||
| 79 | |||
| 80 | for (ph = 0; ph < phase_count; ph++) { | ||
| 81 | double norm = 0; | ||
| 82 | for (i = 0; i < tap_count; i++) { | ||
| 83 | x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor; | ||
| 84 | if (x == 0) y = 1.0; | ||
| 85 | else y = sin(x) / x; | ||
| 86 | switch (c->filter_type) { | ||
| 87 | case AV_RESAMPLE_FILTER_TYPE_CUBIC: { | ||
| 88 | const float d = -0.5; //first order derivative = -0.5 | ||
| 89 | x = fabs(((double)(i - center) - (double)ph / phase_count) * factor); | ||
| 90 | if (x < 1.0) y = 1 - 3 * x*x + 2 * x*x*x + d * ( -x*x + x*x*x); | ||
| 91 | else y = d * (-4 + 8 * x - 5 * x*x + x*x*x); | ||
| 92 | break; | ||
| 93 | } | ||
| 94 | case AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL: | ||
| 95 | w = 2.0 * x / (factor * tap_count) + M_PI; | ||
| 96 | y *= 0.3635819 - 0.4891775 * cos( w) + | ||
| 97 | 0.1365995 * cos(2 * w) - | ||
| 98 | 0.0106411 * cos(3 * w); | ||
| 99 | break; | ||
| 100 | case AV_RESAMPLE_FILTER_TYPE_KAISER: | ||
| 101 | w = 2.0 * x / (factor * tap_count * M_PI); | ||
| 102 | y *= bessel(c->kaiser_beta * sqrt(FFMAX(1 - w * w, 0))); | ||
| 103 | break; | ||
| 104 | } | ||
| 105 | |||
| 106 | tab[i] = y; | ||
| 107 | norm += y; | ||
| 108 | } | ||
| 109 | /* normalize so that an uniform color remains the same */ | ||
| 110 | for (i = 0; i < tap_count; i++) | ||
| 111 | tab[i] = tab[i] / norm; | ||
| 112 | |||
| 113 | c->set_filter(c->filter_bank, tab, ph, tap_count); | ||
| 114 | } | ||
| 115 | |||
| 116 | av_free(tab); | ||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr) | ||
| 121 | { | ||
| 122 | ResampleContext *c; | ||
| 123 | int out_rate = avr->out_sample_rate; | ||
| 124 | int in_rate = avr->in_sample_rate; | ||
| 125 | double factor = FFMIN(out_rate * avr->cutoff / in_rate, 1.0); | ||
| 126 | int phase_count = 1 << avr->phase_shift; | ||
| 127 | int felem_size; | ||
| 128 | |||
| 129 | if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && | ||
| 130 | avr->internal_sample_fmt != AV_SAMPLE_FMT_S32P && | ||
| 131 | avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP && | ||
| 132 | avr->internal_sample_fmt != AV_SAMPLE_FMT_DBLP) { | ||
| 133 | av_log(avr, AV_LOG_ERROR, "Unsupported internal format for " | ||
| 134 | "resampling: %s\n", | ||
| 135 | av_get_sample_fmt_name(avr->internal_sample_fmt)); | ||
| 136 | return NULL; | ||
| 137 | } | ||
| 138 | c = av_mallocz(sizeof(*c)); | ||
| 139 | if (!c) | ||
| 140 | return NULL; | ||
| 141 | |||
| 142 | c->avr = avr; | ||
| 143 | c->phase_shift = avr->phase_shift; | ||
| 144 | c->phase_mask = phase_count - 1; | ||
| 145 | c->linear = avr->linear_interp; | ||
| 146 | c->filter_length = FFMAX((int)ceil(avr->filter_size / factor), 1); | ||
| 147 | c->filter_type = avr->filter_type; | ||
| 148 | c->kaiser_beta = avr->kaiser_beta; | ||
| 149 | |||
| 150 | switch (avr->internal_sample_fmt) { | ||
| 151 | case AV_SAMPLE_FMT_DBLP: | ||
| 152 | c->resample_one = c->linear ? resample_linear_dbl : resample_one_dbl; | ||
| 153 | c->resample_nearest = resample_nearest_dbl; | ||
| 154 | c->set_filter = set_filter_dbl; | ||
| 155 | break; | ||
| 156 | case AV_SAMPLE_FMT_FLTP: | ||
| 157 | c->resample_one = c->linear ? resample_linear_flt : resample_one_flt; | ||
| 158 | c->resample_nearest = resample_nearest_flt; | ||
| 159 | c->set_filter = set_filter_flt; | ||
| 160 | break; | ||
| 161 | case AV_SAMPLE_FMT_S32P: | ||
| 162 | c->resample_one = c->linear ? resample_linear_s32 : resample_one_s32; | ||
| 163 | c->resample_nearest = resample_nearest_s32; | ||
| 164 | c->set_filter = set_filter_s32; | ||
| 165 | break; | ||
| 166 | case AV_SAMPLE_FMT_S16P: | ||
| 167 | c->resample_one = c->linear ? resample_linear_s16 : resample_one_s16; | ||
| 168 | c->resample_nearest = resample_nearest_s16; | ||
| 169 | c->set_filter = set_filter_s16; | ||
| 170 | break; | ||
| 171 | } | ||
| 172 | |||
| 173 | if (ARCH_AARCH64) | ||
| 174 | ff_audio_resample_init_aarch64(c, avr->internal_sample_fmt); | ||
| 175 | if (ARCH_ARM) | ||
| 176 | ff_audio_resample_init_arm(c, avr->internal_sample_fmt); | ||
| 177 | |||
| 178 | felem_size = av_get_bytes_per_sample(avr->internal_sample_fmt); | ||
| 179 | c->filter_bank = av_mallocz(c->filter_length * (phase_count + 1) * felem_size); | ||
| 180 | if (!c->filter_bank) | ||
| 181 | goto error; | ||
| 182 | |||
| 183 | if (build_filter(c, factor) < 0) | ||
| 184 | goto error; | ||
| 185 | |||
| 186 | memcpy(&c->filter_bank[(c->filter_length * phase_count + 1) * felem_size], | ||
| 187 | c->filter_bank, (c->filter_length - 1) * felem_size); | ||
| 188 | memcpy(&c->filter_bank[c->filter_length * phase_count * felem_size], | ||
| 189 | &c->filter_bank[(c->filter_length - 1) * felem_size], felem_size); | ||
| 190 | |||
| 191 | c->compensation_distance = 0; | ||
| 192 | if (!av_reduce(&c->src_incr, &c->dst_incr, out_rate, | ||
| 193 | in_rate * (int64_t)phase_count, INT32_MAX / 2)) | ||
| 194 | goto error; | ||
| 195 | c->ideal_dst_incr = c->dst_incr; | ||
| 196 | |||
| 197 | c->padding_size = (c->filter_length - 1) / 2; | ||
| 198 | c->initial_padding_filled = 0; | ||
| 199 | c->index = 0; | ||
| 200 | c->frac = 0; | ||
| 201 | |||
| 202 | /* allocate internal buffer */ | ||
| 203 | c->buffer = ff_audio_data_alloc(avr->resample_channels, c->padding_size, | ||
| 204 | avr->internal_sample_fmt, | ||
| 205 | "resample buffer"); | ||
| 206 | if (!c->buffer) | ||
| 207 | goto error; | ||
| 208 | c->buffer->nb_samples = c->padding_size; | ||
| 209 | c->initial_padding_samples = c->padding_size; | ||
| 210 | |||
| 211 | av_log(avr, AV_LOG_DEBUG, "resample: %s from %d Hz to %d Hz\n", | ||
| 212 | av_get_sample_fmt_name(avr->internal_sample_fmt), | ||
| 213 | avr->in_sample_rate, avr->out_sample_rate); | ||
| 214 | |||
| 215 | return c; | ||
| 216 | |||
| 217 | error: | ||
| 218 | ff_audio_data_free(&c->buffer); | ||
| 219 | av_free(c->filter_bank); | ||
| 220 | av_free(c); | ||
| 221 | return NULL; | ||
| 222 | } | ||
| 223 | |||
| 224 | void ff_audio_resample_free(ResampleContext **c) | ||
| 225 | { | ||
| 226 | if (!*c) | ||
| 227 | return; | ||
| 228 | ff_audio_data_free(&(*c)->buffer); | ||
| 229 | av_free((*c)->filter_bank); | ||
| 230 | av_freep(c); | ||
| 231 | } | ||
| 232 | |||
| 233 | int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, | ||
| 234 | int compensation_distance) | ||
| 235 | { | ||
| 236 | ResampleContext *c; | ||
| 237 | |||
| 238 | if (compensation_distance < 0) | ||
| 239 | return AVERROR(EINVAL); | ||
| 240 | if (!compensation_distance && sample_delta) | ||
| 241 | return AVERROR(EINVAL); | ||
| 242 | |||
| 243 | if (!avr->resample_needed) { | ||
| 244 | av_log(avr, AV_LOG_ERROR, "Unable to set resampling compensation\n"); | ||
| 245 | return AVERROR(EINVAL); | ||
| 246 | } | ||
| 247 | c = avr->resample; | ||
| 248 | c->compensation_distance = compensation_distance; | ||
| 249 | if (compensation_distance) { | ||
| 250 | c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * | ||
| 251 | (int64_t)sample_delta / compensation_distance; | ||
| 252 | } else { | ||
| 253 | c->dst_incr = c->ideal_dst_incr; | ||
| 254 | } | ||
| 255 | |||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | static int resample(ResampleContext *c, void *dst, const void *src, | ||
| 260 | int *consumed, int src_size, int dst_size, int update_ctx, | ||
| 261 | int nearest_neighbour) | ||
| 262 | { | ||
| 263 | int dst_index; | ||
| 264 | unsigned int index = c->index; | ||
| 265 | int frac = c->frac; | ||
| 266 | int dst_incr_frac = c->dst_incr % c->src_incr; | ||
| 267 | int dst_incr = c->dst_incr / c->src_incr; | ||
| 268 | int compensation_distance = c->compensation_distance; | ||
| 269 | |||
| 270 | if (!dst != !src) | ||
| 271 | return AVERROR(EINVAL); | ||
| 272 | |||
| 273 | if (nearest_neighbour) { | ||
| 274 | uint64_t index2 = ((uint64_t)index) << 32; | ||
| 275 | int64_t incr = (1LL << 32) * c->dst_incr / c->src_incr; | ||
| 276 | dst_size = FFMIN(dst_size, | ||
| 277 | (src_size-1-index) * (int64_t)c->src_incr / | ||
| 278 | c->dst_incr); | ||
| 279 | |||
| 280 | if (dst) { | ||
| 281 | for(dst_index = 0; dst_index < dst_size; dst_index++) { | ||
| 282 | c->resample_nearest(dst, dst_index, src, index2 >> 32); | ||
| 283 | index2 += incr; | ||
| 284 | } | ||
| 285 | } else { | ||
| 286 | dst_index = dst_size; | ||
| 287 | } | ||
| 288 | index += dst_index * dst_incr; | ||
| 289 | index += (frac + dst_index * (int64_t)dst_incr_frac) / c->src_incr; | ||
| 290 | frac = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr; | ||
| 291 | } else { | ||
| 292 | for (dst_index = 0; dst_index < dst_size; dst_index++) { | ||
| 293 | int sample_index = index >> c->phase_shift; | ||
| 294 | |||
| 295 | if (sample_index + c->filter_length > src_size) | ||
| 296 | break; | ||
| 297 | |||
| 298 | if (dst) | ||
| 299 | c->resample_one(c, dst, dst_index, src, index, frac); | ||
| 300 | |||
| 301 | frac += dst_incr_frac; | ||
| 302 | index += dst_incr; | ||
| 303 | if (frac >= c->src_incr) { | ||
| 304 | frac -= c->src_incr; | ||
| 305 | index++; | ||
| 306 | } | ||
| 307 | if (dst_index + 1 == compensation_distance) { | ||
| 308 | compensation_distance = 0; | ||
| 309 | dst_incr_frac = c->ideal_dst_incr % c->src_incr; | ||
| 310 | dst_incr = c->ideal_dst_incr / c->src_incr; | ||
| 311 | } | ||
| 312 | } | ||
| 313 | } | ||
| 314 | if (consumed) | ||
| 315 | *consumed = index >> c->phase_shift; | ||
| 316 | |||
| 317 | if (update_ctx) { | ||
| 318 | index &= c->phase_mask; | ||
| 319 | |||
| 320 | if (compensation_distance) { | ||
| 321 | compensation_distance -= dst_index; | ||
| 322 | if (compensation_distance <= 0) | ||
| 323 | return AVERROR_BUG; | ||
| 324 | } | ||
| 325 | c->frac = frac; | ||
| 326 | c->index = index; | ||
| 327 | c->dst_incr = dst_incr_frac + c->src_incr*dst_incr; | ||
| 328 | c->compensation_distance = compensation_distance; | ||
| 329 | } | ||
| 330 | |||
| 331 | return dst_index; | ||
| 332 | } | ||
| 333 | |||
| 334 | int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src) | ||
| 335 | { | ||
| 336 | int ch, in_samples, in_leftover, consumed = 0, out_samples = 0; | ||
| 337 | int ret = AVERROR(EINVAL); | ||
| 338 | int nearest_neighbour = (c->compensation_distance == 0 && | ||
| 339 | c->filter_length == 1 && | ||
| 340 | c->phase_shift == 0); | ||
| 341 | |||
| 342 | in_samples = src ? src->nb_samples : 0; | ||
| 343 | in_leftover = c->buffer->nb_samples; | ||
| 344 | |||
| 345 | /* add input samples to the internal buffer */ | ||
| 346 | if (src) { | ||
| 347 | ret = ff_audio_data_combine(c->buffer, in_leftover, src, 0, in_samples); | ||
| 348 | if (ret < 0) | ||
| 349 | return ret; | ||
| 350 | } else if (in_leftover <= c->final_padding_samples) { | ||
| 351 | /* no remaining samples to flush */ | ||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | |||
| 355 | if (!c->initial_padding_filled) { | ||
| 356 | int bps = av_get_bytes_per_sample(c->avr->internal_sample_fmt); | ||
| 357 | int i; | ||
| 358 | |||
| 359 | if (src && c->buffer->nb_samples < 2 * c->padding_size) | ||
| 360 | return 0; | ||
| 361 | |||
| 362 | for (i = 0; i < c->padding_size; i++) | ||
| 363 | for (ch = 0; ch < c->buffer->channels; ch++) { | ||
| 364 | if (c->buffer->nb_samples > 2 * c->padding_size - i) { | ||
| 365 | memcpy(c->buffer->data[ch] + bps * i, | ||
| 366 | c->buffer->data[ch] + bps * (2 * c->padding_size - i), bps); | ||
| 367 | } else { | ||
| 368 | memset(c->buffer->data[ch] + bps * i, 0, bps); | ||
| 369 | } | ||
| 370 | } | ||
| 371 | c->initial_padding_filled = 1; | ||
| 372 | } | ||
| 373 | |||
| 374 | if (!src && !c->final_padding_filled) { | ||
| 375 | int bps = av_get_bytes_per_sample(c->avr->internal_sample_fmt); | ||
| 376 | int i; | ||
| 377 | |||
| 378 | ret = ff_audio_data_realloc(c->buffer, | ||
| 379 | FFMAX(in_samples, in_leftover) + | ||
| 380 | c->padding_size); | ||
| 381 | if (ret < 0) { | ||
| 382 | av_log(c->avr, AV_LOG_ERROR, "Error reallocating resampling buffer\n"); | ||
| 383 | return AVERROR(ENOMEM); | ||
| 384 | } | ||
| 385 | |||
| 386 | for (i = 0; i < c->padding_size; i++) | ||
| 387 | for (ch = 0; ch < c->buffer->channels; ch++) { | ||
| 388 | if (in_leftover > i) { | ||
| 389 | memcpy(c->buffer->data[ch] + bps * (in_leftover + i), | ||
| 390 | c->buffer->data[ch] + bps * (in_leftover - i - 1), | ||
| 391 | bps); | ||
| 392 | } else { | ||
| 393 | memset(c->buffer->data[ch] + bps * (in_leftover + i), | ||
| 394 | 0, bps); | ||
| 395 | } | ||
| 396 | } | ||
| 397 | c->buffer->nb_samples += c->padding_size; | ||
| 398 | c->final_padding_samples = c->padding_size; | ||
| 399 | c->final_padding_filled = 1; | ||
| 400 | } | ||
| 401 | |||
| 402 | |||
| 403 | /* calculate output size and reallocate output buffer if needed */ | ||
| 404 | /* TODO: try to calculate this without the dummy resample() run */ | ||
| 405 | if (!dst->read_only && dst->allow_realloc) { | ||
| 406 | out_samples = resample(c, NULL, NULL, NULL, c->buffer->nb_samples, | ||
| 407 | INT_MAX, 0, nearest_neighbour); | ||
| 408 | ret = ff_audio_data_realloc(dst, out_samples); | ||
| 409 | if (ret < 0) { | ||
| 410 | av_log(c->avr, AV_LOG_ERROR, "error reallocating output\n"); | ||
| 411 | return ret; | ||
| 412 | } | ||
| 413 | } | ||
| 414 | |||
| 415 | /* resample each channel plane */ | ||
| 416 | for (ch = 0; ch < c->buffer->channels; ch++) { | ||
| 417 | out_samples = resample(c, (void *)dst->data[ch], | ||
| 418 | (const void *)c->buffer->data[ch], &consumed, | ||
| 419 | c->buffer->nb_samples, dst->allocated_samples, | ||
| 420 | ch + 1 == c->buffer->channels, nearest_neighbour); | ||
| 421 | } | ||
| 422 | if (out_samples < 0) { | ||
| 423 | av_log(c->avr, AV_LOG_ERROR, "error during resampling\n"); | ||
| 424 | return out_samples; | ||
| 425 | } | ||
| 426 | |||
| 427 | /* drain consumed samples from the internal buffer */ | ||
| 428 | ff_audio_data_drain(c->buffer, consumed); | ||
| 429 | c->initial_padding_samples = FFMAX(c->initial_padding_samples - consumed, 0); | ||
| 430 | |||
| 431 | av_log(c->avr, AV_LOG_TRACE, "resampled %d in + %d leftover to %d out + %d leftover\n", | ||
| 432 | in_samples, in_leftover, out_samples, c->buffer->nb_samples); | ||
| 433 | |||
| 434 | dst->nb_samples = out_samples; | ||
| 435 | return 0; | ||
| 436 | } | ||
| 437 | |||
| 438 | int avresample_get_delay(AVAudioResampleContext *avr) | ||
| 439 | { | ||
| 440 | ResampleContext *c = avr->resample; | ||
| 441 | |||
| 442 | if (!avr->resample_needed || !avr->resample) | ||
| 443 | return 0; | ||
| 444 | |||
| 445 | return FFMAX(c->buffer->nb_samples - c->padding_size, 0); | ||
| 446 | } | ||
| @@ -1,96 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef AVRESAMPLE_RESAMPLE_H | ||
| 22 | #define AVRESAMPLE_RESAMPLE_H | ||
| 23 | |||
| 24 | #include "avresample.h" | ||
| 25 | #include "internal.h" | ||
| 26 | #include "audio_data.h" | ||
| 27 | |||
| 28 | struct ResampleContext { | ||
| 29 | AVAudioResampleContext *avr; | ||
| 30 | AudioData *buffer; | ||
| 31 | uint8_t *filter_bank; | ||
| 32 | int filter_length; | ||
| 33 | int ideal_dst_incr; | ||
| 34 | int dst_incr; | ||
| 35 | unsigned int index; | ||
| 36 | int frac; | ||
| 37 | int src_incr; | ||
| 38 | int compensation_distance; | ||
| 39 | int phase_shift; | ||
| 40 | int phase_mask; | ||
| 41 | int linear; | ||
| 42 | enum AVResampleFilterType filter_type; | ||
| 43 | int kaiser_beta; | ||
| 44 | void (*set_filter)(void *filter, double *tab, int phase, int tap_count); | ||
| 45 | void (*resample_one)(struct ResampleContext *c, void *dst0, | ||
| 46 | int dst_index, const void *src0, | ||
| 47 | unsigned int index, int frac); | ||
| 48 | void (*resample_nearest)(void *dst0, int dst_index, | ||
| 49 | const void *src0, unsigned int index); | ||
| 50 | int padding_size; | ||
| 51 | int initial_padding_filled; | ||
| 52 | int initial_padding_samples; | ||
| 53 | int final_padding_filled; | ||
| 54 | int final_padding_samples; | ||
| 55 | }; | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Allocate and initialize a ResampleContext. | ||
| 59 | * | ||
| 60 | * The parameters in the AVAudioResampleContext are used to initialize the | ||
| 61 | * ResampleContext. | ||
| 62 | * | ||
| 63 | * @param avr AVAudioResampleContext | ||
| 64 | * @return newly-allocated ResampleContext | ||
| 65 | */ | ||
| 66 | ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr); | ||
| 67 | |||
| 68 | /** | ||
| 69 | * Free a ResampleContext. | ||
| 70 | * | ||
| 71 | * @param c ResampleContext | ||
| 72 | */ | ||
| 73 | void ff_audio_resample_free(ResampleContext **c); | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Resample audio data. | ||
| 77 | * | ||
| 78 | * Changes the sample rate. | ||
| 79 | * | ||
| 80 | * @par | ||
| 81 | * All samples in the source data may not be consumed depending on the | ||
| 82 | * resampling parameters and the size of the output buffer. The unconsumed | ||
| 83 | * samples are automatically added to the start of the source in the next call. | ||
| 84 | * If the destination data can be reallocated, that may be done in this function | ||
| 85 | * in order to fit all available output. If it cannot be reallocated, fewer | ||
| 86 | * input samples will be consumed in order to have the output fit in the | ||
| 87 | * destination data buffers. | ||
| 88 | * | ||
| 89 | * @param c ResampleContext | ||
| 90 | * @param dst destination audio data | ||
| 91 | * @param src source audio data | ||
| 92 | * @return 0 on success, negative AVERROR code on failure | ||
| 93 | */ | ||
| 94 | int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src); | ||
| 95 | |||
| 96 | #endif /* AVRESAMPLE_RESAMPLE_H */ | ||
| @@ -1,118 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <math.h> | ||
| 22 | #include <stdint.h> | ||
| 23 | |||
| 24 | #include "libavutil/common.h" | ||
| 25 | #include "internal.h" | ||
| 26 | |||
| 27 | #if defined(CONFIG_RESAMPLE_DBL) | ||
| 28 | #define SET_TYPE(func) func ## _dbl | ||
| 29 | #define FELEM double | ||
| 30 | #define FELEM2 double | ||
| 31 | #define FELEML double | ||
| 32 | #define OUT(d, v) d = v | ||
| 33 | #define DBL_TO_FELEM(d, v) d = v | ||
| 34 | #elif defined(CONFIG_RESAMPLE_FLT) | ||
| 35 | #define SET_TYPE(func) func ## _flt | ||
| 36 | #define FELEM float | ||
| 37 | #define FELEM2 float | ||
| 38 | #define FELEML float | ||
| 39 | #define OUT(d, v) d = v | ||
| 40 | #define DBL_TO_FELEM(d, v) d = v | ||
| 41 | #elif defined(CONFIG_RESAMPLE_S32) | ||
| 42 | #define SET_TYPE(func) func ## _s32 | ||
| 43 | #define FELEM int32_t | ||
| 44 | #define FELEM2 int64_t | ||
| 45 | #define FELEML int64_t | ||
| 46 | #define OUT(d, v) d = av_clipl_int32((v + (1 << 29)) >> 30) | ||
| 47 | #define DBL_TO_FELEM(d, v) d = av_clipl_int32(llrint(v * (1 << 30))); | ||
| 48 | #else | ||
| 49 | #define SET_TYPE(func) func ## _s16 | ||
| 50 | #define FELEM int16_t | ||
| 51 | #define FELEM2 int32_t | ||
| 52 | #define FELEML int64_t | ||
| 53 | #define OUT(d, v) d = av_clip_int16((v + (1 << 14)) >> 15) | ||
| 54 | #define DBL_TO_FELEM(d, v) d = av_clip_int16(lrint(v * (1 << 15))) | ||
| 55 | #endif | ||
| 56 | |||
| 57 | static void SET_TYPE(resample_nearest)(void *dst0, int dst_index, const void *src0, unsigned int index) | ||
| 58 | { | ||
| 59 | FELEM *dst = dst0; | ||
| 60 | const FELEM *src = src0; | ||
| 61 | dst[dst_index] = src[index]; | ||
| 62 | } | ||
| 63 | |||
| 64 | static void SET_TYPE(resample_linear)(ResampleContext *c, void *dst0, int dst_index, | ||
| 65 | const void *src0, unsigned int index, int frac) | ||
| 66 | { | ||
| 67 | FELEM *dst = dst0; | ||
| 68 | const FELEM *src = src0; | ||
| 69 | int i; | ||
| 70 | unsigned int sample_index = index >> c->phase_shift; | ||
| 71 | FELEM2 val = 0; | ||
| 72 | FELEM *filter = ((FELEM *)c->filter_bank) + | ||
| 73 | c->filter_length * (index & c->phase_mask); | ||
| 74 | FELEM2 v2 = 0; | ||
| 75 | |||
| 76 | for (i = 0; i < c->filter_length; i++) { | ||
| 77 | val += src[sample_index + i] * (FELEM2)filter[i]; | ||
| 78 | v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length]; | ||
| 79 | } | ||
| 80 | val += (v2 - val) * (FELEML)frac / c->src_incr; | ||
| 81 | |||
| 82 | OUT(dst[dst_index], val); | ||
| 83 | } | ||
| 84 | |||
| 85 | static void SET_TYPE(resample_one)(ResampleContext *c, | ||
| 86 | void *dst0, int dst_index, const void *src0, | ||
| 87 | unsigned int index, int frac) | ||
| 88 | { | ||
| 89 | FELEM *dst = dst0; | ||
| 90 | const FELEM *src = src0; | ||
| 91 | int i; | ||
| 92 | unsigned int sample_index = index >> c->phase_shift; | ||
| 93 | FELEM2 val = 0; | ||
| 94 | FELEM *filter = ((FELEM *)c->filter_bank) + | ||
| 95 | c->filter_length * (index & c->phase_mask); | ||
| 96 | |||
| 97 | for (i = 0; i < c->filter_length; i++) | ||
| 98 | val += src[sample_index + i] * (FELEM2)filter[i]; | ||
| 99 | |||
| 100 | OUT(dst[dst_index], val); | ||
| 101 | } | ||
| 102 | |||
| 103 | static void SET_TYPE(set_filter)(void *filter0, double *tab, int phase, | ||
| 104 | int tap_count) | ||
| 105 | { | ||
| 106 | int i; | ||
| 107 | FELEM *filter = ((FELEM *)filter0) + phase * tap_count; | ||
| 108 | for (i = 0; i < tap_count; i++) { | ||
| 109 | DBL_TO_FELEM(filter[i], tab[i]); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | #undef SET_TYPE | ||
| 114 | #undef FELEM | ||
| 115 | #undef FELEM2 | ||
| 116 | #undef FELEML | ||
| 117 | #undef OUT | ||
| 118 | #undef DBL_TO_FELEM | ||
| @@ -1 +0,0 @@ | |||
| 1 | /avresample | ||
| @@ -1,342 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2002 Fabrice Bellard | ||
| 3 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <stdint.h> | ||
| 23 | #include <stdio.h> | ||
| 24 | |||
| 25 | #include "libavutil/avstring.h" | ||
| 26 | #include "libavutil/common.h" | ||
| 27 | #include "libavutil/lfg.h" | ||
| 28 | #include "libavutil/libm.h" | ||
| 29 | #include "libavutil/log.h" | ||
| 30 | #include "libavutil/mem.h" | ||
| 31 | #include "libavutil/opt.h" | ||
| 32 | #include "libavutil/samplefmt.h" | ||
| 33 | |||
| 34 | #include "libavresample/avresample.h" | ||
| 35 | |||
| 36 | static double dbl_rand(AVLFG *lfg) | ||
| 37 | { | ||
| 38 | return 2.0 * (av_lfg_get(lfg) / (double)UINT_MAX) - 1.0; | ||
| 39 | } | ||
| 40 | |||
| 41 | #define PUT_FUNC(name, fmt, type, expr) \ | ||
| 42 | static void put_sample_ ## name(void **data, enum AVSampleFormat sample_fmt,\ | ||
| 43 | int channels, int sample, int ch, \ | ||
| 44 | double v_dbl) \ | ||
| 45 | { \ | ||
| 46 | type v = expr; \ | ||
| 47 | type **out = (type **)data; \ | ||
| 48 | if (av_sample_fmt_is_planar(sample_fmt)) \ | ||
| 49 | out[ch][sample] = v; \ | ||
| 50 | else \ | ||
| 51 | out[0][sample * channels + ch] = v; \ | ||
| 52 | } | ||
| 53 | |||
| 54 | PUT_FUNC(u8, AV_SAMPLE_FMT_U8, uint8_t, av_clip_uint8 ( lrint(v_dbl * (1 << 7)) + 128)) | ||
| 55 | PUT_FUNC(s16, AV_SAMPLE_FMT_S16, int16_t, av_clip_int16 ( lrint(v_dbl * (1 << 15)))) | ||
| 56 | PUT_FUNC(s32, AV_SAMPLE_FMT_S32, int32_t, av_clipl_int32(llrint(v_dbl * (1U << 31)))) | ||
| 57 | PUT_FUNC(flt, AV_SAMPLE_FMT_FLT, float, v_dbl) | ||
| 58 | PUT_FUNC(dbl, AV_SAMPLE_FMT_DBL, double, v_dbl) | ||
| 59 | |||
| 60 | static void put_sample(void **data, enum AVSampleFormat sample_fmt, | ||
| 61 | int channels, int sample, int ch, double v_dbl) | ||
| 62 | { | ||
| 63 | switch (av_get_packed_sample_fmt(sample_fmt)) { | ||
| 64 | case AV_SAMPLE_FMT_U8: | ||
| 65 | put_sample_u8(data, sample_fmt, channels, sample, ch, v_dbl); | ||
| 66 | break; | ||
| 67 | case AV_SAMPLE_FMT_S16: | ||
| 68 | put_sample_s16(data, sample_fmt, channels, sample, ch, v_dbl); | ||
| 69 | break; | ||
| 70 | case AV_SAMPLE_FMT_S32: | ||
| 71 | put_sample_s32(data, sample_fmt, channels, sample, ch, v_dbl); | ||
| 72 | break; | ||
| 73 | case AV_SAMPLE_FMT_FLT: | ||
| 74 | put_sample_flt(data, sample_fmt, channels, sample, ch, v_dbl); | ||
| 75 | break; | ||
| 76 | case AV_SAMPLE_FMT_DBL: | ||
| 77 | put_sample_dbl(data, sample_fmt, channels, sample, ch, v_dbl); | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | static void audiogen(AVLFG *rnd, void **data, enum AVSampleFormat sample_fmt, | ||
| 83 | int channels, int sample_rate, int nb_samples) | ||
| 84 | { | ||
| 85 | int i, ch, k; | ||
| 86 | double v, f, a, ampa; | ||
| 87 | double tabf1[AVRESAMPLE_MAX_CHANNELS]; | ||
| 88 | double tabf2[AVRESAMPLE_MAX_CHANNELS]; | ||
| 89 | double taba[AVRESAMPLE_MAX_CHANNELS]; | ||
| 90 | |||
| 91 | #define PUT_SAMPLE put_sample(data, sample_fmt, channels, k, ch, v); | ||
| 92 | |||
| 93 | k = 0; | ||
| 94 | |||
| 95 | /* 1 second of single freq sine at 1000 Hz */ | ||
| 96 | a = 0; | ||
| 97 | for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | ||
| 98 | v = sin(a) * 0.30; | ||
| 99 | for (ch = 0; ch < channels; ch++) | ||
| 100 | PUT_SAMPLE | ||
| 101 | a += M_PI * 1000.0 * 2.0 / sample_rate; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* 1 second of varying frequency between 100 and 10000 Hz */ | ||
| 105 | a = 0; | ||
| 106 | for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | ||
| 107 | v = sin(a) * 0.30; | ||
| 108 | for (ch = 0; ch < channels; ch++) | ||
| 109 | PUT_SAMPLE | ||
| 110 | f = 100.0 + (((10000.0 - 100.0) * i) / sample_rate); | ||
| 111 | a += M_PI * f * 2.0 / sample_rate; | ||
| 112 | } | ||
| 113 | |||
| 114 | /* 0.5 second of low amplitude white noise */ | ||
| 115 | for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { | ||
| 116 | v = dbl_rand(rnd) * 0.30; | ||
| 117 | for (ch = 0; ch < channels; ch++) | ||
| 118 | PUT_SAMPLE | ||
| 119 | } | ||
| 120 | |||
| 121 | /* 0.5 second of high amplitude white noise */ | ||
| 122 | for (i = 0; i < sample_rate / 2 && k < nb_samples; i++, k++) { | ||
| 123 | v = dbl_rand(rnd); | ||
| 124 | for (ch = 0; ch < channels; ch++) | ||
| 125 | PUT_SAMPLE | ||
| 126 | } | ||
| 127 | |||
| 128 | /* 1 second of unrelated ramps for each channel */ | ||
| 129 | for (ch = 0; ch < channels; ch++) { | ||
| 130 | taba[ch] = 0; | ||
| 131 | tabf1[ch] = 100 + av_lfg_get(rnd) % 5000; | ||
| 132 | tabf2[ch] = 100 + av_lfg_get(rnd) % 5000; | ||
| 133 | } | ||
| 134 | for (i = 0; i < 1 * sample_rate && k < nb_samples; i++, k++) { | ||
| 135 | for (ch = 0; ch < channels; ch++) { | ||
| 136 | v = sin(taba[ch]) * 0.30; | ||
| 137 | PUT_SAMPLE | ||
| 138 | f = tabf1[ch] + (((tabf2[ch] - tabf1[ch]) * i) / sample_rate); | ||
| 139 | taba[ch] += M_PI * f * 2.0 / sample_rate; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | /* 2 seconds of 500 Hz with varying volume */ | ||
| 144 | a = 0; | ||
| 145 | ampa = 0; | ||
| 146 | for (i = 0; i < 2 * sample_rate && k < nb_samples; i++, k++) { | ||
| 147 | for (ch = 0; ch < channels; ch++) { | ||
| 148 | double amp = (1.0 + sin(ampa)) * 0.15; | ||
| 149 | if (ch & 1) | ||
| 150 | amp = 0.30 - amp; | ||
| 151 | v = sin(a) * amp; | ||
| 152 | PUT_SAMPLE | ||
| 153 | a += M_PI * 500.0 * 2.0 / sample_rate; | ||
| 154 | ampa += M_PI * 2.0 / sample_rate; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | /* formats, rates, and layouts are ordered for priority in testing. | ||
| 160 | e.g. 'avresample-test 4 2 2' will test all input/output combinations of | ||
| 161 | S16/FLTP/S16P/FLT, 48000/44100, and stereo/mono */ | ||
| 162 | |||
| 163 | static const enum AVSampleFormat formats[] = { | ||
| 164 | AV_SAMPLE_FMT_S16, | ||
| 165 | AV_SAMPLE_FMT_FLTP, | ||
| 166 | AV_SAMPLE_FMT_S16P, | ||
| 167 | AV_SAMPLE_FMT_FLT, | ||
| 168 | AV_SAMPLE_FMT_S32P, | ||
| 169 | AV_SAMPLE_FMT_S32, | ||
| 170 | AV_SAMPLE_FMT_U8P, | ||
| 171 | AV_SAMPLE_FMT_U8, | ||
| 172 | AV_SAMPLE_FMT_DBLP, | ||
| 173 | AV_SAMPLE_FMT_DBL, | ||
| 174 | }; | ||
| 175 | |||
| 176 | static const int rates[] = { | ||
| 177 | 48000, | ||
| 178 | 44100, | ||
| 179 | 16000 | ||
| 180 | }; | ||
| 181 | |||
| 182 | static const uint64_t layouts[] = { | ||
| 183 | AV_CH_LAYOUT_STEREO, | ||
| 184 | AV_CH_LAYOUT_MONO, | ||
| 185 | AV_CH_LAYOUT_5POINT1, | ||
| 186 | AV_CH_LAYOUT_7POINT1, | ||
| 187 | }; | ||
| 188 | |||
| 189 | int main(int argc, char **argv) | ||
| 190 | { | ||
| 191 | AVAudioResampleContext *s; | ||
| 192 | AVLFG rnd; | ||
| 193 | int ret = 0; | ||
| 194 | uint8_t *in_buf = NULL; | ||
| 195 | uint8_t *out_buf = NULL; | ||
| 196 | unsigned int in_buf_size; | ||
| 197 | unsigned int out_buf_size; | ||
| 198 | uint8_t *in_data[AVRESAMPLE_MAX_CHANNELS] = { 0 }; | ||
| 199 | uint8_t *out_data[AVRESAMPLE_MAX_CHANNELS] = { 0 }; | ||
| 200 | int in_linesize; | ||
| 201 | int out_linesize; | ||
| 202 | uint64_t in_ch_layout; | ||
| 203 | int in_channels; | ||
| 204 | enum AVSampleFormat in_fmt; | ||
| 205 | int in_rate; | ||
| 206 | uint64_t out_ch_layout; | ||
| 207 | int out_channels; | ||
| 208 | enum AVSampleFormat out_fmt; | ||
| 209 | int out_rate; | ||
| 210 | int num_formats, num_rates, num_layouts; | ||
| 211 | int i, j, k, l, m, n; | ||
| 212 | |||
| 213 | num_formats = 2; | ||
| 214 | num_rates = 2; | ||
| 215 | num_layouts = 2; | ||
| 216 | if (argc > 1) { | ||
| 217 | if (!av_strncasecmp(argv[1], "-h", 3)) { | ||
| 218 | av_log(NULL, AV_LOG_INFO, "Usage: avresample-test [<num formats> " | ||
| 219 | "[<num sample rates> [<num channel layouts>]]]\n" | ||
| 220 | "Default is 2 2 2\n"); | ||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | num_formats = strtol(argv[1], NULL, 0); | ||
| 224 | num_formats = av_clip(num_formats, 1, FF_ARRAY_ELEMS(formats)); | ||
| 225 | } | ||
| 226 | if (argc > 2) { | ||
| 227 | num_rates = strtol(argv[2], NULL, 0); | ||
| 228 | num_rates = av_clip(num_rates, 1, FF_ARRAY_ELEMS(rates)); | ||
| 229 | } | ||
| 230 | if (argc > 3) { | ||
| 231 | num_layouts = strtol(argv[3], NULL, 0); | ||
| 232 | num_layouts = av_clip(num_layouts, 1, FF_ARRAY_ELEMS(layouts)); | ||
| 233 | } | ||
| 234 | |||
| 235 | av_log_set_level(AV_LOG_DEBUG); | ||
| 236 | |||
| 237 | av_lfg_init(&rnd, 0xC0FFEE); | ||
| 238 | |||
| 239 | in_buf_size = av_samples_get_buffer_size(&in_linesize, 8, 48000 * 6, | ||
| 240 | AV_SAMPLE_FMT_DBLP, 0); | ||
| 241 | out_buf_size = in_buf_size; | ||
| 242 | |||
| 243 | in_buf = av_malloc(in_buf_size); | ||
| 244 | if (!in_buf) | ||
| 245 | goto end; | ||
| 246 | out_buf = av_malloc(out_buf_size); | ||
| 247 | if (!out_buf) | ||
| 248 | goto end; | ||
| 249 | |||
| 250 | s = avresample_alloc_context(); | ||
| 251 | if (!s) { | ||
| 252 | av_log(NULL, AV_LOG_ERROR, "Error allocating AVAudioResampleContext\n"); | ||
| 253 | ret = 1; | ||
| 254 | goto end; | ||
| 255 | } | ||
| 256 | |||
| 257 | for (i = 0; i < num_formats; i++) { | ||
| 258 | in_fmt = formats[i]; | ||
| 259 | for (k = 0; k < num_layouts; k++) { | ||
| 260 | in_ch_layout = layouts[k]; | ||
| 261 | in_channels = av_get_channel_layout_nb_channels(in_ch_layout); | ||
| 262 | for (m = 0; m < num_rates; m++) { | ||
| 263 | in_rate = rates[m]; | ||
| 264 | |||
| 265 | ret = av_samples_fill_arrays(in_data, &in_linesize, in_buf, | ||
| 266 | in_channels, in_rate * 6, | ||
| 267 | in_fmt, 0); | ||
| 268 | if (ret < 0) { | ||
| 269 | av_log(s, AV_LOG_ERROR, "failed in_data fill arrays\n"); | ||
| 270 | goto end; | ||
| 271 | } | ||
| 272 | audiogen(&rnd, (void **)in_data, in_fmt, in_channels, in_rate, in_rate * 6); | ||
| 273 | |||
| 274 | for (j = 0; j < num_formats; j++) { | ||
| 275 | out_fmt = formats[j]; | ||
| 276 | for (l = 0; l < num_layouts; l++) { | ||
| 277 | out_ch_layout = layouts[l]; | ||
| 278 | out_channels = av_get_channel_layout_nb_channels(out_ch_layout); | ||
| 279 | for (n = 0; n < num_rates; n++) { | ||
| 280 | out_rate = rates[n]; | ||
| 281 | |||
| 282 | av_log(NULL, AV_LOG_INFO, "%s to %s, %d to %d channels, %d Hz to %d Hz\n", | ||
| 283 | av_get_sample_fmt_name(in_fmt), av_get_sample_fmt_name(out_fmt), | ||
| 284 | in_channels, out_channels, in_rate, out_rate); | ||
| 285 | |||
| 286 | ret = av_samples_fill_arrays(out_data, &out_linesize, | ||
| 287 | out_buf, out_channels, | ||
| 288 | out_rate * 6, out_fmt, 0); | ||
| 289 | if (ret < 0) { | ||
| 290 | av_log(s, AV_LOG_ERROR, "failed out_data fill arrays\n"); | ||
| 291 | goto end; | ||
| 292 | } | ||
| 293 | |||
| 294 | av_opt_set_int(s, "in_channel_layout", in_ch_layout, 0); | ||
| 295 | av_opt_set_int(s, "in_sample_fmt", in_fmt, 0); | ||
| 296 | av_opt_set_int(s, "in_sample_rate", in_rate, 0); | ||
| 297 | av_opt_set_int(s, "out_channel_layout", out_ch_layout, 0); | ||
| 298 | av_opt_set_int(s, "out_sample_fmt", out_fmt, 0); | ||
| 299 | av_opt_set_int(s, "out_sample_rate", out_rate, 0); | ||
| 300 | |||
| 301 | av_opt_set_int(s, "internal_sample_fmt", AV_SAMPLE_FMT_FLTP, 0); | ||
| 302 | |||
| 303 | ret = avresample_open(s); | ||
| 304 | if (ret < 0) { | ||
| 305 | av_log(s, AV_LOG_ERROR, "Error opening context\n"); | ||
| 306 | goto end; | ||
| 307 | } | ||
| 308 | |||
| 309 | ret = avresample_convert(s, out_data, out_linesize, out_rate * 6, | ||
| 310 | in_data, in_linesize, in_rate * 6); | ||
| 311 | if (ret < 0) { | ||
| 312 | char errbuf[256]; | ||
| 313 | av_strerror(ret, errbuf, sizeof(errbuf)); | ||
| 314 | av_log(NULL, AV_LOG_ERROR, "%s\n", errbuf); | ||
| 315 | goto end; | ||
| 316 | } | ||
| 317 | av_log(NULL, AV_LOG_INFO, "Converted %d samples to %d samples\n", | ||
| 318 | in_rate * 6, ret); | ||
| 319 | if (avresample_get_delay(s) > 0) | ||
| 320 | av_log(NULL, AV_LOG_INFO, "%d delay samples not converted\n", | ||
| 321 | avresample_get_delay(s)); | ||
| 322 | if (avresample_available(s) > 0) | ||
| 323 | av_log(NULL, AV_LOG_INFO, "%d samples available for output\n", | ||
| 324 | avresample_available(s)); | ||
| 325 | av_log(NULL, AV_LOG_INFO, "\n"); | ||
| 326 | |||
| 327 | avresample_close(s); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | } | ||
| 331 | } | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | ret = 0; | ||
| 336 | |||
| 337 | end: | ||
| 338 | av_freep(&in_buf); | ||
| 339 | av_freep(&out_buf); | ||
| 340 | avresample_free(&s); | ||
| 341 | return ret; | ||
| 342 | } | ||
| @@ -1,793 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "libavutil/common.h" | ||
| 22 | #include "libavutil/dict.h" | ||
| 23 | // #include "libavutil/error.h" | ||
| 24 | #include "libavutil/frame.h" | ||
| 25 | #include "libavutil/log.h" | ||
| 26 | #include "libavutil/mem.h" | ||
| 27 | #include "libavutil/opt.h" | ||
| 28 | |||
| 29 | #include "avresample.h" | ||
| 30 | #include "internal.h" | ||
| 31 | #include "audio_data.h" | ||
| 32 | #include "audio_convert.h" | ||
| 33 | #include "audio_mix.h" | ||
| 34 | #include "resample.h" | ||
| 35 | |||
| 36 | int avresample_open(AVAudioResampleContext *avr) | ||
| 37 | { | ||
| 38 | int ret; | ||
| 39 | |||
| 40 | if (avresample_is_open(avr)) { | ||
| 41 | av_log(avr, AV_LOG_ERROR, "The resampling context is already open.\n"); | ||
| 42 | return AVERROR(EINVAL); | ||
| 43 | } | ||
| 44 | |||
| 45 | /* set channel mixing parameters */ | ||
| 46 | avr->in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | ||
| 47 | if (avr->in_channels <= 0 || avr->in_channels > AVRESAMPLE_MAX_CHANNELS) { | ||
| 48 | av_log(avr, AV_LOG_ERROR, "Invalid input channel layout: %"PRIu64"\n", | ||
| 49 | avr->in_channel_layout); | ||
| 50 | return AVERROR(EINVAL); | ||
| 51 | } | ||
| 52 | avr->out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | ||
| 53 | if (avr->out_channels <= 0 || avr->out_channels > AVRESAMPLE_MAX_CHANNELS) { | ||
| 54 | av_log(avr, AV_LOG_ERROR, "Invalid output channel layout: %"PRIu64"\n", | ||
| 55 | avr->out_channel_layout); | ||
| 56 | return AVERROR(EINVAL); | ||
| 57 | } | ||
| 58 | avr->resample_channels = FFMIN(avr->in_channels, avr->out_channels); | ||
| 59 | avr->downmix_needed = avr->in_channels > avr->out_channels; | ||
| 60 | avr->upmix_needed = avr->out_channels > avr->in_channels || | ||
| 61 | (!avr->downmix_needed && (avr->mix_matrix || | ||
| 62 | avr->in_channel_layout != avr->out_channel_layout)); | ||
| 63 | avr->mixing_needed = avr->downmix_needed || avr->upmix_needed; | ||
| 64 | |||
| 65 | /* set resampling parameters */ | ||
| 66 | avr->resample_needed = avr->in_sample_rate != avr->out_sample_rate || | ||
| 67 | avr->force_resampling; | ||
| 68 | |||
| 69 | /* select internal sample format if not specified by the user */ | ||
| 70 | if (avr->internal_sample_fmt == AV_SAMPLE_FMT_NONE && | ||
| 71 | (avr->mixing_needed || avr->resample_needed)) { | ||
| 72 | enum AVSampleFormat in_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); | ||
| 73 | enum AVSampleFormat out_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); | ||
| 74 | int max_bps = FFMAX(av_get_bytes_per_sample(in_fmt), | ||
| 75 | av_get_bytes_per_sample(out_fmt)); | ||
| 76 | if (max_bps <= 2) { | ||
| 77 | avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; | ||
| 78 | } else if (avr->mixing_needed) { | ||
| 79 | avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; | ||
| 80 | } else { | ||
| 81 | if (max_bps <= 4) { | ||
| 82 | if (in_fmt == AV_SAMPLE_FMT_S32P || | ||
| 83 | out_fmt == AV_SAMPLE_FMT_S32P) { | ||
| 84 | if (in_fmt == AV_SAMPLE_FMT_FLTP || | ||
| 85 | out_fmt == AV_SAMPLE_FMT_FLTP) { | ||
| 86 | /* if one is s32 and the other is flt, use dbl */ | ||
| 87 | avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; | ||
| 88 | } else { | ||
| 89 | /* if one is s32 and the other is s32, s16, or u8, use s32 */ | ||
| 90 | avr->internal_sample_fmt = AV_SAMPLE_FMT_S32P; | ||
| 91 | } | ||
| 92 | } else { | ||
| 93 | /* if one is flt and the other is flt, s16 or u8, use flt */ | ||
| 94 | avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; | ||
| 95 | } | ||
| 96 | } else { | ||
| 97 | /* if either is dbl, use dbl */ | ||
| 98 | avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | av_log(avr, AV_LOG_DEBUG, "Using %s as internal sample format\n", | ||
| 102 | av_get_sample_fmt_name(avr->internal_sample_fmt)); | ||
| 103 | } | ||
| 104 | |||
| 105 | /* we may need to add an extra conversion in order to remap channels if | ||
| 106 | the output format is not planar */ | ||
| 107 | if (avr->use_channel_map && !avr->mixing_needed && !avr->resample_needed && | ||
| 108 | !ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels)) { | ||
| 109 | avr->internal_sample_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); | ||
| 110 | } | ||
| 111 | |||
| 112 | /* set sample format conversion parameters */ | ||
| 113 | if (avr->resample_needed || avr->mixing_needed) | ||
| 114 | avr->in_convert_needed = avr->in_sample_fmt != avr->internal_sample_fmt; | ||
| 115 | else | ||
| 116 | avr->in_convert_needed = avr->use_channel_map && | ||
| 117 | !ff_sample_fmt_is_planar(avr->out_sample_fmt, avr->out_channels); | ||
| 118 | |||
| 119 | if (avr->resample_needed || avr->mixing_needed || avr->in_convert_needed) | ||
| 120 | avr->out_convert_needed = avr->internal_sample_fmt != avr->out_sample_fmt; | ||
| 121 | else | ||
| 122 | avr->out_convert_needed = avr->in_sample_fmt != avr->out_sample_fmt; | ||
| 123 | |||
| 124 | avr->in_copy_needed = !avr->in_convert_needed && (avr->mixing_needed || | ||
| 125 | (avr->use_channel_map && avr->resample_needed)); | ||
| 126 | |||
| 127 | if (avr->use_channel_map) { | ||
| 128 | if (avr->in_copy_needed) { | ||
| 129 | avr->remap_point = REMAP_IN_COPY; | ||
| 130 | av_log(avr, AV_LOG_TRACE, "remap channels during in_copy\n"); | ||
| 131 | } else if (avr->in_convert_needed) { | ||
| 132 | avr->remap_point = REMAP_IN_CONVERT; | ||
| 133 | av_log(avr, AV_LOG_TRACE, "remap channels during in_convert\n"); | ||
| 134 | } else if (avr->out_convert_needed) { | ||
| 135 | avr->remap_point = REMAP_OUT_CONVERT; | ||
| 136 | av_log(avr, AV_LOG_TRACE, "remap channels during out_convert\n"); | ||
| 137 | } else { | ||
| 138 | avr->remap_point = REMAP_OUT_COPY; | ||
| 139 | av_log(avr, AV_LOG_TRACE, "remap channels during out_copy\n"); | ||
| 140 | } | ||
| 141 | |||
| 142 | #ifdef DEBUG | ||
| 143 | { | ||
| 144 | int ch; | ||
| 145 | av_log(avr, AV_LOG_TRACE, "output map: "); | ||
| 146 | if (avr->ch_map_info.do_remap) | ||
| 147 | for (ch = 0; ch < avr->in_channels; ch++) | ||
| 148 | av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_map[ch]); | ||
| 149 | else | ||
| 150 | av_log(avr, AV_LOG_TRACE, "n/a"); | ||
| 151 | av_log(avr, AV_LOG_TRACE, "\n"); | ||
| 152 | av_log(avr, AV_LOG_TRACE, "copy map: "); | ||
| 153 | if (avr->ch_map_info.do_copy) | ||
| 154 | for (ch = 0; ch < avr->in_channels; ch++) | ||
| 155 | av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_copy[ch]); | ||
| 156 | else | ||
| 157 | av_log(avr, AV_LOG_TRACE, "n/a"); | ||
| 158 | av_log(avr, AV_LOG_TRACE, "\n"); | ||
| 159 | av_log(avr, AV_LOG_TRACE, "zero map: "); | ||
| 160 | if (avr->ch_map_info.do_zero) | ||
| 161 | for (ch = 0; ch < avr->in_channels; ch++) | ||
| 162 | av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.channel_zero[ch]); | ||
| 163 | else | ||
| 164 | av_log(avr, AV_LOG_TRACE, "n/a"); | ||
| 165 | av_log(avr, AV_LOG_TRACE, "\n"); | ||
| 166 | av_log(avr, AV_LOG_TRACE, "input map: "); | ||
| 167 | for (ch = 0; ch < avr->in_channels; ch++) | ||
| 168 | av_log(avr, AV_LOG_TRACE, " % 2d", avr->ch_map_info.input_map[ch]); | ||
| 169 | av_log(avr, AV_LOG_TRACE, "\n"); | ||
| 170 | } | ||
| 171 | #endif | ||
| 172 | } else | ||
| 173 | avr->remap_point = REMAP_NONE; | ||
| 174 | |||
| 175 | /* allocate buffers */ | ||
| 176 | if (avr->in_copy_needed || avr->in_convert_needed) { | ||
| 177 | avr->in_buffer = ff_audio_data_alloc(FFMAX(avr->in_channels, avr->out_channels), | ||
| 178 | 0, avr->internal_sample_fmt, | ||
| 179 | "in_buffer"); | ||
| 180 | if (!avr->in_buffer) { | ||
| 181 | ret = AVERROR(EINVAL); | ||
| 182 | goto error; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | if (avr->resample_needed) { | ||
| 186 | avr->resample_out_buffer = ff_audio_data_alloc(avr->out_channels, | ||
| 187 | 1024, avr->internal_sample_fmt, | ||
| 188 | "resample_out_buffer"); | ||
| 189 | if (!avr->resample_out_buffer) { | ||
| 190 | ret = AVERROR(EINVAL); | ||
| 191 | goto error; | ||
| 192 | } | ||
| 193 | } | ||
| 194 | if (avr->out_convert_needed) { | ||
| 195 | avr->out_buffer = ff_audio_data_alloc(avr->out_channels, 0, | ||
| 196 | avr->out_sample_fmt, "out_buffer"); | ||
| 197 | if (!avr->out_buffer) { | ||
| 198 | ret = AVERROR(EINVAL); | ||
| 199 | goto error; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | avr->out_fifo = av_audio_fifo_alloc(avr->out_sample_fmt, avr->out_channels, | ||
| 203 | 1024); | ||
| 204 | if (!avr->out_fifo) { | ||
| 205 | ret = AVERROR(ENOMEM); | ||
| 206 | goto error; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* setup contexts */ | ||
| 210 | if (avr->in_convert_needed) { | ||
| 211 | avr->ac_in = ff_audio_convert_alloc(avr, avr->internal_sample_fmt, | ||
| 212 | avr->in_sample_fmt, avr->in_channels, | ||
| 213 | avr->in_sample_rate, | ||
| 214 | avr->remap_point == REMAP_IN_CONVERT); | ||
| 215 | if (!avr->ac_in) { | ||
| 216 | ret = AVERROR(ENOMEM); | ||
| 217 | goto error; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | if (avr->out_convert_needed) { | ||
| 221 | enum AVSampleFormat src_fmt; | ||
| 222 | if (avr->in_convert_needed) | ||
| 223 | src_fmt = avr->internal_sample_fmt; | ||
| 224 | else | ||
| 225 | src_fmt = avr->in_sample_fmt; | ||
| 226 | avr->ac_out = ff_audio_convert_alloc(avr, avr->out_sample_fmt, src_fmt, | ||
| 227 | avr->out_channels, | ||
| 228 | avr->out_sample_rate, | ||
| 229 | avr->remap_point == REMAP_OUT_CONVERT); | ||
| 230 | if (!avr->ac_out) { | ||
| 231 | ret = AVERROR(ENOMEM); | ||
| 232 | goto error; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | if (avr->resample_needed) { | ||
| 236 | avr->resample = ff_audio_resample_init(avr); | ||
| 237 | if (!avr->resample) { | ||
| 238 | ret = AVERROR(ENOMEM); | ||
| 239 | goto error; | ||
| 240 | } | ||
| 241 | } | ||
| 242 | if (avr->mixing_needed) { | ||
| 243 | avr->am = ff_audio_mix_alloc(avr); | ||
| 244 | if (!avr->am) { | ||
| 245 | ret = AVERROR(ENOMEM); | ||
| 246 | goto error; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | return 0; | ||
| 251 | |||
| 252 | error: | ||
| 253 | avresample_close(avr); | ||
| 254 | return ret; | ||
| 255 | } | ||
| 256 | |||
| 257 | int avresample_is_open(AVAudioResampleContext *avr) | ||
| 258 | { | ||
| 259 | return !!avr->out_fifo; | ||
| 260 | } | ||
| 261 | |||
| 262 | void avresample_close(AVAudioResampleContext *avr) | ||
| 263 | { | ||
| 264 | ff_audio_data_free(&avr->in_buffer); | ||
| 265 | ff_audio_data_free(&avr->resample_out_buffer); | ||
| 266 | ff_audio_data_free(&avr->out_buffer); | ||
| 267 | av_audio_fifo_free(avr->out_fifo); | ||
| 268 | avr->out_fifo = NULL; | ||
| 269 | ff_audio_convert_free(&avr->ac_in); | ||
| 270 | ff_audio_convert_free(&avr->ac_out); | ||
| 271 | ff_audio_resample_free(&avr->resample); | ||
| 272 | ff_audio_mix_free(&avr->am); | ||
| 273 | av_freep(&avr->mix_matrix); | ||
| 274 | |||
| 275 | avr->use_channel_map = 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | void avresample_free(AVAudioResampleContext **avr) | ||
| 279 | { | ||
| 280 | if (!*avr) | ||
| 281 | return; | ||
| 282 | avresample_close(*avr); | ||
| 283 | av_opt_free(*avr); | ||
| 284 | av_freep(avr); | ||
| 285 | } | ||
| 286 | |||
| 287 | static int handle_buffered_output(AVAudioResampleContext *avr, | ||
| 288 | AudioData *output, AudioData *converted) | ||
| 289 | { | ||
| 290 | int ret; | ||
| 291 | |||
| 292 | if (!output || av_audio_fifo_size(avr->out_fifo) > 0 || | ||
| 293 | (converted && output->allocated_samples < converted->nb_samples)) { | ||
| 294 | if (converted) { | ||
| 295 | /* if there are any samples in the output FIFO or if the | ||
| 296 | user-supplied output buffer is not large enough for all samples, | ||
| 297 | we add to the output FIFO */ | ||
| 298 | av_log(avr, AV_LOG_TRACE, "[FIFO] add %s to out_fifo\n", converted->name); | ||
| 299 | ret = ff_audio_data_add_to_fifo(avr->out_fifo, converted, 0, | ||
| 300 | converted->nb_samples); | ||
| 301 | if (ret < 0) | ||
| 302 | return ret; | ||
| 303 | } | ||
| 304 | |||
| 305 | /* if the user specified an output buffer, read samples from the output | ||
| 306 | FIFO to the user output */ | ||
| 307 | if (output && output->allocated_samples > 0) { | ||
| 308 | av_log(avr, AV_LOG_TRACE, "[FIFO] read from out_fifo to output\n"); | ||
| 309 | av_log(avr, AV_LOG_TRACE, "[end conversion]\n"); | ||
| 310 | return ff_audio_data_read_from_fifo(avr->out_fifo, output, | ||
| 311 | output->allocated_samples); | ||
| 312 | } | ||
| 313 | } else if (converted) { | ||
| 314 | /* copy directly to output if it is large enough or there is not any | ||
| 315 | data in the output FIFO */ | ||
| 316 | av_log(avr, AV_LOG_TRACE, "[copy] %s to output\n", converted->name); | ||
| 317 | output->nb_samples = 0; | ||
| 318 | ret = ff_audio_data_copy(output, converted, | ||
| 319 | avr->remap_point == REMAP_OUT_COPY ? | ||
| 320 | &avr->ch_map_info : NULL); | ||
| 321 | if (ret < 0) | ||
| 322 | return ret; | ||
| 323 | av_log(avr, AV_LOG_TRACE, "[end conversion]\n"); | ||
| 324 | return output->nb_samples; | ||
| 325 | } | ||
| 326 | av_log(avr, AV_LOG_TRACE, "[end conversion]\n"); | ||
| 327 | return 0; | ||
| 328 | } | ||
| 329 | |||
| 330 | int attribute_align_arg avresample_convert(AVAudioResampleContext *avr, | ||
| 331 | uint8_t **output, int out_plane_size, | ||
| 332 | int out_samples, | ||
| 333 | uint8_t * const *input, | ||
| 334 | int in_plane_size, int in_samples) | ||
| 335 | { | ||
| 336 | AudioData input_buffer; | ||
| 337 | AudioData output_buffer; | ||
| 338 | AudioData *current_buffer; | ||
| 339 | int ret, direct_output; | ||
| 340 | |||
| 341 | /* reset internal buffers */ | ||
| 342 | if (avr->in_buffer) { | ||
| 343 | avr->in_buffer->nb_samples = 0; | ||
| 344 | ff_audio_data_set_channels(avr->in_buffer, | ||
| 345 | avr->in_buffer->allocated_channels); | ||
| 346 | } | ||
| 347 | if (avr->resample_out_buffer) { | ||
| 348 | avr->resample_out_buffer->nb_samples = 0; | ||
| 349 | ff_audio_data_set_channels(avr->resample_out_buffer, | ||
| 350 | avr->resample_out_buffer->allocated_channels); | ||
| 351 | } | ||
| 352 | if (avr->out_buffer) { | ||
| 353 | avr->out_buffer->nb_samples = 0; | ||
| 354 | ff_audio_data_set_channels(avr->out_buffer, | ||
| 355 | avr->out_buffer->allocated_channels); | ||
| 356 | } | ||
| 357 | |||
| 358 | av_log(avr, AV_LOG_TRACE, "[start conversion]\n"); | ||
| 359 | |||
| 360 | /* initialize output_buffer with output data */ | ||
| 361 | direct_output = output && av_audio_fifo_size(avr->out_fifo) == 0; | ||
| 362 | if (output) { | ||
| 363 | ret = ff_audio_data_init(&output_buffer, output, out_plane_size, | ||
| 364 | avr->out_channels, out_samples, | ||
| 365 | avr->out_sample_fmt, 0, "output"); | ||
| 366 | if (ret < 0) | ||
| 367 | return ret; | ||
| 368 | output_buffer.nb_samples = 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | if (input) { | ||
| 372 | /* initialize input_buffer with input data */ | ||
| 373 | ret = ff_audio_data_init(&input_buffer, input, in_plane_size, | ||
| 374 | avr->in_channels, in_samples, | ||
| 375 | avr->in_sample_fmt, 1, "input"); | ||
| 376 | if (ret < 0) | ||
| 377 | return ret; | ||
| 378 | current_buffer = &input_buffer; | ||
| 379 | |||
| 380 | if (avr->upmix_needed && !avr->in_convert_needed && !avr->resample_needed && | ||
| 381 | !avr->out_convert_needed && direct_output && out_samples >= in_samples) { | ||
| 382 | /* in some rare cases we can copy input to output and upmix | ||
| 383 | directly in the output buffer */ | ||
| 384 | av_log(avr, AV_LOG_TRACE, "[copy] %s to output\n", current_buffer->name); | ||
| 385 | ret = ff_audio_data_copy(&output_buffer, current_buffer, | ||
| 386 | avr->remap_point == REMAP_OUT_COPY ? | ||
| 387 | &avr->ch_map_info : NULL); | ||
| 388 | if (ret < 0) | ||
| 389 | return ret; | ||
| 390 | current_buffer = &output_buffer; | ||
| 391 | } else if (avr->remap_point == REMAP_OUT_COPY && | ||
| 392 | (!direct_output || out_samples < in_samples)) { | ||
| 393 | /* if remapping channels during output copy, we may need to | ||
| 394 | * use an intermediate buffer in order to remap before adding | ||
| 395 | * samples to the output fifo */ | ||
| 396 | av_log(avr, AV_LOG_TRACE, "[copy] %s to out_buffer\n", current_buffer->name); | ||
| 397 | ret = ff_audio_data_copy(avr->out_buffer, current_buffer, | ||
| 398 | &avr->ch_map_info); | ||
| 399 | if (ret < 0) | ||
| 400 | return ret; | ||
| 401 | current_buffer = avr->out_buffer; | ||
| 402 | } else if (avr->in_copy_needed || avr->in_convert_needed) { | ||
| 403 | /* if needed, copy or convert input to in_buffer, and downmix if | ||
| 404 | applicable */ | ||
| 405 | if (avr->in_convert_needed) { | ||
| 406 | ret = ff_audio_data_realloc(avr->in_buffer, | ||
| 407 | current_buffer->nb_samples); | ||
| 408 | if (ret < 0) | ||
| 409 | return ret; | ||
| 410 | av_log(avr, AV_LOG_TRACE, "[convert] %s to in_buffer\n", current_buffer->name); | ||
| 411 | ret = ff_audio_convert(avr->ac_in, avr->in_buffer, | ||
| 412 | current_buffer); | ||
| 413 | if (ret < 0) | ||
| 414 | return ret; | ||
| 415 | } else { | ||
| 416 | av_log(avr, AV_LOG_TRACE, "[copy] %s to in_buffer\n", current_buffer->name); | ||
| 417 | ret = ff_audio_data_copy(avr->in_buffer, current_buffer, | ||
| 418 | avr->remap_point == REMAP_IN_COPY ? | ||
| 419 | &avr->ch_map_info : NULL); | ||
| 420 | if (ret < 0) | ||
| 421 | return ret; | ||
| 422 | } | ||
| 423 | ff_audio_data_set_channels(avr->in_buffer, avr->in_channels); | ||
| 424 | if (avr->downmix_needed) { | ||
| 425 | av_log(avr, AV_LOG_TRACE, "[downmix] in_buffer\n"); | ||
| 426 | ret = ff_audio_mix(avr->am, avr->in_buffer); | ||
| 427 | if (ret < 0) | ||
| 428 | return ret; | ||
| 429 | } | ||
| 430 | current_buffer = avr->in_buffer; | ||
| 431 | } | ||
| 432 | } else { | ||
| 433 | /* flush resampling buffer and/or output FIFO if input is NULL */ | ||
| 434 | if (!avr->resample_needed) | ||
| 435 | return handle_buffered_output(avr, output ? &output_buffer : NULL, | ||
| 436 | NULL); | ||
| 437 | current_buffer = NULL; | ||
| 438 | } | ||
| 439 | |||
| 440 | if (avr->resample_needed) { | ||
| 441 | AudioData *resample_out; | ||
| 442 | |||
| 443 | if (!avr->out_convert_needed && direct_output && out_samples > 0) | ||
| 444 | resample_out = &output_buffer; | ||
| 445 | else | ||
| 446 | resample_out = avr->resample_out_buffer; | ||
| 447 | av_log(avr, AV_LOG_TRACE, "[resample] %s to %s\n", | ||
| 448 | current_buffer ? current_buffer->name : "null", | ||
| 449 | resample_out->name); | ||
| 450 | ret = ff_audio_resample(avr->resample, resample_out, | ||
| 451 | current_buffer); | ||
| 452 | if (ret < 0) | ||
| 453 | return ret; | ||
| 454 | |||
| 455 | /* if resampling did not produce any samples, just return 0 */ | ||
| 456 | if (resample_out->nb_samples == 0) { | ||
| 457 | av_log(avr, AV_LOG_TRACE, "[end conversion]\n"); | ||
| 458 | return 0; | ||
| 459 | } | ||
| 460 | |||
| 461 | current_buffer = resample_out; | ||
| 462 | } | ||
| 463 | |||
| 464 | if (avr->upmix_needed) { | ||
| 465 | av_log(avr, AV_LOG_TRACE, "[upmix] %s\n", current_buffer->name); | ||
| 466 | ret = ff_audio_mix(avr->am, current_buffer); | ||
| 467 | if (ret < 0) | ||
| 468 | return ret; | ||
| 469 | } | ||
| 470 | |||
| 471 | /* if we resampled or upmixed directly to output, return here */ | ||
| 472 | if (current_buffer == &output_buffer) { | ||
| 473 | av_log(avr, AV_LOG_TRACE, "[end conversion]\n"); | ||
| 474 | return current_buffer->nb_samples; | ||
| 475 | } | ||
| 476 | |||
| 477 | if (avr->out_convert_needed) { | ||
| 478 | if (direct_output && out_samples >= current_buffer->nb_samples) { | ||
| 479 | /* convert directly to output */ | ||
| 480 | av_log(avr, AV_LOG_TRACE, "[convert] %s to output\n", current_buffer->name); | ||
| 481 | ret = ff_audio_convert(avr->ac_out, &output_buffer, current_buffer); | ||
| 482 | if (ret < 0) | ||
| 483 | return ret; | ||
| 484 | |||
| 485 | av_log(avr, AV_LOG_TRACE, "[end conversion]\n"); | ||
| 486 | return output_buffer.nb_samples; | ||
| 487 | } else { | ||
| 488 | ret = ff_audio_data_realloc(avr->out_buffer, | ||
| 489 | current_buffer->nb_samples); | ||
| 490 | if (ret < 0) | ||
| 491 | return ret; | ||
| 492 | av_log(avr, AV_LOG_TRACE, "[convert] %s to out_buffer\n", current_buffer->name); | ||
| 493 | ret = ff_audio_convert(avr->ac_out, avr->out_buffer, | ||
| 494 | current_buffer); | ||
| 495 | if (ret < 0) | ||
| 496 | return ret; | ||
| 497 | current_buffer = avr->out_buffer; | ||
| 498 | } | ||
| 499 | } | ||
| 500 | |||
| 501 | return handle_buffered_output(avr, output ? &output_buffer : NULL, | ||
| 502 | current_buffer); | ||
| 503 | } | ||
| 504 | |||
| 505 | int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in) | ||
| 506 | { | ||
| 507 | if (avresample_is_open(avr)) { | ||
| 508 | avresample_close(avr); | ||
| 509 | } | ||
| 510 | |||
| 511 | if (in) { | ||
| 512 | avr->in_channel_layout = in->channel_layout; | ||
| 513 | avr->in_sample_rate = in->sample_rate; | ||
| 514 | avr->in_sample_fmt = in->format; | ||
| 515 | } | ||
| 516 | |||
| 517 | if (out) { | ||
| 518 | avr->out_channel_layout = out->channel_layout; | ||
| 519 | avr->out_sample_rate = out->sample_rate; | ||
| 520 | avr->out_sample_fmt = out->format; | ||
| 521 | } | ||
| 522 | |||
| 523 | return 0; | ||
| 524 | } | ||
| 525 | |||
| 526 | static int config_changed(AVAudioResampleContext *avr, | ||
| 527 | AVFrame *out, AVFrame *in) | ||
| 528 | { | ||
| 529 | int ret = 0; | ||
| 530 | |||
| 531 | if (in) { | ||
| 532 | if (avr->in_channel_layout != in->channel_layout || | ||
| 533 | avr->in_sample_rate != in->sample_rate || | ||
| 534 | avr->in_sample_fmt != in->format) { | ||
| 535 | ret |= AVERROR_INPUT_CHANGED; | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | if (out) { | ||
| 540 | if (avr->out_channel_layout != out->channel_layout || | ||
| 541 | avr->out_sample_rate != out->sample_rate || | ||
| 542 | avr->out_sample_fmt != out->format) { | ||
| 543 | ret |= AVERROR_OUTPUT_CHANGED; | ||
| 544 | } | ||
| 545 | } | ||
| 546 | |||
| 547 | return ret; | ||
| 548 | } | ||
| 549 | |||
| 550 | static inline int convert_frame(AVAudioResampleContext *avr, | ||
| 551 | AVFrame *out, AVFrame *in) | ||
| 552 | { | ||
| 553 | int ret; | ||
| 554 | uint8_t **out_data = NULL, **in_data = NULL; | ||
| 555 | int out_linesize = 0, in_linesize = 0; | ||
| 556 | int out_nb_samples = 0, in_nb_samples = 0; | ||
| 557 | |||
| 558 | if (out) { | ||
| 559 | out_data = out->extended_data; | ||
| 560 | out_linesize = out->linesize[0]; | ||
| 561 | out_nb_samples = out->nb_samples; | ||
| 562 | } | ||
| 563 | |||
| 564 | if (in) { | ||
| 565 | in_data = in->extended_data; | ||
| 566 | in_linesize = in->linesize[0]; | ||
| 567 | in_nb_samples = in->nb_samples; | ||
| 568 | } | ||
| 569 | |||
| 570 | ret = avresample_convert(avr, out_data, out_linesize, | ||
| 571 | out_nb_samples, | ||
| 572 | in_data, in_linesize, | ||
| 573 | in_nb_samples); | ||
| 574 | |||
| 575 | if (ret < 0) { | ||
| 576 | if (out) | ||
| 577 | out->nb_samples = 0; | ||
| 578 | return ret; | ||
| 579 | } | ||
| 580 | |||
| 581 | if (out) | ||
| 582 | out->nb_samples = ret; | ||
| 583 | |||
| 584 | return 0; | ||
| 585 | } | ||
| 586 | |||
| 587 | static inline int available_samples(AVFrame *out) | ||
| 588 | { | ||
| 589 | int samples; | ||
| 590 | int bytes_per_sample = av_get_bytes_per_sample(out->format); | ||
| 591 | if (!bytes_per_sample) | ||
| 592 | return AVERROR(EINVAL); | ||
| 593 | |||
| 594 | samples = out->linesize[0] / bytes_per_sample; | ||
| 595 | if (av_sample_fmt_is_planar(out->format)) { | ||
| 596 | return samples; | ||
| 597 | } else { | ||
| 598 | int channels = av_get_channel_layout_nb_channels(out->channel_layout); | ||
| 599 | return samples / channels; | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | int avresample_convert_frame(AVAudioResampleContext *avr, | ||
| 604 | AVFrame *out, AVFrame *in) | ||
| 605 | { | ||
| 606 | int ret, setup = 0; | ||
| 607 | |||
| 608 | if (!avresample_is_open(avr)) { | ||
| 609 | if ((ret = avresample_config(avr, out, in)) < 0) | ||
| 610 | return ret; | ||
| 611 | if ((ret = avresample_open(avr)) < 0) | ||
| 612 | return ret; | ||
| 613 | setup = 1; | ||
| 614 | } else { | ||
| 615 | // return as is or reconfigure for input changes? | ||
| 616 | if ((ret = config_changed(avr, out, in))) | ||
| 617 | return ret; | ||
| 618 | } | ||
| 619 | |||
| 620 | if (out) { | ||
| 621 | if (!out->linesize[0]) { | ||
| 622 | out->nb_samples = avresample_get_out_samples(avr, in->nb_samples); | ||
| 623 | if ((ret = av_frame_get_buffer(out, 0)) < 0) { | ||
| 624 | if (setup) | ||
| 625 | avresample_close(avr); | ||
| 626 | return ret; | ||
| 627 | } | ||
| 628 | } else { | ||
| 629 | if (!out->nb_samples) | ||
| 630 | out->nb_samples = available_samples(out); | ||
| 631 | } | ||
| 632 | } | ||
| 633 | |||
| 634 | return convert_frame(avr, out, in); | ||
| 635 | } | ||
| 636 | |||
| 637 | int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, | ||
| 638 | int stride) | ||
| 639 | { | ||
| 640 | int in_channels, out_channels, i, o; | ||
| 641 | |||
| 642 | if (avr->am) | ||
| 643 | return ff_audio_mix_get_matrix(avr->am, matrix, stride); | ||
| 644 | |||
| 645 | in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | ||
| 646 | out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | ||
| 647 | |||
| 648 | if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS || | ||
| 649 | out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) { | ||
| 650 | av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n"); | ||
| 651 | return AVERROR(EINVAL); | ||
| 652 | } | ||
| 653 | |||
| 654 | if (!avr->mix_matrix) { | ||
| 655 | av_log(avr, AV_LOG_ERROR, "matrix is not set\n"); | ||
| 656 | return AVERROR(EINVAL); | ||
| 657 | } | ||
| 658 | |||
| 659 | for (o = 0; o < out_channels; o++) | ||
| 660 | for (i = 0; i < in_channels; i++) | ||
| 661 | matrix[o * stride + i] = avr->mix_matrix[o * in_channels + i]; | ||
| 662 | |||
| 663 | return 0; | ||
| 664 | } | ||
| 665 | |||
| 666 | int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, | ||
| 667 | int stride) | ||
| 668 | { | ||
| 669 | int in_channels, out_channels, i, o; | ||
| 670 | |||
| 671 | if (avr->am) | ||
| 672 | return ff_audio_mix_set_matrix(avr->am, matrix, stride); | ||
| 673 | |||
| 674 | in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | ||
| 675 | out_channels = av_get_channel_layout_nb_channels(avr->out_channel_layout); | ||
| 676 | |||
| 677 | if ( in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS || | ||
| 678 | out_channels <= 0 || out_channels > AVRESAMPLE_MAX_CHANNELS) { | ||
| 679 | av_log(avr, AV_LOG_ERROR, "Invalid channel layouts\n"); | ||
| 680 | return AVERROR(EINVAL); | ||
| 681 | } | ||
| 682 | |||
| 683 | if (avr->mix_matrix) | ||
| 684 | av_freep(&avr->mix_matrix); | ||
| 685 | avr->mix_matrix = av_malloc(in_channels * out_channels * | ||
| 686 | sizeof(*avr->mix_matrix)); | ||
| 687 | if (!avr->mix_matrix) | ||
| 688 | return AVERROR(ENOMEM); | ||
| 689 | |||
| 690 | for (o = 0; o < out_channels; o++) | ||
| 691 | for (i = 0; i < in_channels; i++) | ||
| 692 | avr->mix_matrix[o * in_channels + i] = matrix[o * stride + i]; | ||
| 693 | |||
| 694 | return 0; | ||
| 695 | } | ||
| 696 | |||
| 697 | int avresample_set_channel_mapping(AVAudioResampleContext *avr, | ||
| 698 | const int *channel_map) | ||
| 699 | { | ||
| 700 | ChannelMapInfo *info = &avr->ch_map_info; | ||
| 701 | int in_channels, ch, i; | ||
| 702 | |||
| 703 | in_channels = av_get_channel_layout_nb_channels(avr->in_channel_layout); | ||
| 704 | if (in_channels <= 0 || in_channels > AVRESAMPLE_MAX_CHANNELS) { | ||
| 705 | av_log(avr, AV_LOG_ERROR, "Invalid input channel layout\n"); | ||
| 706 | return AVERROR(EINVAL); | ||
| 707 | } | ||
| 708 | |||
| 709 | memset(info, 0, sizeof(*info)); | ||
| 710 | memset(info->input_map, -1, sizeof(info->input_map)); | ||
| 711 | |||
| 712 | for (ch = 0; ch < in_channels; ch++) { | ||
| 713 | if (channel_map[ch] >= in_channels) { | ||
| 714 | av_log(avr, AV_LOG_ERROR, "Invalid channel map\n"); | ||
| 715 | return AVERROR(EINVAL); | ||
| 716 | } | ||
| 717 | if (channel_map[ch] < 0) { | ||
| 718 | info->channel_zero[ch] = 1; | ||
| 719 | info->channel_map[ch] = -1; | ||
| 720 | info->do_zero = 1; | ||
| 721 | } else if (info->input_map[channel_map[ch]] >= 0) { | ||
| 722 | info->channel_copy[ch] = info->input_map[channel_map[ch]]; | ||
| 723 | info->channel_map[ch] = -1; | ||
| 724 | info->do_copy = 1; | ||
| 725 | } else { | ||
| 726 | info->channel_map[ch] = channel_map[ch]; | ||
| 727 | info->input_map[channel_map[ch]] = ch; | ||
| 728 | info->do_remap = 1; | ||
| 729 | } | ||
| 730 | } | ||
| 731 | /* Fill-in unmapped input channels with unmapped output channels. | ||
| 732 | This is used when remapping during conversion from interleaved to | ||
| 733 | planar format. */ | ||
| 734 | for (ch = 0, i = 0; ch < in_channels && i < in_channels; ch++, i++) { | ||
| 735 | while (ch < in_channels && info->input_map[ch] >= 0) | ||
| 736 | ch++; | ||
| 737 | while (i < in_channels && info->channel_map[i] >= 0) | ||
| 738 | i++; | ||
| 739 | if (ch >= in_channels || i >= in_channels) | ||
| 740 | break; | ||
| 741 | info->input_map[ch] = i; | ||
| 742 | } | ||
| 743 | |||
| 744 | avr->use_channel_map = 1; | ||
| 745 | return 0; | ||
| 746 | } | ||
| 747 | |||
| 748 | int avresample_available(AVAudioResampleContext *avr) | ||
| 749 | { | ||
| 750 | return av_audio_fifo_size(avr->out_fifo); | ||
| 751 | } | ||
| 752 | |||
| 753 | int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples) | ||
| 754 | { | ||
| 755 | int64_t samples = avresample_get_delay(avr) + (int64_t)in_nb_samples; | ||
| 756 | |||
| 757 | if (avr->resample_needed) { | ||
| 758 | samples = av_rescale_rnd(samples, | ||
| 759 | avr->out_sample_rate, | ||
| 760 | avr->in_sample_rate, | ||
| 761 | AV_ROUND_UP); | ||
| 762 | } | ||
| 763 | |||
| 764 | samples += avresample_available(avr); | ||
| 765 | |||
| 766 | if (samples > INT_MAX) | ||
| 767 | return AVERROR(EINVAL); | ||
| 768 | |||
| 769 | return samples; | ||
| 770 | } | ||
| 771 | |||
| 772 | int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples) | ||
| 773 | { | ||
| 774 | if (!output) | ||
| 775 | return av_audio_fifo_drain(avr->out_fifo, nb_samples); | ||
| 776 | return av_audio_fifo_read(avr->out_fifo, (void**)output, nb_samples); | ||
| 777 | } | ||
| 778 | |||
| 779 | unsigned avresample_version(void) | ||
| 780 | { | ||
| 781 | return LIBAVRESAMPLE_VERSION_INT; | ||
| 782 | } | ||
| 783 | |||
| 784 | const char *avresample_license(void) | ||
| 785 | { | ||
| 786 | #define LICENSE_PREFIX "libavresample license: " | ||
| 787 | return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; | ||
| 788 | } | ||
| 789 | |||
| 790 | const char *avresample_configuration(void) | ||
| 791 | { | ||
| 792 | return FFMPEG_CONFIGURATION; | ||
| 793 | } | ||
| @@ -1,50 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * This file is part of FFmpeg. | ||
| 3 | * | ||
| 4 | * FFmpeg is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU Lesser General Public | ||
| 6 | * License as published by the Free Software Foundation; either | ||
| 7 | * version 2.1 of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 12 | * Lesser General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU Lesser General Public | ||
| 15 | * License along with FFmpeg; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef AVRESAMPLE_VERSION_H | ||
| 20 | #define AVRESAMPLE_VERSION_H | ||
| 21 | |||
| 22 | /** | ||
| 23 | * @file | ||
| 24 | * @ingroup lavr | ||
| 25 | * Libavresample version macros. | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include "libavutil/version.h" | ||
| 29 | |||
| 30 | #define LIBAVRESAMPLE_VERSION_MAJOR 4 | ||
| 31 | #define LIBAVRESAMPLE_VERSION_MINOR 0 | ||
| 32 | #define LIBAVRESAMPLE_VERSION_MICRO 0 | ||
| 33 | |||
| 34 | #define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \ | ||
| 35 | LIBAVRESAMPLE_VERSION_MINOR, \ | ||
| 36 | LIBAVRESAMPLE_VERSION_MICRO) | ||
| 37 | #define LIBAVRESAMPLE_VERSION AV_VERSION(LIBAVRESAMPLE_VERSION_MAJOR, \ | ||
| 38 | LIBAVRESAMPLE_VERSION_MINOR, \ | ||
| 39 | LIBAVRESAMPLE_VERSION_MICRO) | ||
| 40 | #define LIBAVRESAMPLE_BUILD LIBAVRESAMPLE_VERSION_INT | ||
| 41 | |||
| 42 | #define LIBAVRESAMPLE_IDENT "Lavr" AV_STRINGIFY(LIBAVRESAMPLE_VERSION) | ||
| 43 | |||
| 44 | /** | ||
| 45 | * FF_API_* defines may be placed below to indicate public API that will be | ||
| 46 | * dropped at a future version bump. The defines themselves are not part of | ||
| 47 | * the public API and may change, break or disappear at any time. | ||
| 48 | */ | ||
| 49 | |||
| 50 | #endif /* AVRESAMPLE_VERSION_H */ | ||
| @@ -1,9 +0,0 @@ | |||
| 1 | OBJS += x86/audio_convert_init.o \ | ||
| 2 | x86/audio_mix_init.o \ | ||
| 3 | x86/dither_init.o \ | ||
| 4 | |||
| 5 | OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o | ||
| 6 | |||
| 7 | X86ASM-OBJS += x86/audio_convert.o \ | ||
| 8 | x86/audio_mix.o \ | ||
| 9 | x86/dither.o \ | ||
| @@ -1,1261 +0,0 @@ | |||
| 1 | ;****************************************************************************** | ||
| 2 | ;* x86 optimized Format Conversion Utils | ||
| 3 | ;* Copyright (c) 2008 Loren Merritt | ||
| 4 | ;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 5 | ;* | ||
| 6 | ;* This file is part of FFmpeg. | ||
| 7 | ;* | ||
| 8 | ;* FFmpeg is free software; you can redistribute it and/or | ||
| 9 | ;* modify it under the terms of the GNU Lesser General Public | ||
| 10 | ;* License as published by the Free Software Foundation; either | ||
| 11 | ;* version 2.1 of the License, or (at your option) any later version. | ||
| 12 | ;* | ||
| 13 | ;* FFmpeg is distributed in the hope that it will be useful, | ||
| 14 | ;* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 16 | ;* Lesser General Public License for more details. | ||
| 17 | ;* | ||
| 18 | ;* You should have received a copy of the GNU Lesser General Public | ||
| 19 | ;* License along with FFmpeg; if not, write to the Free Software | ||
| 20 | ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 21 | ;****************************************************************************** | ||
| 22 | |||
| 23 | %include "libavutil/x86/x86util.asm" | ||
| 24 | %include "util.asm" | ||
| 25 | |||
| 26 | SECTION_RODATA 32 | ||
| 27 | |||
| 28 | pf_s32_inv_scale: times 8 dd 0x30000000 | ||
| 29 | pf_s32_scale: times 8 dd 0x4f000000 | ||
| 30 | pf_s32_clip: times 8 dd 0x4effffff | ||
| 31 | pf_s16_inv_scale: times 4 dd 0x38000000 | ||
| 32 | pf_s16_scale: times 4 dd 0x47000000 | ||
| 33 | pb_shuf_unpack_even: db -1, -1, 0, 1, -1, -1, 2, 3, -1, -1, 8, 9, -1, -1, 10, 11 | ||
| 34 | pb_shuf_unpack_odd: db -1, -1, 4, 5, -1, -1, 6, 7, -1, -1, 12, 13, -1, -1, 14, 15 | ||
| 35 | pb_interleave_words: SHUFFLE_MASK_W 0, 4, 1, 5, 2, 6, 3, 7 | ||
| 36 | pb_deinterleave_words: SHUFFLE_MASK_W 0, 2, 4, 6, 1, 3, 5, 7 | ||
| 37 | pw_zero_even: times 4 dw 0x0000, 0xffff | ||
| 38 | |||
| 39 | SECTION .text | ||
| 40 | |||
| 41 | ;------------------------------------------------------------------------------ | ||
| 42 | ; void ff_conv_s16_to_s32(int32_t *dst, const int16_t *src, int len); | ||
| 43 | ;------------------------------------------------------------------------------ | ||
| 44 | |||
| 45 | INIT_XMM sse2 | ||
| 46 | cglobal conv_s16_to_s32, 3,3,3, dst, src, len | ||
| 47 | lea lenq, [2*lend] | ||
| 48 | lea dstq, [dstq+2*lenq] | ||
| 49 | add srcq, lenq | ||
| 50 | neg lenq | ||
| 51 | .loop: | ||
| 52 | mova m2, [srcq+lenq] | ||
| 53 | pxor m0, m0 | ||
| 54 | pxor m1, m1 | ||
| 55 | punpcklwd m0, m2 | ||
| 56 | punpckhwd m1, m2 | ||
| 57 | mova [dstq+2*lenq ], m0 | ||
| 58 | mova [dstq+2*lenq+mmsize], m1 | ||
| 59 | add lenq, mmsize | ||
| 60 | jl .loop | ||
| 61 | REP_RET | ||
| 62 | |||
| 63 | ;------------------------------------------------------------------------------ | ||
| 64 | ; void ff_conv_s16_to_flt(float *dst, const int16_t *src, int len); | ||
| 65 | ;------------------------------------------------------------------------------ | ||
| 66 | |||
| 67 | %macro CONV_S16_TO_FLT 0 | ||
| 68 | cglobal conv_s16_to_flt, 3,3,3, dst, src, len | ||
| 69 | lea lenq, [2*lend] | ||
| 70 | add srcq, lenq | ||
| 71 | lea dstq, [dstq + 2*lenq] | ||
| 72 | neg lenq | ||
| 73 | mova m2, [pf_s16_inv_scale] | ||
| 74 | ALIGN 16 | ||
| 75 | .loop: | ||
| 76 | mova m0, [srcq+lenq] | ||
| 77 | S16_TO_S32_SX 0, 1 | ||
| 78 | cvtdq2ps m0, m0 | ||
| 79 | cvtdq2ps m1, m1 | ||
| 80 | mulps m0, m2 | ||
| 81 | mulps m1, m2 | ||
| 82 | mova [dstq+2*lenq ], m0 | ||
| 83 | mova [dstq+2*lenq+mmsize], m1 | ||
| 84 | add lenq, mmsize | ||
| 85 | jl .loop | ||
| 86 | REP_RET | ||
| 87 | %endmacro | ||
| 88 | |||
| 89 | INIT_XMM sse2 | ||
| 90 | CONV_S16_TO_FLT | ||
| 91 | INIT_XMM sse4 | ||
| 92 | CONV_S16_TO_FLT | ||
| 93 | |||
| 94 | ;------------------------------------------------------------------------------ | ||
| 95 | ; void ff_conv_s32_to_s16(int16_t *dst, const int32_t *src, int len); | ||
| 96 | ;------------------------------------------------------------------------------ | ||
| 97 | |||
| 98 | %macro CONV_S32_TO_S16 0 | ||
| 99 | cglobal conv_s32_to_s16, 3,3,4, dst, src, len | ||
| 100 | lea lenq, [2*lend] | ||
| 101 | lea srcq, [srcq+2*lenq] | ||
| 102 | add dstq, lenq | ||
| 103 | neg lenq | ||
| 104 | .loop: | ||
| 105 | mova m0, [srcq+2*lenq ] | ||
| 106 | mova m1, [srcq+2*lenq+ mmsize] | ||
| 107 | mova m2, [srcq+2*lenq+2*mmsize] | ||
| 108 | mova m3, [srcq+2*lenq+3*mmsize] | ||
| 109 | psrad m0, 16 | ||
| 110 | psrad m1, 16 | ||
| 111 | psrad m2, 16 | ||
| 112 | psrad m3, 16 | ||
| 113 | packssdw m0, m1 | ||
| 114 | packssdw m2, m3 | ||
| 115 | mova [dstq+lenq ], m0 | ||
| 116 | mova [dstq+lenq+mmsize], m2 | ||
| 117 | add lenq, mmsize*2 | ||
| 118 | jl .loop | ||
| 119 | %if mmsize == 8 | ||
| 120 | emms | ||
| 121 | RET | ||
| 122 | %else | ||
| 123 | REP_RET | ||
| 124 | %endif | ||
| 125 | %endmacro | ||
| 126 | |||
| 127 | INIT_MMX mmx | ||
| 128 | CONV_S32_TO_S16 | ||
| 129 | INIT_XMM sse2 | ||
| 130 | CONV_S32_TO_S16 | ||
| 131 | |||
| 132 | ;------------------------------------------------------------------------------ | ||
| 133 | ; void ff_conv_s32_to_flt(float *dst, const int32_t *src, int len); | ||
| 134 | ;------------------------------------------------------------------------------ | ||
| 135 | |||
| 136 | %macro CONV_S32_TO_FLT 0 | ||
| 137 | cglobal conv_s32_to_flt, 3,3,3, dst, src, len | ||
| 138 | lea lenq, [4*lend] | ||
| 139 | add srcq, lenq | ||
| 140 | add dstq, lenq | ||
| 141 | neg lenq | ||
| 142 | mova m0, [pf_s32_inv_scale] | ||
| 143 | ALIGN 16 | ||
| 144 | .loop: | ||
| 145 | cvtdq2ps m1, [srcq+lenq ] | ||
| 146 | cvtdq2ps m2, [srcq+lenq+mmsize] | ||
| 147 | mulps m1, m1, m0 | ||
| 148 | mulps m2, m2, m0 | ||
| 149 | mova [dstq+lenq ], m1 | ||
| 150 | mova [dstq+lenq+mmsize], m2 | ||
| 151 | add lenq, mmsize*2 | ||
| 152 | jl .loop | ||
| 153 | REP_RET | ||
| 154 | %endmacro | ||
| 155 | |||
| 156 | INIT_XMM sse2 | ||
| 157 | CONV_S32_TO_FLT | ||
| 158 | %if HAVE_AVX_EXTERNAL | ||
| 159 | INIT_YMM avx | ||
| 160 | CONV_S32_TO_FLT | ||
| 161 | %endif | ||
| 162 | |||
| 163 | ;------------------------------------------------------------------------------ | ||
| 164 | ; void ff_conv_flt_to_s16(int16_t *dst, const float *src, int len); | ||
| 165 | ;------------------------------------------------------------------------------ | ||
| 166 | |||
| 167 | INIT_XMM sse2 | ||
| 168 | cglobal conv_flt_to_s16, 3,3,5, dst, src, len | ||
| 169 | lea lenq, [2*lend] | ||
| 170 | lea srcq, [srcq+2*lenq] | ||
| 171 | add dstq, lenq | ||
| 172 | neg lenq | ||
| 173 | mova m4, [pf_s16_scale] | ||
| 174 | .loop: | ||
| 175 | mova m0, [srcq+2*lenq ] | ||
| 176 | mova m1, [srcq+2*lenq+1*mmsize] | ||
| 177 | mova m2, [srcq+2*lenq+2*mmsize] | ||
| 178 | mova m3, [srcq+2*lenq+3*mmsize] | ||
| 179 | mulps m0, m4 | ||
| 180 | mulps m1, m4 | ||
| 181 | mulps m2, m4 | ||
| 182 | mulps m3, m4 | ||
| 183 | cvtps2dq m0, m0 | ||
| 184 | cvtps2dq m1, m1 | ||
| 185 | cvtps2dq m2, m2 | ||
| 186 | cvtps2dq m3, m3 | ||
| 187 | packssdw m0, m1 | ||
| 188 | packssdw m2, m3 | ||
| 189 | mova [dstq+lenq ], m0 | ||
| 190 | mova [dstq+lenq+mmsize], m2 | ||
| 191 | add lenq, mmsize*2 | ||
| 192 | jl .loop | ||
| 193 | REP_RET | ||
| 194 | |||
| 195 | ;------------------------------------------------------------------------------ | ||
| 196 | ; void ff_conv_flt_to_s32(int32_t *dst, const float *src, int len); | ||
| 197 | ;------------------------------------------------------------------------------ | ||
| 198 | |||
| 199 | %macro CONV_FLT_TO_S32 0 | ||
| 200 | cglobal conv_flt_to_s32, 3,3,6, dst, src, len | ||
| 201 | lea lenq, [lend*4] | ||
| 202 | add srcq, lenq | ||
| 203 | add dstq, lenq | ||
| 204 | neg lenq | ||
| 205 | mova m4, [pf_s32_scale] | ||
| 206 | mova m5, [pf_s32_clip] | ||
| 207 | .loop: | ||
| 208 | mulps m0, m4, [srcq+lenq ] | ||
| 209 | mulps m1, m4, [srcq+lenq+1*mmsize] | ||
| 210 | mulps m2, m4, [srcq+lenq+2*mmsize] | ||
| 211 | mulps m3, m4, [srcq+lenq+3*mmsize] | ||
| 212 | minps m0, m0, m5 | ||
| 213 | minps m1, m1, m5 | ||
| 214 | minps m2, m2, m5 | ||
| 215 | minps m3, m3, m5 | ||
| 216 | cvtps2dq m0, m0 | ||
| 217 | cvtps2dq m1, m1 | ||
| 218 | cvtps2dq m2, m2 | ||
| 219 | cvtps2dq m3, m3 | ||
| 220 | mova [dstq+lenq ], m0 | ||
| 221 | mova [dstq+lenq+1*mmsize], m1 | ||
| 222 | mova [dstq+lenq+2*mmsize], m2 | ||
| 223 | mova [dstq+lenq+3*mmsize], m3 | ||
| 224 | add lenq, mmsize*4 | ||
| 225 | jl .loop | ||
| 226 | REP_RET | ||
| 227 | %endmacro | ||
| 228 | |||
| 229 | INIT_XMM sse2 | ||
| 230 | CONV_FLT_TO_S32 | ||
| 231 | %if HAVE_AVX_EXTERNAL | ||
| 232 | INIT_YMM avx | ||
| 233 | CONV_FLT_TO_S32 | ||
| 234 | %endif | ||
| 235 | |||
| 236 | ;------------------------------------------------------------------------------ | ||
| 237 | ; void ff_conv_s16p_to_s16_2ch(int16_t *dst, int16_t *const *src, int len, | ||
| 238 | ; int channels); | ||
| 239 | ;------------------------------------------------------------------------------ | ||
| 240 | |||
| 241 | %macro CONV_S16P_TO_S16_2CH 0 | ||
| 242 | cglobal conv_s16p_to_s16_2ch, 3,4,5, dst, src0, len, src1 | ||
| 243 | mov src1q, [src0q+gprsize] | ||
| 244 | mov src0q, [src0q ] | ||
| 245 | lea lenq, [2*lend] | ||
| 246 | add src0q, lenq | ||
| 247 | add src1q, lenq | ||
| 248 | lea dstq, [dstq+2*lenq] | ||
| 249 | neg lenq | ||
| 250 | .loop: | ||
| 251 | mova m0, [src0q+lenq ] | ||
| 252 | mova m1, [src1q+lenq ] | ||
| 253 | mova m2, [src0q+lenq+mmsize] | ||
| 254 | mova m3, [src1q+lenq+mmsize] | ||
| 255 | SBUTTERFLY2 wd, 0, 1, 4 | ||
| 256 | SBUTTERFLY2 wd, 2, 3, 4 | ||
| 257 | mova [dstq+2*lenq+0*mmsize], m0 | ||
| 258 | mova [dstq+2*lenq+1*mmsize], m1 | ||
| 259 | mova [dstq+2*lenq+2*mmsize], m2 | ||
| 260 | mova [dstq+2*lenq+3*mmsize], m3 | ||
| 261 | add lenq, 2*mmsize | ||
| 262 | jl .loop | ||
| 263 | REP_RET | ||
| 264 | %endmacro | ||
| 265 | |||
| 266 | INIT_XMM sse2 | ||
| 267 | CONV_S16P_TO_S16_2CH | ||
| 268 | %if HAVE_AVX_EXTERNAL | ||
| 269 | INIT_XMM avx | ||
| 270 | CONV_S16P_TO_S16_2CH | ||
| 271 | %endif | ||
| 272 | |||
| 273 | ;------------------------------------------------------------------------------ | ||
| 274 | ; void ff_conv_s16p_to_s16_6ch(int16_t *dst, int16_t *const *src, int len, | ||
| 275 | ; int channels); | ||
| 276 | ;------------------------------------------------------------------------------ | ||
| 277 | |||
| 278 | ;------------------------------------------------------------------------------ | ||
| 279 | ; NOTE: In the 6-channel functions, len could be used as an index on x86-64 | ||
| 280 | ; instead of just a counter, which would avoid incrementing the | ||
| 281 | ; pointers, but the extra complexity and amount of code is not worth | ||
| 282 | ; the small gain. On x86-32 there are not enough registers to use len | ||
| 283 | ; as an index without keeping two of the pointers on the stack and | ||
| 284 | ; loading them in each iteration. | ||
| 285 | ;------------------------------------------------------------------------------ | ||
| 286 | |||
| 287 | %macro CONV_S16P_TO_S16_6CH 0 | ||
| 288 | %if ARCH_X86_64 | ||
| 289 | cglobal conv_s16p_to_s16_6ch, 3,8,7, dst, src0, len, src1, src2, src3, src4, src5 | ||
| 290 | %else | ||
| 291 | cglobal conv_s16p_to_s16_6ch, 2,7,7, dst, src0, src1, src2, src3, src4, src5 | ||
| 292 | %define lend dword r2m | ||
| 293 | %endif | ||
| 294 | mov src1q, [src0q+1*gprsize] | ||
| 295 | mov src2q, [src0q+2*gprsize] | ||
| 296 | mov src3q, [src0q+3*gprsize] | ||
| 297 | mov src4q, [src0q+4*gprsize] | ||
| 298 | mov src5q, [src0q+5*gprsize] | ||
| 299 | mov src0q, [src0q] | ||
| 300 | sub src1q, src0q | ||
| 301 | sub src2q, src0q | ||
| 302 | sub src3q, src0q | ||
| 303 | sub src4q, src0q | ||
| 304 | sub src5q, src0q | ||
| 305 | .loop: | ||
| 306 | %if cpuflag(sse2slow) | ||
| 307 | movq m0, [src0q ] ; m0 = 0, 6, 12, 18, x, x, x, x | ||
| 308 | movq m1, [src0q+src1q] ; m1 = 1, 7, 13, 19, x, x, x, x | ||
| 309 | movq m2, [src0q+src2q] ; m2 = 2, 8, 14, 20, x, x, x, x | ||
| 310 | movq m3, [src0q+src3q] ; m3 = 3, 9, 15, 21, x, x, x, x | ||
| 311 | movq m4, [src0q+src4q] ; m4 = 4, 10, 16, 22, x, x, x, x | ||
| 312 | movq m5, [src0q+src5q] ; m5 = 5, 11, 17, 23, x, x, x, x | ||
| 313 | ; unpack words: | ||
| 314 | punpcklwd m0, m1 ; m0 = 0, 1, 6, 7, 12, 13, 18, 19 | ||
| 315 | punpcklwd m2, m3 ; m2 = 4, 5, 10, 11, 16, 17, 22, 23 | ||
| 316 | punpcklwd m4, m5 ; m4 = 2, 3, 8, 9, 14, 15, 20, 21 | ||
| 317 | ; blend dwords | ||
| 318 | shufps m1, m0, m2, q2020 ; m1 = 0, 1, 12, 13, 2, 3, 14, 15 | ||
| 319 | shufps m0, m4, q2031 ; m0 = 6, 7, 18, 19, 4, 5, 16, 17 | ||
| 320 | shufps m2, m4, q3131 ; m2 = 8, 9, 20, 21, 10, 11, 22, 23 | ||
| 321 | ; shuffle dwords | ||
| 322 | pshufd m0, m0, q1302 ; m0 = 4, 5, 6, 7, 16, 17, 18, 19 | ||
| 323 | pshufd m1, m1, q3120 ; m1 = 0, 1, 2, 3, 12, 13, 14, 15 | ||
| 324 | pshufd m2, m2, q3120 ; m2 = 8, 9, 10, 11, 20, 21, 22, 23 | ||
| 325 | movq [dstq+0*mmsize/2], m1 | ||
| 326 | movq [dstq+1*mmsize/2], m0 | ||
| 327 | movq [dstq+2*mmsize/2], m2 | ||
| 328 | movhps [dstq+3*mmsize/2], m1 | ||
| 329 | movhps [dstq+4*mmsize/2], m0 | ||
| 330 | movhps [dstq+5*mmsize/2], m2 | ||
| 331 | add src0q, mmsize/2 | ||
| 332 | add dstq, mmsize*3 | ||
| 333 | sub lend, mmsize/4 | ||
| 334 | %else | ||
| 335 | mova m0, [src0q ] ; m0 = 0, 6, 12, 18, 24, 30, 36, 42 | ||
| 336 | mova m1, [src0q+src1q] ; m1 = 1, 7, 13, 19, 25, 31, 37, 43 | ||
| 337 | mova m2, [src0q+src2q] ; m2 = 2, 8, 14, 20, 26, 32, 38, 44 | ||
| 338 | mova m3, [src0q+src3q] ; m3 = 3, 9, 15, 21, 27, 33, 39, 45 | ||
| 339 | mova m4, [src0q+src4q] ; m4 = 4, 10, 16, 22, 28, 34, 40, 46 | ||
| 340 | mova m5, [src0q+src5q] ; m5 = 5, 11, 17, 23, 29, 35, 41, 47 | ||
| 341 | ; unpack words: | ||
| 342 | SBUTTERFLY2 wd, 0, 1, 6 ; m0 = 0, 1, 6, 7, 12, 13, 18, 19 | ||
| 343 | ; m1 = 24, 25, 30, 31, 36, 37, 42, 43 | ||
| 344 | SBUTTERFLY2 wd, 2, 3, 6 ; m2 = 2, 3, 8, 9, 14, 15, 20, 21 | ||
| 345 | ; m3 = 26, 27, 32, 33, 38, 39, 44, 45 | ||
| 346 | SBUTTERFLY2 wd, 4, 5, 6 ; m4 = 4, 5, 10, 11, 16, 17, 22, 23 | ||
| 347 | ; m5 = 28, 29, 34, 35, 40, 41, 46, 47 | ||
| 348 | ; blend dwords | ||
| 349 | shufps m6, m0, m2, q2020 ; m6 = 0, 1, 12, 13, 2, 3, 14, 15 | ||
| 350 | shufps m0, m4, q2031 ; m0 = 6, 7, 18, 19, 4, 5, 16, 17 | ||
| 351 | shufps m2, m4, q3131 ; m2 = 8, 9, 20, 21, 10, 11, 22, 23 | ||
| 352 | SWAP 4,6 ; m4 = 0, 1, 12, 13, 2, 3, 14, 15 | ||
| 353 | shufps m6, m1, m3, q2020 ; m6 = 24, 25, 36, 37, 26, 27, 38, 39 | ||
| 354 | shufps m1, m5, q2031 ; m1 = 30, 31, 42, 43, 28, 29, 40, 41 | ||
| 355 | shufps m3, m5, q3131 ; m3 = 32, 33, 44, 45, 34, 35, 46, 47 | ||
| 356 | SWAP 5,6 ; m5 = 24, 25, 36, 37, 26, 27, 38, 39 | ||
| 357 | ; shuffle dwords | ||
| 358 | pshufd m0, m0, q1302 ; m0 = 4, 5, 6, 7, 16, 17, 18, 19 | ||
| 359 | pshufd m2, m2, q3120 ; m2 = 8, 9, 10, 11, 20, 21, 22, 23 | ||
| 360 | pshufd m4, m4, q3120 ; m4 = 0, 1, 2, 3, 12, 13, 14, 15 | ||
| 361 | pshufd m1, m1, q1302 ; m1 = 28, 29, 30, 31, 40, 41, 42, 43 | ||
| 362 | pshufd m3, m3, q3120 ; m3 = 32, 33, 34, 35, 44, 45, 46, 47 | ||
| 363 | pshufd m5, m5, q3120 ; m5 = 24, 25, 26, 27, 36, 37, 38, 39 | ||
| 364 | ; shuffle qwords | ||
| 365 | punpcklqdq m6, m4, m0 ; m6 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 366 | punpckhqdq m0, m2 ; m0 = 16, 17, 18, 19, 20, 21, 22, 23 | ||
| 367 | shufps m2, m4, q3210 ; m2 = 8, 9, 10, 11, 12, 13, 14, 15 | ||
| 368 | SWAP 4,6 ; m4 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 369 | punpcklqdq m6, m5, m1 ; m6 = 24, 25, 26, 27, 28, 29, 30, 31 | ||
| 370 | punpckhqdq m1, m3 ; m1 = 40, 41, 42, 43, 44, 45, 46, 47 | ||
| 371 | shufps m3, m5, q3210 ; m3 = 32, 33, 34, 35, 36, 37, 38, 39 | ||
| 372 | SWAP 5,6 ; m5 = 24, 25, 26, 27, 28, 29, 30, 31 | ||
| 373 | mova [dstq+0*mmsize], m4 | ||
| 374 | mova [dstq+1*mmsize], m2 | ||
| 375 | mova [dstq+2*mmsize], m0 | ||
| 376 | mova [dstq+3*mmsize], m5 | ||
| 377 | mova [dstq+4*mmsize], m3 | ||
| 378 | mova [dstq+5*mmsize], m1 | ||
| 379 | add src0q, mmsize | ||
| 380 | add dstq, mmsize*6 | ||
| 381 | sub lend, mmsize/2 | ||
| 382 | %endif | ||
| 383 | jg .loop | ||
| 384 | REP_RET | ||
| 385 | %endmacro | ||
| 386 | |||
| 387 | INIT_XMM sse2 | ||
| 388 | CONV_S16P_TO_S16_6CH | ||
| 389 | INIT_XMM sse2slow | ||
| 390 | CONV_S16P_TO_S16_6CH | ||
| 391 | %if HAVE_AVX_EXTERNAL | ||
| 392 | INIT_XMM avx | ||
| 393 | CONV_S16P_TO_S16_6CH | ||
| 394 | %endif | ||
| 395 | |||
| 396 | ;------------------------------------------------------------------------------ | ||
| 397 | ; void ff_conv_s16p_to_flt_2ch(float *dst, int16_t *const *src, int len, | ||
| 398 | ; int channels); | ||
| 399 | ;------------------------------------------------------------------------------ | ||
| 400 | |||
| 401 | %macro CONV_S16P_TO_FLT_2CH 0 | ||
| 402 | cglobal conv_s16p_to_flt_2ch, 3,4,6, dst, src0, len, src1 | ||
| 403 | lea lenq, [2*lend] | ||
| 404 | mov src1q, [src0q+gprsize] | ||
| 405 | mov src0q, [src0q ] | ||
| 406 | lea dstq, [dstq+4*lenq] | ||
| 407 | add src0q, lenq | ||
| 408 | add src1q, lenq | ||
| 409 | neg lenq | ||
| 410 | mova m5, [pf_s32_inv_scale] | ||
| 411 | .loop: | ||
| 412 | mova m2, [src0q+lenq] ; m2 = 0, 2, 4, 6, 8, 10, 12, 14 | ||
| 413 | mova m4, [src1q+lenq] ; m4 = 1, 3, 5, 7, 9, 11, 13, 15 | ||
| 414 | SBUTTERFLY2 wd, 2, 4, 3 ; m2 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 415 | ; m4 = 8, 9, 10, 11, 12, 13, 14, 15 | ||
| 416 | pxor m3, m3 | ||
| 417 | punpcklwd m0, m3, m2 ; m0 = 0, 1, 2, 3 | ||
| 418 | punpckhwd m1, m3, m2 ; m1 = 4, 5, 6, 7 | ||
| 419 | punpcklwd m2, m3, m4 ; m2 = 8, 9, 10, 11 | ||
| 420 | punpckhwd m3, m4 ; m3 = 12, 13, 14, 15 | ||
| 421 | cvtdq2ps m0, m0 | ||
| 422 | cvtdq2ps m1, m1 | ||
| 423 | cvtdq2ps m2, m2 | ||
| 424 | cvtdq2ps m3, m3 | ||
| 425 | mulps m0, m5 | ||
| 426 | mulps m1, m5 | ||
| 427 | mulps m2, m5 | ||
| 428 | mulps m3, m5 | ||
| 429 | mova [dstq+4*lenq ], m0 | ||
| 430 | mova [dstq+4*lenq+ mmsize], m1 | ||
| 431 | mova [dstq+4*lenq+2*mmsize], m2 | ||
| 432 | mova [dstq+4*lenq+3*mmsize], m3 | ||
| 433 | add lenq, mmsize | ||
| 434 | jl .loop | ||
| 435 | REP_RET | ||
| 436 | %endmacro | ||
| 437 | |||
| 438 | INIT_XMM sse2 | ||
| 439 | CONV_S16P_TO_FLT_2CH | ||
| 440 | %if HAVE_AVX_EXTERNAL | ||
| 441 | INIT_XMM avx | ||
| 442 | CONV_S16P_TO_FLT_2CH | ||
| 443 | %endif | ||
| 444 | |||
| 445 | ;------------------------------------------------------------------------------ | ||
| 446 | ; void ff_conv_s16p_to_flt_6ch(float *dst, int16_t *const *src, int len, | ||
| 447 | ; int channels); | ||
| 448 | ;------------------------------------------------------------------------------ | ||
| 449 | |||
| 450 | %macro CONV_S16P_TO_FLT_6CH 0 | ||
| 451 | %if ARCH_X86_64 | ||
| 452 | cglobal conv_s16p_to_flt_6ch, 3,8,8, dst, src, len, src1, src2, src3, src4, src5 | ||
| 453 | %else | ||
| 454 | cglobal conv_s16p_to_flt_6ch, 2,7,8, dst, src, src1, src2, src3, src4, src5 | ||
| 455 | %define lend dword r2m | ||
| 456 | %endif | ||
| 457 | mov src1q, [srcq+1*gprsize] | ||
| 458 | mov src2q, [srcq+2*gprsize] | ||
| 459 | mov src3q, [srcq+3*gprsize] | ||
| 460 | mov src4q, [srcq+4*gprsize] | ||
| 461 | mov src5q, [srcq+5*gprsize] | ||
| 462 | mov srcq, [srcq] | ||
| 463 | sub src1q, srcq | ||
| 464 | sub src2q, srcq | ||
| 465 | sub src3q, srcq | ||
| 466 | sub src4q, srcq | ||
| 467 | sub src5q, srcq | ||
| 468 | mova m7, [pf_s32_inv_scale] | ||
| 469 | %if cpuflag(ssse3) | ||
| 470 | %define unpack_even m6 | ||
| 471 | mova m6, [pb_shuf_unpack_even] | ||
| 472 | %if ARCH_X86_64 | ||
| 473 | %define unpack_odd m8 | ||
| 474 | mova m8, [pb_shuf_unpack_odd] | ||
| 475 | %else | ||
| 476 | %define unpack_odd [pb_shuf_unpack_odd] | ||
| 477 | %endif | ||
| 478 | %endif | ||
| 479 | .loop: | ||
| 480 | movq m0, [srcq ] ; m0 = 0, 6, 12, 18, x, x, x, x | ||
| 481 | movq m1, [srcq+src1q] ; m1 = 1, 7, 13, 19, x, x, x, x | ||
| 482 | movq m2, [srcq+src2q] ; m2 = 2, 8, 14, 20, x, x, x, x | ||
| 483 | movq m3, [srcq+src3q] ; m3 = 3, 9, 15, 21, x, x, x, x | ||
| 484 | movq m4, [srcq+src4q] ; m4 = 4, 10, 16, 22, x, x, x, x | ||
| 485 | movq m5, [srcq+src5q] ; m5 = 5, 11, 17, 23, x, x, x, x | ||
| 486 | ; unpack words: | ||
| 487 | punpcklwd m0, m1 ; m0 = 0, 1, 6, 7, 12, 13, 18, 19 | ||
| 488 | punpcklwd m2, m3 ; m2 = 2, 3, 8, 9, 14, 15, 20, 21 | ||
| 489 | punpcklwd m4, m5 ; m4 = 4, 5, 10, 11, 16, 17, 22, 23 | ||
| 490 | ; blend dwords | ||
| 491 | shufps m1, m4, m0, q3120 ; m1 = 4, 5, 16, 17, 6, 7, 18, 19 | ||
| 492 | shufps m0, m2, q2020 ; m0 = 0, 1, 12, 13, 2, 3, 14, 15 | ||
| 493 | shufps m2, m4, q3131 ; m2 = 8, 9, 20, 21, 10, 11, 22, 23 | ||
| 494 | %if cpuflag(ssse3) | ||
| 495 | pshufb m3, m0, unpack_odd ; m3 = 12, 13, 14, 15 | ||
| 496 | pshufb m0, unpack_even ; m0 = 0, 1, 2, 3 | ||
| 497 | pshufb m4, m1, unpack_odd ; m4 = 16, 17, 18, 19 | ||
| 498 | pshufb m1, unpack_even ; m1 = 4, 5, 6, 7 | ||
| 499 | pshufb m5, m2, unpack_odd ; m5 = 20, 21, 22, 23 | ||
| 500 | pshufb m2, unpack_even ; m2 = 8, 9, 10, 11 | ||
| 501 | %else | ||
| 502 | ; shuffle dwords | ||
| 503 | pshufd m0, m0, q3120 ; m0 = 0, 1, 2, 3, 12, 13, 14, 15 | ||
| 504 | pshufd m1, m1, q3120 ; m1 = 4, 5, 6, 7, 16, 17, 18, 19 | ||
| 505 | pshufd m2, m2, q3120 ; m2 = 8, 9, 10, 11, 20, 21, 22, 23 | ||
| 506 | pxor m6, m6 ; convert s16 in m0-m2 to s32 in m0-m5 | ||
| 507 | punpcklwd m3, m6, m0 ; m3 = 0, 1, 2, 3 | ||
| 508 | punpckhwd m4, m6, m0 ; m4 = 12, 13, 14, 15 | ||
| 509 | punpcklwd m0, m6, m1 ; m0 = 4, 5, 6, 7 | ||
| 510 | punpckhwd m5, m6, m1 ; m5 = 16, 17, 18, 19 | ||
| 511 | punpcklwd m1, m6, m2 ; m1 = 8, 9, 10, 11 | ||
| 512 | punpckhwd m6, m2 ; m6 = 20, 21, 22, 23 | ||
| 513 | SWAP 6,2,1,0,3,4,5 ; swap registers 3,0,1,4,5,6 to 0,1,2,3,4,5 | ||
| 514 | %endif | ||
| 515 | cvtdq2ps m0, m0 ; convert s32 to float | ||
| 516 | cvtdq2ps m1, m1 | ||
| 517 | cvtdq2ps m2, m2 | ||
| 518 | cvtdq2ps m3, m3 | ||
| 519 | cvtdq2ps m4, m4 | ||
| 520 | cvtdq2ps m5, m5 | ||
| 521 | mulps m0, m7 ; scale float from s32 range to [-1.0,1.0] | ||
| 522 | mulps m1, m7 | ||
| 523 | mulps m2, m7 | ||
| 524 | mulps m3, m7 | ||
| 525 | mulps m4, m7 | ||
| 526 | mulps m5, m7 | ||
| 527 | mova [dstq ], m0 | ||
| 528 | mova [dstq+ mmsize], m1 | ||
| 529 | mova [dstq+2*mmsize], m2 | ||
| 530 | mova [dstq+3*mmsize], m3 | ||
| 531 | mova [dstq+4*mmsize], m4 | ||
| 532 | mova [dstq+5*mmsize], m5 | ||
| 533 | add srcq, mmsize/2 | ||
| 534 | add dstq, mmsize*6 | ||
| 535 | sub lend, mmsize/4 | ||
| 536 | jg .loop | ||
| 537 | REP_RET | ||
| 538 | %endmacro | ||
| 539 | |||
| 540 | INIT_XMM sse2 | ||
| 541 | CONV_S16P_TO_FLT_6CH | ||
| 542 | INIT_XMM ssse3 | ||
| 543 | CONV_S16P_TO_FLT_6CH | ||
| 544 | %if HAVE_AVX_EXTERNAL | ||
| 545 | INIT_XMM avx | ||
| 546 | CONV_S16P_TO_FLT_6CH | ||
| 547 | %endif | ||
| 548 | |||
| 549 | ;------------------------------------------------------------------------------ | ||
| 550 | ; void ff_conv_fltp_to_s16_2ch(int16_t *dst, float *const *src, int len, | ||
| 551 | ; int channels); | ||
| 552 | ;------------------------------------------------------------------------------ | ||
| 553 | |||
| 554 | %macro CONV_FLTP_TO_S16_2CH 0 | ||
| 555 | cglobal conv_fltp_to_s16_2ch, 3,4,3, dst, src0, len, src1 | ||
| 556 | lea lenq, [4*lend] | ||
| 557 | mov src1q, [src0q+gprsize] | ||
| 558 | mov src0q, [src0q ] | ||
| 559 | add dstq, lenq | ||
| 560 | add src0q, lenq | ||
| 561 | add src1q, lenq | ||
| 562 | neg lenq | ||
| 563 | mova m2, [pf_s16_scale] | ||
| 564 | %if cpuflag(ssse3) | ||
| 565 | mova m3, [pb_interleave_words] | ||
| 566 | %endif | ||
| 567 | .loop: | ||
| 568 | mulps m0, m2, [src0q+lenq] ; m0 = 0, 2, 4, 6 | ||
| 569 | mulps m1, m2, [src1q+lenq] ; m1 = 1, 3, 5, 7 | ||
| 570 | cvtps2dq m0, m0 | ||
| 571 | cvtps2dq m1, m1 | ||
| 572 | %if cpuflag(ssse3) | ||
| 573 | packssdw m0, m1 ; m0 = 0, 2, 4, 6, 1, 3, 5, 7 | ||
| 574 | pshufb m0, m3 ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 575 | %else | ||
| 576 | packssdw m0, m0 ; m0 = 0, 2, 4, 6, x, x, x, x | ||
| 577 | packssdw m1, m1 ; m1 = 1, 3, 5, 7, x, x, x, x | ||
| 578 | punpcklwd m0, m1 ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 579 | %endif | ||
| 580 | mova [dstq+lenq], m0 | ||
| 581 | add lenq, mmsize | ||
| 582 | jl .loop | ||
| 583 | REP_RET | ||
| 584 | %endmacro | ||
| 585 | |||
| 586 | INIT_XMM sse2 | ||
| 587 | CONV_FLTP_TO_S16_2CH | ||
| 588 | INIT_XMM ssse3 | ||
| 589 | CONV_FLTP_TO_S16_2CH | ||
| 590 | |||
| 591 | ;------------------------------------------------------------------------------ | ||
| 592 | ; void ff_conv_fltp_to_s16_6ch(int16_t *dst, float *const *src, int len, | ||
| 593 | ; int channels); | ||
| 594 | ;------------------------------------------------------------------------------ | ||
| 595 | |||
| 596 | %macro CONV_FLTP_TO_S16_6CH 0 | ||
| 597 | %if ARCH_X86_64 | ||
| 598 | cglobal conv_fltp_to_s16_6ch, 3,8,7, dst, src, len, src1, src2, src3, src4, src5 | ||
| 599 | %else | ||
| 600 | cglobal conv_fltp_to_s16_6ch, 2,7,7, dst, src, src1, src2, src3, src4, src5 | ||
| 601 | %define lend dword r2m | ||
| 602 | %endif | ||
| 603 | mov src1q, [srcq+1*gprsize] | ||
| 604 | mov src2q, [srcq+2*gprsize] | ||
| 605 | mov src3q, [srcq+3*gprsize] | ||
| 606 | mov src4q, [srcq+4*gprsize] | ||
| 607 | mov src5q, [srcq+5*gprsize] | ||
| 608 | mov srcq, [srcq] | ||
| 609 | sub src1q, srcq | ||
| 610 | sub src2q, srcq | ||
| 611 | sub src3q, srcq | ||
| 612 | sub src4q, srcq | ||
| 613 | sub src5q, srcq | ||
| 614 | movaps xmm6, [pf_s16_scale] | ||
| 615 | .loop: | ||
| 616 | %if cpuflag(sse2) | ||
| 617 | mulps m0, m6, [srcq ] | ||
| 618 | mulps m1, m6, [srcq+src1q] | ||
| 619 | mulps m2, m6, [srcq+src2q] | ||
| 620 | mulps m3, m6, [srcq+src3q] | ||
| 621 | mulps m4, m6, [srcq+src4q] | ||
| 622 | mulps m5, m6, [srcq+src5q] | ||
| 623 | cvtps2dq m0, m0 | ||
| 624 | cvtps2dq m1, m1 | ||
| 625 | cvtps2dq m2, m2 | ||
| 626 | cvtps2dq m3, m3 | ||
| 627 | cvtps2dq m4, m4 | ||
| 628 | cvtps2dq m5, m5 | ||
| 629 | packssdw m0, m3 ; m0 = 0, 6, 12, 18, 3, 9, 15, 21 | ||
| 630 | packssdw m1, m4 ; m1 = 1, 7, 13, 19, 4, 10, 16, 22 | ||
| 631 | packssdw m2, m5 ; m2 = 2, 8, 14, 20, 5, 11, 17, 23 | ||
| 632 | ; unpack words: | ||
| 633 | movhlps m3, m0 ; m3 = 3, 9, 15, 21, x, x, x, x | ||
| 634 | punpcklwd m0, m1 ; m0 = 0, 1, 6, 7, 12, 13, 18, 19 | ||
| 635 | punpckhwd m1, m2 ; m1 = 4, 5, 10, 11, 16, 17, 22, 23 | ||
| 636 | punpcklwd m2, m3 ; m2 = 2, 3, 8, 9, 14, 15, 20, 21 | ||
| 637 | ; blend dwords: | ||
| 638 | shufps m3, m0, m2, q2020 ; m3 = 0, 1, 12, 13, 2, 3, 14, 15 | ||
| 639 | shufps m0, m1, q2031 ; m0 = 6, 7, 18, 19, 4, 5, 16, 17 | ||
| 640 | shufps m2, m1, q3131 ; m2 = 8, 9, 20, 21, 10, 11, 22, 23 | ||
| 641 | ; shuffle dwords: | ||
| 642 | shufps m1, m2, m3, q3120 ; m1 = 8, 9, 10, 11, 12, 13, 14, 15 | ||
| 643 | shufps m3, m0, q0220 ; m3 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 644 | shufps m0, m2, q3113 ; m0 = 16, 17, 18, 19, 20, 21, 22, 23 | ||
| 645 | mova [dstq+0*mmsize], m3 | ||
| 646 | mova [dstq+1*mmsize], m1 | ||
| 647 | mova [dstq+2*mmsize], m0 | ||
| 648 | %else ; sse | ||
| 649 | movlps xmm0, [srcq ] | ||
| 650 | movlps xmm1, [srcq+src1q] | ||
| 651 | movlps xmm2, [srcq+src2q] | ||
| 652 | movlps xmm3, [srcq+src3q] | ||
| 653 | movlps xmm4, [srcq+src4q] | ||
| 654 | movlps xmm5, [srcq+src5q] | ||
| 655 | mulps xmm0, xmm6 | ||
| 656 | mulps xmm1, xmm6 | ||
| 657 | mulps xmm2, xmm6 | ||
| 658 | mulps xmm3, xmm6 | ||
| 659 | mulps xmm4, xmm6 | ||
| 660 | mulps xmm5, xmm6 | ||
| 661 | cvtps2pi mm0, xmm0 | ||
| 662 | cvtps2pi mm1, xmm1 | ||
| 663 | cvtps2pi mm2, xmm2 | ||
| 664 | cvtps2pi mm3, xmm3 | ||
| 665 | cvtps2pi mm4, xmm4 | ||
| 666 | cvtps2pi mm5, xmm5 | ||
| 667 | packssdw mm0, mm3 ; m0 = 0, 6, 3, 9 | ||
| 668 | packssdw mm1, mm4 ; m1 = 1, 7, 4, 10 | ||
| 669 | packssdw mm2, mm5 ; m2 = 2, 8, 5, 11 | ||
| 670 | ; unpack words | ||
| 671 | pshufw mm3, mm0, q1032 ; m3 = 3, 9, 0, 6 | ||
| 672 | punpcklwd mm0, mm1 ; m0 = 0, 1, 6, 7 | ||
| 673 | punpckhwd mm1, mm2 ; m1 = 4, 5, 10, 11 | ||
| 674 | punpcklwd mm2, mm3 ; m2 = 2, 3, 8, 9 | ||
| 675 | ; unpack dwords | ||
| 676 | pshufw mm3, mm0, q1032 ; m3 = 6, 7, 0, 1 | ||
| 677 | punpckldq mm0, mm2 ; m0 = 0, 1, 2, 3 (final) | ||
| 678 | punpckhdq mm2, mm1 ; m2 = 8, 9, 10, 11 (final) | ||
| 679 | punpckldq mm1, mm3 ; m1 = 4, 5, 6, 7 (final) | ||
| 680 | mova [dstq+0*mmsize], mm0 | ||
| 681 | mova [dstq+1*mmsize], mm1 | ||
| 682 | mova [dstq+2*mmsize], mm2 | ||
| 683 | %endif | ||
| 684 | add srcq, mmsize | ||
| 685 | add dstq, mmsize*3 | ||
| 686 | sub lend, mmsize/4 | ||
| 687 | jg .loop | ||
| 688 | %if mmsize == 8 | ||
| 689 | emms | ||
| 690 | RET | ||
| 691 | %else | ||
| 692 | REP_RET | ||
| 693 | %endif | ||
| 694 | %endmacro | ||
| 695 | |||
| 696 | INIT_MMX sse | ||
| 697 | CONV_FLTP_TO_S16_6CH | ||
| 698 | INIT_XMM sse2 | ||
| 699 | CONV_FLTP_TO_S16_6CH | ||
| 700 | %if HAVE_AVX_EXTERNAL | ||
| 701 | INIT_XMM avx | ||
| 702 | CONV_FLTP_TO_S16_6CH | ||
| 703 | %endif | ||
| 704 | |||
| 705 | ;------------------------------------------------------------------------------ | ||
| 706 | ; void ff_conv_fltp_to_flt_2ch(float *dst, float *const *src, int len, | ||
| 707 | ; int channels); | ||
| 708 | ;------------------------------------------------------------------------------ | ||
| 709 | |||
| 710 | %macro CONV_FLTP_TO_FLT_2CH 0 | ||
| 711 | cglobal conv_fltp_to_flt_2ch, 3,4,5, dst, src0, len, src1 | ||
| 712 | mov src1q, [src0q+gprsize] | ||
| 713 | mov src0q, [src0q] | ||
| 714 | lea lenq, [4*lend] | ||
| 715 | add src0q, lenq | ||
| 716 | add src1q, lenq | ||
| 717 | lea dstq, [dstq+2*lenq] | ||
| 718 | neg lenq | ||
| 719 | .loop: | ||
| 720 | mova m0, [src0q+lenq ] | ||
| 721 | mova m1, [src1q+lenq ] | ||
| 722 | mova m2, [src0q+lenq+mmsize] | ||
| 723 | mova m3, [src1q+lenq+mmsize] | ||
| 724 | SBUTTERFLYPS 0, 1, 4 | ||
| 725 | SBUTTERFLYPS 2, 3, 4 | ||
| 726 | mova [dstq+2*lenq+0*mmsize], m0 | ||
| 727 | mova [dstq+2*lenq+1*mmsize], m1 | ||
| 728 | mova [dstq+2*lenq+2*mmsize], m2 | ||
| 729 | mova [dstq+2*lenq+3*mmsize], m3 | ||
| 730 | add lenq, 2*mmsize | ||
| 731 | jl .loop | ||
| 732 | REP_RET | ||
| 733 | %endmacro | ||
| 734 | |||
| 735 | INIT_XMM sse | ||
| 736 | CONV_FLTP_TO_FLT_2CH | ||
| 737 | %if HAVE_AVX_EXTERNAL | ||
| 738 | INIT_XMM avx | ||
| 739 | CONV_FLTP_TO_FLT_2CH | ||
| 740 | %endif | ||
| 741 | |||
| 742 | ;----------------------------------------------------------------------------- | ||
| 743 | ; void ff_conv_fltp_to_flt_6ch(float *dst, float *const *src, int len, | ||
| 744 | ; int channels); | ||
| 745 | ;----------------------------------------------------------------------------- | ||
| 746 | |||
| 747 | %macro CONV_FLTP_TO_FLT_6CH 0 | ||
| 748 | cglobal conv_fltp_to_flt_6ch, 2,8,7, dst, src, src1, src2, src3, src4, src5, len | ||
| 749 | %if ARCH_X86_64 | ||
| 750 | mov lend, r2d | ||
| 751 | %else | ||
| 752 | %define lend dword r2m | ||
| 753 | %endif | ||
| 754 | mov src1q, [srcq+1*gprsize] | ||
| 755 | mov src2q, [srcq+2*gprsize] | ||
| 756 | mov src3q, [srcq+3*gprsize] | ||
| 757 | mov src4q, [srcq+4*gprsize] | ||
| 758 | mov src5q, [srcq+5*gprsize] | ||
| 759 | mov srcq, [srcq] | ||
| 760 | sub src1q, srcq | ||
| 761 | sub src2q, srcq | ||
| 762 | sub src3q, srcq | ||
| 763 | sub src4q, srcq | ||
| 764 | sub src5q, srcq | ||
| 765 | .loop: | ||
| 766 | mova m0, [srcq ] | ||
| 767 | mova m1, [srcq+src1q] | ||
| 768 | mova m2, [srcq+src2q] | ||
| 769 | mova m3, [srcq+src3q] | ||
| 770 | mova m4, [srcq+src4q] | ||
| 771 | mova m5, [srcq+src5q] | ||
| 772 | %if cpuflag(sse4) | ||
| 773 | SBUTTERFLYPS 0, 1, 6 | ||
| 774 | SBUTTERFLYPS 2, 3, 6 | ||
| 775 | SBUTTERFLYPS 4, 5, 6 | ||
| 776 | |||
| 777 | blendps m6, m4, m0, 1100b | ||
| 778 | movlhps m0, m2 | ||
| 779 | movhlps m4, m2 | ||
| 780 | blendps m2, m5, m1, 1100b | ||
| 781 | movlhps m1, m3 | ||
| 782 | movhlps m5, m3 | ||
| 783 | |||
| 784 | movaps [dstq ], m0 | ||
| 785 | movaps [dstq+16], m6 | ||
| 786 | movaps [dstq+32], m4 | ||
| 787 | movaps [dstq+48], m1 | ||
| 788 | movaps [dstq+64], m2 | ||
| 789 | movaps [dstq+80], m5 | ||
| 790 | %else ; mmx | ||
| 791 | SBUTTERFLY dq, 0, 1, 6 | ||
| 792 | SBUTTERFLY dq, 2, 3, 6 | ||
| 793 | SBUTTERFLY dq, 4, 5, 6 | ||
| 794 | |||
| 795 | movq [dstq ], m0 | ||
| 796 | movq [dstq+ 8], m2 | ||
| 797 | movq [dstq+16], m4 | ||
| 798 | movq [dstq+24], m1 | ||
| 799 | movq [dstq+32], m3 | ||
| 800 | movq [dstq+40], m5 | ||
| 801 | %endif | ||
| 802 | add srcq, mmsize | ||
| 803 | add dstq, mmsize*6 | ||
| 804 | sub lend, mmsize/4 | ||
| 805 | jg .loop | ||
| 806 | %if mmsize == 8 | ||
| 807 | emms | ||
| 808 | RET | ||
| 809 | %else | ||
| 810 | REP_RET | ||
| 811 | %endif | ||
| 812 | %endmacro | ||
| 813 | |||
| 814 | INIT_MMX mmx | ||
| 815 | CONV_FLTP_TO_FLT_6CH | ||
| 816 | INIT_XMM sse4 | ||
| 817 | CONV_FLTP_TO_FLT_6CH | ||
| 818 | %if HAVE_AVX_EXTERNAL | ||
| 819 | INIT_XMM avx | ||
| 820 | CONV_FLTP_TO_FLT_6CH | ||
| 821 | %endif | ||
| 822 | |||
| 823 | ;------------------------------------------------------------------------------ | ||
| 824 | ; void ff_conv_s16_to_s16p_2ch(int16_t *const *dst, int16_t *src, int len, | ||
| 825 | ; int channels); | ||
| 826 | ;------------------------------------------------------------------------------ | ||
| 827 | |||
| 828 | %macro CONV_S16_TO_S16P_2CH 0 | ||
| 829 | cglobal conv_s16_to_s16p_2ch, 3,4,4, dst0, src, len, dst1 | ||
| 830 | lea lenq, [2*lend] | ||
| 831 | mov dst1q, [dst0q+gprsize] | ||
| 832 | mov dst0q, [dst0q ] | ||
| 833 | lea srcq, [srcq+2*lenq] | ||
| 834 | add dst0q, lenq | ||
| 835 | add dst1q, lenq | ||
| 836 | neg lenq | ||
| 837 | %if cpuflag(ssse3) | ||
| 838 | mova m3, [pb_deinterleave_words] | ||
| 839 | %endif | ||
| 840 | .loop: | ||
| 841 | mova m0, [srcq+2*lenq ] ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 842 | mova m1, [srcq+2*lenq+mmsize] ; m1 = 8, 9, 10, 11, 12, 13, 14, 15 | ||
| 843 | %if cpuflag(ssse3) | ||
| 844 | pshufb m0, m3 ; m0 = 0, 2, 4, 6, 1, 3, 5, 7 | ||
| 845 | pshufb m1, m3 ; m1 = 8, 10, 12, 14, 9, 11, 13, 15 | ||
| 846 | SBUTTERFLY2 qdq, 0, 1, 2 ; m0 = 0, 2, 4, 6, 8, 10, 12, 14 | ||
| 847 | ; m1 = 1, 3, 5, 7, 9, 11, 13, 15 | ||
| 848 | %else ; sse2 | ||
| 849 | pshuflw m0, m0, q3120 ; m0 = 0, 2, 1, 3, 4, 5, 6, 7 | ||
| 850 | pshufhw m0, m0, q3120 ; m0 = 0, 2, 1, 3, 4, 6, 5, 7 | ||
| 851 | pshuflw m1, m1, q3120 ; m1 = 8, 10, 9, 11, 12, 13, 14, 15 | ||
| 852 | pshufhw m1, m1, q3120 ; m1 = 8, 10, 9, 11, 12, 14, 13, 15 | ||
| 853 | DEINT2_PS 0, 1, 2 ; m0 = 0, 2, 4, 6, 8, 10, 12, 14 | ||
| 854 | ; m1 = 1, 3, 5, 7, 9, 11, 13, 15 | ||
| 855 | %endif | ||
| 856 | mova [dst0q+lenq], m0 | ||
| 857 | mova [dst1q+lenq], m1 | ||
| 858 | add lenq, mmsize | ||
| 859 | jl .loop | ||
| 860 | REP_RET | ||
| 861 | %endmacro | ||
| 862 | |||
| 863 | INIT_XMM sse2 | ||
| 864 | CONV_S16_TO_S16P_2CH | ||
| 865 | INIT_XMM ssse3 | ||
| 866 | CONV_S16_TO_S16P_2CH | ||
| 867 | %if HAVE_AVX_EXTERNAL | ||
| 868 | INIT_XMM avx | ||
| 869 | CONV_S16_TO_S16P_2CH | ||
| 870 | %endif | ||
| 871 | |||
| 872 | ;------------------------------------------------------------------------------ | ||
| 873 | ; void ff_conv_s16_to_s16p_6ch(int16_t *const *dst, int16_t *src, int len, | ||
| 874 | ; int channels); | ||
| 875 | ;------------------------------------------------------------------------------ | ||
| 876 | |||
| 877 | %macro CONV_S16_TO_S16P_6CH 0 | ||
| 878 | %if ARCH_X86_64 | ||
| 879 | cglobal conv_s16_to_s16p_6ch, 3,8,5, dst, src, len, dst1, dst2, dst3, dst4, dst5 | ||
| 880 | %else | ||
| 881 | cglobal conv_s16_to_s16p_6ch, 2,7,5, dst, src, dst1, dst2, dst3, dst4, dst5 | ||
| 882 | %define lend dword r2m | ||
| 883 | %endif | ||
| 884 | mov dst1q, [dstq+ gprsize] | ||
| 885 | mov dst2q, [dstq+2*gprsize] | ||
| 886 | mov dst3q, [dstq+3*gprsize] | ||
| 887 | mov dst4q, [dstq+4*gprsize] | ||
| 888 | mov dst5q, [dstq+5*gprsize] | ||
| 889 | mov dstq, [dstq ] | ||
| 890 | sub dst1q, dstq | ||
| 891 | sub dst2q, dstq | ||
| 892 | sub dst3q, dstq | ||
| 893 | sub dst4q, dstq | ||
| 894 | sub dst5q, dstq | ||
| 895 | .loop: | ||
| 896 | mova m0, [srcq+0*mmsize] ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 897 | mova m3, [srcq+1*mmsize] ; m3 = 8, 9, 10, 11, 12, 13, 14, 15 | ||
| 898 | mova m2, [srcq+2*mmsize] ; m2 = 16, 17, 18, 19, 20, 21, 22, 23 | ||
| 899 | PALIGNR m1, m3, m0, 12, m4 ; m1 = 6, 7, 8, 9, 10, 11, x, x | ||
| 900 | shufps m3, m2, q1032 ; m3 = 12, 13, 14, 15, 16, 17, 18, 19 | ||
| 901 | psrldq m2, 4 ; m2 = 18, 19, 20, 21, 22, 23, x, x | ||
| 902 | SBUTTERFLY2 wd, 0, 1, 4 ; m0 = 0, 6, 1, 7, 2, 8, 3, 9 | ||
| 903 | ; m1 = 4, 10, 5, 11, x, x, x, x | ||
| 904 | SBUTTERFLY2 wd, 3, 2, 4 ; m3 = 12, 18, 13, 19, 14, 20, 15, 21 | ||
| 905 | ; m2 = 16, 22, 17, 23, x, x, x, x | ||
| 906 | SBUTTERFLY2 dq, 0, 3, 4 ; m0 = 0, 6, 12, 18, 1, 7, 13, 19 | ||
| 907 | ; m3 = 2, 8, 14, 20, 3, 9, 15, 21 | ||
| 908 | punpckldq m1, m2 ; m1 = 4, 10, 16, 22, 5, 11, 17, 23 | ||
| 909 | movq [dstq ], m0 | ||
| 910 | movhps [dstq+dst1q], m0 | ||
| 911 | movq [dstq+dst2q], m3 | ||
| 912 | movhps [dstq+dst3q], m3 | ||
| 913 | movq [dstq+dst4q], m1 | ||
| 914 | movhps [dstq+dst5q], m1 | ||
| 915 | add srcq, mmsize*3 | ||
| 916 | add dstq, mmsize/2 | ||
| 917 | sub lend, mmsize/4 | ||
| 918 | jg .loop | ||
| 919 | REP_RET | ||
| 920 | %endmacro | ||
| 921 | |||
| 922 | INIT_XMM sse2 | ||
| 923 | CONV_S16_TO_S16P_6CH | ||
| 924 | INIT_XMM ssse3 | ||
| 925 | CONV_S16_TO_S16P_6CH | ||
| 926 | %if HAVE_AVX_EXTERNAL | ||
| 927 | INIT_XMM avx | ||
| 928 | CONV_S16_TO_S16P_6CH | ||
| 929 | %endif | ||
| 930 | |||
| 931 | ;------------------------------------------------------------------------------ | ||
| 932 | ; void ff_conv_s16_to_fltp_2ch(float *const *dst, int16_t *src, int len, | ||
| 933 | ; int channels); | ||
| 934 | ;------------------------------------------------------------------------------ | ||
| 935 | |||
| 936 | %macro CONV_S16_TO_FLTP_2CH 0 | ||
| 937 | cglobal conv_s16_to_fltp_2ch, 3,4,5, dst0, src, len, dst1 | ||
| 938 | lea lenq, [4*lend] | ||
| 939 | mov dst1q, [dst0q+gprsize] | ||
| 940 | mov dst0q, [dst0q ] | ||
| 941 | add srcq, lenq | ||
| 942 | add dst0q, lenq | ||
| 943 | add dst1q, lenq | ||
| 944 | neg lenq | ||
| 945 | mova m3, [pf_s32_inv_scale] | ||
| 946 | mova m4, [pw_zero_even] | ||
| 947 | .loop: | ||
| 948 | mova m1, [srcq+lenq] | ||
| 949 | pslld m0, m1, 16 | ||
| 950 | pand m1, m4 | ||
| 951 | cvtdq2ps m0, m0 | ||
| 952 | cvtdq2ps m1, m1 | ||
| 953 | mulps m0, m0, m3 | ||
| 954 | mulps m1, m1, m3 | ||
| 955 | mova [dst0q+lenq], m0 | ||
| 956 | mova [dst1q+lenq], m1 | ||
| 957 | add lenq, mmsize | ||
| 958 | jl .loop | ||
| 959 | REP_RET | ||
| 960 | %endmacro | ||
| 961 | |||
| 962 | INIT_XMM sse2 | ||
| 963 | CONV_S16_TO_FLTP_2CH | ||
| 964 | %if HAVE_AVX_EXTERNAL | ||
| 965 | INIT_XMM avx | ||
| 966 | CONV_S16_TO_FLTP_2CH | ||
| 967 | %endif | ||
| 968 | |||
| 969 | ;------------------------------------------------------------------------------ | ||
| 970 | ; void ff_conv_s16_to_fltp_6ch(float *const *dst, int16_t *src, int len, | ||
| 971 | ; int channels); | ||
| 972 | ;------------------------------------------------------------------------------ | ||
| 973 | |||
| 974 | %macro CONV_S16_TO_FLTP_6CH 0 | ||
| 975 | %if ARCH_X86_64 | ||
| 976 | cglobal conv_s16_to_fltp_6ch, 3,8,7, dst, src, len, dst1, dst2, dst3, dst4, dst5 | ||
| 977 | %else | ||
| 978 | cglobal conv_s16_to_fltp_6ch, 2,7,7, dst, src, dst1, dst2, dst3, dst4, dst5 | ||
| 979 | %define lend dword r2m | ||
| 980 | %endif | ||
| 981 | mov dst1q, [dstq+ gprsize] | ||
| 982 | mov dst2q, [dstq+2*gprsize] | ||
| 983 | mov dst3q, [dstq+3*gprsize] | ||
| 984 | mov dst4q, [dstq+4*gprsize] | ||
| 985 | mov dst5q, [dstq+5*gprsize] | ||
| 986 | mov dstq, [dstq ] | ||
| 987 | sub dst1q, dstq | ||
| 988 | sub dst2q, dstq | ||
| 989 | sub dst3q, dstq | ||
| 990 | sub dst4q, dstq | ||
| 991 | sub dst5q, dstq | ||
| 992 | mova m6, [pf_s16_inv_scale] | ||
| 993 | .loop: | ||
| 994 | mova m0, [srcq+0*mmsize] ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 995 | mova m3, [srcq+1*mmsize] ; m3 = 8, 9, 10, 11, 12, 13, 14, 15 | ||
| 996 | mova m2, [srcq+2*mmsize] ; m2 = 16, 17, 18, 19, 20, 21, 22, 23 | ||
| 997 | PALIGNR m1, m3, m0, 12, m4 ; m1 = 6, 7, 8, 9, 10, 11, x, x | ||
| 998 | shufps m3, m2, q1032 ; m3 = 12, 13, 14, 15, 16, 17, 18, 19 | ||
| 999 | psrldq m2, 4 ; m2 = 18, 19, 20, 21, 22, 23, x, x | ||
| 1000 | SBUTTERFLY2 wd, 0, 1, 4 ; m0 = 0, 6, 1, 7, 2, 8, 3, 9 | ||
| 1001 | ; m1 = 4, 10, 5, 11, x, x, x, x | ||
| 1002 | SBUTTERFLY2 wd, 3, 2, 4 ; m3 = 12, 18, 13, 19, 14, 20, 15, 21 | ||
| 1003 | ; m2 = 16, 22, 17, 23, x, x, x, x | ||
| 1004 | SBUTTERFLY2 dq, 0, 3, 4 ; m0 = 0, 6, 12, 18, 1, 7, 13, 19 | ||
| 1005 | ; m3 = 2, 8, 14, 20, 3, 9, 15, 21 | ||
| 1006 | punpckldq m1, m2 ; m1 = 4, 10, 16, 22, 5, 11, 17, 23 | ||
| 1007 | S16_TO_S32_SX 0, 2 ; m0 = 0, 6, 12, 18 | ||
| 1008 | ; m2 = 1, 7, 13, 19 | ||
| 1009 | S16_TO_S32_SX 3, 4 ; m3 = 2, 8, 14, 20 | ||
| 1010 | ; m4 = 3, 9, 15, 21 | ||
| 1011 | S16_TO_S32_SX 1, 5 ; m1 = 4, 10, 16, 22 | ||
| 1012 | ; m5 = 5, 11, 17, 23 | ||
| 1013 | SWAP 1,2,3,4 | ||
| 1014 | cvtdq2ps m0, m0 | ||
| 1015 | cvtdq2ps m1, m1 | ||
| 1016 | cvtdq2ps m2, m2 | ||
| 1017 | cvtdq2ps m3, m3 | ||
| 1018 | cvtdq2ps m4, m4 | ||
| 1019 | cvtdq2ps m5, m5 | ||
| 1020 | mulps m0, m6 | ||
| 1021 | mulps m1, m6 | ||
| 1022 | mulps m2, m6 | ||
| 1023 | mulps m3, m6 | ||
| 1024 | mulps m4, m6 | ||
| 1025 | mulps m5, m6 | ||
| 1026 | mova [dstq ], m0 | ||
| 1027 | mova [dstq+dst1q], m1 | ||
| 1028 | mova [dstq+dst2q], m2 | ||
| 1029 | mova [dstq+dst3q], m3 | ||
| 1030 | mova [dstq+dst4q], m4 | ||
| 1031 | mova [dstq+dst5q], m5 | ||
| 1032 | add srcq, mmsize*3 | ||
| 1033 | add dstq, mmsize | ||
| 1034 | sub lend, mmsize/4 | ||
| 1035 | jg .loop | ||
| 1036 | REP_RET | ||
| 1037 | %endmacro | ||
| 1038 | |||
| 1039 | INIT_XMM sse2 | ||
| 1040 | CONV_S16_TO_FLTP_6CH | ||
| 1041 | INIT_XMM ssse3 | ||
| 1042 | CONV_S16_TO_FLTP_6CH | ||
| 1043 | INIT_XMM sse4 | ||
| 1044 | CONV_S16_TO_FLTP_6CH | ||
| 1045 | %if HAVE_AVX_EXTERNAL | ||
| 1046 | INIT_XMM avx | ||
| 1047 | CONV_S16_TO_FLTP_6CH | ||
| 1048 | %endif | ||
| 1049 | |||
| 1050 | ;------------------------------------------------------------------------------ | ||
| 1051 | ; void ff_conv_flt_to_s16p_2ch(int16_t *const *dst, float *src, int len, | ||
| 1052 | ; int channels); | ||
| 1053 | ;------------------------------------------------------------------------------ | ||
| 1054 | |||
| 1055 | %macro CONV_FLT_TO_S16P_2CH 0 | ||
| 1056 | cglobal conv_flt_to_s16p_2ch, 3,4,6, dst0, src, len, dst1 | ||
| 1057 | lea lenq, [2*lend] | ||
| 1058 | mov dst1q, [dst0q+gprsize] | ||
| 1059 | mov dst0q, [dst0q ] | ||
| 1060 | lea srcq, [srcq+4*lenq] | ||
| 1061 | add dst0q, lenq | ||
| 1062 | add dst1q, lenq | ||
| 1063 | neg lenq | ||
| 1064 | mova m5, [pf_s16_scale] | ||
| 1065 | .loop: | ||
| 1066 | mova m0, [srcq+4*lenq ] | ||
| 1067 | mova m1, [srcq+4*lenq+ mmsize] | ||
| 1068 | mova m2, [srcq+4*lenq+2*mmsize] | ||
| 1069 | mova m3, [srcq+4*lenq+3*mmsize] | ||
| 1070 | DEINT2_PS 0, 1, 4 | ||
| 1071 | DEINT2_PS 2, 3, 4 | ||
| 1072 | mulps m0, m0, m5 | ||
| 1073 | mulps m1, m1, m5 | ||
| 1074 | mulps m2, m2, m5 | ||
| 1075 | mulps m3, m3, m5 | ||
| 1076 | cvtps2dq m0, m0 | ||
| 1077 | cvtps2dq m1, m1 | ||
| 1078 | cvtps2dq m2, m2 | ||
| 1079 | cvtps2dq m3, m3 | ||
| 1080 | packssdw m0, m2 | ||
| 1081 | packssdw m1, m3 | ||
| 1082 | mova [dst0q+lenq], m0 | ||
| 1083 | mova [dst1q+lenq], m1 | ||
| 1084 | add lenq, mmsize | ||
| 1085 | jl .loop | ||
| 1086 | REP_RET | ||
| 1087 | %endmacro | ||
| 1088 | |||
| 1089 | INIT_XMM sse2 | ||
| 1090 | CONV_FLT_TO_S16P_2CH | ||
| 1091 | %if HAVE_AVX_EXTERNAL | ||
| 1092 | INIT_XMM avx | ||
| 1093 | CONV_FLT_TO_S16P_2CH | ||
| 1094 | %endif | ||
| 1095 | |||
| 1096 | ;------------------------------------------------------------------------------ | ||
| 1097 | ; void ff_conv_flt_to_s16p_6ch(int16_t *const *dst, float *src, int len, | ||
| 1098 | ; int channels); | ||
| 1099 | ;------------------------------------------------------------------------------ | ||
| 1100 | |||
| 1101 | %macro CONV_FLT_TO_S16P_6CH 0 | ||
| 1102 | %if ARCH_X86_64 | ||
| 1103 | cglobal conv_flt_to_s16p_6ch, 3,8,7, dst, src, len, dst1, dst2, dst3, dst4, dst5 | ||
| 1104 | %else | ||
| 1105 | cglobal conv_flt_to_s16p_6ch, 2,7,7, dst, src, dst1, dst2, dst3, dst4, dst5 | ||
| 1106 | %define lend dword r2m | ||
| 1107 | %endif | ||
| 1108 | mov dst1q, [dstq+ gprsize] | ||
| 1109 | mov dst2q, [dstq+2*gprsize] | ||
| 1110 | mov dst3q, [dstq+3*gprsize] | ||
| 1111 | mov dst4q, [dstq+4*gprsize] | ||
| 1112 | mov dst5q, [dstq+5*gprsize] | ||
| 1113 | mov dstq, [dstq ] | ||
| 1114 | sub dst1q, dstq | ||
| 1115 | sub dst2q, dstq | ||
| 1116 | sub dst3q, dstq | ||
| 1117 | sub dst4q, dstq | ||
| 1118 | sub dst5q, dstq | ||
| 1119 | mova m6, [pf_s16_scale] | ||
| 1120 | .loop: | ||
| 1121 | mulps m0, m6, [srcq+0*mmsize] | ||
| 1122 | mulps m3, m6, [srcq+1*mmsize] | ||
| 1123 | mulps m1, m6, [srcq+2*mmsize] | ||
| 1124 | mulps m4, m6, [srcq+3*mmsize] | ||
| 1125 | mulps m2, m6, [srcq+4*mmsize] | ||
| 1126 | mulps m5, m6, [srcq+5*mmsize] | ||
| 1127 | cvtps2dq m0, m0 | ||
| 1128 | cvtps2dq m1, m1 | ||
| 1129 | cvtps2dq m2, m2 | ||
| 1130 | cvtps2dq m3, m3 | ||
| 1131 | cvtps2dq m4, m4 | ||
| 1132 | cvtps2dq m5, m5 | ||
| 1133 | packssdw m0, m3 ; m0 = 0, 1, 2, 3, 4, 5, 6, 7 | ||
| 1134 | packssdw m1, m4 ; m1 = 8, 9, 10, 11, 12, 13, 14, 15 | ||
| 1135 | packssdw m2, m5 ; m2 = 16, 17, 18, 19, 20, 21, 22, 23 | ||
| 1136 | PALIGNR m3, m1, m0, 12, m4 ; m3 = 6, 7, 8, 9, 10, 11, x, x | ||
| 1137 | shufps m1, m2, q1032 ; m1 = 12, 13, 14, 15, 16, 17, 18, 19 | ||
| 1138 | psrldq m2, 4 ; m2 = 18, 19, 20, 21, 22, 23, x, x | ||
| 1139 | SBUTTERFLY2 wd, 0, 3, 4 ; m0 = 0, 6, 1, 7, 2, 8, 3, 9 | ||
| 1140 | ; m3 = 4, 10, 5, 11, x, x, x, x | ||
| 1141 | SBUTTERFLY2 wd, 1, 2, 4 ; m1 = 12, 18, 13, 19, 14, 20, 15, 21 | ||
| 1142 | ; m2 = 16, 22, 17, 23, x, x, x, x | ||
| 1143 | SBUTTERFLY2 dq, 0, 1, 4 ; m0 = 0, 6, 12, 18, 1, 7, 13, 19 | ||
| 1144 | ; m1 = 2, 8, 14, 20, 3, 9, 15, 21 | ||
| 1145 | punpckldq m3, m2 ; m3 = 4, 10, 16, 22, 5, 11, 17, 23 | ||
| 1146 | movq [dstq ], m0 | ||
| 1147 | movhps [dstq+dst1q], m0 | ||
| 1148 | movq [dstq+dst2q], m1 | ||
| 1149 | movhps [dstq+dst3q], m1 | ||
| 1150 | movq [dstq+dst4q], m3 | ||
| 1151 | movhps [dstq+dst5q], m3 | ||
| 1152 | add srcq, mmsize*6 | ||
| 1153 | add dstq, mmsize/2 | ||
| 1154 | sub lend, mmsize/4 | ||
| 1155 | jg .loop | ||
| 1156 | REP_RET | ||
| 1157 | %endmacro | ||
| 1158 | |||
| 1159 | INIT_XMM sse2 | ||
| 1160 | CONV_FLT_TO_S16P_6CH | ||
| 1161 | INIT_XMM ssse3 | ||
| 1162 | CONV_FLT_TO_S16P_6CH | ||
| 1163 | %if HAVE_AVX_EXTERNAL | ||
| 1164 | INIT_XMM avx | ||
| 1165 | CONV_FLT_TO_S16P_6CH | ||
| 1166 | %endif | ||
| 1167 | |||
| 1168 | ;------------------------------------------------------------------------------ | ||
| 1169 | ; void ff_conv_flt_to_fltp_2ch(float *const *dst, float *src, int len, | ||
| 1170 | ; int channels); | ||
| 1171 | ;------------------------------------------------------------------------------ | ||
| 1172 | |||
| 1173 | %macro CONV_FLT_TO_FLTP_2CH 0 | ||
| 1174 | cglobal conv_flt_to_fltp_2ch, 3,4,3, dst0, src, len, dst1 | ||
| 1175 | lea lenq, [4*lend] | ||
| 1176 | mov dst1q, [dst0q+gprsize] | ||
| 1177 | mov dst0q, [dst0q ] | ||
| 1178 | lea srcq, [srcq+2*lenq] | ||
| 1179 | add dst0q, lenq | ||
| 1180 | add dst1q, lenq | ||
| 1181 | neg lenq | ||
| 1182 | .loop: | ||
| 1183 | mova m0, [srcq+2*lenq ] | ||
| 1184 | mova m1, [srcq+2*lenq+mmsize] | ||
| 1185 | DEINT2_PS 0, 1, 2 | ||
| 1186 | mova [dst0q+lenq], m0 | ||
| 1187 | mova [dst1q+lenq], m1 | ||
| 1188 | add lenq, mmsize | ||
| 1189 | jl .loop | ||
| 1190 | REP_RET | ||
| 1191 | %endmacro | ||
| 1192 | |||
| 1193 | INIT_XMM sse | ||
| 1194 | CONV_FLT_TO_FLTP_2CH | ||
| 1195 | %if HAVE_AVX_EXTERNAL | ||
| 1196 | INIT_XMM avx | ||
| 1197 | CONV_FLT_TO_FLTP_2CH | ||
| 1198 | %endif | ||
| 1199 | |||
| 1200 | ;------------------------------------------------------------------------------ | ||
| 1201 | ; void ff_conv_flt_to_fltp_6ch(float *const *dst, float *src, int len, | ||
| 1202 | ; int channels); | ||
| 1203 | ;------------------------------------------------------------------------------ | ||
| 1204 | |||
| 1205 | %macro CONV_FLT_TO_FLTP_6CH 0 | ||
| 1206 | %if ARCH_X86_64 | ||
| 1207 | cglobal conv_flt_to_fltp_6ch, 3,8,7, dst, src, len, dst1, dst2, dst3, dst4, dst5 | ||
| 1208 | %else | ||
| 1209 | cglobal conv_flt_to_fltp_6ch, 2,7,7, dst, src, dst1, dst2, dst3, dst4, dst5 | ||
| 1210 | %define lend dword r2m | ||
| 1211 | %endif | ||
| 1212 | mov dst1q, [dstq+ gprsize] | ||
| 1213 | mov dst2q, [dstq+2*gprsize] | ||
| 1214 | mov dst3q, [dstq+3*gprsize] | ||
| 1215 | mov dst4q, [dstq+4*gprsize] | ||
| 1216 | mov dst5q, [dstq+5*gprsize] | ||
| 1217 | mov dstq, [dstq ] | ||
| 1218 | sub dst1q, dstq | ||
| 1219 | sub dst2q, dstq | ||
| 1220 | sub dst3q, dstq | ||
| 1221 | sub dst4q, dstq | ||
| 1222 | sub dst5q, dstq | ||
| 1223 | .loop: | ||
| 1224 | mova m0, [srcq+0*mmsize] ; m0 = 0, 1, 2, 3 | ||
| 1225 | mova m1, [srcq+1*mmsize] ; m1 = 4, 5, 6, 7 | ||
| 1226 | mova m2, [srcq+2*mmsize] ; m2 = 8, 9, 10, 11 | ||
| 1227 | mova m3, [srcq+3*mmsize] ; m3 = 12, 13, 14, 15 | ||
| 1228 | mova m4, [srcq+4*mmsize] ; m4 = 16, 17, 18, 19 | ||
| 1229 | mova m5, [srcq+5*mmsize] ; m5 = 20, 21, 22, 23 | ||
| 1230 | |||
| 1231 | SBUTTERFLY2 dq, 0, 3, 6 ; m0 = 0, 12, 1, 13 | ||
| 1232 | ; m3 = 2, 14, 3, 15 | ||
| 1233 | SBUTTERFLY2 dq, 1, 4, 6 ; m1 = 4, 16, 5, 17 | ||
| 1234 | ; m4 = 6, 18, 7, 19 | ||
| 1235 | SBUTTERFLY2 dq, 2, 5, 6 ; m2 = 8, 20, 9, 21 | ||
| 1236 | ; m5 = 10, 22, 11, 23 | ||
| 1237 | SBUTTERFLY2 dq, 0, 4, 6 ; m0 = 0, 6, 12, 18 | ||
| 1238 | ; m4 = 1, 7, 13, 19 | ||
| 1239 | SBUTTERFLY2 dq, 3, 2, 6 ; m3 = 2, 8, 14, 20 | ||
| 1240 | ; m2 = 3, 9, 15, 21 | ||
| 1241 | SBUTTERFLY2 dq, 1, 5, 6 ; m1 = 4, 10, 16, 22 | ||
| 1242 | ; m5 = 5, 11, 17, 23 | ||
| 1243 | mova [dstq ], m0 | ||
| 1244 | mova [dstq+dst1q], m4 | ||
| 1245 | mova [dstq+dst2q], m3 | ||
| 1246 | mova [dstq+dst3q], m2 | ||
| 1247 | mova [dstq+dst4q], m1 | ||
| 1248 | mova [dstq+dst5q], m5 | ||
| 1249 | add srcq, mmsize*6 | ||
| 1250 | add dstq, mmsize | ||
| 1251 | sub lend, mmsize/4 | ||
| 1252 | jg .loop | ||
| 1253 | REP_RET | ||
| 1254 | %endmacro | ||
| 1255 | |||
| 1256 | INIT_XMM sse2 | ||
| 1257 | CONV_FLT_TO_FLTP_6CH | ||
| 1258 | %if HAVE_AVX_EXTERNAL | ||
| 1259 | INIT_XMM avx | ||
| 1260 | CONV_FLT_TO_FLTP_6CH | ||
| 1261 | %endif | ||
| @@ -1,265 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | #include "libavutil/cpu.h" | ||
| 23 | #include "libavutil/x86/cpu.h" | ||
| 24 | #include "libavresample/audio_convert.h" | ||
| 25 | |||
| 26 | /* flat conversions */ | ||
| 27 | |||
| 28 | void ff_conv_s16_to_s32_sse2(int16_t *dst, const int32_t *src, int len); | ||
| 29 | |||
| 30 | void ff_conv_s16_to_flt_sse2(float *dst, const int16_t *src, int len); | ||
| 31 | void ff_conv_s16_to_flt_sse4(float *dst, const int16_t *src, int len); | ||
| 32 | |||
| 33 | void ff_conv_s32_to_s16_mmx (int16_t *dst, const int32_t *src, int len); | ||
| 34 | void ff_conv_s32_to_s16_sse2(int16_t *dst, const int32_t *src, int len); | ||
| 35 | |||
| 36 | void ff_conv_s32_to_flt_sse2(float *dst, const int32_t *src, int len); | ||
| 37 | void ff_conv_s32_to_flt_avx (float *dst, const int32_t *src, int len); | ||
| 38 | |||
| 39 | void ff_conv_flt_to_s16_sse2(int16_t *dst, const float *src, int len); | ||
| 40 | |||
| 41 | void ff_conv_flt_to_s32_sse2(int32_t *dst, const float *src, int len); | ||
| 42 | void ff_conv_flt_to_s32_avx (int32_t *dst, const float *src, int len); | ||
| 43 | |||
| 44 | /* interleave conversions */ | ||
| 45 | |||
| 46 | void ff_conv_s16p_to_s16_2ch_sse2(int16_t *dst, int16_t *const *src, | ||
| 47 | int len, int channels); | ||
| 48 | void ff_conv_s16p_to_s16_2ch_avx (int16_t *dst, int16_t *const *src, | ||
| 49 | int len, int channels); | ||
| 50 | |||
| 51 | void ff_conv_s16p_to_s16_6ch_sse2(int16_t *dst, int16_t *const *src, | ||
| 52 | int len, int channels); | ||
| 53 | void ff_conv_s16p_to_s16_6ch_sse2slow(int16_t *dst, int16_t *const *src, | ||
| 54 | int len, int channels); | ||
| 55 | void ff_conv_s16p_to_s16_6ch_avx (int16_t *dst, int16_t *const *src, | ||
| 56 | int len, int channels); | ||
| 57 | |||
| 58 | void ff_conv_s16p_to_flt_2ch_sse2(float *dst, int16_t *const *src, | ||
| 59 | int len, int channels); | ||
| 60 | void ff_conv_s16p_to_flt_2ch_avx (float *dst, int16_t *const *src, | ||
| 61 | int len, int channels); | ||
| 62 | |||
| 63 | void ff_conv_s16p_to_flt_6ch_sse2 (float *dst, int16_t *const *src, | ||
| 64 | int len, int channels); | ||
| 65 | void ff_conv_s16p_to_flt_6ch_ssse3(float *dst, int16_t *const *src, | ||
| 66 | int len, int channels); | ||
| 67 | void ff_conv_s16p_to_flt_6ch_avx (float *dst, int16_t *const *src, | ||
| 68 | int len, int channels); | ||
| 69 | |||
| 70 | void ff_conv_fltp_to_s16_2ch_sse2 (int16_t *dst, float *const *src, | ||
| 71 | int len, int channels); | ||
| 72 | void ff_conv_fltp_to_s16_2ch_ssse3(int16_t *dst, float *const *src, | ||
| 73 | int len, int channels); | ||
| 74 | |||
| 75 | void ff_conv_fltp_to_s16_6ch_sse (int16_t *dst, float *const *src, | ||
| 76 | int len, int channels); | ||
| 77 | void ff_conv_fltp_to_s16_6ch_sse2(int16_t *dst, float *const *src, | ||
| 78 | int len, int channels); | ||
| 79 | void ff_conv_fltp_to_s16_6ch_avx (int16_t *dst, float *const *src, | ||
| 80 | int len, int channels); | ||
| 81 | |||
| 82 | void ff_conv_fltp_to_flt_2ch_sse(float *dst, float *const *src, int len, | ||
| 83 | int channels); | ||
| 84 | void ff_conv_fltp_to_flt_2ch_avx(float *dst, float *const *src, int len, | ||
| 85 | int channels); | ||
| 86 | |||
| 87 | void ff_conv_fltp_to_flt_6ch_mmx (float *dst, float *const *src, int len, | ||
| 88 | int channels); | ||
| 89 | void ff_conv_fltp_to_flt_6ch_sse4(float *dst, float *const *src, int len, | ||
| 90 | int channels); | ||
| 91 | void ff_conv_fltp_to_flt_6ch_avx (float *dst, float *const *src, int len, | ||
| 92 | int channels); | ||
| 93 | |||
| 94 | /* deinterleave conversions */ | ||
| 95 | |||
| 96 | void ff_conv_s16_to_s16p_2ch_sse2(int16_t *const *dst, int16_t *src, | ||
| 97 | int len, int channels); | ||
| 98 | void ff_conv_s16_to_s16p_2ch_ssse3(int16_t *const *dst, int16_t *src, | ||
| 99 | int len, int channels); | ||
| 100 | void ff_conv_s16_to_s16p_2ch_avx (int16_t *const *dst, int16_t *src, | ||
| 101 | int len, int channels); | ||
| 102 | |||
| 103 | void ff_conv_s16_to_s16p_6ch_sse2 (int16_t *const *dst, int16_t *src, | ||
| 104 | int len, int channels); | ||
| 105 | void ff_conv_s16_to_s16p_6ch_ssse3(int16_t *const *dst, int16_t *src, | ||
| 106 | int len, int channels); | ||
| 107 | void ff_conv_s16_to_s16p_6ch_avx (int16_t *const *dst, int16_t *src, | ||
| 108 | int len, int channels); | ||
| 109 | |||
| 110 | void ff_conv_s16_to_fltp_2ch_sse2(float *const *dst, int16_t *src, | ||
| 111 | int len, int channels); | ||
| 112 | void ff_conv_s16_to_fltp_2ch_avx (float *const *dst, int16_t *src, | ||
| 113 | int len, int channels); | ||
| 114 | |||
| 115 | void ff_conv_s16_to_fltp_6ch_sse2 (float *const *dst, int16_t *src, | ||
| 116 | int len, int channels); | ||
| 117 | void ff_conv_s16_to_fltp_6ch_ssse3(float *const *dst, int16_t *src, | ||
| 118 | int len, int channels); | ||
| 119 | void ff_conv_s16_to_fltp_6ch_sse4 (float *const *dst, int16_t *src, | ||
| 120 | int len, int channels); | ||
| 121 | void ff_conv_s16_to_fltp_6ch_avx (float *const *dst, int16_t *src, | ||
| 122 | int len, int channels); | ||
| 123 | |||
| 124 | void ff_conv_flt_to_s16p_2ch_sse2(int16_t *const *dst, float *src, | ||
| 125 | int len, int channels); | ||
| 126 | void ff_conv_flt_to_s16p_2ch_avx (int16_t *const *dst, float *src, | ||
| 127 | int len, int channels); | ||
| 128 | |||
| 129 | void ff_conv_flt_to_s16p_6ch_sse2 (int16_t *const *dst, float *src, | ||
| 130 | int len, int channels); | ||
| 131 | void ff_conv_flt_to_s16p_6ch_ssse3(int16_t *const *dst, float *src, | ||
| 132 | int len, int channels); | ||
| 133 | void ff_conv_flt_to_s16p_6ch_avx (int16_t *const *dst, float *src, | ||
| 134 | int len, int channels); | ||
| 135 | |||
| 136 | void ff_conv_flt_to_fltp_2ch_sse(float *const *dst, float *src, int len, | ||
| 137 | int channels); | ||
| 138 | void ff_conv_flt_to_fltp_2ch_avx(float *const *dst, float *src, int len, | ||
| 139 | int channels); | ||
| 140 | |||
| 141 | void ff_conv_flt_to_fltp_6ch_sse2(float *const *dst, float *src, int len, | ||
| 142 | int channels); | ||
| 143 | void ff_conv_flt_to_fltp_6ch_avx (float *const *dst, float *src, int len, | ||
| 144 | int channels); | ||
| 145 | |||
| 146 | av_cold void ff_audio_convert_init_x86(AudioConvert *ac) | ||
| 147 | { | ||
| 148 | int cpu_flags = av_get_cpu_flags(); | ||
| 149 | |||
| 150 | if (EXTERNAL_MMX(cpu_flags)) { | ||
| 151 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, | ||
| 152 | 0, 1, 8, "MMX", ff_conv_s32_to_s16_mmx); | ||
| 153 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, | ||
| 154 | 6, 1, 4, "MMX", ff_conv_fltp_to_flt_6ch_mmx); | ||
| 155 | } | ||
| 156 | if (EXTERNAL_SSE(cpu_flags)) { | ||
| 157 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, | ||
| 158 | 6, 1, 2, "SSE", ff_conv_fltp_to_s16_6ch_sse); | ||
| 159 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, | ||
| 160 | 2, 16, 8, "SSE", ff_conv_fltp_to_flt_2ch_sse); | ||
| 161 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT, | ||
| 162 | 2, 16, 4, "SSE", ff_conv_flt_to_fltp_2ch_sse); | ||
| 163 | } | ||
| 164 | if (EXTERNAL_SSE2(cpu_flags)) { | ||
| 165 | if (!(cpu_flags & AV_CPU_FLAG_SSE2SLOW)) { | ||
| 166 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S32, | ||
| 167 | 0, 16, 16, "SSE2", ff_conv_s32_to_s16_sse2); | ||
| 168 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, | ||
| 169 | 6, 16, 8, "SSE2", ff_conv_s16p_to_s16_6ch_sse2); | ||
| 170 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, | ||
| 171 | 6, 16, 4, "SSE2", ff_conv_fltp_to_s16_6ch_sse2); | ||
| 172 | } else { | ||
| 173 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, | ||
| 174 | 6, 1, 4, "SSE2SLOW", ff_conv_s16p_to_s16_6ch_sse2slow); | ||
| 175 | } | ||
| 176 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_S16, | ||
| 177 | 0, 16, 8, "SSE2", ff_conv_s16_to_s32_sse2); | ||
| 178 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16, | ||
| 179 | 0, 16, 8, "SSE2", ff_conv_s16_to_flt_sse2); | ||
| 180 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32, | ||
| 181 | 0, 16, 8, "SSE2", ff_conv_s32_to_flt_sse2); | ||
| 182 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLT, | ||
| 183 | 0, 16, 16, "SSE2", ff_conv_flt_to_s16_sse2); | ||
| 184 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT, | ||
| 185 | 0, 16, 16, "SSE2", ff_conv_flt_to_s32_sse2); | ||
| 186 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, | ||
| 187 | 2, 16, 16, "SSE2", ff_conv_s16p_to_s16_2ch_sse2); | ||
| 188 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, | ||
| 189 | 2, 16, 8, "SSE2", ff_conv_s16p_to_flt_2ch_sse2); | ||
| 190 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, | ||
| 191 | 6, 16, 4, "SSE2", ff_conv_s16p_to_flt_6ch_sse2); | ||
| 192 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, | ||
| 193 | 2, 16, 4, "SSE2", ff_conv_fltp_to_s16_2ch_sse2); | ||
| 194 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, | ||
| 195 | 2, 16, 8, "SSE2", ff_conv_s16_to_s16p_2ch_sse2); | ||
| 196 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, | ||
| 197 | 6, 16, 4, "SSE2", ff_conv_s16_to_s16p_6ch_sse2); | ||
| 198 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, | ||
| 199 | 2, 16, 8, "SSE2", ff_conv_s16_to_fltp_2ch_sse2); | ||
| 200 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, | ||
| 201 | 6, 16, 4, "SSE2", ff_conv_s16_to_fltp_6ch_sse2); | ||
| 202 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, | ||
| 203 | 2, 16, 8, "SSE2", ff_conv_flt_to_s16p_2ch_sse2); | ||
| 204 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, | ||
| 205 | 6, 16, 4, "SSE2", ff_conv_flt_to_s16p_6ch_sse2); | ||
| 206 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT, | ||
| 207 | 6, 16, 4, "SSE2", ff_conv_flt_to_fltp_6ch_sse2); | ||
| 208 | } | ||
| 209 | if (EXTERNAL_SSSE3(cpu_flags)) { | ||
| 210 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, | ||
| 211 | 6, 16, 4, "SSSE3", ff_conv_s16p_to_flt_6ch_ssse3); | ||
| 212 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, | ||
| 213 | 2, 16, 4, "SSSE3", ff_conv_fltp_to_s16_2ch_ssse3); | ||
| 214 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, | ||
| 215 | 2, 16, 8, "SSSE3", ff_conv_s16_to_s16p_2ch_ssse3); | ||
| 216 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, | ||
| 217 | 6, 16, 4, "SSSE3", ff_conv_s16_to_s16p_6ch_ssse3); | ||
| 218 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, | ||
| 219 | 6, 16, 4, "SSSE3", ff_conv_s16_to_fltp_6ch_ssse3); | ||
| 220 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, | ||
| 221 | 6, 16, 4, "SSSE3", ff_conv_flt_to_s16p_6ch_ssse3); | ||
| 222 | } | ||
| 223 | if (EXTERNAL_SSE4(cpu_flags)) { | ||
| 224 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16, | ||
| 225 | 0, 16, 8, "SSE4", ff_conv_s16_to_flt_sse4); | ||
| 226 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, | ||
| 227 | 6, 16, 4, "SSE4", ff_conv_fltp_to_flt_6ch_sse4); | ||
| 228 | } | ||
| 229 | if (EXTERNAL_AVX_FAST(cpu_flags)) { | ||
| 230 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S32, | ||
| 231 | 0, 32, 16, "AVX", ff_conv_s32_to_flt_avx); | ||
| 232 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_FLT, | ||
| 233 | 0, 32, 32, "AVX", ff_conv_flt_to_s32_avx); | ||
| 234 | } | ||
| 235 | if (EXTERNAL_AVX(cpu_flags)) { | ||
| 236 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, | ||
| 237 | 2, 16, 16, "AVX", ff_conv_s16p_to_s16_2ch_avx); | ||
| 238 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_S16P, | ||
| 239 | 6, 16, 8, "AVX", ff_conv_s16p_to_s16_6ch_avx); | ||
| 240 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, | ||
| 241 | 2, 16, 8, "AVX", ff_conv_s16p_to_flt_2ch_avx); | ||
| 242 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16P, | ||
| 243 | 6, 16, 4, "AVX", ff_conv_s16p_to_flt_6ch_avx); | ||
| 244 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_FLTP, | ||
| 245 | 6, 16, 4, "AVX", ff_conv_fltp_to_s16_6ch_avx); | ||
| 246 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, | ||
| 247 | 6, 16, 4, "AVX", ff_conv_fltp_to_flt_6ch_avx); | ||
| 248 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, | ||
| 249 | 2, 16, 8, "AVX", ff_conv_s16_to_s16p_2ch_avx); | ||
| 250 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S16, | ||
| 251 | 6, 16, 4, "AVX", ff_conv_s16_to_s16p_6ch_avx); | ||
| 252 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, | ||
| 253 | 2, 16, 8, "AVX", ff_conv_s16_to_fltp_2ch_avx); | ||
| 254 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_S16, | ||
| 255 | 6, 16, 4, "AVX", ff_conv_s16_to_fltp_6ch_avx); | ||
| 256 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, | ||
| 257 | 2, 16, 8, "AVX", ff_conv_flt_to_s16p_2ch_avx); | ||
| 258 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLT, | ||
| 259 | 6, 16, 4, "AVX", ff_conv_flt_to_s16p_6ch_avx); | ||
| 260 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT, | ||
| 261 | 2, 16, 4, "AVX", ff_conv_flt_to_fltp_2ch_avx); | ||
| 262 | ff_audio_convert_set_func(ac, AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT, | ||
| 263 | 6, 16, 4, "AVX", ff_conv_flt_to_fltp_6ch_avx); | ||
| 264 | } | ||
| 265 | } | ||
| @@ -1,511 +0,0 @@ | |||
| 1 | ;****************************************************************************** | ||
| 2 | ;* x86 optimized channel mixing | ||
| 3 | ;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 4 | ;* | ||
| 5 | ;* This file is part of FFmpeg. | ||
| 6 | ;* | ||
| 7 | ;* FFmpeg is free software; you can redistribute it and/or | ||
| 8 | ;* modify it under the terms of the GNU Lesser General Public | ||
| 9 | ;* License as published by the Free Software Foundation; either | ||
| 10 | ;* version 2.1 of the License, or (at your option) any later version. | ||
| 11 | ;* | ||
| 12 | ;* FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | ;* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | ;* Lesser General Public License for more details. | ||
| 16 | ;* | ||
| 17 | ;* You should have received a copy of the GNU Lesser General Public | ||
| 18 | ;* License along with FFmpeg; if not, write to the Free Software | ||
| 19 | ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | ;****************************************************************************** | ||
| 21 | |||
| 22 | %include "libavutil/x86/x86util.asm" | ||
| 23 | %include "util.asm" | ||
| 24 | |||
| 25 | SECTION .text | ||
| 26 | |||
| 27 | ;----------------------------------------------------------------------------- | ||
| 28 | ; void ff_mix_2_to_1_fltp_flt(float **src, float **matrix, int len, | ||
| 29 | ; int out_ch, int in_ch); | ||
| 30 | ;----------------------------------------------------------------------------- | ||
| 31 | |||
| 32 | %macro MIX_2_TO_1_FLTP_FLT 0 | ||
| 33 | cglobal mix_2_to_1_fltp_flt, 3,4,6, src, matrix, len, src1 | ||
| 34 | mov src1q, [srcq+gprsize] | ||
| 35 | mov srcq, [srcq ] | ||
| 36 | sub src1q, srcq | ||
| 37 | mov matrixq, [matrixq ] | ||
| 38 | VBROADCASTSS m4, [matrixq ] | ||
| 39 | VBROADCASTSS m5, [matrixq+4] | ||
| 40 | ALIGN 16 | ||
| 41 | .loop: | ||
| 42 | mulps m0, m4, [srcq ] | ||
| 43 | mulps m1, m5, [srcq+src1q ] | ||
| 44 | mulps m2, m4, [srcq+ mmsize] | ||
| 45 | mulps m3, m5, [srcq+src1q+mmsize] | ||
| 46 | addps m0, m0, m1 | ||
| 47 | addps m2, m2, m3 | ||
| 48 | mova [srcq ], m0 | ||
| 49 | mova [srcq+mmsize], m2 | ||
| 50 | add srcq, mmsize*2 | ||
| 51 | sub lend, mmsize*2/4 | ||
| 52 | jg .loop | ||
| 53 | REP_RET | ||
| 54 | %endmacro | ||
| 55 | |||
| 56 | INIT_XMM sse | ||
| 57 | MIX_2_TO_1_FLTP_FLT | ||
| 58 | %if HAVE_AVX_EXTERNAL | ||
| 59 | INIT_YMM avx | ||
| 60 | MIX_2_TO_1_FLTP_FLT | ||
| 61 | %endif | ||
| 62 | |||
| 63 | ;----------------------------------------------------------------------------- | ||
| 64 | ; void ff_mix_2_to_1_s16p_flt(int16_t **src, float **matrix, int len, | ||
| 65 | ; int out_ch, int in_ch); | ||
| 66 | ;----------------------------------------------------------------------------- | ||
| 67 | |||
| 68 | %macro MIX_2_TO_1_S16P_FLT 0 | ||
| 69 | cglobal mix_2_to_1_s16p_flt, 3,4,6, src, matrix, len, src1 | ||
| 70 | mov src1q, [srcq+gprsize] | ||
| 71 | mov srcq, [srcq] | ||
| 72 | sub src1q, srcq | ||
| 73 | mov matrixq, [matrixq ] | ||
| 74 | VBROADCASTSS m4, [matrixq ] | ||
| 75 | VBROADCASTSS m5, [matrixq+4] | ||
| 76 | ALIGN 16 | ||
| 77 | .loop: | ||
| 78 | mova m0, [srcq ] | ||
| 79 | mova m2, [srcq+src1q] | ||
| 80 | S16_TO_S32_SX 0, 1 | ||
| 81 | S16_TO_S32_SX 2, 3 | ||
| 82 | cvtdq2ps m0, m0 | ||
| 83 | cvtdq2ps m1, m1 | ||
| 84 | cvtdq2ps m2, m2 | ||
| 85 | cvtdq2ps m3, m3 | ||
| 86 | mulps m0, m4 | ||
| 87 | mulps m1, m4 | ||
| 88 | mulps m2, m5 | ||
| 89 | mulps m3, m5 | ||
| 90 | addps m0, m2 | ||
| 91 | addps m1, m3 | ||
| 92 | cvtps2dq m0, m0 | ||
| 93 | cvtps2dq m1, m1 | ||
| 94 | packssdw m0, m1 | ||
| 95 | mova [srcq], m0 | ||
| 96 | add srcq, mmsize | ||
| 97 | sub lend, mmsize/2 | ||
| 98 | jg .loop | ||
| 99 | REP_RET | ||
| 100 | %endmacro | ||
| 101 | |||
| 102 | INIT_XMM sse2 | ||
| 103 | MIX_2_TO_1_S16P_FLT | ||
| 104 | INIT_XMM sse4 | ||
| 105 | MIX_2_TO_1_S16P_FLT | ||
| 106 | |||
| 107 | ;----------------------------------------------------------------------------- | ||
| 108 | ; void ff_mix_2_to_1_s16p_q8(int16_t **src, int16_t **matrix, int len, | ||
| 109 | ; int out_ch, int in_ch); | ||
| 110 | ;----------------------------------------------------------------------------- | ||
| 111 | |||
| 112 | INIT_XMM sse2 | ||
| 113 | cglobal mix_2_to_1_s16p_q8, 3,4,6, src, matrix, len, src1 | ||
| 114 | mov src1q, [srcq+gprsize] | ||
| 115 | mov srcq, [srcq] | ||
| 116 | sub src1q, srcq | ||
| 117 | mov matrixq, [matrixq] | ||
| 118 | movd m4, [matrixq] | ||
| 119 | movd m5, [matrixq] | ||
| 120 | SPLATW m4, m4, 0 | ||
| 121 | SPLATW m5, m5, 1 | ||
| 122 | pxor m0, m0 | ||
| 123 | punpcklwd m4, m0 | ||
| 124 | punpcklwd m5, m0 | ||
| 125 | ALIGN 16 | ||
| 126 | .loop: | ||
| 127 | mova m0, [srcq ] | ||
| 128 | mova m2, [srcq+src1q] | ||
| 129 | punpckhwd m1, m0, m0 | ||
| 130 | punpcklwd m0, m0 | ||
| 131 | punpckhwd m3, m2, m2 | ||
| 132 | punpcklwd m2, m2 | ||
| 133 | pmaddwd m0, m4 | ||
| 134 | pmaddwd m1, m4 | ||
| 135 | pmaddwd m2, m5 | ||
| 136 | pmaddwd m3, m5 | ||
| 137 | paddd m0, m2 | ||
| 138 | paddd m1, m3 | ||
| 139 | psrad m0, 8 | ||
| 140 | psrad m1, 8 | ||
| 141 | packssdw m0, m1 | ||
| 142 | mova [srcq], m0 | ||
| 143 | add srcq, mmsize | ||
| 144 | sub lend, mmsize/2 | ||
| 145 | jg .loop | ||
| 146 | REP_RET | ||
| 147 | |||
| 148 | ;----------------------------------------------------------------------------- | ||
| 149 | ; void ff_mix_1_to_2_fltp_flt(float **src, float **matrix, int len, | ||
| 150 | ; int out_ch, int in_ch); | ||
| 151 | ;----------------------------------------------------------------------------- | ||
| 152 | |||
| 153 | %macro MIX_1_TO_2_FLTP_FLT 0 | ||
| 154 | cglobal mix_1_to_2_fltp_flt, 3,5,4, src0, matrix0, len, src1, matrix1 | ||
| 155 | mov src1q, [src0q+gprsize] | ||
| 156 | mov src0q, [src0q] | ||
| 157 | sub src1q, src0q | ||
| 158 | mov matrix1q, [matrix0q+gprsize] | ||
| 159 | mov matrix0q, [matrix0q] | ||
| 160 | VBROADCASTSS m2, [matrix0q] | ||
| 161 | VBROADCASTSS m3, [matrix1q] | ||
| 162 | ALIGN 16 | ||
| 163 | .loop: | ||
| 164 | mova m0, [src0q] | ||
| 165 | mulps m1, m0, m3 | ||
| 166 | mulps m0, m0, m2 | ||
| 167 | mova [src0q ], m0 | ||
| 168 | mova [src0q+src1q], m1 | ||
| 169 | add src0q, mmsize | ||
| 170 | sub lend, mmsize/4 | ||
| 171 | jg .loop | ||
| 172 | REP_RET | ||
| 173 | %endmacro | ||
| 174 | |||
| 175 | INIT_XMM sse | ||
| 176 | MIX_1_TO_2_FLTP_FLT | ||
| 177 | %if HAVE_AVX_EXTERNAL | ||
| 178 | INIT_YMM avx | ||
| 179 | MIX_1_TO_2_FLTP_FLT | ||
| 180 | %endif | ||
| 181 | |||
| 182 | ;----------------------------------------------------------------------------- | ||
| 183 | ; void ff_mix_1_to_2_s16p_flt(int16_t **src, float **matrix, int len, | ||
| 184 | ; int out_ch, int in_ch); | ||
| 185 | ;----------------------------------------------------------------------------- | ||
| 186 | |||
| 187 | %macro MIX_1_TO_2_S16P_FLT 0 | ||
| 188 | cglobal mix_1_to_2_s16p_flt, 3,5,6, src0, matrix0, len, src1, matrix1 | ||
| 189 | mov src1q, [src0q+gprsize] | ||
| 190 | mov src0q, [src0q] | ||
| 191 | sub src1q, src0q | ||
| 192 | mov matrix1q, [matrix0q+gprsize] | ||
| 193 | mov matrix0q, [matrix0q] | ||
| 194 | VBROADCASTSS m4, [matrix0q] | ||
| 195 | VBROADCASTSS m5, [matrix1q] | ||
| 196 | ALIGN 16 | ||
| 197 | .loop: | ||
| 198 | mova m0, [src0q] | ||
| 199 | S16_TO_S32_SX 0, 2 | ||
| 200 | cvtdq2ps m0, m0 | ||
| 201 | cvtdq2ps m2, m2 | ||
| 202 | mulps m1, m0, m5 | ||
| 203 | mulps m0, m0, m4 | ||
| 204 | mulps m3, m2, m5 | ||
| 205 | mulps m2, m2, m4 | ||
| 206 | cvtps2dq m0, m0 | ||
| 207 | cvtps2dq m1, m1 | ||
| 208 | cvtps2dq m2, m2 | ||
| 209 | cvtps2dq m3, m3 | ||
| 210 | packssdw m0, m2 | ||
| 211 | packssdw m1, m3 | ||
| 212 | mova [src0q ], m0 | ||
| 213 | mova [src0q+src1q], m1 | ||
| 214 | add src0q, mmsize | ||
| 215 | sub lend, mmsize/2 | ||
| 216 | jg .loop | ||
| 217 | REP_RET | ||
| 218 | %endmacro | ||
| 219 | |||
| 220 | INIT_XMM sse2 | ||
| 221 | MIX_1_TO_2_S16P_FLT | ||
| 222 | INIT_XMM sse4 | ||
| 223 | MIX_1_TO_2_S16P_FLT | ||
| 224 | %if HAVE_AVX_EXTERNAL | ||
| 225 | INIT_XMM avx | ||
| 226 | MIX_1_TO_2_S16P_FLT | ||
| 227 | %endif | ||
| 228 | |||
| 229 | ;----------------------------------------------------------------------------- | ||
| 230 | ; void ff_mix_3_8_to_1_2_fltp/s16p_flt(float/int16_t **src, float **matrix, | ||
| 231 | ; int len, int out_ch, int in_ch); | ||
| 232 | ;----------------------------------------------------------------------------- | ||
| 233 | |||
| 234 | %macro MIX_3_8_TO_1_2_FLT 3 ; %1 = in channels, %2 = out channels, %3 = s16p or fltp | ||
| 235 | ; define some names to make the code clearer | ||
| 236 | %assign in_channels %1 | ||
| 237 | %assign out_channels %2 | ||
| 238 | %assign stereo out_channels - 1 | ||
| 239 | %ifidn %3, s16p | ||
| 240 | %assign is_s16 1 | ||
| 241 | %else | ||
| 242 | %assign is_s16 0 | ||
| 243 | %endif | ||
| 244 | |||
| 245 | ; determine how many matrix elements must go on the stack vs. mmregs | ||
| 246 | %assign matrix_elements in_channels * out_channels | ||
| 247 | %if is_s16 | ||
| 248 | %if stereo | ||
| 249 | %assign needed_mmregs 7 | ||
| 250 | %else | ||
| 251 | %assign needed_mmregs 5 | ||
| 252 | %endif | ||
| 253 | %else | ||
| 254 | %if stereo | ||
| 255 | %assign needed_mmregs 4 | ||
| 256 | %else | ||
| 257 | %assign needed_mmregs 3 | ||
| 258 | %endif | ||
| 259 | %endif | ||
| 260 | %assign matrix_elements_mm num_mmregs - needed_mmregs | ||
| 261 | %if matrix_elements < matrix_elements_mm | ||
| 262 | %assign matrix_elements_mm matrix_elements | ||
| 263 | %endif | ||
| 264 | %if matrix_elements_mm < matrix_elements | ||
| 265 | %assign matrix_elements_stack matrix_elements - matrix_elements_mm | ||
| 266 | %else | ||
| 267 | %assign matrix_elements_stack 0 | ||
| 268 | %endif | ||
| 269 | %assign matrix_stack_size matrix_elements_stack * mmsize | ||
| 270 | |||
| 271 | %assign needed_stack_size -1 * matrix_stack_size | ||
| 272 | %if ARCH_X86_32 && in_channels >= 7 | ||
| 273 | %assign needed_stack_size needed_stack_size - 16 | ||
| 274 | %endif | ||
| 275 | |||
| 276 | cglobal mix_%1_to_%2_%3_flt, 3,in_channels+2,needed_mmregs+matrix_elements_mm, needed_stack_size, src0, src1, len, src2, src3, src4, src5, src6, src7 | ||
| 277 | |||
| 278 | ; define src pointers on stack if needed | ||
| 279 | %if matrix_elements_stack > 0 && ARCH_X86_32 && in_channels >= 7 | ||
| 280 | %define src5m [rsp+matrix_stack_size+0] | ||
| 281 | %define src6m [rsp+matrix_stack_size+4] | ||
| 282 | %define src7m [rsp+matrix_stack_size+8] | ||
| 283 | %endif | ||
| 284 | |||
| 285 | ; load matrix pointers | ||
| 286 | %define matrix0q r1q | ||
| 287 | %define matrix1q r3q | ||
| 288 | %if stereo | ||
| 289 | mov matrix1q, [matrix0q+gprsize] | ||
| 290 | %endif | ||
| 291 | mov matrix0q, [matrix0q] | ||
| 292 | |||
| 293 | ; define matrix coeff names | ||
| 294 | %assign %%i 0 | ||
| 295 | %assign %%j needed_mmregs | ||
| 296 | %rep in_channels | ||
| 297 | %if %%i >= matrix_elements_mm | ||
| 298 | CAT_XDEFINE mx_stack_0_, %%i, 1 | ||
| 299 | CAT_XDEFINE mx_0_, %%i, [rsp+(%%i-matrix_elements_mm)*mmsize] | ||
| 300 | %else | ||
| 301 | CAT_XDEFINE mx_stack_0_, %%i, 0 | ||
| 302 | CAT_XDEFINE mx_0_, %%i, m %+ %%j | ||
| 303 | %assign %%j %%j+1 | ||
| 304 | %endif | ||
| 305 | %assign %%i %%i+1 | ||
| 306 | %endrep | ||
| 307 | %if stereo | ||
| 308 | %assign %%i 0 | ||
| 309 | %rep in_channels | ||
| 310 | %if in_channels + %%i >= matrix_elements_mm | ||
| 311 | CAT_XDEFINE mx_stack_1_, %%i, 1 | ||
| 312 | CAT_XDEFINE mx_1_, %%i, [rsp+(in_channels+%%i-matrix_elements_mm)*mmsize] | ||
| 313 | %else | ||
| 314 | CAT_XDEFINE mx_stack_1_, %%i, 0 | ||
| 315 | CAT_XDEFINE mx_1_, %%i, m %+ %%j | ||
| 316 | %assign %%j %%j+1 | ||
| 317 | %endif | ||
| 318 | %assign %%i %%i+1 | ||
| 319 | %endrep | ||
| 320 | %endif | ||
| 321 | |||
| 322 | ; load/splat matrix coeffs | ||
| 323 | %assign %%i 0 | ||
| 324 | %rep in_channels | ||
| 325 | %if mx_stack_0_ %+ %%i | ||
| 326 | VBROADCASTSS m0, [matrix0q+4*%%i] | ||
| 327 | mova mx_0_ %+ %%i, m0 | ||
| 328 | %else | ||
| 329 | VBROADCASTSS mx_0_ %+ %%i, [matrix0q+4*%%i] | ||
| 330 | %endif | ||
| 331 | %if stereo | ||
| 332 | %if mx_stack_1_ %+ %%i | ||
| 333 | VBROADCASTSS m0, [matrix1q+4*%%i] | ||
| 334 | mova mx_1_ %+ %%i, m0 | ||
| 335 | %else | ||
| 336 | VBROADCASTSS mx_1_ %+ %%i, [matrix1q+4*%%i] | ||
| 337 | %endif | ||
| 338 | %endif | ||
| 339 | %assign %%i %%i+1 | ||
| 340 | %endrep | ||
| 341 | |||
| 342 | ; load channel pointers to registers as offsets from the first channel pointer | ||
| 343 | %if ARCH_X86_64 | ||
| 344 | movsxd lenq, r2d | ||
| 345 | %endif | ||
| 346 | shl lenq, 2-is_s16 | ||
| 347 | %assign %%i 1 | ||
| 348 | %rep (in_channels - 1) | ||
| 349 | %if ARCH_X86_32 && in_channels >= 7 && %%i >= 5 | ||
| 350 | mov src5q, [src0q+%%i*gprsize] | ||
| 351 | add src5q, lenq | ||
| 352 | mov src %+ %%i %+ m, src5q | ||
| 353 | %else | ||
| 354 | mov src %+ %%i %+ q, [src0q+%%i*gprsize] | ||
| 355 | add src %+ %%i %+ q, lenq | ||
| 356 | %endif | ||
| 357 | %assign %%i %%i+1 | ||
| 358 | %endrep | ||
| 359 | mov src0q, [src0q] | ||
| 360 | add src0q, lenq | ||
| 361 | neg lenq | ||
| 362 | .loop: | ||
| 363 | ; for x86-32 with 7-8 channels we do not have enough gp registers for all src | ||
| 364 | ; pointers, so we have to load some of them from the stack each time | ||
| 365 | %define copy_src_from_stack ARCH_X86_32 && in_channels >= 7 && %%i >= 5 | ||
| 366 | %if is_s16 | ||
| 367 | ; mix with s16p input | ||
| 368 | mova m0, [src0q+lenq] | ||
| 369 | S16_TO_S32_SX 0, 1 | ||
| 370 | cvtdq2ps m0, m0 | ||
| 371 | cvtdq2ps m1, m1 | ||
| 372 | %if stereo | ||
| 373 | mulps m2, m0, mx_1_0 | ||
| 374 | mulps m3, m1, mx_1_0 | ||
| 375 | %endif | ||
| 376 | mulps m0, m0, mx_0_0 | ||
| 377 | mulps m1, m1, mx_0_0 | ||
| 378 | %assign %%i 1 | ||
| 379 | %rep (in_channels - 1) | ||
| 380 | %if copy_src_from_stack | ||
| 381 | %define src_ptr src5q | ||
| 382 | %else | ||
| 383 | %define src_ptr src %+ %%i %+ q | ||
| 384 | %endif | ||
| 385 | %if stereo | ||
| 386 | %if copy_src_from_stack | ||
| 387 | mov src_ptr, src %+ %%i %+ m | ||
| 388 | %endif | ||
| 389 | mova m4, [src_ptr+lenq] | ||
| 390 | S16_TO_S32_SX 4, 5 | ||
| 391 | cvtdq2ps m4, m4 | ||
| 392 | cvtdq2ps m5, m5 | ||
| 393 | FMULADD_PS m2, m4, mx_1_ %+ %%i, m2, m6 | ||
| 394 | FMULADD_PS m3, m5, mx_1_ %+ %%i, m3, m6 | ||
| 395 | FMULADD_PS m0, m4, mx_0_ %+ %%i, m0, m4 | ||
| 396 | FMULADD_PS m1, m5, mx_0_ %+ %%i, m1, m5 | ||
| 397 | %else | ||
| 398 | %if copy_src_from_stack | ||
| 399 | mov src_ptr, src %+ %%i %+ m | ||
| 400 | %endif | ||
| 401 | mova m2, [src_ptr+lenq] | ||
| 402 | S16_TO_S32_SX 2, 3 | ||
| 403 | cvtdq2ps m2, m2 | ||
| 404 | cvtdq2ps m3, m3 | ||
| 405 | FMULADD_PS m0, m2, mx_0_ %+ %%i, m0, m4 | ||
| 406 | FMULADD_PS m1, m3, mx_0_ %+ %%i, m1, m4 | ||
| 407 | %endif | ||
| 408 | %assign %%i %%i+1 | ||
| 409 | %endrep | ||
| 410 | %if stereo | ||
| 411 | cvtps2dq m2, m2 | ||
| 412 | cvtps2dq m3, m3 | ||
| 413 | packssdw m2, m3 | ||
| 414 | mova [src1q+lenq], m2 | ||
| 415 | %endif | ||
| 416 | cvtps2dq m0, m0 | ||
| 417 | cvtps2dq m1, m1 | ||
| 418 | packssdw m0, m1 | ||
| 419 | mova [src0q+lenq], m0 | ||
| 420 | %else | ||
| 421 | ; mix with fltp input | ||
| 422 | %if stereo || mx_stack_0_0 | ||
| 423 | mova m0, [src0q+lenq] | ||
| 424 | %endif | ||
| 425 | %if stereo | ||
| 426 | mulps m1, m0, mx_1_0 | ||
| 427 | %endif | ||
| 428 | %if stereo || mx_stack_0_0 | ||
| 429 | mulps m0, m0, mx_0_0 | ||
| 430 | %else | ||
| 431 | mulps m0, mx_0_0, [src0q+lenq] | ||
| 432 | %endif | ||
| 433 | %assign %%i 1 | ||
| 434 | %rep (in_channels - 1) | ||
| 435 | %if copy_src_from_stack | ||
| 436 | %define src_ptr src5q | ||
| 437 | mov src_ptr, src %+ %%i %+ m | ||
| 438 | %else | ||
| 439 | %define src_ptr src %+ %%i %+ q | ||
| 440 | %endif | ||
| 441 | ; avoid extra load for mono if matrix is in a mm register | ||
| 442 | %if stereo || mx_stack_0_ %+ %%i | ||
| 443 | mova m2, [src_ptr+lenq] | ||
| 444 | %endif | ||
| 445 | %if stereo | ||
| 446 | FMULADD_PS m1, m2, mx_1_ %+ %%i, m1, m3 | ||
| 447 | %endif | ||
| 448 | %if stereo || mx_stack_0_ %+ %%i | ||
| 449 | FMULADD_PS m0, m2, mx_0_ %+ %%i, m0, m2 | ||
| 450 | %else | ||
| 451 | FMULADD_PS m0, mx_0_ %+ %%i, [src_ptr+lenq], m0, m1 | ||
| 452 | %endif | ||
| 453 | %assign %%i %%i+1 | ||
| 454 | %endrep | ||
| 455 | mova [src0q+lenq], m0 | ||
| 456 | %if stereo | ||
| 457 | mova [src1q+lenq], m1 | ||
| 458 | %endif | ||
| 459 | %endif | ||
| 460 | |||
| 461 | add lenq, mmsize | ||
| 462 | jl .loop | ||
| 463 | ; zero ymm high halves | ||
| 464 | %if mmsize == 32 | ||
| 465 | vzeroupper | ||
| 466 | %endif | ||
| 467 | RET | ||
| 468 | %endmacro | ||
| 469 | |||
| 470 | %macro MIX_3_8_TO_1_2_FLT_FUNCS 0 | ||
| 471 | %assign %%i 3 | ||
| 472 | %rep 6 | ||
| 473 | INIT_XMM sse | ||
| 474 | MIX_3_8_TO_1_2_FLT %%i, 1, fltp | ||
| 475 | MIX_3_8_TO_1_2_FLT %%i, 2, fltp | ||
| 476 | INIT_XMM sse2 | ||
| 477 | MIX_3_8_TO_1_2_FLT %%i, 1, s16p | ||
| 478 | MIX_3_8_TO_1_2_FLT %%i, 2, s16p | ||
| 479 | INIT_XMM sse4 | ||
| 480 | MIX_3_8_TO_1_2_FLT %%i, 1, s16p | ||
| 481 | MIX_3_8_TO_1_2_FLT %%i, 2, s16p | ||
| 482 | ; do not use ymm AVX or FMA4 in x86-32 for 6 or more channels due to stack alignment issues | ||
| 483 | %if HAVE_AVX_EXTERNAL | ||
| 484 | %if ARCH_X86_64 || %%i < 6 | ||
| 485 | INIT_YMM avx | ||
| 486 | %else | ||
| 487 | INIT_XMM avx | ||
| 488 | %endif | ||
| 489 | MIX_3_8_TO_1_2_FLT %%i, 1, fltp | ||
| 490 | MIX_3_8_TO_1_2_FLT %%i, 2, fltp | ||
| 491 | INIT_XMM avx | ||
| 492 | MIX_3_8_TO_1_2_FLT %%i, 1, s16p | ||
| 493 | MIX_3_8_TO_1_2_FLT %%i, 2, s16p | ||
| 494 | %endif | ||
| 495 | %if HAVE_FMA4_EXTERNAL | ||
| 496 | %if ARCH_X86_64 || %%i < 6 | ||
| 497 | INIT_YMM fma4 | ||
| 498 | %else | ||
| 499 | INIT_XMM fma4 | ||
| 500 | %endif | ||
| 501 | MIX_3_8_TO_1_2_FLT %%i, 1, fltp | ||
| 502 | MIX_3_8_TO_1_2_FLT %%i, 2, fltp | ||
| 503 | INIT_XMM fma4 | ||
| 504 | MIX_3_8_TO_1_2_FLT %%i, 1, s16p | ||
| 505 | MIX_3_8_TO_1_2_FLT %%i, 2, s16p | ||
| 506 | %endif | ||
| 507 | %assign %%i %%i+1 | ||
| 508 | %endrep | ||
| 509 | %endmacro | ||
| 510 | |||
| 511 | MIX_3_8_TO_1_2_FLT_FUNCS | ||
| @@ -1,215 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | #include "libavutil/cpu.h" | ||
| 23 | #include "libavutil/x86/cpu.h" | ||
| 24 | #include "libavresample/audio_mix.h" | ||
| 25 | |||
| 26 | void ff_mix_2_to_1_fltp_flt_sse(float **src, float **matrix, int len, | ||
| 27 | int out_ch, int in_ch); | ||
| 28 | void ff_mix_2_to_1_fltp_flt_avx(float **src, float **matrix, int len, | ||
| 29 | int out_ch, int in_ch); | ||
| 30 | |||
| 31 | void ff_mix_2_to_1_s16p_flt_sse2(int16_t **src, float **matrix, int len, | ||
| 32 | int out_ch, int in_ch); | ||
| 33 | void ff_mix_2_to_1_s16p_flt_sse4(int16_t **src, float **matrix, int len, | ||
| 34 | int out_ch, int in_ch); | ||
| 35 | |||
| 36 | void ff_mix_2_to_1_s16p_q8_sse2(int16_t **src, int16_t **matrix, | ||
| 37 | int len, int out_ch, int in_ch); | ||
| 38 | |||
| 39 | void ff_mix_1_to_2_fltp_flt_sse(float **src, float **matrix, int len, | ||
| 40 | int out_ch, int in_ch); | ||
| 41 | void ff_mix_1_to_2_fltp_flt_avx(float **src, float **matrix, int len, | ||
| 42 | int out_ch, int in_ch); | ||
| 43 | |||
| 44 | void ff_mix_1_to_2_s16p_flt_sse2(int16_t **src, float **matrix, int len, | ||
| 45 | int out_ch, int in_ch); | ||
| 46 | void ff_mix_1_to_2_s16p_flt_sse4(int16_t **src, float **matrix, int len, | ||
| 47 | int out_ch, int in_ch); | ||
| 48 | void ff_mix_1_to_2_s16p_flt_avx (int16_t **src, float **matrix, int len, | ||
| 49 | int out_ch, int in_ch); | ||
| 50 | |||
| 51 | #define DEFINE_MIX_3_8_TO_1_2(chan) \ | ||
| 52 | void ff_mix_ ## chan ## _to_1_fltp_flt_sse(float **src, \ | ||
| 53 | float **matrix, int len, \ | ||
| 54 | int out_ch, int in_ch); \ | ||
| 55 | void ff_mix_ ## chan ## _to_2_fltp_flt_sse(float **src, \ | ||
| 56 | float **matrix, int len, \ | ||
| 57 | int out_ch, int in_ch); \ | ||
| 58 | \ | ||
| 59 | void ff_mix_ ## chan ## _to_1_s16p_flt_sse2(int16_t **src, \ | ||
| 60 | float **matrix, int len, \ | ||
| 61 | int out_ch, int in_ch); \ | ||
| 62 | void ff_mix_ ## chan ## _to_2_s16p_flt_sse2(int16_t **src, \ | ||
| 63 | float **matrix, int len, \ | ||
| 64 | int out_ch, int in_ch); \ | ||
| 65 | \ | ||
| 66 | void ff_mix_ ## chan ## _to_1_s16p_flt_sse4(int16_t **src, \ | ||
| 67 | float **matrix, int len, \ | ||
| 68 | int out_ch, int in_ch); \ | ||
| 69 | void ff_mix_ ## chan ## _to_2_s16p_flt_sse4(int16_t **src, \ | ||
| 70 | float **matrix, int len, \ | ||
| 71 | int out_ch, int in_ch); \ | ||
| 72 | \ | ||
| 73 | void ff_mix_ ## chan ## _to_1_fltp_flt_avx(float **src, \ | ||
| 74 | float **matrix, int len, \ | ||
| 75 | int out_ch, int in_ch); \ | ||
| 76 | void ff_mix_ ## chan ## _to_2_fltp_flt_avx(float **src, \ | ||
| 77 | float **matrix, int len, \ | ||
| 78 | int out_ch, int in_ch); \ | ||
| 79 | \ | ||
| 80 | void ff_mix_ ## chan ## _to_1_s16p_flt_avx(int16_t **src, \ | ||
| 81 | float **matrix, int len, \ | ||
| 82 | int out_ch, int in_ch); \ | ||
| 83 | void ff_mix_ ## chan ## _to_2_s16p_flt_avx(int16_t **src, \ | ||
| 84 | float **matrix, int len, \ | ||
| 85 | int out_ch, int in_ch); \ | ||
| 86 | \ | ||
| 87 | void ff_mix_ ## chan ## _to_1_fltp_flt_fma4(float **src, \ | ||
| 88 | float **matrix, int len, \ | ||
| 89 | int out_ch, int in_ch); \ | ||
| 90 | void ff_mix_ ## chan ## _to_2_fltp_flt_fma4(float **src, \ | ||
| 91 | float **matrix, int len, \ | ||
| 92 | int out_ch, int in_ch); \ | ||
| 93 | \ | ||
| 94 | void ff_mix_ ## chan ## _to_1_s16p_flt_fma4(int16_t **src, \ | ||
| 95 | float **matrix, int len, \ | ||
| 96 | int out_ch, int in_ch); \ | ||
| 97 | void ff_mix_ ## chan ## _to_2_s16p_flt_fma4(int16_t **src, \ | ||
| 98 | float **matrix, int len, \ | ||
| 99 | int out_ch, int in_ch); | ||
| 100 | |||
| 101 | DEFINE_MIX_3_8_TO_1_2(3) | ||
| 102 | DEFINE_MIX_3_8_TO_1_2(4) | ||
| 103 | DEFINE_MIX_3_8_TO_1_2(5) | ||
| 104 | DEFINE_MIX_3_8_TO_1_2(6) | ||
| 105 | DEFINE_MIX_3_8_TO_1_2(7) | ||
| 106 | DEFINE_MIX_3_8_TO_1_2(8) | ||
| 107 | |||
| 108 | #define SET_MIX_3_8_TO_1_2(chan) \ | ||
| 109 | if (EXTERNAL_SSE(cpu_flags)) { \ | ||
| 110 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 111 | chan, 1, 16, 4, "SSE", \ | ||
| 112 | ff_mix_ ## chan ## _to_1_fltp_flt_sse); \ | ||
| 113 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 114 | chan, 2, 16, 4, "SSE", \ | ||
| 115 | ff_mix_## chan ##_to_2_fltp_flt_sse); \ | ||
| 116 | } \ | ||
| 117 | if (EXTERNAL_SSE2(cpu_flags)) { \ | ||
| 118 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 119 | chan, 1, 16, 8, "SSE2", \ | ||
| 120 | ff_mix_ ## chan ## _to_1_s16p_flt_sse2); \ | ||
| 121 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 122 | chan, 2, 16, 8, "SSE2", \ | ||
| 123 | ff_mix_ ## chan ## _to_2_s16p_flt_sse2); \ | ||
| 124 | } \ | ||
| 125 | if (EXTERNAL_SSE4(cpu_flags)) { \ | ||
| 126 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 127 | chan, 1, 16, 8, "SSE4", \ | ||
| 128 | ff_mix_ ## chan ## _to_1_s16p_flt_sse4); \ | ||
| 129 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 130 | chan, 2, 16, 8, "SSE4", \ | ||
| 131 | ff_mix_ ## chan ## _to_2_s16p_flt_sse4); \ | ||
| 132 | } \ | ||
| 133 | if (EXTERNAL_AVX(cpu_flags)) { \ | ||
| 134 | int ptr_align = 32; \ | ||
| 135 | int smp_align = 8; \ | ||
| 136 | if (ARCH_X86_32 || chan >= 6) { \ | ||
| 137 | ptr_align = 16; \ | ||
| 138 | smp_align = 4; \ | ||
| 139 | } \ | ||
| 140 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 141 | chan, 1, ptr_align, smp_align, "AVX", \ | ||
| 142 | ff_mix_ ## chan ## _to_1_fltp_flt_avx); \ | ||
| 143 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 144 | chan, 2, ptr_align, smp_align, "AVX", \ | ||
| 145 | ff_mix_ ## chan ## _to_2_fltp_flt_avx); \ | ||
| 146 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 147 | chan, 1, 16, 8, "AVX", \ | ||
| 148 | ff_mix_ ## chan ## _to_1_s16p_flt_avx); \ | ||
| 149 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 150 | chan, 2, 16, 8, "AVX", \ | ||
| 151 | ff_mix_ ## chan ## _to_2_s16p_flt_avx); \ | ||
| 152 | } \ | ||
| 153 | if (EXTERNAL_FMA4(cpu_flags)) { \ | ||
| 154 | int ptr_align = 32; \ | ||
| 155 | int smp_align = 8; \ | ||
| 156 | if (ARCH_X86_32 || chan >= 6) { \ | ||
| 157 | ptr_align = 16; \ | ||
| 158 | smp_align = 4; \ | ||
| 159 | } \ | ||
| 160 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 161 | chan, 1, ptr_align, smp_align, "FMA4", \ | ||
| 162 | ff_mix_ ## chan ## _to_1_fltp_flt_fma4); \ | ||
| 163 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 164 | chan, 2, ptr_align, smp_align, "FMA4", \ | ||
| 165 | ff_mix_ ## chan ## _to_2_fltp_flt_fma4); \ | ||
| 166 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 167 | chan, 1, 16, 8, "FMA4", \ | ||
| 168 | ff_mix_ ## chan ## _to_1_s16p_flt_fma4); \ | ||
| 169 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT,\ | ||
| 170 | chan, 2, 16, 8, "FMA4", \ | ||
| 171 | ff_mix_ ## chan ## _to_2_s16p_flt_fma4); \ | ||
| 172 | } | ||
| 173 | |||
| 174 | av_cold void ff_audio_mix_init_x86(AudioMix *am) | ||
| 175 | { | ||
| 176 | int cpu_flags = av_get_cpu_flags(); | ||
| 177 | |||
| 178 | if (EXTERNAL_SSE(cpu_flags)) { | ||
| 179 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||
| 180 | 2, 1, 16, 8, "SSE", ff_mix_2_to_1_fltp_flt_sse); | ||
| 181 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||
| 182 | 1, 2, 16, 4, "SSE", ff_mix_1_to_2_fltp_flt_sse); | ||
| 183 | } | ||
| 184 | if (EXTERNAL_SSE2(cpu_flags)) { | ||
| 185 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | ||
| 186 | 2, 1, 16, 8, "SSE2", ff_mix_2_to_1_s16p_flt_sse2); | ||
| 187 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_Q8, | ||
| 188 | 2, 1, 16, 8, "SSE2", ff_mix_2_to_1_s16p_q8_sse2); | ||
| 189 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | ||
| 190 | 1, 2, 16, 8, "SSE2", ff_mix_1_to_2_s16p_flt_sse2); | ||
| 191 | } | ||
| 192 | if (EXTERNAL_SSE4(cpu_flags)) { | ||
| 193 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | ||
| 194 | 2, 1, 16, 8, "SSE4", ff_mix_2_to_1_s16p_flt_sse4); | ||
| 195 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | ||
| 196 | 1, 2, 16, 8, "SSE4", ff_mix_1_to_2_s16p_flt_sse4); | ||
| 197 | } | ||
| 198 | if (EXTERNAL_AVX_FAST(cpu_flags)) { | ||
| 199 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||
| 200 | 2, 1, 32, 16, "AVX", ff_mix_2_to_1_fltp_flt_avx); | ||
| 201 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_FLTP, AV_MIX_COEFF_TYPE_FLT, | ||
| 202 | 1, 2, 32, 8, "AVX", ff_mix_1_to_2_fltp_flt_avx); | ||
| 203 | } | ||
| 204 | if (EXTERNAL_AVX(cpu_flags)) { | ||
| 205 | ff_audio_mix_set_func(am, AV_SAMPLE_FMT_S16P, AV_MIX_COEFF_TYPE_FLT, | ||
| 206 | 1, 2, 16, 8, "AVX", ff_mix_1_to_2_s16p_flt_avx); | ||
| 207 | } | ||
| 208 | |||
| 209 | SET_MIX_3_8_TO_1_2(3) | ||
| 210 | SET_MIX_3_8_TO_1_2(4) | ||
| 211 | SET_MIX_3_8_TO_1_2(5) | ||
| 212 | SET_MIX_3_8_TO_1_2(6) | ||
| 213 | SET_MIX_3_8_TO_1_2(7) | ||
| 214 | SET_MIX_3_8_TO_1_2(8) | ||
| 215 | } | ||
| @@ -1,117 +0,0 @@ | |||
| 1 | ;****************************************************************************** | ||
| 2 | ;* x86 optimized dithering format conversion | ||
| 3 | ;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 4 | ;* | ||
| 5 | ;* This file is part of FFmpeg. | ||
| 6 | ;* | ||
| 7 | ;* FFmpeg is free software; you can redistribute it and/or | ||
| 8 | ;* modify it under the terms of the GNU Lesser General Public | ||
| 9 | ;* License as published by the Free Software Foundation; either | ||
| 10 | ;* version 2.1 of the License, or (at your option) any later version. | ||
| 11 | ;* | ||
| 12 | ;* FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | ;* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | ;* Lesser General Public License for more details. | ||
| 16 | ;* | ||
| 17 | ;* You should have received a copy of the GNU Lesser General Public | ||
| 18 | ;* License along with FFmpeg; if not, write to the Free Software | ||
| 19 | ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | ;****************************************************************************** | ||
| 21 | |||
| 22 | %include "libavutil/x86/x86util.asm" | ||
| 23 | |||
| 24 | SECTION_RODATA 32 | ||
| 25 | |||
| 26 | ; 1.0f / (2.0f * INT32_MAX) | ||
| 27 | pf_dither_scale: times 8 dd 2.32830643762e-10 | ||
| 28 | |||
| 29 | pf_s16_scale: times 4 dd 32753.0 | ||
| 30 | |||
| 31 | SECTION .text | ||
| 32 | |||
| 33 | ;------------------------------------------------------------------------------ | ||
| 34 | ; void ff_quantize(int16_t *dst, float *src, float *dither, int len); | ||
| 35 | ;------------------------------------------------------------------------------ | ||
| 36 | |||
| 37 | INIT_XMM sse2 | ||
| 38 | cglobal quantize, 4,4,3, dst, src, dither, len | ||
| 39 | lea lenq, [2*lend] | ||
| 40 | add dstq, lenq | ||
| 41 | lea srcq, [srcq+2*lenq] | ||
| 42 | lea ditherq, [ditherq+2*lenq] | ||
| 43 | neg lenq | ||
| 44 | mova m2, [pf_s16_scale] | ||
| 45 | .loop: | ||
| 46 | mulps m0, m2, [srcq+2*lenq] | ||
| 47 | mulps m1, m2, [srcq+2*lenq+mmsize] | ||
| 48 | addps m0, [ditherq+2*lenq] | ||
| 49 | addps m1, [ditherq+2*lenq+mmsize] | ||
| 50 | cvtps2dq m0, m0 | ||
| 51 | cvtps2dq m1, m1 | ||
| 52 | packssdw m0, m1 | ||
| 53 | mova [dstq+lenq], m0 | ||
| 54 | add lenq, mmsize | ||
| 55 | jl .loop | ||
| 56 | REP_RET | ||
| 57 | |||
| 58 | ;------------------------------------------------------------------------------ | ||
| 59 | ; void ff_dither_int_to_float_rectangular(float *dst, int *src, int len) | ||
| 60 | ;------------------------------------------------------------------------------ | ||
| 61 | |||
| 62 | %macro DITHER_INT_TO_FLOAT_RECTANGULAR 0 | ||
| 63 | cglobal dither_int_to_float_rectangular, 3,3,3, dst, src, len | ||
| 64 | lea lenq, [4*lend] | ||
| 65 | add srcq, lenq | ||
| 66 | add dstq, lenq | ||
| 67 | neg lenq | ||
| 68 | mova m0, [pf_dither_scale] | ||
| 69 | .loop: | ||
| 70 | cvtdq2ps m1, [srcq+lenq] | ||
| 71 | cvtdq2ps m2, [srcq+lenq+mmsize] | ||
| 72 | mulps m1, m1, m0 | ||
| 73 | mulps m2, m2, m0 | ||
| 74 | mova [dstq+lenq], m1 | ||
| 75 | mova [dstq+lenq+mmsize], m2 | ||
| 76 | add lenq, 2*mmsize | ||
| 77 | jl .loop | ||
| 78 | REP_RET | ||
| 79 | %endmacro | ||
| 80 | |||
| 81 | INIT_XMM sse2 | ||
| 82 | DITHER_INT_TO_FLOAT_RECTANGULAR | ||
| 83 | INIT_YMM avx | ||
| 84 | DITHER_INT_TO_FLOAT_RECTANGULAR | ||
| 85 | |||
| 86 | ;------------------------------------------------------------------------------ | ||
| 87 | ; void ff_dither_int_to_float_triangular(float *dst, int *src0, int len) | ||
| 88 | ;------------------------------------------------------------------------------ | ||
| 89 | |||
| 90 | %macro DITHER_INT_TO_FLOAT_TRIANGULAR 0 | ||
| 91 | cglobal dither_int_to_float_triangular, 3,4,5, dst, src0, len, src1 | ||
| 92 | lea lenq, [4*lend] | ||
| 93 | lea src1q, [src0q+2*lenq] | ||
| 94 | add src0q, lenq | ||
| 95 | add dstq, lenq | ||
| 96 | neg lenq | ||
| 97 | mova m0, [pf_dither_scale] | ||
| 98 | .loop: | ||
| 99 | cvtdq2ps m1, [src0q+lenq] | ||
| 100 | cvtdq2ps m2, [src0q+lenq+mmsize] | ||
| 101 | cvtdq2ps m3, [src1q+lenq] | ||
| 102 | cvtdq2ps m4, [src1q+lenq+mmsize] | ||
| 103 | addps m1, m1, m3 | ||
| 104 | addps m2, m2, m4 | ||
| 105 | mulps m1, m1, m0 | ||
| 106 | mulps m2, m2, m0 | ||
| 107 | mova [dstq+lenq], m1 | ||
| 108 | mova [dstq+lenq+mmsize], m2 | ||
| 109 | add lenq, 2*mmsize | ||
| 110 | jl .loop | ||
| 111 | REP_RET | ||
| 112 | %endmacro | ||
| 113 | |||
| 114 | INIT_XMM sse2 | ||
| 115 | DITHER_INT_TO_FLOAT_TRIANGULAR | ||
| 116 | INIT_YMM avx | ||
| 117 | DITHER_INT_TO_FLOAT_TRIANGULAR | ||
| @@ -1,60 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "config.h" | ||
| 22 | #include "libavutil/cpu.h" | ||
| 23 | #include "libavutil/x86/cpu.h" | ||
| 24 | #include "libavresample/dither.h" | ||
| 25 | |||
| 26 | void ff_quantize_sse2(int16_t *dst, const float *src, float *dither, int len); | ||
| 27 | |||
| 28 | void ff_dither_int_to_float_rectangular_sse2(float *dst, int *src, int len); | ||
| 29 | void ff_dither_int_to_float_rectangular_avx(float *dst, int *src, int len); | ||
| 30 | |||
| 31 | void ff_dither_int_to_float_triangular_sse2(float *dst, int *src0, int len); | ||
| 32 | void ff_dither_int_to_float_triangular_avx(float *dst, int *src0, int len); | ||
| 33 | |||
| 34 | av_cold void ff_dither_init_x86(DitherDSPContext *ddsp, | ||
| 35 | enum AVResampleDitherMethod method) | ||
| 36 | { | ||
| 37 | int cpu_flags = av_get_cpu_flags(); | ||
| 38 | |||
| 39 | if (EXTERNAL_SSE2(cpu_flags)) { | ||
| 40 | ddsp->quantize = ff_quantize_sse2; | ||
| 41 | ddsp->ptr_align = 16; | ||
| 42 | ddsp->samples_align = 8; | ||
| 43 | } | ||
| 44 | |||
| 45 | if (method == AV_RESAMPLE_DITHER_RECTANGULAR) { | ||
| 46 | if (EXTERNAL_SSE2(cpu_flags)) { | ||
| 47 | ddsp->dither_int_to_float = ff_dither_int_to_float_rectangular_sse2; | ||
| 48 | } | ||
| 49 | if (EXTERNAL_AVX_FAST(cpu_flags)) { | ||
| 50 | ddsp->dither_int_to_float = ff_dither_int_to_float_rectangular_avx; | ||
| 51 | } | ||
| 52 | } else { | ||
| 53 | if (EXTERNAL_SSE2(cpu_flags)) { | ||
| 54 | ddsp->dither_int_to_float = ff_dither_int_to_float_triangular_sse2; | ||
| 55 | } | ||
| 56 | if (EXTERNAL_AVX_FAST(cpu_flags)) { | ||
| 57 | ddsp->dither_int_to_float = ff_dither_int_to_float_triangular_avx; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| @@ -1,41 +0,0 @@ | |||
| 1 | ;****************************************************************************** | ||
| 2 | ;* x86 utility macros for libavresample | ||
| 3 | ;* Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com> | ||
| 4 | ;* | ||
| 5 | ;* This file is part of FFmpeg. | ||
| 6 | ;* | ||
| 7 | ;* FFmpeg is free software; you can redistribute it and/or | ||
| 8 | ;* modify it under the terms of the GNU Lesser General Public | ||
| 9 | ;* License as published by the Free Software Foundation; either | ||
| 10 | ;* version 2.1 of the License, or (at your option) any later version. | ||
| 11 | ;* | ||
| 12 | ;* FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | ;* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | ;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | ;* Lesser General Public License for more details. | ||
| 16 | ;* | ||
| 17 | ;* You should have received a copy of the GNU Lesser General Public | ||
| 18 | ;* License along with FFmpeg; if not, write to the Free Software | ||
| 19 | ;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | ;****************************************************************************** | ||
| 21 | |||
| 22 | %macro S16_TO_S32_SX 2 ; src/low dst, high dst | ||
| 23 | %if cpuflag(sse4) | ||
| 24 | pmovsxwd m%2, m%1 | ||
| 25 | psrldq m%1, 8 | ||
| 26 | pmovsxwd m%1, m%1 | ||
| 27 | SWAP %1, %2 | ||
| 28 | %else | ||
| 29 | mova m%2, m%1 | ||
| 30 | punpckhwd m%2, m%2 | ||
| 31 | punpcklwd m%1, m%1 | ||
| 32 | psrad m%2, 16 | ||
| 33 | psrad m%1, 16 | ||
| 34 | %endif | ||
| 35 | %endmacro | ||
| 36 | |||
| 37 | %macro DEINT2_PS 3 ; src0/even dst, src1/odd dst, temp | ||
| 38 | shufps m%3, m%1, m%2, q3131 | ||
| 39 | shufps m%1, m%2, q2020 | ||
| 40 | SWAP %2,%3 | ||
| 41 | %endmacro | ||
| @@ -1,31 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * check XMM registers for clobbers on Win64 | ||
| 3 | * Copyright (c) 2013 Martin Storsjo | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include "libavresample/avresample.h" | ||
| 23 | #include "libavutil/x86/w64xmmtest.h" | ||
| 24 | |||
| 25 | wrap(avresample_convert(AVAudioResampleContext *avr, uint8_t **output, | ||
| 26 | int out_plane_size, int out_samples, uint8_t **input, | ||
| 27 | int in_plane_size, int in_samples)) | ||
| 28 | { | ||
| 29 | testxmmclobbers(avresample_convert, avr, output, out_plane_size, | ||
| 30 | out_samples, input, in_plane_size, in_samples); | ||
| 31 | } | ||
| @@ -157,7 +157,6 @@ include $(SRC_PATH)/tests/fate/indeo.mak · 156 unmodified lines | |||
| 157 | include $(SRC_PATH)/tests/fate/libavcodec.mak | 157 | include $(SRC_PATH)/tests/fate/libavcodec.mak |
| 158 | include $(SRC_PATH)/tests/fate/libavdevice.mak | 158 | include $(SRC_PATH)/tests/fate/libavdevice.mak |
| 159 | include $(SRC_PATH)/tests/fate/libavformat.mak | 159 | include $(SRC_PATH)/tests/fate/libavformat.mak |
| 160 | include $(SRC_PATH)/tests/fate/libavresample.mak | ||
| 161 | include $(SRC_PATH)/tests/fate/libavutil.mak | 160 | include $(SRC_PATH)/tests/fate/libavutil.mak |
| 162 | include $(SRC_PATH)/tests/fate/libswresample.mak | 161 | include $(SRC_PATH)/tests/fate/libswresample.mak |
| 163 | include $(SRC_PATH)/tests/fate/libswscale.mak | 162 | include $(SRC_PATH)/tests/fate/libswscale.mak |
| @@ -48,7 +48,6 @@ configure()( · 47 unmodified lines | |||
| 48 | --samples="${samples}" \ | 48 | --samples="${samples}" \ |
| 49 | --enable-gpl \ | 49 | --enable-gpl \ |
| 50 | --enable-memory-poisoning \ | 50 | --enable-memory-poisoning \ |
| 51 | --enable-avresample \ | ||
| 52 | ${ignore_tests:+--ignore-tests="$ignore_tests"} \ | 51 | ${ignore_tests:+--ignore-tests="$ignore_tests"} \ |
| 53 | ${arch:+--arch=$arch} \ | 52 | ${arch:+--arch=$arch} \ |
| 54 | ${cpu:+--cpu="$cpu"} \ | 53 | ${cpu:+--cpu="$cpu"} \ |
| @@ -1,68 +0,0 @@ | |||
| 1 | CROSS_TEST = $(foreach I,$(1), \ | ||
| 2 | $(foreach J,$(1), \ | ||
| 3 | $(if $(filter-out $(I),$(J)), \ | ||
| 4 | $(eval $(call $(2),$(I),$(J),$(3),$(4),$(5))), \ | ||
| 5 | ))) | ||
| 6 | |||
| 7 | MIX_CHANNELS = 1 2 3 4 5 6 7 8 | ||
| 8 | |||
| 9 | define MIX | ||
| 10 | FATE_LAVR_MIX += fate-lavr-mix-$(3)-$(1)-$(2) | ||
| 11 | fate-lavr-mix-$(3)-$(1)-$(2): tests/data/asynth-44100-$(1).wav | ||
| 12 | fate-lavr-mix-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-44100-$(1).wav -ac $(2) -mix_coeff_type $(3) -internal_sample_fmt $(4) -f s16le -af atrim=end_sample=1024 - | ||
| 13 | fate-lavr-mix-$(3)-$(1)-$(2): CMP = oneoff | ||
| 14 | fate-lavr-mix-$(3)-$(1)-$(2): REF = $(SAMPLES)/lavr/lavr-mix-$(3)-$(1)-$(2) | ||
| 15 | endef | ||
| 16 | |||
| 17 | $(call CROSS_TEST,$(MIX_CHANNELS),MIX,q8,s16p) | ||
| 18 | $(call CROSS_TEST,$(MIX_CHANNELS),MIX,q15,s16p) | ||
| 19 | $(call CROSS_TEST,$(MIX_CHANNELS),MIX,flt,fltp) | ||
| 20 | |||
| 21 | # test output zeroing with skipped corresponding input | ||
| 22 | FATE_LAVR_MIX-$(call FILTERDEMDECENCMUX, CHANNELMAP RESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-lavr-mix-output-zero | ||
| 23 | fate-lavr-mix-output-zero: tests/data/filtergraphs/lavr_mix_output_zero tests/data/asynth-44100-4.wav | ||
| 24 | fate-lavr-mix-output-zero: CMP = oneoff | ||
| 25 | fate-lavr-mix-output-zero: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-44100-4.wav -filter_script $(TARGET_PATH)/tests/data/filtergraphs/lavr_mix_output_zero -f s16le - | ||
| 26 | fate-lavr-mix-output-zero: REF = $(SAMPLES)/lavr/lavr-mix-output-zero | ||
| 27 | |||
| 28 | FATE_LAVR_MIX-$(call FILTERDEMDECENCMUX, RESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_LAVR_MIX) | ||
| 29 | fate-lavr-mix: $(FATE_LAVR_MIX-yes) | ||
| 30 | #FATE_LAVR += $(FATE_LAVR_MIX-yes) | ||
| 31 | |||
| 32 | SAMPLERATES = 2626 8000 44100 48000 96000 | ||
| 33 | |||
| 34 | define RESAMPLE | ||
| 35 | FATE_LAVR_RESAMPLE += fate-lavr-resample-$(3)-$(1)-$(2) | ||
| 36 | fate-lavr-resample-$(3)-$(1)-$(2): tests/data/asynth-$(1)-1.wav | ||
| 37 | fate-lavr-resample-$(3)-$(1)-$(2): CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-$(1)-1.wav -ar $(2) -internal_sample_fmt $(3) -f $(4) -af atrim=end_sample=10240 - | ||
| 38 | fate-lavr-resample-$(3)-$(1)-$(2): CMP = oneoff | ||
| 39 | fate-lavr-resample-$(3)-$(1)-$(2): CMP_UNIT = $(5) | ||
| 40 | fate-lavr-resample-$(3)-$(1)-$(2): FUZZ = 6 | ||
| 41 | fate-lavr-resample-$(3)-$(1)-$(2): REF = $(SAMPLES)/lavr/lavr-resample-$(3)-$(1)-$(2)-v3 | ||
| 42 | endef | ||
| 43 | |||
| 44 | $(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,s16p,s16le,s16) | ||
| 45 | $(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,s32p,s32le,s16) | ||
| 46 | $(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,fltp,f32le,f32) | ||
| 47 | $(call CROSS_TEST,$(SAMPLERATES),RESAMPLE,dblp,f64le,f64) | ||
| 48 | |||
| 49 | FATE_LAVR_RESAMPLE += fate-lavr-resample-linear | ||
| 50 | fate-lavr-resample-linear: tests/data/asynth-44100-1.wav | ||
| 51 | fate-lavr-resample-linear: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-44100-1.wav -ar 48000 -filter_size 32 -linear_interp 1 -f s16le -af atrim=end_sample=10240 - | ||
| 52 | fate-lavr-resample-linear: CMP = oneoff | ||
| 53 | fate-lavr-resample-linear: CMP_UNIT = s16 | ||
| 54 | fate-lavr-resample-linear: REF = $(SAMPLES)/lavr/lavr-resample-linear | ||
| 55 | |||
| 56 | FATE_LAVR_RESAMPLE += fate-lavr-resample-nearest | ||
| 57 | fate-lavr-resample-nearest: tests/data/asynth-48000-1.wav | ||
| 58 | fate-lavr-resample-nearest: CMD = ffmpeg -i $(TARGET_PATH)/tests/data/asynth-48000-1.wav -ar 44100 -filter_size 0 -phase_shift 0 -f s16le -af atrim=end_sample=10240 - | ||
| 59 | fate-lavr-resample-nearest: CMP = oneoff | ||
| 60 | fate-lavr-resample-nearest: CMP_UNIT = s16 | ||
| 61 | fate-lavr-resample-nearest: REF = $(SAMPLES)/lavr/lavr-resample-nearest | ||
| 62 | |||
| 63 | FATE_LAVR_RESAMPLE-$(call FILTERDEMDECENCMUX, RESAMPLE, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_LAVR_RESAMPLE) | ||
| 64 | fate-lavr-resample: $(FATE_LAVR_RESAMPLE-yes) | ||
| 65 | #FATE_LAVR += $(FATE_LAVR_RESAMPLE-yes) | ||
| 66 | |||
| 67 | FATE_SAMPLES_AVCONV += $(FATE_LAVR) | ||
| 68 | fate-lavr: $(FATE_LAVR) | ||
| @@ -43,7 +43,6 @@ EOF · 42 unmodified lines | |||
| 43 | # gen-rc libavdevice "FFmpeg device handling library" | 43 | # gen-rc libavdevice "FFmpeg device handling library" |
| 44 | # gen-rc libavfilter "FFmpeg audio/video filtering library" | 44 | # gen-rc libavfilter "FFmpeg audio/video filtering library" |
| 45 | # gen-rc libpostproc "FFmpeg postprocessing library" | 45 | # gen-rc libpostproc "FFmpeg postprocessing library" |
| 46 | # gen-rc libavresample "Libav audio resampling library" | ||
| 47 | # gen-rc libswscale "FFmpeg image rescaling library" | 46 | # gen-rc libswscale "FFmpeg image rescaling library" |
| 48 | # gen-rc libswresample "FFmpeg audio resampling library" | 47 | # gen-rc libswresample "FFmpeg audio resampling library" |
| 49 | 48 | ||
| @@ -30,7 +30,7 @@ · 29 unmodified lines | |||
| 30 | * build the fuzz target. | 30 | * build the fuzz target. |
| 31 | Choose the value of FFMPEG_CODEC (e.g. AV_CODEC_ID_DVD_SUBTITLE) and | 31 | Choose the value of FFMPEG_CODEC (e.g. AV_CODEC_ID_DVD_SUBTITLE) and |
| 32 | choose one of FUZZ_FFMPEG_VIDEO, FUZZ_FFMPEG_AUDIO, FUZZ_FFMPEG_SUBTITLE. | 32 | choose one of FUZZ_FFMPEG_VIDEO, FUZZ_FFMPEG_AUDIO, FUZZ_FFMPEG_SUBTITLE. |
| 33 | clang -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp tools/target_dec_fuzzer.c -o target_dec_fuzzer -I. -DFFMPEG_CODEC=AV_CODEC_ID_MPEG1VIDEO -DFUZZ_FFMPEG_VIDEO ../../libfuzzer/libFuzzer.a -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -ldl -lxcb -lxcb-shm -lxcb -lxcb-xfixes -lxcb -lxcb-shape -lxcb -lX11 -lasound -lm -lbz2 -lz -pthread | 33 | clang -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp tools/target_dec_fuzzer.c -o target_dec_fuzzer -I. -DFFMPEG_CODEC=AV_CODEC_ID_MPEG1VIDEO -DFUZZ_FFMPEG_VIDEO ../../libfuzzer/libFuzzer.a -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -ldl -lxcb -lxcb-shm -lxcb -lxcb-xfixes -lxcb -lxcb-shape -lxcb -lX11 -lasound -lm -lbz2 -lz -pthread |
| 34 | * create a corpus directory and put some samples there (empty dir is ok too): | 34 | * create a corpus directory and put some samples there (empty dir is ok too): |
| 35 | mkdir CORPUS && cp some-files CORPUS | 35 | mkdir CORPUS && cp some-files CORPUS |
| 36 | 36 | ||