├── .appveyor.yml ├── .github └── workflows │ └── action.yml ├── .gitignore ├── .gitlab-ci.yml ├── .travis.yml ├── AUTHORS ├── COPYING ├── Makefile.am ├── README.md ├── autogen.sh ├── configure.ac ├── doc ├── Doxyfile.in ├── Makefile └── opus_logo.svg ├── examples └── opusenc_example.c ├── include └── opusenc.h ├── libopusenc-uninstalled.pc.in ├── libopusenc.pc.in ├── m4 └── attributes.m4 ├── src ├── arch.h ├── ogg_packer.c ├── ogg_packer.h ├── opus_header.c ├── opus_header.h ├── opusenc.c ├── picture.c ├── picture.h ├── resample.c ├── resample_sse.h ├── speex_resampler.h ├── unicode_support.c └── unicode_support.h ├── update_version └── win32 ├── .gitignore ├── VS2015 ├── common.props ├── opusenc.sln ├── opusenc.vcxproj └── opusenc.vcxproj.filters ├── config.h └── genversion.bat /.appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2015 2 | configuration: 3 | - Debug 4 | - DebugDLL 5 | - Release 6 | - ReleaseDLL 7 | 8 | platform: 9 | - Win32 10 | - x64 11 | 12 | environment: 13 | opus_url: https://ci.appveyor.com/api/projects/$(APPVEYOR_ACCOUNT_NAME)/opus/artifacts/opus.zip 14 | 15 | install: 16 | - cd %APPVEYOR_BUILD_FOLDER% 17 | - 'curl -LOG --data-urlencode "job=Configuration: %CONFIGURATION%; Platform: %PLATFORM%" %OPUS_URL%' 18 | - 7z x opus.zip -oopus-artifacts 19 | - move /Y opus-artifacts ..\opus 20 | 21 | build: 22 | project: win32\VS2015\opusenc.sln 23 | parallel: true 24 | verbosity: minimal 25 | 26 | after_build: 27 | - 7z a libopusenc.zip win32\VS2015\%PLATFORM%\%CONFIGURATION%\opusenc.??? include\ 28 | 29 | artifacts: 30 | - path: libopusenc.zip 31 | -------------------------------------------------------------------------------- /.github/workflows/action.yml: -------------------------------------------------------------------------------- 1 | name: GitHub CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: '0 0 1 * *' 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | name: 14 | [ 15 | ubuntu-latest-autotools, 16 | macos-latest-autotools, 17 | ] 18 | include: 19 | 20 | - name: ubuntu-latest-autotools 21 | os: ubuntu-latest 22 | build-system: autotools 23 | 24 | - name: macos-latest-autotools 25 | os: macos-latest 26 | build-system: autotools 27 | 28 | runs-on: ${{ matrix.os }} 29 | 30 | steps: 31 | - uses: actions/checkout@v2 32 | 33 | - name: Install Linux dependencies 34 | if: startsWith(matrix.os,'ubuntu') 35 | run: | 36 | sudo apt-get update 37 | sudo apt-get install -y libopus-dev zip doxygen graphviz 38 | 39 | - name: Install MacOS dependencies 40 | if: startsWith(matrix.os,'macos') 41 | run: | 42 | brew install pkg-config automake opus 43 | 44 | - name: Build with Autotools 45 | if: startsWith(matrix.build-system,'autotools') 46 | run: | 47 | ./autogen.sh 48 | ./configure 49 | make 50 | make check 51 | 52 | - name: distcheck with Autotools 53 | if: startsWith(matrix.build-system,'autotools') 54 | run: | 55 | make distcheck 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .s[a-w][a-z] 2 | .*.s[a-w][a-z] 3 | Session.vim 4 | *~ 5 | 6 | *.exe 7 | *.la 8 | *.lo 9 | *.o 10 | *.pc 11 | 12 | .deps 13 | .dirstamp 14 | .libs 15 | 16 | /package_version 17 | /doc/Doxyfile 18 | 19 | # http://www.gnu.org/software/automake 20 | 21 | /Makefile 22 | /Makefile.in 23 | /ar-lib 24 | /mdate-sh 25 | /py-compile 26 | /test-driver 27 | /ylwrap 28 | 29 | # http://www.gnu.org/software/autoconf 30 | 31 | /autom4te.cache 32 | /autoscan.log 33 | /autoscan-*.log 34 | /aclocal.m4 35 | /compile 36 | /config.guess 37 | /config.h 38 | /config.h.in 39 | /config.log 40 | /config.status 41 | /config.sub 42 | /configure 43 | /configure.scan 44 | /depcomp 45 | /install-sh 46 | /missing 47 | /stamp-h1 48 | 49 | # https://www.gnu.org/software/libtool/ 50 | 51 | /ltmain.sh 52 | /libtool 53 | 54 | # http://www.gnu.org/software/m4/ 55 | 56 | m4/libtool.m4 57 | m4/ltoptions.m4 58 | m4/ltsugar.m4 59 | m4/ltversion.m4 60 | m4/lt~obsolete.m4 61 | autom4te.cache 62 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | default: 2 | tags: 3 | - docker 4 | # Image from https://hub.docker.com/_/gcc/ based on Debian 5 | image: gcc:9 6 | 7 | autoconf: 8 | stage: build 9 | before_script: 10 | - apt-get update && 11 | apt-get install -y libopus-dev zip doxygen graphviz 12 | script: 13 | - ./autogen.sh 14 | - ./configure 15 | - make 16 | - make distcheck 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | dist: trusty 4 | addons: 5 | apt: 6 | packages: 7 | - libopus-dev 8 | 9 | script: 10 | - ./autogen.sh 11 | - ./configure 12 | - make 13 | - make distcheck 14 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Jean-Marc Valin 2 | Timothy B. Terriberry 3 | Ralph Giles 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 1994-2013 Xiph.Org Foundation and contributors 2 | Copyright (c) 2017 Jean-Marc Valin 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | - Neither the name of the Xiph.Org Foundation nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 23 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | DEFS += -DRANDOM_PREFIX=libopusenc -DOUTSIDE_SPEEX 4 | 5 | AM_CFLAGS = -I$(top_srcdir)/include $(DEPS_CFLAGS) 6 | 7 | dist_doc_DATA = COPYING AUTHORS README.md 8 | 9 | opusincludedir = ${includedir}/opus 10 | opusinclude_HEADERS = include/opusenc.h 11 | 12 | lib_LTLIBRARIES = libopusenc.la 13 | noinst_HEADERS = src/arch.h \ 14 | src/ogg_packer.h \ 15 | src/opus_header.h \ 16 | src/picture.h \ 17 | src/resample_sse.h \ 18 | src/speex_resampler.h \ 19 | src/unicode_support.h 20 | 21 | libopusenc_la_SOURCES = \ 22 | src/ogg_packer.c \ 23 | src/opus_header.c \ 24 | src/opusenc.c \ 25 | src/picture.c \ 26 | src/resample.c \ 27 | src/unicode_support.c 28 | libopusenc_la_LIBADD = $(DEPS_LIBS) $(lrintf_lib) 29 | libopusenc_la_LDFLAGS = -no-undefined \ 30 | -version-info @OP_LT_CURRENT@:@OP_LT_REVISION@:@OP_LT_AGE@ 31 | 32 | if OP_ENABLE_EXAMPLES 33 | noinst_PROGRAMS = examples/opusenc_example 34 | endif 35 | 36 | examples_opusenc_example_SOURCES = examples/opusenc_example.c 37 | examples_opusenc_example_LDADD = libopusenc.la 38 | 39 | pkgconfigdir = $(libdir)/pkgconfig 40 | pkgconfig_DATA = libopusenc.pc 41 | 42 | debug: 43 | $(MAKE) CFLAGS="${CFLAGS} -O0 -ggdb -DOP_ENABLE_ASSERTIONS" all 44 | 45 | EXTRA_DIST = \ 46 | libopusenc.pc.in \ 47 | libopusenc-uninstalled.pc.in \ 48 | doc/Doxyfile.in \ 49 | doc/opus_logo.svg \ 50 | doc/Makefile \ 51 | win32/VS2015/opusenc.sln \ 52 | win32/VS2015/opusenc.vcxproj \ 53 | win32/VS2015/opusenc.vcxproj.filters \ 54 | win32/VS2015/common.props \ 55 | win32/genversion.bat \ 56 | win32/config.h 57 | 58 | # Targets to build and install just the library without the docs 59 | libopusenc install-libopusenc: NO_DOXYGEN = 1 60 | 61 | libopusenc: all 62 | install-libopusenc: install 63 | 64 | # Or just the docs 65 | docs: doc/doxygen-build.stamp 66 | 67 | install-docs: 68 | @if [ -z "$(NO_DOXYGEN)" ]; then \ 69 | ( cd doc && \ 70 | echo "Installing documentation in $(DESTDIR)$(docdir)"; \ 71 | $(INSTALL) -d $(DESTDIR)$(docdir)/html/search; \ 72 | for f in `find html -type f \! -name "installdox" -a \! -name '*.md5'` ; do \ 73 | $(INSTALL_DATA) $$f $(DESTDIR)$(docdir)/$$f; \ 74 | done ) \ 75 | fi 76 | 77 | doc/doxygen-build.stamp: doc/Doxyfile $(top_srcdir)/doc/opus_logo.svg \ 78 | $(top_srcdir)/include/*.h 79 | @[ -n "$(NO_DOXYGEN)" ] || ( cd doc && doxygen && touch $(@F) ) 80 | 81 | 82 | if HAVE_DOXYGEN 83 | 84 | # Or everything (by default) 85 | all-local: docs 86 | 87 | install-data-local: install-docs 88 | 89 | clean-local: 90 | $(RM) -r doc/html 91 | $(RM) -r doc/latex 92 | $(RM) doc/doxygen-build.stamp 93 | 94 | uninstall-local: 95 | $(RM) -r $(DESTDIR)$(docdir)/html 96 | 97 | endif 98 | 99 | # We check this every time make is run, with configure.ac being touched to 100 | # trigger an update of the build system files if update_version changes the 101 | # current PACKAGE_VERSION (or if package_version was modified manually by a 102 | # user with either AUTO_UPDATE=no or no update_version script present - the 103 | # latter being the normal case for tarball releases). 104 | # 105 | # We can't just add the package_version file to CONFIGURE_DEPENDENCIES since 106 | # simply running autoconf will not actually regenerate configure for us when 107 | # the content of that file changes (due to autoconf dependency checking not 108 | # knowing about that without us creating yet another file for it to include). 109 | # 110 | # The MAKECMDGOALS check is a gnu-make'ism, but will degrade 'gracefully' for 111 | # makes that don't support it. The only loss of functionality is not forcing 112 | # an update of package_version for `make dist` if AUTO_UPDATE=no, but that is 113 | # unlikely to be a real problem for any real user. 114 | $(top_srcdir)/configure.ac: force 115 | @case "$(MAKECMDGOALS)" in \ 116 | dist-hook) exit 0 ;; \ 117 | dist-* | dist | distcheck | distclean) _arg=release ;; \ 118 | esac; \ 119 | if ! $(top_srcdir)/update_version $$_arg 2> /dev/null; then \ 120 | if [ ! -e $(top_srcdir)/package_version ]; then \ 121 | echo 'PACKAGE_VERSION="unknown"' > $(top_srcdir)/package_version; \ 122 | fi; \ 123 | . $(top_srcdir)/package_version || exit 1; \ 124 | [ "$(PACKAGE_VERSION)" != "$$PACKAGE_VERSION" ] || exit 0; \ 125 | fi; \ 126 | touch $@ 127 | 128 | force: 129 | 130 | # Create a minimal package_version file when make dist is run. 131 | dist-hook: 132 | echo 'PACKAGE_VERSION="$(PACKAGE_VERSION)"' > $(top_distdir)/package_version 133 | 134 | 135 | .PHONY: libopusenc install-libopusenc docs install-docs 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Libopusenc 2 | 3 | The libopusenc libraries provide a high-level API for 4 | encoding .opus files. libopusenc depends only on libopus. 5 | 6 | The library is in very early development. 7 | Please give feedback 8 | in #opus on irc.libera.chat or at opus@xiph.org. 9 | 10 | Programming documentation is available in tree and online at 11 | https://opus-codec.org/docs/ 12 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run this to set up the build system: configure, makefiles, etc. 3 | set -e 4 | 5 | srcdir=`dirname $0` 6 | test -n "$srcdir" && cd "$srcdir" 7 | 8 | echo "Updating build configuration files for libopusenc, please wait...." 9 | 10 | autoreconf -isf 11 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # autoconf source script for generating configure 2 | 3 | dnl The package_version file will be automatically synced to the git revision 4 | dnl by the update_version script when configured in the repository, but will 5 | dnl remain constant in tarball releases unless it is manually edited. 6 | m4_define([CURRENT_VERSION], 7 | m4_esyscmd([ ./update_version 2>/dev/null || true 8 | if test -e package_version; then 9 | . ./package_version 10 | printf "$PACKAGE_VERSION" 11 | else 12 | printf "unknown" 13 | fi ])) 14 | 15 | AC_INIT([libopusenc],[CURRENT_VERSION],[opus@xiph.org]) 16 | AC_CONFIG_SRCDIR([src/opusenc.c]) 17 | AC_CONFIG_MACRO_DIR([m4]) 18 | 19 | AC_USE_SYSTEM_EXTENSIONS 20 | AC_SYS_LARGEFILE 21 | 22 | AM_INIT_AUTOMAKE([1.11 foreign no-define dist-zip subdir-objects]) 23 | AM_MAINTAINER_MODE([enable]) 24 | 25 | AC_C_INLINE 26 | 27 | LT_INIT 28 | 29 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 30 | 31 | AC_DEFINE([OPE_BUILD], [], [This is a build of libopusenc]) 32 | 33 | dnl Library versioning for libtool. 34 | dnl Please update these for releases. 35 | dnl CURRENT, REVISION, AGE 36 | dnl - library source changed -> increment REVISION 37 | dnl - interfaces added/removed/changed -> increment CURRENT, REVISION = 0 38 | dnl - interfaces added -> increment AGE 39 | dnl - interfaces removed -> AGE = 0 40 | 41 | OP_LT_CURRENT=4 42 | OP_LT_REVISION=2 43 | OP_LT_AGE=4 44 | 45 | AC_SUBST(OP_LT_CURRENT) 46 | AC_SUBST(OP_LT_REVISION) 47 | AC_SUBST(OP_LT_AGE) 48 | 49 | CC_CHECK_CFLAGS_APPEND( 50 | [-pedantic -Wall -Wextra -Wno-sign-compare -Wno-parentheses -Wno-long-long]) 51 | 52 | # Platform-specific tweaks 53 | case $host in 54 | *-mingw*) 55 | # -std=c89 causes some warnings under mingw. 56 | CC_CHECK_CFLAGS_APPEND([-U__STRICT_ANSI__]) 57 | # We need WINNT>=0x501 (WindowsXP) for getaddrinfo/freeaddrinfo. 58 | # It's okay to define this even when HTTP support is disabled, as it only 59 | # affects header declarations, not linking (unless we actually use some 60 | # XP-only functions). 61 | AC_DEFINE_UNQUOTED(_WIN32_WINNT,0x501, 62 | [We need at least WindowsXP for getaddrinfo/freeaddrinfo]) 63 | host_mingw=true 64 | ;; 65 | esac 66 | AM_CONDITIONAL(OP_WIN32, test "$host_mingw" = "true") 67 | 68 | dnl AC_ARG_ENABLE([assertions], 69 | dnl AS_HELP_STRING([--enable-assertions], [Enable assertions in code]),, 70 | dnl enable_assertions=no) 71 | 72 | AS_IF([test "$enable_assertions" = "yes"], [ 73 | AC_DEFINE([OP_ENABLE_ASSERTIONS], [1], [Enable assertions in code]) 74 | ]) 75 | 76 | m4_ifndef([PKG_PROG_PKG_CONFIG], 77 | [m4_fatal([Could not locate the pkg-config autoconf macros. 78 | Please make sure pkg-config is installed and, if necessary, set the environment 79 | variable ACLOCAL="aclocal -I/path/to/pkg.m4".])]) 80 | 81 | PKG_CHECK_MODULES([DEPS], [opus >= 1.1]) 82 | 83 | dnl AC_ARG_ENABLE([fixed-point], 84 | dnl AS_HELP_STRING([--enable-fixed-point], [Enable fixed-point calculation]),, 85 | dnl enable_fixed_point=no) 86 | dnl AC_ARG_ENABLE([float], 87 | dnl AS_HELP_STRING([--disable-float], [Disable floating-point API]),, 88 | dnl enable_float=yes) 89 | 90 | AC_DEFINE([RESAMPLE_FULL_SINC_TABLE], [1], [Faster, takes more memory]) 91 | 92 | dnl AS_IF([test "$enable_float" = "no"], 93 | dnl [enable_fixed_point=yes 94 | dnl AC_DEFINE([OP_DISABLE_FLOAT_API], [1], [Disable floating-point API]) 95 | dnl ] 96 | dnl ) 97 | 98 | AS_IF([test "$enable_fixed_point" = "yes"], 99 | [AC_DEFINE([OP_FIXED_POINT], [1], [Enable fixed-point calculation])], 100 | [dnl This only has to be tested for if float->fixed conversions are required 101 | saved_LIBS="$LIBS" 102 | AC_SEARCH_LIBS([lrintf], [m], [ 103 | AC_DEFINE([OP_HAVE_LRINTF], [1], [Enable use of lrintf function]) 104 | lrintf_notice=" 105 | Library for lrintf() ......... ${ac_cv_search_lrintf}" 106 | ]) 107 | LIBS="$saved_LIBS" 108 | ] 109 | ) 110 | 111 | AC_ARG_ENABLE([examples], 112 | AS_HELP_STRING([--disable-examples], [Do not build example applications]),, 113 | enable_examples=yes) 114 | AM_CONDITIONAL([OP_ENABLE_EXAMPLES], [test "$enable_examples" = "yes"]) 115 | 116 | AS_CASE(["$ac_cv_search_lrintf"], 117 | ["no"],[], 118 | ["none required"],[], 119 | [lrintf_lib="$ac_cv_search_lrintf"]) 120 | 121 | AC_SUBST([lrintf_lib]) 122 | 123 | CC_ATTRIBUTE_VISIBILITY([default], [ 124 | CC_FLAG_VISIBILITY([CFLAGS="${CFLAGS} -fvisibility=hidden"]) 125 | ]) 126 | 127 | dnl Check for doxygen 128 | AC_ARG_ENABLE([doc], 129 | AS_HELP_STRING([--disable-doc], [Do not build API documentation]),, 130 | [enable_doc=yes] 131 | ) 132 | 133 | AS_IF([test "$enable_doc" = "yes"], [ 134 | AC_CHECK_PROG([HAVE_DOXYGEN], [doxygen], [yes], [no]) 135 | AC_CHECK_PROG([HAVE_DOT], [dot], [yes], [no]) 136 | ],[ 137 | HAVE_DOXYGEN=no 138 | ]) 139 | 140 | AM_CONDITIONAL([HAVE_DOXYGEN], [test "$HAVE_DOXYGEN" = "yes"]) 141 | 142 | AC_CONFIG_FILES([ 143 | Makefile 144 | libopusenc.pc 145 | libopusenc-uninstalled.pc 146 | doc/Doxyfile 147 | ]) 148 | AC_CONFIG_HEADERS([config.h]) 149 | AC_OUTPUT 150 | 151 | AC_MSG_NOTICE([ 152 | ------------------------------------------------------------------------ 153 | $PACKAGE_NAME $PACKAGE_VERSION: Automatic configuration OK. 154 | 155 | dnl Assertions ................... ${enable_assertions} 156 | dnl 157 | dnl Fixed-point .................. ${enable_fixed_point} 158 | dnl Floating-point API ........... ${enable_float}${lrintf_notice} 159 | dnl 160 | Hidden visibility ............ ${cc_cv_flag_visibility} 161 | 162 | API code examples ............ ${enable_examples} 163 | API documentation ............ ${enable_doc} 164 | ------------------------------------------------------------------------ 165 | ]) 166 | -------------------------------------------------------------------------------- /doc/Doxyfile.in: -------------------------------------------------------------------------------- 1 | # Process with doxygen to generate API documentation 2 | 3 | PROJECT_NAME = @PACKAGE_NAME@ 4 | PROJECT_NUMBER = @PACKAGE_VERSION@ 5 | PROJECT_BRIEF = "Stand-alone encoder library for .opus files." 6 | INPUT = @top_srcdir@/include/opusenc.h 7 | OPTIMIZE_OUTPUT_FOR_C = YES 8 | 9 | QUIET = YES 10 | WARNINGS = YES 11 | WARN_IF_UNDOCUMENTED = YES 12 | WARN_IF_DOC_ERROR = YES 13 | WARN_NO_PARAMDOC = YES 14 | 15 | JAVADOC_AUTOBRIEF = YES 16 | SORT_MEMBER_DOCS = NO 17 | 18 | HAVE_DOT = @HAVE_DOT@ 19 | 20 | PROJECT_LOGO = @top_srcdir@/doc/opus_logo.svg 21 | 22 | FULL_PATH_NAMES = NO 23 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | ## GNU makefile for libopusenc documentation. 2 | 3 | -include ../package_version 4 | 5 | all: doxygen 6 | 7 | doxygen: Doxyfile ../include/opusenc.h 8 | doxygen 9 | 10 | pdf: doxygen 11 | make -C latex 12 | 13 | clean: 14 | $(RM) -r html 15 | $(RM) -r latex 16 | 17 | distclean: clean 18 | $(RM) Doxyfile 19 | 20 | .PHONY: all clean distclean doxygen pdf 21 | 22 | ../package_version: 23 | @if [ -x ../update_version ]; then \ 24 | ../update_version || true; \ 25 | elif [ ! -e $@ ]; then \ 26 | echo 'PACKAGE_VERSION="unknown"' > $@; \ 27 | fi 28 | 29 | # run autoconf-like replacements to finalize our config 30 | Doxyfile: Doxyfile.in Makefile ../package_version 31 | sed -e 's/@PACKAGE_NAME@/libopusenc/' \ 32 | -e 's/@PACKAGE_VERSION@/$(PACKAGE_VERSION)/' \ 33 | -e 's/@top_srcdir@/../' \ 34 | < $< > $@ 35 | -------------------------------------------------------------------------------- /doc/opus_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 55 | 62 | 66 | 70 | 71 | 72 | 79 | 83 | 87 | 88 | 89 | 96 | 100 | 104 | 105 | 106 | 113 | 117 | 121 | 122 | 123 | 130 | 134 | 138 | 139 | 157 | 158 | -------------------------------------------------------------------------------- /examples/opusenc_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "opusenc.h" 3 | 4 | #define READ_SIZE 256 5 | 6 | int main(int argc, char **argv) { 7 | FILE *fin; 8 | OggOpusEnc *enc; 9 | OggOpusComments *comments; 10 | int error; 11 | if (argc != 3) { 12 | fprintf(stderr, "usage: %s \n", argv[0]); 13 | return 1; 14 | } 15 | fin = fopen(argv[1], "rb"); 16 | if (!fin) { 17 | fprintf(stderr, "cannot open input file: %s\n", argv[1]); 18 | return 1; 19 | } 20 | comments = ope_comments_create(); 21 | ope_comments_add(comments, "ARTIST", "Someone"); 22 | ope_comments_add(comments, "TITLE", "Some track"); 23 | enc = ope_encoder_create_file(argv[2], comments, 44100, 2, 0, &error); 24 | if (!enc) { 25 | fprintf(stderr, "error encoding to file %s: %s\n", argv[2], ope_strerror(error)); 26 | ope_comments_destroy(comments); 27 | fclose(fin); 28 | return 1; 29 | } 30 | while (1) { 31 | short buf[2*READ_SIZE]; 32 | int ret = fread(buf, 2*sizeof(short), READ_SIZE, fin); 33 | if (ret > 0) { 34 | ope_encoder_write(enc, buf, ret); 35 | } else break; 36 | } 37 | ope_encoder_drain(enc); 38 | ope_encoder_destroy(enc); 39 | ope_comments_destroy(comments); 40 | fclose(fin); 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /include/opusenc.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017 Jean-Marc Valin */ 2 | /* 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | - Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | - Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 18 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef OPUSENC_H 28 | # define OPUSENC_H 29 | 30 | /**\mainpage 31 | \section Introduction 32 | 33 | This is the documentation for the libopusenc C API. 34 | 35 | The libopusenc package provides a convenient high-level API for 36 | encoding Ogg Opus files. 37 | 38 | \section Organization 39 | 40 | The main API is divided into several sections: 41 | - \ref encoding 42 | - \ref comments 43 | - \ref encoder_ctl 44 | - \ref callbacks 45 | - \ref error_codes 46 | 47 | \section Overview 48 | 49 | The libopusfile API provides an easy way to encode Ogg Opus files using 50 | libopus. 51 | */ 52 | 53 | # if defined(__cplusplus) 54 | extern "C" { 55 | # endif 56 | 57 | #include 58 | #include 59 | 60 | #ifndef OPE_EXPORT 61 | # if defined(WIN32) 62 | # if defined(OPE_BUILD) && defined(DLL_EXPORT) 63 | # define OPE_EXPORT __declspec(dllexport) 64 | # else 65 | # define OPE_EXPORT 66 | # endif 67 | # elif defined(__GNUC__) && defined(OPE_BUILD) 68 | # define OPE_EXPORT __attribute__ ((visibility ("default"))) 69 | # else 70 | # define OPE_EXPORT 71 | # endif 72 | #endif 73 | 74 | /**\defgroup error_codes Error Codes*/ 75 | /**@{*/ 76 | /**\name List of possible error codes 77 | Many of the functions in this library return a negative error code when a 78 | function fails. 79 | This list provides a brief explanation of the common errors. 80 | See each individual function for more details on what a specific error code 81 | means in that context.*/ 82 | /**@{*/ 83 | 84 | 85 | /* Bump this when we change the API. */ 86 | /** API version for this header. Can be used to check for features at compile time. */ 87 | #define OPE_API_VERSION 0 88 | 89 | #define OPE_OK 0 90 | /* Based on the relevant libopus code minus 10. */ 91 | #define OPE_BAD_ARG -11 92 | #define OPE_INTERNAL_ERROR -13 93 | #define OPE_UNIMPLEMENTED -15 94 | #define OPE_ALLOC_FAIL -17 95 | 96 | /* Specific to libopusenc. */ 97 | #define OPE_CANNOT_OPEN -30 98 | #define OPE_TOO_LATE -31 99 | #define OPE_INVALID_PICTURE -32 100 | #define OPE_INVALID_ICON -33 101 | #define OPE_WRITE_FAIL -34 102 | #define OPE_CLOSE_FAIL -35 103 | 104 | /**@}*/ 105 | /**@}*/ 106 | 107 | 108 | /* These are the "raw" request values -- they should usually not be used. */ 109 | #define OPE_SET_DECISION_DELAY_REQUEST 14000 110 | #define OPE_GET_DECISION_DELAY_REQUEST 14001 111 | #define OPE_SET_MUXING_DELAY_REQUEST 14002 112 | #define OPE_GET_MUXING_DELAY_REQUEST 14003 113 | #define OPE_SET_COMMENT_PADDING_REQUEST 14004 114 | #define OPE_GET_COMMENT_PADDING_REQUEST 14005 115 | #define OPE_SET_SERIALNO_REQUEST 14006 116 | #define OPE_GET_SERIALNO_REQUEST 14007 117 | #define OPE_SET_PACKET_CALLBACK_REQUEST 14008 118 | /*#define OPE_GET_PACKET_CALLBACK_REQUEST 14009*/ 119 | #define OPE_SET_HEADER_GAIN_REQUEST 14010 120 | #define OPE_GET_HEADER_GAIN_REQUEST 14011 121 | #define OPE_GET_NB_STREAMS_REQUEST 14013 122 | #define OPE_GET_NB_COUPLED_STREAMS_REQUEST 14015 123 | 124 | /**\defgroup encoder_ctl Encoding Options*/ 125 | /**@{*/ 126 | 127 | /**\name Control parameters 128 | 129 | Macros for setting encoder options.*/ 130 | /**@{*/ 131 | 132 | #define OPE_SET_DECISION_DELAY(x) OPE_SET_DECISION_DELAY_REQUEST, __opus_check_int(x) 133 | #define OPE_GET_DECISION_DELAY(x) OPE_GET_DECISION_DELAY_REQUEST, __opus_check_int_ptr(x) 134 | #define OPE_SET_MUXING_DELAY(x) OPE_SET_MUXING_DELAY_REQUEST, __opus_check_int(x) 135 | #define OPE_GET_MUXING_DELAY(x) OPE_GET_MUXING_DELAY_REQUEST, __opus_check_int_ptr(x) 136 | #define OPE_SET_COMMENT_PADDING(x) OPE_SET_COMMENT_PADDING_REQUEST, __opus_check_int(x) 137 | #define OPE_GET_COMMENT_PADDING(x) OPE_GET_COMMENT_PADDING_REQUEST, __opus_check_int_ptr(x) 138 | #define OPE_SET_SERIALNO(x) OPE_SET_SERIALNO_REQUEST, __opus_check_int(x) 139 | #define OPE_GET_SERIALNO(x) OPE_GET_SERIALNO_REQUEST, __opus_check_int_ptr(x) 140 | /* FIXME: Add type-checking macros to these. */ 141 | #define OPE_SET_PACKET_CALLBACK(x,u) OPE_SET_PACKET_CALLBACK_REQUEST, (x), (u) 142 | /*#define OPE_GET_PACKET_CALLBACK(x,u) OPE_GET_PACKET_CALLBACK_REQUEST, (x), (u)*/ 143 | #define OPE_SET_HEADER_GAIN(x) OPE_SET_HEADER_GAIN_REQUEST, __opus_check_int(x) 144 | #define OPE_GET_HEADER_GAIN(x) OPE_GET_HEADER_GAIN_REQUEST, __opus_check_int_ptr(x) 145 | #define OPE_GET_NB_STREAMS(x) OPE_GET_NB_STREAMS_REQUEST, __opus_check_int_ptr(x) 146 | #define OPE_GET_NB_COUPLED_STREAMS(x) OPE_GET_NB_COUPLED_STREAMS_REQUEST, __opus_check_int_ptr(x) 147 | /**@}*/ 148 | /**@}*/ 149 | 150 | /**\defgroup callbacks Callback Functions */ 151 | /**@{*/ 152 | 153 | /**\name Callback functions 154 | 155 | These are the callbacks that can be implemented for an encoder.*/ 156 | /**@{*/ 157 | 158 | /** Called for writing a page. 159 | \param user_data user-defined data passed to the callback 160 | \param ptr buffer to be written 161 | \param len number of bytes to be written 162 | \return error code 163 | \retval 0 success 164 | \retval 1 failure 165 | */ 166 | typedef int (*ope_write_func)(void *user_data, const unsigned char *ptr, opus_int32 len); 167 | 168 | /** Called for closing a stream. 169 | \param user_data user-defined data passed to the callback 170 | \return error code 171 | \retval 0 success 172 | \retval 1 failure 173 | */ 174 | typedef int (*ope_close_func)(void *user_data); 175 | 176 | /** Called on every packet encoded (including header). 177 | \param user_data user-defined data passed to the callback 178 | \param packet_ptr packet data 179 | \param packet_len number of bytes in the packet 180 | \param flags optional flags (none defined for now so zero) 181 | */ 182 | typedef void (*ope_packet_func)(void *user_data, const unsigned char *packet_ptr, opus_int32 packet_len, opus_uint32 flags); 183 | 184 | /** Callback functions for accessing the stream. */ 185 | typedef struct { 186 | /** Callback for writing to the stream. */ 187 | ope_write_func write; 188 | /** Callback for closing the stream. */ 189 | ope_close_func close; 190 | } OpusEncCallbacks; 191 | /**@}*/ 192 | /**@}*/ 193 | 194 | /** Opaque comments struct. */ 195 | typedef struct OggOpusComments OggOpusComments; 196 | 197 | /** Opaque encoder struct. */ 198 | typedef struct OggOpusEnc OggOpusEnc; 199 | 200 | /**\defgroup comments Comments Handling */ 201 | /**@{*/ 202 | 203 | /**\name Functions for handling comments 204 | 205 | These functions make it possible to add comments and pictures to Ogg Opus files.*/ 206 | /**@{*/ 207 | 208 | /** Create a new comments object. 209 | \return Newly-created comments object. */ 210 | OPE_EXPORT OggOpusComments *ope_comments_create(void); 211 | 212 | /** Create a deep copy of a comments object. 213 | \param comments Comments object to copy 214 | \return Deep copy of input. */ 215 | OPE_EXPORT OggOpusComments *ope_comments_copy(OggOpusComments *comments); 216 | 217 | /** Destroys a comments object. 218 | \param comments Comments object to destroy*/ 219 | OPE_EXPORT void ope_comments_destroy(OggOpusComments *comments); 220 | 221 | /** Add a comment. 222 | \param[in,out] comments Where to add the comments 223 | \param tag Tag for the comment (must not contain = char) 224 | \param val Value for the tag 225 | \return Error code 226 | */ 227 | OPE_EXPORT int ope_comments_add(OggOpusComments *comments, const char *tag, const char *val); 228 | 229 | /** Add a comment as a single tag=value string. 230 | \param[in,out] comments Where to add the comments 231 | \param tag_and_val string of the form tag=value (must contain = char) 232 | \return Error code 233 | */ 234 | OPE_EXPORT int ope_comments_add_string(OggOpusComments *comments, const char *tag_and_val); 235 | 236 | /** Add a picture from a file. 237 | \param[in,out] comments Where to add the comments 238 | \param filename File name for the picture 239 | \param picture_type Type of picture (-1 for default) 240 | \param description Description (NULL means no comment) 241 | \return Error code 242 | */ 243 | OPE_EXPORT int ope_comments_add_picture(OggOpusComments *comments, const char *filename, int picture_type, const char *description); 244 | 245 | /** Add a picture already in memory. 246 | \param[in,out] comments Where to add the comments 247 | \param ptr Pointer to picture in memory 248 | \param size Size of picture pointed to by ptr 249 | \param picture_type Type of picture (-1 for default) 250 | \param description Description (NULL means no comment) 251 | \return Error code 252 | */ 253 | OPE_EXPORT int ope_comments_add_picture_from_memory(OggOpusComments *comments, const char *ptr, size_t size, int picture_type, const char *description); 254 | 255 | /**@}*/ 256 | /**@}*/ 257 | 258 | /**\defgroup encoding Encoding */ 259 | /**@{*/ 260 | 261 | /**\name Functions for encoding Ogg Opus files 262 | 263 | These functions make it possible to encode Ogg Opus files.*/ 264 | /**@{*/ 265 | 266 | /** Create a new OggOpus file. 267 | \param path Path where to create the file 268 | \param comments Comments associated with the stream 269 | \param rate Input sampling rate (48 kHz is faster) 270 | \param channels Number of channels 271 | \param family Mapping family (0 for mono/stereo, 1 for surround) 272 | \param[out] error Error code (NULL if no error is to be returned) 273 | \return Newly-created encoder. 274 | */ 275 | OPE_EXPORT OggOpusEnc *ope_encoder_create_file(const char *path, OggOpusComments *comments, opus_int32 rate, int channels, int family, int *error); 276 | 277 | /** Create a new OggOpus stream to be handled using callbacks 278 | \param callbacks Callback functions 279 | \param user_data Pointer to be associated with the stream and passed to the callbacks 280 | \param comments Comments associated with the stream 281 | \param rate Input sampling rate (48 kHz is faster) 282 | \param channels Number of channels 283 | \param family Mapping family (0 for mono/stereo, 1 for surround) 284 | \param[out] error Error code (NULL if no error is to be returned) 285 | \return Newly-created encoder. 286 | */ 287 | OPE_EXPORT OggOpusEnc *ope_encoder_create_callbacks(const OpusEncCallbacks *callbacks, void *user_data, 288 | OggOpusComments *comments, opus_int32 rate, int channels, int family, int *error); 289 | 290 | /** Create a new OggOpus stream to be used along with.ope_encoder_get_page(). 291 | This is mostly useful for muxing with other streams. 292 | \param comments Comments associated with the stream 293 | \param rate Input sampling rate (48 kHz is faster) 294 | \param channels Number of channels 295 | \param family Mapping family (0 for mono/stereo, 1 for surround) 296 | \param[out] error Error code (NULL if no error is to be returned) 297 | \return Newly-created encoder. 298 | */ 299 | OPE_EXPORT OggOpusEnc *ope_encoder_create_pull(OggOpusComments *comments, opus_int32 rate, int channels, int family, int *error); 300 | 301 | /** Deferred initialization of the encoder to force an explicit channel mapping. This can be used to override the default channel coupling, 302 | but using it for regular surround will almost certainly lead to worse quality. 303 | \param[in,out] enc Encoder 304 | \param family Mapping family (0 for mono/stereo, 1 for surround) 305 | \param streams Total number of streams 306 | \param coupled_streams Number of coupled streams 307 | \param mapping Channel mapping 308 | \return Error code 309 | */ 310 | OPE_EXPORT int ope_encoder_deferred_init_with_mapping(OggOpusEnc *enc, int family, int streams, 311 | int coupled_streams, const unsigned char *mapping); 312 | 313 | /** Add/encode any number of float samples to the stream. 314 | \param[in,out] enc Encoder 315 | \param pcm Floating-point PCM values in the +/-1 range (interleaved if multiple channels) 316 | \param samples_per_channel Number of samples for each channel 317 | \return Error code*/ 318 | OPE_EXPORT int ope_encoder_write_float(OggOpusEnc *enc, const float *pcm, int samples_per_channel); 319 | 320 | /** Add/encode any number of 16-bit linear samples to the stream. 321 | \param[in,out] enc Encoder 322 | \param pcm Linear 16-bit PCM values in the [-32768,32767] range (interleaved if multiple channels) 323 | \param samples_per_channel Number of samples for each channel 324 | \return Error code*/ 325 | OPE_EXPORT int ope_encoder_write(OggOpusEnc *enc, const opus_int16 *pcm, int samples_per_channel); 326 | 327 | /** Get the next page from the stream (only if using ope_encoder_create_pull()). 328 | \param[in,out] enc Encoder 329 | \param[out] page Next available encoded page 330 | \param[out] len Size (in bytes) of the page returned 331 | \param flush If non-zero, forces a flush of the page (if any data avaiable) 332 | \return 1 if there is a page available, 0 if not. */ 333 | OPE_EXPORT int ope_encoder_get_page(OggOpusEnc *enc, unsigned char **page, opus_int32 *len, int flush); 334 | 335 | /** Finalizes the stream, but does not deallocate the object. 336 | \param[in,out] enc Encoder 337 | \return Error code 338 | */ 339 | OPE_EXPORT int ope_encoder_drain(OggOpusEnc *enc); 340 | 341 | /** Deallocates the obect. Make sure to ope_drain() first. 342 | \param[in,out] enc Encoder 343 | */ 344 | OPE_EXPORT void ope_encoder_destroy(OggOpusEnc *enc); 345 | 346 | /** Ends the stream and create a new stream within the same file. 347 | \param[in,out] enc Encoder 348 | \param comments Comments associated with the stream 349 | \return Error code 350 | */ 351 | OPE_EXPORT int ope_encoder_chain_current(OggOpusEnc *enc, OggOpusComments *comments); 352 | 353 | /** Ends the stream and create a new file. 354 | \param[in,out] enc Encoder 355 | \param path Path where to write the new file 356 | \param comments Comments associated with the stream 357 | \return Error code 358 | */ 359 | OPE_EXPORT int ope_encoder_continue_new_file(OggOpusEnc *enc, const char *path, OggOpusComments *comments); 360 | 361 | /** Ends the stream and create a new file (callback-based). 362 | \param[in,out] enc Encoder 363 | \param user_data Pointer to be associated with the new stream and passed to the callbacks 364 | \param comments Comments associated with the stream 365 | \return Error code 366 | */ 367 | OPE_EXPORT int ope_encoder_continue_new_callbacks(OggOpusEnc *enc, void *user_data, OggOpusComments *comments); 368 | 369 | /** Write out the header now rather than wait for audio to begin. 370 | \param[in,out] enc Encoder 371 | \return Error code 372 | */ 373 | OPE_EXPORT int ope_encoder_flush_header(OggOpusEnc *enc); 374 | 375 | /** Sets encoder options. 376 | \param[in,out] enc Encoder 377 | \param request Use a request macro 378 | \return Error code 379 | */ 380 | OPE_EXPORT int ope_encoder_ctl(OggOpusEnc *enc, int request, ...); 381 | 382 | /** Converts a libopusenc error code into a human readable string. 383 | * 384 | * @param error Error number 385 | * @returns Error string 386 | */ 387 | OPE_EXPORT const char *ope_strerror(int error); 388 | 389 | /** Returns a string representing the version of libopusenc being used at run time. 390 | \return A string describing the version of this library */ 391 | OPE_EXPORT const char *ope_get_version_string(void); 392 | 393 | /** ABI version for this header. Can be used to check for features at run time. 394 | \return An integer representing the ABI version */ 395 | OPE_EXPORT int ope_get_abi_version(void); 396 | 397 | /**@}*/ 398 | /**@}*/ 399 | 400 | # if defined(__cplusplus) 401 | } 402 | # endif 403 | 404 | #endif 405 | -------------------------------------------------------------------------------- /libopusenc-uninstalled.pc.in: -------------------------------------------------------------------------------- 1 | # libopusenc uninstalled pkg-config file 2 | 3 | prefix= 4 | exec_prefix= 5 | libdir=${pcfiledir}/.libs 6 | includedir=${pcfiledir}/@top_srcdir@/include 7 | 8 | Name: libopusenc uninstalled 9 | Description: High-level Opus encoding library (not installed) 10 | URL: https://opus-codec.org/ 11 | Version: @PACKAGE_VERSION@ 12 | Requires.private: opus >= 1.1 13 | Conflicts: 14 | Libs: ${libdir}/libopusenc.la @lrintf_lib@ 15 | Cflags: -I${includedir} 16 | -------------------------------------------------------------------------------- /libopusenc.pc.in: -------------------------------------------------------------------------------- 1 | # libopusenc installed pkg-config file 2 | 3 | prefix=@prefix@ 4 | exec_prefix=@exec_prefix@ 5 | libdir=@libdir@ 6 | includedir=@includedir@ 7 | 8 | Name: libopusenc 9 | Description: High-level Opus encoding library 10 | URL: https://opus-codec.org/ 11 | Version: @PACKAGE_VERSION@ 12 | Requires.private: opus >= 1.1 13 | Conflicts: 14 | Libs: -L${libdir} -lopusenc 15 | Libs.private: @lrintf_lib@ 16 | Cflags: -I${includedir}/opus 17 | -------------------------------------------------------------------------------- /m4/attributes.m4: -------------------------------------------------------------------------------- 1 | dnl Macros to check the presence of generic (non-typed) symbols. 2 | dnl Copyright (c) 2006-2007 Diego Pettenò 3 | dnl Copyright (c) 2006-2007 xine project 4 | dnl 5 | dnl This program is free software; you can redistribute it and/or modify 6 | dnl it under the terms of the GNU General Public License as published by 7 | dnl the Free Software Foundation; either version 2, or (at your option) 8 | dnl any later version. 9 | dnl 10 | dnl This program is distributed in the hope that it will be useful, 11 | dnl but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | dnl GNU General Public License for more details. 14 | dnl 15 | dnl You should have received a copy of the GNU General Public License 16 | dnl along with this program; if not, write to the Free Software 17 | dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | dnl 02110-1301, USA. 19 | dnl 20 | dnl As a special exception, the copyright owners of the 21 | dnl macro gives unlimited permission to copy, distribute and modify the 22 | dnl configure scripts that are the output of Autoconf when processing the 23 | dnl Macro. You need not follow the terms of the GNU General Public 24 | dnl License when using or distributing such scripts, even though portions 25 | dnl of the text of the Macro appear in them. The GNU General Public 26 | dnl License (GPL) does govern all other use of the material that 27 | dnl constitutes the Autoconf Macro. 28 | dnl 29 | dnl This special exception to the GPL applies to versions of the 30 | dnl Autoconf Macro released by this project. When you make and 31 | dnl distribute a modified version of the Autoconf Macro, you may extend 32 | dnl this special exception to the GPL to apply to your modified version as 33 | dnl well. 34 | 35 | dnl Check if the flag is supported by compiler 36 | dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) 37 | 38 | AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ 39 | AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]), 40 | [ac_save_CFLAGS="$CFLAGS" 41 | CFLAGS="$CFLAGS $1" 42 | AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; }])], 43 | [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"], 44 | [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"]) 45 | CFLAGS="$ac_save_CFLAGS" 46 | ]) 47 | 48 | AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], 49 | [$2], [$3]) 50 | ]) 51 | 52 | dnl Check if the flag is supported by compiler (cacheable) 53 | dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) 54 | 55 | AC_DEFUN([CC_CHECK_CFLAGS], [ 56 | AC_CACHE_CHECK([if $CC supports $1 flag], 57 | AS_TR_SH([cc_cv_cflags_$1]), 58 | CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! 59 | ) 60 | 61 | AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], 62 | [$2], [$3]) 63 | ]) 64 | 65 | dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) 66 | dnl Check for CFLAG and appends them to CFLAGS if supported 67 | AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ 68 | AC_CACHE_CHECK([if $CC supports $1 flag], 69 | AS_TR_SH([cc_cv_cflags_$1]), 70 | CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! 71 | ) 72 | 73 | AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], 74 | [CFLAGS="$CFLAGS $1"; $2], [$3]) 75 | ]) 76 | 77 | dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) 78 | AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [ 79 | for flag in $1; do 80 | CC_CHECK_CFLAG_APPEND($flag, [$2], [$3]) 81 | done 82 | ]) 83 | 84 | dnl Check if the flag is supported by linker (cacheable) 85 | dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) 86 | 87 | AC_DEFUN([CC_CHECK_LDFLAGS], [ 88 | AC_CACHE_CHECK([if $CC supports $1 flag], 89 | AS_TR_SH([cc_cv_ldflags_$1]), 90 | [ac_save_LDFLAGS="$LDFLAGS" 91 | LDFLAGS="$LDFLAGS $1" 92 | AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return 1; }])], 93 | [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], 94 | [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) 95 | LDFLAGS="$ac_save_LDFLAGS" 96 | ]) 97 | 98 | AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], 99 | [$2], [$3]) 100 | ]) 101 | 102 | dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for 103 | dnl the current linker to avoid undefined references in a shared object. 104 | AC_DEFUN([CC_NOUNDEFINED], [ 105 | dnl We check $host for which systems to enable this for. 106 | AC_REQUIRE([AC_CANONICAL_HOST]) 107 | 108 | case $host in 109 | dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads 110 | dnl are requested, as different implementations are present; to avoid problems 111 | dnl use -Wl,-z,defs only for those platform not behaving this way. 112 | *-freebsd* | *-openbsd*) ;; 113 | *) 114 | dnl First of all check for the --no-undefined variant of GNU ld. This allows 115 | dnl for a much more readable commandline, so that people can understand what 116 | dnl it does without going to look for what the heck -z defs does. 117 | for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do 118 | CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) 119 | break 120 | done 121 | ;; 122 | esac 123 | 124 | AC_SUBST([LDFLAGS_NOUNDEFINED]) 125 | ]) 126 | 127 | dnl Check for a -Werror flag or equivalent. -Werror is the GCC 128 | dnl and ICC flag that tells the compiler to treat all the warnings 129 | dnl as fatal. We usually need this option to make sure that some 130 | dnl constructs (like attributes) are not simply ignored. 131 | dnl 132 | dnl Other compilers don't support -Werror per se, but they support 133 | dnl an equivalent flag: 134 | dnl - Sun Studio compiler supports -errwarn=%all 135 | AC_DEFUN([CC_CHECK_WERROR], [ 136 | AC_CACHE_CHECK( 137 | [for $CC way to treat warnings as errors], 138 | [cc_cv_werror], 139 | [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], 140 | [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) 141 | ]) 142 | ]) 143 | 144 | AC_DEFUN([CC_CHECK_ATTRIBUTE], [ 145 | AC_REQUIRE([CC_CHECK_WERROR]) 146 | AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], 147 | AS_TR_SH([cc_cv_attribute_$1]), 148 | [ac_save_CFLAGS="$CFLAGS" 149 | CFLAGS="$CFLAGS $cc_cv_werror" 150 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])], 151 | [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], 152 | [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) 153 | CFLAGS="$ac_save_CFLAGS" 154 | ]) 155 | 156 | AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], 157 | [AC_DEFINE( 158 | AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, 159 | [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] 160 | ) 161 | $4], 162 | [$5]) 163 | ]) 164 | 165 | AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ 166 | CC_CHECK_ATTRIBUTE( 167 | [constructor],, 168 | [extern void foo(void); 169 | void __attribute__((constructor)) ctor(void) { foo(); }], 170 | [$1], [$2]) 171 | ]) 172 | 173 | AC_DEFUN([CC_ATTRIBUTE_DESTRUCTOR], [ 174 | CC_CHECK_ATTRIBUTE( 175 | [destructor],, 176 | [extern void foo(void); 177 | void __attribute__((destructor)) dtor(void) { foo(); }], 178 | [$1], [$2]) 179 | ]) 180 | 181 | AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ 182 | CC_CHECK_ATTRIBUTE( 183 | [format], [format(printf, n, n)], 184 | [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], 185 | [$1], [$2]) 186 | ]) 187 | 188 | AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ 189 | CC_CHECK_ATTRIBUTE( 190 | [format_arg], [format_arg(printf)], 191 | [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], 192 | [$1], [$2]) 193 | ]) 194 | 195 | AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ 196 | CC_CHECK_ATTRIBUTE( 197 | [visibility_$1], [visibility("$1")], 198 | [void __attribute__((visibility("$1"))) $1_function(void) { }], 199 | [$2], [$3]) 200 | ]) 201 | 202 | AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ 203 | CC_CHECK_ATTRIBUTE( 204 | [nonnull], [nonnull()], 205 | [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], 206 | [$1], [$2]) 207 | ]) 208 | 209 | AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ 210 | CC_CHECK_ATTRIBUTE( 211 | [unused], , 212 | [void some_function(void *foo, __attribute__((unused)) void *bar);], 213 | [$1], [$2]) 214 | ]) 215 | 216 | AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ 217 | CC_CHECK_ATTRIBUTE( 218 | [sentinel], , 219 | [void some_function(void *foo, ...) __attribute__((sentinel));], 220 | [$1], [$2]) 221 | ]) 222 | 223 | AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ 224 | CC_CHECK_ATTRIBUTE( 225 | [deprecated], , 226 | [void some_function(void *foo, ...) __attribute__((deprecated));], 227 | [$1], [$2]) 228 | ]) 229 | 230 | AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ 231 | CC_CHECK_ATTRIBUTE( 232 | [alias], [weak, alias], 233 | [void other_function(void *foo) { } 234 | void some_function(void *foo) __attribute__((weak, alias("other_function")));], 235 | [$1], [$2]) 236 | ]) 237 | 238 | AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ 239 | CC_CHECK_ATTRIBUTE( 240 | [malloc], , 241 | [void * __attribute__((malloc)) my_alloc(int n);], 242 | [$1], [$2]) 243 | ]) 244 | 245 | AC_DEFUN([CC_ATTRIBUTE_PACKED], [ 246 | CC_CHECK_ATTRIBUTE( 247 | [packed], , 248 | [struct astructure { char a; int b; long c; void *d; } __attribute__((packed)); 249 | char assert@<:@(sizeof(struct astructure) == (sizeof(char)+sizeof(int)+sizeof(long)+sizeof(void*)))-1@:>@;], 250 | [$1], [$2]) 251 | ]) 252 | 253 | AC_DEFUN([CC_ATTRIBUTE_CONST], [ 254 | CC_CHECK_ATTRIBUTE( 255 | [const], , 256 | [int __attribute__((const)) twopow(int n) { return 1 << n; } ], 257 | [$1], [$2]) 258 | ]) 259 | 260 | AC_DEFUN([CC_FLAG_VISIBILITY], [ 261 | AC_REQUIRE([CC_CHECK_WERROR]) 262 | AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], 263 | [cc_cv_flag_visibility], 264 | [cc_flag_visibility_save_CFLAGS="$CFLAGS" 265 | CFLAGS="$CFLAGS $cc_cv_werror" 266 | CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], 267 | cc_cv_flag_visibility='yes', 268 | cc_cv_flag_visibility='no') 269 | CFLAGS="$cc_flag_visibility_save_CFLAGS"]) 270 | 271 | AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], 272 | [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, 273 | [Define this if the compiler supports the -fvisibility flag]) 274 | $1], 275 | [$2]) 276 | ]) 277 | 278 | AC_DEFUN([CC_FUNC_EXPECT], [ 279 | AC_REQUIRE([CC_CHECK_WERROR]) 280 | AC_CACHE_CHECK([if compiler has __builtin_expect function], 281 | [cc_cv_func_expect], 282 | [ac_save_CFLAGS="$CFLAGS" 283 | CFLAGS="$CFLAGS $cc_cv_werror" 284 | AC_COMPILE_IFELSE([AC_LANG_SOURCE( 285 | [int some_function() { 286 | int a = 3; 287 | return (int)__builtin_expect(a, 3); 288 | }])], 289 | [cc_cv_func_expect=yes], 290 | [cc_cv_func_expect=no]) 291 | CFLAGS="$ac_save_CFLAGS" 292 | ]) 293 | 294 | AS_IF([test "x$cc_cv_func_expect" = "xyes"], 295 | [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, 296 | [Define this if the compiler supports __builtin_expect() function]) 297 | $1], 298 | [$2]) 299 | ]) 300 | 301 | AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ 302 | AC_REQUIRE([CC_CHECK_WERROR]) 303 | AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], 304 | [cc_cv_attribute_aligned], 305 | [ac_save_CFLAGS="$CFLAGS" 306 | CFLAGS="$CFLAGS $cc_cv_werror" 307 | for cc_attribute_align_try in 64 32 16 8 4 2; do 308 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([ 309 | int main(void) { 310 | static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; 311 | return c; 312 | }])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) 313 | done 314 | CFLAGS="$ac_save_CFLAGS" 315 | ]) 316 | 317 | if test "x$cc_cv_attribute_aligned" != "x"; then 318 | AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], 319 | [Define the highest alignment supported]) 320 | fi 321 | ]) 322 | -------------------------------------------------------------------------------- /src/arch.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2003 Jean-Marc Valin */ 2 | /** 3 | @file arch.h 4 | @brief Various architecture definitions Speex 5 | */ 6 | /* 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | - Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | - Neither the name of the Xiph.org Foundation nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef ARCH_H 36 | #define ARCH_H 37 | 38 | /* A couple test to catch stupid option combinations */ 39 | #ifdef FIXED_POINT 40 | 41 | #if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM)) 42 | #error Make up your mind. What CPU do you have? 43 | #endif 44 | 45 | #else 46 | 47 | #if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM) 48 | #error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions? 49 | #endif 50 | 51 | #endif 52 | 53 | #ifndef OUTSIDE_SPEEX 54 | #include "speex/speexdsp_types.h" 55 | #endif 56 | 57 | #define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ 58 | #define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ 59 | #define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */ 60 | #define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ 61 | #define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ 62 | #define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */ 63 | #define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ 64 | 65 | #ifdef FIXED_POINT 66 | 67 | typedef spx_int16_t spx_word16_t; 68 | typedef spx_int32_t spx_word32_t; 69 | typedef spx_word32_t spx_mem_t; 70 | typedef spx_word16_t spx_coef_t; 71 | typedef spx_word16_t spx_lsp_t; 72 | typedef spx_word32_t spx_sig_t; 73 | 74 | #define Q15ONE 32767 75 | 76 | #define LPC_SCALING 8192 77 | #define SIG_SCALING 16384 78 | #define LSP_SCALING 8192. 79 | #define GAMMA_SCALING 32768. 80 | #define GAIN_SCALING 64 81 | #define GAIN_SCALING_1 0.015625 82 | 83 | #define LPC_SHIFT 13 84 | #define LSP_SHIFT 13 85 | #define SIG_SHIFT 14 86 | #define GAIN_SHIFT 6 87 | 88 | #define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) 89 | 90 | #define VERY_SMALL 0 91 | #define VERY_LARGE32 ((spx_word32_t)2147483647) 92 | #define VERY_LARGE16 ((spx_word16_t)32767) 93 | #define Q15_ONE ((spx_word16_t)32767) 94 | 95 | 96 | #ifdef FIXED_DEBUG 97 | #include "fixed_debug.h" 98 | #else 99 | 100 | #include "fixed_generic.h" 101 | 102 | #ifdef ARM5E_ASM 103 | #include "fixed_arm5e.h" 104 | #elif defined (ARM4_ASM) 105 | #include "fixed_arm4.h" 106 | #elif defined (BFIN_ASM) 107 | #include "fixed_bfin.h" 108 | #endif 109 | 110 | #endif 111 | 112 | 113 | #else 114 | 115 | typedef float spx_mem_t; 116 | typedef float spx_coef_t; 117 | typedef float spx_lsp_t; 118 | typedef float spx_sig_t; 119 | typedef float spx_word16_t; 120 | typedef float spx_word32_t; 121 | 122 | #define Q15ONE 1.0f 123 | #define LPC_SCALING 1.f 124 | #define SIG_SCALING 1.f 125 | #define LSP_SCALING 1.f 126 | #define GAMMA_SCALING 1.f 127 | #define GAIN_SCALING 1.f 128 | #define GAIN_SCALING_1 1.f 129 | 130 | 131 | #define VERY_SMALL 1e-15f 132 | #define VERY_LARGE32 1e15f 133 | #define VERY_LARGE16 1e15f 134 | #define Q15_ONE ((spx_word16_t)1.f) 135 | 136 | #define QCONST16(x,bits) (x) 137 | #define QCONST32(x,bits) (x) 138 | 139 | #define NEG16(x) (-(x)) 140 | #define NEG32(x) (-(x)) 141 | #define EXTRACT16(x) (x) 142 | #define EXTEND32(x) (x) 143 | #define SHR16(a,shift) (a) 144 | #define SHL16(a,shift) (a) 145 | #define SHR32(a,shift) (a) 146 | #define SHL32(a,shift) (a) 147 | #define PSHR16(a,shift) (a) 148 | #define PSHR32(a,shift) (a) 149 | #define VSHR32(a,shift) (a) 150 | #define SATURATE16(x,a) (x) 151 | #define SATURATE32(x,a) (x) 152 | #define SATURATE32PSHR(x,shift,a) (x) 153 | 154 | #define PSHR(a,shift) (a) 155 | #define SHR(a,shift) (a) 156 | #define SHL(a,shift) (a) 157 | #define SATURATE(x,a) (x) 158 | 159 | #define ADD16(a,b) ((a)+(b)) 160 | #define SUB16(a,b) ((a)-(b)) 161 | #define ADD32(a,b) ((a)+(b)) 162 | #define SUB32(a,b) ((a)-(b)) 163 | #define MULT16_16_16(a,b) ((a)*(b)) 164 | #define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b)) 165 | #define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b)) 166 | 167 | #define MULT16_32_Q11(a,b) ((a)*(b)) 168 | #define MULT16_32_Q13(a,b) ((a)*(b)) 169 | #define MULT16_32_Q14(a,b) ((a)*(b)) 170 | #define MULT16_32_Q15(a,b) ((a)*(b)) 171 | #define MULT16_32_P15(a,b) ((a)*(b)) 172 | 173 | #define MAC16_32_Q11(c,a,b) ((c)+(a)*(b)) 174 | #define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) 175 | 176 | #define MAC16_16_Q11(c,a,b) ((c)+(a)*(b)) 177 | #define MAC16_16_Q13(c,a,b) ((c)+(a)*(b)) 178 | #define MAC16_16_P13(c,a,b) ((c)+(a)*(b)) 179 | #define MULT16_16_Q11_32(a,b) ((a)*(b)) 180 | #define MULT16_16_Q13(a,b) ((a)*(b)) 181 | #define MULT16_16_Q14(a,b) ((a)*(b)) 182 | #define MULT16_16_Q15(a,b) ((a)*(b)) 183 | #define MULT16_16_P15(a,b) ((a)*(b)) 184 | #define MULT16_16_P13(a,b) ((a)*(b)) 185 | #define MULT16_16_P14(a,b) ((a)*(b)) 186 | 187 | #define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) 188 | #define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b)) 189 | #define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) 190 | #define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b)) 191 | 192 | #define WORD2INT(x) ((x) < -32767.5f ? -32768 : \ 193 | ((x) > 32766.5f ? 32767 : (spx_int16_t)floor(.5 + (x)))) 194 | #endif 195 | 196 | 197 | #if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) 198 | 199 | /* 2 on TI C5x DSP */ 200 | #define BYTES_PER_CHAR 2 201 | #define BITS_PER_CHAR 16 202 | #define LOG2_BITS_PER_CHAR 4 203 | 204 | #else 205 | 206 | #define BYTES_PER_CHAR 1 207 | #define BITS_PER_CHAR 8 208 | #define LOG2_BITS_PER_CHAR 3 209 | 210 | #endif 211 | 212 | 213 | 214 | #ifdef FIXED_DEBUG 215 | extern long long spx_mips; 216 | #endif 217 | 218 | 219 | #endif 220 | -------------------------------------------------------------------------------- /src/ogg_packer.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017 Jean-Marc Valin 2 | Copyright (c) 1994-2010 Xiph.Org Foundation */ 3 | /* 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 19 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include "ogg_packer.h" 34 | 35 | #define MAX_HEADER_SIZE (27+255) 36 | 37 | #define MAX_PAGE_SIZE (255*255 + MAX_HEADER_SIZE) 38 | 39 | static const oggp_uint32 crc_lookup[256]={ 40 | 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9, 41 | 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, 42 | 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61, 43 | 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, 44 | 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9, 45 | 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, 46 | 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011, 47 | 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, 48 | 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039, 49 | 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, 50 | 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81, 51 | 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, 52 | 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49, 53 | 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, 54 | 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1, 55 | 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, 56 | 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae, 57 | 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, 58 | 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16, 59 | 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, 60 | 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde, 61 | 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, 62 | 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066, 63 | 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, 64 | 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e, 65 | 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, 66 | 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6, 67 | 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, 68 | 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e, 69 | 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, 70 | 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686, 71 | 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, 72 | 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637, 73 | 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, 74 | 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f, 75 | 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, 76 | 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47, 77 | 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, 78 | 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff, 79 | 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, 80 | 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7, 81 | 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, 82 | 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f, 83 | 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, 84 | 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7, 85 | 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, 86 | 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f, 87 | 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, 88 | 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640, 89 | 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, 90 | 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8, 91 | 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, 92 | 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30, 93 | 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, 94 | 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088, 95 | 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, 96 | 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0, 97 | 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, 98 | 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18, 99 | 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, 100 | 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0, 101 | 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, 102 | 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668, 103 | 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}; 104 | 105 | static void ogg_page_checksum_set(unsigned char *page, oggp_int32 len){ 106 | oggp_uint32 crc_reg=0; 107 | oggp_int32 i; 108 | 109 | /* safety; needed for API behavior, but not framing code */ 110 | page[22]=0; 111 | page[23]=0; 112 | page[24]=0; 113 | page[25]=0; 114 | 115 | for(i=0;i> 24)&0xff)^page[i]]; 116 | 117 | page[22]=(unsigned char)(crc_reg&0xff); 118 | page[23]=(unsigned char)((crc_reg>>8)&0xff); 119 | page[24]=(unsigned char)((crc_reg>>16)&0xff); 120 | page[25]=(unsigned char)((crc_reg>>24)&0xff); 121 | } 122 | 123 | typedef struct { 124 | oggp_uint64 granulepos; 125 | size_t buf_pos; 126 | size_t buf_size; 127 | size_t lacing_pos; 128 | size_t lacing_size; 129 | int flags; 130 | size_t pageno; 131 | } oggp_page; 132 | 133 | struct oggpacker { 134 | oggp_int32 serialno; 135 | unsigned char *buf; 136 | unsigned char *alloc_buf; 137 | unsigned char *user_buf; 138 | size_t buf_size; 139 | size_t buf_fill; 140 | size_t buf_begin; 141 | unsigned char *lacing; 142 | size_t lacing_size; 143 | size_t lacing_fill; 144 | size_t lacing_begin; 145 | oggp_page *pages; 146 | size_t pages_size; 147 | size_t pages_fill; 148 | oggp_uint64 muxing_delay; 149 | int is_eos; 150 | oggp_uint64 curr_granule; 151 | oggp_uint64 last_granule; 152 | size_t pageno; 153 | }; 154 | 155 | /** Allocates an oggpacker object */ 156 | oggpacker *oggp_create(oggp_int32 serialno) { 157 | oggpacker *oggp; 158 | oggp = malloc(sizeof(*oggp)); 159 | if (oggp == NULL) goto fail; 160 | oggp->alloc_buf = NULL; 161 | oggp->lacing = NULL; 162 | oggp->pages = NULL; 163 | oggp->user_buf = NULL; 164 | 165 | oggp->buf_size = MAX_PAGE_SIZE; 166 | oggp->lacing_size = 256; 167 | oggp->pages_size = 10; 168 | 169 | oggp->alloc_buf = malloc(oggp->buf_size + MAX_HEADER_SIZE); 170 | oggp->lacing = malloc(oggp->lacing_size); 171 | oggp->pages = malloc(oggp->pages_size * sizeof(oggp->pages[0])); 172 | if (!oggp->alloc_buf || !oggp->lacing || !oggp->pages) goto fail; 173 | oggp->buf = oggp->alloc_buf + MAX_HEADER_SIZE; 174 | 175 | oggp->serialno = serialno; 176 | oggp->buf_fill = 0; 177 | oggp->buf_begin = 0; 178 | oggp->lacing_fill = 0; 179 | oggp->lacing_begin = 0; 180 | oggp->pages_fill = 0; 181 | 182 | oggp->is_eos = 0; 183 | oggp->curr_granule = 0; 184 | oggp->last_granule = 0; 185 | oggp->pageno = 0; 186 | oggp->muxing_delay = 0; 187 | return oggp; 188 | fail: 189 | if (oggp) { 190 | if (oggp->lacing) free(oggp->lacing); 191 | if (oggp->alloc_buf) free(oggp->alloc_buf); 192 | if (oggp->pages) free(oggp->pages); 193 | free(oggp); 194 | } 195 | return NULL; 196 | } 197 | 198 | /** Frees memory associated with an oggpacker object */ 199 | void oggp_destroy(oggpacker *oggp) { 200 | free(oggp->lacing); 201 | free(oggp->alloc_buf); 202 | free(oggp->pages); 203 | free(oggp); 204 | } 205 | 206 | /** Sets the maximum muxing delay in granulepos units. Pages will be auto-flushed 207 | to enforce the delay and to avoid continued pages if possible. */ 208 | void oggp_set_muxing_delay(oggpacker *oggp, oggp_uint64 delay) { 209 | oggp->muxing_delay = delay; 210 | } 211 | 212 | static void shift_buffer(oggpacker *oggp) { 213 | size_t buf_shift; 214 | size_t lacing_shift; 215 | size_t i; 216 | buf_shift = oggp->pages_fill ? oggp->pages[0].buf_pos : oggp->buf_begin; 217 | lacing_shift = oggp->pages_fill ? oggp->pages[0].lacing_pos : oggp->lacing_begin; 218 | if (4*lacing_shift > oggp->lacing_fill) { 219 | memmove(&oggp->lacing[0], &oggp->lacing[lacing_shift], oggp->lacing_fill-lacing_shift); 220 | for (i=0;ipages_fill;i++) oggp->pages[i].lacing_pos -= lacing_shift; 221 | oggp->lacing_fill -= lacing_shift; 222 | oggp->lacing_begin -= lacing_shift; 223 | } 224 | if (4*buf_shift > oggp->buf_fill) { 225 | memmove(&oggp->buf[0], &oggp->buf[buf_shift], oggp->buf_fill-buf_shift); 226 | for (i=0;ipages_fill;i++) oggp->pages[i].buf_pos -= buf_shift; 227 | oggp->buf_fill -= buf_shift; 228 | oggp->buf_begin -= buf_shift; 229 | } 230 | } 231 | 232 | /** Get a buffer where to write the next packet. The buffer will have 233 | size "bytes", but fewer bytes can be written. The buffer remains valid through 234 | a call to oggp_close_page() or oggp_get_next_page(), but is invalidated by 235 | another call to oggp_get_packet_buffer() or by a call to oggp_commit_packet(). */ 236 | unsigned char *oggp_get_packet_buffer(oggpacker *oggp, oggp_int32 bytes) { 237 | if (oggp->buf_fill + bytes > oggp->buf_size) { 238 | shift_buffer(oggp); 239 | 240 | /* If we didn't shift the buffer or if we did and there's still not enough room, make some more. */ 241 | if (oggp->buf_fill + bytes > oggp->buf_size) { 242 | size_t newsize; 243 | unsigned char *newbuf; 244 | newsize = oggp->buf_fill + bytes + MAX_HEADER_SIZE; 245 | /* Making sure we don't need to do that too often. */ 246 | newsize = newsize*3/2; 247 | newbuf = realloc(oggp->alloc_buf, newsize); 248 | if (newbuf != NULL) { 249 | oggp->alloc_buf = newbuf; 250 | oggp->buf_size = newsize; 251 | oggp->buf = oggp->alloc_buf + MAX_HEADER_SIZE; 252 | } else { 253 | return NULL; 254 | } 255 | } 256 | } 257 | oggp->user_buf = &oggp->buf[oggp->buf_fill]; 258 | return oggp->user_buf; 259 | } 260 | 261 | /** Tells the oggpacker that the packet buffer obtained from 262 | oggp_get_packet_buffer() has been filled and the number of bytes written 263 | has to be no more than what was originally asked for. */ 264 | int oggp_commit_packet(oggpacker *oggp, oggp_int32 bytes, oggp_uint64 granulepos, int eos) { 265 | size_t i; 266 | size_t nb_255s; 267 | assert(oggp->user_buf != NULL); 268 | nb_255s = bytes/255; 269 | if (oggp->lacing_fill-oggp->lacing_begin+nb_255s+1 > 255 || 270 | (oggp->muxing_delay && granulepos - oggp->last_granule > oggp->muxing_delay)) { 271 | oggp_flush_page(oggp); 272 | } 273 | assert(oggp->user_buf >= &oggp->buf[oggp->buf_fill]); 274 | oggp->buf_fill += bytes; 275 | if (oggp->lacing_fill + nb_255s + 1 > oggp->lacing_size) { 276 | shift_buffer(oggp); 277 | 278 | /* If we didn't shift the values or if we did and there's still not enough room, make some more. */ 279 | if (oggp->lacing_fill + nb_255s + 1 > oggp->lacing_size) { 280 | size_t newsize; 281 | unsigned char *newbuf; 282 | newsize = oggp->lacing_fill + nb_255s + 1; 283 | /* Making sure we don't need to do that too often. */ 284 | newsize = newsize*3/2; 285 | newbuf = realloc(oggp->lacing, newsize); 286 | if (newbuf != NULL) { 287 | oggp->lacing = newbuf; 288 | oggp->lacing_size = newsize; 289 | } else { 290 | return 1; 291 | } 292 | } 293 | } 294 | /* If we moved the buffer data, update the incoming packet location. */ 295 | if (oggp->user_buf > &oggp->buf[oggp->buf_fill]) { 296 | memmove(&oggp->buf[oggp->buf_fill], oggp->user_buf, bytes); 297 | } 298 | for (i=0;ilacing[oggp->lacing_fill+i] = 255; 300 | } 301 | oggp->lacing[oggp->lacing_fill+nb_255s] = bytes - 255*nb_255s; 302 | oggp->lacing_fill += nb_255s + 1; 303 | oggp->curr_granule = granulepos; 304 | oggp->is_eos = eos; 305 | if (oggp->muxing_delay && granulepos - oggp->last_granule >= oggp->muxing_delay) { 306 | oggp_flush_page(oggp); 307 | } 308 | return 0; 309 | } 310 | 311 | /** Create a page from the data written so far (and not yet part of a previous page). 312 | If there is too much data for one page, all page continuations will be closed too. */ 313 | int oggp_flush_page(oggpacker *oggp) { 314 | oggp_page *p; 315 | int cont = 0; 316 | size_t nb_lacing; 317 | if (oggp->lacing_fill == oggp->lacing_begin) { 318 | return 1; 319 | } 320 | nb_lacing = oggp->lacing_fill - oggp->lacing_begin; 321 | do { 322 | if (oggp->pages_fill >= oggp->pages_size) { 323 | size_t newsize; 324 | oggp_page *newbuf; 325 | /* Making sure we don't need to do that too often. */ 326 | newsize = 1 + oggp->pages_size*3/2; 327 | newbuf = realloc(oggp->pages, newsize*sizeof(oggp_page)); 328 | assert(newbuf != NULL); 329 | oggp->pages = newbuf; 330 | oggp->pages_size = newsize; 331 | } 332 | p = &oggp->pages[oggp->pages_fill++]; 333 | p->granulepos = oggp->curr_granule; 334 | 335 | p->lacing_pos = oggp->lacing_begin; 336 | p->lacing_size = nb_lacing; 337 | p->flags = cont; 338 | p->buf_pos = oggp->buf_begin; 339 | if (p->lacing_size > 255) { 340 | size_t bytes=0; 341 | int i; 342 | for (i=0;i<255;i++) bytes += oggp->lacing[oggp->lacing_begin+1]; 343 | p->buf_size = bytes; 344 | p->lacing_size = 255; 345 | p->granulepos = -1; 346 | cont = 1; 347 | } else { 348 | p->buf_size = oggp->buf_fill - oggp->buf_begin; 349 | if (oggp->is_eos) p->flags |= 0x04; 350 | } 351 | nb_lacing -= p->lacing_size; 352 | oggp->lacing_begin += p->lacing_size; 353 | oggp->buf_begin += p->buf_size; 354 | p->pageno = oggp->pageno++; 355 | if (p->pageno == 0) 356 | p->flags |= 0x02; 357 | } while (nb_lacing>0); 358 | 359 | oggp->last_granule = oggp->curr_granule; 360 | return 0; 361 | } 362 | 363 | /** Get a pointer to the contents of the next available page. Pointer is 364 | invalidated on the next call to oggp_get_next_page() or oggp_commit_packet(). */ 365 | int oggp_get_next_page(oggpacker *oggp, unsigned char **page, oggp_int32 *bytes) { 366 | oggp_page *p; 367 | int i; 368 | unsigned char *ptr; 369 | size_t len; 370 | int header_size; 371 | oggp_uint64 granule_pos; 372 | if (oggp->pages_fill == 0) { 373 | *page = NULL; 374 | *bytes = 0; 375 | return 0; 376 | } 377 | p = &oggp->pages[0]; 378 | header_size = 27 + p->lacing_size; 379 | /* Don't use indexing in case header_size > p->buf_pos. */ 380 | ptr = oggp->buf + p->buf_pos - header_size; 381 | len = p->buf_size + header_size; 382 | memcpy(&ptr[27], &oggp->lacing[p->lacing_pos], p->lacing_size); 383 | memcpy(ptr, "OggS", 4); 384 | 385 | /* stream structure version */ 386 | ptr[4]=0x00; 387 | 388 | ptr[5]=0x00 | p->flags; 389 | 390 | granule_pos = p->granulepos; 391 | /* 64 bits of PCM position */ 392 | for(i=6;i<14;i++){ 393 | ptr[i]=(unsigned char)(granule_pos&0xff); 394 | granule_pos>>=8; 395 | } 396 | 397 | /* 32 bits of stream serial number */ 398 | { 399 | oggp_int32 serialno=oggp->serialno; 400 | for(i=14;i<18;i++){ 401 | ptr[i]=(unsigned char)(serialno&0xff); 402 | serialno>>=8; 403 | } 404 | } 405 | 406 | { 407 | oggp_int32 pageno=p->pageno; 408 | for(i=18;i<22;i++){ 409 | ptr[i]=(unsigned char)(pageno&0xff); 410 | pageno>>=8; 411 | } 412 | } 413 | 414 | ptr[26] = p->lacing_size; 415 | 416 | /* CRC is always last. */ 417 | ogg_page_checksum_set(ptr, len); 418 | 419 | *page = ptr; 420 | *bytes = len; 421 | oggp->pages_fill--; 422 | memmove(&oggp->pages[0], &oggp->pages[1], oggp->pages_fill*sizeof(oggp_page)); 423 | return 1; 424 | } 425 | 426 | /** Creates a new (chained) stream. This closes all outstanding pages. These 427 | pages remain available with oggp_get_next_page(). */ 428 | int oggp_chain(oggpacker *oggp, oggp_int32 serialno) { 429 | oggp_flush_page(oggp); 430 | oggp->serialno = serialno; 431 | oggp->curr_granule = 0; 432 | oggp->last_granule = 0; 433 | oggp->is_eos = 0; 434 | oggp->pageno = 0; 435 | return 0; 436 | } 437 | -------------------------------------------------------------------------------- /src/ogg_packer.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2017 Jean-Marc Valin */ 2 | /* 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | - Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | - Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 18 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef OGGPACKER_H 28 | # define OGGPACKER_H 29 | 30 | 31 | # if defined(__cplusplus) 32 | extern "C" { 33 | # endif 34 | 35 | typedef unsigned long long oggp_uint64; 36 | typedef unsigned oggp_uint32; 37 | typedef int oggp_int32; 38 | 39 | typedef struct oggpacker oggpacker; 40 | 41 | /** Allocates an oggpacker object */ 42 | oggpacker *oggp_create(oggp_int32 serialno); 43 | 44 | /** Frees memory associated with an oggpacker object */ 45 | void oggp_destroy(oggpacker *oggp); 46 | 47 | /** Sets the maximum muxing delay in granulepos units. Pages will be auto-flushed 48 | to enforce the delay and to avoid continued pages if possible. */ 49 | void oggp_set_muxing_delay(oggpacker *oggp, oggp_uint64 delay); 50 | 51 | /** Get a buffer where to write the next packet. The buffer will have 52 | size "bytes", but fewer bytes can be written. The buffer remains valid through 53 | a call to oggp_close_page() or oggp_get_next_page(), but is invalidated by 54 | another call to oggp_get_packet_buffer() or by a call to oggp_commit_packet(). */ 55 | unsigned char *oggp_get_packet_buffer(oggpacker *oggp, oggp_int32 bytes); 56 | 57 | /** Tells the oggpacker that the packet buffer obtained from 58 | oggp_get_packet_buffer() has been filled and the number of bytes written 59 | has to be no more than what was originally asked for. */ 60 | int oggp_commit_packet(oggpacker *oggp, oggp_int32 bytes, oggp_uint64 granulepos, int eos); 61 | 62 | /** Create a page from the data written so far (and not yet part of a previous page). 63 | If there is too much data for one page, then all page continuations will be closed too. */ 64 | int oggp_flush_page(oggpacker *oggp); 65 | 66 | /** Get a pointer to the contents of the next available page. Pointer is 67 | invalidated on the next call to oggp_get_next_page() or oggp_commit_packet(). */ 68 | int oggp_get_next_page(oggpacker *oggp, unsigned char **page, oggp_int32 *bytes); 69 | 70 | /** Creates a new (chained) stream. This closes all outstanding pages. These 71 | pages remain available with oggp_get_next_page(). */ 72 | int oggp_chain(oggpacker *oggp, oggp_int32 serialno); 73 | 74 | # if defined(__cplusplus) 75 | } 76 | # endif 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /src/opus_header.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C)2012 Xiph.Org Foundation 2 | File: opus_header.c 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 19 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifdef HAVE_CONFIG_H 29 | # include "config.h" 30 | #endif 31 | 32 | #include "opus_header.h" 33 | #include 34 | #include 35 | 36 | /* Header contents: 37 | - "OpusHead" (64 bits) 38 | - version number (8 bits) 39 | - Channels C (8 bits) 40 | - Pre-skip (16 bits) 41 | - Sampling rate (32 bits) 42 | - Gain in dB (16 bits, S7.8) 43 | - Mapping (8 bits, 0=single stream (mono/stereo) 1=Vorbis mapping, 44 | 2=ambisonics, 3=projection ambisonics, 4..239: reserved, 45 | 240..254: experiments, 255: multistream with no mapping) 46 | 47 | - if (mapping != 0) 48 | - N = total number of streams (8 bits) 49 | - M = number of paired streams (8 bits) 50 | - if (mapping != a projection family) 51 | - C times channel origin 52 | - if (C<2*M) 53 | - stream = byte/2 54 | - if (byte&0x1 == 0) 55 | - left 56 | else 57 | - right 58 | - else 59 | - stream = byte-M 60 | - else 61 | - D demixing matrix (C*(N+M)*16 bits) 62 | */ 63 | 64 | typedef struct { 65 | unsigned char *data; 66 | int maxlen; 67 | int pos; 68 | } Packet; 69 | 70 | static int write_uint32(Packet *p, opus_uint32 val) 71 | { 72 | if (p->pos>p->maxlen-4) 73 | return 0; 74 | p->data[p->pos ] = (val ) & 0xFF; 75 | p->data[p->pos+1] = (val>> 8) & 0xFF; 76 | p->data[p->pos+2] = (val>>16) & 0xFF; 77 | p->data[p->pos+3] = (val>>24) & 0xFF; 78 | p->pos += 4; 79 | return 1; 80 | } 81 | 82 | static int write_uint16(Packet *p, opus_uint16 val) 83 | { 84 | if (p->pos>p->maxlen-2) 85 | return 0; 86 | p->data[p->pos ] = (val ) & 0xFF; 87 | p->data[p->pos+1] = (val>> 8) & 0xFF; 88 | p->pos += 2; 89 | return 1; 90 | } 91 | 92 | static int write_chars(Packet *p, const unsigned char *str, int nb_chars) 93 | { 94 | int i; 95 | if (p->pos>p->maxlen-nb_chars) 96 | return 0; 97 | for (i=0;idata[p->pos++] = str[i]; 99 | return 1; 100 | } 101 | 102 | static int write_matrix_chars(Packet *p, const OpusGenericEncoder *st) 103 | { 104 | #ifdef OPUS_HAVE_OPUS_PROJECTION_H 105 | opus_int32 size; 106 | int ret; 107 | ret=opeint_encoder_ctl(st, OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE(&size)); 108 | if (ret != OPUS_OK) return 0; 109 | if (size>p->maxlen-p->pos) return 0; 110 | ret=opeint_encoder_ctl(st, OPUS_PROJECTION_GET_DEMIXING_MATRIX(&p->data[p->pos], size)); 111 | if (ret != OPUS_OK) return 0; 112 | p->pos += size; 113 | return 1; 114 | #else 115 | (void)p; 116 | (void)st; 117 | return 0; 118 | #endif 119 | } 120 | 121 | int opeint_opus_header_get_size(const OpusHeader *h) 122 | { 123 | int len=0; 124 | if (opeint_use_projection(h->channel_mapping)) 125 | { 126 | /* 19 bytes from fixed header, 127 | * 2 bytes for nb_streams & nb_coupled, 128 | * 2 bytes per cell of demixing matrix, where: 129 | * rows=channels, cols=nb_streams+nb_coupled 130 | */ 131 | len=21+(h->channels*(h->nb_streams+h->nb_coupled)*2); 132 | } 133 | else 134 | { 135 | /* 19 bytes from fixed header, 136 | * 2 bytes for nb_streams & nb_coupled, 137 | * 1 byte per channel 138 | */ 139 | len=21+h->channels; 140 | } 141 | return len; 142 | } 143 | 144 | int opeint_opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len, const OpusGenericEncoder *st) 145 | { 146 | int i; 147 | Packet p; 148 | unsigned char ch; 149 | 150 | p.data = packet; 151 | p.maxlen = len; 152 | p.pos = 0; 153 | if (len<19)return 0; 154 | if (!write_chars(&p, (const unsigned char*)"OpusHead", 8)) 155 | return 0; 156 | /* Version is 1 */ 157 | ch = 1; 158 | if (!write_chars(&p, &ch, 1)) 159 | return 0; 160 | 161 | ch = h->channels; 162 | if (!write_chars(&p, &ch, 1)) 163 | return 0; 164 | 165 | if (!write_uint16(&p, h->preskip)) 166 | return 0; 167 | 168 | if (!write_uint32(&p, h->input_sample_rate)) 169 | return 0; 170 | 171 | if (opeint_use_projection(h->channel_mapping)) 172 | { 173 | #ifdef OPUS_HAVE_OPUS_PROJECTION_H 174 | opus_int32 matrix_gain; 175 | int ret; 176 | ret=opeint_encoder_ctl(st, OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN(&matrix_gain)); 177 | if (ret != OPUS_OK) return 0; 178 | if (!write_uint16(&p, h->gain + matrix_gain)) 179 | return 0; 180 | #else 181 | return 0; 182 | #endif 183 | } 184 | else 185 | { 186 | if (!write_uint16(&p, h->gain)) 187 | return 0; 188 | } 189 | 190 | ch = h->channel_mapping; 191 | if (!write_chars(&p, &ch, 1)) 192 | return 0; 193 | 194 | if (h->channel_mapping != 0) 195 | { 196 | ch = h->nb_streams; 197 | if (!write_chars(&p, &ch, 1)) 198 | return 0; 199 | 200 | ch = h->nb_coupled; 201 | if (!write_chars(&p, &ch, 1)) 202 | return 0; 203 | 204 | /* Multi-stream support */ 205 | if (opeint_use_projection(h->channel_mapping)) 206 | { 207 | if (!write_matrix_chars(&p, st)) 208 | return 0; 209 | } 210 | else 211 | { 212 | for (i=0;ichannels;i++) 213 | { 214 | if (!write_chars(&p, &h->stream_map[i], 1)) 215 | return 0; 216 | } 217 | } 218 | } 219 | 220 | return p.pos; 221 | } 222 | 223 | /* 224 | Comments will be stored in the Vorbis style. 225 | It is described in the "Structure" section of 226 | http://www.xiph.org/ogg/vorbis/doc/v-comment.html 227 | 228 | However, Opus and other non-vorbis formats omit the "framing_bit". 229 | 230 | The comment header is decoded as follows: 231 | 1) [vendor_length] = read an unsigned integer of 32 bits 232 | 2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets 233 | 3) [user_comment_list_length] = read an unsigned integer of 32 bits 234 | 4) iterate [user_comment_list_length] times { 235 | 5) [length] = read an unsigned integer of 32 bits 236 | 6) this iteration's user comment = read a UTF-8 vector as [length] octets 237 | } 238 | 7) done. 239 | */ 240 | 241 | #define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \ 242 | ((buf[base+2]<<16)&0xff0000)| \ 243 | ((buf[base+1]<<8)&0xff00)| \ 244 | (buf[base]&0xff)) 245 | #define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \ 246 | buf[base+2]=((val)>>16)&0xff; \ 247 | buf[base+1]=((val)>>8)&0xff; \ 248 | buf[base]=(val)&0xff; \ 249 | }while(0) 250 | 251 | void opeint_comment_init(char **comments, int* length, const char *vendor_string) 252 | { 253 | /*The 'vendor' field should be the actual encoding library used.*/ 254 | int vendor_length=strlen(vendor_string); 255 | int user_comment_list_length=0; 256 | int len=8+4+vendor_length+4; 257 | char *p=(char*)malloc(len); 258 | if (p == NULL) { 259 | len=0; 260 | } else { 261 | memcpy(p, "OpusTags", 8); 262 | writeint(p, 8, vendor_length); 263 | memcpy(p+12, vendor_string, vendor_length); 264 | writeint(p, 12+vendor_length, user_comment_list_length); 265 | } 266 | *length=len; 267 | *comments=p; 268 | } 269 | 270 | int opeint_comment_add(char **comments, int* length, const char *tag, const char *val) 271 | { 272 | char* p=*comments; 273 | int vendor_length=readint(p, 8); 274 | int user_comment_list_length=readint(p, 8+4+vendor_length); 275 | int tag_len=(tag?strlen(tag)+1:0); 276 | int val_len=strlen(val); 277 | int len=(*length)+4+tag_len+val_len; 278 | 279 | p=(char*)realloc(p, len); 280 | if (p == NULL) return 1; 281 | 282 | writeint(p, *length, tag_len+val_len); /* length of comment */ 283 | if(tag){ 284 | memcpy(p+*length+4, tag, tag_len); /* comment tag */ 285 | (p+*length+4)[tag_len-1] = '='; /* separator */ 286 | } 287 | memcpy(p+*length+4+tag_len, val, val_len); /* comment */ 288 | writeint(p, 8+4+vendor_length, user_comment_list_length+1); 289 | *comments=p; 290 | *length=len; 291 | return 0; 292 | } 293 | 294 | void opeint_comment_pad(char **comments, int* length, int amount) 295 | { 296 | if(amount>0){ 297 | int i; 298 | int newlen; 299 | char* p=*comments; 300 | /*Make sure there is at least amount worth of padding free, and 301 | round up to the maximum that fits in the current ogg segments.*/ 302 | newlen=(*length+amount+255)/255*255-1; 303 | p=realloc(p,newlen); 304 | if (p == NULL) return; 305 | for(i=*length;i 32 | #include 33 | 34 | #include 35 | #ifdef OPUS_HAVE_OPUS_PROJECTION_H 36 | #include 37 | #endif 38 | 39 | typedef struct OpusGenericEncoder OpusGenericEncoder; 40 | struct OpusGenericEncoder { 41 | OpusMSEncoder *ms; 42 | #ifdef OPUS_HAVE_OPUS_PROJECTION_H 43 | OpusProjectionEncoder *pr; 44 | #endif 45 | }; 46 | 47 | int opeint_use_projection(int channel_mapping); 48 | 49 | int opeint_encoder_surround_init(OpusGenericEncoder *st, int Fs, int channels, int channel_mapping, int *nb_streams, int *nb_coupled, unsigned char *stream_map, int application); 50 | 51 | void opeint_encoder_cleanup(OpusGenericEncoder *st); 52 | 53 | int opeint_encoder_init(OpusGenericEncoder *st, opus_int32 Fs, int channels, int streams, int coupled_streams, const unsigned char *mapping, int application); 54 | 55 | int opeint_encode_float(OpusGenericEncoder *st, const float *pcm, int frame_size, unsigned char *data, opus_int32 max_data_bytes); 56 | 57 | #ifdef OPUS_HAVE_OPUS_PROJECTION_H 58 | # define opeint_encoder_ctl(st, request) \ 59 | ((st)->pr!=NULL ? \ 60 | opus_projection_encoder_ctl((st)->pr, request) : \ 61 | opus_multistream_encoder_ctl((st)->ms, request)) 62 | # define opeint_encoder_ctl2(st, request, value) \ 63 | ((st)->pr!=NULL ? \ 64 | opus_projection_encoder_ctl((st)->pr, request, value) : \ 65 | opus_multistream_encoder_ctl((st)->ms, request, value)) 66 | #else 67 | # define opeint_encoder_ctl(st, request) \ 68 | opus_multistream_encoder_ctl((st)->ms, request) 69 | # define opeint_encoder_ctl2(st, request, value) \ 70 | opus_multistream_encoder_ctl((st)->ms, request, value) 71 | #endif 72 | 73 | typedef struct { 74 | int version; 75 | int channels; /* Number of channels: 1..255 */ 76 | int preskip; 77 | opus_uint32 input_sample_rate; 78 | opus_int32 gain; /* in dB S7.8 should be zero whenever possible */ 79 | int channel_mapping; 80 | /* The rest is only used if channel_mapping != 0 */ 81 | int nb_streams; 82 | int nb_coupled; 83 | unsigned char stream_map[255]; 84 | } OpusHeader; 85 | 86 | int opeint_opus_header_get_size(const OpusHeader *h); 87 | 88 | int opeint_opus_header_to_packet(const OpusHeader *h, unsigned char *packet, int len, const OpusGenericEncoder *st); 89 | 90 | void opeint_comment_init(char **comments, int* length, const char *vendor_string); 91 | 92 | int opeint_comment_add(char **comments, int* length, const char *tag, const char *val); 93 | 94 | void opeint_comment_pad(char **comments, int* length, int amount); 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/picture.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C)2007-2013 Xiph.Org Foundation 2 | File: picture.c 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 19 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifdef HAVE_CONFIG_H 29 | # include "config.h" 30 | #endif 31 | 32 | #include 33 | #include 34 | #include 35 | #include "picture.h" 36 | #include "unicode_support.h" 37 | 38 | static const char BASE64_TABLE[64]={ 39 | 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 40 | 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 41 | 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 42 | 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' 43 | }; 44 | 45 | /*Utility function for base64 encoding METADATA_BLOCK_PICTURE tags. 46 | Stores BASE64_LENGTH(len)+1 bytes in dst (including a terminating NUL).*/ 47 | static void base64_encode(char *dst, const char *src, int len){ 48 | unsigned s0; 49 | unsigned s1; 50 | unsigned s2; 51 | int ngroups; 52 | int i; 53 | ngroups=len/3; 54 | for(i=0;i>2]; 59 | dst[4*i+1]=BASE64_TABLE[(s0&3)<<4|s1>>4]; 60 | dst[4*i+2]=BASE64_TABLE[(s1&15)<<2|s2>>6]; 61 | dst[4*i+3]=BASE64_TABLE[s2&63]; 62 | } 63 | len-=3*i; 64 | if(len==1){ 65 | s0=(unsigned char)src[3*i+0]; 66 | dst[4*i+0]=BASE64_TABLE[s0>>2]; 67 | dst[4*i+1]=BASE64_TABLE[(s0&3)<<4]; 68 | dst[4*i+2]='='; 69 | dst[4*i+3]='='; 70 | i++; 71 | } 72 | else if(len==2){ 73 | s0=(unsigned char)src[3*i+0]; 74 | s1=(unsigned char)src[3*i+1]; 75 | dst[4*i+0]=BASE64_TABLE[s0>>2]; 76 | dst[4*i+1]=BASE64_TABLE[(s0&3)<<4|s1>>4]; 77 | dst[4*i+2]=BASE64_TABLE[(s1&15)<<2]; 78 | dst[4*i+3]='='; 79 | i++; 80 | } 81 | dst[4*i]='\0'; 82 | } 83 | 84 | /*A version of strncasecmp() that is guaranteed to only ignore the case of 85 | ASCII characters.*/ 86 | static int oi_strncasecmp(const char *a, const char *b, int n){ 87 | int i; 88 | for(i=0;i='a'&&aval<='z') { 95 | aval-='a'-'A'; 96 | } 97 | if(bval>='a'&&bval<='z'){ 98 | bval-='a'-'A'; 99 | } 100 | diff=aval-bval; 101 | if(diff){ 102 | return diff; 103 | } 104 | } 105 | return 0; 106 | } 107 | 108 | static int is_jpeg(const unsigned char *buf, size_t length){ 109 | return length>=3&&memcmp(buf,"\xFF\xD8\xFF",3)==0; 110 | } 111 | 112 | static int is_png(const unsigned char *buf, size_t length){ 113 | return length>=8&&memcmp(buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0; 114 | } 115 | 116 | static int is_gif(const unsigned char *buf, size_t length){ 117 | return length>=6 118 | &&(memcmp(buf,"GIF87a",6)==0||memcmp(buf,"GIF89a",6)==0); 119 | } 120 | 121 | #define READ_U32_BE(buf) \ 122 | (((opus_uint32)(buf)[0]<<24)|((buf)[1]<<16)|((buf)[2]<<8)|(buf)[3]) 123 | 124 | /*Tries to extract the width, height, bits per pixel, and palette size of a 125 | PNG. 126 | On failure, simply leaves its outputs unmodified.*/ 127 | static void extract_png_params(const unsigned char *data, size_t data_length, 128 | opus_uint32 *width, opus_uint32 *height, 129 | opus_uint32 *depth, opus_uint32 *colors, 130 | int *has_palette){ 131 | if(is_png(data,data_length)){ 132 | size_t offs; 133 | offs=8; 134 | while(data_length-offs>=12){ 135 | opus_uint32 chunk_len; 136 | chunk_len=READ_U32_BE(data+offs); 137 | if(chunk_len>data_length-(offs+12))break; 138 | else if(chunk_len==13&&memcmp(data+offs+4,"IHDR",4)==0){ 139 | int color_type; 140 | *width=READ_U32_BE(data+offs+8); 141 | *height=READ_U32_BE(data+offs+12); 142 | color_type=data[offs+17]; 143 | if(color_type==3){ 144 | *depth=24; 145 | *has_palette=1; 146 | } 147 | else{ 148 | int sample_depth; 149 | sample_depth=data[offs+16]; 150 | if(color_type==0)*depth=sample_depth; 151 | else if(color_type==2)*depth=sample_depth*3; 152 | else if(color_type==4)*depth=sample_depth*2; 153 | else if(color_type==6)*depth=sample_depth*4; 154 | *colors=0; 155 | *has_palette=0; 156 | break; 157 | } 158 | } 159 | else if(*has_palette>0&&memcmp(data+offs+4,"PLTE",4)==0){ 160 | *colors=chunk_len/3; 161 | break; 162 | } 163 | offs+=12+chunk_len; 164 | } 165 | } 166 | } 167 | 168 | /*Tries to extract the width, height, bits per pixel, and palette size of a 169 | GIF. 170 | On failure, simply leaves its outputs unmodified.*/ 171 | static void extract_gif_params(const unsigned char *data, size_t data_length, 172 | opus_uint32 *width, opus_uint32 *height, 173 | opus_uint32 *depth, opus_uint32 *colors, 174 | int *has_palette){ 175 | if(is_gif(data,data_length)&&data_length>=14){ 176 | *width=data[6]|data[7]<<8; 177 | *height=data[8]|data[9]<<8; 178 | /*libFLAC hard-codes the depth to 24.*/ 179 | *depth=24; 180 | *colors=1<<((data[10]&7)+1); 181 | *has_palette=1; 182 | } 183 | } 184 | 185 | 186 | /*Tries to extract the width, height, bits per pixel, and palette size of a 187 | JPEG. 188 | On failure, simply leaves its outputs unmodified.*/ 189 | static void extract_jpeg_params(const unsigned char *data, size_t data_length, 190 | opus_uint32 *width, opus_uint32 *height, 191 | opus_uint32 *depth, opus_uint32 *colors, 192 | int *has_palette){ 193 | if(is_jpeg(data,data_length)){ 194 | size_t offs; 195 | offs=2; 196 | for(;;){ 197 | size_t segment_len; 198 | int marker; 199 | while(offs=data_length||(marker>=0xD8&&marker<=0xDA))break; 206 | /*RST* (restart markers): skip (no segment length).*/ 207 | else if(marker>=0xD0&&marker<=0xD7)continue; 208 | /*Read the length of the marker segment.*/ 209 | if(data_length-offs<2)break; 210 | segment_len=data[offs]<<8|data[offs+1]; 211 | if(segment_len<2||data_length-offs0xC0&&marker<0xD0&&(marker&3)!=0)){ 213 | /*Found a SOFn (start of frame) marker segment:*/ 214 | if(segment_len>=8){ 215 | *height=data[offs+3]<<8|data[offs+4]; 216 | *width=data[offs+5]<<8|data[offs+6]; 217 | *depth=data[offs+2]*data[offs+7]; 218 | *colors=0; 219 | *has_palette=0; 220 | } 221 | break; 222 | } 223 | /*Other markers: skip the whole marker segment.*/ 224 | offs+=segment_len; 225 | } 226 | } 227 | } 228 | 229 | #define IMAX(a,b) ((a) > (b) ? (a) : (b)) 230 | 231 | static unsigned char *opeint_read_picture_file(const char *filename, const char *description, int *error, size_t *size, size_t *offset) { 232 | FILE *picture_file; 233 | size_t cbuf; 234 | size_t nbuf; 235 | size_t data_offset; 236 | unsigned char *buf; 237 | picture_file=opeint_fopen(filename,"rb"); 238 | /*Buffer size: 8 static 4-byte fields plus 2 dynamic fields, plus the 239 | file/URL data. 240 | We reserve at least 10 bytes for the media type, in case we still need to 241 | extract it from the file.*/ 242 | data_offset=32+strlen(description)+10; 243 | buf=NULL; 244 | /*Complicated case: we have a real file. 245 | Read it in, attempt to parse the media type and image dimensions if 246 | necessary, and validate what the user passed in.*/ 247 | if(picture_file==NULL){ 248 | *error = OPE_CANNOT_OPEN; 249 | return NULL; 250 | } 251 | nbuf=data_offset; 252 | /*Add a reasonable starting image file size.*/ 253 | cbuf=data_offset+65536; 254 | for(;;){ 255 | unsigned char *new_buf; 256 | size_t nread; 257 | new_buf=realloc(buf,cbuf); 258 | if(new_buf==NULL){ 259 | fclose(picture_file); 260 | free(buf); 261 | *error = OPE_ALLOC_FAIL; 262 | return NULL; 263 | } 264 | buf=new_buf; 265 | nread=fread(buf+nbuf,1,cbuf-nbuf,picture_file); 266 | nbuf+=nread; 267 | if(nbuf0x7FFFFFFFU)cbuf=0xFFFFFFFFU; 285 | else cbuf=cbuf<<1|1; 286 | } 287 | *size = nbuf; 288 | *offset = data_offset; 289 | return buf; 290 | } 291 | 292 | static int validate_picture_type(int picture_type, int seen_file_icons) { 293 | if (picture_type > 20) return 0; 294 | if(picture_type>=1&&picture_type<=2&&(seen_file_icons&picture_type)) return 0; 295 | return 1; 296 | } 297 | 298 | /*Parse a picture SPECIFICATION as given on the command-line. 299 | spec: The specification. 300 | error_message: Returns an error message on error. 301 | seen_file_icons: Bit flags used to track if any pictures of type 1 or type 2 302 | have already been added, to ensure only one is allowed. 303 | Return: A Base64-encoded string suitable for use in a METADATA_BLOCK_PICTURE 304 | tag.*/ 305 | static char *opeint_parse_picture_specification_impl(unsigned char *buf, size_t nbuf, size_t data_offset, int picture_type, const char *description, 306 | int *error, int *seen_file_icons){ 307 | opus_uint32 width; 308 | opus_uint32 height; 309 | opus_uint32 depth; 310 | opus_uint32 colors; 311 | const char *mime_type; 312 | char *out; 313 | size_t data_length; 314 | size_t b64_length; 315 | int has_palette; 316 | *error = OPE_OK; 317 | if (picture_type < 0) picture_type=3; 318 | if (!validate_picture_type(picture_type, *seen_file_icons)) { 319 | *error = OPE_INVALID_PICTURE; 320 | return NULL; 321 | } 322 | if (buf == NULL) return NULL; 323 | data_length=nbuf-data_offset; 324 | /*Try to extract the image dimensions/color information from the file.*/ 325 | width=height=depth=colors=0; 326 | has_palette=-1; 327 | { 328 | if(is_jpeg(buf+data_offset,data_length)){ 329 | mime_type="image/jpeg"; 330 | extract_jpeg_params(buf+data_offset,data_length, 331 | &width,&height,&depth,&colors,&has_palette); 332 | } 333 | else if(is_png(buf+data_offset,data_length)){ 334 | mime_type="image/png"; 335 | extract_png_params(buf+data_offset,data_length, 336 | &width,&height,&depth,&colors,&has_palette); 337 | } 338 | else if(is_gif(buf+data_offset,data_length)){ 339 | mime_type="image/gif"; 340 | extract_gif_params(buf+data_offset,data_length, 341 | &width,&height,&depth,&colors,&has_palette); 342 | } 343 | else{ 344 | *error = OPE_INVALID_PICTURE; 345 | return NULL; 346 | } 347 | } 348 | /*These fields MUST be set correctly OR all set to zero. 349 | So if any of them (except colors, for which 0 is a valid value) are still 350 | zero, clear the rest to zero.*/ 351 | if(width==0||height==0||depth==0)width=height=depth=colors=0; 352 | if(picture_type==1&&(width!=32||height!=32 353 | ||strlen(mime_type)!=9 354 | ||oi_strncasecmp("image/png",mime_type,9)!=0)){ 355 | *error = OPE_INVALID_ICON; 356 | return NULL; 357 | } 358 | /*Build the METADATA_BLOCK_PICTURE buffer. 359 | We do this backwards from data_offset, because we didn't necessarily know 360 | how big the media type string was before we read the data in.*/ 361 | data_offset-=4; 362 | WRITE_U32_BE(buf+data_offset,(unsigned long)data_length); 363 | data_offset-=4; 364 | WRITE_U32_BE(buf+data_offset,colors); 365 | data_offset-=4; 366 | WRITE_U32_BE(buf+data_offset,depth); 367 | data_offset-=4; 368 | WRITE_U32_BE(buf+data_offset,height); 369 | data_offset-=4; 370 | WRITE_U32_BE(buf+data_offset,width); 371 | data_offset-=strlen(description); 372 | memcpy(buf+data_offset,description,strlen(description)); 373 | data_offset-=4; 374 | WRITE_U32_BE(buf+data_offset,strlen(description)); 375 | data_offset-=strlen(mime_type); 376 | memcpy(buf+data_offset,mime_type,strlen(mime_type)); 377 | data_offset-=4; 378 | WRITE_U32_BE(buf+data_offset,strlen(mime_type)); 379 | data_offset-=4; 380 | WRITE_U32_BE(buf+data_offset,picture_type); 381 | data_length=nbuf-data_offset; 382 | b64_length=BASE64_LENGTH(data_length); 383 | out=(char *)malloc(b64_length+1); 384 | if(out!=NULL){ 385 | base64_encode(out,(char *)buf+data_offset,data_length); 386 | if(picture_type>=1&&picture_type<=2)*seen_file_icons|=picture_type; 387 | } else { 388 | *error = OPE_ALLOC_FAIL; 389 | } 390 | return out; 391 | } 392 | 393 | char *opeint_parse_picture_specification(const char *filename, int picture_type, const char *description, 394 | int *error, int *seen_file_icons){ 395 | size_t nbuf; 396 | size_t data_offset; 397 | unsigned char *buf; 398 | char *ret; 399 | if (picture_type < 0) picture_type=3; 400 | if (!validate_picture_type(picture_type, *seen_file_icons)) { 401 | *error = OPE_INVALID_PICTURE; 402 | return NULL; 403 | } 404 | if (description == NULL) description = ""; 405 | buf = opeint_read_picture_file(filename, description, error, &nbuf, &data_offset); 406 | if (buf == NULL) return NULL; 407 | ret = opeint_parse_picture_specification_impl(buf, nbuf, data_offset, picture_type, description, error, seen_file_icons); 408 | free(buf); 409 | return ret; 410 | } 411 | 412 | char *opeint_parse_picture_specification_from_memory(const char *mem, size_t size, int picture_type, const char *description, 413 | int *error, int *seen_file_icons){ 414 | size_t nbuf; 415 | size_t data_offset; 416 | unsigned char *buf; 417 | char *ret; 418 | if (picture_type < 0) picture_type=3; 419 | if (!validate_picture_type(picture_type, *seen_file_icons)) { 420 | *error = OPE_INVALID_PICTURE; 421 | return NULL; 422 | } 423 | if (description == NULL) description = ""; 424 | data_offset=32+strlen(description)+10; 425 | nbuf = data_offset + size; 426 | buf = (unsigned char *)malloc(nbuf); 427 | if (buf == NULL) { 428 | *error = OPE_ALLOC_FAIL; 429 | return NULL; 430 | } 431 | memcpy(buf+data_offset, mem, size); 432 | ret = opeint_parse_picture_specification_impl(buf, nbuf, data_offset, picture_type, description, error, seen_file_icons); 433 | free(buf); 434 | return ret; 435 | } 436 | -------------------------------------------------------------------------------- /src/picture.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C)2007-2013 Xiph.Org Foundation 2 | File: picture.h 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | - Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | - Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 19 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef PICTURE_H 29 | #define PICTURE_H 30 | 31 | #include 32 | #include "opusenc.h" 33 | 34 | typedef enum{ 35 | PIC_FORMAT_JPEG, 36 | PIC_FORMAT_PNG, 37 | PIC_FORMAT_GIF 38 | }picture_format; 39 | 40 | #define BASE64_LENGTH(len) (((len)+2)/3*4) 41 | 42 | char *opeint_parse_picture_specification(const char *filename, int picture_type, const char *description, 43 | int *error, int *seen_file_icons); 44 | 45 | char *opeint_parse_picture_specification_from_memory(const char *mem, size_t size, int picture_type, const char *description, 46 | int *error, int *seen_file_icons); 47 | 48 | #define WRITE_U32_BE(buf, val) \ 49 | do{ \ 50 | (buf)[0]=(unsigned char)((val)>>24); \ 51 | (buf)[1]=(unsigned char)((val)>>16); \ 52 | (buf)[2]=(unsigned char)((val)>>8); \ 53 | (buf)[3]=(unsigned char)(val); \ 54 | } \ 55 | while(0); 56 | 57 | #endif /* PICTURE_H */ 58 | -------------------------------------------------------------------------------- /src/resample.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007-2008 Jean-Marc Valin 2 | Copyright (C) 2008 Thorvald Natvig 3 | 4 | File: resample.c 5 | Arbitrary resampling code 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | 1. Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | 14 | 2. Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | 3. The name of the author may not be used to endorse or promote products 19 | derived from this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | /* 35 | The design goals of this code are: 36 | - Very fast algorithm 37 | - SIMD-friendly algorithm 38 | - Low memory requirement 39 | - Good *perceptual* quality (and not best SNR) 40 | 41 | Warning: This resampler is relatively new. Although I think I got rid of 42 | all the major bugs and I don't expect the API to change anymore, there 43 | may be something I've missed. So use with caution. 44 | 45 | This algorithm is based on this original resampling algorithm: 46 | Smith, Julius O. Digital Audio Resampling Home Page 47 | Center for Computer Research in Music and Acoustics (CCRMA), 48 | Stanford University, 2007. 49 | Web published at https://ccrma.stanford.edu/~jos/resample/. 50 | 51 | There is one main difference, though. This resampler uses cubic 52 | interpolation instead of linear interpolation in the above paper. This 53 | makes the table much smaller and makes it possible to compute that table 54 | on a per-stream basis. In turn, being able to tweak the table for each 55 | stream makes it possible to both reduce complexity on simple ratios 56 | (e.g. 2/3), and get rid of the rounding operations in the inner loop. 57 | The latter both reduces CPU time and makes the algorithm more SIMD-friendly. 58 | */ 59 | 60 | #ifdef HAVE_CONFIG_H 61 | #include "config.h" 62 | #endif 63 | 64 | #ifdef OUTSIDE_SPEEX 65 | #include 66 | static void *speex_alloc(int size) {return calloc(size,1);} 67 | static void *speex_realloc(void *ptr, int size) {return realloc(ptr, size);} 68 | static void speex_free(void *ptr) {free(ptr);} 69 | #ifndef EXPORT 70 | #define EXPORT 71 | #endif 72 | #include "speex_resampler.h" 73 | #include "arch.h" 74 | #else /* OUTSIDE_SPEEX */ 75 | 76 | #include "speex/speex_resampler.h" 77 | #include "arch.h" 78 | #include "os_support.h" 79 | #endif /* OUTSIDE_SPEEX */ 80 | 81 | #include 82 | #include 83 | 84 | #ifndef M_PI 85 | #define M_PI 3.14159265358979323846 86 | #endif 87 | 88 | #define IMAX(a,b) ((a) > (b) ? (a) : (b)) 89 | #define IMIN(a,b) ((a) < (b) ? (a) : (b)) 90 | 91 | #ifndef NULL 92 | #define NULL 0 93 | #endif 94 | 95 | #ifndef UINT32_MAX 96 | #define UINT32_MAX 4294967295U 97 | #endif 98 | 99 | #if defined(__SSE__) && !defined(FIXED_POINT) 100 | #include "resample_sse.h" 101 | #endif 102 | 103 | #ifdef USE_NEON 104 | #include "resample_neon.h" 105 | #endif 106 | 107 | /* Numer of elements to allocate on the stack */ 108 | #ifdef VAR_ARRAYS 109 | #define FIXED_STACK_ALLOC 8192 110 | #else 111 | #define FIXED_STACK_ALLOC 1024 112 | #endif 113 | 114 | typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); 115 | 116 | struct SpeexResamplerState_ { 117 | spx_uint32_t in_rate; 118 | spx_uint32_t out_rate; 119 | spx_uint32_t num_rate; 120 | spx_uint32_t den_rate; 121 | 122 | int quality; 123 | spx_uint32_t nb_channels; 124 | spx_uint32_t filt_len; 125 | spx_uint32_t mem_alloc_size; 126 | spx_uint32_t buffer_size; 127 | int int_advance; 128 | int frac_advance; 129 | float cutoff; 130 | spx_uint32_t oversample; 131 | int initialised; 132 | int started; 133 | 134 | /* These are per-channel */ 135 | spx_int32_t *last_sample; 136 | spx_uint32_t *samp_frac_num; 137 | spx_uint32_t *magic_samples; 138 | 139 | spx_word16_t *mem; 140 | spx_word16_t *sinc_table; 141 | spx_uint32_t sinc_table_length; 142 | resampler_basic_func resampler_ptr; 143 | 144 | int in_stride; 145 | int out_stride; 146 | } ; 147 | 148 | static const double kaiser12_table[68] = { 149 | 0.99859849, 1.00000000, 0.99859849, 0.99440475, 0.98745105, 0.97779076, 150 | 0.96549770, 0.95066529, 0.93340547, 0.91384741, 0.89213598, 0.86843014, 151 | 0.84290116, 0.81573067, 0.78710866, 0.75723148, 0.72629970, 0.69451601, 152 | 0.66208321, 0.62920216, 0.59606986, 0.56287762, 0.52980938, 0.49704014, 153 | 0.46473455, 0.43304576, 0.40211431, 0.37206735, 0.34301800, 0.31506490, 154 | 0.28829195, 0.26276832, 0.23854851, 0.21567274, 0.19416736, 0.17404546, 155 | 0.15530766, 0.13794294, 0.12192957, 0.10723616, 0.09382272, 0.08164178, 156 | 0.07063950, 0.06075685, 0.05193064, 0.04409466, 0.03718069, 0.03111947, 157 | 0.02584161, 0.02127838, 0.01736250, 0.01402878, 0.01121463, 0.00886058, 158 | 0.00691064, 0.00531256, 0.00401805, 0.00298291, 0.00216702, 0.00153438, 159 | 0.00105297, 0.00069463, 0.00043489, 0.00025272, 0.00013031, 0.0000527734, 160 | 0.00001000, 0.00000000}; 161 | /* 162 | static const double kaiser12_table[36] = { 163 | 0.99440475, 1.00000000, 0.99440475, 0.97779076, 0.95066529, 0.91384741, 164 | 0.86843014, 0.81573067, 0.75723148, 0.69451601, 0.62920216, 0.56287762, 165 | 0.49704014, 0.43304576, 0.37206735, 0.31506490, 0.26276832, 0.21567274, 166 | 0.17404546, 0.13794294, 0.10723616, 0.08164178, 0.06075685, 0.04409466, 167 | 0.03111947, 0.02127838, 0.01402878, 0.00886058, 0.00531256, 0.00298291, 168 | 0.00153438, 0.00069463, 0.00025272, 0.0000527734, 0.00000500, 0.00000000}; 169 | */ 170 | static const double kaiser10_table[36] = { 171 | 0.99537781, 1.00000000, 0.99537781, 0.98162644, 0.95908712, 0.92831446, 172 | 0.89005583, 0.84522401, 0.79486424, 0.74011713, 0.68217934, 0.62226347, 173 | 0.56155915, 0.50119680, 0.44221549, 0.38553619, 0.33194107, 0.28205962, 174 | 0.23636152, 0.19515633, 0.15859932, 0.12670280, 0.09935205, 0.07632451, 175 | 0.05731132, 0.04193980, 0.02979584, 0.02044510, 0.01345224, 0.00839739, 176 | 0.00488951, 0.00257636, 0.00115101, 0.00035515, 0.00000000, 0.00000000}; 177 | 178 | static const double kaiser8_table[36] = { 179 | 0.99635258, 1.00000000, 0.99635258, 0.98548012, 0.96759014, 0.94302200, 180 | 0.91223751, 0.87580811, 0.83439927, 0.78875245, 0.73966538, 0.68797126, 181 | 0.63451750, 0.58014482, 0.52566725, 0.47185369, 0.41941150, 0.36897272, 182 | 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, 183 | 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, 184 | 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; 185 | 186 | static const double kaiser6_table[36] = { 187 | 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, 188 | 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, 189 | 0.71712752, 0.67172623, 0.62508937, 0.57774224, 0.53019925, 0.48295561, 190 | 0.43647969, 0.39120616, 0.34752997, 0.30580127, 0.26632152, 0.22934058, 191 | 0.19505503, 0.16360756, 0.13508755, 0.10953262, 0.08693120, 0.06722600, 192 | 0.05031820, 0.03607231, 0.02432151, 0.01487334, 0.00752000, 0.00000000}; 193 | 194 | struct FuncDef { 195 | const double *table; 196 | int oversample; 197 | }; 198 | 199 | static const struct FuncDef kaiser12_funcdef = {kaiser12_table, 64}; 200 | #define KAISER12 (&kaiser12_funcdef) 201 | static const struct FuncDef kaiser10_funcdef = {kaiser10_table, 32}; 202 | #define KAISER10 (&kaiser10_funcdef) 203 | static const struct FuncDef kaiser8_funcdef = {kaiser8_table, 32}; 204 | #define KAISER8 (&kaiser8_funcdef) 205 | static const struct FuncDef kaiser6_funcdef = {kaiser6_table, 32}; 206 | #define KAISER6 (&kaiser6_funcdef) 207 | 208 | struct QualityMapping { 209 | int base_length; 210 | int oversample; 211 | float downsample_bandwidth; 212 | float upsample_bandwidth; 213 | const struct FuncDef *window_func; 214 | }; 215 | 216 | 217 | /* This table maps conversion quality to internal parameters. There are two 218 | reasons that explain why the up-sampling bandwidth is larger than the 219 | down-sampling bandwidth: 220 | 1) When up-sampling, we can assume that the spectrum is already attenuated 221 | close to the Nyquist rate (from an A/D or a previous resampling filter) 222 | 2) Any aliasing that occurs very close to the Nyquist rate will be masked 223 | by the sinusoids/noise just below the Nyquist rate (guaranteed only for 224 | up-sampling). 225 | */ 226 | static const struct QualityMapping quality_map[11] = { 227 | { 8, 4, 0.830f, 0.860f, KAISER6 }, /* Q0 */ 228 | { 16, 4, 0.850f, 0.880f, KAISER6 }, /* Q1 */ 229 | { 32, 4, 0.882f, 0.910f, KAISER6 }, /* Q2 */ /* 82.3% cutoff ( ~60 dB stop) 6 */ 230 | { 48, 8, 0.895f, 0.917f, KAISER8 }, /* Q3 */ /* 84.9% cutoff ( ~80 dB stop) 8 */ 231 | { 64, 8, 0.921f, 0.940f, KAISER8 }, /* Q4 */ /* 88.7% cutoff ( ~80 dB stop) 8 */ 232 | { 80, 16, 0.922f, 0.940f, KAISER10}, /* Q5 */ /* 89.1% cutoff (~100 dB stop) 10 */ 233 | { 96, 16, 0.940f, 0.945f, KAISER10}, /* Q6 */ /* 91.5% cutoff (~100 dB stop) 10 */ 234 | {128, 16, 0.950f, 0.950f, KAISER10}, /* Q7 */ /* 93.1% cutoff (~100 dB stop) 10 */ 235 | {160, 16, 0.960f, 0.960f, KAISER10}, /* Q8 */ /* 94.5% cutoff (~100 dB stop) 10 */ 236 | {192, 32, 0.968f, 0.968f, KAISER12}, /* Q9 */ /* 95.5% cutoff (~100 dB stop) 10 */ 237 | {256, 32, 0.975f, 0.975f, KAISER12}, /* Q10 */ /* 96.6% cutoff (~100 dB stop) 10 */ 238 | }; 239 | /*8,24,40,56,80,104,128,160,200,256,320*/ 240 | static double compute_func(float x, const struct FuncDef *func) 241 | { 242 | float y, frac; 243 | double interp[4]; 244 | int ind; 245 | y = x*func->oversample; 246 | ind = (int)floor(y); 247 | frac = (y-ind); 248 | /* CSE with handle the repeated powers */ 249 | interp[3] = -0.1666666667*frac + 0.1666666667*(frac*frac*frac); 250 | interp[2] = frac + 0.5*(frac*frac) - 0.5*(frac*frac*frac); 251 | /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ 252 | interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); 253 | /* Just to make sure we don't have rounding problems */ 254 | interp[1] = 1.f-interp[3]-interp[2]-interp[0]; 255 | 256 | /*sum = frac*accum[1] + (1-frac)*accum[2];*/ 257 | return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; 258 | } 259 | 260 | #if 0 261 | #include 262 | int main(int argc, char **argv) 263 | { 264 | int i; 265 | for (i=0;i<256;i++) 266 | { 267 | printf ("%f\n", compute_func(i/256., KAISER12)); 268 | } 269 | return 0; 270 | } 271 | #endif 272 | 273 | #ifdef FIXED_POINT 274 | /* The slow way of computing a sinc for the table. Should improve that some day */ 275 | static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef *window_func) 276 | { 277 | /*fprintf (stderr, "%f ", x);*/ 278 | float xx = x * cutoff; 279 | if (fabs(x)<1e-6f) 280 | return WORD2INT(32768.*cutoff); 281 | else if (fabs(x) > .5f*N) 282 | return 0; 283 | /*FIXME: Can it really be any slower than this? */ 284 | return WORD2INT(32768.*cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func)); 285 | } 286 | #else 287 | /* The slow way of computing a sinc for the table. Should improve that some day */ 288 | static spx_word16_t sinc(float cutoff, float x, int N, const struct FuncDef *window_func) 289 | { 290 | /*fprintf (stderr, "%f ", x);*/ 291 | float xx = x * cutoff; 292 | if (fabs(x)<1e-6) 293 | return cutoff; 294 | else if (fabs(x) > .5*N) 295 | return 0; 296 | /*FIXME: Can it really be any slower than this? */ 297 | return cutoff*sin(M_PI*xx)/(M_PI*xx) * compute_func(fabs(2.*x/N), window_func); 298 | } 299 | #endif 300 | 301 | #ifdef FIXED_POINT 302 | static void cubic_coef(spx_word16_t x, spx_word16_t interp[4]) 303 | { 304 | /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation 305 | but I know it's MMSE-optimal on a sinc */ 306 | spx_word16_t x2, x3; 307 | x2 = MULT16_16_P15(x, x); 308 | x3 = MULT16_16_P15(x, x2); 309 | interp[0] = PSHR32(MULT16_16(QCONST16(-0.16667f, 15),x) + MULT16_16(QCONST16(0.16667f, 15),x3),15); 310 | interp[1] = EXTRACT16(EXTEND32(x) + SHR32(SUB32(EXTEND32(x2),EXTEND32(x3)),1)); 311 | interp[3] = PSHR32(MULT16_16(QCONST16(-0.33333f, 15),x) + MULT16_16(QCONST16(.5f,15),x2) - MULT16_16(QCONST16(0.16667f, 15),x3),15); 312 | /* Just to make sure we don't have rounding problems */ 313 | interp[2] = Q15_ONE-interp[0]-interp[1]-interp[3]; 314 | if (interp[2]<32767) 315 | interp[2]+=1; 316 | } 317 | #else 318 | static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) 319 | { 320 | /* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation 321 | but I know it's MMSE-optimal on a sinc */ 322 | interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac; 323 | interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac; 324 | /*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/ 325 | interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac; 326 | /* Just to make sure we don't have rounding problems */ 327 | interp[2] = 1.-interp[0]-interp[1]-interp[3]; 328 | } 329 | #endif 330 | 331 | static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 332 | { 333 | const int N = st->filt_len; 334 | int out_sample = 0; 335 | int last_sample = st->last_sample[channel_index]; 336 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 337 | const spx_word16_t *sinc_table = st->sinc_table; 338 | const int out_stride = st->out_stride; 339 | const int int_advance = st->int_advance; 340 | const int frac_advance = st->frac_advance; 341 | const spx_uint32_t den_rate = st->den_rate; 342 | spx_word32_t sum; 343 | 344 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 345 | { 346 | const spx_word16_t *sinct = & sinc_table[samp_frac_num*N]; 347 | const spx_word16_t *iptr = & in[last_sample]; 348 | 349 | #ifndef OVERRIDE_INNER_PRODUCT_SINGLE 350 | int j; 351 | sum = 0; 352 | for(j=0;j= den_rate) 375 | { 376 | samp_frac_num -= den_rate; 377 | last_sample++; 378 | } 379 | } 380 | 381 | st->last_sample[channel_index] = last_sample; 382 | st->samp_frac_num[channel_index] = samp_frac_num; 383 | return out_sample; 384 | } 385 | 386 | #ifdef FIXED_POINT 387 | #else 388 | /* This is the same as the previous function, except with a double-precision accumulator */ 389 | static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 390 | { 391 | const int N = st->filt_len; 392 | int out_sample = 0; 393 | int last_sample = st->last_sample[channel_index]; 394 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 395 | const spx_word16_t *sinc_table = st->sinc_table; 396 | const int out_stride = st->out_stride; 397 | const int int_advance = st->int_advance; 398 | const int frac_advance = st->frac_advance; 399 | const spx_uint32_t den_rate = st->den_rate; 400 | double sum; 401 | 402 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 403 | { 404 | const spx_word16_t *sinct = & sinc_table[samp_frac_num*N]; 405 | const spx_word16_t *iptr = & in[last_sample]; 406 | 407 | #ifndef OVERRIDE_INNER_PRODUCT_DOUBLE 408 | int j; 409 | double accum[4] = {0,0,0,0}; 410 | 411 | for(j=0;j= den_rate) 426 | { 427 | samp_frac_num -= den_rate; 428 | last_sample++; 429 | } 430 | } 431 | 432 | st->last_sample[channel_index] = last_sample; 433 | st->samp_frac_num[channel_index] = samp_frac_num; 434 | return out_sample; 435 | } 436 | #endif 437 | 438 | static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 439 | { 440 | const int N = st->filt_len; 441 | int out_sample = 0; 442 | int last_sample = st->last_sample[channel_index]; 443 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 444 | const int out_stride = st->out_stride; 445 | const int int_advance = st->int_advance; 446 | const int frac_advance = st->frac_advance; 447 | const spx_uint32_t den_rate = st->den_rate; 448 | spx_word32_t sum; 449 | 450 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 451 | { 452 | const spx_word16_t *iptr = & in[last_sample]; 453 | 454 | const int offset = samp_frac_num*st->oversample/st->den_rate; 455 | #ifdef FIXED_POINT 456 | const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); 457 | #else 458 | const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; 459 | #endif 460 | spx_word16_t interp[4]; 461 | 462 | 463 | #ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE 464 | int j; 465 | spx_word32_t accum[4] = {0,0,0,0}; 466 | 467 | for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); 470 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); 471 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); 472 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); 473 | } 474 | 475 | cubic_coef(frac, interp); 476 | sum = MULT16_32_Q15(interp[0],SHR32(accum[0], 1)) + MULT16_32_Q15(interp[1],SHR32(accum[1], 1)) + MULT16_32_Q15(interp[2],SHR32(accum[2], 1)) + MULT16_32_Q15(interp[3],SHR32(accum[3], 1)); 477 | sum = SATURATE32PSHR(sum, 15, 32767); 478 | #else 479 | cubic_coef(frac, interp); 480 | sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); 481 | #endif 482 | 483 | out[out_stride * out_sample++] = sum; 484 | last_sample += int_advance; 485 | samp_frac_num += frac_advance; 486 | if (samp_frac_num >= den_rate) 487 | { 488 | samp_frac_num -= den_rate; 489 | last_sample++; 490 | } 491 | } 492 | 493 | st->last_sample[channel_index] = last_sample; 494 | st->samp_frac_num[channel_index] = samp_frac_num; 495 | return out_sample; 496 | } 497 | 498 | #ifdef FIXED_POINT 499 | #else 500 | /* This is the same as the previous function, except with a double-precision accumulator */ 501 | static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 502 | { 503 | const int N = st->filt_len; 504 | int out_sample = 0; 505 | int last_sample = st->last_sample[channel_index]; 506 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 507 | const int out_stride = st->out_stride; 508 | const int int_advance = st->int_advance; 509 | const int frac_advance = st->frac_advance; 510 | const spx_uint32_t den_rate = st->den_rate; 511 | spx_word32_t sum; 512 | 513 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 514 | { 515 | const spx_word16_t *iptr = & in[last_sample]; 516 | 517 | const int offset = samp_frac_num*st->oversample/st->den_rate; 518 | #ifdef FIXED_POINT 519 | const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); 520 | #else 521 | const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; 522 | #endif 523 | spx_word16_t interp[4]; 524 | 525 | 526 | #ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE 527 | int j; 528 | double accum[4] = {0,0,0,0}; 529 | 530 | for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); 533 | accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); 534 | accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); 535 | accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); 536 | } 537 | 538 | cubic_coef(frac, interp); 539 | sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); 540 | #else 541 | cubic_coef(frac, interp); 542 | sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); 543 | #endif 544 | 545 | out[out_stride * out_sample++] = PSHR32(sum,15); 546 | last_sample += int_advance; 547 | samp_frac_num += frac_advance; 548 | if (samp_frac_num >= den_rate) 549 | { 550 | samp_frac_num -= den_rate; 551 | last_sample++; 552 | } 553 | } 554 | 555 | st->last_sample[channel_index] = last_sample; 556 | st->samp_frac_num[channel_index] = samp_frac_num; 557 | return out_sample; 558 | } 559 | #endif 560 | 561 | /* This resampler is used to produce zero output in situations where memory 562 | for the filter could not be allocated. The expected numbers of input and 563 | output samples are still processed so that callers failing to check error 564 | codes are not surprised, possibly getting into infinite loops. */ 565 | static int resampler_basic_zero(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 566 | { 567 | int out_sample = 0; 568 | int last_sample = st->last_sample[channel_index]; 569 | spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; 570 | const int out_stride = st->out_stride; 571 | const int int_advance = st->int_advance; 572 | const int frac_advance = st->frac_advance; 573 | const spx_uint32_t den_rate = st->den_rate; 574 | 575 | (void)in; 576 | while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) 577 | { 578 | out[out_stride * out_sample++] = 0; 579 | last_sample += int_advance; 580 | samp_frac_num += frac_advance; 581 | if (samp_frac_num >= den_rate) 582 | { 583 | samp_frac_num -= den_rate; 584 | last_sample++; 585 | } 586 | } 587 | 588 | st->last_sample[channel_index] = last_sample; 589 | st->samp_frac_num[channel_index] = samp_frac_num; 590 | return out_sample; 591 | } 592 | 593 | static int multiply_frac(spx_uint32_t *result, spx_uint32_t value, spx_uint32_t num, spx_uint32_t den) 594 | { 595 | spx_uint32_t major = value / den; 596 | spx_uint32_t remain = value % den; 597 | /* TODO: Could use 64 bits operation to check for overflow. But only guaranteed in C99+ */ 598 | if (remain > UINT32_MAX / num || major > UINT32_MAX / num 599 | || major * num > UINT32_MAX - remain * num / den) 600 | return RESAMPLER_ERR_OVERFLOW; 601 | *result = remain * num / den + major * num; 602 | return RESAMPLER_ERR_SUCCESS; 603 | } 604 | 605 | static int update_filter(SpeexResamplerState *st) 606 | { 607 | spx_uint32_t old_length = st->filt_len; 608 | spx_uint32_t old_alloc_size = st->mem_alloc_size; 609 | int use_direct; 610 | spx_uint32_t min_sinc_table_length; 611 | spx_uint32_t min_alloc_size; 612 | 613 | st->int_advance = st->num_rate/st->den_rate; 614 | st->frac_advance = st->num_rate%st->den_rate; 615 | st->oversample = quality_map[st->quality].oversample; 616 | st->filt_len = quality_map[st->quality].base_length; 617 | 618 | if (st->num_rate > st->den_rate) 619 | { 620 | /* down-sampling */ 621 | st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate; 622 | if (multiply_frac(&st->filt_len,st->filt_len,st->num_rate,st->den_rate) != RESAMPLER_ERR_SUCCESS) 623 | goto fail; 624 | /* Round up to make sure we have a multiple of 8 for SSE */ 625 | st->filt_len = ((st->filt_len-1)&(~0x7))+8; 626 | if (2*st->den_rate < st->num_rate) 627 | st->oversample >>= 1; 628 | if (4*st->den_rate < st->num_rate) 629 | st->oversample >>= 1; 630 | if (8*st->den_rate < st->num_rate) 631 | st->oversample >>= 1; 632 | if (16*st->den_rate < st->num_rate) 633 | st->oversample >>= 1; 634 | if (st->oversample < 1) 635 | st->oversample = 1; 636 | } else { 637 | /* up-sampling */ 638 | st->cutoff = quality_map[st->quality].upsample_bandwidth; 639 | } 640 | 641 | #ifdef RESAMPLE_FULL_SINC_TABLE 642 | use_direct = 1; 643 | if (INT_MAX/sizeof(spx_word16_t)/st->den_rate < st->filt_len) 644 | goto fail; 645 | #else 646 | /* Choose the resampling type that requires the least amount of memory */ 647 | use_direct = st->filt_len*st->den_rate <= st->filt_len*st->oversample+8 648 | && INT_MAX/sizeof(spx_word16_t)/st->den_rate >= st->filt_len; 649 | #endif 650 | if (use_direct) 651 | { 652 | min_sinc_table_length = st->filt_len*st->den_rate; 653 | } else { 654 | if ((INT_MAX/sizeof(spx_word16_t)-8)/st->oversample < st->filt_len) 655 | goto fail; 656 | 657 | min_sinc_table_length = st->filt_len*st->oversample+8; 658 | } 659 | if (st->sinc_table_length < min_sinc_table_length) 660 | { 661 | spx_word16_t *sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,min_sinc_table_length*sizeof(spx_word16_t)); 662 | if (!sinc_table) 663 | goto fail; 664 | 665 | st->sinc_table = sinc_table; 666 | st->sinc_table_length = min_sinc_table_length; 667 | } 668 | if (use_direct) 669 | { 670 | spx_uint32_t i; 671 | for (i=0;iden_rate;i++) 672 | { 673 | spx_int32_t j; 674 | for (j=0;jfilt_len;j++) 675 | { 676 | st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-(spx_int32_t)st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len, quality_map[st->quality].window_func); 677 | } 678 | } 679 | #ifdef FIXED_POINT 680 | st->resampler_ptr = resampler_basic_direct_single; 681 | #else 682 | if (st->quality>8) 683 | st->resampler_ptr = resampler_basic_direct_double; 684 | else 685 | st->resampler_ptr = resampler_basic_direct_single; 686 | #endif 687 | /*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/ 688 | } else { 689 | spx_int32_t i; 690 | for (i=-4;i<(spx_int32_t)(st->oversample*st->filt_len+4);i++) 691 | st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len, quality_map[st->quality].window_func); 692 | #ifdef FIXED_POINT 693 | st->resampler_ptr = resampler_basic_interpolate_single; 694 | #else 695 | if (st->quality>8) 696 | st->resampler_ptr = resampler_basic_interpolate_double; 697 | else 698 | st->resampler_ptr = resampler_basic_interpolate_single; 699 | #endif 700 | /*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/ 701 | } 702 | 703 | /* Here's the place where we update the filter memory to take into account 704 | the change in filter length. It's probably the messiest part of the code 705 | due to handling of lots of corner cases. */ 706 | 707 | /* Adding buffer_size to filt_len won't overflow here because filt_len 708 | could be multiplied by sizeof(spx_word16_t) above. */ 709 | min_alloc_size = st->filt_len-1 + st->buffer_size; 710 | if (min_alloc_size > st->mem_alloc_size) 711 | { 712 | spx_word16_t *mem; 713 | if (INT_MAX/sizeof(spx_word16_t)/st->nb_channels < min_alloc_size) 714 | goto fail; 715 | else if (!(mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*min_alloc_size * sizeof(*mem)))) 716 | goto fail; 717 | 718 | st->mem = mem; 719 | st->mem_alloc_size = min_alloc_size; 720 | } 721 | if (!st->started) 722 | { 723 | spx_uint32_t i; 724 | for (i=0;inb_channels*st->mem_alloc_size;i++) 725 | st->mem[i] = 0; 726 | /*speex_warning("reinit filter");*/ 727 | } else if (st->filt_len > old_length) 728 | { 729 | spx_uint32_t i; 730 | /* Increase the filter length */ 731 | /*speex_warning("increase filter size");*/ 732 | for (i=st->nb_channels;i--;) 733 | { 734 | spx_uint32_t j; 735 | spx_uint32_t olen = old_length; 736 | /*if (st->magic_samples[i])*/ 737 | { 738 | /* Try and remove the magic samples as if nothing had happened */ 739 | 740 | /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ 741 | olen = old_length + 2*st->magic_samples[i]; 742 | for (j=old_length-1+st->magic_samples[i];j--;) 743 | st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]] = st->mem[i*old_alloc_size+j]; 744 | for (j=0;jmagic_samples[i];j++) 745 | st->mem[i*st->mem_alloc_size+j] = 0; 746 | st->magic_samples[i] = 0; 747 | } 748 | if (st->filt_len > olen) 749 | { 750 | /* If the new filter length is still bigger than the "augmented" length */ 751 | /* Copy data going backward */ 752 | for (j=0;jmem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*st->mem_alloc_size+(olen-2-j)]; 754 | /* Then put zeros for lack of anything better */ 755 | for (;jfilt_len-1;j++) 756 | st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0; 757 | /* Adjust last_sample */ 758 | st->last_sample[i] += (st->filt_len - olen)/2; 759 | } else { 760 | /* Put back some of the magic! */ 761 | st->magic_samples[i] = (olen - st->filt_len)/2; 762 | for (j=0;jfilt_len-1+st->magic_samples[i];j++) 763 | st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; 764 | } 765 | } 766 | } else if (st->filt_len < old_length) 767 | { 768 | spx_uint32_t i; 769 | /* Reduce filter length, this a bit tricky. We need to store some of the memory as "magic" 770 | samples so they can be used directly as input the next time(s) */ 771 | for (i=0;inb_channels;i++) 772 | { 773 | spx_uint32_t j; 774 | spx_uint32_t old_magic = st->magic_samples[i]; 775 | st->magic_samples[i] = (old_length - st->filt_len)/2; 776 | /* We must copy some of the memory that's no longer used */ 777 | /* Copy data going backward */ 778 | for (j=0;jfilt_len-1+st->magic_samples[i]+old_magic;j++) 779 | st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]]; 780 | st->magic_samples[i] += old_magic; 781 | } 782 | } 783 | return RESAMPLER_ERR_SUCCESS; 784 | 785 | fail: 786 | st->resampler_ptr = resampler_basic_zero; 787 | /* st->mem may still contain consumed input samples for the filter. 788 | Restore filt_len so that filt_len - 1 still points to the position after 789 | the last of these samples. */ 790 | st->filt_len = old_length; 791 | return RESAMPLER_ERR_ALLOC_FAILED; 792 | } 793 | 794 | EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) 795 | { 796 | return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); 797 | } 798 | 799 | EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) 800 | { 801 | SpeexResamplerState *st; 802 | int filter_err; 803 | 804 | if (nb_channels == 0 || ratio_num == 0 || ratio_den == 0 || quality > 10 || quality < 0) 805 | { 806 | if (err) 807 | *err = RESAMPLER_ERR_INVALID_ARG; 808 | return NULL; 809 | } 810 | st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState)); 811 | if (!st) 812 | { 813 | if (err) 814 | *err = RESAMPLER_ERR_ALLOC_FAILED; 815 | return NULL; 816 | } 817 | st->initialised = 0; 818 | st->started = 0; 819 | st->in_rate = 0; 820 | st->out_rate = 0; 821 | st->num_rate = 0; 822 | st->den_rate = 0; 823 | st->quality = -1; 824 | st->sinc_table_length = 0; 825 | st->mem_alloc_size = 0; 826 | st->filt_len = 0; 827 | st->mem = 0; 828 | st->resampler_ptr = 0; 829 | 830 | st->cutoff = 1.f; 831 | st->nb_channels = nb_channels; 832 | st->in_stride = 1; 833 | st->out_stride = 1; 834 | 835 | st->buffer_size = 160; 836 | 837 | /* Per channel data */ 838 | if (!(st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(spx_int32_t)))) 839 | goto fail; 840 | if (!(st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)))) 841 | goto fail; 842 | if (!(st->samp_frac_num = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(spx_uint32_t)))) 843 | goto fail; 844 | 845 | speex_resampler_set_quality(st, quality); 846 | speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); 847 | 848 | filter_err = update_filter(st); 849 | if (filter_err == RESAMPLER_ERR_SUCCESS) 850 | { 851 | st->initialised = 1; 852 | } else { 853 | speex_resampler_destroy(st); 854 | st = NULL; 855 | } 856 | if (err) 857 | *err = filter_err; 858 | 859 | return st; 860 | 861 | fail: 862 | if (err) 863 | *err = RESAMPLER_ERR_ALLOC_FAILED; 864 | speex_resampler_destroy(st); 865 | return NULL; 866 | } 867 | 868 | EXPORT void speex_resampler_destroy(SpeexResamplerState *st) 869 | { 870 | speex_free(st->mem); 871 | speex_free(st->sinc_table); 872 | speex_free(st->last_sample); 873 | speex_free(st->magic_samples); 874 | speex_free(st->samp_frac_num); 875 | speex_free(st); 876 | } 877 | 878 | static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) 879 | { 880 | int j=0; 881 | const int N = st->filt_len; 882 | int out_sample = 0; 883 | spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; 884 | spx_uint32_t ilen; 885 | 886 | st->started = 1; 887 | 888 | /* Call the right resampler through the function ptr */ 889 | out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); 890 | 891 | if (st->last_sample[channel_index] < (spx_int32_t)*in_len) 892 | *in_len = st->last_sample[channel_index]; 893 | *out_len = out_sample; 894 | st->last_sample[channel_index] -= *in_len; 895 | 896 | ilen = *in_len; 897 | 898 | for(j=0;jmagic_samples[channel_index]; 906 | spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; 907 | const int N = st->filt_len; 908 | 909 | speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); 910 | 911 | st->magic_samples[channel_index] -= tmp_in_len; 912 | 913 | /* If we couldn't process all "magic" input samples, save the rest for next time */ 914 | if (st->magic_samples[channel_index]) 915 | { 916 | spx_uint32_t i; 917 | for (i=0;imagic_samples[channel_index];i++) 918 | mem[N-1+i]=mem[N-1+i+tmp_in_len]; 919 | } 920 | *out += out_len*st->out_stride; 921 | return out_len; 922 | } 923 | 924 | #ifdef FIXED_POINT 925 | EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) 926 | #else 927 | EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) 928 | #endif 929 | { 930 | int j; 931 | spx_uint32_t ilen = *in_len; 932 | spx_uint32_t olen = *out_len; 933 | spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; 934 | const int filt_offs = st->filt_len - 1; 935 | const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; 936 | const int istride = st->in_stride; 937 | 938 | if (st->magic_samples[channel_index]) 939 | olen -= speex_resampler_magic(st, channel_index, &out, olen); 940 | if (! st->magic_samples[channel_index]) { 941 | while (ilen && olen) { 942 | spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; 943 | spx_uint32_t ochunk = olen; 944 | 945 | if (in) { 946 | for(j=0;jout_stride; 956 | if (in) 957 | in += ichunk * istride; 958 | } 959 | } 960 | *in_len -= ilen; 961 | *out_len -= olen; 962 | return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS; 963 | } 964 | 965 | #ifdef FIXED_POINT 966 | EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) 967 | #else 968 | EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) 969 | #endif 970 | { 971 | int j; 972 | const int istride_save = st->in_stride; 973 | const int ostride_save = st->out_stride; 974 | spx_uint32_t ilen = *in_len; 975 | spx_uint32_t olen = *out_len; 976 | spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; 977 | const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1); 978 | #ifdef VAR_ARRAYS 979 | const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; 980 | spx_word16_t ystack[ylen]; 981 | #else 982 | const unsigned int ylen = FIXED_STACK_ALLOC; 983 | spx_word16_t ystack[FIXED_STACK_ALLOC]; 984 | #endif 985 | 986 | st->out_stride = 1; 987 | 988 | while (ilen && olen) { 989 | spx_word16_t *y = ystack; 990 | spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; 991 | spx_uint32_t ochunk = (olen > ylen) ? ylen : olen; 992 | spx_uint32_t omagic = 0; 993 | 994 | if (st->magic_samples[channel_index]) { 995 | omagic = speex_resampler_magic(st, channel_index, &y, ochunk); 996 | ochunk -= omagic; 997 | olen -= omagic; 998 | } 999 | if (! st->magic_samples[channel_index]) { 1000 | if (in) { 1001 | for(j=0;jfilt_len-1]=WORD2INT(in[j*istride_save]); 1004 | #else 1005 | x[j+st->filt_len-1]=in[j*istride_save]; 1006 | #endif 1007 | } else { 1008 | for(j=0;jfilt_len-1]=0; 1010 | } 1011 | 1012 | speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk); 1013 | } else { 1014 | ichunk = 0; 1015 | ochunk = 0; 1016 | } 1017 | 1018 | for (j=0;jout_stride = ostride_save; 1032 | *in_len -= ilen; 1033 | *out_len -= olen; 1034 | 1035 | return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS; 1036 | } 1037 | 1038 | EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) 1039 | { 1040 | spx_uint32_t i; 1041 | int istride_save, ostride_save; 1042 | spx_uint32_t bak_out_len = *out_len; 1043 | spx_uint32_t bak_in_len = *in_len; 1044 | istride_save = st->in_stride; 1045 | ostride_save = st->out_stride; 1046 | st->in_stride = st->out_stride = st->nb_channels; 1047 | for (i=0;inb_channels;i++) 1048 | { 1049 | *out_len = bak_out_len; 1050 | *in_len = bak_in_len; 1051 | if (in != NULL) 1052 | speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); 1053 | else 1054 | speex_resampler_process_float(st, i, NULL, in_len, out+i, out_len); 1055 | } 1056 | st->in_stride = istride_save; 1057 | st->out_stride = ostride_save; 1058 | return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS; 1059 | } 1060 | 1061 | EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) 1062 | { 1063 | spx_uint32_t i; 1064 | int istride_save, ostride_save; 1065 | spx_uint32_t bak_out_len = *out_len; 1066 | spx_uint32_t bak_in_len = *in_len; 1067 | istride_save = st->in_stride; 1068 | ostride_save = st->out_stride; 1069 | st->in_stride = st->out_stride = st->nb_channels; 1070 | for (i=0;inb_channels;i++) 1071 | { 1072 | *out_len = bak_out_len; 1073 | *in_len = bak_in_len; 1074 | if (in != NULL) 1075 | speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); 1076 | else 1077 | speex_resampler_process_int(st, i, NULL, in_len, out+i, out_len); 1078 | } 1079 | st->in_stride = istride_save; 1080 | st->out_stride = ostride_save; 1081 | return st->resampler_ptr == resampler_basic_zero ? RESAMPLER_ERR_ALLOC_FAILED : RESAMPLER_ERR_SUCCESS; 1082 | } 1083 | 1084 | EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) 1085 | { 1086 | return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); 1087 | } 1088 | 1089 | EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) 1090 | { 1091 | *in_rate = st->in_rate; 1092 | *out_rate = st->out_rate; 1093 | } 1094 | 1095 | static inline spx_uint32_t compute_gcd(spx_uint32_t a, spx_uint32_t b) 1096 | { 1097 | while (b != 0) 1098 | { 1099 | spx_uint32_t temp = a; 1100 | 1101 | a = b; 1102 | b = temp % b; 1103 | } 1104 | return a; 1105 | } 1106 | 1107 | EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) 1108 | { 1109 | spx_uint32_t fact; 1110 | spx_uint32_t old_den; 1111 | spx_uint32_t i; 1112 | 1113 | if (ratio_num == 0 || ratio_den == 0) 1114 | return RESAMPLER_ERR_INVALID_ARG; 1115 | 1116 | if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) 1117 | return RESAMPLER_ERR_SUCCESS; 1118 | 1119 | old_den = st->den_rate; 1120 | st->in_rate = in_rate; 1121 | st->out_rate = out_rate; 1122 | st->num_rate = ratio_num; 1123 | st->den_rate = ratio_den; 1124 | 1125 | fact = compute_gcd(st->num_rate, st->den_rate); 1126 | 1127 | st->num_rate /= fact; 1128 | st->den_rate /= fact; 1129 | 1130 | if (old_den > 0) 1131 | { 1132 | for (i=0;inb_channels;i++) 1133 | { 1134 | if (multiply_frac(&st->samp_frac_num[i],st->samp_frac_num[i],st->den_rate,old_den) != RESAMPLER_ERR_SUCCESS) 1135 | return RESAMPLER_ERR_OVERFLOW; 1136 | /* Safety net */ 1137 | if (st->samp_frac_num[i] >= st->den_rate) 1138 | st->samp_frac_num[i] = st->den_rate-1; 1139 | } 1140 | } 1141 | 1142 | if (st->initialised) 1143 | return update_filter(st); 1144 | return RESAMPLER_ERR_SUCCESS; 1145 | } 1146 | 1147 | EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) 1148 | { 1149 | *ratio_num = st->num_rate; 1150 | *ratio_den = st->den_rate; 1151 | } 1152 | 1153 | EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality) 1154 | { 1155 | if (quality > 10 || quality < 0) 1156 | return RESAMPLER_ERR_INVALID_ARG; 1157 | if (st->quality == quality) 1158 | return RESAMPLER_ERR_SUCCESS; 1159 | st->quality = quality; 1160 | if (st->initialised) 1161 | return update_filter(st); 1162 | return RESAMPLER_ERR_SUCCESS; 1163 | } 1164 | 1165 | EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) 1166 | { 1167 | *quality = st->quality; 1168 | } 1169 | 1170 | EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) 1171 | { 1172 | st->in_stride = stride; 1173 | } 1174 | 1175 | EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) 1176 | { 1177 | *stride = st->in_stride; 1178 | } 1179 | 1180 | EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) 1181 | { 1182 | st->out_stride = stride; 1183 | } 1184 | 1185 | EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) 1186 | { 1187 | *stride = st->out_stride; 1188 | } 1189 | 1190 | EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st) 1191 | { 1192 | return st->filt_len / 2; 1193 | } 1194 | 1195 | EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st) 1196 | { 1197 | return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate; 1198 | } 1199 | 1200 | EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st) 1201 | { 1202 | spx_uint32_t i; 1203 | for (i=0;inb_channels;i++) 1204 | st->last_sample[i] = st->filt_len/2; 1205 | return RESAMPLER_ERR_SUCCESS; 1206 | } 1207 | 1208 | EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st) 1209 | { 1210 | spx_uint32_t i; 1211 | for (i=0;inb_channels;i++) 1212 | { 1213 | st->last_sample[i] = 0; 1214 | st->magic_samples[i] = 0; 1215 | st->samp_frac_num[i] = 0; 1216 | } 1217 | for (i=0;inb_channels*(st->filt_len-1);i++) 1218 | st->mem[i] = 0; 1219 | return RESAMPLER_ERR_SUCCESS; 1220 | } 1221 | 1222 | EXPORT const char *speex_resampler_strerror(int err) 1223 | { 1224 | switch (err) 1225 | { 1226 | case RESAMPLER_ERR_SUCCESS: 1227 | return "Success."; 1228 | case RESAMPLER_ERR_ALLOC_FAILED: 1229 | return "Memory allocation failed."; 1230 | case RESAMPLER_ERR_BAD_STATE: 1231 | return "Bad resampler state."; 1232 | case RESAMPLER_ERR_INVALID_ARG: 1233 | return "Invalid argument."; 1234 | case RESAMPLER_ERR_PTR_OVERLAP: 1235 | return "Input and output buffers overlap."; 1236 | default: 1237 | return "Unknown error. Bad error code or strange version mismatch."; 1238 | } 1239 | } 1240 | -------------------------------------------------------------------------------- /src/resample_sse.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2007-2008 Jean-Marc Valin 2 | * Copyright (C) 2008 Thorvald Natvig 3 | */ 4 | /** 5 | @file resample_sse.h 6 | @brief Resampler functions (SSE version) 7 | */ 8 | /* 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions 11 | are met: 12 | 13 | - Redistributions of source code must retain the above copyright 14 | notice, this list of conditions and the following disclaimer. 15 | 16 | - Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | 20 | - Neither the name of the Xiph.org Foundation nor the names of its 21 | contributors may be used to endorse or promote products derived from 22 | this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 27 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 28 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | #include 38 | 39 | #define OVERRIDE_INNER_PRODUCT_SINGLE 40 | static inline float inner_product_single(const float *a, const float *b, unsigned int len) 41 | { 42 | int i; 43 | float ret; 44 | __m128 sum = _mm_setzero_ps(); 45 | for (i=0;i 76 | #define OVERRIDE_INNER_PRODUCT_DOUBLE 77 | 78 | static inline double inner_product_double(const float *a, const float *b, unsigned int len) 79 | { 80 | int i; 81 | double ret; 82 | __m128d sum = _mm_setzero_pd(); 83 | __m128 t; 84 | for (i=0;i 2 | File: unicode_support.c 3 | 4 | This file was originally part of a patch included with LameXP, 5 | released under the same license as the original audio tools. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | - Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 22 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #include "unicode_support.h" 31 | 32 | #if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 33 | 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | static wchar_t *utf8_to_utf16(const char *input) 40 | { 41 | wchar_t *Buffer; 42 | int BuffSize = 0, Result = 0; 43 | 44 | BuffSize = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); 45 | Buffer = (wchar_t*) malloc(sizeof(wchar_t) * BuffSize); 46 | if(Buffer) 47 | { 48 | Result = MultiByteToWideChar(CP_UTF8, 0, input, -1, Buffer, BuffSize); 49 | } 50 | 51 | return ((Result > 0) && (Result <= BuffSize)) ? Buffer : NULL; 52 | } 53 | 54 | FILE *opeint_fopen(const char *filename_utf8, const char *mode_utf8) 55 | { 56 | FILE *ret = NULL; 57 | wchar_t *filename_utf16 = utf8_to_utf16(filename_utf8); 58 | wchar_t *mode_utf16 = utf8_to_utf16(mode_utf8); 59 | 60 | if(filename_utf16 && mode_utf16) 61 | { 62 | ret = _wfopen(filename_utf16, mode_utf16); 63 | } 64 | 65 | if(filename_utf16) free(filename_utf16); 66 | if(mode_utf16) free(mode_utf16); 67 | 68 | return ret; 69 | } 70 | 71 | #else 72 | 73 | #include 74 | 75 | FILE *opeint_fopen(const char *filename_utf8, const char *mode_utf8) { 76 | return fopen(filename_utf8, mode_utf8); 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/unicode_support.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2004-2012 LoRd_MuldeR 2 | File: unicode_support.h 3 | 4 | This file was originally part of a patch included with LameXP, 5 | released under the same license as the original audio tools. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions 9 | are met: 10 | 11 | - Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | - Redistributions in binary form must reproduce the above copyright 15 | notice, this list of conditions and the following disclaimer in the 16 | documentation and/or other materials provided with the distribution. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR 22 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #ifndef UNICODE_SUPPORT_H_INCLUDED 31 | #define UNICODE_SUPPORT_H_INCLUDED 32 | 33 | #include 34 | 35 | #define WIN_UNICODE 1 36 | 37 | FILE *opeint_fopen(const char *filename_utf8, const char *mode_utf8); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /update_version: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Creates and updates the package_version information used by configure.ac 4 | # (or other makefiles). When run inside a git repository it will use the 5 | # version information that can be queried from it unless AUTO_UPDATE is set 6 | # to 'no'. If no version is currently known it will be set to 'unknown'. 7 | # 8 | # If called with the argument 'release', the PACKAGE_VERSION will be updated 9 | # even if AUTO_UPDATE=no, but the value of AUTO_UPDATE shall be preserved. 10 | # This is used to force a version update whenever `make dist` is run. 11 | # 12 | # The exit status is 1 if package_version is not modified, else 0 is returned. 13 | # 14 | # This script should NOT be included in distributed tarballs, because if a 15 | # parent directory contains a git repository we do not want to accidentally 16 | # retrieve the version information from it instead. Tarballs should ship 17 | # with only the package_version file. 18 | # 19 | # Ron , 2012. 20 | 21 | SRCDIR=$(dirname $0) 22 | 23 | if [ -e "$SRCDIR/package_version" ]; then 24 | . "$SRCDIR/package_version" 25 | fi 26 | 27 | if [ "$AUTO_UPDATE" = no ]; then 28 | [ "$1" = release ] || exit 1 29 | else 30 | AUTO_UPDATE=yes 31 | fi 32 | 33 | # We run `git status` before describe here to ensure that we don't get a false 34 | # -dirty from files that have been touched but are not actually altered in the 35 | # working dir. 36 | GIT_VERSION=$(cd "$SRCDIR" && git status > /dev/null 2>&1 \ 37 | && git describe --tags --match 'v*' --dirty 2> /dev/null) 38 | GIT_VERSION=${GIT_VERSION#v} 39 | 40 | if [ -n "$GIT_VERSION" ]; then 41 | 42 | [ "$GIT_VERSION" != "$PACKAGE_VERSION" ] || exit 1 43 | PACKAGE_VERSION="$GIT_VERSION" 44 | 45 | elif [ -z "$PACKAGE_VERSION" ]; then 46 | # No current package_version and no git ... 47 | # We really shouldn't ever get here, because this script should only be 48 | # included in the git repository, and should usually be export-ignored. 49 | PACKAGE_VERSION="unknown" 50 | else 51 | exit 1 52 | fi 53 | 54 | cat > "$SRCDIR/package_version" <<-EOF 55 | # Automatically generated by update_version. 56 | # This file may be sourced into a shell script or makefile. 57 | 58 | # Set this to 'no' if you do not wish the version information 59 | # to be checked and updated for every build. Most people will 60 | # never want to change this, it is an option for developers 61 | # making frequent changes that they know will not be released. 62 | AUTO_UPDATE=$AUTO_UPDATE 63 | 64 | PACKAGE_VERSION="$PACKAGE_VERSION" 65 | EOF 66 | -------------------------------------------------------------------------------- /win32/.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio ignores 2 | [Dd]ebug/ 3 | [Dd]ebugDLL/ 4 | [Dd]ebugDLL_fixed/ 5 | [Dd]ebugPublic/ 6 | [Rr]elease/ 7 | [Rr]eleaseDLL/ 8 | [Rr]eleaseDLL_fixed/ 9 | [Rr]eleases/ 10 | .vs/ 11 | *.manifest 12 | *.lastbuildstate 13 | *.lib 14 | *.log 15 | *.idb 16 | *.ipdb 17 | *.ilk 18 | *.iobj 19 | *.obj 20 | *.opensdf 21 | *.pdb 22 | *.sdf 23 | *.suo 24 | *.tlog 25 | *.vcxproj.user 26 | *.vc.db 27 | *.vc.opendb 28 | version.h 29 | -------------------------------------------------------------------------------- /win32/VS2015/common.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | $(Platform)\$(Configuration)\ 7 | $(Platform)\$(Configuration)\$(ProjectName)\ 8 | Unicode 9 | 10 | 11 | true 12 | true 13 | false 14 | 15 | 16 | false 17 | false 18 | true 19 | 20 | 21 | 22 | Level3 23 | false 24 | false 25 | ..\..\..\opus\include;..\..\include;..\;%(AdditionalIncludeDirectories) 26 | _CRT_SECURE_NO_WARNINGS;_LIB;RANDOM_PREFIX=libopusenc;OUTSIDE_SPEEX;HAVE_CONFIG_H;WIN32;%(PreprocessorDefinitions) 27 | false 28 | false 29 | 30 | 31 | Console 32 | 33 | 34 | true 35 | Console 36 | 37 | 38 | 39 | 40 | Guard 41 | ProgramDatabase 42 | NoExtensions 43 | false 44 | true 45 | false 46 | Disabled 47 | false 48 | false 49 | Disabled 50 | MultiThreadedDebug 51 | MultiThreadedDebugDLL 52 | true 53 | false 54 | 55 | 56 | true 57 | 58 | 59 | 60 | 61 | false 62 | None 63 | true 64 | true 65 | false 66 | Speed 67 | Fast 68 | Precise 69 | true 70 | true 71 | true 72 | MaxSpeed 73 | MultiThreaded 74 | MultiThreadedDLL 75 | 16Bytes 76 | 77 | 78 | false 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /win32/VS2015/opusenc.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2010 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "opusenc", "opusenc.vcxproj", "{755C376F-0786-46A6-B706-A55E37430A4A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Win32 = Debug|Win32 11 | Debug|x64 = Debug|x64 12 | DebugDLL|Win32 = DebugDLL|Win32 13 | DebugDLL|x64 = DebugDLL|x64 14 | Release|Win32 = Release|Win32 15 | Release|x64 = Release|x64 16 | ReleaseDLL|Win32 = ReleaseDLL|Win32 17 | ReleaseDLL|x64 = ReleaseDLL|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {755C376F-0786-46A6-B706-A55E37430A4A}.Debug|Win32.ActiveCfg = Debug|Win32 21 | {755C376F-0786-46A6-B706-A55E37430A4A}.Debug|Win32.Build.0 = Debug|Win32 22 | {755C376F-0786-46A6-B706-A55E37430A4A}.Debug|x64.ActiveCfg = Debug|x64 23 | {755C376F-0786-46A6-B706-A55E37430A4A}.Debug|x64.Build.0 = Debug|x64 24 | {755C376F-0786-46A6-B706-A55E37430A4A}.DebugDLL|Win32.ActiveCfg = DebugDLL|Win32 25 | {755C376F-0786-46A6-B706-A55E37430A4A}.DebugDLL|Win32.Build.0 = DebugDLL|Win32 26 | {755C376F-0786-46A6-B706-A55E37430A4A}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 27 | {755C376F-0786-46A6-B706-A55E37430A4A}.DebugDLL|x64.Build.0 = DebugDLL|x64 28 | {755C376F-0786-46A6-B706-A55E37430A4A}.Release|Win32.ActiveCfg = Release|Win32 29 | {755C376F-0786-46A6-B706-A55E37430A4A}.Release|Win32.Build.0 = Release|Win32 30 | {755C376F-0786-46A6-B706-A55E37430A4A}.Release|x64.ActiveCfg = Release|x64 31 | {755C376F-0786-46A6-B706-A55E37430A4A}.Release|x64.Build.0 = Release|x64 32 | {755C376F-0786-46A6-B706-A55E37430A4A}.ReleaseDLL|Win32.ActiveCfg = ReleaseDLL|Win32 33 | {755C376F-0786-46A6-B706-A55E37430A4A}.ReleaseDLL|Win32.Build.0 = ReleaseDLL|Win32 34 | {755C376F-0786-46A6-B706-A55E37430A4A}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 35 | {755C376F-0786-46A6-B706-A55E37430A4A}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {5155F8F7-8F52-4E77-96F3-B57072D180B6} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /win32/VS2015/opusenc.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | DebugDLL 14 | Win32 15 | 16 | 17 | DebugDLL 18 | x64 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | ReleaseDLL 30 | Win32 31 | 32 | 33 | ReleaseDLL 34 | x64 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | {755C376F-0786-46A6-B706-A55E37430A4A} 57 | Win32Proj 58 | opusenc 59 | 60 | 61 | 62 | StaticLibrary 63 | true 64 | v140 65 | 66 | 67 | DynamicLibrary 68 | true 69 | v140 70 | 71 | 72 | StaticLibrary 73 | true 74 | v140 75 | 76 | 77 | DynamicLibrary 78 | true 79 | v140 80 | 81 | 82 | StaticLibrary 83 | false 84 | true 85 | v140 86 | 87 | 88 | DynamicLibrary 89 | false 90 | true 91 | v140 92 | 93 | 94 | StaticLibrary 95 | false 96 | true 97 | v140 98 | 99 | 100 | DynamicLibrary 101 | false 102 | true 103 | v140 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | DLL_EXPORT;%(PreprocessorDefinitions) 144 | 145 | 146 | /ignore:4221 %(AdditionalOptions) 147 | 148 | 149 | "$(ProjectDir)..\..\win32\genversion.bat" "$(ProjectDir)..\..\win32\version.h" PACKAGE_VERSION 150 | Generating version.h 151 | 152 | 153 | ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration) 154 | opus.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 155 | 156 | 157 | ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration) 158 | opus.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 159 | 160 | 161 | ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration) 162 | opus.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 163 | 164 | 165 | ..\..\..\opus\win32\VS2015\$(Platform)\$(Configuration) 166 | opus.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /win32/VS2015/opusenc.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | -------------------------------------------------------------------------------- /win32/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | /* use faster resampler (uses more memory) */ 5 | #define RESAMPLE_FULL_SINC_TABLE 1 6 | 7 | #define OPE_BUILD 8 | 9 | #define PACKAGE_NAME "libopusenc" 10 | 11 | #include "version.h" 12 | 13 | #endif /* CONFIG_H */ 14 | -------------------------------------------------------------------------------- /win32/genversion.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | setlocal enableextensions enabledelayedexpansion 4 | 5 | for /f %%v in ('cd "%~dp0.." ^&^& git status ^>NUL 2^>NUL ^&^& git describe --tags --match "v*" --dirty 2^>NUL') do set version=%%v 6 | 7 | if not "%version%"=="" set version=!version:~1! && goto :gotversion 8 | 9 | if exist "%~dp0..\package_version" goto :getversion 10 | 11 | echo Git cannot be found, nor can package_version. Generating unknown version. 12 | 13 | set version=unknown 14 | 15 | goto :gotversion 16 | 17 | :getversion 18 | 19 | for /f "delims== tokens=2" %%v in (%~dps0..\package_version) do set version=%%v 20 | set version=!version:"=! 21 | 22 | :gotversion 23 | 24 | set version=!version: =! 25 | set version_out=#define %~2 "%version%" 26 | 27 | echo %version_out%> "%~1_temp" 28 | 29 | echo n | comp "%~1_temp" "%~1" > NUL 2> NUL 30 | 31 | if not errorlevel 1 goto exit 32 | 33 | copy /y "%~1_temp" "%~1" 34 | 35 | :exit 36 | 37 | del "%~1_temp" 38 | --------------------------------------------------------------------------------