set SDLMIXER_VENDORED to ON and vendor the required libraries into libs/SDL3_mixer/external

disable SDLMIXER_VORBIS_VORBISFILE
add ogg v1.3.5-SDL
add opus v1.4.x-SDL
add opusfile v0.13-git-SDL
This commit is contained in:
Sven Balzer
2026-04-13 11:20:08 +02:00
parent 85d1832a0c
commit 6ac2b1fde0
588 changed files with 133445 additions and 11 deletions
@@ -0,0 +1,99 @@
name: GitHub CI
on:
push:
pull_request:
schedule:
- cron: '0 0 1 * *'
jobs:
build:
strategy:
matrix:
name:
[
ubuntu-autotools,
ubuntu-cmake,
ubuntu-makefile,
macos-autotools,
macos-cmake,
macos-makefile,
]
include:
- name: ubuntu-autotools
os: ubuntu-latest
build-system: autotools
- name: ubuntu-cmake
os: ubuntu-latest
build-system: cmake
- name: ubuntu-makefile
os: ubuntu-latest
build-system: makefile
- name: macos-autotools
os: macos-latest
build-system: autotools
- name: macos-cmake
os: macos-latest
build-system: cmake
- name: macos-makefile
os: macos-latest
build-system: makefile
runs-on: ${{ matrix.os }}
env:
BUILD: _build
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Install Linux dependencies
if: startsWith(matrix.os,'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y libopus-dev libogg-dev libssl-dev
sudo apt-get install -y doxygen graphviz
- name: Install macOS dependencies
if: startsWith(matrix.os,'macos')
run: |
brew bundle
- name: Build with Autotools
if: startsWith(matrix.build-system,'autotools')
run: |
./autogen.sh
./configure
make
make check
- name: distcheck with Autotools
if: startsWith(matrix.build-system,'autotools')
run: |
make distcheck
- name: Build with Makefile
if: startsWith(matrix.build-system,'makefile')
run: |
make -C unix
make -C unix check
- name: Build Documentation
if: ${{ ! startsWith(matrix.build-system,'cmake') }}
run: |
make -C doc
- name: Build with CMake
if: startsWith(matrix.build-system,'cmake')
run: |
cmake -S . -B ${{ env.BUILD }}
cmake --build ${{ env.BUILD }}
ctest --test-dir ${{ env.BUILD }} -V -C Debug
+72
View File
@@ -0,0 +1,72 @@
default:
tags:
- docker
# Image from https://hub.docker.com/_/gcc/ based on Debian
image: gcc:9
autotools:
stage: build
before_script:
- apt-get update &&
apt-get install -y libopus-dev libogg-dev libssl-dev
zip
script:
- ./autogen.sh
- ./configure
- make
- make distcheck
cmake-3.16:
stage: build
before_script:
- apt-get update &&
apt-get install -y libopus-dev libogg-dev libssl-dev
doxygen
script:
- curl -O https://cmake.org/files/v3.16/cmake-3.16.9-Linux-x86_64.tar.gz
- tar xzf cmake-3.16.9-Linux-x86_64.tar.gz
- cmake-3.16.9-Linux-x86_64/bin/cmake -Bbuild -H.
- cmake-3.16.9-Linux-x86_64/bin/cmake --build build
tags:
- docker
cmake:
stage: build
before_script:
- apt-get update &&
apt-get install -y libopus-dev libogg-dev libssl-dev
cmake doxygen
script:
- cmake -Bbuild -H.
- cmake --build build
tags:
- docker
cmake-nohttp:
stage: build
before_script:
- apt-get update &&
apt-get install -y libopus-dev libogg-dev libssl-dev
cmake doxygen
script:
- cmake -Bbuild -H. -D OP_DISABLE_HTTP=YES
- cmake --build build
tags:
- docker
makefile:
stage: build
before_script:
- apt-get update &&
apt-get install -y libopus-dev libogg-dev libssl-dev
script:
- make -C unix
- make -C unix check
doc:
stage: build
before_script:
- apt-get update &&
apt-get install -y doxygen graphviz
script:
- make -C doc
+38
View File
@@ -0,0 +1,38 @@
language: c
compiler:
- gcc
- clang
os:
- linux
- osx
osx_image: xcode11.3
addons:
apt:
packages:
- doxygen
- libogg-dev
- libopus-dev
- libssl-dev
homebrew:
brewfile: true
env: PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/opt/openssl/lib/pkgconfig
before_script:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
curl -O https://cmake.org/files/v3.16/cmake-3.16.9-Linux-x86_64.tar.gz;
tar xzf cmake-3.16.9-Linux-x86_64.tar.gz;
export PATH="${PWD}/cmake-3.16.9-Linux-x86_64/bin:${PATH}";
fi
script:
- cmake -Bbuild -H.
- cmake --build build
- ./autogen.sh
- ./configure
- make
- make distcheck
+5
View File
@@ -0,0 +1,5 @@
Timothy B. Terriberry <tterribe@xiph.org>
Ralph Giles <giles@xiph.org>
Christopher "Monty" Montgomery <xiphmont@xiph.org> (original libvorbisfile)
Gregory Maxwell <greg@xiph.org> (noise shaping dithering)
nu774 <honeycomb77@gmail.com> (original winsock support)
+22
View File
@@ -0,0 +1,22 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := opusfile
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include
LOCAL_CFLAGS := -DOPUS_BUILD -DHAVE_LRINTF -DFLOATING_POINT -DFLOAT_APPROX -DUSE_ALLOCA
LOCAL_SRC_FILES += \
src/http.c \
src/info.c \
src/internal.c \
src/opusfile.c \
src/stream.c \
src/wincerts.c
LOCAL_SHARED_LIBRARIES := opus
include $(BUILD_STATIC_LIBRARY)
+9
View File
@@ -0,0 +1,9 @@
brew 'opus'
brew 'libogg'
brew 'openssl'
brew 'autoconf'
brew 'automake'
brew 'libtool'
brew 'pkg-config'
brew 'cmake'
brew 'doxygen'
+321
View File
@@ -0,0 +1,321 @@
cmake_minimum_required(VERSION 3.16)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
include(OpusFilePackageVersion)
get_package_version(PACKAGE_VERSION PROJECT_VERSION)
string(REPLACE "." ";" PROJECT_VERSION_LIST ${PROJECT_VERSION})
list(GET PROJECT_VERSION_LIST 0 PROJECT_VERSION_MAJOR)
list(GET PROJECT_VERSION_LIST 1 PROJECT_VERSION_MINOR)
project(OpusFile
VERSION ${PROJECT_VERSION}
LANGUAGES C
)
option(OP_DISABLE_HTTP "Disable HTTP support" OFF)
option(OP_DISABLE_FLOAT_API "Disable floating-point API" OFF)
option(OP_FIXED_POINT "Enable fixed-point calculation" OFF)
option(OP_ENABLE_ASSERTIONS "Enable assertions in code" OFF)
option(OP_DISABLE_EXAMPLES "Do not build example applications" OFF)
option(OP_DISABLE_DOCS "Do not build API documentation" OFF)
include(GNUInstallDirs)
if (NOT TARGET Ogg::ogg)
find_package(Ogg REQUIRED)
endif()
if (NOT TARGET Opus::opus)
find_package(Opus REQUIRED)
endif()
include(CMakePushCheckState)
include(CheckSymbolExists)
cmake_push_check_state(RESET)
include(CheckLibraryExists)
check_library_exists(m lrintf "" OP_HAVE_LIBM)
if(OP_HAVE_LIBM)
list(APPEND CMAKE_REQUIRED_LIBRARIES "m")
endif()
check_symbol_exists(lrintf "math.h" OP_HAVE_LRINTF)
cmake_pop_check_state()
add_library(opusfile
"${CMAKE_CURRENT_SOURCE_DIR}/include/opusfile.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/info.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/internal.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/internal.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/opusfile.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/stream.c"
)
add_library(OpusFile::opusfile ALIAS opusfile)
set_target_properties(opusfile PROPERTIES
#PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/opusfile.h"
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
if(WIN32 AND BUILD_SHARED_LIBS)
# FIXME: keep soversion in sync with autotools
set_property(TARGET opusfile PROPERTY RUNTIME_OUTPUT_NAME "opusfile-0")
# Requires CMake 3.27, so not sufficient
set_property(TARGET opusfile PROPERTY DLL_NAME_WITH_SOVERSION FALSE)
endif()
target_include_directories(opusfile
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/opus>
)
target_link_libraries(opusfile
PUBLIC
Ogg::ogg
Opus::opus
$<$<BOOL:${OP_HAVE_LIBM}>:m>
)
target_compile_options(opusfile
PRIVATE
$<$<C_COMPILER_ID:MSVC>:/wd4267>
$<$<C_COMPILER_ID:MSVC>:/wd4244>
$<$<C_COMPILER_ID:MSVC>:/wd4090>
$<$<C_COMPILER_ID:Clang,GNU>:-std=c89>
$<$<C_COMPILER_ID:Clang,GNU>:-pedantic>
$<$<C_COMPILER_ID:Clang,GNU>:-Wall>
$<$<C_COMPILER_ID:Clang,GNU>:-Wextra>
$<$<C_COMPILER_ID:Clang,GNU>:-Wno-parentheses>
$<$<C_COMPILER_ID:Clang,GNU>:-Wno-long-long>
$<$<C_COMPILER_ID:Clang,GNU>:-fvisibility=hidden>
)
target_compile_definitions(opusfile
PRIVATE
$<$<BOOL:${OP_DISABLE_FLOAT_API}>:OP_DISABLE_FLOAT_API>
$<$<BOOL:${OP_FIXED_POINT}>:OP_FIXED_POINT>
$<$<BOOL:${OP_ENABLE_ASSERTIONS}>:OP_ENABLE_ASSERTIONS>
$<$<BOOL:${OP_HAVE_LRINTF}>:OP_HAVE_LRINTF>
)
install(TARGETS opusfile
EXPORT OpusFileTargets
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/opus"
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/opus"
)
if(NOT OP_DISABLE_HTTP)
find_package(OpenSSL REQUIRED)
include(CheckIncludeFile)
include(CheckCSourceCompiles)
cmake_push_check_state(RESET)
if(NOT WIN32)
check_include_file("sys/socket.h" OP_HAVE_SYS_SOCKET_H)
if(NOT OP_HAVE_SYS_SOCKET_H)
message(FATAL_ERROR "HTTP support requires a POSIX socket library")
endif()
check_symbol_exists(getsockopt "sys/socket.h" OP_HAVE_GETSOCKOPT)
if(NOT OP_HAVE_GETSOCKOPT)
cmake_push_check_state()
list(APPEND CMAKE_REQUIRED_LIBRARIES "socket")
check_symbol_exists(getsockopt "sys/socket.h" OP_NEED_SOCKET)
cmake_pop_check_state()
endif()
endif()
check_c_source_compiles(
"#include <time.h>
int main(void)
{
struct timespec ts;
return clock_gettime(CLOCK_REALTIME, &ts);
}"
OP_HAVE_CLOCK_GETTIME
)
if(NOT OP_HAVE_CLOCK_GETTIME)
check_symbol_exists(ftime "sys/timeb.h" OP_HAVE_FTIME)
if(NOT OP_HAVE_FTIME)
message(FATAL_ERROR "HTTP support requires either clock_gettime() or ftime()")
endif()
endif()
cmake_pop_check_state()
endif()
add_library(opusurl
"${CMAKE_CURRENT_SOURCE_DIR}/include/opusfile.h"
"${CMAKE_CURRENT_SOURCE_DIR}/src/http.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/internal.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/internal.h"
)
add_library(OpusFile::opusurl ALIAS opusurl)
if(WIN32)
target_sources(opusurl PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/src/wincerts.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/winerrno.h"
)
endif()
set_target_properties(opusurl PROPERTIES
PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/include/opusfile.h"
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
target_include_directories(opusurl
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/opus>
)
target_compile_definitions(opusurl
PRIVATE
$<$<BOOL:${OP_DISABLE_FLOAT_API}>:OP_DISABLE_FLOAT_API>
$<$<BOOL:${OP_FIXED_POINT}>:OP_FIXED_POINT>
$<$<BOOL:${OP_ENABLE_ASSERTIONS}>:OP_ENABLE_ASSERTIONS>
$<$<BOOL:${OP_HAVE_LRINTF}>:OP_HAVE_LRINTF>
$<$<BOOL:${OP_HAVE_CLOCK_GETTIME}>:OP_HAVE_CLOCK_GETTIME>
$<$<BOOL:${OP_HAVE_FTIME}>:OP_HAVE_FTIME>
$<$<NOT:$<BOOL:${OP_DISABLE_HTTP}>>:OP_ENABLE_HTTP>
)
target_link_libraries(opusurl
PRIVATE
opusfile
$<$<NOT:$<BOOL:${OP_DISABLE_HTTP}>>:OpenSSL::SSL>
$<$<C_COMPILER_ID:MSVC>:ws2_32>
$<$<C_COMPILER_ID:MSVC>:crypt32>
$<$<BOOL:${OP_HAVE_LIBM}>:m>
$<$<BOOL:${OP_NEED_SOCKET}>:socket>
)
target_compile_options(opusurl
PRIVATE
$<$<C_COMPILER_ID:MSVC>:/wd4267>
$<$<C_COMPILER_ID:MSVC>:/wd4244>
$<$<C_COMPILER_ID:MSVC>:/wd4090>
$<$<C_COMPILER_ID:Clang,GNU>:-std=c89>
$<$<C_COMPILER_ID:Clang,GNU>:-pedantic>
$<$<C_COMPILER_ID:Clang,GNU>:-Wall>
$<$<C_COMPILER_ID:Clang,GNU>:-Wextra>
$<$<C_COMPILER_ID:Clang,GNU>:-Wno-parentheses>
$<$<C_COMPILER_ID:Clang,GNU>:-Wno-long-long>
$<$<C_COMPILER_ID:Clang,GNU>:-fvisibility=hidden>
)
install(TARGETS opusurl
EXPORT OpusFileTargets
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/opus"
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/opus"
)
if(NOT OP_DISABLE_EXAMPLES)
add_executable(opusfile_example
"${CMAKE_CURRENT_SOURCE_DIR}/examples/opusfile_example.c"
)
add_executable(OpusFile::opusfile_example ALIAS opusfile_example)
if(WIN32)
target_sources(opusfile_example PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/examples/win32utf8.c"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/win32utf8.h"
)
endif()
target_include_directories(opusfile_example
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/examples"
)
target_link_libraries(opusfile_example
PRIVATE
opusfile
opusurl
)
target_compile_options(opusfile_example
PRIVATE
$<$<C_COMPILER_ID:MSVC>:/wd4267>
$<$<C_COMPILER_ID:MSVC>:/wd4244>
$<$<C_COMPILER_ID:MSVC>:/wd4090>
$<$<C_COMPILER_ID:Clang,GNU>:-std=c89>
$<$<C_COMPILER_ID:Clang,GNU>:-pedantic>
$<$<C_COMPILER_ID:Clang,GNU>:-Wall>
$<$<C_COMPILER_ID:Clang,GNU>:-Wextra>
$<$<C_COMPILER_ID:Clang,GNU>:-Wno-parentheses>
$<$<C_COMPILER_ID:Clang,GNU>:-Wno-long-long>
$<$<C_COMPILER_ID:Clang,GNU>:-fvisibility=hidden>
)
add_executable(seeking_example
"${CMAKE_CURRENT_SOURCE_DIR}/examples/seeking_example.c"
)
add_executable(OpusFile::seeking_example ALIAS seeking_example)
if(WIN32)
target_sources(seeking_example PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/examples/win32utf8.c"
"${CMAKE_CURRENT_SOURCE_DIR}/examples/win32utf8.h"
)
endif()
target_include_directories(seeking_example
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/examples"
)
target_link_libraries(seeking_example
PRIVATE
opusfile
opusurl
)
target_compile_options(seeking_example
PRIVATE
$<$<C_COMPILER_ID:MSVC>:/wd4267>
$<$<C_COMPILER_ID:MSVC>:/wd4244>
$<$<C_COMPILER_ID:MSVC>:/wd4090>
$<$<C_COMPILER_ID:Clang,GNU>:-std=c89>
$<$<C_COMPILER_ID:Clang,GNU>:-pedantic>
$<$<C_COMPILER_ID:Clang,GNU>:-Wall>
$<$<C_COMPILER_ID:Clang,GNU>:-Wextra>
$<$<C_COMPILER_ID:Clang,GNU>:-Wno-parentheses>
$<$<C_COMPILER_ID:Clang,GNU>:-Wno-long-long>
$<$<C_COMPILER_ID:Clang,GNU>:-fvisibility=hidden>
)
endif()
if(NOT OP_DISABLE_DOCS)
find_package(Doxygen OPTIONAL_COMPONENTS dot)
set(DOXYGEN_PROJECT_BRIEF "Stand-alone decoder library for .opus files.")
set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES)
set(DOXYGEN_QUIET YES)
set(DOXYGEN_WARNINGS YES)
set(DOXYGEN_WARN_IF_UNDOCUMENTED YES)
set(DOXYGEN_WARN_IF_DOC_ERROR YES)
set(DOXYGEN_WARN_NO_PARAMDOC YES)
set(DOXYGEN_JAVADOC_AUTOBRIEF YES)
set(DOXYGEN_SORT_MEMBER_DOCS NO)
set(DOXYGEN_PROJECT_LOGO "${CMAKE_CURRENT_SOURCE_DIR}/doc/opus_logo.svg")
set(DOXYGEN_FULL_PATH_NAMES NO)
doxygen_add_docs(doxygen "${CMAKE_CURRENT_SOURCE_DIR}/include/opusfile.h" ALL USE_STAMP_FILE)
endif()
if(0) # when vendoring opusfile in SDL_mixer, libogg is also vendored and thus missing from this the OpusFileTargets export set
install(EXPORT OpusFileTargets
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/opusfile"
NAMESPACE OpusFile::
)
endif()
include(CMakePackageConfigHelpers)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/OpusFileConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/OpusFileConfig.cmake"
INSTALL_DESTINATION
"${CMAKE_INSTALL_LIBDIR}/cmake/opusfile"
)
write_basic_package_version_file(
"OpusFileConfigVersion.cmake"
VERSION "${PACKAGE_VERSION}"
COMPATIBILITY AnyNewerVersion
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/OpusFileConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/OpusFileConfigVersion.cmake"
DESTINATION
"${CMAKE_INSTALL_LIBDIR}/cmake/opusfile"
)
+28
View File
@@ -0,0 +1,28 @@
Copyright (c) 1994-2013 Xiph.Org Foundation and contributors
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.Org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+141
View File
@@ -0,0 +1,141 @@
ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -I$(top_srcdir)/include $(DEPS_CFLAGS)
dist_doc_DATA = COPYING AUTHORS README.md
opusincludedir = ${includedir}/opus
opusinclude_HEADERS = include/opusfile.h
lib_LTLIBRARIES = libopusfile.la libopusurl.la
libopusfile_la_SOURCES = \
src/info.c \
src/internal.c src/internal.h \
src/opusfile.c src/stream.c
libopusfile_la_LIBADD = $(DEPS_LIBS) $(lrintf_lib)
libopusfile_la_LDFLAGS = -no-undefined \
-version-info @OP_LT_CURRENT@:@OP_LT_REVISION@:@OP_LT_AGE@
libopusurl_la_SOURCES = src/http.c src/internal.c src/internal.h
libopusurl_la_CFLAGS = $(AM_CFLAGS) $(URL_DEPS_CFLAGS)
libopusurl_la_LIBADD = libopusfile.la $(URL_DEPS_LIBS)
libopusurl_la_LDFLAGS = -no-undefined \
-version-info @OP_LT_CURRENT@:@OP_LT_REVISION@:@OP_LT_AGE@
if OP_ENABLE_EXAMPLES
noinst_PROGRAMS = examples/opusfile_example examples/seeking_example
endif
examples_opusfile_example_SOURCES = examples/opusfile_example.c
examples_seeking_example_SOURCES = examples/seeking_example.c
examples_opusfile_example_LDADD = libopusurl.la libopusfile.la
examples_seeking_example_LDADD = libopusurl.la libopusfile.la
if OP_WIN32
if OP_ENABLE_HTTP
libopusurl_la_SOURCES += src/wincerts.c src/winerrno.h
libopusurl_la_LIBADD += -lws2_32 -lcrypt32
endif
examples_opusfile_example_SOURCES += examples/win32utf8.c examples/win32utf8.h
examples_seeking_example_SOURCES += examples/win32utf8.c examples/win32utf8.h
endif
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = opusfile.pc opusurl.pc
debug:
$(MAKE) CFLAGS="${CFLAGS} -O0 -ggdb -DOP_ENABLE_ASSERTIONS" all
EXTRA_DIST = \
opusfile.pc.in \
opusurl.pc.in \
opusfile-uninstalled.pc.in \
opusurl-uninstalled.pc.in \
doc/Doxyfile.in \
doc/opus_logo.svg \
doc/Makefile \
unix/Makefile \
cmake/FindOgg.cmake \
cmake/FindOpus.cmake \
cmake/OpusFileConfig.cmake.in \
cmake/OpusFilePackageVersion.cmake \
CMakeLists.txt
# Targets to build and install just the library without the docs
opusfile install-opusfile: NO_DOXYGEN = 1
opusfile: all
install-opusfile: install
# Or just the docs
docs: doc/doxygen-build.stamp
install-docs:
@if [ -z "$(NO_DOXYGEN)" ]; then \
( cd doc && \
echo "Installing documentation in $(DESTDIR)$(docdir)"; \
$(INSTALL) -d $(DESTDIR)$(docdir)/html/search; \
for f in `find html -type f \! -name "installdox"` ; do \
$(INSTALL_DATA) $$f $(DESTDIR)$(docdir)/$$f; \
done ) \
fi
doc/doxygen-build.stamp: doc/Doxyfile $(top_srcdir)/doc/opus_logo.svg \
$(top_srcdir)/include/*.h
@[ -n "$(NO_DOXYGEN)" ] || ( cd doc && doxygen && touch $(@F) )
if HAVE_DOXYGEN
# Or everything (by default)
all-local: docs
install-data-local: install-docs
clean-local:
$(RM) -r doc/html
$(RM) -r doc/latex
$(RM) doc/doxygen-build.stamp
uninstall-local:
$(RM) -r $(DESTDIR)$(docdir)/html
endif
# We check this every time make is run, with configure.ac being touched to
# trigger an update of the build system files if update_version changes the
# current PACKAGE_VERSION (or if package_version was modified manually by a
# user with either AUTO_UPDATE=no or no update_version script present - the
# latter being the normal case for tarball releases).
#
# We can't just add the package_version file to CONFIGURE_DEPENDENCIES since
# simply running autoconf will not actually regenerate configure for us when
# the content of that file changes (due to autoconf dependency checking not
# knowing about that without us creating yet another file for it to include).
#
# The MAKECMDGOALS check is a gnu-make'ism, but will degrade 'gracefully' for
# makes that don't support it. The only loss of functionality is not forcing
# an update of package_version for `make dist` if AUTO_UPDATE=no, but that is
# unlikely to be a real problem for any real user.
$(top_srcdir)/configure.ac: force
@case "$(MAKECMDGOALS)" in \
dist-hook) exit 0 ;; \
dist-* | dist | distcheck | distclean) _arg=release ;; \
esac; \
if ! $(top_srcdir)/update_version $$_arg 2> /dev/null; then \
if [ ! -e $(top_srcdir)/package_version ]; then \
echo 'PACKAGE_VERSION="unknown"' > $(top_srcdir)/package_version; \
fi; \
. $(top_srcdir)/package_version || exit 1; \
[ "$(PACKAGE_VERSION)" != "$$PACKAGE_VERSION" ] || exit 0; \
fi; \
touch $@
force:
# Create a minimal package_version file when make dist is run.
dist-hook:
echo 'PACKAGE_VERSION="$(PACKAGE_VERSION)"' > $(top_distdir)/package_version
.PHONY: opusfile install-opusfile docs install-docs
+17
View File
@@ -0,0 +1,17 @@
# Opusfile
[![GitLab Pipeline Status](https://gitlab.xiph.org/xiph/opusfile/badges/master/pipeline.svg)](https://gitlab.xiph.org/xiph/opusfile/commits/master)
[![GitHub CI](https://github.com/xiph/opusfile/actions/workflows/build.yml/badge.svg)](https://github.com/xiph/opusfile/actions/workflows/build.yml)
The opusfile and opusurl libraries provide a high-level API for
decoding and seeking within .opus files on disk or over http(s).
opusfile depends on libopus and libogg.
opusurl depends on opusfile and openssl.
The library is functional, but there are likely issues
we didn't find in our own testing. Please give feedback
in #opus on irc.libera.chat or at opus@xiph.org.
Programming documentation is available in tree and online at
https://opus-codec.org/docs/
+10
View File
@@ -0,0 +1,10 @@
#!/bin/sh
# Run this to set up the build system: configure, makefiles, etc.
set -e
srcdir=`dirname $0`
test -n "$srcdir" && cd "$srcdir"
echo "Updating build configuration files for opusfile, please wait...."
autoreconf -isf
+65
View File
@@ -0,0 +1,65 @@
# Continuous integration build script for opusfile.
# This script is run by automated frameworks to verify commits
# see https://mf4.xiph.org/jenkins/job/opusfile-autotools/
# This is intended to be run from the top-level source directory.
set -x
# WARNING: clobbers outside the current tree!
rm -f ../opus
ln -s /srv/jenkins/jobs/opus/workspace ../opus
rm -f ../ogg
ln -s /srv/jenkins/jobs/libogg/workspace ../ogg
# HACK: libtool can't link a dynamic library to a static
# library, and the 'unix' makefile build can't link to
# a libopus.la. As a work around, hack our own pkg-config
# file for the uninstalled opus library we want to build
# against.
cat <<EOF > opus-uninstalled.pc
# Opus codec uninstalled pkg-config file
# hacked up for the opusfile autotools build.
libdir=\${pcfiledir}/../opus
includedir=\${libdir}/include
Name: opus uninstalled for opusfile
Description: Opus IETF audio codec (not installed)
Version: 1.0.1
Requires:
Conflicts:
Libs: \${libdir}/libopus.la -lm
Cflags: -I\${includedir}
EOF
cat <<EOF > ogg-uninstalled.pc
# ogg uninstalled pkg-config file
# hacked up for the opusfile autotools build
libdir=\${pcfiledir}/../ogg/src
includedir=\${pcfiledir}/../ogg/include
Name: ogg uninstalled for opusfile
Description: ogg is a library for manipulating ogg bitstreams (not installed)
Version: 1.3.0
Requires:
Conflicts:
Libs: \${libdir}/libogg.la
Cflags: -I\${includedir}
EOF
PKG_CONFIG_PATH=$PWD
# compile
./autogen.sh
./configure PKG_CONFIG_PATH=${PKG_CONFIG_PATH}
make clean
make
# verify distribution target
make distcheck PKG_CONFIG_PATH=${PKG_CONFIG_PATH}
# build the documentation
# currently fails on jenkins (debian stretch)
# make -C doc/latex
+23
View File
@@ -0,0 +1,23 @@
# Continuous integration build script for opusfile.
# This script is run by automated frameworks to verify commits
# see https://mf4.xiph.org/jenkins/job/opusfile-unix/
# This is intended to be run from the top-level source directory.
set -x
# WARNING: clobbers outside the current tree!
rm -f ../opus
ln -s /srv/jenkins/jobs/opus/workspace ../opus
# compile
make -C unix PKG_CONFIG_PATH=$PWD/../opus clean
make -C unix PKG_CONFIG_PATH=$PWD/../opus
# run any built-in tests
make -C unix PKG_CONFIG_PATH=$PWD/../opus check
# build the documentation
make -C doc
# currently fails on jenkins (debian stretch)
# make -C doc/latex
+7
View File
@@ -0,0 +1,7 @@
find_package(Ogg CONFIG)
if(NOT TARGET Ogg::ogg)
find_package(PkgConfig REQUIRED)
pkg_check_modules(Ogg REQUIRED IMPORTED_TARGET ogg)
set_target_properties(PkgConfig::Ogg PROPERTIES IMPORTED_GLOBAL TRUE)
add_library(Ogg::ogg ALIAS PkgConfig::Ogg)
endif()
@@ -0,0 +1,7 @@
find_package(Opus CONFIG)
if(NOT TARGET Opus::opus)
find_package(PkgConfig REQUIRED)
pkg_check_modules(Opus REQUIRED IMPORTED_TARGET opus)
set_target_properties(PkgConfig::Opus PROPERTIES IMPORTED_GLOBAL TRUE)
add_library(Opus::opus ALIAS PkgConfig::Opus)
endif()
@@ -0,0 +1,52 @@
@PACKAGE_INIT@
# Ported from CMakeFindDependencyMacro.cmake (finding configs and using pkgconfig as fallback)
set(cmake_quiet_arg)
if(${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
set(cmake_quiet_arg QUIET)
endif()
set(cmake_required_arg)
if(${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
set(cmake_required_arg REQUIRED)
endif()
find_package(Ogg CONFIG ${cmake_quiet_arg})
if(NOT TARGET Ogg::ogg)
find_package(PkgConfig REQUIRED ${cmake_quiet_arg})
pkg_check_modules(Ogg ${cmake_required_arg} ${cmake_quiet_arg} IMPORTED_TARGET ogg)
set_target_properties(PkgConfig::Ogg PROPERTIES IMPORTED_GLOBAL TRUE)
add_library(Ogg::ogg ALIAS PkgConfig::Ogg)
endif()
if (NOT TARGET Ogg::ogg)
set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency Ogg could not be found.")
set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
return()
endif()
find_package(Opus CONFIG ${cmake_quiet_arg})
if(NOT TARGET Opus::opus)
find_package(PkgConfig REQUIRED ${cmake_quiet_arg})
pkg_check_modules(Opus ${cmake_required_arg} ${cmake_quiet_arg} IMPORTED_TARGET opus)
set_target_properties(PkgConfig::Opus PROPERTIES IMPORTED_GLOBAL TRUE)
add_library(Opus::opus ALIAS PkgConfig::Opus)
endif()
if (NOT TARGET Opus::opus)
set(${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE "${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency Opus could not be found.")
set(${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
return()
endif()
set(cmake_fd_required_arg)
set(cmake_fd_quiet_arg)
if (NOT @OP_DISABLE_HTTP@)
include(CMakeFindDependencyMacro)
find_dependency(OpenSSL)
endif()
# Including targets of opusfile
include("${CMAKE_CURRENT_LIST_DIR}/OpusFileTargets.cmake")
check_required_components(OpusFile)
@@ -0,0 +1,71 @@
if(__opusfile_version)
return()
endif()
set(__opusfile_version INCLUDED)
function(get_package_version PACKAGE_VERSION PROJECT_VERSION)
find_package(Git)
if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE}
--git-dir=${CMAKE_CURRENT_LIST_DIR}/.git describe
--tags --match "v*" OUTPUT_VARIABLE OPUSFILE_PACKAGE_VERSION)
if(OPUSFILE_PACKAGE_VERSION)
string(STRIP ${OPUSFILE_PACKAGE_VERSION}, OPUSFILE_PACKAGE_VERSION)
string(REPLACE \n
""
OPUSFILE_PACKAGE_VERSION
${OPUSFILE_PACKAGE_VERSION})
string(REPLACE ,
""
OPUSFILE_PACKAGE_VERSION
${OPUSFILE_PACKAGE_VERSION})
string(SUBSTRING ${OPUSFILE_PACKAGE_VERSION}
1
-1
OPUSFILE_PACKAGE_VERSION)
message(STATUS "Opus package version from git repo: ${OPUSFILE_PACKAGE_VERSION}")
endif()
endif()
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/package_version"
AND NOT OPUSFILE_PACKAGE_VERSION)
# Not a git repo, lets' try to parse it from package_version file if exists
file(STRINGS package_version OPUSFILE_PACKAGE_VERSION
LIMIT_COUNT 1
REGEX "PACKAGE_VERSION=")
string(REPLACE "PACKAGE_VERSION="
""
OPUSFILE_PACKAGE_VERSION
${OPUSFILE_PACKAGE_VERSION})
string(REPLACE "\""
""
OPUSFILE_PACKAGE_VERSION
${OPUSFILE_PACKAGE_VERSION})
# In case we have a unknown dist here we just replace it with 0
string(REPLACE "unknown"
"0"
OPUSFILE_PACKAGE_VERSION
${OPUSFILE_PACKAGE_VERSION})
message(STATUS "Opus package version from package_version file: ${OPUSFILE_PACKAGE_VERSION}")
endif()
if(OPUSFILE_PACKAGE_VERSION)
string(REGEX
REPLACE "^([0-9]+.[0-9]+\\.?([0-9]+)?).*"
"\\1"
OPUSFILE_PROJECT_VERSION
${OPUSFILE_PACKAGE_VERSION})
else()
# fail to parse version from git and package version
message(WARNING "Could not get package version.")
set(OPUSFILE_PACKAGE_VERSION 0)
set(OPUSFILE_PROJECT_VERSION 0.0)
endif()
message(STATUS "Opus project version: ${OPUSFILE_PROJECT_VERSION}")
set(PACKAGE_VERSION ${OPUSFILE_PACKAGE_VERSION} PARENT_SCOPE)
set(PROJECT_VERSION ${OPUSFILE_PROJECT_VERSION} PARENT_SCOPE)
endfunction()
+210
View File
@@ -0,0 +1,210 @@
# autoconf source script for generating configure
dnl The package_version file will be automatically synced to the git revision
dnl by the update_version script when configured in the repository, but will
dnl remain constant in tarball releases unless it is manually edited.
m4_define([CURRENT_VERSION],
m4_esyscmd([ ./update_version 2>/dev/null || true
if test -e package_version; then
. ./package_version
printf "$PACKAGE_VERSION"
else
printf "unknown"
fi ]))
AC_INIT([opusfile],[CURRENT_VERSION],[opus@xiph.org])
AC_CONFIG_SRCDIR([src/opusfile.c])
AC_CONFIG_MACRO_DIR([m4])
AC_USE_SYSTEM_EXTENSIONS
AC_SYS_LARGEFILE
AM_INIT_AUTOMAKE([1.11 foreign no-define dist-zip subdir-objects])
AM_MAINTAINER_MODE([enable])
LT_INIT
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
dnl Library versioning for libtool.
dnl Please update these for releases.
dnl CURRENT, REVISION, AGE
dnl - library source changed -> increment REVISION
dnl - interfaces added/removed/changed -> increment CURRENT, REVISION = 0
dnl - interfaces added -> increment AGE
dnl - interfaces removed -> AGE = 0
OP_LT_CURRENT=4
OP_LT_REVISION=5
OP_LT_AGE=4
AC_SUBST(OP_LT_CURRENT)
AC_SUBST(OP_LT_REVISION)
AC_SUBST(OP_LT_AGE)
CC_CHECK_CFLAGS_APPEND(
[-std=c89 -pedantic -Wall -Wextra -Wno-parentheses -Wno-long-long])
# Platform-specific tweaks
case $host in
*-mingw*)
# -std=c89 causes some warnings under mingw.
CC_CHECK_CFLAGS_APPEND([-U__STRICT_ANSI__])
# We need WINNT>=0x501 (WindowsXP) for getaddrinfo/freeaddrinfo.
# It's okay to define this even when HTTP support is disabled, as it only
# affects header declarations, not linking (unless we actually use some
# XP-only functions).
AC_DEFINE_UNQUOTED(_WIN32_WINNT,0x501,
[We need at least WindowsXP for getaddrinfo/freeaddrinfo])
host_mingw=true
;;
esac
AM_CONDITIONAL(OP_WIN32, [test "$host_mingw" = "true"])
AC_ARG_ENABLE([assertions],
AS_HELP_STRING([--enable-assertions], [Enable assertions in code]),,
enable_assertions=no)
AS_IF([test "$enable_assertions" = "yes"], [
AC_DEFINE([OP_ENABLE_ASSERTIONS], [1], [Enable assertions in code])
])
AC_ARG_ENABLE([http],
AS_HELP_STRING([--disable-http], [Disable HTTP support]),,
enable_http=yes)
AM_COND_IF(OP_WIN32, [
AS_IF([test "$enable_http" != "no"], [
AC_CHECK_HEADER([winsock2.h],, [
AC_MSG_WARN([HTTP support requires a Winsock socket library.])
enable_http=no
])
])
], [
AS_IF([test "$enable_http" != "no"], [
AC_CHECK_HEADER([sys/socket.h],, [
AC_MSG_WARN([HTTP support requires a POSIX socket library.])
enable_http=no
])
])
])
# HTTP support requires either clock_gettime or ftime. clock_gettime is
# used only if time.h defines CLOCK_REALTIME and the function is available
# in the standard library; on platforms such as glibc < 2.17 where -lrt
# or another library would be required, ftime will be used.
AS_IF([test "$enable_http" != "no"], [
AC_MSG_CHECKING([for clock_gettime])
AC_LINK_IFELSE([
AC_LANG_PROGRAM([[#include <time.h>]], [[
struct timespec ts;
return clock_gettime(CLOCK_REALTIME, &ts);
]])
], [
AC_MSG_RESULT([yes])
AC_DEFINE([OP_HAVE_CLOCK_GETTIME], [1],
[Enable use of clock_gettime function])
], [
AC_MSG_RESULT([no])
AC_SEARCH_LIBS(ftime, [compat], , [enable_http=no])
])
])
m4_ifndef([PKG_PROG_PKG_CONFIG],
[m4_fatal([Could not locate the pkg-config autoconf macros.
Please make sure pkg-config is installed and, if necessary, set the environment
variable ACLOCAL="aclocal -I/path/to/pkg.m4".])])
AS_IF([test "$enable_http" != "no"], [
openssl="openssl"
AC_DEFINE([OP_ENABLE_HTTP], [1], [Enable HTTP support])
PKG_CHECK_MODULES([URL_DEPS], [openssl])
])
AM_CONDITIONAL(OP_ENABLE_HTTP, [test "$enable_http" != "no"])
AC_SUBST([openssl])
PKG_CHECK_MODULES([DEPS], [ogg >= 1.1 opus >= 1.0.1])
AC_ARG_ENABLE([fixed-point],
AS_HELP_STRING([--enable-fixed-point], [Enable fixed-point calculation]),,
enable_fixed_point=no)
AC_ARG_ENABLE([float],
AS_HELP_STRING([--disable-float], [Disable floating-point API]),,
enable_float=yes)
AS_IF([test "$enable_float" = "no"],
[enable_fixed_point=yes
AC_DEFINE([OP_DISABLE_FLOAT_API], [1], [Disable floating-point API])
]
)
AS_IF([test "$enable_fixed_point" = "yes"],
[AC_DEFINE([OP_FIXED_POINT], [1], [Enable fixed-point calculation])],
[dnl This only has to be tested for if float->fixed conversions are required
saved_LIBS="$LIBS"
AC_SEARCH_LIBS([lrintf], [m], [
AC_DEFINE([OP_HAVE_LRINTF], [1], [Enable use of lrintf function])
lrintf_notice="
Library for lrintf() ......... ${ac_cv_search_lrintf}"
])
LIBS="$saved_LIBS"
]
)
AC_ARG_ENABLE([examples],
AS_HELP_STRING([--disable-examples], [Do not build example applications]),,
enable_examples=yes)
AM_CONDITIONAL([OP_ENABLE_EXAMPLES], [test "$enable_examples" = "yes"])
AS_CASE(["$ac_cv_search_lrintf"],
["no"],[],
["none required"],[],
[lrintf_lib="$ac_cv_search_lrintf"])
AC_SUBST([lrintf_lib])
CC_ATTRIBUTE_VISIBILITY([default], [
CC_FLAG_VISIBILITY([CFLAGS="${CFLAGS} -fvisibility=hidden"])
])
dnl Check for doxygen
AC_ARG_ENABLE([doc],
AS_HELP_STRING([--disable-doc], [Do not build API documentation]),,
[enable_doc=yes]
)
AS_IF([test "$enable_doc" = "yes"], [
AC_CHECK_PROG([HAVE_DOXYGEN], [doxygen], [yes], [no])
AC_CHECK_PROG([HAVE_DOT], [dot], [yes], [no])
],[
HAVE_DOXYGEN=no
])
AM_CONDITIONAL([HAVE_DOXYGEN], [test "$HAVE_DOXYGEN" = "yes"])
AC_CONFIG_FILES([
Makefile
opusfile.pc
opusurl.pc
opusfile-uninstalled.pc
opusurl-uninstalled.pc
doc/Doxyfile
])
AC_CONFIG_HEADERS([config.h])
AC_OUTPUT
AC_MSG_NOTICE([
------------------------------------------------------------------------
$PACKAGE_NAME $PACKAGE_VERSION: Automatic configuration OK.
Assertions ................... ${enable_assertions}
HTTP support ................. ${enable_http}
Fixed-point .................. ${enable_fixed_point}
Floating-point API ........... ${enable_float}${lrintf_notice}
Hidden visibility ............ ${cc_cv_flag_visibility}
API code examples ............ ${enable_examples}
API documentation ............ ${enable_doc}
------------------------------------------------------------------------
])
+22
View File
@@ -0,0 +1,22 @@
# Process with doxygen to generate API documentation
PROJECT_NAME = @PACKAGE_NAME@
PROJECT_NUMBER = @PACKAGE_VERSION@
PROJECT_BRIEF = "Stand-alone decoder library for .opus files."
INPUT = @top_srcdir@/include/opusfile.h
OPTIMIZE_OUTPUT_FOR_C = YES
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
JAVADOC_AUTOBRIEF = YES
SORT_MEMBER_DOCS = NO
HAVE_DOT = @HAVE_DOT@
PROJECT_LOGO = @top_srcdir@/doc/opus_logo.svg
FULL_PATH_NAMES = NO
+35
View File
@@ -0,0 +1,35 @@
## GNU makefile for opusfile documentation.
-include ../package_version
all: doxygen
doxygen: Doxyfile ../include/opusfile.h
doxygen
pdf: doxygen
make -C latex
clean:
$(RM) -r html
$(RM) -r latex
distclean: clean
$(RM) Doxyfile
.PHONY: all clean distclean doxygen pdf
../package_version:
@if [ -x ../update_version ]; then \
../update_version || true; \
elif [ ! -e $@ ]; then \
echo 'PACKAGE_VERSION="unknown"' > $@; \
fi
# run autoconf-like replacements to finalize our config
Doxyfile: Doxyfile.in Makefile ../package_version
sed -e 's/@PACKAGE_NAME@/opusfile/' \
-e 's/@PACKAGE_VERSION@/$(PACKAGE_VERSION)/' \
-e 's/@HAVE_DOT@/yes/' \
-e 's/@top_srcdir@/../' \
< $< > $@
+157
View File
@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
x="0px"
y="0px"
width="97"
height="55"
viewBox="-72 -23.757 97 55"
overflow="visible"
enable-background="new -72 -23.757 169 78.757"
xml:space="preserve"
id="svg2"
style="overflow:visible">
<defs
id="defs4">
<linearGradient
xlink:href="#SVGID_1_"
id="linearGradient3027"
gradientUnits="userSpaceOnUse"
x1="194.53169"
y1="95.107399"
x2="194.53169"
y2="9.9475983e-14" /><linearGradient
xlink:href="#SVGID_2_"
id="linearGradient3029"
gradientUnits="userSpaceOnUse"
x1="229.61819"
y1="116.208"
x2="229.61819"
y2="164.46291" /><linearGradient
xlink:href="#SVGID_3_"
id="linearGradient3031"
gradientUnits="userSpaceOnUse"
x1="43.9897"
y1="115.4395"
x2="43.9897"
y2="165.2314" /><linearGradient
xlink:href="#SVGID_4_"
id="linearGradient3033"
gradientUnits="userSpaceOnUse"
x1="311.2847"
y1="115.7188"
x2="311.2847"
y2="165.2822" /><linearGradient
xlink:href="#SVGID_5_"
id="linearGradient3035"
gradientUnits="userSpaceOnUse"
x1="129.1987"
y1="115.5791"
x2="129.1987"
y2="204.4863" /></defs>
<linearGradient
id="SVGID_1_"
gradientUnits="userSpaceOnUse"
x1="194.53169"
y1="95.107399"
x2="194.53169"
y2="9.9475983e-14">
<stop
offset="0.0056"
style="stop-color:#8E8E8E"
id="stop7" />
<stop
offset="1"
style="stop-color:#B5B5B5"
id="stop9" />
</linearGradient>
<linearGradient
id="SVGID_2_"
gradientUnits="userSpaceOnUse"
x1="229.61819"
y1="116.208"
x2="229.61819"
y2="164.46291">
<stop
offset="0.0056"
style="stop-color:#494748"
id="stop14" />
<stop
offset="1"
style="stop-color:#000000"
id="stop16" />
</linearGradient>
<linearGradient
id="SVGID_3_"
gradientUnits="userSpaceOnUse"
x1="43.9897"
y1="115.4395"
x2="43.9897"
y2="165.2314">
<stop
offset="0.0056"
style="stop-color:#494748"
id="stop21" />
<stop
offset="1"
style="stop-color:#000000"
id="stop23" />
</linearGradient>
<linearGradient
id="SVGID_4_"
gradientUnits="userSpaceOnUse"
x1="311.2847"
y1="115.7188"
x2="311.2847"
y2="165.2822">
<stop
offset="0.0056"
style="stop-color:#494748"
id="stop28" />
<stop
offset="1"
style="stop-color:#000000"
id="stop30" />
</linearGradient>
<linearGradient
id="SVGID_5_"
gradientUnits="userSpaceOnUse"
x1="129.1987"
y1="115.5791"
x2="129.1987"
y2="204.4863">
<stop
offset="0.0056"
style="stop-color:#494748"
id="stop35" />
<stop
offset="1"
style="stop-color:#000000"
id="stop37" />
</linearGradient>
<g
id="g3020"
transform="matrix(0.26931937,0,0,0.26931937,-72.00048,-23.756955)"><path
id="path11"
d="M 257.355,13.996 C 249.943,7.826 238.533,3.695 223.153,1.588 l -11.302,35.935 c -0.244,1.318 -0.664,2.815 -1.315,4.54 -1.153,2.883 -2.542,5.258 -4.174,7.127 -1.634,1.874 -3.463,3.335 -5.489,4.4 -2.028,1.059 -4.232,1.79 -6.614,2.193 -2.382,0.4 -4.847,0.526 -7.393,0.378 -2.549,-0.148 -4.717,-0.495 -6.501,-1.042 -1.786,-0.546 -3.428,-1.452 -4.925,-2.72 -1.107,-1.245 -1.751,-2.878 -1.927,-4.902 -0.177,-2.024 0.313,-4.527 1.471,-7.509 1.035,-2.592 2.345,-4.852 3.933,-6.771 1.587,-1.921 3.443,-3.411 5.565,-4.467 2.027,-1.059 4.206,-1.768 6.539,-2.125 2.327,-0.354 4.915,-0.448 7.756,-0.283 2.352,0.139 4.542,0.485 6.574,1.048 0.964,0.265 1.808,0.613 2.542,1.033 L 216.57,0.832 c -2.142,-0.202 -4.333,-0.379 -6.609,-0.51 -21.901,-1.279 -40.308,1.251 -55.229,7.576 -14.918,6.33 -24.865,15.715 -29.833,28.154 -1.491,3.814 -2.292,7.408 -2.41,10.785 l -0.01,-0.005 c -1.426,24.463 14.295,38.245 24.007,44.373 3.897,2.609 7.362,3.901 7.362,3.901 l 4.451,-14.225 1.316,-3.496 c 5.859,1.108 12.375,1.879 19.573,2.298 22.053,1.286 40.539,-1.232 55.458,-7.564 14.916,-6.325 24.78,-15.638 29.591,-27.942 4.806,-12.295 2.514,-22.357 -6.882,-30.181 z"
style="fill:url(#linearGradient3027)"/><path
id="path18"
d="m 269.531,139.499 c -2.511,7.718 -8.23,13.807 -17.156,18.27 -8.926,4.463 -20.223,6.694 -33.891,6.694 -13.484,0 -23.292,-2.208 -29.43,-6.626 -6.136,-4.415 -7.904,-10.528 -5.299,-18.338 l 7.53,-23.291 h 25.663 l -7.252,23.151 c -0.931,2.883 -1.232,5.278 -0.906,7.183 0.326,1.907 1.046,3.417 2.162,4.533 1.394,1.113 2.95,1.88 4.672,2.299 1.72,0.419 3.788,0.629 6.207,0.629 2.417,0 4.742,-0.255 6.974,-0.769 2.231,-0.51 4.275,-1.323 6.138,-2.438 1.858,-1.116 3.508,-2.602 4.951,-4.463 1.44,-1.859 2.626,-4.186 3.557,-6.974 l 7.532,-23.151 h 25.663 l -7.115,23.291 z"
style="fill:url(#linearGradient3029)"/><path
id="path25"
d="m 86.875,140.404 c 2.51,-7.717 0.743,-13.808 -5.301,-18.271 -6.044,-4.463 -15.899,-6.694 -29.567,-6.694 -13.483,0 -24.686,2.21 -33.611,6.625 -8.928,4.417 -14.693,10.53 -17.295,18.34 -2.51,7.72 -0.722,13.786 5.37,18.201 6.089,4.418 15.922,6.626 29.498,6.626 13.575,0 24.826,-2.208 33.753,-6.626 8.924,-4.415 14.642,-10.481 17.153,-18.201 z m -26.082,0.14 c -0.931,2.978 -2.069,5.3 -3.417,6.974 -1.349,1.675 -3.046,3.116 -5.09,4.323 -1.768,1.116 -3.765,1.883 -5.997,2.302 -2.232,0.419 -4.463,0.627 -6.696,0.627 -2.697,0 -4.999,-0.23 -6.903,-0.696 -1.907,-0.465 -3.417,-1.256 -4.533,-2.371 -1.21,-1.116 -1.906,-2.626 -2.092,-4.533 -0.188,-1.904 0.14,-4.114 0.977,-6.625 0.929,-2.88 2.161,-5.275 3.696,-7.183 1.534,-1.904 3.229,-3.417 5.09,-4.533 2.138,-1.115 4.206,-1.882 6.207,-2.301 1.999,-0.419 4.207,-0.627 6.625,-0.627 2.416,0 4.603,0.257 6.555,0.767 1.953,0.512 3.486,1.325 4.603,2.44 1.115,1.116 1.789,2.605 2.021,4.463 0.231,1.86 -0.117,4.185 -1.046,6.973 z"
style="fill:url(#linearGradient3031)"/><path
id="path32"
d="m 310.14,126.807 c 2.928,-0.698 9.041,-1.046 18.339,-1.046 4.833,0 9.506,0.487 14.018,1.465 4.508,0.976 9.042,2.209 13.598,3.696 L 360,119.066 c -2.698,-0.744 -6.625,-1.487 -11.787,-2.231 -5.159,-0.744 -10.669,-1.116 -16.526,-1.116 -17.574,0 -30.405,1.513 -38.493,4.533 -8.089,3.022 -12.879,6.812 -14.366,11.366 -1.115,3.44 -0.348,6.346 2.302,8.717 2.65,2.371 7.322,4.115 14.016,5.229 2.511,0.467 6.624,0.838 12.343,1.117 5.718,0.279 9.46,0.557 11.228,0.836 3.717,0.373 6.205,0.837 7.461,1.396 1.254,0.558 1.695,1.394 1.325,2.511 -0.467,1.303 -1.976,2.279 -4.533,2.928 -2.559,0.652 -6.3,0.977 -11.227,0.977 -0.77,0 -1.513,-0.003 -2.241,-0.007 -1.846,-0.101 -3.858,-0.272 -5.791,-0.476 -2.06,-0.22 -4.118,-0.485 -6.162,-0.795 -4.089,-0.62 -8.132,-1.419 -12.058,-2.439 -3.921,-1.022 -7.734,-2.267 -11.26,-3.813 -0.474,-0.208 -0.932,-0.433 -1.394,-0.654 -2.476,3.979 -5.905,7.451 -10.27,10.396 2.259,1.085 4.539,1.976 6.807,2.742 4.52,1.506 9.034,2.52 13.525,3.266 4.494,0.741 8.969,1.203 13.431,1.472 2.231,0.133 4.459,0.215 6.691,0.248 1.966,0.026 3.882,0.02 5.902,-0.045 12.216,-0.072 22.318,-1.53 30.294,-4.386 8.18,-2.929 13.062,-6.81 14.644,-11.645 1.116,-3.349 0.441,-6.138 -2.021,-8.369 -2.466,-2.231 -6.813,-3.857 -13.041,-4.882 -2.883,-0.371 -5.768,-0.719 -8.647,-1.046 -2.884,-0.324 -5.533,-0.628 -7.951,-0.906 -9.577,-0.65 -14.924,-1.255 -16.039,-1.813 -1.116,-0.558 -1.488,-1.394 -1.116,-2.511 0.467,-1.209 2.164,-2.163 5.094,-2.859 z"
style="fill:url(#linearGradient3033)"/><path
id="path39"
d="m 172.838,122.204 c -6.091,-4.415 -15.924,-6.625 -29.499,-6.625 -13.577,0 -24.826,2.21 -33.751,6.625 -8.926,4.417 -14.4,10.415 -16.911,18.131 l -0.105,0.349 -12.692,39.19 c -5.26,17.631 17.526,24.612 17.526,24.612 l 7.58,-24.612 0.656,-2.106 c 0.592,-1.982 1.192,-3.964 1.781,-5.948 l 1.686,-5.531 c 0.603,-1.832 1.207,-3.662 1.85,-5.481 l 3.979,-10.875 1.993,-5.436 1.429,-3.718 c 0.051,-0.172 0.099,-0.339 0.155,-0.514 0.836,-2.509 1.953,-4.718 3.347,-6.624 1.396,-1.904 3.069,-3.417 5.021,-4.533 1.859,-1.115 3.882,-1.904 6.067,-2.371 2.183,-0.464 4.625,-0.696 7.322,-0.696 2.231,0 4.325,0.208 6.277,0.627 1.952,0.419 3.438,1.186 4.463,2.301 1.301,1.209 2.068,2.65 2.3,4.323 0.231,1.675 -0.117,3.999 -1.046,6.974 -0.931,2.79 -2.116,5.116 -3.557,6.974 -1.442,1.862 -3.091,3.348 -4.951,4.464 -1.861,1.115 -3.905,1.931 -6.136,2.44 -2.231,0.512 -4.558,0.767 -6.973,0.767 -2.419,0 -4.487,-0.208 -6.207,-0.627 -1.721,-0.419 -3.326,-1.186 -4.812,-2.302 -0.112,-0.112 -0.201,-0.247 -0.305,-0.366 l -3.674,10.658 c -0.206,0.613 -0.403,1.228 -0.601,1.842 3.479,0.708 7.507,1.13 12.111,1.256 13.668,0 24.965,-2.231 33.893,-6.694 8.926,-4.464 14.643,-10.552 17.154,-18.271 2.511,-7.719 0.718,-13.786 -5.37,-18.203 z"
style="fill:url(#linearGradient3035)"/></g>
</svg>

After

Width:  |  Height:  |  Size: 8.4 KiB

+58
View File
@@ -0,0 +1,58 @@
# Release checklist
## Source release
- Update OP_LT_* API versioning in configure.ac.
- Check for uncommitted changes to master.
- Prepare win32 binaries
- Do this before tagging the release, as it may require changes which should
be committed
- Tag the release commit with 'git tag -s vN.M'.
- Include release notes in the tag annotation.
- Verify 'make distcheck' produces a tarball with
the desired name.
- Push tag to public repo.
- Upload source package 'opusfile-${version}.tar.gz'
to website and verify file permissions.
- Update checksum files on website.
- Update links on <https://www.opus-codec.org/downloads/>.
- Add a copy of the documentation to <https://www.opus-codec.org/docs/>
and update the links.
- Add doc/latex/refman as docs/opusfile_api-${version}.pdf on opus-codec.org
- Add doc/html as docs/opusfile_api-${version} on opus-codec.org
Releases are commited to https://svn.xiph.org/releases/opus/
which propagates to downloads.xiph.org, and copied manually
to https://archive.mozilla.org/pub/opus/
Release notes and package links should be added to the corresponding
tag at https://gitlab.xiph.org/xiph/opusfile so they show on the
releases page.
Release packages should also be manually attached to the corresponding
tag on the github mirror https://github.com/xiph/opusfile/releases
## Win32 binaries
- Install cross-i686-w64-mingw32-gcc and associated binutils.
- If you skip this step, libopus will still try to build with the system gcc
and then fail to link.
- Edit mingw/Makefile to point to the latest versions of libogg. opus, openssl
(see <https://archive.mozilla.org/pub/opus/>, checksums in SHA256SUMS.txt)
- run `make -C mingw`
- Downloads versions of libogg, opus, openssl.
- Compiles them.
- Compiles static opusfile and examples against the built deps.
- run `make -C mingw package`
- Creates an opusfile-${version}-win32.zip binary package.
- Merge changes between README.md and the version in the last
binary release. E.g. it's good to include versions of the dependencies,
release notes, etc.
- Copy the archive to a clean system and verify the examples work
to make sure you've included all the necessary libraries.
- Upload the archive zipfile to websites.
- Verify file permissions and that it's available at the expected URL.
- Update links on <https://www.opus-codec.org/downloads/>.
Binary releases are copied manually to s3 to appear at
https://archive.mozilla.org/pub/mozilla.org/opus/win32/
@@ -0,0 +1,390 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2020 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/*For fileno()*/
#if !defined(_POSIX_SOURCE)
# define _POSIX_SOURCE 1
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <opusfile.h>
#if defined(_WIN32)
# include "win32utf8.h"
# undef fileno
# define fileno _fileno
#endif
static void print_duration(FILE *_fp,ogg_int64_t _nsamples,int _frac){
ogg_int64_t seconds;
ogg_int64_t minutes;
ogg_int64_t hours;
ogg_int64_t days;
ogg_int64_t weeks;
_nsamples+=_frac?24:24000;
seconds=_nsamples/48000;
_nsamples-=seconds*48000;
minutes=seconds/60;
seconds-=minutes*60;
hours=minutes/60;
minutes-=hours*60;
days=hours/24;
hours-=days*24;
weeks=days/7;
days-=weeks*7;
if(weeks)fprintf(_fp,"%liw",(long)weeks);
if(weeks||days)fprintf(_fp,"%id",(int)days);
if(weeks||days||hours){
if(weeks||days)fprintf(_fp,"%02ih",(int)hours);
else fprintf(_fp,"%ih",(int)hours);
}
if(weeks||days||hours||minutes){
if(weeks||days||hours)fprintf(_fp,"%02im",(int)minutes);
else fprintf(_fp,"%im",(int)minutes);
fprintf(_fp,"%02i",(int)seconds);
}
else fprintf(_fp,"%i",(int)seconds);
if(_frac)fprintf(_fp,".%03i",(int)(_nsamples/48));
fprintf(_fp,"s");
}
static void print_size(FILE *_fp,opus_int64 _nbytes,int _metric,
const char *_spacer){
static const char SUFFIXES[7]={' ','k','M','G','T','P','E'};
opus_int64 val;
opus_int64 den;
opus_int64 round;
int base;
int shift;
base=_metric?1000:1024;
round=0;
den=1;
for(shift=0;shift<6;shift++){
if(_nbytes<den*base-round)break;
den*=base;
round=den>>1;
}
val=(_nbytes+round)/den;
if(den>1&&val<10){
if(den>=1000000000)val=(_nbytes+(round/100))/(den/100);
else val=(_nbytes*100+round)/den;
fprintf(_fp,"%li.%02i%s%c",(long)(val/100),(int)(val%100),
_spacer,SUFFIXES[shift]);
}
else if(den>1&&val<100){
if(den>=1000000000)val=(_nbytes+(round/10))/(den/10);
else val=(_nbytes*10+round)/den;
fprintf(_fp,"%li.%i%s%c",(long)(val/10),(int)(val%10),
_spacer,SUFFIXES[shift]);
}
else fprintf(_fp,"%li%s%c",(long)val,_spacer,SUFFIXES[shift]);
}
static void put_le32(unsigned char *_dst,opus_uint32 _x){
_dst[0]=(unsigned char)(_x&0xFF);
_dst[1]=(unsigned char)(_x>>8&0xFF);
_dst[2]=(unsigned char)(_x>>16&0xFF);
_dst[3]=(unsigned char)(_x>>24&0xFF);
}
/*Make a header for a 48 kHz, stereo, signed, 16-bit little-endian PCM WAV.*/
static void make_wav_header(unsigned char _dst[44],ogg_int64_t _duration){
/*The chunk sizes are set to 0x7FFFFFFF by default.
Many, though not all, programs will interpret this to mean the duration is
"undefined", and continue to read from the file so long as there is actual
data.*/
static const unsigned char WAV_HEADER_TEMPLATE[44]={
'R','I','F','F',0xFF,0xFF,0xFF,0x7F,
'W','A','V','E','f','m','t',' ',
0x10,0x00,0x00,0x00,0x01,0x00,0x02,0x00,
0x80,0xBB,0x00,0x00,0x00,0xEE,0x02,0x00,
0x04,0x00,0x10,0x00,'d','a','t','a',
0xFF,0xFF,0xFF,0x7F
};
memcpy(_dst,WAV_HEADER_TEMPLATE,sizeof(WAV_HEADER_TEMPLATE));
if(_duration>0){
if(_duration>0x1FFFFFF6){
fprintf(stderr,"WARNING: WAV output would be larger than 2 GB.\n");
fprintf(stderr,
"Writing non-standard WAV header with invalid chunk sizes.\n");
}
else{
opus_uint32 audio_size;
audio_size=(opus_uint32)(_duration*4);
put_le32(_dst+4,audio_size+36);
put_le32(_dst+40,audio_size);
}
}
}
int main(int _argc,const char **_argv){
OggOpusFile *of;
ogg_int64_t duration;
unsigned char wav_header[44];
int ret;
int is_ssl;
int output_seekable;
#if defined(_WIN32)
win32_utf8_setup(&_argc,&_argv);
#endif
if(_argc!=2){
fprintf(stderr,"Usage: %s <file.opus>\n",_argv[0]);
return EXIT_FAILURE;
}
is_ssl=0;
if(strcmp(_argv[1],"-")==0){
OpusFileCallbacks cb={NULL,NULL,NULL,NULL};
of=op_open_callbacks(op_fdopen(&cb,fileno(stdin),"rb"),&cb,NULL,0,&ret);
}
else{
OpusServerInfo info;
/*Try to treat the argument as a URL.*/
of=op_open_url(_argv[1],&ret,OP_GET_SERVER_INFO(&info),NULL);
#if 0
if(of==NULL){
OpusFileCallbacks cb={NULL,NULL,NULL,NULL};
void *fp;
/*For debugging: force a file to not be seekable.*/
fp=op_fopen(&cb,_argv[1],"rb");
cb.seek=NULL;
cb.tell=NULL;
of=op_open_callbacks(fp,&cb,NULL,0,NULL);
}
#else
if(of==NULL)of=op_open_file(_argv[1],&ret);
#endif
else{
if(info.name!=NULL){
fprintf(stderr,"Station name: %s\n",info.name);
}
if(info.description!=NULL){
fprintf(stderr,"Station description: %s\n",info.description);
}
if(info.genre!=NULL){
fprintf(stderr,"Station genre: %s\n",info.genre);
}
if(info.url!=NULL){
fprintf(stderr,"Station homepage: %s\n",info.url);
}
if(info.bitrate_kbps>=0){
fprintf(stderr,"Station bitrate: %u kbps\n",
(unsigned)info.bitrate_kbps);
}
if(info.is_public>=0){
fprintf(stderr,"%s\n",
info.is_public?"Station is public.":"Station is private.");
}
if(info.server!=NULL){
fprintf(stderr,"Server software: %s\n",info.server);
}
if(info.content_type!=NULL){
fprintf(stderr,"Content-Type: %s\n",info.content_type);
}
is_ssl=info.is_ssl;
opus_server_info_clear(&info);
}
}
if(of==NULL){
fprintf(stderr,"Failed to open file '%s': %i\n",_argv[1],ret);
return EXIT_FAILURE;
}
duration=0;
output_seekable=fseek(stdout,0,SEEK_CUR)!=-1;
if(op_seekable(of)){
opus_int64 size;
fprintf(stderr,"Total number of links: %i\n",op_link_count(of));
duration=op_pcm_total(of,-1);
fprintf(stderr,"Total duration: ");
print_duration(stderr,duration,3);
fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration);
size=op_raw_total(of,-1);
fprintf(stderr,"Total size: ");
print_size(stderr,size,0,"");
fprintf(stderr,"\n");
}
else if(!output_seekable){
fprintf(stderr,"WARNING: Neither input nor output are seekable.\n");
fprintf(stderr,
"Writing non-standard WAV header with invalid chunk sizes.\n");
}
make_wav_header(wav_header,duration);
if(!fwrite(wav_header,sizeof(wav_header),1,stdout)){
fprintf(stderr,"Error writing WAV header: %s\n",strerror(errno));
ret=EXIT_FAILURE;
}
else{
ogg_int64_t pcm_offset;
ogg_int64_t pcm_print_offset;
ogg_int64_t nsamples;
opus_int32 bitrate;
int prev_li;
prev_li=-1;
nsamples=0;
pcm_offset=op_pcm_tell(of);
if(pcm_offset!=0){
fprintf(stderr,"Non-zero starting PCM offset: %li\n",(long)pcm_offset);
}
pcm_print_offset=pcm_offset-48000;
bitrate=0;
for(;;){
ogg_int64_t next_pcm_offset;
opus_int16 pcm[120*48*2];
unsigned char out[120*48*2*2];
int li;
int si;
/*Although we would generally prefer to use the float interface, WAV
files with signed, 16-bit little-endian samples are far more
universally supported, so that's what we output.*/
ret=op_read_stereo(of,pcm,sizeof(pcm)/sizeof(*pcm));
if(ret==OP_HOLE){
fprintf(stderr,"\nHole detected! Corrupt file segment?\n");
continue;
}
else if(ret<0){
fprintf(stderr,"\nError decoding '%s': %i\n",_argv[1],ret);
if(is_ssl)fprintf(stderr,"Possible truncation attack?\n");
ret=EXIT_FAILURE;
break;
}
li=op_current_link(of);
if(li!=prev_li){
const OpusHead *head;
const OpusTags *tags;
int binary_suffix_len;
int ci;
/*We found a new link.
Print out some information.*/
fprintf(stderr,"Decoding link %i: \n",li);
head=op_head(of,li);
fprintf(stderr," Channels: %i\n",head->channel_count);
if(op_seekable(of)){
ogg_int64_t duration;
opus_int64 size;
duration=op_pcm_total(of,li);
fprintf(stderr," Duration: ");
print_duration(stderr,duration,3);
fprintf(stderr," (%li samples @ 48 kHz)\n",(long)duration);
size=op_raw_total(of,li);
fprintf(stderr," Size: ");
print_size(stderr,size,0,"");
fprintf(stderr,"\n");
}
if(head->input_sample_rate){
fprintf(stderr," Original sampling rate: %lu Hz\n",
(unsigned long)head->input_sample_rate);
}
tags=op_tags(of,li);
fprintf(stderr," Encoded by: %s\n",tags->vendor);
for(ci=0;ci<tags->comments;ci++){
const char *comment;
comment=tags->user_comments[ci];
if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,comment)==0){
OpusPictureTag pic;
int err;
err=opus_picture_tag_parse(&pic,comment);
fprintf(stderr," %.23s",comment);
if(err>=0){
fprintf(stderr,"%u|%s|%s|%ux%ux%u",pic.type,pic.mime_type,
pic.description,pic.width,pic.height,pic.depth);
if(pic.colors!=0)fprintf(stderr,"/%u",pic.colors);
if(pic.format==OP_PIC_FORMAT_URL){
fprintf(stderr,"|%s\n",pic.data);
}
else{
fprintf(stderr,"|<%u bytes of image data>\n",pic.data_length);
}
opus_picture_tag_clear(&pic);
}
else fprintf(stderr,"<error parsing picture tag>\n");
}
else fprintf(stderr," %s\n",tags->user_comments[ci]);
}
if(opus_tags_get_binary_suffix(tags,&binary_suffix_len)!=NULL){
fprintf(stderr,"<%u bytes of unknown binary metadata>\n",
binary_suffix_len);
}
fprintf(stderr,"\n");
if(!op_seekable(of)){
pcm_offset=op_pcm_tell(of)-ret;
if(pcm_offset!=0){
fprintf(stderr,"Non-zero starting PCM offset in link %i: %li\n",
li,(long)pcm_offset);
}
}
}
if(li!=prev_li||pcm_offset>=pcm_print_offset+48000){
opus_int32 next_bitrate;
opus_int64 raw_offset;
next_bitrate=op_bitrate_instant(of);
if(next_bitrate>=0)bitrate=next_bitrate;
raw_offset=op_raw_tell(of);
fprintf(stderr,"\r ");
print_size(stderr,raw_offset,0,"");
fprintf(stderr," ");
print_duration(stderr,pcm_offset,0);
fprintf(stderr," (");
print_size(stderr,bitrate,1," ");
fprintf(stderr,"bps) \r");
pcm_print_offset=pcm_offset;
fflush(stderr);
}
next_pcm_offset=op_pcm_tell(of);
if(pcm_offset+ret!=next_pcm_offset){
fprintf(stderr,"\nPCM offset gap! %li+%i!=%li\n",
(long)pcm_offset,ret,(long)next_pcm_offset);
}
pcm_offset=next_pcm_offset;
if(ret<=0){
ret=EXIT_SUCCESS;
break;
}
/*Ensure the data is little-endian before writing it out.*/
for(si=0;si<2*ret;si++){
out[2*si+0]=(unsigned char)(pcm[si]&0xFF);
out[2*si+1]=(unsigned char)(pcm[si]>>8&0xFF);
}
if(!fwrite(out,sizeof(*out)*4*ret,1,stdout)){
fprintf(stderr,"\nError writing decoded audio data: %s\n",
strerror(errno));
ret=EXIT_FAILURE;
break;
}
nsamples+=ret;
prev_li=li;
}
if(ret==EXIT_SUCCESS){
fprintf(stderr,"\nDone: played ");
print_duration(stderr,nsamples,3);
fprintf(stderr," (%li samples @ 48 kHz).\n",(long)nsamples);
}
if(op_seekable(of)&&nsamples!=duration){
fprintf(stderr,"\nWARNING: "
"Number of output samples does not match declared file duration.\n");
if(!output_seekable)fprintf(stderr,"Output WAV file will be corrupt.\n");
}
if(output_seekable&&nsamples!=duration){
make_wav_header(wav_header,nsamples);
if(fseek(stdout,0,SEEK_SET)||
!fwrite(wav_header,sizeof(wav_header),1,stdout)){
fprintf(stderr,"Error rewriting WAV header: %s\n",strerror(errno));
ret=EXIT_FAILURE;
}
}
}
op_free(of);
return ret;
}
@@ -0,0 +1,465 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2020 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/*For fileno()*/
#if !defined(_POSIX_SOURCE)
# define _POSIX_SOURCE 1
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <string.h>
#include <opusfile.h>
#if defined(_WIN32)
# include "win32utf8.h"
# undef fileno
# define fileno _fileno
#endif
/*Use shorts, they're smaller.*/
#if !defined(OP_FIXED_POINT)
# define OP_FIXED_POINT (1)
#endif
#if defined(OP_FIXED_POINT)
typedef opus_int16 op_sample;
# define op_read_native op_read
/*TODO: The convergence after 80 ms of preroll is far from exact.
Our comparison is very rough.
Need to find some way to do this better.*/
# define MATCH_TOL (16384)
# define ABS(_x) ((_x)<0?-(_x):(_x))
# define MATCH(_a,_b) (ABS((_a)-(_b))<MATCH_TOL)
/*Don't have fixed-point downmixing code.*/
# undef OP_WRITE_SEEK_SAMPLES
#else
typedef float op_sample;
# define op_read_native op_read_float
/*TODO: The convergence after 80 ms of preroll is far from exact.
Our comparison is very rough.
Need to find some way to do this better.*/
# define MATCH_TOL (16384.0/32768)
# define FABS(_x) ((_x)<0?-(_x):(_x))
# define MATCH(_a,_b) (FABS((_a)-(_b))<MATCH_TOL)
# if defined(OP_WRITE_SEEK_SAMPLES)
/*Matrices for downmixing from the supported channel counts to stereo.*/
static const float DOWNMIX_MATRIX[8][8][2]={
/*mono*/
{
{1.F,1.F}
},
/*stereo*/
{
{1.F,0.F},{0.F,1.F}
},
/*3.0*/
{
{0.5858F,0.F},{0.4142F,0.4142F},{0,0.5858F}
},
/*quadrophonic*/
{
{0.4226F,0.F},{0,0.4226F},{0.366F,0.2114F},{0.2114F,0.336F}
},
/*5.0*/
{
{0.651F,0.F},{0.46F,0.46F},{0,0.651F},{0.5636F,0.3254F},{0.3254F,0.5636F}
},
/*5.1*/
{
{0.529F,0.F},{0.3741F,0.3741F},{0.F,0.529F},{0.4582F,0.2645F},
{0.2645F,0.4582F},{0.3741F,0.3741F}
},
/*6.1*/
{
{0.4553F,0.F},{0.322F,0.322F},{0.F,0.4553F},{0.3943F,0.2277F},
{0.2277F,0.3943F},{0.2788F,0.2788F},{0.322F,0.322F}
},
/*7.1*/
{
{0.3886F,0.F},{0.2748F,0.2748F},{0.F,0.3886F},{0.3366F,0.1943F},
{0.1943F,0.3366F},{0.3366F,0.1943F},{0.1943F,0.3366F},{0.2748F,0.2748F}
}
};
static void write_samples(float *_samples,int _nsamples,int _nchannels){
float stereo_pcm[120*48*2];
int i;
for(i=0;i<_nsamples;i++){
float l;
float r;
int ci;
l=r=0.F;
for(ci=0;ci<_nchannels;ci++){
l+=DOWNMIX_MATRIX[_nchannels-1][ci][0]*_samples[i*_nchannels+ci];
r+=DOWNMIX_MATRIX[_nchannels-1][ci][1]*_samples[i*_nchannels+ci];
}
stereo_pcm[2*i+0]=l;
stereo_pcm[2*i+1]=r;
}
fwrite(stereo_pcm,sizeof(*stereo_pcm)*2,_nsamples,stdout);
}
# endif
#endif
static long nfailures;
static void verify_seek(OggOpusFile *_of,opus_int64 _byte_offset,
ogg_int64_t _pcm_offset,ogg_int64_t _pcm_length,op_sample *_bigassbuffer){
opus_int64 byte_offset;
ogg_int64_t pcm_offset;
ogg_int64_t duration;
op_sample buffer[120*48*8];
int nchannels;
int nsamples;
int li;
int lj;
int i;
byte_offset=op_raw_tell(_of);
if(_byte_offset!=-1&&byte_offset<_byte_offset){
fprintf(stderr,"\nRaw position out of tolerance: requested %li, "
"got %li.\n",(long)_byte_offset,(long)byte_offset);
nfailures++;
}
pcm_offset=op_pcm_tell(_of);
if(_pcm_offset!=-1&&pcm_offset>_pcm_offset){
fprintf(stderr,"\nPCM position out of tolerance: requested %li, "
"got %li.\n",(long)_pcm_offset,(long)pcm_offset);
nfailures++;
}
if(pcm_offset<0||pcm_offset>_pcm_length){
fprintf(stderr,"\nPCM position out of bounds: got %li.\n",
(long)pcm_offset);
nfailures++;
}
nsamples=op_read_native(_of,buffer,sizeof(buffer)/sizeof(*buffer),&li);
if(nsamples<0){
fprintf(stderr,"\nFailed to read PCM data after seek: %i\n",nsamples);
nfailures++;
li=op_current_link(_of);
}
for(lj=0;lj<li;lj++){
duration=op_pcm_total(_of,lj);
if(0<=pcm_offset&&pcm_offset<duration){
fprintf(stderr,"\nPCM data after seek came from the wrong link: "
"expected %i, got %i.\n",lj,li);
nfailures++;
}
pcm_offset-=duration;
if(_bigassbuffer!=NULL)_bigassbuffer+=op_channel_count(_of,lj)*duration;
}
duration=op_pcm_total(_of,li);
if(pcm_offset+nsamples>duration){
fprintf(stderr,"\nPCM data after seek exceeded link duration: "
"limit %li, got %li.\n",(long)duration,(long)(pcm_offset+nsamples));
nfailures++;
}
nchannels=op_channel_count(_of,li);
if(_bigassbuffer!=NULL){
for(i=0;i<nsamples*nchannels;i++){
if(!MATCH(buffer[i],_bigassbuffer[pcm_offset*nchannels+i])){
ogg_int64_t j;
fprintf(stderr,"\nData after seek doesn't match declared PCM "
"position: mismatch %G\n",
(double)buffer[i]-_bigassbuffer[pcm_offset*nchannels+i]);
for(j=0;j<duration-nsamples;j++){
for(i=0;i<nsamples*nchannels;i++){
if(!MATCH(buffer[i],_bigassbuffer[j*nchannels+i]))break;
}
if(i==nsamples*nchannels){
fprintf(stderr,"\nData after seek appears to match position %li.\n",
(long)i);
}
}
nfailures++;
break;
}
}
}
#if defined(OP_WRITE_SEEK_SAMPLES)
write_samples(buffer,nsamples,nchannels);
#endif
}
#define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
/*A simple wrapper that lets us count the number of underlying seek calls.*/
static op_seek_func real_seek;
static long nreal_seeks;
static int seek_stat_counter(void *_stream,opus_int64 _offset,int _whence){
if(_whence==SEEK_SET)nreal_seeks++;
/*SEEK_CUR with an offset of 0 is free, as is SEEK_END with an offset of 0
(assuming we know the file size), so don't count them.*/
else if(_offset!=0)nreal_seeks++;
return (*real_seek)(_stream,_offset,_whence);
}
#define NSEEK_TESTS (1000)
static void print_duration(FILE *_fp,ogg_int64_t _nsamples){
ogg_int64_t seconds;
ogg_int64_t minutes;
ogg_int64_t hours;
ogg_int64_t days;
ogg_int64_t weeks;
seconds=_nsamples/48000;
_nsamples-=seconds*48000;
minutes=seconds/60;
seconds-=minutes*60;
hours=minutes/60;
minutes-=hours*60;
days=hours/24;
hours-=days*24;
weeks=days/7;
days-=weeks*7;
if(weeks)fprintf(_fp,"%liw",(long)weeks);
if(weeks||days)fprintf(_fp,"%id",(int)days);
if(weeks||days||hours){
if(weeks||days)fprintf(_fp,"%02ih",(int)hours);
else fprintf(_fp,"%ih",(int)hours);
}
if(weeks||days||hours||minutes){
if(weeks||days||hours)fprintf(_fp,"%02im",(int)minutes);
else fprintf(_fp,"%im",(int)minutes);
fprintf(_fp,"%02i",(int)seconds);
}
else fprintf(_fp,"%i",(int)seconds);
fprintf(_fp,".%03is",(int)(_nsamples+24)/48);
}
int main(int _argc,const char **_argv){
OpusFileCallbacks cb;
OggOpusFile *of;
void *fp;
#if defined(_WIN32)
win32_utf8_setup(&_argc,&_argv);
#endif
if(_argc!=2){
fprintf(stderr,"Usage: %s <file.opus>\n",_argv[0]);
return EXIT_FAILURE;
}
memset(&cb,0,sizeof(cb));
if(strcmp(_argv[1],"-")==0)fp=op_fdopen(&cb,fileno(stdin),"rb");
else{
/*Try to treat the argument as a URL.*/
fp=op_url_stream_create(&cb,_argv[1],
OP_SSL_SKIP_CERTIFICATE_CHECK(1),NULL);
/*Fall back assuming it's a regular file name.*/
if(fp==NULL)fp=op_fopen(&cb,_argv[1],"rb");
}
if(cb.seek!=NULL){
real_seek=cb.seek;
cb.seek=seek_stat_counter;
}
of=op_open_callbacks(fp,&cb,NULL,0,NULL);
if(of==NULL){
fprintf(stderr,"Failed to open file '%s'.\n",_argv[1]);
return EXIT_FAILURE;
}
if(op_seekable(of)){
op_sample *bigassbuffer;
ogg_int64_t size;
ogg_int64_t pcm_offset;
ogg_int64_t pcm_length;
ogg_int64_t nsamples;
long max_seeks;
int nlinks;
int ret;
int li;
int i;
/*Because we want to do sample-level verification that the seek does what
it claimed, decode the entire file into memory.*/
nlinks=op_link_count(of);
fprintf(stderr,"Opened file containing %i links with %li seeks "
"(%0.3f per link).\n",nlinks,nreal_seeks,nreal_seeks/(double)nlinks);
/*Reset the seek counter.*/
nreal_seeks=0;
nsamples=0;
for(li=0;li<nlinks;li++){
nsamples+=op_pcm_total(of,li)*op_channel_count(of,li);
}
/*Until we find another way to do the comparisons that solves the MATCH_TOL
problem, disable this.*/
#if 0
bigassbuffer=_ogg_malloc(sizeof(*bigassbuffer)*nsamples);
if(bigassbuffer==NULL){
fprintf(stderr,
"Buffer allocation failed. Seek offset detection disabled.\n");
}
#else
bigassbuffer=NULL;
#endif
pcm_offset=op_pcm_tell(of);
if(pcm_offset!=0){
fprintf(stderr,"Initial PCM offset was not 0, got %li instead.!\n",
(long)pcm_offset);
nfailures++;
}
/*Disabling the linear scan for now.
Only test on non-borken files!*/
#if 0
{
op_sample smallerbuffer[120*48*8];
ogg_int64_t pcm_print_offset;
ogg_int64_t si;
opus_int32 bitrate;
int saw_hole;
pcm_print_offset=pcm_offset-48000;
bitrate=0;
saw_hole=0;
for(si=0;si<nsamples;){
ogg_int64_t next_pcm_offset;
opus_int32 next_bitrate;
op_sample *buf;
int buf_size;
buf=bigassbuffer==NULL?smallerbuffer:bigassbuffer+si;
buf_size=(int)OP_MIN(nsamples-si,
(int)(sizeof(smallerbuffer)/sizeof(*smallerbuffer))),
ret=op_read_native(of,buf,buf_size,&li);
if(ret==OP_HOLE){
/*Only warn once in a row.*/
if(saw_hole)continue;
saw_hole=1;
/*This is just a warning.
As long as the timestamps are still contiguous we're okay.*/
fprintf(stderr,"\nHole in PCM data at sample %li\n",
(long)pcm_offset);
continue;
}
else if(ret<=0){
fprintf(stderr,"\nFailed to read PCM data: %i\n",ret);
exit(EXIT_FAILURE);
}
saw_hole=0;
/*If we have gaps in the PCM positions, seeking is not likely to work
near them.*/
next_pcm_offset=op_pcm_tell(of);
if(pcm_offset+ret!=next_pcm_offset){
fprintf(stderr,"\nGap in PCM offset: expecting %li, got %li\n",
(long)(pcm_offset+ret),(long)next_pcm_offset);
nfailures++;
}
pcm_offset=next_pcm_offset;
si+=ret*op_channel_count(of,li);
if(pcm_offset>=pcm_print_offset+48000){
next_bitrate=op_bitrate_instant(of);
if(next_bitrate>=0)bitrate=next_bitrate;
fprintf(stderr,"\r%s... [%li left] (%0.3f kbps) ",
bigassbuffer==NULL?"Scanning":"Loading",nsamples-si,bitrate/1000.0);
pcm_print_offset=pcm_offset;
}
}
ret=op_read_native(of,smallerbuffer,8,&li);
if(ret<0){
fprintf(stderr,"Failed to read PCM data: %i\n",ret);
nfailures++;
}
if(ret>0){
fprintf(stderr,"Read too much PCM data!\n");
nfailures++;
}
}
#endif
pcm_length=op_pcm_total(of,-1);
size=op_raw_total(of,-1);
fprintf(stderr,"\rLoaded (%0.3f kbps average). \n",
op_bitrate(of,-1)/1000.0);
fprintf(stderr,"Testing raw seeking to random places in %li bytes...\n",
(long)size);
max_seeks=0;
for(i=0;i<NSEEK_TESTS;i++){
long nseeks_tmp;
opus_int64 byte_offset;
nseeks_tmp=nreal_seeks;
byte_offset=(opus_int64)(rand()/(double)RAND_MAX*size);
fprintf(stderr,"\r\t%3i [raw position %li]... ",
i,(long)byte_offset);
ret=op_raw_seek(of,byte_offset);
if(ret<0){
fprintf(stderr,"\nSeek failed: %i.\n",ret);
nfailures++;
}
if(i==28){
i=28;
}
verify_seek(of,byte_offset,-1,pcm_length,bigassbuffer);
nseeks_tmp=nreal_seeks-nseeks_tmp;
max_seeks=nseeks_tmp>max_seeks?nseeks_tmp:max_seeks;
}
fprintf(stderr,"\rTotal seek operations: %li (%.3f per raw seek, %li maximum).\n",
nreal_seeks,nreal_seeks/(double)NSEEK_TESTS,max_seeks);
nreal_seeks=0;
fprintf(stderr,"Testing exact PCM seeking to random places in %li "
"samples (",(long)pcm_length);
print_duration(stderr,pcm_length);
fprintf(stderr,")...\n");
max_seeks=0;
for(i=0;i<NSEEK_TESTS;i++){
ogg_int64_t pcm_offset2;
long nseeks_tmp;
nseeks_tmp=nreal_seeks;
pcm_offset=(ogg_int64_t)(rand()/(double)RAND_MAX*pcm_length);
fprintf(stderr,"\r\t%3i [PCM position %li]... ",
i,(long)pcm_offset);
ret=op_pcm_seek(of,pcm_offset);
if(ret<0){
fprintf(stderr,"\nSeek failed: %i.\n",ret);
nfailures++;
}
pcm_offset2=op_pcm_tell(of);
if(pcm_offset!=pcm_offset2){
fprintf(stderr,"\nDeclared PCM position did not perfectly match "
"request: requested %li, got %li.\n",
(long)pcm_offset,(long)pcm_offset2);
nfailures++;
}
verify_seek(of,-1,pcm_offset,pcm_length,bigassbuffer);
nseeks_tmp=nreal_seeks-nseeks_tmp;
max_seeks=nseeks_tmp>max_seeks?nseeks_tmp:max_seeks;
}
fprintf(stderr,"\rTotal seek operations: %li (%.3f per exact seek, %li maximum).\n",
nreal_seeks,nreal_seeks/(double)NSEEK_TESTS,max_seeks);
nreal_seeks=0;
fprintf(stderr,"OK.\n");
_ogg_free(bigassbuffer);
}
else{
fprintf(stderr,"Input was not seekable.\n");
exit(EXIT_FAILURE);
}
op_free(of);
if(nfailures>0){
fprintf(stderr,"FAILED: %li failure conditions encountered.\n",nfailures);
}
return nfailures!=0?EXIT_FAILURE:EXIT_SUCCESS;
}
+123
View File
@@ -0,0 +1,123 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2020 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************/
#if defined(_WIN32)
# include <stdio.h>
# include <stdlib.h>
# include <wchar.h>
/*We need the following two to set stdin/stdout to binary.*/
# include <io.h>
# include <fcntl.h>
# define WIN32_LEAN_AND_MEAN
# define WIN32_EXTRA_LEAN
# include <windows.h>
# include "win32utf8.h"
static char *utf16_to_utf8(const wchar_t *_src){
char *dst;
size_t len;
size_t si;
size_t di;
len=wcslen(_src);
dst=(char *)malloc(sizeof(*dst)*(3*len+1));
if(dst==NULL)return dst;
for(di=si=0;si<len;si++){
unsigned c0;
c0=_src[si];
if(c0<0x80){
/*Can be represented by a 1-byte sequence.*/
dst[di++]=(char)c0;
continue;
}
else if(c0<0x800){
/*Can be represented by a 2-byte sequence.*/
dst[di++]=(char)(0xC0|c0>>6);
dst[di++]=(char)(0x80|c0&0x3F);
continue;
}
else if(c0>=0xD800&&c0<0xDC00){
unsigned c1;
/*This is safe, because c0 was not 0 and _src is NUL-terminated.*/
c1=_src[si+1];
if(c1>=0xDC00&&c1<0xE000){
unsigned w;
/*Surrogate pair.*/
w=((c0&0x3FF)<<10|c1&0x3FF)+0x10000;
/*Can be represented by a 4-byte sequence.*/
dst[di++]=(char)(0xF0|w>>18);
dst[di++]=(char)(0x80|w>>12&0x3F);
dst[di++]=(char)(0x80|w>>6&0x3F);
dst[di++]=(char)(0x80|w&0x3F);
si++;
continue;
}
}
/*Anything else is either a valid 3-byte sequence, an invalid surrogate
pair, or 'not a character'.
In the latter two cases, we just encode the value as a 3-byte
sequence anyway (producing technically invalid UTF-8).
Later error handling will detect the problem, with a better
chance of giving a useful error message.*/
dst[di++]=(char)(0xE0|c0>>12);
dst[di++]=(char)(0x80|c0>>6&0x3F);
dst[di++]=(char)(0x80|c0&0x3F);
}
dst[di++]='\0';
return dst;
}
typedef LPWSTR *(APIENTRY *command_line_to_argv_w_func)(LPCWSTR cmd_line,
int *num_args);
/*Make a best-effort attempt to support UTF-8 on Windows.*/
void win32_utf8_setup(int *_argc,const char ***_argv){
HMODULE hlib;
/*We need to set stdin/stdout to binary mode.
This is unrelated to UTF-8 support, but it's platform specific and we need
to do it in the same places.*/
_setmode(_fileno(stdin),_O_BINARY);
_setmode(_fileno(stdout),_O_BINARY);
hlib=LoadLibraryA("shell32.dll");
if(hlib!=NULL){
command_line_to_argv_w_func command_line_to_argv_w;
/*This function is only available on Windows 2000 or later.*/
command_line_to_argv_w=(command_line_to_argv_w_func)GetProcAddress(hlib,
"CommandLineToArgvW");
if(command_line_to_argv_w!=NULL){
wchar_t **argvw;
int argc;
argvw=(*command_line_to_argv_w)(GetCommandLineW(),&argc);
if(argvw!=NULL){
int ai;
/*Really, I don't see why argc would ever differ from *_argc, but let's
be paranoid.*/
if(argc>*_argc)argc=*_argc;
for(ai=0;ai<argc;ai++){
char *argv;
argv=utf16_to_utf8(argvw[ai]);
if(argv!=NULL)(*_argv)[ai]=argv;
}
*_argc=argc;
LocalFree(argvw);
}
}
FreeLibrary(hlib);
}
# if defined(CP_UTF8)
/*This does not work correctly in all environments (it breaks output in
mingw32 for me), and requires a Unicode font (e.g., when using the default
Raster font, even characters that are available in the font's codepage
won't display properly).*/
/*SetConsoleOutputCP(CP_UTF8);*/
# endif
}
#endif
+21
View File
@@ -0,0 +1,21 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2020 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************/
#if !defined(_win32utf8_H)
# define _win32utf8_H (1)
# if defined(_WIN32)
/*Make a best-effort attempt to support UTF-8 on Windows.*/
void win32_utf8_setup(int *_argc,const char ***_argv);
# endif
#endif
File diff suppressed because it is too large Load Diff
+321
View File
@@ -0,0 +1,321 @@
dnl Macros to check the presence of generic (non-typed) symbols.
dnl Copyright (c) 2006-2007 Diego Pettenò <flameeyes@gmail.com>
dnl Copyright (c) 2006-2007 xine project
dnl
dnl This program is free software; you can redistribute it and/or modify
dnl it under the terms of the GNU General Public License as published by
dnl the Free Software Foundation; either version 2, or (at your option)
dnl any later version.
dnl
dnl This program is distributed in the hope that it will be useful,
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
dnl GNU General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
dnl 02110-1301, USA.
dnl
dnl As a special exception, the copyright owners of the
dnl macro gives unlimited permission to copy, distribute and modify the
dnl configure scripts that are the output of Autoconf when processing the
dnl Macro. You need not follow the terms of the GNU General Public
dnl License when using or distributing such scripts, even though portions
dnl of the text of the Macro appear in them. The GNU General Public
dnl License (GPL) does govern all other use of the material that
dnl constitutes the Autoconf Macro.
dnl
dnl This special exception to the GPL applies to versions of the
dnl Autoconf Macro released by this project. When you make and
dnl distribute a modified version of the Autoconf Macro, you may extend
dnl this special exception to the GPL to apply to your modified version as
dnl well.
dnl Check if the flag is supported by compiler
dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [
AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]),
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $1"
AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return 0; }])],
[eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"],
[eval "AS_TR_SH([cc_cv_cflags_$1])='no'"])
CFLAGS="$ac_save_CFLAGS"
])
AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
[$2], [$3])
])
dnl Check if the flag is supported by compiler (cacheable)
dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
AC_DEFUN([CC_CHECK_CFLAGS], [
AC_CACHE_CHECK([if $CC supports $1 flag],
AS_TR_SH([cc_cv_cflags_$1]),
CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
)
AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
[$2], [$3])
])
dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found])
dnl Check for CFLAG and appends them to CFLAGS if supported
AC_DEFUN([CC_CHECK_CFLAG_APPEND], [
AC_CACHE_CHECK([if $CC supports $1 flag],
AS_TR_SH([cc_cv_cflags_$1]),
CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here!
)
AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes],
[CFLAGS="$CFLAGS $1"; $2], [$3])
])
dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not])
AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [
for flag in $1; do
CC_CHECK_CFLAG_APPEND($flag, [$2], [$3])
done
])
dnl Check if the flag is supported by linker (cacheable)
dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND])
AC_DEFUN([CC_CHECK_LDFLAGS], [
AC_CACHE_CHECK([if $CC supports $1 flag],
AS_TR_SH([cc_cv_ldflags_$1]),
[ac_save_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS $1"
AC_LINK_IFELSE([AC_LANG_SOURCE([int main(void) { return 1; }])],
[eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"],
[eval "AS_TR_SH([cc_cv_ldflags_$1])="])
LDFLAGS="$ac_save_LDFLAGS"
])
AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes],
[$2], [$3])
])
dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for
dnl the current linker to avoid undefined references in a shared object.
AC_DEFUN([CC_NOUNDEFINED], [
dnl We check $host for which systems to enable this for.
AC_REQUIRE([AC_CANONICAL_HOST])
case $host in
dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads
dnl are requested, as different implementations are present; to avoid problems
dnl use -Wl,-z,defs only for those platform not behaving this way.
*-freebsd* | *-openbsd*) ;;
*)
dnl First of all check for the --no-undefined variant of GNU ld. This allows
dnl for a much more readable commandline, so that people can understand what
dnl it does without going to look for what the heck -z defs does.
for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do
CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"])
break
done
;;
esac
AC_SUBST([LDFLAGS_NOUNDEFINED])
])
dnl Check for a -Werror flag or equivalent. -Werror is the GCC
dnl and ICC flag that tells the compiler to treat all the warnings
dnl as fatal. We usually need this option to make sure that some
dnl constructs (like attributes) are not simply ignored.
dnl
dnl Other compilers don't support -Werror per se, but they support
dnl an equivalent flag:
dnl - Sun Studio compiler supports -errwarn=%all
AC_DEFUN([CC_CHECK_WERROR], [
AC_CACHE_CHECK(
[for $CC way to treat warnings as errors],
[cc_cv_werror],
[CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror],
[CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])])
])
])
AC_DEFUN([CC_CHECK_ATTRIBUTE], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))],
AS_TR_SH([cc_cv_attribute_$1]),
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([$3])],
[eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"],
[eval "AS_TR_SH([cc_cv_attribute_$1])='no'"])
CFLAGS="$ac_save_CFLAGS"
])
AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes],
[AC_DEFINE(
AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1,
[Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))]
)
$4],
[$5])
])
AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [
CC_CHECK_ATTRIBUTE(
[constructor],,
[extern void foo(void);
void __attribute__((constructor)) ctor(void) { foo(); }],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_DESTRUCTOR], [
CC_CHECK_ATTRIBUTE(
[destructor],,
[extern void foo(void);
void __attribute__((destructor)) dtor(void) { foo(); }],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_FORMAT], [
CC_CHECK_ATTRIBUTE(
[format], [format(printf, n, n)],
[void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [
CC_CHECK_ATTRIBUTE(
[format_arg], [format_arg(printf)],
[char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [
CC_CHECK_ATTRIBUTE(
[visibility_$1], [visibility("$1")],
[void __attribute__((visibility("$1"))) $1_function(void) { }],
[$2], [$3])
])
AC_DEFUN([CC_ATTRIBUTE_NONNULL], [
CC_CHECK_ATTRIBUTE(
[nonnull], [nonnull()],
[void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_UNUSED], [
CC_CHECK_ATTRIBUTE(
[unused], ,
[void some_function(void *foo, __attribute__((unused)) void *bar);],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [
CC_CHECK_ATTRIBUTE(
[sentinel], ,
[void some_function(void *foo, ...) __attribute__((sentinel));],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [
CC_CHECK_ATTRIBUTE(
[deprecated], ,
[void some_function(void *foo, ...) __attribute__((deprecated));],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_ALIAS], [
CC_CHECK_ATTRIBUTE(
[alias], [weak, alias],
[void other_function(void *foo) { }
void some_function(void *foo) __attribute__((weak, alias("other_function")));],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_MALLOC], [
CC_CHECK_ATTRIBUTE(
[malloc], ,
[void * __attribute__((malloc)) my_alloc(int n);],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_PACKED], [
CC_CHECK_ATTRIBUTE(
[packed], ,
[struct astructure { char a; int b; long c; void *d; } __attribute__((packed));
char assert@<:@(sizeof(struct astructure) == (sizeof(char)+sizeof(int)+sizeof(long)+sizeof(void*)))-1@:>@;],
[$1], [$2])
])
AC_DEFUN([CC_ATTRIBUTE_CONST], [
CC_CHECK_ATTRIBUTE(
[const], ,
[int __attribute__((const)) twopow(int n) { return 1 << n; } ],
[$1], [$2])
])
AC_DEFUN([CC_FLAG_VISIBILITY], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([if $CC supports -fvisibility=hidden],
[cc_cv_flag_visibility],
[cc_flag_visibility_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden],
cc_cv_flag_visibility='yes',
cc_cv_flag_visibility='no')
CFLAGS="$cc_flag_visibility_save_CFLAGS"])
AS_IF([test "x$cc_cv_flag_visibility" = "xyes"],
[AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1,
[Define this if the compiler supports the -fvisibility flag])
$1],
[$2])
])
AC_DEFUN([CC_FUNC_EXPECT], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([if compiler has __builtin_expect function],
[cc_cv_func_expect],
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[int some_function() {
int a = 3;
return (int)__builtin_expect(a, 3);
}])],
[cc_cv_func_expect=yes],
[cc_cv_func_expect=no])
CFLAGS="$ac_save_CFLAGS"
])
AS_IF([test "x$cc_cv_func_expect" = "xyes"],
[AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1,
[Define this if the compiler supports __builtin_expect() function])
$1],
[$2])
])
AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [
AC_REQUIRE([CC_CHECK_WERROR])
AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported],
[cc_cv_attribute_aligned],
[ac_save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $cc_cv_werror"
for cc_attribute_align_try in 64 32 16 8 4 2; do
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
int main(void) {
static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0;
return c;
}])], [cc_cv_attribute_aligned=$cc_attribute_align_try; break])
done
CFLAGS="$ac_save_CFLAGS"
])
if test "x$cc_cv_attribute_aligned" != "x"; then
AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned],
[Define the highest alignment supported])
fi
])
+21
View File
@@ -0,0 +1,21 @@
FROM fedora:32
MAINTAINER opus@xiph.org
# Linux build.
RUN dnf update -y --setopt=deltarpm=0
RUN dnf install -y git gcc make wget xz
RUN dnf install -y autoconf automake libtool pkgconfig
# mingw cross build.
RUN dnf install -y mingw32-gcc zip
RUN dnf clean all
RUN git clone https://gitlab.xiph.org/xiph/opusfile.git
WORKDIR opusfile
RUN git pull
COPY Makefile mingw/Makefile
RUN make -C mingw
RUN ./autogen.sh && ./configure --host=i686-w64-mingw32 --prefix=${PWD}/mingw PKG_CONFIG_PATH=${PWD}/mingw/lib/pkgconfig && make && make check && make install
RUN make -C mingw package
+113
View File
@@ -0,0 +1,113 @@
# Cross-compile opusfile under mingw
TOOL_PREFIX ?= i686-w64-mingw32
# To build opusfile under mingw, we first need to build:
DEPS = ogg opus ssl
ogg_URL := https://downloads.xiph.org/releases/ogg/libogg-1.3.4.tar.xz
ogg_SHA := c163bc12bc300c401b6aa35907ac682671ea376f13ae0969a220f7ddf71893fe
opus_URL := https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz
opus_SHA := 65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d
ssl_URL := https://openssl.org/source/openssl-1.0.2u.tar.gz
ssl_SHA := ecd0c6ffb493dd06707d38b14bb4d8c2288bb7033735606569d8f90f89669d16
all: $(DEPS)
libopusfile-0.dll: ../unix/Makefile $(DEPS)
CC=$(TOOL_PREFIX)-gcc \
RANLIB=$(TOOL_PREFIX)-ranlib \
PKG_CONFIG_PATH=$(CURDIR)/lib/pkgconfig \
$(MAKE) -f $<
opusfile: $(DEPS)
$(MKDIR) $@
cd $@ && ../configure --host=$(TOOL_PREFIX) --prefix=$(CURDIR) \
PKG_CONFIG_PATH=$(CURDIR)/lib/pkgconfig
$(MAKE) -C $@
clean:
$(RM) -r objs
$(RM) -r bin include lib share ssl
$(RM) -r $(DEP_DIRS)
$(RM) opusfile_example.exe seeking_example.exe
$(RM) libopusfile.a libopusurl.a
# Generate rules to download and verify each dependency.
define WGET_template =
# Generate tarball name from the url.
DEP_TARBALLS += $$(notdir $$($(1)_URL))
$(1)_DIR := $$(basename $$(basename $$(notdir $$($(1)_URL))))
DEP_DIRS += $$($(1)_DIR)
# Verify and unpack tarball.
$$($(1)_DIR): $$(notdir $$($(1)_URL))
@if test "$$($(1)_SHA)" = "$$$$(sha256sum $$< | cut -f 1 -d ' ')"; \
then \
echo "+ $$< checksum verified."; \
else \
echo "! $$< checksum didn't match!"; \
$(RM) $$<; exit 1; \
fi
tar xf $$<
# Fetch tarball from the url.
$$(notdir $$($(1)_URL)):
wget $$($(1)_URL)
# Hook project-specific build rule.
$(1): $(1)_BUILD
endef
$(foreach dep,$(DEPS),$(eval $(call WGET_template,$(dep))))
fetch: $(DEP_TARBALLS)
realclean: clean
$(RM) $(DEP_TARBALLS)
# Build scripts for each specific target.
# NOTE: 'make check' generally requires wine with cross-compiling.
ogg_BUILD: $(ogg_DIR)
cd $< && ./configure --host=$(TOOL_PREFIX) --prefix=$(CURDIR)
$(MAKE) -C $< install
opus_BUILD: $(opus_DIR)
cd $< && ./configure --host=$(TOOL_PREFIX) --prefix=$(CURDIR)
$(MAKE) -C $< install
ssl_BUILD: $(ssl_DIR)
cd $< && ./Configure mingw \
--prefix=$(CURDIR) \
--cross-compile-prefix=$(TOOL_PREFIX)-
$(MAKE) -C $< depend
$(MAKE) -C $<
$(MAKE) -C $< install
# Package the binaries.
DIST_VERSION := $(shell git describe --dirty)
DIST := opusfile-$(DIST_VERSION)-win32
package: $(DIST).zip
$(DIST).zip: $(DIST)
zip -r $@ $</*
@echo $@ ready to go.
$(DIST): $(addprefix $(CURDIR)/bin/, libogg-0.dll libopus-0.dll)
#cd .. && make install
mkdir -p $(DIST)
cp ../AUTHORS ../COPYING ../README.md ../include/opusfile.h $@
cp .libs/libopusfile-0.dll $@
cp .libs/libopusfile.a $@
cp .libs/libopusurl-0.dll $@
cp .libs/libopusurl.a $@
cp bin/*.dll $@
cp *.exe $@
cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_dw2-1.dll $@
cp /usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll $@
i686-w64-mingw32-strip $@/*.exe
i686-w64-mingw32-strip $@/*.dll
i686-w64-mingw32-strip $@/*.a
cd $@ && sha256sum * > SHA256SUMS.txt
+69
View File
@@ -0,0 +1,69 @@
# Cross-compiling under mingw
Just running `make libopusfile-0.dll` in this directory should download
and build opusfile and its dependencies. Some mingw
libraries need to be compiled into the final package.
## Generic instructions
To build opusfile under mingw, you need to first build:
- libogg
- libopus
- openssl
For 'make check' to work, you may need wine installed.
To build openssl, try:
CROSS_COMPILE="i686-w64-mingw32-" ./Configure mingw no-asm no-shared --prefix=$PWD/mingw && make depend && make -j8 && make install
To build opusfile, try:
CC=i686-w64-mingw32-gcc PKG_CONFIG_PATH=$PWD/lib/pkgconfig RANLIB=i686-w64-mingw32-ranlib make -f ../unix/Makefile
## Building the release package
Running `make package` should produce a binary package.
The steps are something like
- Compile dynamic opusfile with:
- ./configure --host=i686-w64-mingw32 --prefix=/path/to/builddir/mingw \
PKG_CONFIG_PATH=/path/to/builddir/mingw/lib/pkgconfig
- make && make check && make -C doc/latex
- If Doxygen fails because of unescaped '#' characters in URLs
Update to at least Doxygen 1.8.15. Doxygen 1.8.3 also works.
- mkdir opusfile-${version}-win32
- Copy AUTHORS COPYING README.md include/opusfile.h to the release dir.
- Don't put opusfile.h in an opusfile-${version}-win32/include directory,
just put it straight in the release dir.
- Merge changes between README.md and the version in the last
binary release. E.g. it's good to include versions of the dependencies,
release notes, etc.
- Convert README.md to DOS line endings.
- Copy .libs/libopusfile-0.dll to the release dir.
- Copy .libs/libopusfile.a to the release dir.
- Copy .libs/libopusurl-0.dll to the release dir.
- Copy .libs/libopusurl.a to the release dir.
- Copy mingw/bin/*.dll to the release dir for dependencies.
- Copy any other dependent dlls, e.g. on Fedora 32 I needed to copy
/usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_dw2-1.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll
On Fedora 23 I needed to copy
/usr/i686-w64-mingw32/sys-root/mingw/bin/libgcc_s_sjlj-1.dll
/usr/i686-w64-mingw32/sys-root/mingw/bin/libwinpthread-1.dll
On Gentoo I needed to copy
/usr/lib64/gcc/i686-w64-mingw32/7.3.0/libgcc_s_sjlj-1.dll
TODO: It may be possible to avoid this with CFLAGS="-static-libgcc"
- Copy doc/latex/refman.pdf to opusfile-${version}-win32/opusfile-${version}.pdf
- Copy examples/.libs/*.exe to the release dir.
- Run "i686-w64-ming32-strip *.dll *.a *.exe" in the release dir.
- In the release dir, run:
sha256sum * > SHA256SUMS.txt
gpg --detach-sign --armor SHA256SUMS.txt
- In the parent directory, create the archive:
zip -r opusfile-${version}-win32.zip opusfile-${version}-win32/*
- Copy the archive to a clean system and verify the examples work
to make sure you've included all the necessary libraries.
@@ -0,0 +1,14 @@
# opusfile uninstalled pkg-config file
prefix=
exec_prefix=
libdir=${pcfiledir}/.libs
includedir=${pcfiledir}/@top_srcdir@/include
Name: opusfile uninstalled
Description: High-level Opus decoding library (not installed)
Version: @PACKAGE_VERSION@
Requires.private: ogg >= 1.1 opus >= 1.0.1
Conflicts:
Libs: ${libdir}/libopusfile.la @lrintf_lib@
Cflags: -I${includedir}
+15
View File
@@ -0,0 +1,15 @@
# opusfile installed pkg-config file
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: opusfile
Description: High-level Opus decoding library
Version: @PACKAGE_VERSION@
Requires.private: ogg >= 1.1 opus >= 1.0.1
Conflicts:
Libs: -L${libdir} -lopusfile
Libs.private: @lrintf_lib@
Cflags: -I${includedir}/opus
@@ -0,0 +1,14 @@
# opusurl uninstalled pkg-config file
prefix=
exec_prefix=
libdir=${pcfiledir}/.libs
includedir=${pcfiledir}/@top_srcdir@/include
Name: opusfile uninstalled
Description: High-level Opus decoding library, URL support (not installed)
Version: @PACKAGE_VERSION@
Requires: opusfile
Requires.private: @openssl@
Conflicts:
Libs: ${libdir}/libopusurl.la
+14
View File
@@ -0,0 +1,14 @@
# opusurl installed pkg-config file
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: opusurl
Description: High-level Opus decoding library, URL support
Version: @PACKAGE_VERSION@
Requires: opusfile
Requires.private: @openssl@
Conflicts:
Libs: -L${libdir} -lopusurl
+1
View File
@@ -0,0 +1 @@
PACKAGE_VERSION="0.12"
+27
View File
@@ -0,0 +1,27 @@
8071b968475c1a17f54b6840d6de9d9ee20f930e827b0401abe3c4cf4f3bf30a opusfile-0.1.tar.gz
b4a678b3b6c4adfb6aff1f67ef658becfe146ea7c7ff228e99543762171557f9 opusfile-0.2.tar.gz
094b789ee975fbc5ac706b14e5c83f12b92448fa0a55c8a9f7d79afa7f962aae opusfile-0.1-win32.zip
33521cef2ef341a938b386439e9879d3e8e916638ffdd5a7d11e09172f307d35 opusfile-0.2-win32.zip
4248927f2c4e316ea5b84fb02bd100bfec8fa4624a6910d77f0af7f0c6cb8baa opusfile-0.3.tar.gz
9836ea11706c44f36de92c4c9b1248e03a4c521e7fb2cff18a0cb4f8b0e79140 opusfile-0.4.tar.gz
f187906b1b35f7f0d7de6a759b4aab512a9279d23adb35d8009e7e33bd6a922a opusfile-0.4.zip
ae23da5963295c6aa13c97becf50ae013e2317706f0e2a9472f2384aa70aaa43 opusfile-0.4-win32.zip
2ce52d006aeeec9f10260dbe3073c4636954a1ab19c82b8baafefe0180aa4a39 opusfile-0.5.tar.gz
b940d62beb15b5974764574b9f265481fe5b6ee16902fb705727546caf956261 opusfile-0.5.zip
93104cab67a2b038753d125028d63c0028a277e798f8ca88df73d4edbfb9a787 opusfile-0.5-win32.zip
2428717b356e139f18ed2fdb5ad990b5654a238907a0058200b39c46a7d03ea6 opusfile-0.6.tar.gz
753339225193df605372944889023b9b3c5378d672e8784d69fa241cd465278c opusfile-0.6.zip
5c461b6e037f3843b31295c1eefbaf785bf165442f47fc90267bbcbd939b6e1b opusfile-0.6-win32.zip
9e2bed13bc729058591a0f1cab2505e8cfd8e7ac460bf10a78bcc3b125e7c301 opusfile-0.7.tar.gz
346967d7989bb83b05949483b76bd0f69a12c59bd8b4457e864902b52bb0ac34 opusfile-0.7.zip
c4c4c57b6b4bc9780a08c1e6300cc35846671bee61d8487c277ea1e8041cfbf8 opusfile-0.7-win32.zip
2c231ed3cfaa1b3173f52d740e5bbd77d51b9dfecb87014b404917fba4b855a4 opusfile-0.8.tar.gz
89dff4342c3b789574cbea5c57f11b96d4ebe4d28ab90248c1783ea569b1e9e3 opusfile-0.8.zip
f75fb500e40b122775ac1a71ad80c4477698842a8fe9da4a1b4a1a9f16e4e979 opusfile-0.9.tar.gz
e9591da4d4c9e857436c2d46a28a9e470fa5355ea5a76d4d582f137d18755d36 opusfile-0.9.zip
48e03526ba87ef9cf5f1c47b5ebe3aa195bd89b912a57060c36184a6cd19412f opusfile-0.10.tar.gz
9d9e95d01817ecf48bf6daaea8f071f9b45bd1751ca1fc8ce50e5075eb2bc3c8 opusfile-0.10.zip
74ce9b6cf4da103133e7b5c95df810ceb7195471e1162ed57af415fabf5603bf opusfile-0.11.tar.gz
23c5168026c4f1fc34843650135b409d0fc8cf452508163b4ece8077256ac6ff opusfile-0.11.zip
118d8601c12dd6a44f52423e68ca9083cc9f2bfe72da7a8c1acb22a80ae3550b opusfile-0.12.tar.gz
7f44575596b78d7787c1865b9653e2a71546ff1ae77d87c53ab16dcc7af295ba opusfile-0.12.zip
File diff suppressed because it is too large Load Diff
+791
View File
@@ -0,0 +1,791 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012-2020 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "internal.h"
#include <limits.h>
#include <string.h>
static unsigned op_parse_uint16le(const unsigned char *_data){
return _data[0]|_data[1]<<8;
}
static int op_parse_int16le(const unsigned char *_data){
int ret;
ret=_data[0]|_data[1]<<8;
return (ret^0x8000)-0x8000;
}
static opus_uint32 op_parse_uint32le(const unsigned char *_data){
return _data[0]|(opus_uint32)_data[1]<<8|
(opus_uint32)_data[2]<<16|(opus_uint32)_data[3]<<24;
}
static opus_uint32 op_parse_uint32be(const unsigned char *_data){
return _data[3]|(opus_uint32)_data[2]<<8|
(opus_uint32)_data[1]<<16|(opus_uint32)_data[0]<<24;
}
int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){
OpusHead head;
if(_len<8)return OP_ENOTFORMAT;
if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT;
if(_len<9)return OP_EBADHEADER;
head.version=_data[8];
if(head.version>15)return OP_EVERSION;
if(_len<19)return OP_EBADHEADER;
head.channel_count=_data[9];
head.pre_skip=op_parse_uint16le(_data+10);
head.input_sample_rate=op_parse_uint32le(_data+12);
head.output_gain=op_parse_int16le(_data+16);
head.mapping_family=_data[18];
if(head.mapping_family==0){
if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER;
if(head.version<=1&&_len>19)return OP_EBADHEADER;
head.stream_count=1;
head.coupled_count=head.channel_count-1;
if(_head!=NULL){
_head->mapping[0]=0;
_head->mapping[1]=1;
}
}
else if(head.mapping_family==1){
size_t size;
int ci;
if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER;
size=21+head.channel_count;
if(_len<size||head.version<=1&&_len>size)return OP_EBADHEADER;
head.stream_count=_data[19];
if(head.stream_count<1)return OP_EBADHEADER;
head.coupled_count=_data[20];
if(head.coupled_count>head.stream_count)return OP_EBADHEADER;
for(ci=0;ci<head.channel_count;ci++){
if(_data[21+ci]>=head.stream_count+head.coupled_count
&&_data[21+ci]!=255){
return OP_EBADHEADER;
}
}
if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count);
}
/*General purpose players should not attempt to play back content with
channel mapping family 255.*/
else if(head.mapping_family==255)return OP_EIMPL;
/*No other channel mapping families are currently defined.*/
else return OP_EBADHEADER;
if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head);
return 0;
}
void opus_tags_init(OpusTags *_tags){
memset(_tags,0,sizeof(*_tags));
}
void opus_tags_clear(OpusTags *_tags){
int ncomments;
int ci;
ncomments=_tags->comments;
if(_tags->user_comments!=NULL)ncomments++;
else{
OP_ASSERT(ncomments==0);
}
for(ci=ncomments;ci-->0;)_ogg_free(_tags->user_comments[ci]);
_ogg_free(_tags->user_comments);
_ogg_free(_tags->comment_lengths);
_ogg_free(_tags->vendor);
}
/*Ensure there's room for up to _ncomments comments.*/
static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){
char **user_comments;
int *comment_lengths;
int cur_ncomments;
size_t size;
if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT;
size=sizeof(*_tags->comment_lengths)*(_ncomments+1);
if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT;
cur_ncomments=_tags->comments;
/*We only support growing.
Trimming requires cleaning up the allocated strings in the old space, and
is best handled separately if it's ever needed.*/
OP_ASSERT(_ncomments>=(size_t)cur_ncomments);
comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size);
if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT;
if(_tags->comment_lengths==NULL){
OP_ASSERT(cur_ncomments==0);
comment_lengths[cur_ncomments]=0;
}
comment_lengths[_ncomments]=comment_lengths[cur_ncomments];
_tags->comment_lengths=comment_lengths;
size=sizeof(*_tags->user_comments)*(_ncomments+1);
if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT;
user_comments=(char **)_ogg_realloc(_tags->user_comments,size);
if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT;
if(_tags->user_comments==NULL){
OP_ASSERT(cur_ncomments==0);
user_comments[cur_ncomments]=NULL;
}
user_comments[_ncomments]=user_comments[cur_ncomments];
_tags->user_comments=user_comments;
return 0;
}
/*Duplicate a (possibly non-NUL terminated) string with a known length.*/
static char *op_strdup_with_len(const char *_s,size_t _len){
size_t size;
char *ret;
size=sizeof(*ret)*(_len+1);
if(OP_UNLIKELY(size<_len))return NULL;
ret=(char *)_ogg_malloc(size);
if(OP_LIKELY(ret!=NULL)){
ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len);
ret[_len]='\0';
}
return ret;
}
/*The actual implementation of opus_tags_parse().
Unlike the public API, this function requires _tags to already be
initialized, modifies its contents before success is guaranteed, and assumes
the caller will clear it on error.*/
static int opus_tags_parse_impl(OpusTags *_tags,
const unsigned char *_data,size_t _len){
opus_uint32 count;
size_t len;
int ncomments;
int ci;
len=_len;
if(len<8)return OP_ENOTFORMAT;
if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT;
if(len<16)return OP_EBADHEADER;
_data+=8;
len-=8;
count=op_parse_uint32le(_data);
_data+=4;
len-=4;
if(count>len)return OP_EBADHEADER;
if(_tags!=NULL){
_tags->vendor=op_strdup_with_len((char *)_data,count);
if(_tags->vendor==NULL)return OP_EFAULT;
}
_data+=count;
len-=count;
if(len<4)return OP_EBADHEADER;
count=op_parse_uint32le(_data);
_data+=4;
len-=4;
/*Check to make sure there's minimally sufficient data left in the packet.*/
if(count>len>>2)return OP_EBADHEADER;
/*Check for overflow (the API limits this to an int).*/
if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT;
if(_tags!=NULL){
int ret;
ret=op_tags_ensure_capacity(_tags,count);
if(ret<0)return ret;
}
ncomments=(int)count;
for(ci=0;ci<ncomments;ci++){
/*Check to make sure there's minimally sufficient data left in the packet.*/
if((size_t)(ncomments-ci)>len>>2)return OP_EBADHEADER;
count=op_parse_uint32le(_data);
_data+=4;
len-=4;
if(count>len)return OP_EBADHEADER;
/*Check for overflow (the API limits this to an int).*/
if(count>(opus_uint32)INT_MAX)return OP_EFAULT;
if(_tags!=NULL){
_tags->user_comments[ci]=op_strdup_with_len((char *)_data,count);
if(_tags->user_comments[ci]==NULL)return OP_EFAULT;
_tags->comment_lengths[ci]=(int)count;
_tags->comments=ci+1;
/*Needed by opus_tags_clear() if we fail before parsing the (optional)
binary metadata.*/
_tags->user_comments[ci+1]=NULL;
}
_data+=count;
len-=count;
}
if(len>0&&(_data[0]&1)){
if(len>(opus_uint32)INT_MAX)return OP_EFAULT;
if(_tags!=NULL){
_tags->user_comments[ncomments]=(char *)_ogg_malloc(len);
if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT;
memcpy(_tags->user_comments[ncomments],_data,len);
_tags->comment_lengths[ncomments]=(int)len;
}
}
return 0;
}
int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){
if(_tags!=NULL){
OpusTags tags;
int ret;
opus_tags_init(&tags);
ret=opus_tags_parse_impl(&tags,_data,_len);
if(ret<0)opus_tags_clear(&tags);
else *_tags=*&tags;
return ret;
}
else return opus_tags_parse_impl(NULL,_data,_len);
}
/*The actual implementation of opus_tags_copy().
Unlike the public API, this function requires _dst to already be
initialized, modifies its contents before success is guaranteed, and assumes
the caller will clear it on error.*/
static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){
char *vendor;
int ncomments;
int ret;
int ci;
vendor=_src->vendor;
_dst->vendor=op_strdup_with_len(vendor,strlen(vendor));
if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT;
ncomments=_src->comments;
ret=op_tags_ensure_capacity(_dst,ncomments);
if(OP_UNLIKELY(ret<0))return ret;
for(ci=0;ci<ncomments;ci++){
int len;
len=_src->comment_lengths[ci];
OP_ASSERT(len>=0);
_dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len);
if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT;
_dst->comment_lengths[ci]=len;
_dst->comments=ci+1;
}
if(_src->comment_lengths!=NULL){
int len;
len=_src->comment_lengths[ncomments];
if(len>0){
_dst->user_comments[ncomments]=(char *)_ogg_malloc(len);
if(OP_UNLIKELY(_dst->user_comments[ncomments]==NULL))return OP_EFAULT;
memcpy(_dst->user_comments[ncomments],_src->user_comments[ncomments],len);
_dst->comment_lengths[ncomments]=len;
}
}
return 0;
}
int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){
OpusTags dst;
int ret;
opus_tags_init(&dst);
ret=opus_tags_copy_impl(&dst,_src);
if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst);
else *_dst=*&dst;
return ret;
}
int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
char *comment;
size_t tag_len;
size_t value_len;
int ncomments;
int ret;
ncomments=_tags->comments;
ret=op_tags_ensure_capacity(_tags,ncomments+1);
if(OP_UNLIKELY(ret<0))return ret;
tag_len=strlen(_tag);
value_len=strlen(_value);
/*+2 for '=' and '\0'.*/
if(tag_len+value_len<tag_len)return OP_EFAULT;
if(tag_len+value_len>(size_t)INT_MAX-2)return OP_EFAULT;
comment=(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
memcpy(comment,_tag,sizeof(*comment)*tag_len);
comment[tag_len]='=';
memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
_tags->user_comments[ncomments]=comment;
_tags->comment_lengths[ncomments]=(int)(tag_len+value_len+1);
_tags->comments=ncomments+1;
return 0;
}
int opus_tags_add_comment(OpusTags *_tags,const char *_comment){
char *comment;
int comment_len;
int ncomments;
int ret;
ncomments=_tags->comments;
ret=op_tags_ensure_capacity(_tags,ncomments+1);
if(OP_UNLIKELY(ret<0))return ret;
comment_len=(int)strlen(_comment);
comment=op_strdup_with_len(_comment,comment_len);
if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
_tags->user_comments[ncomments]=comment;
_tags->comment_lengths[ncomments]=comment_len;
_tags->comments=ncomments+1;
return 0;
}
int opus_tags_set_binary_suffix(OpusTags *_tags,
const unsigned char *_data,int _len){
unsigned char *binary_suffix_data;
int ncomments;
int ret;
if(_len<0||_len>0&&(_data==NULL||!(_data[0]&1)))return OP_EINVAL;
ncomments=_tags->comments;
ret=op_tags_ensure_capacity(_tags,ncomments);
if(OP_UNLIKELY(ret<0))return ret;
if(_len!=0){
binary_suffix_data=
(unsigned char *)_ogg_realloc(_tags->user_comments[ncomments],_len);
if(OP_UNLIKELY(binary_suffix_data==NULL))return OP_EFAULT;
memcpy(binary_suffix_data,_data,_len);
}
else{
_ogg_free(_tags->user_comments[ncomments]);
binary_suffix_data=NULL;
}
_tags->user_comments[ncomments]=(char *)binary_suffix_data;
_tags->comment_lengths[ncomments]=_len;
return 0;
}
int opus_tagcompare(const char *_tag_name,const char *_comment){
size_t tag_len;
tag_len=strlen(_tag_name);
if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return -1;
return opus_tagncompare(_tag_name,(int)tag_len,_comment);
}
int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
int ret;
OP_ASSERT(_tag_len>=0);
ret=op_strncasecmp(_tag_name,_comment,_tag_len);
return ret?ret:'='-_comment[_tag_len];
}
const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
char **user_comments;
size_t tag_len;
int found;
int ncomments;
int ci;
tag_len=strlen(_tag);
if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return NULL;
ncomments=_tags->comments;
user_comments=_tags->user_comments;
found=0;
for(ci=0;ci<ncomments;ci++){
if(!opus_tagncompare(_tag,(int)tag_len,user_comments[ci])){
/*We return a pointer to the data, not a copy.*/
if(_count==found++)return user_comments[ci]+tag_len+1;
}
}
/*Didn't find anything.*/
return NULL;
}
int opus_tags_query_count(const OpusTags *_tags,const char *_tag){
char **user_comments;
size_t tag_len;
int found;
int ncomments;
int ci;
tag_len=strlen(_tag);
if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return 0;
ncomments=_tags->comments;
user_comments=_tags->user_comments;
found=0;
for(ci=0;ci<ncomments;ci++){
if(!opus_tagncompare(_tag,(int)tag_len,user_comments[ci]))found++;
}
return found;
}
const unsigned char *opus_tags_get_binary_suffix(const OpusTags *_tags,
int *_len){
int ncomments;
int len;
ncomments=_tags->comments;
len=_tags->comment_lengths==NULL?0:_tags->comment_lengths[ncomments];
*_len=len;
OP_ASSERT(len==0||_tags->user_comments!=NULL);
return len>0?(const unsigned char *)_tags->user_comments[ncomments]:NULL;
}
static int opus_tags_get_gain(const OpusTags *_tags,int *_gain_q8,
const char *_tag_name,size_t _tag_len){
char **comments;
int ncomments;
int ci;
comments=_tags->user_comments;
ncomments=_tags->comments;
/*Look for the first valid tag with the name _tag_name and use that.*/
for(ci=0;ci<ncomments;ci++){
OP_ASSERT(_tag_len<=(size_t)INT_MAX);
if(opus_tagncompare(_tag_name,(int)_tag_len,comments[ci])==0){
char *p;
opus_int32 gain_q8;
int negative;
p=comments[ci]+_tag_len+1;
negative=0;
if(*p=='-'){
negative=-1;
p++;
}
else if(*p=='+')p++;
gain_q8=0;
while(*p>='0'&&*p<='9'){
gain_q8=10*gain_q8+*p-'0';
if(gain_q8>32767-negative)break;
p++;
}
/*This didn't look like a signed 16-bit decimal integer.
Not a valid gain tag.*/
if(*p!='\0')continue;
*_gain_q8=(int)(gain_q8+negative^negative);
return 0;
}
}
return OP_FALSE;
}
int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8){
return opus_tags_get_gain(_tags,_gain_q8,"R128_ALBUM_GAIN",15);
}
int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
return opus_tags_get_gain(_tags,_gain_q8,"R128_TRACK_GAIN",15);
}
static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){
return _buf_sz>=3&&memcmp(_buf,"\xFF\xD8\xFF",3)==0;
}
/*Tries to extract the width, height, bits per pixel, and palette size of a
JPEG.
On failure, simply leaves its outputs unmodified.*/
static void op_extract_jpeg_params(const unsigned char *_buf,size_t _buf_sz,
opus_uint32 *_width,opus_uint32 *_height,
opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
if(op_is_jpeg(_buf,_buf_sz)){
size_t offs;
offs=2;
for(;;){
size_t segment_len;
int marker;
while(offs<_buf_sz&&_buf[offs]!=0xFF)offs++;
while(offs<_buf_sz&&_buf[offs]==0xFF)offs++;
marker=_buf[offs];
offs++;
/*If we hit EOI* (end of image), or another SOI* (start of image),
or SOS (start of scan), then stop now.*/
if(offs>=_buf_sz||(marker>=0xD8&&marker<=0xDA))break;
/*RST* (restart markers): skip (no segment length).*/
else if(marker>=0xD0&&marker<=0xD7)continue;
/*Read the length of the marker segment.*/
if(_buf_sz-offs<2)break;
segment_len=_buf[offs]<<8|_buf[offs+1];
if(segment_len<2||_buf_sz-offs<segment_len)break;
if(marker==0xC0||(marker>0xC0&&marker<0xD0&&(marker&3)!=0)){
/*Found a SOFn (start of frame) marker segment:*/
if(segment_len>=8){
*_height=_buf[offs+3]<<8|_buf[offs+4];
*_width=_buf[offs+5]<<8|_buf[offs+6];
*_depth=_buf[offs+2]*_buf[offs+7];
*_colors=0;
*_has_palette=0;
}
break;
}
/*Other markers: skip the whole marker segment.*/
offs+=segment_len;
}
}
}
static int op_is_png(const unsigned char *_buf,size_t _buf_sz){
return _buf_sz>=8&&memcmp(_buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0;
}
/*Tries to extract the width, height, bits per pixel, and palette size of a
PNG.
On failure, simply leaves its outputs unmodified.*/
static void op_extract_png_params(const unsigned char *_buf,size_t _buf_sz,
opus_uint32 *_width,opus_uint32 *_height,
opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
if(op_is_png(_buf,_buf_sz)){
size_t offs;
offs=8;
while(_buf_sz-offs>=12){
ogg_uint32_t chunk_len;
chunk_len=op_parse_uint32be(_buf+offs);
if(chunk_len>_buf_sz-(offs+12))break;
else if(chunk_len==13&&memcmp(_buf+offs+4,"IHDR",4)==0){
int color_type;
*_width=op_parse_uint32be(_buf+offs+8);
*_height=op_parse_uint32be(_buf+offs+12);
color_type=_buf[offs+17];
if(color_type==3){
*_depth=24;
*_has_palette=1;
}
else{
int sample_depth;
sample_depth=_buf[offs+16];
if(color_type==0)*_depth=sample_depth;
else if(color_type==2)*_depth=sample_depth*3;
else if(color_type==4)*_depth=sample_depth*2;
else if(color_type==6)*_depth=sample_depth*4;
*_colors=0;
*_has_palette=0;
break;
}
}
else if(*_has_palette>0&&memcmp(_buf+offs+4,"PLTE",4)==0){
*_colors=chunk_len/3;
break;
}
offs+=12+chunk_len;
}
}
}
static int op_is_gif(const unsigned char *_buf,size_t _buf_sz){
return _buf_sz>=6&&(memcmp(_buf,"GIF87a",6)==0||memcmp(_buf,"GIF89a",6)==0);
}
/*Tries to extract the width, height, bits per pixel, and palette size of a
GIF.
On failure, simply leaves its outputs unmodified.*/
static void op_extract_gif_params(const unsigned char *_buf,size_t _buf_sz,
opus_uint32 *_width,opus_uint32 *_height,
opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
if(op_is_gif(_buf,_buf_sz)&&_buf_sz>=14){
*_width=_buf[6]|_buf[7]<<8;
*_height=_buf[8]|_buf[9]<<8;
/*libFLAC hard-codes the depth to 24.*/
*_depth=24;
*_colors=1<<((_buf[10]&7)+1);
*_has_palette=1;
}
}
/*The actual implementation of opus_picture_tag_parse().
Unlike the public API, this function requires _pic to already be
initialized, modifies its contents before success is guaranteed, and assumes
the caller will clear it on error.*/
static int opus_picture_tag_parse_impl(OpusPictureTag *_pic,const char *_tag,
unsigned char *_buf,size_t _buf_sz,size_t _base64_sz){
opus_int32 picture_type;
opus_uint32 mime_type_length;
char *mime_type;
opus_uint32 description_length;
char *description;
opus_uint32 width;
opus_uint32 height;
opus_uint32 depth;
opus_uint32 colors;
opus_uint32 data_length;
opus_uint32 file_width;
opus_uint32 file_height;
opus_uint32 file_depth;
opus_uint32 file_colors;
int format;
int has_palette;
int colors_set;
size_t i;
/*Decode the BASE64 data.*/
OP_ASSERT(_base64_sz>=11);
for(i=0;i<_base64_sz;i++){
opus_uint32 value;
int j;
value=0;
for(j=0;j<4;j++){
unsigned c;
unsigned d;
c=(unsigned char)_tag[4*i+j];
if(c=='+')d=62;
else if(c=='/')d=63;
else if(c>='0'&&c<='9')d=52+c-'0';
else if(c>='a'&&c<='z')d=26+c-'a';
else if(c>='A'&&c<='Z')d=c-'A';
else if(c=='='&&3*i+j>_buf_sz)d=0;
else return OP_ENOTFORMAT;
value=value<<6|d;
}
_buf[3*i]=(unsigned char)(value>>16);
if(3*i+1<_buf_sz){
_buf[3*i+1]=(unsigned char)(value>>8);
if(3*i+2<_buf_sz)_buf[3*i+2]=(unsigned char)value;
}
}
i=0;
picture_type=op_parse_uint32be(_buf+i);
i+=4;
/*Extract the MIME type.*/
mime_type_length=op_parse_uint32be(_buf+i);
i+=4;
if(mime_type_length>_buf_sz-32)return OP_ENOTFORMAT;
mime_type=(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(mime_type_length+1));
if(mime_type==NULL)return OP_EFAULT;
memcpy(mime_type,_buf+i,sizeof(*mime_type)*mime_type_length);
mime_type[mime_type_length]='\0';
_pic->mime_type=mime_type;
i+=mime_type_length;
/*Extract the description string.*/
description_length=op_parse_uint32be(_buf+i);
i+=4;
if(description_length>_buf_sz-mime_type_length-32)return OP_ENOTFORMAT;
description=
(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(description_length+1));
if(description==NULL)return OP_EFAULT;
memcpy(description,_buf+i,sizeof(*description)*description_length);
description[description_length]='\0';
_pic->description=description;
i+=description_length;
/*Extract the remaining fields.*/
width=op_parse_uint32be(_buf+i);
i+=4;
height=op_parse_uint32be(_buf+i);
i+=4;
depth=op_parse_uint32be(_buf+i);
i+=4;
colors=op_parse_uint32be(_buf+i);
i+=4;
/*If one of these is set, they all must be, but colors==0 is a valid value.*/
colors_set=width!=0||height!=0||depth!=0||colors!=0;
if((width==0||height==0||depth==0)&&colors_set)return OP_ENOTFORMAT;
data_length=op_parse_uint32be(_buf+i);
i+=4;
if(data_length>_buf_sz-i)return OP_ENOTFORMAT;
/*Trim extraneous data so we don't copy it below.*/
_buf_sz=i+data_length;
/*Attempt to determine the image format.*/
format=OP_PIC_FORMAT_UNKNOWN;
if(mime_type_length==3&&strcmp(mime_type,"-->")==0){
format=OP_PIC_FORMAT_URL;
/*Picture type 1 must be a 32x32 PNG.*/
if(picture_type==1&&(width!=0||height!=0)&&(width!=32||height!=32)){
return OP_ENOTFORMAT;
}
/*Append a terminating NUL for the convenience of our callers.*/
_buf[_buf_sz++]='\0';
}
else{
if(mime_type_length==10
&&op_strncasecmp(mime_type,"image/jpeg",mime_type_length)==0){
if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
}
else if(mime_type_length==9
&&op_strncasecmp(mime_type,"image/png",mime_type_length)==0){
if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
}
else if(mime_type_length==9
&&op_strncasecmp(mime_type,"image/gif",mime_type_length)==0){
if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
}
else if(mime_type_length==0||(mime_type_length==6
&&op_strncasecmp(mime_type,"image/",mime_type_length)==0)){
if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
else if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
else if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
}
file_width=file_height=file_depth=file_colors=0;
has_palette=-1;
switch(format){
case OP_PIC_FORMAT_JPEG:{
op_extract_jpeg_params(_buf+i,data_length,
&file_width,&file_height,&file_depth,&file_colors,&has_palette);
}break;
case OP_PIC_FORMAT_PNG:{
op_extract_png_params(_buf+i,data_length,
&file_width,&file_height,&file_depth,&file_colors,&has_palette);
}break;
case OP_PIC_FORMAT_GIF:{
op_extract_gif_params(_buf+i,data_length,
&file_width,&file_height,&file_depth,&file_colors,&has_palette);
}break;
}
if(has_palette>=0){
/*If we successfully extracted these parameters from the image, override
any declared values.*/
width=file_width;
height=file_height;
depth=file_depth;
colors=file_colors;
}
/*Picture type 1 must be a 32x32 PNG.*/
if(picture_type==1&&(format!=OP_PIC_FORMAT_PNG||width!=32||height!=32)){
return OP_ENOTFORMAT;
}
}
/*Adjust _buf_sz instead of using data_length to capture the terminating NUL
for URLs.*/
_buf_sz-=i;
memmove(_buf,_buf+i,sizeof(*_buf)*_buf_sz);
if(_buf_sz>0){
unsigned char *shrunk_buf;
shrunk_buf=(unsigned char *)_ogg_realloc(_buf,_buf_sz);
/*Failure is okay here, since we were strictly trying to reduce the buffer
size.
We can just proceed with the original, larger buffer.*/
if(shrunk_buf!=NULL)_buf=shrunk_buf;
}
else{
_ogg_free(_buf);
_buf=NULL;
}
_pic->type=picture_type;
_pic->width=width;
_pic->height=height;
_pic->depth=depth;
_pic->colors=colors;
_pic->data_length=data_length;
_pic->data=_buf;
_pic->format=format;
return 0;
}
int opus_picture_tag_parse(OpusPictureTag *_pic,const char *_tag){
OpusPictureTag pic;
unsigned char *buf;
size_t base64_sz;
size_t buf_sz;
size_t tag_length;
int ret;
if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,_tag)==0)_tag+=23;
/*Figure out how much BASE64-encoded data we have.*/
tag_length=strlen(_tag);
if(tag_length&3)return OP_ENOTFORMAT;
base64_sz=tag_length>>2;
buf_sz=3*base64_sz;
if(buf_sz<32)return OP_ENOTFORMAT;
if(_tag[tag_length-1]=='=')buf_sz--;
if(_tag[tag_length-2]=='=')buf_sz--;
if(buf_sz<32)return OP_ENOTFORMAT;
/*Allocate an extra byte to allow appending a terminating NUL to URL data.*/
buf=(unsigned char *)_ogg_malloc(sizeof(*buf)*(buf_sz+1));
if(buf==NULL)return OP_EFAULT;
opus_picture_tag_init(&pic);
ret=opus_picture_tag_parse_impl(&pic,_tag,buf,buf_sz,base64_sz);
if(ret<0){
opus_picture_tag_clear(&pic);
_ogg_free(buf);
}
else *_pic=*&pic;
return ret;
}
void opus_picture_tag_init(OpusPictureTag *_pic){
memset(_pic,0,sizeof(*_pic));
}
void opus_picture_tag_clear(OpusPictureTag *_pic){
_ogg_free(_pic->description);
_ogg_free(_pic->mime_type);
_ogg_free(_pic->data);
}
+42
View File
@@ -0,0 +1,42 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012-2020 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "internal.h"
#if defined(OP_ENABLE_ASSERTIONS)
void op_fatal_impl(const char *_str,const char *_file,int _line){
fprintf(stderr,"Fatal (internal) error in %s, line %i: %s\n",
_file,_line,_str);
abort();
}
#endif
/*A version of strncasecmp() that is guaranteed to only ignore the case of
ASCII characters.*/
int op_strncasecmp(const char *_a,const char *_b,int _n){
int i;
for(i=0;i<_n;i++){
int a;
int b;
int d;
a=_a[i];
b=_b[i];
if(a>='a'&&a<='z')a-='a'-'A';
if(b>='a'&&b<='z')b-='a'-'A';
d=a-b;
if(d)return d;
}
return 0;
}
+259
View File
@@ -0,0 +1,259 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012-2020 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************/
#if !defined(_opusfile_internal_h)
# define _opusfile_internal_h (1)
# if !defined(_REENTRANT)
# define _REENTRANT
# endif
# if !defined(_GNU_SOURCE)
# define _GNU_SOURCE
# endif
# if !defined(_LARGEFILE_SOURCE)
# define _LARGEFILE_SOURCE
# endif
# if !defined(_LARGEFILE64_SOURCE)
# define _LARGEFILE64_SOURCE
# endif
# if !defined(_FILE_OFFSET_BITS)
# define _FILE_OFFSET_BITS 64
# endif
# include <stdlib.h>
# include <opusfile.h>
typedef struct OggOpusLink OggOpusLink;
# if defined(OP_FIXED_POINT)
typedef opus_int16 op_sample;
# else
typedef float op_sample;
/*We're using this define to test for libopus 1.1 or later until libopus
provides a better mechanism.*/
# if defined(OPUS_GET_EXPERT_FRAME_DURATION_REQUEST)
/*Enable soft clipping prevention in 16-bit decodes.*/
# define OP_SOFT_CLIP (1)
# endif
# endif
# if OP_GNUC_PREREQ(4,2)
/*Disable excessive warnings about the order of operations.*/
# pragma GCC diagnostic ignored "-Wparentheses"
# elif defined(_MSC_VER)
/*Disable excessive warnings about the order of operations.*/
# pragma warning(disable:4554)
/*Disable warnings about "deprecated" POSIX functions.*/
# pragma warning(disable:4996)
# endif
# if OP_GNUC_PREREQ(3,0)
/*Another alternative is
(__builtin_constant_p(_x)?!!(_x):__builtin_expect(!!(_x),1))
but that evaluates _x multiple times, which may be bad.*/
# define OP_LIKELY(_x) (__builtin_expect(!!(_x),1))
# define OP_UNLIKELY(_x) (__builtin_expect(!!(_x),0))
# else
# define OP_LIKELY(_x) (!!(_x))
# define OP_UNLIKELY(_x) (!!(_x))
# endif
# if defined(OP_ENABLE_ASSERTIONS)
# if OP_GNUC_PREREQ(2,5)||__SUNPRO_C>=0x590
__attribute__((noreturn))
# endif
void op_fatal_impl(const char *_str,const char *_file,int _line);
# define OP_FATAL(_str) (op_fatal_impl(_str,__FILE__,__LINE__))
# define OP_ASSERT(_cond) \
do{ \
if(OP_UNLIKELY(!(_cond)))OP_FATAL("assertion failed: " #_cond); \
} \
while(0)
# define OP_ALWAYS_TRUE(_cond) OP_ASSERT(_cond)
# else
# define OP_FATAL(_str) abort()
# define OP_ASSERT(_cond)
# define OP_ALWAYS_TRUE(_cond) ((void)(_cond))
# endif
# define OP_INT64_MAX (2*(((ogg_int64_t)1<<62)-1)|1)
# define OP_INT64_MIN (-OP_INT64_MAX-1)
# define OP_INT32_MAX (2*(((ogg_int32_t)1<<30)-1)|1)
# define OP_INT32_MIN (-OP_INT32_MAX-1)
# define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
# define OP_MAX(_a,_b) ((_a)>(_b)?(_a):(_b))
# define OP_CLAMP(_lo,_x,_hi) (OP_MAX(_lo,OP_MIN(_x,_hi)))
/*Advance a file offset by the given amount, clamping against OP_INT64_MAX.
This is used to advance a known offset by things like OP_CHUNK_SIZE or
OP_PAGE_SIZE_MAX, while making sure to avoid signed overflow.
It assumes that both _offset and _amount are non-negative.*/
#define OP_ADV_OFFSET(_offset,_amount) \
(OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount))
/*The maximum channel count for any mapping we'll actually decode.*/
# define OP_NCHANNELS_MAX (8)
/*Initial state.*/
# define OP_NOTOPEN (0)
/*We've found the first Opus stream in the first link.*/
# define OP_PARTOPEN (1)
# define OP_OPENED (2)
/*We've found the first Opus stream in the current link.*/
# define OP_STREAMSET (3)
/*We've initialized the decoder for the chosen Opus stream in the current
link.*/
# define OP_INITSET (4)
/*Information cached for a single link in a chained Ogg Opus file.
We choose the first Opus stream encountered in each link to play back (and
require at least one).*/
struct OggOpusLink{
/*The byte offset of the first header page in this link.*/
opus_int64 offset;
/*The byte offset of the first data page from the chosen Opus stream in this
link (after the headers).*/
opus_int64 data_offset;
/*The byte offset of the last page from the chosen Opus stream in this link.
This is used when seeking to ensure we find a page before the last one, so
that end-trimming calculations work properly.
This is only valid for seekable sources.*/
opus_int64 end_offset;
/*The total duration of all prior links.
This is always zero for non-seekable sources.*/
ogg_int64_t pcm_file_offset;
/*The granule position of the last sample.
This is only valid for seekable sources.*/
ogg_int64_t pcm_end;
/*The granule position before the first sample.*/
ogg_int64_t pcm_start;
/*The serial number.*/
ogg_uint32_t serialno;
/*The contents of the info header.*/
OpusHead head;
/*The contents of the comment header.*/
OpusTags tags;
};
struct OggOpusFile{
/*The callbacks used to access the stream.*/
OpusFileCallbacks callbacks;
/*A FILE *, memory buffer, etc.*/
void *stream;
/*Whether or not we can seek with this stream.*/
int seekable;
/*The number of links in this chained Ogg Opus file.*/
int nlinks;
/*The cached information from each link in a chained Ogg Opus file.
If stream isn't seekable (e.g., it's a pipe), only the current link
appears.*/
OggOpusLink *links;
/*The number of serial numbers from a single link.*/
int nserialnos;
/*The capacity of the list of serial numbers from a single link.*/
int cserialnos;
/*Storage for the list of serial numbers from a single link.
This is a scratch buffer used when scanning the BOS pages at the start of
each link.*/
ogg_uint32_t *serialnos;
/*This is the current offset of the data processed by the ogg_sync_state.
After a seek, this should be set to the target offset so that we can track
the byte offsets of subsequent pages.
After a call to op_get_next_page(), this will point to the first byte after
that page.*/
opus_int64 offset;
/*The total size of this stream, or -1 if it's unseekable.*/
opus_int64 end;
/*Used to locate pages in the stream.*/
ogg_sync_state oy;
/*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/
int ready_state;
/*The current link being played back.*/
int cur_link;
/*The number of decoded samples to discard from the start of decoding.*/
opus_int32 cur_discard_count;
/*The granule position of the previous packet (current packet start time).*/
ogg_int64_t prev_packet_gp;
/*The stream offset of the most recent page with completed packets, or -1.
This is only needed to recover continued packet data in the seeking logic,
when we use the current position as one of our bounds, only to later
discover it was the correct starting point.*/
opus_int64 prev_page_offset;
/*The number of bytes read since the last bitrate query, including framing.*/
opus_int64 bytes_tracked;
/*The number of samples decoded since the last bitrate query.*/
ogg_int64_t samples_tracked;
/*Takes physical pages and welds them into a logical stream of packets.*/
ogg_stream_state os;
/*Re-timestamped packets from a single page.
Buffering these relies on the undocumented libogg behavior that ogg_packet
pointers remain valid until the next page is submitted to the
ogg_stream_state they came from.*/
ogg_packet op[255];
/*The index of the next packet to return.*/
int op_pos;
/*The total number of packets available.*/
int op_count;
/*Central working state for the packet-to-PCM decoder.*/
OpusMSDecoder *od;
/*The application-provided packet decode callback.*/
op_decode_cb_func decode_cb;
/*The application-provided packet decode callback context.*/
void *decode_cb_ctx;
/*The stream count used to initialize the decoder.*/
int od_stream_count;
/*The coupled stream count used to initialize the decoder.*/
int od_coupled_count;
/*The channel count used to initialize the decoder.*/
int od_channel_count;
/*The channel mapping used to initialize the decoder.*/
unsigned char od_mapping[OP_NCHANNELS_MAX];
/*The buffered data for one decoded packet.*/
op_sample *od_buffer;
/*The current position in the decoded buffer.*/
int od_buffer_pos;
/*The number of valid samples in the decoded buffer.*/
int od_buffer_size;
/*The type of gain offset to apply.
One of OP_HEADER_GAIN, OP_ALBUM_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/
int gain_type;
/*The offset to apply to the gain.*/
opus_int32 gain_offset_q8;
/*Internal state for soft clipping and dithering float->short output.*/
#if !defined(OP_FIXED_POINT)
# if defined(OP_SOFT_CLIP)
float clip_state[OP_NCHANNELS_MAX];
# endif
float dither_a[OP_NCHANNELS_MAX*4];
float dither_b[OP_NCHANNELS_MAX*4];
opus_uint32 dither_seed;
int dither_mute;
int dither_disabled;
/*The number of channels represented by the internal state.
This gets set to 0 whenever anything that would prevent state propagation
occurs (switching between the float/short APIs, or between the
stereo/multistream APIs).*/
int state_channel_count;
#endif
};
int op_strncasecmp(const char *_a,const char *_b,int _n);
#endif
File diff suppressed because it is too large Load Diff
+434
View File
@@ -0,0 +1,434 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2018 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************
function: stdio-based convenience library for opening/seeking/decoding
last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
********************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "internal.h"
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#if defined(_WIN32)
# include <io.h>
#endif
typedef struct OpusMemStream OpusMemStream;
#define OP_MEM_SIZE_MAX (~(size_t)0>>1)
#define OP_MEM_DIFF_MAX ((ptrdiff_t)OP_MEM_SIZE_MAX)
/*The context information needed to read from a block of memory as if it were a
file.*/
struct OpusMemStream{
/*The block of memory to read from.*/
const unsigned char *data;
/*The total size of the block.
This must be at most OP_MEM_SIZE_MAX to prevent signed overflow while
seeking.*/
ptrdiff_t size;
/*The current file position.
This is allowed to be set arbitrarily greater than size (i.e., past the end
of the block, though we will not read data past the end of the block), but
is not allowed to be negative (i.e., before the beginning of the block).*/
ptrdiff_t pos;
};
static int op_fread(void *_stream,unsigned char *_ptr,int _buf_size){
FILE *stream;
size_t ret;
/*Check for empty read.*/
if(_buf_size<=0)return 0;
stream=(FILE *)_stream;
ret=fread(_ptr,1,_buf_size,stream);
OP_ASSERT(ret<=(size_t)_buf_size);
/*If ret==0 and !feof(stream), there was a read error.*/
return ret>0||feof(stream)?(int)ret:OP_EREAD;
}
static int op_fseek(void *_stream,opus_int64 _offset,int _whence){
#if defined(_WIN32)
/*_fseeki64() is not exposed until MSVCRT80.
This is the default starting with MSVC 2005 (_MSC_VER>=1400), but we want
to allow linking against older MSVCRT versions for compatibility back to
XP without installing extra runtime libraries.
i686-pc-mingw32 does not have fseeko() and requires
__MSVCRT_VERSION__>=0x800 for _fseeki64(), which screws up linking with
other libraries (that don't use MSVCRT80 from MSVC 2005 by default).
i686-w64-mingw32 does have fseeko() and respects _FILE_OFFSET_BITS, but I
don't know how to detect that at compile time.
We could just use fseeko64() (which is available in both), but it's
implemented using fgetpos()/fsetpos() just like this code, except without
the overflow checking, so we prefer our version.*/
opus_int64 pos;
/*We don't use fpos_t directly because it might be a struct if __STDC__ is
non-zero or _INTEGRAL_MAX_BITS < 64.
I'm not certain when the latter is true, but someone could in theory set
the former.
Either way, it should be binary compatible with a normal 64-bit int (this
assumption is not portable, but I believe it is true for MSVCRT).*/
OP_ASSERT(sizeof(pos)==sizeof(fpos_t));
/*Translate the seek to an absolute one.*/
if(_whence==SEEK_CUR){
int ret;
ret=fgetpos((FILE *)_stream,(fpos_t *)&pos);
if(ret)return ret;
}
else if(_whence==SEEK_END)pos=_filelengthi64(_fileno((FILE *)_stream));
else if(_whence==SEEK_SET)pos=0;
else return -1;
/*Check for errors or overflow.*/
if(pos<0||_offset<-pos||_offset>OP_INT64_MAX-pos)return -1;
pos+=_offset;
return fsetpos((FILE *)_stream,(fpos_t *)&pos);
#elif defined(__ANDROID_API__) && ((__ANDROID_API__ < 24) && !defined(__LP64__))
/* no fseeko on 32-bit Android before API 24. */
if ((_offset > 0x7FFFFFFF) || (_offset < -0x80000000)) {
return -1;
}
return fseek((FILE *)_stream,(long)_offset,_whence);
#else
/*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer
it except on Windows.*/
return fseeko((FILE *)_stream,(off_t)_offset,_whence);
#endif
}
static opus_int64 op_ftell(void *_stream){
#if defined(_WIN32)
/*_ftelli64() is not exposed until MSVCRT80, and ftello()/ftello64() have
the same problems as fseeko()/fseeko64() in MingW.
See above for a more detailed explanation.*/
opus_int64 pos;
OP_ASSERT(sizeof(pos)==sizeof(fpos_t));
return fgetpos((FILE *)_stream,(fpos_t *)&pos)?-1:pos;
#elif defined(__ANDROID_API__) && ((__ANDROID_API__ < 24) && !defined(__LP64__))
/* no ftello on 32-bit Android before API 24. */
return (opus_int64) ftell((FILE *)_stream);
#else
/*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer
it except on Windows.*/
return ftello((FILE *)_stream);
#endif
}
static int op_fclose(void *_stream){
/*This indirection maintains fclose's type signature which is necessary for
Control Flow Integrity.*/
return fclose((FILE *)_stream);
}
static const OpusFileCallbacks OP_FILE_CALLBACKS={
op_fread,
op_fseek,
op_ftell,
op_fclose
};
#if defined(_WIN32)
# include <stddef.h>
# include <errno.h>
/*Windows doesn't accept UTF-8 by default, and we don't have a wchar_t API,
so if we just pass the path to fopen(), then there'd be no way for a user
of our API to open a Unicode filename.
Instead, we translate from UTF-8 to UTF-16 and use Windows' wchar_t API.
This makes this API more consistent with platforms where the character set
used by fopen is the same as used on disk, which is generally UTF-8, and
with our metadata API, which always uses UTF-8.*/
static wchar_t *op_utf8_to_utf16(const char *_src){
wchar_t *dst;
size_t len;
len=strlen(_src);
/*Worst-case output is 1 wide character per 1 input character.*/
dst=(wchar_t *)_ogg_malloc(sizeof(*dst)*(len+1));
if(dst!=NULL){
size_t si;
size_t di;
for(di=si=0;si<len;si++){
int c0;
c0=(unsigned char)_src[si];
if(!(c0&0x80)){
/*Start byte says this is a 1-byte sequence.*/
dst[di++]=(wchar_t)c0;
continue;
}
else{
int c1;
/*This is safe, because c0 was not 0 and _src is NUL-terminated.*/
c1=(unsigned char)_src[si+1];
if((c1&0xC0)==0x80){
/*Found at least one continuation byte.*/
if((c0&0xE0)==0xC0){
wchar_t w;
/*Start byte says this is a 2-byte sequence.*/
w=(c0&0x1F)<<6|c1&0x3F;
if(w>=0x80U){
/*This is a 2-byte sequence that is not overlong.*/
dst[di++]=w;
si++;
continue;
}
}
else{
int c2;
/*This is safe, because c1 was not 0 and _src is NUL-terminated.*/
c2=(unsigned char)_src[si+2];
if((c2&0xC0)==0x80){
/*Found at least two continuation bytes.*/
if((c0&0xF0)==0xE0){
wchar_t w;
/*Start byte says this is a 3-byte sequence.*/
w=(c0&0xF)<<12|(c1&0x3F)<<6|c2&0x3F;
if(w>=0x800U&&(w<0xD800||w>=0xE000)&&w<0xFFFE){
/*This is a 3-byte sequence that is not overlong, not a
UTF-16 surrogate pair value, and not a 'not a character'
value.*/
dst[di++]=w;
si+=2;
continue;
}
}
else{
int c3;
/*This is safe, because c2 was not 0 and _src is
NUL-terminated.*/
c3=(unsigned char)_src[si+3];
if((c3&0xC0)==0x80){
/*Found at least three continuation bytes.*/
if((c0&0xF8)==0xF0){
opus_uint32 w;
/*Start byte says this is a 4-byte sequence.*/
w=(c0&7)<<18|(c1&0x3F)<<12|(c2&0x3F)<<6&(c3&0x3F);
if(w>=0x10000U&&w<0x110000U){
/*This is a 4-byte sequence that is not overlong and not
greater than the largest valid Unicode code point.
Convert it to a surrogate pair.*/
w-=0x10000;
dst[di++]=(wchar_t)(0xD800+(w>>10));
dst[di++]=(wchar_t)(0xDC00+(w&0x3FF));
si+=3;
continue;
}
}
}
}
}
}
}
}
/*If we got here, we encountered an illegal UTF-8 sequence.*/
_ogg_free(dst);
return NULL;
}
OP_ASSERT(di<=len);
dst[di]='\0';
}
return dst;
}
/*fsetpos() internally dispatches to the win32 API call SetFilePointer().
According to SetFilePointer()'s documentation [0], the behavior is
undefined if you do not call it on "a file stored on a seeking device".
However, none of the MSVCRT seeking functions verify what kind of file is
being used before calling it (which I believe is a bug, since they are
supposed to fail and return an error, but it is a bug that has been there
for multiple decades now).
In practice, SetFilePointer() appears to succeed for things like stdin,
even when you are not just piping in a regular file, which prevents the use
of this API to determine whether it is possible to seek in a file at all.
Therefore, we take the approach recommended by the SetFilePointer()
documentation and confirm the type of file using GetFileType() first.
We do this once, when the file is opened, and return the corresponding
callback in order to avoid an extra win32 API call on every seek in the
common case.
Hopefully the return value of GetFileType() cannot actually change for the
lifetime of a file handle.
[0] https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointer
*/
static int op_fseek_fail(void *_stream,opus_int64 _offset,int _whence){
(void)_stream;
(void)_offset;
(void)_whence;
return -1;
}
static const OpusFileCallbacks OP_UNSEEKABLE_FILE_CALLBACKS={
op_fread,
op_fseek_fail,
op_ftell,
op_fclose
};
# define WIN32_LEAN_AND_MEAN
# define WIN32_EXTRA_LEAN
# include <windows.h>
static const OpusFileCallbacks *op_get_file_callbacks(FILE *_fp){
intptr_t h_file;
h_file=_get_osfhandle(_fileno(_fp));
if(h_file!=-1
&&(GetFileType((HANDLE)h_file)&~FILE_TYPE_REMOTE)==FILE_TYPE_DISK){
return &OP_FILE_CALLBACKS;
}
return &OP_UNSEEKABLE_FILE_CALLBACKS;
}
#else
static const OpusFileCallbacks *op_get_file_callbacks(FILE *_fp){
(void)_fp;
return &OP_FILE_CALLBACKS;
}
#endif
void *op_fopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode){
FILE *fp;
#if !defined(_WIN32)
fp=fopen(_path,_mode);
#else
fp=NULL;
{
wchar_t *wpath;
wchar_t *wmode;
wpath=op_utf8_to_utf16(_path);
wmode=op_utf8_to_utf16(_mode);
if(wmode==NULL)errno=EINVAL;
else if(wpath==NULL)errno=ENOENT;
else fp=_wfopen(wpath,wmode);
_ogg_free(wmode);
_ogg_free(wpath);
}
#endif
if(fp!=NULL)*_cb=*op_get_file_callbacks(fp);
return fp;
}
void *op_fdopen(OpusFileCallbacks *_cb,int _fd,const char *_mode){
FILE *fp;
#ifdef _WIN32
fp=_fdopen(_fd,_mode);
#else
fp=fdopen(_fd,_mode);
#endif
if(fp!=NULL)*_cb=*op_get_file_callbacks(fp);
return fp;
}
void *op_freopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode,
void *_stream){
FILE *fp;
#if !defined(_WIN32)
fp=freopen(_path,_mode,(FILE *)_stream);
#else
fp=NULL;
{
wchar_t *wpath;
wchar_t *wmode;
wpath=op_utf8_to_utf16(_path);
wmode=op_utf8_to_utf16(_mode);
if(wmode==NULL)errno=EINVAL;
else if(wpath==NULL)errno=ENOENT;
else fp=_wfreopen(wpath,wmode,(FILE *)_stream);
_ogg_free(wmode);
_ogg_free(wpath);
}
#endif
if(fp!=NULL)*_cb=*op_get_file_callbacks(fp);
return fp;
}
static int op_mem_read(void *_stream,unsigned char *_ptr,int _buf_size){
OpusMemStream *stream;
ptrdiff_t size;
ptrdiff_t pos;
stream=(OpusMemStream *)_stream;
/*Check for empty read.*/
if(_buf_size<=0)return 0;
size=stream->size;
pos=stream->pos;
/*Check for EOF.*/
if(pos>=size)return 0;
/*Check for a short read.*/
_buf_size=(int)OP_MIN(size-pos,_buf_size);
memcpy(_ptr,stream->data+pos,_buf_size);
pos+=_buf_size;
stream->pos=pos;
return _buf_size;
}
static int op_mem_seek(void *_stream,opus_int64 _offset,int _whence){
OpusMemStream *stream;
ptrdiff_t pos;
stream=(OpusMemStream *)_stream;
pos=stream->pos;
OP_ASSERT(pos>=0);
switch(_whence){
case SEEK_SET:{
/*Check for overflow:*/
if(_offset<0||_offset>OP_MEM_DIFF_MAX)return -1;
pos=(ptrdiff_t)_offset;
}break;
case SEEK_CUR:{
/*Check for overflow:*/
if(_offset<-pos||_offset>OP_MEM_DIFF_MAX-pos)return -1;
pos=(ptrdiff_t)(pos+_offset);
}break;
case SEEK_END:{
ptrdiff_t size;
size=stream->size;
OP_ASSERT(size>=0);
/*Check for overflow:*/
if(_offset<-size||_offset>OP_MEM_DIFF_MAX-size)return -1;
pos=(ptrdiff_t)(size+_offset);
}break;
default:return -1;
}
stream->pos=pos;
return 0;
}
static opus_int64 op_mem_tell(void *_stream){
OpusMemStream *stream;
stream=(OpusMemStream *)_stream;
return (ogg_int64_t)stream->pos;
}
static int op_mem_close(void *_stream){
_ogg_free(_stream);
return 0;
}
static const OpusFileCallbacks OP_MEM_CALLBACKS={
op_mem_read,
op_mem_seek,
op_mem_tell,
op_mem_close
};
void *op_mem_stream_create(OpusFileCallbacks *_cb,
const unsigned char *_data,size_t _size){
OpusMemStream *stream;
if(_size>OP_MEM_SIZE_MAX)return NULL;
stream=(OpusMemStream *)_ogg_malloc(sizeof(*stream));
if(stream!=NULL){
*_cb=*&OP_MEM_CALLBACKS;
stream->data=_data;
stream->size=_size;
stream->pos=0;
}
return stream;
}
+173
View File
@@ -0,0 +1,173 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2013-2016 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************/
/*This should really be part of OpenSSL, but there's been a patch [1] sitting
in their bugtracker for over two years that implements this, without any
action, so I'm giving up and re-implementing it locally.
[1] <https://rt.openssl.org/Ticket/Display.html?id=2158>*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "internal.h"
#if defined(OP_ENABLE_HTTP)&&defined(_WIN32)
/*You must include windows.h before wincrypt.h and x509.h.*/
# define WIN32_LEAN_AND_MEAN
# define WIN32_EXTRA_LEAN
# include <windows.h>
/*You must include wincrypt.h before x509.h, too, or X509_NAME doesn't get
defined properly.*/
# include <wincrypt.h>
# include <openssl/ssl.h>
# include <openssl/err.h>
# include <openssl/x509.h>
static int op_capi_new(X509_LOOKUP *_lu){
HCERTSTORE h_store;
h_store=CertOpenStore(CERT_STORE_PROV_SYSTEM_A,0,0,
CERT_STORE_OPEN_EXISTING_FLAG|CERT_STORE_READONLY_FLAG|
CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_SHARE_CONTEXT_FLAG,"ROOT");
if(h_store!=NULL){
_lu->method_data=(char *)h_store;
return 1;
}
return 0;
}
static void op_capi_free(X509_LOOKUP *_lu){
HCERTSTORE h_store;
h_store=(HCERTSTORE)_lu->method_data;
# if defined(OP_ENABLE_ASSERTIONS)
OP_ALWAYS_TRUE(CertCloseStore(h_store,CERT_CLOSE_STORE_CHECK_FLAG));
# else
CertCloseStore(h_store,0);
# endif
}
static int op_capi_retrieve_by_subject(X509_LOOKUP *_lu,int _type,
X509_NAME *_name,X509_OBJECT *_ret){
X509_OBJECT *obj;
CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
obj=X509_OBJECT_retrieve_by_subject(_lu->store_ctx->objs,_type,_name);
CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
if(obj!=NULL){
_ret->type=obj->type;
memcpy(&_ret->data,&obj->data,sizeof(_ret->data));
return 1;
}
return 0;
}
static int op_capi_get_by_subject(X509_LOOKUP *_lu,int _type,X509_NAME *_name,
X509_OBJECT *_ret){
HCERTSTORE h_store;
if(_name==NULL)return 0;
if(_name->bytes==NULL||_name->bytes->length<=0||_name->modified){
if(i2d_X509_NAME(_name,NULL)<0)return 0;
OP_ASSERT(_name->bytes->length>0);
}
h_store=(HCERTSTORE)_lu->method_data;
switch(_type){
case X509_LU_X509:{
CERT_NAME_BLOB find_para;
PCCERT_CONTEXT cert;
X509 *x;
int ret;
/*Although X509_NAME contains a canon_enc field, that "canonical" [1]
encoding was just made up by OpenSSL.
It doesn't correspond to any actual standard, and since it drops the
initial sequence header, won't be recognized by the Crypto API.
The assumption here is that CertFindCertificateInStore() will allow any
appropriate variations in the encoding when it does its comparison.
This is, however, emphatically not true under Wine, which just compares
the encodings with memcmp().
Most of the time things work anyway, though, and there isn't really
anything we can do to make the situation better.
[1] A "canonical form" is defined as the one where, if you locked 10
mathematicians in a room and asked them to come up with a
representation for something, it's the answer that 9 of them would
give you back.
I don't think OpenSSL's encoding qualifies.*/
if(OP_UNLIKELY(_name->bytes->length>MAXDWORD))return 0;
find_para.cbData=(DWORD)_name->bytes->length;
find_para.pbData=(unsigned char *)_name->bytes->data;
cert=CertFindCertificateInStore(h_store,X509_ASN_ENCODING,0,
CERT_FIND_SUBJECT_NAME,&find_para,NULL);
if(cert==NULL)return 0;
x=d2i_X509(NULL,(const unsigned char **)&cert->pbCertEncoded,
cert->cbCertEncoded);
CertFreeCertificateContext(cert);
if(x==NULL)return 0;
ret=X509_STORE_add_cert(_lu->store_ctx,x);
X509_free(x);
if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
}break;
case X509_LU_CRL:{
CERT_INFO cert_info;
CERT_CONTEXT find_para;
PCCRL_CONTEXT crl;
X509_CRL *x;
int ret;
ret=op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
if(ret>0)return ret;
memset(&cert_info,0,sizeof(cert_info));
if(OP_UNLIKELY(_name->bytes->length>MAXDWORD))return 0;
cert_info.Issuer.cbData=(DWORD)_name->bytes->length;
cert_info.Issuer.pbData=(unsigned char *)_name->bytes->data;
memset(&find_para,0,sizeof(find_para));
find_para.pCertInfo=&cert_info;
crl=CertFindCRLInStore(h_store,0,0,CRL_FIND_ISSUED_BY,&find_para,NULL);
if(crl==NULL)return 0;
x=d2i_X509_CRL(NULL,(const unsigned char **)&crl->pbCrlEncoded,
crl->cbCrlEncoded);
CertFreeCRLContext(crl);
if(x==NULL)return 0;
ret=X509_STORE_add_crl(_lu->store_ctx,x);
X509_CRL_free(x);
if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
}break;
}
return 0;
}
/*This is not const because OpenSSL doesn't allow it, even though it won't
write to it.*/
static X509_LOOKUP_METHOD X509_LOOKUP_CAPI={
"Load Crypto API store into cache",
op_capi_new,
op_capi_free,
NULL,
NULL,
NULL,
op_capi_get_by_subject,
NULL,
NULL,
NULL
};
int SSL_CTX_set_default_verify_paths_win32(SSL_CTX *_ssl_ctx){
X509_STORE *store;
X509_LOOKUP *lu;
/*We intentionally do not add the normal default paths, as they are usually
wrong, and are just asking to be used as an exploit vector.*/
store=SSL_CTX_get_cert_store(_ssl_ctx);
OP_ASSERT(store!=NULL);
lu=X509_STORE_add_lookup(store,&X509_LOOKUP_CAPI);
if(lu==NULL)return 0;
ERR_clear_error();
return 1;
}
#endif
+90
View File
@@ -0,0 +1,90 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
* THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012-2013 *
* by the Xiph.Org Foundation and contributors https://xiph.org/ *
* *
********************************************************************/
#if !defined(_opusfile_winerrno_h)
# define _opusfile_winerrno_h (1)
# include <errno.h>
# include <winerror.h>
/*These conflict with the MSVC errno.h definitions, but we don't need to use
the original ones in any file that deals with sockets.
We could map the WSA errors to the errno.h ones (most of which are only
available on sufficiently new versions of MSVC), but they aren't ordered the
same, and given how rarely we actually look at the values, I don't think
it's worth a lookup table.*/
# undef EWOULDBLOCK
# undef EINPROGRESS
# undef EALREADY
# undef ENOTSOCK
# undef EDESTADDRREQ
# undef EMSGSIZE
# undef EPROTOTYPE
# undef ENOPROTOOPT
# undef EPROTONOSUPPORT
# undef EOPNOTSUPP
# undef EAFNOSUPPORT
# undef EADDRINUSE
# undef EADDRNOTAVAIL
# undef ENETDOWN
# undef ENETUNREACH
# undef ENETRESET
# undef ECONNABORTED
# undef ECONNRESET
# undef ENOBUFS
# undef EISCONN
# undef ENOTCONN
# undef ETIMEDOUT
# undef ECONNREFUSED
# undef ELOOP
# undef ENAMETOOLONG
# undef EHOSTUNREACH
# undef ENOTEMPTY
# define EWOULDBLOCK (WSAEWOULDBLOCK-WSABASEERR)
# define EINPROGRESS (WSAEINPROGRESS-WSABASEERR)
# define EALREADY (WSAEALREADY-WSABASEERR)
# define ENOTSOCK (WSAENOTSOCK-WSABASEERR)
# define EDESTADDRREQ (WSAEDESTADDRREQ-WSABASEERR)
# define EMSGSIZE (WSAEMSGSIZE-WSABASEERR)
# define EPROTOTYPE (WSAEPROTOTYPE-WSABASEERR)
# define ENOPROTOOPT (WSAENOPROTOOPT-WSABASEERR)
# define EPROTONOSUPPORT (WSAEPROTONOSUPPORT-WSABASEERR)
# define ESOCKTNOSUPPORT (WSAESOCKTNOSUPPORT-WSABASEERR)
# define EOPNOTSUPP (WSAEOPNOTSUPP-WSABASEERR)
# define EPFNOSUPPORT (WSAEPFNOSUPPORT-WSABASEERR)
# define EAFNOSUPPORT (WSAEAFNOSUPPORT-WSABASEERR)
# define EADDRINUSE (WSAEADDRINUSE-WSABASEERR)
# define EADDRNOTAVAIL (WSAEADDRNOTAVAIL-WSABASEERR)
# define ENETDOWN (WSAENETDOWN-WSABASEERR)
# define ENETUNREACH (WSAENETUNREACH-WSABASEERR)
# define ENETRESET (WSAENETRESET-WSABASEERR)
# define ECONNABORTED (WSAECONNABORTED-WSABASEERR)
# define ECONNRESET (WSAECONNRESET-WSABASEERR)
# define ENOBUFS (WSAENOBUFS-WSABASEERR)
# define EISCONN (WSAEISCONN-WSABASEERR)
# define ENOTCONN (WSAENOTCONN-WSABASEERR)
# define ESHUTDOWN (WSAESHUTDOWN-WSABASEERR)
# define ETOOMANYREFS (WSAETOOMANYREFS-WSABASEERR)
# define ETIMEDOUT (WSAETIMEDOUT-WSABASEERR)
# define ECONNREFUSED (WSAECONNREFUSED-WSABASEERR)
# define ELOOP (WSAELOOP-WSABASEERR)
# define ENAMETOOLONG (WSAENAMETOOLONG-WSABASEERR)
# define EHOSTDOWN (WSAEHOSTDOWN-WSABASEERR)
# define EHOSTUNREACH (WSAEHOSTUNREACH-WSABASEERR)
# define ENOTEMPTY (WSAENOTEMPTY-WSABASEERR)
# define EPROCLIM (WSAEPROCLIM-WSABASEERR)
# define EUSERS (WSAEUSERS-WSABASEERR)
# define EDQUOT (WSAEDQUOT-WSABASEERR)
# define ESTALE (WSAESTALE-WSABASEERR)
# define EREMOTE (WSAEREMOTE-WSABASEERR)
#endif
+243
View File
@@ -0,0 +1,243 @@
# NOTE: This Makefile requires GNU make
# Location to put the targets.
TARGETBINDIR = .
TESTBINDIR = tests
TARGETLIBDIR = .
# Name of the targets
LIBOPUSFILE_TARGET = libopusfile.a
LIBOPUSURL_TARGET = libopusurl.a
OPUSFILE_EXAMPLE_TARGET = opusfile_example
SEEKING_EXAMPLE_TARGET = seeking_example
# Test targets
#TODO: tests
FOO_TARGET = foo
# The command to use to generate dependency information
MAKEDEPEND = ${CC} -MM
#MAKEDEPEND = makedepend -f- -Y --
# Optional features to enable
#CFLAGS := $(CFLAGS) -DOP_HAVE_LRINTF
CFLAGS := $(CFLAGS) -DOP_ENABLE_HTTP
# Extra compilation flags.
# You may get speed increases by including flags such as -O2 or -O3 or
# -ffast-math, or additional flags, depending on your system and compiler.
# The -g flag will generally include debugging information.
CFLAGS := -g $(CFLAGS)
CFLAGS := -DOP_ENABLE_ASSERTIONS $(CFLAGS)
# These are gcc-only, but not actually critical.
CFLAGS := -fPIC $(CFLAGS)
CFLAGS := -std=c89 -pedantic $(CFLAGS)
CFLAGS := -fvisibility=hidden $(CFLAGS)
CFLAGS := -Wextra -Wno-parentheses -Wno-long-long $(CFLAGS)
CFLAGS := -Wall $(CFLAGS)
# The list of pkg-config packages we depend on.
PACKAGES := ogg opus
ifeq ($(findstring -DOP_ENABLE_HTTP,${CFLAGS}),-DOP_ENABLE_HTTP)
PACKAGES += openssl
endif
# The location of include files.
# Modify these to point to your Ogg and Opus include directories if they are
# not installed in a standard location.
CINCLUDE := `pkg-config --cflags ${PACKAGES}`
# Libraries to link with, and the location of library files.
LIBS := `pkg-config --libs ${PACKAGES}`
ifeq ($(findstring -DOP_HAVE_LRINTF,${CFLAGS}),-DOP_HAVE_LRINTF)
LIBS := -lm $(LIBS)
endif
# Extras for the MS target
ifneq ($(findstring mingw,${CC}),)
LIBS += -lwsock32 -lws2_32 -lgdi32 -lcrypt32
EXEEXT := .exe
endif
RANLIB ?= ranlib
#TODO: tests
FOO_LIBS =
# ANYTHING BELOW THIS LINE PROBABLY DOES NOT NEED EDITING
CINCLUDE := -I../include ${CINCLUDE}
LIBSRCDIR = ../src
BINSRCDIR = ../examples
TESTSRCDIR = ${LIBSRCDIR}
WORKDIR = objs
# C source file lists
LIBOPUSFILE_CSOURCES = \
http.c \
info.c \
internal.c \
opusfile.c \
stream.c \
LIBOPUSFILE_CHEADERS = \
internal.h \
LIBOPUSURL_CSOURCES = \
internal.c \
http.c \
ifneq ($(findstring mingw,${CC}),)
LIBOPUSURL_CSOURCES += wincerts.c
endif
LIBOPUSURL_CHEADERS = \
internal.h \
OPUSFILE_EXAMPLE_CSOURCES = opusfile_example.c
SEEKING_EXAMPLE_CSOURCES = seeking_example.c
ifneq ($(findstring mingw,${CC}),)
OPUSFILE_EXAMPLE_CSOURCES += win32utf8.c
SEEKING_EXAMPLE_CSOURCES += win32utf8.c
endif
FOO_CSOURCES = tests/foo.c
# Create object file list.
LIBOPUSFILE_OBJS:= ${LIBOPUSFILE_CSOURCES:%.c=${WORKDIR}/%.o}
LIBOPUSFILE_ASMS:= ${LIBOPUSFILE_OBJS:%.o=%.s}
LIBOPUSFILE_DEPS:= ${LIBOPUSFILE_OBJS:%.o=%.d}
LIBOPUSURL_OBJS:= ${LIBOPUSURL_CSOURCES:%.c=${WORKDIR}/%.o}
LIBOPUSURL_ASMS:= ${LIBOPUSURL_OBJS:%.o=%.s}
LIBOPUSURL_DEPS:= ${LIBOPUSURL_OBJS:%.o=%.d}
OPUSFILE_EXAMPLE_OBJS:= ${OPUSFILE_EXAMPLE_CSOURCES:%.c=${WORKDIR}/%.o}
SEEKING_EXAMPLE_OBJS:= ${SEEKING_EXAMPLE_CSOURCES:%.c=${WORKDIR}/%.o}
#TODO: tests
FOO_OBJS:= ${FOO_CSOURCES:%.c=${WORKDIR}/%.o}
ALL_OBJS:= \
${LIBOPUSFILE_OBJS} \
${LIBOPUSURL_OBJS} \
${OPUSFILE_EXAMPLE_OBJS} \
${SEEKING_EXAMPLE_OBJS} \
#TODO: tests
# ${FOO_OBJS}
# Create the dependency file list
ALL_DEPS:= ${ALL_OBJS:%.o=%.d}
# Prepend source path to file names.
LIBOPUSFILE_CSOURCES:= ${LIBOPUSFILE_CSOURCES:%=${LIBSRCDIR}/%}
LIBOPUSFILE_CHEADERS:= ${LIBOPUSFILE_CHEADERS:%=${LIBSRCDIR}/%}
LIBOPUSURL_CSOURCES:= ${LIBOPUSURL_CSOURCES:%=${LIBSRCDIR}/%}
LIBOPUSURL_CHEADERS:= ${LIBOPUSURL_CHEADERS:%=${LIBSRCDIR}/%}
OPUSFILE_EXAMPLE_CSOURCES:= ${OPUSFILE_EXAMPLE_CSOURCES:%=${BINSRCDIR}/%}
SEEKING_EXAMPLE_CSOURCES:= ${SEEKING_EXAMPLE_CSOURCES:%=${BINSRCDIR}/%}
#TODO: tests
FOO_CSOURCES:= ${FOO_CSOURCES:%=${TESTSRCDIR}/%}
ALL_CSOURCES:= \
${LIBOPUSFILE_CSOURCES} \
${LIBOPUSURL_CSOURCES} \
${OPUSFILE_EXAMPLE_CSOURCES} \
${SEEKING_EXAMPLE_CSOURCES} \
#TODO: tests
# ${FOO_CSOURCES} \
# Prepand target path to file names.
LIBOPUSFILE_TARGET:= ${TARGETLIBDIR}/${LIBOPUSFILE_TARGET}
LIBOPUSURL_TARGET:= ${TARGETLIBDIR}/${LIBOPUSURL_TARGET}
OPUSFILE_EXAMPLE_TARGET:= ${TARGETBINDIR}/${OPUSFILE_EXAMPLE_TARGET}${EXEEXT}
SEEKING_EXAMPLE_TARGET:= ${TARGETBINDIR}/${SEEKING_EXAMPLE_TARGET}${EXEEXT}
# Prepend test path to file names.
#TODO: tests
FOO_TARGET:= ${TESTBINDIR}/${FOO_TARGET}
# Complete set of targets
ALL_TARGETS:= \
${LIBOPUSFILE_TARGET} \
${LIBOPUSURL_TARGET} \
${OPUSFILE_EXAMPLE_TARGET} \
${SEEKING_EXAMPLE_TARGET} \
#TODO: tests
# ${FOO_TARGET} \
# Targets:
# Everything (default)
all: ${ALL_TARGETS}
# libopusfile
${LIBOPUSFILE_TARGET}: ${LIBOPUSFILE_OBJS}
mkdir -p ${TARGETLIBDIR}
$(AR) cqs $@ ${LIBOPUSFILE_OBJS}
-$(RANLIB) $@
# libopusurl
${LIBOPUSURL_TARGET}: ${LIBOPUSURL_OBJS}
mkdir -p ${TARGETLIBDIR}
$(AR) cqs $@ ${LIBOPUSURL_OBJS}
-$(RANLIB) $@
# opusfile_example
${OPUSFILE_EXAMPLE_TARGET}: ${OPUSFILE_EXAMPLE_OBJS} ${LIBOPUSFILE_TARGET} \
${LIBOPUSURL_TARGET}
mkdir -p ${TARGETBINDIR}
${CC} ${CFLAGS} ${OPUSFILE_EXAMPLE_OBJS} ${LIBOPUSFILE_TARGET} \
${LIBOPUSURL_TARGET} ${LIBS} -o $@
# seeking_example
${SEEKING_EXAMPLE_TARGET}: ${SEEKING_EXAMPLE_OBJS} ${LIBOPUSFILE_TARGET} \
${LIBOPUSURL_TARGET}
mkdir -p ${TARGETBINDIR}
${CC} ${CFLAGS} ${SEEKING_EXAMPLE_OBJS} ${LIBOPUSFILE_TARGET} \
${LIBOPUSURL_TARGET} ${LIBS} -o $@
#TODO:
#tests: foo
#
#${FOO_TARGET}: ${FOO_OBJS}
# mkdir -p ${TESTBINDIR}
# ${CC} ${CFLAGS} ${FOO_OBJS} ${FOO_LIBS} -o $@
#
#tests-clean:
# -rmdir ${TESTBINDIR}
# Assembly listing
ALL_ASM := ${ALL_OBJS:%.o=%.s}
asm: ${ALL_ASM}
# Check that build is complete.
check: all
# Remove all targets.
clean:
${RM} ${ALL_ASM} ${ALL_OBJS} ${ALL_DEPS}
${RM} ${ALL_TARGETS}
-rmdir ${WORKDIR}
# Make everything depend on changes in the Makefile
# This vpath directive needs to be before any include statements
vpath Makefile $(dir $(lastword $(MAKEFILE_LIST)))
${ALL_ASM} ${ALL_OBJS} ${ALL_DEPS} ${ALL_TARGETS} : Makefile
# Specify which targets are phony for GNU make
.PHONY : all clean check
# Rules
${WORKDIR}/%.d: ${LIBSRCDIR}/%.c
mkdir -p ${dir $@}
${MAKEDEPEND} ${CINCLUDE} ${CFLAGS} $< -MT ${@:%.d=%.o} > $@
${MAKEDEPEND} ${CINCLUDE} ${CFLAGS} $< -MT ${@:%.d=%.s} >> $@
${MAKEDEPEND} ${CINCLUDE} ${CFLAGS} $< -MT $@ >> $@
${WORKDIR}/%.s: ${LIBSRCDIR}/%.c
mkdir -p ${dir $@}
${CC} ${CINCLUDE} ${CFLAGS} -S -o $@ $<
${WORKDIR}/%.o: ${LIBSRCDIR}/%.c
mkdir -p ${dir $@}
${CC} ${CINCLUDE} ${CFLAGS} -c -o $@ $<
${WORKDIR}/%.d : ${BINSRCDIR}/%.c
mkdir -p ${dir $@}
${MAKEDEPEND} ${CINCLUDE} ${CFLAGS} $< -MT ${@:%.d=%.o} > $@
${WORKDIR}/%.s : ${BINSRCDIR}/%.c ${WORKDIR}/%.o
mkdir -p ${dir $@}
${CC} ${CINCLUDE} ${CFLAGS} -S -o $@ $<
${WORKDIR}/%.o : ${BINSRCDIR}/%.c
mkdir -p ${dir $@}
${CC} ${CINCLUDE} ${CFLAGS} -c -o $@ $<
# Include header file dependencies, except when cleaning
ifneq ($(MAKECMDGOALS),clean)
include ${ALL_DEPS}
endif