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:
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,9 @@
|
||||
brew 'opus'
|
||||
brew 'libogg'
|
||||
brew 'openssl'
|
||||
brew 'autoconf'
|
||||
brew 'automake'
|
||||
brew 'libtool'
|
||||
brew 'pkg-config'
|
||||
brew 'cmake'
|
||||
brew 'doxygen'
|
||||
+321
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,17 @@
|
||||
# Opusfile
|
||||
|
||||
[](https://gitlab.xiph.org/xiph/opusfile/commits/master)
|
||||
[](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
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
@@ -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}
|
||||
------------------------------------------------------------------------
|
||||
])
|
||||
@@ -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
@@ -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
@@ -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 |
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
+2151
File diff suppressed because it is too large
Load Diff
+321
@@ -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
|
||||
])
|
||||
@@ -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
@@ -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
|
||||
@@ -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}
|
||||
@@ -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
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
PACKAGE_VERSION="0.12"
|
||||
+27
@@ -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
|
||||
+3593
File diff suppressed because it is too large
Load Diff
+791
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
+3371
File diff suppressed because it is too large
Load Diff
+434
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user