summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-tidy17
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md29
-rw-r--r--.github/workflows/ci.yml43
-rw-r--r--.gitignore4
-rw-r--r--.travis.yml38
-rw-r--r--CMakeLists.txt140
-rw-r--r--README.md65
-rw-r--r--SECURITY.md17
-rw-r--r--cmake/FindSDL2.cmake392
-rw-r--r--cmake/Findffmpeg.cmake1
-rw-r--r--debian/changelog72
-rw-r--r--debian/compat1
-rw-r--r--debian/control6
-rw-r--r--debian/libsdl-kitchensink-dev.install1
-rw-r--r--debian/libsdl-kitchensink1.symbols3
-rwxr-xr-xdebian/rules2
-rw-r--r--debian/salsa-ci.yml3
-rw-r--r--debian/upstream/metadata4
-rw-r--r--debian/watch2
-rw-r--r--examples/example_audio.c10
-rw-r--r--examples/example_complex.c21
-rw-r--r--examples/example_custom.c2
-rw-r--r--examples/example_rwops.c2
-rw-r--r--examples/example_simple.c2
-rw-r--r--include/kitchensink/internal/audio/kitaudio.h2
-rw-r--r--include/kitchensink/internal/kitdecoder.h43
-rw-r--r--include/kitchensink/internal/libass.h32
-rw-r--r--include/kitchensink/internal/subtitle/kitatlas.h4
-rw-r--r--include/kitchensink/internal/subtitle/kitsubtitle.h6
-rw-r--r--include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h4
-rw-r--r--include/kitchensink/internal/utils/kithelpers.h2
-rw-r--r--include/kitchensink/internal/video/kitvideo.h4
-rw-r--r--include/kitchensink/kitlib.h4
-rw-r--r--include/kitchensink/kitplayer.h52
-rw-r--r--include/kitchensink/kitsource.h4
-rw-r--r--src/internal/audio/kitaudio.c169
-rw-r--r--src/internal/kitdecoder.c102
-rw-r--r--src/internal/kitlibstate.c2
-rw-r--r--src/internal/libass.c19
-rw-r--r--src/internal/subtitle/kitatlas.c44
-rw-r--r--src/internal/subtitle/kitsubtitle.c34
-rw-r--r--src/internal/subtitle/kitsubtitlepacket.c2
-rw-r--r--src/internal/subtitle/renderers/kitsubass.c73
-rw-r--r--src/internal/subtitle/renderers/kitsubimage.c16
-rw-r--r--src/internal/subtitle/renderers/kitsubrenderer.c1
-rw-r--r--src/internal/utils/kithelpers.c4
-rw-r--r--src/internal/utils/kitringbuffer.c2
-rw-r--r--src/internal/video/kitvideo.c167
-rw-r--r--src/kiterror.c3
-rw-r--r--src/kitlib.c28
-rw-r--r--src/kitplayer.c166
-rw-r--r--src/kitsource.c44
52 files changed, 1272 insertions, 638 deletions
diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 0000000..20b04eb
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,17 @@
+---
+Checks: >
+ -*,
+ clang-analyzer-*,
+ clang-diagnostic-*,
+ performance-*,
+ -clang-analyzer-cplusplus*,
+ -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,
+WarningsAsErrors: '*'
+HeaderFilterRegex: ''
+FormatStyle: llvm
+CheckOptions:
+ - key: google-readability-braces-around-statements.ShortStatementLines
+ value: '1'
+ - key: google-readability-function-size.StatementThreshold
+ value: '800'
+...
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..737033e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,29 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: bug
+assignees: katajakasa
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Observed behaviour**
+A clear and concise description of what actually happened.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Platform (please fill out as much as possible):**
+ - OS: [e.g. Ubuntu linux 18.04 LTS]
+ - SDL version
+ - FFMPEG version
+ - SDL_Kitchensink version or commit id
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..2174f73
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,43 @@
+name: CI
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ pull_request:
+ repository_dispatch:
+ types: [run_build]
+
+jobs:
+ ci:
+ name: Run CI on ${{ matrix.config.name }}
+ runs-on: ubuntu-latest
+ env:
+ CC: ${{ matrix.config.cc }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ config:
+ - { name: "gcc 11", cc: gcc-11 }
+ - { name: "gcc 12", cc: gcc-12 }
+ - { name: "gcc 13", cc: gcc-13 }
+ - { name: "clang 13", cc: clang-13 }
+ - { name: "clang 14", cc: clang-14 }
+ - { name: "clang 15", cc: clang-15 }
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Install Dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get -y install libsdl2-dev libavcodec-dev libavformat-dev libavutil-dev \
+ libswresample-dev libswscale-dev libass-dev clang-tidy ${{ matrix.config.cc }}
+
+ - name: Build
+ run: |
+ mkdir build && cd build
+ cmake -DCMAKE_BUILD_TYPE=Release -DUSE_TIDY=1 -DBUILD_EXAMPLES=1 ..
+ make -j2
diff --git a/.gitignore b/.gitignore
index 100120e..d3de1e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,10 @@
# VSCode
.vscode
+# CLion
+.idea
+cmake-build-*
+
# Other
build/
docs/ \ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 2dc6271..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-language: c
-
-sudo: required
-dist: trusty
-
-compiler:
- - gcc
-
-script:
- - wget https://www.libsdl.org/release/SDL2-2.0.8.tar.gz -O - | tar -xz
- - cd SDL2-2.0.8 && CC=gcc-7 ./configure --prefix=/usr && make -j2 && sudo make install && cd ..
- - cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_EXAMPLES=On -DUSE_DYNAMIC_LIBASS=On -DCMAKE_C_COMPILER=/usr/bin/gcc-7 .
- - build-wrapper-linux-x86-64 --out-dir bw-output make && sonar-scanner
-
-notifications:
- email: false
-
-addons:
- sonarcloud:
- organization: "katajakasa-github"
- apt:
- sources:
- - sourceline: 'ppa:ubuntu-toolchain-r/test'
- - sourceline: 'ppa:george-edison55/cmake-3.x'
- - sourceline: 'ppa:jonathonf/ffmpeg-3'
- packages:
- - cmake
- - gcc-7
- - libass-dev
- - libavcodec-dev
- - libavformat-dev
- - libswresample-dev
- - libswscale-dev
- - libavutil-dev
-
-cache:
- directories:
- - '$HOME/.sonar/cache'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f048ee9..e5806fe 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
set(KIT_VERSION_MAJOR "1")
set(KIT_VERSION_MINOR "0")
-set(KIT_VERSION_PATCH "7")
+set(KIT_VERSION_PATCH "12")
set(KIT_VERSION ${KIT_VERSION_MAJOR}.${KIT_VERSION_MINOR}.${KIT_VERSION_PATCH})
add_definitions(
-DKIT_VERSION_MAJOR=${KIT_VERSION_MAJOR}
@@ -22,6 +22,29 @@ set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -DNDEBUG")
option(BUILD_EXAMPLES "Build examples" OFF)
option(USE_DYNAMIC_LIBASS "Use dynamically loaded libass" OFF)
option(USE_ASAN "Use AddressSanitizer" OFF)
+option(USE_TIDY "Use clang-tidy" OFF)
+option(BUILD_SHARED "Build shared library" ON)
+option(BUILD_STATIC "Build static library" ON)
+
+if(NOT BUILD_SHARED AND NOT BUILD_STATIC)
+ message(FATAL_ERROR "Nothing to build, set BUILD_SHARED and/or BUILD_STATIC.")
+endif()
+
+if(BUILD_SHARED)
+ message(STATUS "Building shared libraries")
+else()
+ message(STATUS "NOT building shared libraries")
+endif()
+
+if(BUILD_STATIC)
+ message(STATUS "Building static libraries")
+else()
+ message(STATUS "NOT building static libraries")
+endif()
+
+if(USE_ASAN)
+ message(STATUS "DEVELOPMENT: AddressSanitizer enabled!")
+endif()
find_package(SDL2 REQUIRED)
find_package(ffmpeg COMPONENTS avcodec avformat avutil swscale swresample)
@@ -53,32 +76,57 @@ endif()
FILE(GLOB_RECURSE SOURCES "src/*.c")
FILE(GLOB INSTALL_HEADERS "include/kitchensink/*.h")
-add_library(SDL_kitchensink SHARED ${SOURCES})
-add_library(SDL_kitchensink_static STATIC ${SOURCES})
+include_directories(${INCLUDES})
+
+set(INSTALL_TARGETS "")
-set_target_properties(SDL_kitchensink PROPERTIES VERSION ${KIT_VERSION})
-set_target_properties(SDL_kitchensink PROPERTIES SOVERSION ${KIT_VERSION_MAJOR})
+if(BUILD_SHARED)
+ add_library(SDL_kitchensink SHARED ${SOURCES})
-set_target_properties(SDL_kitchensink PROPERTIES DEBUG_POSTFIX "d")
-set_target_properties(SDL_kitchensink_static PROPERTIES DEBUG_POSTFIX "d")
+ if(USE_ASAN)
+ target_compile_options(SDL_kitchensink PRIVATE "-fsanitize=address")
+ target_link_libraries(SDL_kitchensink asan)
+ endif()
-target_compile_definitions(SDL_kitchensink PRIVATE "KIT_DLL;KIT_DLL_EXPORTS")
-target_compile_options(SDL_kitchensink PRIVATE "-fvisibility=hidden")
+ target_link_libraries(SDL_kitchensink ${LIBRARIES})
-set_property(TARGET SDL_kitchensink PROPERTY C_STANDARD 99)
-set_property(TARGET SDL_kitchensink_static PROPERTY C_STANDARD 99)
+ set_target_properties(SDL_kitchensink PROPERTIES VERSION ${KIT_VERSION})
+ set_target_properties(SDL_kitchensink PROPERTIES SOVERSION ${KIT_VERSION_MAJOR})
+ set_target_properties(SDL_kitchensink PROPERTIES DEBUG_POSTFIX "d")
-if(USE_ASAN)
- set(LIBRARIES asan ${LIBRARIES})
- target_compile_options(SDL_kitchensink PRIVATE "-fsanitize=address")
- message(STATUS "DEVELOPMENT: AddressSanitizer enabled!")
+ target_compile_definitions(SDL_kitchensink PRIVATE "KIT_DLL;KIT_DLL_EXPORTS")
+ target_compile_options(SDL_kitchensink PRIVATE "-fvisibility=hidden")
+
+ set_property(TARGET SDL_kitchensink PROPERTY C_STANDARD 99)
+
+ set(INSTALL_TARGETS SDL_kitchensink ${INSTALL_TARGETS})
endif()
-include_directories(${INCLUDES})
-target_link_libraries(SDL_kitchensink ${LIBRARIES})
+if(BUILD_STATIC)
+ add_library(SDL_kitchensink_static STATIC ${SOURCES})
-set(PKG_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/SDL_kitchensink.pc")
+ if(USE_ASAN)
+ target_compile_options(SDL_kitchensink_static PRIVATE "-fsanitize=address")
+ endif()
+ set_target_properties(SDL_kitchensink_static PROPERTIES DEBUG_POSTFIX "d")
+ set_property(TARGET SDL_kitchensink_static PROPERTY C_STANDARD 99)
+
+ set(INSTALL_TARGETS SDL_kitchensink_static ${INSTALL_TARGETS})
+endif()
+
+if(USE_TIDY)
+ if(BUILD_STATIC)
+ set_target_properties(SDL_kitchensink_static PROPERTIES C_CLANG_TIDY "clang-tidy")
+ else()
+ set_target_properties(SDL_kitchensink PROPERTIES C_CLANG_TIDY "clang-tidy")
+ endif()
+ message(STATUS "Development: clang-tidy enabled")
+else()
+ message(STATUS "Development: clang-tidy disabled")
+endif()
+
+set(PKG_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/SDL_kitchensink.pc")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/pkg-config.pc.in"
${PKG_CONFIG_FILE}
@@ -86,40 +134,44 @@ configure_file(
)
if(BUILD_EXAMPLES)
- add_executable(audio examples/example_audio.c)
- add_executable(complex examples/example_complex.c)
- add_executable(simple examples/example_simple.c)
- add_executable(custom examples/example_custom.c)
- add_executable(rwops examples/example_rwops.c)
-
- if(MINGW)
- target_link_libraries(audio mingw32)
- target_link_libraries(complex mingw32)
- target_link_libraries(simple mingw32)
- target_link_libraries(custom mingw32)
- target_link_libraries(rwops mingw32)
+ list(APPEND EXAMPLE_TARGETS audio complex simple custom rwops)
+
+ # If we are building static, just link all libraries (ffmpeg, sdl, etc.)
+ # If building shared, link shared kitchensink + SDL2 (ffmpeg gets pulled by kitchensink)
+ if(BUILD_STATIC)
+ set(EXAMPLE_LIBRARIES SDL_kitchensink_static ${LIBRARIES})
+ else()
+ set(EXAMPLE_LIBRARIES SDL_kitchensink ${SDL2_LIBRARIES})
+ endif()
+ if(USE_ASAN)
+ set(EXAMPLE_LIBRARIES asan ${EXAMPLE_LIBRARIES})
endif()
- set_property(TARGET audio PROPERTY C_STANDARD 99)
- set_property(TARGET complex PROPERTY C_STANDARD 99)
- set_property(TARGET simple PROPERTY C_STANDARD 99)
- set_property(TARGET custom PROPERTY C_STANDARD 99)
- set_property(TARGET rwops PROPERTY C_STANDARD 99)
-
- target_link_libraries(audio SDL_kitchensink_static ${LIBRARIES})
- target_link_libraries(complex SDL_kitchensink_static ${LIBRARIES})
- target_link_libraries(simple SDL_kitchensink_static ${LIBRARIES})
- target_link_libraries(custom SDL_kitchensink_static ${LIBRARIES})
- target_link_libraries(rwops SDL_kitchensink_static ${LIBRARIES})
+ foreach(TARGET ${EXAMPLE_TARGETS})
+ add_executable(${TARGET} examples/example_${TARGET}.c)
+ set_property(TARGET ${TARGET} PROPERTY C_STANDARD 99)
+ target_link_libraries(${TARGET} ${EXAMPLE_LIBRARIES})
+
+ if(MINGW)
+ # If we are compiling with mingw, remember to link in mingw libs and set console mode
+ # This way stdout/stderr are handled correctly.
+ target_link_libraries(${TARGET} mingw32)
+ set_target_properties(${TARGET} PROPERTIES LINK_FLAGS "-mconsole")
+ endif()
+
+ if(USE_ASAN)
+ target_compile_options(${TARGET} PRIVATE "-fsanitize=address")
+ endif()
+ endforeach()
endif()
# documentation target
add_custom_target(docs COMMAND doxygen WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
# Installation
-install(FILES ${PKG_CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
-install(FILES ${INSTALL_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/kitchensink)
-INSTALL(TARGETS SDL_kitchensink SDL_kitchensink_static
+INSTALL(FILES ${PKG_CONFIG_FILE} DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+INSTALL(FILES ${INSTALL_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/kitchensink)
+INSTALL(TARGETS ${INSTALL_TARGETS}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
diff --git a/README.md b/README.md
index d2745ce..6031190 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
# SDL_kitchensink
-[![Build Status](https://travis-ci.org/katajakasa/SDL_kitchensink.svg?branch=master)](https://travis-ci.org/katajakasa/SDL_kitchensink)
-[![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=sdl_kitchensink&metric=alert_status)](https://sonarcloud.io/dashboard?id=sdl_kitchensink)
+[![CI](https://github.com/katajakasa/SDL_kitchensink/actions/workflows/ci.yml/badge.svg)](https://github.com/katajakasa/SDL_kitchensink/actions/workflows/ci.yml)
FFmpeg and SDL2 based library for audio and video playback, written in C99.
@@ -20,38 +19,49 @@ Note! Master branch is for the development of v1.0.0 series. v0 can be found in
rel-kitchensink-0 branch. v0 is no longer in active development and only bug- and security-fixes
are accepted.
-## 1. Library requirements
+## 1. Installation
+
+Nowadays you can find SDL_kitchensink in eg. linux repositories. Installation might be as simple as
+running the following (or your distributions' equivalent):
+
+```apt install libsdl-kitchensink libsdl-kitchensink-dev```
+
+If you are running on windows/MSYS2 or on linux distributions where the package management does not
+have kitchensink, you will need to compile it yourself. Please see the "Compiling" section below.
+
+## 2. Library requirements
Build requirements:
-* CMake (>=3.0)
+* CMake (>=3.7)
* GCC (C99 support required)
Library requirements:
-* SDL2 (>=2.0.5)
-* FFmpeg (>=3.0)
+* SDL2 2.0.5 or newer
+* FFmpeg 3.2 or newer
* libass (optional, supports runtime linking via SDL_LoadSO)
Note that Clang might work, but is not tested. Older SDL2 and FFmpeg library versions
may or may not work; versions noted here are the only ones tested.
-### 1.1. Debian / Ubuntu
+### 2.1. Debian / Ubuntu
```
-sudo apt-get install libsdl2-dev libavcodec-dev libavdevice-dev libavfilter-dev \
-libavformat-dev libavresample-dev libavutil-dev libswresample-dev libswscale-dev \
-libpostproc-dev libass-dev
+sudo apt-get install libsdl2-dev libavcodec-dev libavformat-dev \
+ libavutil-dev libswresample-dev libswscale-dev libass-dev
```
-### 1.2. MSYS2 64bit
+### 2.2. MSYS2 64bit
These are for x86_64. For 32bit installation, just change the package names a bit .
```
pacman -S mingw-w64-x86_64-SDL2 mingw-w64-x86_64-ffmpeg mingw-w64-x86_64-libass
```
-## 2. Compiling
+## 3. Compiling
By default, both static and dynamic libraries are built.
+* Set BUILD_STATIC off if you don't want to build static library
+* Set BUILD_SHARED off if you don't want to build shared library
* Dynamic library is called libSDL_kitchensink.dll or .so
* Static library is called libSDL_kitchensink_static.a
* If you build in debug mode (```-DCMAKE_BUILD_TYPE=Debug```), libraries will be postfixed with 'd'.
@@ -61,25 +71,25 @@ Change CMAKE_INSTALL_PREFIX as necessary to change the installation path. The fi
* CMAKE_INSTALL_PREFIX/bin for binaries (.dll, .so)
* CMAKE_INSTALL_PREFIX/include for headers
-### 2.1. Building the libraries on Debian/Ubuntu
+### 3.1. Building the libraries on Debian/Ubuntu
1. ```mkdir build && cd build```
2. ```cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..```
3. ```make -j```
4. ```sudo make install```
-### 2.2. Building the libraries on MSYS2
+### 3.2. Building the libraries on MSYS2
1. ```mkdir build && cd build```
2. ```cmake -G "MSYS Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..```
3. ```make```
4. ```make install```
-### 2.3. Building examples
+### 3.3. Building examples
Just add ```-DBUILD_EXAMPLES=1``` to cmake arguments and rebuild.
-### 2.4. Building with AddressSanitizer
+### 3.4. Building with AddressSanitizer
This is for development/debugging use only!
@@ -88,31 +98,38 @@ supported on all OSes (eg. windows).
After building, you can run with the following (make sure to set correct llvm-symbolizer path):
```
-ASAN_OPTIONS=symbolize=1 ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer ./examplevideo <my videofile>
+ASAN_OPTIONS=symbolize=1 ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer ./complex <my videofile>
```
-## 3. Why the name SDL_kitchensink
+## 4. Q&A
+
+Q: What's with the USE_DYNAMIC_LIBASS cmake flag ?
+* A: It can be used to link the libass dynamically when needed. This also makes it possible to build the
+ library without libass, if needed. Using this flag is not recommended however, and it will probably
+ be deprecated in the next major version(s). If you use it, you might need to also patch the library
+ path and name to match yours in kitchensink source.
-Because pulling major blob of library code like ffmpeg feels like bringing in a whole house with its
-kitchensink and everything to the project. Also, it sounded funny. Also, SDL_ffmpeg is already reserved :(
+Q: Why the name SDL_kitchensink
+* A: Because pulling major blob of library code like ffmpeg feels like bringing in a whole house with its
+ kitchensink and everything to the project. Also, it sounded funny. Also, SDL_ffmpeg is already reserved :(
-## 4. Examples
+## 5. Examples
Please see examples directory. You can also take a look at unittests for some help.
Note that examples are NOT meant for any kind of real life use; they are only meant to
show simple use cases for the library.
-## 5. FFMPEG & licensing
+## 6. FFMPEG & licensing
Note that FFmpeg has a rather complex license. Please take a look at
[FFmpeg Legal page](http://ffmpeg.org/legal.html) for details.
-## 6. License
+## 7. License
```
The MIT License (MIT)
-Copyright (c) 2018 Tuomas Virtanen
+Copyright (c) 2020 Tuomas Virtanen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000..75059ee
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,17 @@
+# Security Policy
+
+## Supported Versions
+
+Master branch is for the development of v1.0.0 series.
+v0 can be found in the rel-kitchensink-0 branch. v0 is no longer in active
+development and only fixes for severe security bugs are accepted.
+
+| Version | Supported |
+| ------- | ------------------ |
+| 1.0.x | :white_check_mark: |
+| 0.0.x | :x: |
+
+## Reporting a Vulnerability
+
+To report a vulnerability, please email me at katajakasa@gmail.com. Note that it may
+take me a few days to respond, as I don't constantly check my emails :)
diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake
new file mode 100644
index 0000000..00a860d
--- /dev/null
+++ b/cmake/FindSDL2.cmake
@@ -0,0 +1,392 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
+# Copyright 2000-2019 Kitware, Inc. and Contributors
+# All rights reserved.
+
+# 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 Kitware, Inc. nor the names of 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 COPYRIGHT
+# HOLDER 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.
+
+#[=======================================================================[.rst:
+FindSDL2
+--------
+
+Locate SDL2 library
+
+This module defines the following 'IMPORTED' targets:
+
+::
+
+ SDL2::Core (for compatibility with older versions)
+ SDL2::SDL2 (compatibility with CONFIG mode)
+ The SDL2 library, if found.
+ Libraries should link to SDL2::SDL2
+
+ SDL2::Main (for compatibility with older versions)
+ SDL2::SDL2main (compatibility with CONFIG mode)
+ The SDL2main library, if found.
+ Applications should link to SDL2::SDL2main instead of SDL2::SDL2
+
+
+
+This module will set the following variables in your project:
+
+::
+
+ SDL2_LIBRARIES, the name of the library to link against
+ SDL2_INCLUDE_DIRS, where to find SDL.h
+ SDL2_FOUND, if false, do not try to link to SDL2
+ SDL2MAIN_FOUND, if false, do not try to link to SDL2main
+ SDL2_VERSION_STRING, human-readable string containing the version of SDL2
+
+
+
+This module responds to the following cache variables:
+
+::
+
+ SDL2_PATH
+ Set a custom SDL2 Library path (default: empty)
+
+ SDL2_NO_DEFAULT_PATH
+ Disable search SDL2 Library in default path.
+ If SDL2_PATH (default: ON)
+ Else (default: OFF)
+
+ SDL2_INCLUDE_DIR
+ SDL2 headers path.
+
+ SDL2_LIBRARY
+ SDL2 Library (.dll, .so, .a, etc) path.
+
+ SDL2MAIN_LIBRAY
+ SDL2main Library (.a) path.
+
+ SDL2_BUILDING_LIBRARY
+ This flag is useful only when linking to SDL2_LIBRARIES insead of
+ SDL2::Main. It is required only when building a library that links to
+ SDL2_LIBRARIES, because only applications need main() (No need to also
+ link to SDL2main).
+ If this flag is defined, then no SDL2main will be added to SDL2_LIBRARIES
+ and no SDL2::Main target will be created.
+
+
+Don't forget to include SDLmain.h and SDLmain.m in your project for the
+OS X framework based version. (Other versions link to -lSDL2main which
+this module will try to find on your behalf.) Also for OS X, this
+module will automatically add the -framework Cocoa on your behalf.
+
+
+Additional Note: If you see an empty SDL2_LIBRARY in your project
+configuration, it means CMake did not find your SDL2 library
+(SDL2.dll, libsdl2.so, SDL2.framework, etc). Set SDL2_LIBRARY to point
+to your SDL2 library, and configure again. Similarly, if you see an
+empty SDL2MAIN_LIBRARY, you should set this value as appropriate. These
+values are used to generate the final SDL2_LIBRARIES variable and the
+SDL2::Core and SDL2::Main targets, but when these values are unset,
+SDL2_LIBRARIES, SDL2::Core and SDL2::Main does not get created.
+
+
+$SDL2DIR is an environment variable that would correspond to the
+./configure --prefix=$SDL2DIR used in building SDL2. l.e.galup 9-20-02
+
+
+
+Created by Amine Ben Hassouna:
+ Adapt FindSDL.cmake to SDL2 (FindSDL2.cmake).
+ Add cache variables for more flexibility:
+ SDL2_PATH, SDL2_NO_DEFAULT_PATH (for details, see doc above).
+ Mark 'Threads' as a required dependency for non-OSX systems.
+ Modernize the FindSDL2.cmake module by creating specific targets:
+ SDL2::Core and SDL2::Main (for details, see doc above).
+
+
+Original FindSDL.cmake module:
+ Modified by Eric Wing. Added code to assist with automated building
+ by using environmental variables and providing a more
+ controlled/consistent search behavior. Added new modifications to
+ recognize OS X frameworks and additional Unix paths (FreeBSD, etc).
+ Also corrected the header search path to follow "proper" SDL
+ guidelines. Added a search for SDLmain which is needed by some
+ platforms. Added a search for threads which is needed by some
+ platforms. Added needed compile switches for MinGW.
+
+On OSX, this will prefer the Framework version (if found) over others.
+People will have to manually change the cache value of SDL2_LIBRARY to
+override this selection or set the SDL2_PATH variable or the CMake
+environment CMAKE_INCLUDE_PATH to modify the search paths.
+
+Note that the header path has changed from SDL/SDL.h to just SDL.h
+This needed to change because "proper" SDL convention is #include
+"SDL.h", not <SDL/SDL.h>. This is done for portability reasons
+because not all systems place things in SDL/ (see FreeBSD).
+#]=======================================================================]
+
+# Define options for searching SDL2 Library in a custom path
+
+set(SDL2_PATH "" CACHE STRING "Custom SDL2 Library path")
+
+set(_SDL2_NO_DEFAULT_PATH OFF)
+if(SDL2_PATH)
+ set(_SDL2_NO_DEFAULT_PATH ON)
+endif()
+
+set(SDL2_NO_DEFAULT_PATH ${_SDL2_NO_DEFAULT_PATH}
+ CACHE BOOL "Disable search SDL2 Library in default path")
+unset(_SDL2_NO_DEFAULT_PATH)
+
+set(SDL2_NO_DEFAULT_PATH_CMD)
+if(SDL2_NO_DEFAULT_PATH)
+ set(SDL2_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH)
+endif()
+
+# Search for the SDL2 include directory
+find_path(SDL2_INCLUDE_DIR SDL.h
+ HINTS
+ ENV SDL2DIR
+ ${SDL2_NO_DEFAULT_PATH_CMD}
+ PATH_SUFFIXES SDL2
+ # path suffixes to search inside ENV{SDL2DIR}
+ include/SDL2 include
+ PATHS ${SDL2_PATH}
+ DOC "Where the SDL2 headers can be found"
+)
+
+set(SDL2_INCLUDE_DIRS "${SDL2_INCLUDE_DIR}")
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(VC_LIB_PATH_SUFFIX lib/x64)
+else()
+ set(VC_LIB_PATH_SUFFIX lib/x86)
+endif()
+
+# SDL-2.0 is the name used by FreeBSD ports...
+# don't confuse it for the version number.
+find_library(SDL2_LIBRARY
+ NAMES SDL2 SDL-2.0
+ HINTS
+ ENV SDL2DIR
+ ${SDL2_NO_DEFAULT_PATH_CMD}
+ PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+ PATHS ${SDL2_PATH}
+ DOC "Where the SDL2 Library can be found"
+)
+
+set(SDL2_LIBRARIES "${SDL2_LIBRARY}")
+
+if(NOT SDL2_BUILDING_LIBRARY)
+ if(NOT SDL2_INCLUDE_DIR MATCHES ".framework")
+ # Non-OS X framework versions expect you to also dynamically link to
+ # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
+ # seem to provide SDL2main for compatibility even though they don't
+ # necessarily need it.
+
+ if(SDL2_PATH)
+ set(SDL2MAIN_LIBRARY_PATHS "${SDL2_PATH}")
+ endif()
+
+ if(NOT SDL2_NO_DEFAULT_PATH)
+ set(SDL2MAIN_LIBRARY_PATHS
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+ "${SDL2MAIN_LIBRARY_PATHS}"
+ )
+ endif()
+
+ find_library(SDL2MAIN_LIBRARY
+ NAMES SDL2main
+ HINTS
+ ENV SDL2DIR
+ ${SDL2_NO_DEFAULT_PATH_CMD}
+ PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX}
+ PATHS ${SDL2MAIN_LIBRARY_PATHS}
+ DOC "Where the SDL2main library can be found"
+ )
+ unset(SDL2MAIN_LIBRARY_PATHS)
+ endif()
+endif()
+
+# SDL2 may require threads on your system.
+# The Apple build may not need an explicit flag because one of the
+# frameworks may already provide it.
+# But for non-OSX systems, I will use the CMake Threads package.
+if(NOT APPLE)
+ find_package(Threads QUIET)
+ if(NOT Threads_FOUND)
+ set(SDL2_THREADS_NOT_FOUND "Could NOT find Threads (Threads is required by SDL2).")
+ if(SDL2_FIND_REQUIRED)
+ message(FATAL_ERROR ${SDL2_THREADS_NOT_FOUND})
+ else()
+ if(NOT SDL2_FIND_QUIETLY)
+ message(STATUS ${SDL2_THREADS_NOT_FOUND})
+ endif()
+ return()
+ endif()
+ unset(SDL2_THREADS_NOT_FOUND)
+ endif()
+endif()
+
+# MinGW needs an additional link flag, -mwindows
+# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -mwindows
+if(MINGW)
+ set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW")
+endif()
+
+if(SDL2_LIBRARY)
+ # For SDL2main
+ if(SDL2MAIN_LIBRARY AND NOT SDL2_BUILDING_LIBRARY)
+ list(FIND SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" _SDL2_MAIN_INDEX)
+ if(_SDL2_MAIN_INDEX EQUAL -1)
+ set(SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" ${SDL2_LIBRARIES})
+ endif()
+ unset(_SDL2_MAIN_INDEX)
+ endif()
+
+ # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
+ # CMake doesn't display the -framework Cocoa string in the UI even
+ # though it actually is there if I modify a pre-used variable.
+ # I think it has something to do with the CACHE STRING.
+ # So I use a temporary variable until the end so I can set the
+ # "real" variable in one-shot.
+ if(APPLE)
+ set(SDL2_LIBRARIES ${SDL2_LIBRARIES} -framework Cocoa)
+ endif()
+
+ # For threads, as mentioned Apple doesn't need this.
+ # In fact, there seems to be a problem if I used the Threads package
+ # and try using this line, so I'm just skipping it entirely for OS X.
+ if(NOT APPLE)
+ set(SDL2_LIBRARIES ${SDL2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+
+ # For MinGW library
+ if(MINGW)
+ set(SDL2_LIBRARIES ${MINGW32_LIBRARY} ${SDL2_LIBRARIES})
+ endif()
+
+endif()
+
+# Read SDL2 version
+if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL_version.h")
+ file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$")
+ file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$")
+ string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}")
+ string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}")
+ set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH})
+ unset(SDL2_VERSION_MAJOR_LINE)
+ unset(SDL2_VERSION_MINOR_LINE)
+ unset(SDL2_VERSION_PATCH_LINE)
+ unset(SDL2_VERSION_MAJOR)
+ unset(SDL2_VERSION_MINOR)
+ unset(SDL2_VERSION_PATCH)
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+set(SDL2_REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
+if(SDL2MAIN_LIBRARY)
+ list(APPEND SDL2_REQUIRED_VARS SDL2MAIN_LIBRARY SDL2_INCLUDE_DIR)
+endif()
+
+find_package_handle_standard_args(SDL2
+ REQUIRED_VARS ${SDL2_REQUIRED_VARS}
+ VERSION_VAR SDL2_VERSION_STRING)
+
+mark_as_advanced(SDL2_PATH
+ SDL2_NO_DEFAULT_PATH
+ SDL2_LIBRARY
+ SDL2MAIN_LIBRARY
+ SDL2_INCLUDE_DIR
+ SDL2_BUILDING_LIBRARY)
+
+
+# SDL2:: targets (SDL2::Core and SDL2::Main)
+if(SDL2_FOUND)
+
+ # SDL2::Core target
+ if(SDL2_LIBRARY AND NOT TARGET SDL2::Core)
+ add_library(SDL2::Core UNKNOWN IMPORTED)
+ set_target_properties(SDL2::Core PROPERTIES
+ IMPORTED_LOCATION "${SDL2_LIBRARY}"
+ INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}")
+
+ if(APPLE)
+ # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
+ # For more details, please see above.
+ set_property(TARGET SDL2::Core APPEND PROPERTY
+ INTERFACE_LINK_OPTIONS -framework Cocoa)
+ else()
+ # For threads, as mentioned Apple doesn't need this.
+ # For more details, please see above.
+ set_property(TARGET SDL2::Core APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES Threads::Threads)
+ endif()
+ endif()
+
+ # SDL2::Main target
+ # Applications should link to SDL2::Main instead of SDL2::Core
+ # For more details, please see above.
+ if(NOT SDL2_BUILDING_LIBRARY AND NOT TARGET SDL2::Main)
+
+ if(SDL2_INCLUDE_DIR MATCHES ".framework" OR NOT SDL2MAIN_LIBRARY)
+ add_library(SDL2::Main INTERFACE IMPORTED)
+ set_property(TARGET SDL2::Main PROPERTY
+ INTERFACE_LINK_LIBRARIES SDL2::Core)
+ elseif(SDL2MAIN_LIBRARY)
+ # MinGW requires that the mingw32 library is specified before the
+ # libSDL2main.a static library when linking.
+ # The SDL2::MainInternal target is used internally to make sure that
+ # CMake respects this condition.
+ add_library(SDL2::MainInternal UNKNOWN IMPORTED)
+ set_property(TARGET SDL2::MainInternal PROPERTY
+ IMPORTED_LOCATION "${SDL2MAIN_LIBRARY}")
+ set_property(TARGET SDL2::MainInternal PROPERTY
+ INTERFACE_LINK_LIBRARIES SDL2::Core)
+
+ add_library(SDL2::Main INTERFACE IMPORTED)
+
+ if(MINGW)
+ # MinGW needs an additional link flag '-mwindows' and link to mingw32
+ set_property(TARGET SDL2::Main PROPERTY
+ INTERFACE_LINK_LIBRARIES "mingw32" "-mwindows")
+ endif()
+
+ set_property(TARGET SDL2::Main APPEND PROPERTY
+ INTERFACE_LINK_LIBRARIES SDL2::MainInternal)
+ endif()
+
+ # compatibility targets
+ add_library(SDL2::SDL2 ALIAS SDL2::Core)
+ add_library(SDL2::SDL2main ALIAS SDL2::Main)
+
+ endif()
+endif()
diff --git a/cmake/Findffmpeg.cmake b/cmake/Findffmpeg.cmake
index fdb6246..4cb7879 100644
--- a/cmake/Findffmpeg.cmake
+++ b/cmake/Findffmpeg.cmake
@@ -22,7 +22,6 @@ set(FFMPEG_COMPONENTS
avformat
avdevice
avfilter
- avresample
avutil
swresample
swscale
diff --git a/debian/changelog b/debian/changelog
index 0d753b4..d725d3b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,75 @@
+sdl-kitchensink (1.0.12-1) unstable; urgency=medium
+
+ * New 1.0.12 upstream version
+ - add 2 new 1.0.12 symbols
+
+ -- Didier Raboud <odyx@debian.org> Sat, 09 Dec 2023 17:18:59 +0100
+
+sdl-kitchensink (1.0.11-1) unstable; urgency=medium
+
+ * New 1.0.11 upstream release
+ * Re-adopt package
+ * Bump S-V and d/watch versions
+ * Set Rules-Requires-Root to no
+ * Add Build-Depends-Package: libsdl-kitchensink-dev to .symbols
+
+ -- Didier Raboud <odyx@debian.org> Sun, 24 Sep 2023 18:14:01 +0200
+
+sdl-kitchensink (1.0.9-3) unstable; urgency=medium
+
+ * Orphan package
+ * Drop unused libavresample-dev B-D (Closes: #993421)
+ * S-V: Upgrade to 4.6.0 without changes needed
+
+ -- Didier Raboud <odyx@debian.org> Wed, 01 Sep 2021 14:09:02 +0200
+
+sdl-kitchensink (1.0.9-2) unstable; urgency=medium
+
+ * Drop unused ffmpeg avresample requirements (Closes: #971321)
+
+ -- Didier Raboud <odyx@debian.org> Mon, 05 Oct 2020 19:51:51 +0200
+
+sdl-kitchensink (1.0.9-1) unstable; urgency=medium
+
+ * New 1.0.9 release
+ - drop upstream patch backport
+
+ -- Didier Raboud <odyx@debian.org> Wed, 29 Jul 2020 08:21:20 +0200
+
+sdl-kitchensink (1.0.8-3) unstable; urgency=medium
+
+ * Drop -fcommon passing in CFLAGS; replace by upstream patch
+
+ -- Didier Raboud <odyx@debian.org> Mon, 27 Jul 2020 08:55:26 +0200
+
+sdl-kitchensink (1.0.8-2) unstable; urgency=medium
+
+ * Pass -fcommon in CFLAGS to circumvent gcc-10 FTBFS (Closes: #957784)
+
+ -- Didier Raboud <odyx@debian.org> Fri, 24 Jul 2020 14:50:23 +0200
+
+sdl-kitchensink (1.0.8-1) unstable; urgency=medium
+
+ * New 1.0.8 upstream release
+
+ [ Debian Janitor ]
+ * Bump debhelper from old 11 to 12
+ * Set various upstream metadata fields
+ * Rely on pre-initialized dpkg-architecture variables
+
+ [ Didier Raboud ]
+ * Bump S-V to 4.5.0 without changes needed
+ * Bump debhelper compat to 13
+ * Install pkgconfig file in -dev
+
+ -- Didier Raboud <odyx@debian.org> Tue, 05 May 2020 19:19:46 +0200
+
+sdl-kitchensink (1.0.7-1) unstable; urgency=medium
+
+ * New 1.0.7 upstream release
+
+ -- Didier Raboud <odyx@debian.org> Sun, 25 Nov 2018 13:53:27 +0100
+
sdl-kitchensink (1.0.6-1) unstable; urgency=medium
* New 1.0.6 upstream release
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index b4de394..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-11
diff --git a/debian/control b/debian/control
index d7d6405..44df41c 100644
--- a/debian/control
+++ b/debian/control
@@ -2,23 +2,23 @@ Source: sdl-kitchensink
Maintainer: Didier Raboud <odyx@debian.org>
Section: libs
Priority: optional
-Build-Depends: debhelper (>= 11~),
+Build-Depends: debhelper-compat (= 13),
cmake,
libsdl2-dev,
libavcodec-dev,
libavdevice-dev,
libavfilter-dev,
libavformat-dev,
- libavresample-dev,
libavutil-dev,
libswresample-dev,
libswscale-dev,
libpostproc-dev,
libass-dev
-Standards-Version: 4.2.1
+Standards-Version: 4.6.2
Vcs-Browser: https://salsa.debian.org/debian/sdl-kitchensink
Vcs-Git: https://salsa.debian.org/debian/sdl-kitchensink.git
Homepage: https://github.com/katajakasa/SDL_kitchensink
+Rules-Requires-Root: no
Package: libsdl-kitchensink1
Architecture: any
diff --git a/debian/libsdl-kitchensink-dev.install b/debian/libsdl-kitchensink-dev.install
index fe5c134..4e2bd44 100644
--- a/debian/libsdl-kitchensink-dev.install
+++ b/debian/libsdl-kitchensink-dev.install
@@ -1,3 +1,4 @@
usr/include/kitchensink/*.h
usr/lib/*/libSDL_kitchensink.so
usr/lib/*/libSDL_kitchensink_static.a
+usr/lib/*/pkgconfig/SDL_kitchensink.pc
diff --git a/debian/libsdl-kitchensink1.symbols b/debian/libsdl-kitchensink1.symbols
index d5e54a0..e42e00f 100644
--- a/debian/libsdl-kitchensink1.symbols
+++ b/debian/libsdl-kitchensink1.symbols
@@ -1,4 +1,5 @@
libSDL_kitchensink.so.1 libsdl-kitchensink1 #MINVER#
+* Build-Depends-Package: libsdl-kitchensink-dev
Kit_ClearError@Base 0.0.6
Kit_ClosePlayer@Base 0.0.6
Kit_CloseSource@Base 0.0.6
@@ -10,6 +11,7 @@ libSDL_kitchensink.so.1 libsdl-kitchensink1 #MINVER#
Kit_GetError@Base 0.0.6
Kit_GetHint@Base 1.0.2
Kit_GetKitStreamTypeString@Base 0.0.6
+ Kit_GetPlayerAspectRatio@Base 1.0.12
Kit_GetPlayerAudioData@Base 1.0.2
Kit_GetPlayerAudioStream@Base 1.0.2
Kit_GetPlayerDuration@Base 0.0.6
@@ -19,6 +21,7 @@ libSDL_kitchensink.so.1 libsdl-kitchensink1 #MINVER#
Kit_GetPlayerSubtitleData@Base 1.0.2
Kit_GetPlayerSubtitleStream@Base 1.0.2
Kit_GetPlayerVideoData@Base 1.0.2
+ Kit_GetPlayerVideoDataArea@Base 1.0.12
Kit_GetPlayerVideoStream@Base 1.0.2
Kit_GetSDLAudioFormatString@Base 0.0.6
Kit_GetSDLPixelFormatString@Base 0.0.6
diff --git a/debian/rules b/debian/rules
index fbac4e2..2920c41 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,6 +1,6 @@
#!/usr/bin/make -f
-DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
+include /usr/share/dpkg/architecture.mk
%:
dh $@
diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml
new file mode 100644
index 0000000..0c22dc4
--- /dev/null
+++ b/debian/salsa-ci.yml
@@ -0,0 +1,3 @@
+include:
+ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
+ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
new file mode 100644
index 0000000..bf8b4b2
--- /dev/null
+++ b/debian/upstream/metadata
@@ -0,0 +1,4 @@
+Bug-Database: https://github.com/katajakasa/SDL_kitchensink/issues
+Bug-Submit: https://github.com/katajakasa/SDL_kitchensink/issues/new
+Repository: https://github.com/katajakasa/SDL_kitchensink.git
+Repository-Browse: https://github.com/katajakasa/SDL_kitchensink
diff --git a/debian/watch b/debian/watch
index f06af64..0907051 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,4 +1,4 @@
-version=3
+version=4
opts=uversionmangle=s/(\d)[_\.\-\+]?alpha$/$1/,filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/sdl-kitchensink-$1\.tar\.gz/ \
https://github.com/katajakasa/SDL_kitchensink/tags .*/v?(\d\S+)\.tar\.gz
diff --git a/examples/example_audio.c b/examples/example_audio.c
index 20c8cdf..faa99c6 100644
--- a/examples/example_audio.c
+++ b/examples/example_audio.c
@@ -125,6 +125,16 @@ int main(int argc, char *argv[]) {
continue;
}
+ // Handle SDL events so that the application reacts to input.
+ SDL_Event event;
+ while(SDL_PollEvent(&event)) {
+ switch(event.type) {
+ case SDL_QUIT:
+ run = false;
+ break;
+ }
+ }
+
// Refresh audio
int queued = SDL_GetQueuedAudioSize(audio_dev);
if(queued < AUDIOBUFFER_SIZE) {
diff --git a/examples/example_complex.c b/examples/example_complex.c
index 779c879..ceb9caf 100644
--- a/examples/example_complex.c
+++ b/examples/example_complex.c
@@ -96,7 +96,7 @@ int main(int argc, char *argv[]) {
// Create an accelerated renderer. Enable vsync, so we don't need to play around with SDL_Delay.
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
- if(window == NULL) {
+ if(renderer == NULL) {
fprintf(stderr, "Unable to create a renderer!\n");
return 1;
}
@@ -108,8 +108,8 @@ int main(int argc, char *argv[]) {
return 1;
}
- // Allow Kit to use more threads
- Kit_SetHint(KIT_HINT_THREAD_COUNT, SDL_GetCPUCount() <= 4 ? SDL_GetCPUCount() : 4);
+ // Set to 0 to allow ffmpeg decide thread count.
+ Kit_SetHint(KIT_HINT_THREAD_COUNT, 0);
// Lots of buffers for smooth playback (will eat up more memory, too).
Kit_SetHint(KIT_HINT_VIDEO_BUFFER_FRAMES, 5);
@@ -183,6 +183,10 @@ int main(int argc, char *argv[]) {
pinfo.subtitle.codec.description,
pinfo.video.codec.threads);
}
+ int num, den;
+ if(Kit_GetPlayerAspectRatio(player, &num, &den) == 0) {
+ fprintf(stderr, "Aspect ratio: %d:%d\n", num, den);
+ }
fprintf(stderr, "Duration: %f seconds\n", Kit_GetPlayerDuration(player));
// Init audio
@@ -347,9 +351,14 @@ int main(int argc, char *argv[]) {
}
}
- // Refresh videotexture and render it
- Kit_GetPlayerVideoData(player, video_tex);
- SDL_RenderCopy(renderer, video_tex, NULL, NULL);
+ // Clear window first, in case of weirdly sized frames.
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+ SDL_RenderClear(renderer);
+
+ // Refresh the video texture and render it
+ SDL_Rect area;
+ Kit_GetPlayerVideoDataArea(player, video_tex, &area);
+ SDL_RenderCopy(renderer, video_tex, &area, NULL);
// Refresh subtitle texture atlas and render subtitle frames from it
// For subtitles, use screen size instead of video size for best quality
diff --git a/examples/example_custom.c b/examples/example_custom.c
index 8844b79..c02f7dc 100644
--- a/examples/example_custom.c
+++ b/examples/example_custom.c
@@ -56,7 +56,7 @@ int main(int argc, char *argv[]) {
// Create an accelerated renderer. Enable vsync, so we don't need to play around with SDL_Delay.
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
- if(window == NULL) {
+ if(renderer == NULL) {
fprintf(stderr, "Unable to create a renderer!\n");
return 1;
}
diff --git a/examples/example_rwops.c b/examples/example_rwops.c
index 96a3655..9aa6d96 100644
--- a/examples/example_rwops.c
+++ b/examples/example_rwops.c
@@ -48,7 +48,7 @@ int main(int argc, char *argv[]) {
// Create an accelerated renderer. Enable vsync, so we don't need to play around with SDL_Delay.
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
- if(window == NULL) {
+ if(renderer == NULL) {
fprintf(stderr, "Unable to create a renderer!\n");
return 1;
}
diff --git a/examples/example_simple.c b/examples/example_simple.c
index 234a83d..bce0751 100644
--- a/examples/example_simple.c
+++ b/examples/example_simple.c
@@ -47,7 +47,7 @@ int main(int argc, char *argv[]) {
// Create an accelerated renderer. Enable vsync, so we don't need to play around with SDL_Delay.
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
- if(window == NULL) {
+ if(renderer == NULL) {
fprintf(stderr, "Unable to create a renderer!\n");
return 1;
}
diff --git a/include/kitchensink/internal/audio/kitaudio.h b/include/kitchensink/internal/audio/kitaudio.h
index c3db420..0558343 100644
--- a/include/kitchensink/internal/audio/kitaudio.h
+++ b/include/kitchensink/internal/audio/kitaudio.h
@@ -7,6 +7,6 @@
KIT_LOCAL Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, int stream_index);
KIT_LOCAL int Kit_GetAudioDecoderData(Kit_Decoder *dec, unsigned char *buf, int len);
-KIT_LOCAL double Kit_GetAudioDecoderPTS(Kit_Decoder *dec);
+KIT_LOCAL double Kit_GetAudioDecoderPTS(const Kit_Decoder *dec);
#endif // KITAUDIO_H
diff --git a/include/kitchensink/internal/kitdecoder.h b/include/kitchensink/internal/kitdecoder.h
index 17e1e4b..deac1b7 100644
--- a/include/kitchensink/internal/kitdecoder.h
+++ b/include/kitchensink/internal/kitdecoder.h
@@ -25,10 +25,11 @@ typedef int (*dec_decode_cb)(Kit_Decoder *dec, AVPacket *in_packet);
typedef void (*dec_close_cb)(Kit_Decoder *dec);
typedef void (*dec_free_packet_cb)(void *packet);
-KIT_LOCAL struct Kit_Decoder {
+struct Kit_Decoder {
int stream_index; ///< Source stream index for the current stream
double clock_sync; ///< Sync source for current stream
double clock_pos; ///< Current pts for the stream
+ AVRational aspect_ratio; ///< Aspect ratio for the current frame (may change frome-to-frame)
Kit_OutputFormat output; ///< Output format for the decoder
AVCodecContext *codec_ctx; ///< FFMpeg internal: Codec context
@@ -55,25 +56,25 @@ KIT_LOCAL void Kit_SetDecoderClockSync(Kit_Decoder *dec, double sync);
KIT_LOCAL void Kit_ChangeDecoderClockSync(Kit_Decoder *dec, double sync);
KIT_LOCAL int Kit_RunDecoder(Kit_Decoder *dec);
-KIT_LOCAL void Kit_ClearDecoderBuffers(Kit_Decoder *dec);
-
-KIT_LOCAL bool Kit_CanWriteDecoderInput(Kit_Decoder *dec);
-KIT_LOCAL int Kit_WriteDecoderInput(Kit_Decoder *dec, AVPacket *packet);
-KIT_LOCAL AVPacket* Kit_ReadDecoderInput(Kit_Decoder *dec);
-KIT_LOCAL void Kit_ClearDecoderInput(Kit_Decoder *dec);
-KIT_LOCAL AVPacket* Kit_PeekDecoderInput(Kit_Decoder *dec);
-KIT_LOCAL void Kit_AdvanceDecoderInput(Kit_Decoder *dec);
-
-KIT_LOCAL int Kit_WriteDecoderOutput(Kit_Decoder *dec, void *packet);
-KIT_LOCAL bool Kit_CanWriteDecoderOutput(Kit_Decoder *dec);
-KIT_LOCAL void* Kit_PeekDecoderOutput(Kit_Decoder *dec);
-KIT_LOCAL void* Kit_ReadDecoderOutput(Kit_Decoder *dec);
-KIT_LOCAL void Kit_AdvanceDecoderOutput(Kit_Decoder *dec);
-KIT_LOCAL void Kit_ForEachDecoderOutput(Kit_Decoder *dec, Kit_ForEachItemCallback foreach_cb, void *userdata);
-KIT_LOCAL int Kit_LockDecoderOutput(Kit_Decoder *dec);
-KIT_LOCAL void Kit_UnlockDecoderOutput(Kit_Decoder *dec);
-KIT_LOCAL void Kit_ClearDecoderOutput(Kit_Decoder *dec);
-KIT_LOCAL unsigned int Kit_GetDecoderOutputLength(Kit_Decoder *dec);
-
+KIT_LOCAL void Kit_ClearDecoderBuffers(const Kit_Decoder *dec);
+
+KIT_LOCAL bool Kit_CanWriteDecoderInput(const Kit_Decoder *dec);
+KIT_LOCAL int Kit_WriteDecoderInput(const Kit_Decoder *dec, AVPacket *packet);
+KIT_LOCAL AVPacket* Kit_ReadDecoderInput(const Kit_Decoder *dec);
+KIT_LOCAL void Kit_ClearDecoderInput(const Kit_Decoder *dec);
+KIT_LOCAL AVPacket* Kit_PeekDecoderInput(const Kit_Decoder *dec);
+KIT_LOCAL void Kit_AdvanceDecoderInput(const Kit_Decoder *dec);
+
+KIT_LOCAL int Kit_WriteDecoderOutput(const Kit_Decoder *dec, void *packet);
+KIT_LOCAL bool Kit_CanWriteDecoderOutput(const Kit_Decoder *dec);
+KIT_LOCAL void* Kit_PeekDecoderOutput(const Kit_Decoder *dec);
+KIT_LOCAL void* Kit_ReadDecoderOutput(const Kit_Decoder *dec);
+KIT_LOCAL void Kit_ClearDecoderOutput(const Kit_Decoder *dec);
+KIT_LOCAL void Kit_AdvanceDecoderOutput(const Kit_Decoder *dec);
+KIT_LOCAL void Kit_ForEachDecoderOutput(const Kit_Decoder *dec, Kit_ForEachItemCallback foreach_cb, void *userdata);
+KIT_LOCAL unsigned int Kit_GetDecoderOutputLength(const Kit_Decoder *dec);
+
+KIT_LOCAL int Kit_LockDecoderOutput(const Kit_Decoder *dec);
+KIT_LOCAL void Kit_UnlockDecoderOutput(const Kit_Decoder *dec);
#endif // KITDECODER_H
diff --git a/include/kitchensink/internal/libass.h b/include/kitchensink/internal/libass.h
index 0f91d95..0b302d9 100644
--- a/include/kitchensink/internal/libass.h
+++ b/include/kitchensink/internal/libass.h
@@ -37,22 +37,22 @@ typedef enum {
ASS_HINTING_NATIVE
} ASS_Hinting;
-KIT_LOCAL ASS_Library* (*ass_library_init)(void);
-KIT_LOCAL void (*ass_library_done)(ASS_Library *priv);
-KIT_LOCAL void (*ass_process_codec_private)(ASS_Track *track, char *data, int size);
-KIT_LOCAL void (*ass_set_message_cb)(ASS_Library *priv, void (*msg_cb)(int level, const char *fmt, va_list args, void *data), void *data);
-KIT_LOCAL ASS_Renderer* (*ass_renderer_init)(ASS_Library *);
-KIT_LOCAL void (*ass_renderer_done)(ASS_Renderer *priv);
-KIT_LOCAL void (*ass_set_frame_size)(ASS_Renderer *priv, int w, int h);
-KIT_LOCAL void (*ass_set_hinting)(ASS_Renderer *priv, ASS_Hinting ht);
-KIT_LOCAL void (*ass_set_fonts)(ASS_Renderer *priv, const char *default_font, const char *default_family, int dfp, const char *config, int update);
-KIT_LOCAL ASS_Image* (*ass_render_frame)(ASS_Renderer *priv, ASS_Track *track, long long now, int *detect_change);
-KIT_LOCAL ASS_Track* (*ass_new_track)(ASS_Library *);
-KIT_LOCAL void (*ass_free_track)(ASS_Track *track);
-KIT_LOCAL void (*ass_process_data)(ASS_Track *track, char *data, int size);
-KIT_LOCAL void (*ass_process_chunk)(ASS_Track *track, char *data, int size, long long timecode, long long duration);
-KIT_LOCAL void (*ass_add_font)(ASS_Library *library, char *name, char *data, int data_size);
-KIT_LOCAL void (*ass_set_storage_size)(ASS_Renderer *priv, int w, int h);
+extern KIT_LOCAL ASS_Library* (*ass_library_init)(void);
+extern KIT_LOCAL void (*ass_library_done)(ASS_Library *priv);
+extern KIT_LOCAL void (*ass_process_codec_private)(ASS_Track *track, char *data, int size);
+extern KIT_LOCAL void (*ass_set_message_cb)(ASS_Library *priv, void (*msg_cb)(int level, const char *fmt, va_list args, void *data), void *data);
+extern KIT_LOCAL ASS_Renderer* (*ass_renderer_init)(ASS_Library *);
+extern KIT_LOCAL void (*ass_renderer_done)(ASS_Renderer *priv);
+extern KIT_LOCAL void (*ass_set_frame_size)(ASS_Renderer *priv, int w, int h);
+extern KIT_LOCAL void (*ass_set_hinting)(ASS_Renderer *priv, ASS_Hinting ht);
+extern KIT_LOCAL void (*ass_set_fonts)(ASS_Renderer *priv, const char *default_font, const char *default_family, int dfp, const char *config, int update);
+extern KIT_LOCAL ASS_Image* (*ass_render_frame)(ASS_Renderer *priv, ASS_Track *track, long long now, int *detect_change);
+extern KIT_LOCAL ASS_Track* (*ass_new_track)(ASS_Library *);
+extern KIT_LOCAL void (*ass_free_track)(ASS_Track *track);
+extern KIT_LOCAL void (*ass_process_data)(ASS_Track *track, char *data, int size);
+extern KIT_LOCAL void (*ass_process_chunk)(ASS_Track *track, char *data, int size, long long timecode, long long duration);
+extern KIT_LOCAL void (*ass_add_font)(ASS_Library *library, char *name, char *data, int data_size);
+extern KIT_LOCAL void (*ass_set_storage_size)(ASS_Renderer *priv, int w, int h);
KIT_LOCAL int load_libass(void *handle);
diff --git a/include/kitchensink/internal/subtitle/kitatlas.h b/include/kitchensink/internal/subtitle/kitatlas.h
index d9207c1..128e91e 100644
--- a/include/kitchensink/internal/subtitle/kitatlas.h
+++ b/include/kitchensink/internal/subtitle/kitatlas.h
@@ -8,8 +8,6 @@
#include "kitchensink/kitconfig.h"
typedef struct Kit_TextureAtlasItem {
- int cur_shelf; //< Current shelf number in cache
- int cur_slot; //< Current slot on shelf in cache
SDL_Rect source; //< Source coordinates on cache surface
SDL_Rect target; //< Target coordinates on output surface
} Kit_TextureAtlasItem;
@@ -35,6 +33,6 @@ KIT_LOCAL void Kit_FreeAtlas(Kit_TextureAtlas *atlas);
KIT_LOCAL void Kit_ClearAtlasContent(Kit_TextureAtlas *atlas);
KIT_LOCAL void Kit_CheckAtlasTextureSize(Kit_TextureAtlas *atlas, SDL_Texture *texture);
KIT_LOCAL int Kit_GetAtlasItems(const Kit_TextureAtlas *atlas, SDL_Rect *sources, SDL_Rect *targets, int limit);
-KIT_LOCAL int Kit_AddAtlasItem(Kit_TextureAtlas *atlas, SDL_Texture *texture, SDL_Surface *surface, const SDL_Rect *target);
+KIT_LOCAL int Kit_AddAtlasItem(Kit_TextureAtlas *atlas, SDL_Texture *texture, const SDL_Surface *surface, const SDL_Rect *target);
#endif // KITATLAS_H
diff --git a/include/kitchensink/internal/subtitle/kitsubtitle.h b/include/kitchensink/internal/subtitle/kitsubtitle.h
index 09aabec..09ce8ad 100644
--- a/include/kitchensink/internal/subtitle/kitsubtitle.h
+++ b/include/kitchensink/internal/subtitle/kitsubtitle.h
@@ -9,9 +9,9 @@
KIT_LOCAL Kit_Decoder* Kit_CreateSubtitleDecoder(
const Kit_Source *src, int stream_index, int video_w, int video_h, int screen_w, int screen_h);
-KIT_LOCAL void Kit_GetSubtitleDecoderTexture(Kit_Decoder *dec, SDL_Texture *texture, double sync_ts);
-KIT_LOCAL void Kit_SetSubtitleDecoderSize(Kit_Decoder *dec, int w, int h);
+KIT_LOCAL void Kit_GetSubtitleDecoderTexture(const Kit_Decoder *dec, SDL_Texture *texture, double sync_ts);
+KIT_LOCAL void Kit_SetSubtitleDecoderSize(const Kit_Decoder *dec, int w, int h);
KIT_LOCAL int Kit_GetSubtitleDecoderInfo(
- Kit_Decoder *dec, SDL_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit);
+ const Kit_Decoder *dec, const SDL_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit);
#endif // KITSUBTITLE_H
diff --git a/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
index 8b35c2b..767aedb 100644
--- a/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
+++ b/include/kitchensink/internal/subtitle/renderers/kitsubrenderer.h
@@ -4,10 +4,10 @@
#include <SDL_render.h>
#include "kitchensink/kitsource.h"
+#include "kitchensink/internal/subtitle/kitatlas.h"
+#include "kitchensink/internal/kitdecoder.h"
typedef struct Kit_SubtitleRenderer Kit_SubtitleRenderer;
-typedef struct Kit_TextureAtlas Kit_TextureAtlas;
-typedef struct Kit_Decoder Kit_Decoder;
typedef void (*ren_render_cb)(Kit_SubtitleRenderer *ren, void *src, double pts, double start, double end);
typedef int (*ren_get_data_cb)(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, SDL_Texture *texture, double current_pts);
diff --git a/include/kitchensink/internal/utils/kithelpers.h b/include/kitchensink/internal/utils/kithelpers.h
index 5b94a7a..e4c163c 100644
--- a/include/kitchensink/internal/utils/kithelpers.h
+++ b/include/kitchensink/internal/utils/kithelpers.h
@@ -6,6 +6,6 @@
#include "kitchensink/kitconfig.h"
KIT_LOCAL double _GetSystemTime();
-KIT_LOCAL bool attachment_is_font(AVStream *stream);
+KIT_LOCAL bool attachment_is_font(const AVStream *stream);
#endif // KITHELPERS_H
diff --git a/include/kitchensink/internal/video/kitvideo.h b/include/kitchensink/internal/video/kitvideo.h
index b393347..2c78c00 100644
--- a/include/kitchensink/internal/video/kitvideo.h
+++ b/include/kitchensink/internal/video/kitvideo.h
@@ -8,7 +8,7 @@
#include "kitchensink/internal/kitdecoder.h"
KIT_LOCAL Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, int stream_index);
-KIT_LOCAL int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture);
-KIT_LOCAL double Kit_GetVideoDecoderPTS(Kit_Decoder *dec);
+KIT_LOCAL int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture, SDL_Rect *area);
+KIT_LOCAL double Kit_GetVideoDecoderPTS(const Kit_Decoder *dec);
#endif // KITVIDEO_H
diff --git a/include/kitchensink/kitlib.h b/include/kitchensink/kitlib.h
index a5fe913..f562c5a 100644
--- a/include/kitchensink/kitlib.h
+++ b/include/kitchensink/kitlib.h
@@ -42,7 +42,7 @@ typedef struct Kit_Version {
*/
typedef enum Kit_HintType {
KIT_HINT_FONT_HINTING, ///< Set font hinting mode (currently used for libass)
- KIT_HINT_THREAD_COUNT, ///< Set thread count for ffmpeg (1 by default)
+ KIT_HINT_THREAD_COUNT, ///< Set thread count for ffmpeg (1 by default). Set to 0 for autodetect.
KIT_HINT_VIDEO_BUFFER_FRAMES, ///< Video output buffer frames (3 by default)
KIT_HINT_AUDIO_BUFFER_FRAMES, ///< Audio output buffers (64 by default)
KIT_HINT_SUBTITLE_BUFFER_FRAMES ///< Subtitle output buffers (64 by default, used by image subtitles)
@@ -90,7 +90,7 @@ KIT_API int Kit_Init(unsigned int flags);
KIT_API void Kit_Quit();
/**
- * @brief Sets a librarywide hint
+ * @brief Sets a library-wide hint
*
* This can be used to set hints on how the library should behave. See Kit_HintType
* for all the options.
diff --git a/include/kitchensink/kitplayer.h b/include/kitchensink/kitplayer.h
index 1c73020..a6121ce 100644
--- a/include/kitchensink/kitplayer.h
+++ b/include/kitchensink/kitplayer.h
@@ -63,7 +63,7 @@ typedef struct Kit_PlayerInfo {
/**
* @brief Creates a new player from a source.
*
- * Creates a new player from the given source. The source must be previously succesfully
+ * Creates a new player from the given source. The source must be previously successfully
* initialized by calling either Kit_CreateSourceFromUrl() or Kit_CreateSourceFromCustom(),
* and it must not be used by any other player. Source must stay valid during the whole
* playback (as in, don't close it while stuff is playing).
@@ -78,7 +78,7 @@ typedef struct Kit_PlayerInfo {
* or pick them automatically by using Kit_GetBestSourceStream().
*
* On success, this will return an initialized Kit_Player which can later be freed by Kit_ClosePlayer().
- * On error, NULL is returned and a more detailed error is availably via Kit_GetError().
+ * On error, NULL is returned and a more detailed error is available via Kit_GetError().
*
* For example:
* ```
@@ -166,23 +166,35 @@ KIT_API int Kit_GetPlayerSubtitleStream(const Kit_Player *player);
/**
* @brief Fetches a new video frame from the player
*
- * Note that the output texture must be previously allocated and valid.
- *
+ * This is the same as Kit_GetPlayerVideoDataArea() but without the area argument.
+ * Please refer to that function for description.
+ */
+KIT_API int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture);
+
+/**
+ * @brief Fetches a new video frame from the player
+ *
+ * Note that the output texture must be previously allocated and valid.
+ *
* It is important to select the correct texture format and size. If you pick a different
* texture format or size from what the decoder outputs, then the decoder will attempt to convert
* the frames to fit the texture. This will slow down the decoder a *lot* however, so if possible,
* pick the texture format from what Kit_GetPlayerInfo() outputs.
- *
+ *
* Access flag for the texture *MUST* always be SDL_TEXTUREACCESS_STATIC! Anything else will lead to
* undefined behaviour.
- *
+ *
+ * Area argument can be given to acquire the current video frame content area. Note that this may change
+ * if you have video that changes frame size on the fly.
+ *
* This function will do nothing if player playback has not been started.
- *
+ *
* @param player Player instance
* @param texture A previously allocated texture
+ * @param area Rendered video surface area
* @return 0 on success, 1 on error
*/
-KIT_API int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture);
+KIT_API int Kit_GetPlayerVideoDataArea(Kit_Player *player, SDL_Texture *texture, SDL_Rect *area);
/**
* @brief Fetches subtitle data from the player
@@ -192,7 +204,7 @@ KIT_API int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture);
* Note that the output texture must be previously allocated and valid. Make sure to have large
* enough a texture for the rendering resolution you picked! If your rendering resolution if 4k,
* then make sure to have texture sized 4096x4096 etc. This gives the texture room to handle the
- * worst case subtitle textures. If your resolutions is too small, this function will return
+ * worst case subtitle textures. If your resolution is too small, this function will return
* value -1. At that point you can replace your current texture with a bigger one on the fly.
*
* Note that the texture format for the atlas texture *MUST* be SDL_PIXELFORMAT_RGBA32 and
@@ -215,7 +227,7 @@ KIT_API int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture);
*
* @param player Player instance
* @param texture A previously allocated texture
- * @param sources List of source rectangles to copy fropm
+ * @param sources List of source rectangles to copy from
* @param targets List of target rectangles to render
* @param limit Defines the maximum size of your rectangle lists
* @return Number of sources or <0 on error
@@ -234,7 +246,7 @@ KIT_API int Kit_GetPlayerSubtitleData(Kit_Player *player,
* Outputted audio data will be precisely what is described by the output format struct given
* by Kit_GetPlayerInfo().
*
- * This function will attemt to read the maximum allowed amount of data allowed by the length
+ * This function will attempt to read the maximum allowed amount of data allowed by the length
* argument. It is possible however that there is not enough data available, at which point
* this function will read less and return value may differ from maximum allowed value.
* Return value 0 should be taken as a hint that there is nothing available.
@@ -336,6 +348,24 @@ KIT_API double Kit_GetPlayerDuration(const Kit_Player *player);
*/
KIT_API double Kit_GetPlayerPosition(const Kit_Player *player);
+/**
+ * @brief Get the player aspect ratio, if playing video.
+ *
+ * Sets numerator and denominator if it is possible to get a valid aspect ratio.
+ * If valid values were found, then 0 is returned. Otherwise 1 is returned, and num
+ * and den parameters are not changed.
+ *
+ * Aspect ratio may change during the playback of the video. This function will attempt
+ * to first get the aspect ratio of the current frame. If that is not set, then decoder
+ * and finally demuxer data will be tried.
+ *
+ * @param player Player instance
+ * @param num Numerator
+ * @param den Denominator
+ * @return 0 if got valid values, 1 otherwise.
+ */
+KIT_API int Kit_GetPlayerAspectRatio(const Kit_Player *player, int *num, int *den);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/kitchensink/kitsource.h b/include/kitchensink/kitsource.h
index c410be1..9d3b529 100644
--- a/include/kitchensink/kitsource.h
+++ b/include/kitchensink/kitsource.h
@@ -27,7 +27,7 @@ typedef enum Kit_StreamType {
KIT_STREAMTYPE_VIDEO, ///< Video stream
KIT_STREAMTYPE_AUDIO, ///< Audio stream
KIT_STREAMTYPE_DATA, ///< Data stream
- KIT_STREAMTYPE_SUBTITLE, ///< Subtitle streawm
+ KIT_STREAMTYPE_SUBTITLE, ///< Subtitle stream
KIT_STREAMTYPE_ATTACHMENT ///< Attachment stream (images, etc)
} Kit_StreamType;
@@ -73,7 +73,7 @@ typedef struct Kit_SourceStreamInfo {
typedef int (*Kit_ReadCallback)(void *userdata, uint8_t *buf, int size);
/**
- * @brief Callback function type for seeking data strema
+ * @brief Callback function type for seeking data stream
*
* Used by Kit_CreateSourceFromCustom() for seeking a user defined source.
*
diff --git a/src/internal/audio/kitaudio.c b/src/internal/audio/kitaudio.c
index b2f41fc..d79399e 100644
--- a/src/internal/audio/kitaudio.c
+++ b/src/internal/audio/kitaudio.c
@@ -10,10 +10,12 @@
#include "kitchensink/kiterror.h"
#include "kitchensink/internal/kitlibstate.h"
#include "kitchensink/internal/utils/kithelpers.h"
-#include "kitchensink/internal/utils/kitbuffer.h"
#include "kitchensink/internal/audio/kitaudio.h"
#include "kitchensink/internal/utils/kitringbuffer.h"
-#include "kitchensink/internal/utils/kitlog.h"
+
+#if LIBAVUTIL_VERSION_MAJOR < 58
+#define OLD_CHANNEL_LAYOUT
+#endif
#define KIT_AUDIO_SYNC_THRESHOLD 0.05
@@ -29,7 +31,7 @@ typedef struct Kit_AudioPacket {
} Kit_AudioPacket;
-Kit_AudioPacket* _CreateAudioPacket(const char* data, size_t len, double pts) {
+static Kit_AudioPacket* _CreateAudioPacket(const char* data, size_t len, double pts) {
Kit_AudioPacket *p = calloc(1, sizeof(Kit_AudioPacket));
p->rb = Kit_CreateRingBuffer(len);
Kit_WriteRingBuffer(p->rb, data, len);
@@ -37,7 +39,7 @@ Kit_AudioPacket* _CreateAudioPacket(const char* data, size_t len, double pts) {
return p;
}
-enum AVSampleFormat _FindAVSampleFormat(int format) {
+static enum AVSampleFormat _FindAVSampleFormat(int format) {
switch(format) {
case AUDIO_U8: return AV_SAMPLE_FMT_U8;
case AUDIO_S16SYS: return AV_SAMPLE_FMT_S16;
@@ -46,7 +48,8 @@ enum AVSampleFormat _FindAVSampleFormat(int format) {
}
}
-int64_t _FindAVChannelLayout(int channels) {
+#ifdef OLD_CHANNEL_LAYOUT
+static int64_t _FindAVChannelLayout(int channels) {
switch(channels) {
case 1: return AV_CH_LAYOUT_MONO;
case 2: return AV_CH_LAYOUT_STEREO;
@@ -54,15 +57,30 @@ int64_t _FindAVChannelLayout(int channels) {
}
}
-int _FindChannelLayout(uint64_t channel_layout) {
+static int _FindChannelLayout(uint64_t channel_layout) {
switch(channel_layout) {
case AV_CH_LAYOUT_MONO: return 1;
case AV_CH_LAYOUT_STEREO: return 2;
default: return 2;
}
}
+#else
+static void _FindAVChannelLayout(AVChannelLayout *layout, int channels) {
+ switch(channels) {
+ case 1: *layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
+ case 2: *layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
+ default: *layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO;
+ }
+}
-int _FindBytes(enum AVSampleFormat fmt) {
+static int _FindChannelLayout(const AVChannelLayout *channel_layout) {
+ if (channel_layout->nb_channels > 2)
+ return 2;
+ return channel_layout->nb_channels;
+}
+#endif
+
+static int _FindBytes(enum AVSampleFormat fmt) {
switch(fmt) {
case AV_SAMPLE_FMT_U8P:
case AV_SAMPLE_FMT_U8:
@@ -75,7 +93,7 @@ int _FindBytes(enum AVSampleFormat fmt) {
}
}
-int _FindSDLSampleFormat(enum AVSampleFormat fmt) {
+static int _FindSDLSampleFormat(enum AVSampleFormat fmt) {
switch(fmt) {
case AV_SAMPLE_FMT_U8P:
case AV_SAMPLE_FMT_U8:
@@ -88,7 +106,7 @@ int _FindSDLSampleFormat(enum AVSampleFormat fmt) {
}
}
-int _FindSignedness(enum AVSampleFormat fmt) {
+static int _FindSignedness(enum AVSampleFormat fmt) {
switch(fmt) {
case AV_SAMPLE_FMT_U8P:
case AV_SAMPLE_FMT_U8:
@@ -104,86 +122,8 @@ static void free_out_audio_packet_cb(void *packet) {
free(p);
}
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
-static int dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
- assert(dec != NULL);
-
- if(in_packet == NULL) {
- return 0;
- }
-
- Kit_AudioDecoder *audio_dec = dec->userdata;
- int frame_finished;
- int len;
- int len2;
- int dst_linesize;
- int dst_nb_samples;
- int dst_bufsize;
- double pts;
- unsigned char **dst_data;
- Kit_AudioPacket *out_packet = NULL;
-
- // Decode as long as there is data
- while(in_packet->size > 0) {
- len = avcodec_decode_audio4(dec->codec_ctx, audio_dec->scratch_frame, &frame_finished, in_packet);
- if(len < 0) {
- return 0;
- }
-
- if(frame_finished) {
- dst_nb_samples = av_rescale_rnd(
- audio_dec->scratch_frame->nb_samples,
- dec->output.samplerate, // Target samplerate
- dec->codec_ctx->sample_rate, // Source samplerate
- AV_ROUND_UP);
-
- av_samples_alloc_array_and_samples(
- &dst_data,
- &dst_linesize,
- dec->output.channels,
- dst_nb_samples,
- _FindAVSampleFormat(dec->output.format),
- 0);
-
- len2 = swr_convert(
- audio_dec->swr,
- dst_data,
- audio_dec->scratch_frame->nb_samples,
- (const unsigned char **)audio_dec->scratch_frame->extended_data,
- audio_dec->scratch_frame->nb_samples);
-
- dst_bufsize = av_samples_get_buffer_size(
- &dst_linesize,
- dec->output.channels,
- len2,
- _FindAVSampleFormat(dec->output.format), 1);
-
- // Get presentation timestamp
-#ifndef FF_API_FRAME_GET_SET
- pts = av_frame_get_best_effort_timestamp(audio_dec->scratch_frame);
-#else
- pts = audio_dec->scratch_frame->best_effort_timestamp;
-#endif
- pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
-
- // Lock, write to audio buffer, unlock
- out_packet = _CreateAudioPacket(
- (char*)dst_data[0], (size_t)dst_bufsize, pts);
- Kit_WriteDecoderOutput(dec, out_packet);
-
- // Free temps
- av_freep(&dst_data[0]);
- av_freep(&dst_data);
- }
-
- in_packet->size -= len;
- in_packet->data += len;
- }
- return 0;
-}
-#else
-static void dec_read_audio(Kit_Decoder *dec) {
- Kit_AudioDecoder *audio_dec = dec->userdata;
+static void dec_read_audio(const Kit_Decoder *dec) {
+ const Kit_AudioDecoder *audio_dec = dec->userdata;
int len;
int dst_linesize;
int dst_nb_samples;
@@ -245,7 +185,7 @@ static int dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(in_packet != NULL);
// Try to clear the buffer first. We might have too much content in the ffmpeg buffer,
- /// so we want to clear it of outgoing data if we can.
+ // so we want to clear it of outgoing data if we can.
dec_read_audio(dec);
// Write packet to the decoder for handling.
@@ -253,11 +193,10 @@ static int dec_decode_audio_cb(Kit_Decoder *dec, AVPacket *in_packet) {
return 1;
}
- // Some input data was put in succesfully, so try again to get frames.
+ // Some input data was put in successfully, so try again to get frames.
dec_read_audio(dec);
return 0;
}
-#endif
static void dec_close_audio_cb(Kit_Decoder *dec) {
if(dec == NULL) return;
@@ -278,7 +217,7 @@ Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, int stream_index) {
return NULL;
}
- Kit_LibraryState *state = Kit_GetLibraryState();
+ const Kit_LibraryState *state = Kit_GetLibraryState();
// First the generic decoder component ...
Kit_Decoder *dec = Kit_CreateDecoder(
@@ -288,32 +227,37 @@ Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, int stream_index) {
free_out_audio_packet_cb,
state->thread_count);
if(dec == NULL) {
- goto exit_0;
+ goto EXIT_0;
}
// ... then allocate the audio decoder
Kit_AudioDecoder *audio_dec = calloc(1, sizeof(Kit_AudioDecoder));
if(audio_dec == NULL) {
- goto exit_1;
+ goto EXIT_1;
}
// Create temporary audio frame
audio_dec->scratch_frame = av_frame_alloc();
if(audio_dec->scratch_frame == NULL) {
Kit_SetError("Unable to initialize temporary audio frame");
- goto exit_2;
+ goto EXIT_2;
}
// Set format configs
Kit_OutputFormat output;
memset(&output, 0, sizeof(Kit_OutputFormat));
output.samplerate = dec->codec_ctx->sample_rate;
+#ifdef OLD_CHANNEL_LAYOUT
output.channels = _FindChannelLayout(dec->codec_ctx->channel_layout);
+#else
+ output.channels = _FindChannelLayout(&dec->codec_ctx->ch_layout);
+#endif
output.bytes = _FindBytes(dec->codec_ctx->sample_fmt);
output.is_signed = _FindSignedness(dec->codec_ctx->sample_fmt);
output.format = _FindSDLSampleFormat(dec->codec_ctx->sample_fmt);
// Create resampler
+#ifdef OLD_CHANNEL_LAYOUT
audio_dec->swr = swr_alloc_set_opts(
NULL,
_FindAVChannelLayout(output.channels), // Target channel layout
@@ -323,10 +267,27 @@ Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, int stream_index) {
dec->codec_ctx->sample_fmt, // Source fmt
dec->codec_ctx->sample_rate, // Source samplerate
0, NULL);
+#else
+ AVChannelLayout layout;
+ _FindAVChannelLayout(&layout, output.channels);
+ int swr_ok = swr_alloc_set_opts2(
+ &audio_dec->swr,
+ &layout, // Target channel layout
+ _FindAVSampleFormat(output.format), // Target fmt
+ output.samplerate, // Target sample rate
+ &dec->codec_ctx->ch_layout, // Source channel layout
+ dec->codec_ctx->sample_fmt, // Source fmt
+ dec->codec_ctx->sample_rate, // Source sample rate
+ 0, NULL);
+ if (swr_ok != 0) {
+ Kit_SetError("Unable to initialize audio resampler context");
+ goto EXIT_3;
+ }
+#endif
if(swr_init(audio_dec->swr) != 0) {
Kit_SetError("Unable to initialize audio resampler context");
- goto exit_3;
+ goto EXIT_3;
}
// Set callbacks and userdata, and we're go
@@ -336,18 +297,18 @@ Kit_Decoder* Kit_CreateAudioDecoder(const Kit_Source *src, int stream_index) {
dec->output = output;
return dec;
-exit_3:
+EXIT_3:
av_frame_free(&audio_dec->scratch_frame);
-exit_2:
+EXIT_2:
free(audio_dec);
-exit_1:
+EXIT_1:
Kit_CloseDecoder(dec);
-exit_0:
+EXIT_0:
return NULL;
}
-double Kit_GetAudioDecoderPTS(Kit_Decoder *dec) {
- Kit_AudioPacket *packet = Kit_PeekDecoderOutput(dec);
+double Kit_GetAudioDecoderPTS(const Kit_Decoder *dec) {
+ const Kit_AudioPacket *packet = Kit_PeekDecoderOutput(dec);
if(packet == NULL) {
return -1.0;
}
@@ -397,7 +358,7 @@ int Kit_GetAudioDecoderData(Kit_Decoder *dec, unsigned char *buf, int len) {
dec->clock_pos = packet->pts;
// If ringbuffer is cleared, kill packet and advance buffer.
- // Otherwise forward the pts value for the current packet.
+ // Otherwise, forward the pts value for the current packet.
if(Kit_GetRingBufferLength(packet->rb) == 0) {
Kit_AdvanceDecoderOutput(dec);
free_out_audio_packet_cb(packet);
diff --git a/src/internal/kitdecoder.c b/src/internal/kitdecoder.c
index 9b925c7..c20bd86 100644
--- a/src/internal/kitdecoder.c
+++ b/src/internal/kitdecoder.c
@@ -17,11 +17,11 @@ Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
int thread_count) {
assert(src != NULL);
assert(out_b_size > 0);
- assert(thread_count > 0);
+ assert(thread_count >= 0);
AVCodecContext *codec_ctx = NULL;
AVDictionary *codec_opts = NULL;
- AVCodec *codec = NULL;
+ const AVCodec *codec = NULL;
AVFormatContext *format_ctx = src->format_ctx;
int bsizes[2] = {BUFFER_IN_SIZE, out_b_size};
dec_free_packet_cb free_hooks[2] = {free_in_video_packet_cb, free_out_cb};
@@ -29,63 +29,55 @@ Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
// Make sure index seems correct
if(stream_index >= (int)format_ctx->nb_streams || stream_index < 0) {
Kit_SetError("Invalid stream %d", stream_index);
- goto exit_0;
+ goto EXIT_0;
}
// Allocate decoder and make sure allocation was a success
Kit_Decoder *dec = calloc(1, sizeof(Kit_Decoder));
if(dec == NULL) {
Kit_SetError("Unable to allocate kit decoder for stream %d", stream_index);
- goto exit_0;
+ goto EXIT_0;
}
// Find audio decoder
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
- codec = avcodec_find_decoder(format_ctx->streams[stream_index]->codec->codec_id);
-#else
codec = avcodec_find_decoder(format_ctx->streams[stream_index]->codecpar->codec_id);
-#endif
if(codec == NULL) {
Kit_SetError("No suitable decoder found for stream %d", stream_index);
- goto exit_1;
+ goto EXIT_1;
}
// Allocate a context for the codec
codec_ctx = avcodec_alloc_context3(codec);
if(codec_ctx == NULL) {
Kit_SetError("Unable to allocate codec context for stream %d", stream_index);
- goto exit_1;
+ goto EXIT_1;
}
// Copy params
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
- if(avcodec_copy_context(codec_ctx, format_ctx->streams[stream_index]->codec) != 0)
-#else
- if(avcodec_parameters_to_context(codec_ctx, format_ctx->streams[stream_index]->codecpar) < 0)
-#endif
- {
+ if(avcodec_parameters_to_context(codec_ctx, format_ctx->streams[stream_index]->codecpar) < 0) {
Kit_SetError("Unable to copy codec context for stream %d", stream_index);
- goto exit_2;
+ goto EXIT_2;
}
- // Required by ffmpeg for now when using the new API.
-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
codec_ctx->pkt_timebase = format_ctx->streams[stream_index]->time_base;
-#endif
- // Set thread count
+ // Set threading, if possible
codec_ctx->thread_count = thread_count;
- codec_ctx->thread_type = FF_THREAD_SLICE|FF_THREAD_FRAME;
+ if(codec->capabilities | AV_CODEC_CAP_FRAME_THREADS) {
+ codec_ctx->thread_type = FF_THREAD_FRAME;
+ } else if(codec->capabilities | AV_CODEC_CAP_SLICE_THREADS) {
+ codec_ctx->thread_type = FF_THREAD_SLICE;
+ } else {
+ codec_ctx->thread_count = 1; // Disable threading
+ }
- // This is required for ass_process_chunk() support
-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 25, 100)
+ // This is required for ass_process_chunk()
av_dict_set(&codec_opts, "sub_text_format", "ass", 0);
-#endif
// Open the stream
if(avcodec_open2(codec_ctx, codec, &codec_opts) < 0) {
Kit_SetError("Unable to open codec for stream %d", stream_index);
- goto exit_2;
+ goto EXIT_2;
}
// Set index and codec
@@ -98,7 +90,7 @@ Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
dec->buffer[i] = Kit_CreateBuffer(bsizes[i], free_hooks[i]);
if(dec->buffer[i] == NULL) {
Kit_SetError("Unable to allocate buffer for stream %d: %s", stream_index, SDL_GetError());
- goto exit_3;
+ goto EXIT_3;
}
}
@@ -106,23 +98,23 @@ Kit_Decoder* Kit_CreateDecoder(const Kit_Source *src, int stream_index,
dec->output_lock = SDL_CreateMutex();
if(dec->output_lock == NULL) {
Kit_SetError("Unable to allocate mutex for stream %d: %s", stream_index, SDL_GetError());
- goto exit_3;
+ goto EXIT_3;
}
// That's that
return dec;
-exit_3:
+EXIT_3:
for(int i = 0; i < KIT_DEC_BUF_COUNT; i++) {
Kit_DestroyBuffer(dec->buffer[i]);
}
avcodec_close(codec_ctx);
-exit_2:
+EXIT_2:
av_dict_free(&codec_opts);
avcodec_free_context(&codec_ctx);
-exit_1:
+EXIT_1:
free(dec);
-exit_0:
+EXIT_0:
return NULL;
}
@@ -170,6 +162,13 @@ int Kit_RunDecoder(Kit_Decoder *dec) {
return 0;
}
+void Kit_ClearDecoderBuffers(const Kit_Decoder *dec) {
+ if(dec == NULL) return;
+ Kit_ClearDecoderInput(dec);
+ Kit_ClearDecoderOutput(dec);
+ avcodec_flush_buffers(dec->codec_ctx);
+}
+
// ---- Information API ----
int Kit_GetDecoderCodecInfo(const Kit_Decoder *dec, Kit_Codec *codec) {
@@ -214,38 +213,38 @@ void Kit_ChangeDecoderClockSync(Kit_Decoder *dec, double sync) {
// ---- Input buffer handling ----
-int Kit_WriteDecoderInput(Kit_Decoder *dec, AVPacket *packet) {
+int Kit_WriteDecoderInput(const Kit_Decoder *dec, AVPacket *packet) {
assert(dec != NULL);
return Kit_WriteBuffer(dec->buffer[KIT_DEC_BUF_IN], packet);
}
-bool Kit_CanWriteDecoderInput(Kit_Decoder *dec) {
+bool Kit_CanWriteDecoderInput(const Kit_Decoder *dec) {
assert(dec != NULL);
return !Kit_IsBufferFull(dec->buffer[KIT_DEC_BUF_IN]);
}
-AVPacket* Kit_ReadDecoderInput(Kit_Decoder *dec) {
+AVPacket* Kit_ReadDecoderInput(const Kit_Decoder *dec) {
assert(dec != NULL);
return Kit_ReadBuffer(dec->buffer[KIT_DEC_BUF_IN]);
}
-AVPacket* Kit_PeekDecoderInput(Kit_Decoder *dec) {
+AVPacket* Kit_PeekDecoderInput(const Kit_Decoder *dec) {
assert(dec != NULL);
return Kit_PeekBuffer(dec->buffer[KIT_DEC_BUF_IN]);
}
-void Kit_AdvanceDecoderInput(Kit_Decoder *dec) {
+void Kit_AdvanceDecoderInput(const Kit_Decoder *dec) {
assert(dec != NULL);
Kit_AdvanceBuffer(dec->buffer[KIT_DEC_BUF_IN]);
}
-void Kit_ClearDecoderInput(Kit_Decoder *dec) {
+void Kit_ClearDecoderInput(const Kit_Decoder *dec) {
Kit_ClearBuffer(dec->buffer[KIT_DEC_BUF_IN]);
}
// ---- Output buffer handling ----
-int Kit_WriteDecoderOutput(Kit_Decoder *dec, void *packet) {
+int Kit_WriteDecoderOutput(const Kit_Decoder *dec, void *packet) {
assert(dec != NULL);
int ret = 1;
if(SDL_LockMutex(dec->output_lock) == 0) {
@@ -255,14 +254,14 @@ int Kit_WriteDecoderOutput(Kit_Decoder *dec, void *packet) {
return ret;
}
-void Kit_ClearDecoderOutput(Kit_Decoder *dec) {
+void Kit_ClearDecoderOutput(const Kit_Decoder *dec) {
if(SDL_LockMutex(dec->output_lock) == 0) {
Kit_ClearBuffer(dec->buffer[KIT_DEC_BUF_OUT]);
SDL_UnlockMutex(dec->output_lock);
}
}
-void* Kit_PeekDecoderOutput(Kit_Decoder *dec) {
+void* Kit_PeekDecoderOutput(const Kit_Decoder *dec) {
assert(dec != NULL);
void *ret = NULL;
if(SDL_LockMutex(dec->output_lock) == 0) {
@@ -272,7 +271,7 @@ void* Kit_PeekDecoderOutput(Kit_Decoder *dec) {
return ret;
}
-void* Kit_ReadDecoderOutput(Kit_Decoder *dec) {
+void* Kit_ReadDecoderOutput(const Kit_Decoder *dec) {
assert(dec != NULL);
void *ret = NULL;
if(SDL_LockMutex(dec->output_lock) == 0) {
@@ -282,7 +281,7 @@ void* Kit_ReadDecoderOutput(Kit_Decoder *dec) {
return ret;
}
-bool Kit_CanWriteDecoderOutput(Kit_Decoder *dec) {
+bool Kit_CanWriteDecoderOutput(const Kit_Decoder *dec) {
assert(dec != NULL);
bool ret = false;
if(SDL_LockMutex(dec->output_lock) == 0) {
@@ -292,7 +291,7 @@ bool Kit_CanWriteDecoderOutput(Kit_Decoder *dec) {
return ret;
}
-void Kit_ForEachDecoderOutput(Kit_Decoder *dec, Kit_ForEachItemCallback cb, void *userdata) {
+void Kit_ForEachDecoderOutput(const Kit_Decoder *dec, Kit_ForEachItemCallback cb, void *userdata) {
assert(dec != NULL);
if(SDL_LockMutex(dec->output_lock) == 0) {
Kit_ForEachItemInBuffer(dec->buffer[KIT_DEC_BUF_OUT], cb, userdata);
@@ -300,7 +299,7 @@ void Kit_ForEachDecoderOutput(Kit_Decoder *dec, Kit_ForEachItemCallback cb, void
}
}
-void Kit_AdvanceDecoderOutput(Kit_Decoder *dec) {
+void Kit_AdvanceDecoderOutput(const Kit_Decoder *dec) {
assert(dec != NULL);
if(SDL_LockMutex(dec->output_lock) == 0) {
Kit_AdvanceBuffer(dec->buffer[KIT_DEC_BUF_OUT]);
@@ -308,7 +307,7 @@ void Kit_AdvanceDecoderOutput(Kit_Decoder *dec) {
}
}
-unsigned int Kit_GetDecoderOutputLength(Kit_Decoder *dec) {
+unsigned int Kit_GetDecoderOutputLength(const Kit_Decoder *dec) {
assert(dec != NULL);
unsigned int len = 0;
if(SDL_LockMutex(dec->output_lock) == 0) {
@@ -318,17 +317,10 @@ unsigned int Kit_GetDecoderOutputLength(Kit_Decoder *dec) {
return len;
}
-void Kit_ClearDecoderBuffers(Kit_Decoder *dec) {
- if(dec == NULL) return;
- Kit_ClearDecoderInput(dec);
- Kit_ClearDecoderOutput(dec);
- avcodec_flush_buffers(dec->codec_ctx);
-}
-
-int Kit_LockDecoderOutput(Kit_Decoder *dec) {
+int Kit_LockDecoderOutput(const Kit_Decoder *dec) {
return SDL_LockMutex(dec->output_lock);
}
-void Kit_UnlockDecoderOutput(Kit_Decoder *dec) {
+void Kit_UnlockDecoderOutput(const Kit_Decoder *dec) {
SDL_UnlockMutex(dec->output_lock);
}
diff --git a/src/internal/kitlibstate.c b/src/internal/kitlibstate.c
index 4482ee9..8b5aaa7 100644
--- a/src/internal/kitlibstate.c
+++ b/src/internal/kitlibstate.c
@@ -1,4 +1,4 @@
-#include <stdlib.h>
+#include <stddef.h>
#include "kitchensink/internal/kitlibstate.h"
static Kit_LibraryState _librarystate = {0, 1, 0, 3, 64, 64, NULL, NULL};
diff --git a/src/internal/libass.c b/src/internal/libass.c
index 4a43e86..df6de33 100644
--- a/src/internal/libass.c
+++ b/src/internal/libass.c
@@ -3,6 +3,25 @@
#include <SDL_loadso.h>
#include "kitchensink/internal/libass.h"
+
+ASS_Library* (*ass_library_init)(void);
+void (*ass_library_done)(ASS_Library *priv);
+void (*ass_process_codec_private)(ASS_Track *track, char *data, int size);
+void (*ass_set_message_cb)(ASS_Library *priv, void (*msg_cb)(int level, const char *fmt, va_list args, void *data), void *data);
+ASS_Renderer* (*ass_renderer_init)(ASS_Library *);
+void (*ass_renderer_done)(ASS_Renderer *priv);
+void (*ass_set_frame_size)(ASS_Renderer *priv, int w, int h);
+void (*ass_set_hinting)(ASS_Renderer *priv, ASS_Hinting ht);
+void (*ass_set_fonts)(ASS_Renderer *priv, const char *default_font, const char *default_family, int dfp, const char *config, int update);
+ASS_Image* (*ass_render_frame)(ASS_Renderer *priv, ASS_Track *track, long long now, int *detect_change);
+ASS_Track* (*ass_new_track)(ASS_Library *);
+void (*ass_free_track)(ASS_Track *track);
+void (*ass_process_data)(ASS_Track *track, char *data, int size);
+void (*ass_process_chunk)(ASS_Track *track, char *data, int size, long long timecode, long long duration);
+void (*ass_add_font)(ASS_Library *library, char *name, char *data, int data_size);
+void (*ass_set_storage_size)(ASS_Renderer *priv, int w, int h);
+
+
int load_libass(void *handle) {
ass_library_init = SDL_LoadFunction(handle, "ass_library_init");
ass_library_done = SDL_LoadFunction(handle, "ass_library_done");
diff --git a/src/internal/subtitle/kitatlas.c b/src/internal/subtitle/kitatlas.c
index e7bb654..704c879 100644
--- a/src/internal/subtitle/kitatlas.c
+++ b/src/internal/subtitle/kitatlas.c
@@ -1,9 +1,8 @@
#include <assert.h>
-#include "kitchensink/internal/subtitle/kitatlas.h"
-#include "kitchensink/internal/utils/kitlog.h"
-
-static int min(int a, int b) {
+#include "kitchensink/internal/subtitle/kitatlas.h"
+
+static int Kit_min(int a, int b) {
if(a < b)
return a;
return b;
@@ -13,7 +12,7 @@ static int min(int a, int b) {
Kit_TextureAtlas* Kit_CreateAtlas() {
Kit_TextureAtlas *atlas = calloc(1, sizeof(Kit_TextureAtlas));
if(atlas == NULL) {
- goto exit_0;
+ goto EXIT_0;
}
atlas->cur_items = 0;
atlas->max_items = 1024;
@@ -24,22 +23,22 @@ Kit_TextureAtlas* Kit_CreateAtlas() {
// Allocate items. These hold the surfaces that should be in atlas
atlas->items = calloc(atlas->max_items, sizeof(Kit_TextureAtlasItem));
if(atlas->items == NULL) {
- goto exit_1;
+ goto EXIT_1;
}
// Allocate shelves. These describe the used space of the atlas
atlas->shelves = calloc(atlas->max_shelves, sizeof(Kit_Shelf));
if(atlas->shelves == NULL) {
- goto exit_2;
+ goto EXIT_2;
}
return atlas;
-exit_2:
+EXIT_2:
free(atlas->items);
-exit_1:
+EXIT_1:
free(atlas);
-exit_0:
+EXIT_0:
return NULL;
}
@@ -56,18 +55,16 @@ void Kit_FreeAtlas(Kit_TextureAtlas *atlas) {
free(atlas);
}
-void Kit_SetItemAllocation(Kit_TextureAtlasItem *item, SDL_Surface *surface, int shelf, int slot, int x, int y) {
+void Kit_SetItemAllocation(Kit_TextureAtlasItem *item, const SDL_Surface *surface, int x, int y) {
assert(item != NULL);
- item->cur_shelf = shelf;
- item->cur_slot = slot;
item->source.x = x;
item->source.y = y;
item->source.w = surface->w;
item->source.h = surface->h;
}
-int Kit_FindFreeAtlasSlot(Kit_TextureAtlas *atlas, SDL_Surface *surface, Kit_TextureAtlasItem *item) {
+int Kit_FindFreeAtlasSlot(const Kit_TextureAtlas *atlas, const SDL_Surface *surface, Kit_TextureAtlasItem *item) {
assert(atlas != NULL);
assert(item != NULL);
@@ -75,13 +72,11 @@ int Kit_FindFreeAtlasSlot(Kit_TextureAtlas *atlas, SDL_Surface *surface, Kit_Tex
int shelf_h;
int total_remaining_h = atlas->h;
int total_reserved_h = 0;
-
- // First, try to look for a good, existing shelf
int best_shelf_idx = -1;
int best_shelf_h = atlas->h;
int best_shelf_y = 0;
- // Try to find a good shelf to put this item in
+ // Try to find a good, existing shelf to put this item in.
int shelf_idx;
for(shelf_idx = 0; shelf_idx < atlas->max_shelves; shelf_idx++) {
shelf_w = atlas->shelves[shelf_idx].width;
@@ -100,13 +95,11 @@ int Kit_FindFreeAtlasSlot(Kit_TextureAtlas *atlas, SDL_Surface *surface, Kit_Tex
}
}
- // If existing shelf found, put the item there. Otherwise create a new shelf.
+ // If existing shelf found, put the item there. Otherwise, create a new shelf.
if(best_shelf_idx != -1) {
Kit_SetItemAllocation(
item,
surface,
- best_shelf_idx,
- atlas->shelves[best_shelf_idx].count,
atlas->shelves[best_shelf_idx].width,
best_shelf_y);
atlas->shelves[best_shelf_idx].width += surface->w;
@@ -119,8 +112,6 @@ int Kit_FindFreeAtlasSlot(Kit_TextureAtlas *atlas, SDL_Surface *surface, Kit_Tex
Kit_SetItemAllocation(
item,
surface,
- shelf_idx,
- 0,
0,
total_reserved_h);
return 0;
@@ -145,10 +136,11 @@ void Kit_CheckAtlasTextureSize(Kit_TextureAtlas *atlas, SDL_Texture *texture) {
int Kit_GetAtlasItems(const Kit_TextureAtlas *atlas, SDL_Rect *sources, SDL_Rect *targets, int limit) {
assert(atlas != NULL);
assert(limit >= 0);
+ const Kit_TextureAtlasItem *item = NULL;
- int max_count = min(atlas->cur_items, limit);
+ int max_count = Kit_min(atlas->cur_items, limit);
for(int i = 0; i < max_count; i++) {
- Kit_TextureAtlasItem *item = &atlas->items[i];
+ item = &atlas->items[i];
if(sources != NULL)
memcpy(&sources[i], &item->source, sizeof(SDL_Rect));
if(targets != NULL)
@@ -157,7 +149,7 @@ int Kit_GetAtlasItems(const Kit_TextureAtlas *atlas, SDL_Rect *sources, SDL_Rect
return max_count;
}
-int Kit_AddAtlasItem(Kit_TextureAtlas *atlas, SDL_Texture *texture, SDL_Surface *surface, const SDL_Rect *target) {
+int Kit_AddAtlasItem(Kit_TextureAtlas *atlas, SDL_Texture *texture, const SDL_Surface *surface, const SDL_Rect *target) {
assert(atlas != NULL);
assert(surface != NULL);
assert(target != NULL);
@@ -170,8 +162,6 @@ int Kit_AddAtlasItem(Kit_TextureAtlas *atlas, SDL_Texture *texture, SDL_Surface
Kit_TextureAtlasItem item;
memset(&item, 0, sizeof(Kit_TextureAtlasItem));
memcpy(&item.target, target, sizeof(SDL_Rect));
- item.cur_shelf = -1;
- item.cur_slot = -1;
// Allocate space for the new item
if(Kit_FindFreeAtlasSlot(atlas, surface, &item) != 0) {
diff --git a/src/internal/subtitle/kitsubtitle.c b/src/internal/subtitle/kitsubtitle.c
index 024179e..0b84c81 100644
--- a/src/internal/subtitle/kitsubtitle.c
+++ b/src/internal/subtitle/kitsubtitle.c
@@ -3,11 +3,8 @@
#include <SDL.h>
#include <libavformat/avformat.h>
-#include "kitchensink/internal/utils/kitlog.h"
-
#include "kitchensink/kiterror.h"
#include "kitchensink/kitlib.h"
-#include "kitchensink/internal/utils/kitlog.h"
#include "kitchensink/internal/kitlibstate.h"
#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
#include "kitchensink/internal/subtitle/kitsubtitle.h"
@@ -15,7 +12,6 @@
#include "kitchensink/internal/subtitle/renderers/kitsubimage.h"
#include "kitchensink/internal/subtitle/renderers/kitsubass.h"
#include "kitchensink/internal/subtitle/renderers/kitsubrenderer.h"
-#include "kitchensink/internal/utils/kithelpers.h"
typedef struct Kit_SubtitleDecoder {
@@ -95,7 +91,7 @@ Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, int stream_index,
return NULL;
}
- Kit_LibraryState *state = Kit_GetLibraryState();
+ const Kit_LibraryState *state = Kit_GetLibraryState();
// First the generic decoder component
Kit_Decoder *dec = Kit_CreateDecoder(
@@ -106,14 +102,14 @@ Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, int stream_index,
state->thread_count);
if(dec == NULL) {
Kit_SetError("Unable to allocate subtitle decoder");
- goto exit_0;
+ goto EXIT_0;
}
// ... then allocate the subtitle decoder
Kit_SubtitleDecoder *subtitle_dec = calloc(1, sizeof(Kit_SubtitleDecoder));
if(subtitle_dec == NULL) {
Kit_SetError("Unable to allocate subtitle decoder");
- goto exit_1;
+ goto EXIT_1;
}
// Set format. Note that is_enabled may be changed below ...
@@ -144,14 +140,14 @@ Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, int stream_index,
break;
}
if(subtitle_dec->renderer == NULL) {
- goto exit_2;
+ goto EXIT_2;
}
// Allocate texture atlas for subtitle rectangles
subtitle_dec->atlas = Kit_CreateAtlas();
if(subtitle_dec->atlas == NULL) {
Kit_SetError("Unable to allocate subtitle texture atlas");
- goto exit_3;
+ goto EXIT_3;
}
// Set callbacks and userdata, and we're go
@@ -161,31 +157,31 @@ Kit_Decoder* Kit_CreateSubtitleDecoder(const Kit_Source *src, int stream_index,
dec->output = output;
return dec;
-exit_3:
+EXIT_3:
Kit_CloseSubtitleRenderer(subtitle_dec->renderer);
-exit_2:
+EXIT_2:
free(subtitle_dec);
-exit_1:
+EXIT_1:
Kit_CloseDecoder(dec);
-exit_0:
+EXIT_0:
return NULL;
}
-void Kit_SetSubtitleDecoderSize(Kit_Decoder *dec, int screen_w, int screen_h) {
+void Kit_SetSubtitleDecoderSize(const Kit_Decoder *dec, int screen_w, int screen_h) {
assert(dec != NULL);
- Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
+ const Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
Kit_SetSubtitleRendererSize(subtitle_dec->renderer, screen_w, screen_h);
}
-void Kit_GetSubtitleDecoderTexture(Kit_Decoder *dec, SDL_Texture *texture, double sync_ts) {
+void Kit_GetSubtitleDecoderTexture(const Kit_Decoder *dec, SDL_Texture *texture, double sync_ts) {
assert(dec != NULL);
assert(texture != NULL);
- Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
+ const Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
Kit_GetSubtitleRendererData(subtitle_dec->renderer, subtitle_dec->atlas, texture, sync_ts);
}
-int Kit_GetSubtitleDecoderInfo(Kit_Decoder *dec, SDL_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit) {
- Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
+int Kit_GetSubtitleDecoderInfo(const Kit_Decoder *dec, const SDL_Texture *texture, SDL_Rect *sources, SDL_Rect *targets, int limit) {
+ const Kit_SubtitleDecoder *subtitle_dec = dec->userdata;
return Kit_GetAtlasItems(subtitle_dec->atlas, sources, targets, limit);
}
diff --git a/src/internal/subtitle/kitsubtitlepacket.c b/src/internal/subtitle/kitsubtitlepacket.c
index f44eee6..1cca914 100644
--- a/src/internal/subtitle/kitsubtitlepacket.c
+++ b/src/internal/subtitle/kitsubtitlepacket.c
@@ -11,7 +11,7 @@ Kit_SubtitlePacket* Kit_CreateSubtitlePacket(
p->y = pos_y;
p->surface = surface;
if(p->surface != NULL) {
- p->surface->refcount++; // We dont want to needlessly copy; instead increase refcount.
+ p->surface->refcount++; // We don't want to needlessly copy; instead increase refcount.
}
p->clear = clear;
return p;
diff --git a/src/internal/subtitle/renderers/kitsubass.c b/src/internal/subtitle/renderers/kitsubass.c
index 7dfb31b..f3c8a40 100644
--- a/src/internal/subtitle/renderers/kitsubass.c
+++ b/src/internal/subtitle/renderers/kitsubass.c
@@ -2,12 +2,9 @@
#include <stdlib.h>
#include <SDL_surface.h>
-#include <libavcodec/version.h>
#include "kitchensink/kiterror.h"
-#include "kitchensink/internal/utils/kitlog.h"
#include "kitchensink/internal/kitlibstate.h"
-#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
#include "kitchensink/internal/subtitle/kitatlas.h"
#include "kitchensink/internal/utils/kithelpers.h"
#include "kitchensink/internal/subtitle/renderers/kitsubass.h"
@@ -17,12 +14,12 @@ typedef struct Kit_ASSSubtitleRenderer {
ASS_Track *track;
} Kit_ASSSubtitleRenderer;
-static void Kit_ProcessAssImage(SDL_Surface *surface, const ASS_Image *img) {
- unsigned char r = ((img->color) >> 24) & 0xFF;
- unsigned char g = ((img->color) >> 16) & 0xFF;
- unsigned char b = ((img->color) >> 8) & 0xFF;
- unsigned char a = 0xFF - ((img->color) & 0xFF);
- unsigned char *src = img->bitmap;
+static void Kit_ProcessAssImage(const SDL_Surface *surface, const ASS_Image *img) {
+ const unsigned char r = ((img->color) >> 24) & 0xFF;
+ const unsigned char g = ((img->color) >> 16) & 0xFF;
+ const unsigned char b = ((img->color) >> 8) & 0xFF;
+ const unsigned char a = 0xFF - ((img->color) & 0xFF);
+ const unsigned char *src = img->bitmap;
unsigned char *dst = surface->pixels;
unsigned int x;
unsigned int y;
@@ -45,8 +42,8 @@ static void ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double pts,
assert(ren != NULL);
assert(src != NULL);
- Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
- AVSubtitle *sub = src;
+ const Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
+ const AVSubtitle *sub = src;
// Read incoming subtitle packets to libASS
long long start_ms = (start + pts) * 1000;
@@ -55,12 +52,7 @@ static void ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double pts,
for(int r = 0; r < sub->num_rects; r++) {
if(sub->rects[r]->ass == NULL)
continue;
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57,25,100)
- ass_process_data(
- ass_ren->track,
- sub->rects[r]->ass,
- strlen(sub->rects[r]->ass));
-#else
+
// This requires the sub_text_format codec_opt set for ffmpeg
ass_process_chunk(
ass_ren->track,
@@ -68,7 +60,6 @@ static void ren_render_ass_cb(Kit_SubtitleRenderer *ren, void *src, double pts,
strlen(sub->rects[r]->ass),
start_ms,
end_ms);
-#endif
}
Kit_UnlockDecoderOutput(ren->dec);
}
@@ -84,9 +75,10 @@ static void ren_close_ass_cb(Kit_SubtitleRenderer *ren) {
}
static int ren_get_ass_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, SDL_Texture *texture, double current_pts) {
- Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
+ const Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
SDL_Surface *dst = NULL;
- ASS_Image *src = NULL;
+ int dst_w = 0, dst_h = 0;
+ const ASS_Image *src = NULL;
int change = 0;
long long now = current_pts * 1000;
@@ -106,7 +98,15 @@ static int ren_get_ass_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atla
for(; src; src = src->next) {
if(src->w == 0 || src->h == 0)
continue;
- dst = SDL_CreateRGBSurfaceWithFormat(0, src->w, src->h, 32, SDL_PIXELFORMAT_RGBA32);
+
+ // Don't recreate surface if we already have correctly sized one.
+ if(dst == NULL || dst_w != src->w || dst_h != src->h) {
+ dst_w = src->w;
+ dst_h = src->h;
+ SDL_FreeSurface(dst);
+ dst = SDL_CreateRGBSurfaceWithFormat(0, dst_w, dst_h, 32, SDL_PIXELFORMAT_RGBA32);
+ }
+
Kit_ProcessAssImage(dst, src);
SDL_Rect target;
target.x = src->dst_x;
@@ -114,18 +114,18 @@ static int ren_get_ass_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atla
target.w = dst->w;
target.h = dst->h;
Kit_AddAtlasItem(atlas, texture, dst, &target);
- SDL_FreeSurface(dst);
}
Kit_UnlockDecoderOutput(ren->dec);
}
+ SDL_FreeSurface(dst);
ren->dec->clock_pos = current_pts;
return 0;
}
static void ren_set_ass_size_cb(Kit_SubtitleRenderer *ren, int w, int h) {
- Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
+ const Kit_ASSSubtitleRenderer *ass_ren = ren->userdata;
ass_set_frame_size(ass_ren->renderer, w, h);
}
@@ -137,7 +137,7 @@ Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(Kit_Decoder *dec, int video_
assert(screen_h >= 0);
// Make sure that libass library has been initialized + get handle
- Kit_LibraryState *state = Kit_GetLibraryState();
+ const Kit_LibraryState *state = Kit_GetLibraryState();
if(state->libass_handle == NULL) {
Kit_SetError("Libass library has not been initialized");
return NULL;
@@ -146,31 +146,28 @@ Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(Kit_Decoder *dec, int video_
// First allocate the generic decoder component
Kit_SubtitleRenderer *ren = Kit_CreateSubtitleRenderer(dec);
if(ren == NULL) {
- goto exit_0;
+ goto EXIT_0;
}
// Next, allocate ASS subtitle renderer context.
Kit_ASSSubtitleRenderer *ass_ren = calloc(1, sizeof(Kit_ASSSubtitleRenderer));
if(ass_ren == NULL) {
Kit_SetError("Unable to allocate ass subtitle renderer");
- goto exit_1;
+ goto EXIT_1;
}
// Initialize libass renderer
ASS_Renderer *ass_renderer = ass_renderer_init(state->libass_handle);
if(ass_renderer == NULL) {
Kit_SetError("Unable to initialize libass renderer");
- goto exit_2;
+ goto EXIT_2;
}
// Read fonts from attachment streams and give them to libass
+ const AVStream *st = NULL;
for(int j = 0; j < dec->format_ctx->nb_streams; j++) {
- AVStream *st = dec->format_ctx->streams[j];
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
- AVCodecContext *codec = st->codec;
-#else
- AVCodecParameters *codec = st->codecpar;
-#endif
+ st = dec->format_ctx->streams[j];
+ const AVCodecParameters *codec = st->codecpar;
if(codec->codec_type == AVMEDIA_TYPE_ATTACHMENT && attachment_is_font(st)) {
const AVDictionaryEntry *tag = av_dict_get(
st->metadata,
@@ -201,7 +198,7 @@ Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(Kit_Decoder *dec, int video_
ASS_Track *ass_track = ass_new_track(state->libass_handle);
if(ass_track == NULL) {
Kit_SetError("Unable to initialize libass track");
- goto exit_3;
+ goto EXIT_3;
}
// Set up libass track headers (ffmpeg provides these)
@@ -222,12 +219,12 @@ Kit_SubtitleRenderer* Kit_CreateASSSubtitleRenderer(Kit_Decoder *dec, int video_
ren->userdata = ass_ren;
return ren;
-exit_3:
+EXIT_3:
ass_renderer_done(ass_renderer);
-exit_2:
+EXIT_2:
free(ass_ren);
-exit_1:
+EXIT_1:
Kit_CloseSubtitleRenderer(ren);
-exit_0:
+EXIT_0:
return NULL;
}
diff --git a/src/internal/subtitle/renderers/kitsubimage.c b/src/internal/subtitle/renderers/kitsubimage.c
index b9a8e48..df87b1a 100644
--- a/src/internal/subtitle/renderers/kitsubimage.c
+++ b/src/internal/subtitle/renderers/kitsubimage.c
@@ -4,7 +4,6 @@
#include <SDL_surface.h>
#include "kitchensink/kiterror.h"
-#include "kitchensink/internal/utils/kitlog.h"
#include "kitchensink/internal/subtitle/kitatlas.h"
#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
#include "kitchensink/internal/subtitle/renderers/kitsubimage.h"
@@ -21,7 +20,7 @@ static void ren_render_image_cb(Kit_SubtitleRenderer *ren, void *sub_src, double
assert(ren != NULL);
assert(sub_src != NULL);
- AVSubtitle *sub = sub_src;
+ const AVSubtitle *sub = sub_src;
SDL_Surface *dst = NULL;
SDL_Surface *src = NULL;
double start_pts = pts + start;
@@ -35,8 +34,9 @@ static void ren_render_image_cb(Kit_SubtitleRenderer *ren, void *sub_src, double
}
// Convert subtitle images from paletted to RGBA8888
+ const AVSubtitleRect *r = NULL;
for(int n = 0; n < sub->num_rects; n++) {
- AVSubtitleRect *r = sub->rects[n];
+ r = sub->rects[n];
if(r->type != SUBTITLE_BITMAP)
continue;
@@ -60,7 +60,7 @@ static void ren_render_image_cb(Kit_SubtitleRenderer *ren, void *sub_src, double
}
static int ren_get_img_data_cb(Kit_SubtitleRenderer *ren, Kit_TextureAtlas *atlas, SDL_Texture *texture, double current_pts) {
- Kit_ImageSubtitleRenderer *img_ren = ren->userdata;
+ const Kit_ImageSubtitleRenderer *img_ren = ren->userdata;
Kit_SubtitlePacket *packet = NULL;
Kit_CheckAtlasTextureSize(atlas, texture);
@@ -117,14 +117,14 @@ Kit_SubtitleRenderer* Kit_CreateImageSubtitleRenderer(Kit_Decoder *dec, int vide
// Allocate a new renderer
Kit_SubtitleRenderer *ren = Kit_CreateSubtitleRenderer(dec);
if(ren == NULL) {
- goto exit_0;
+ goto EXIT_0;
}
// Allocate image renderer internal context
Kit_ImageSubtitleRenderer *img_ren = calloc(1, sizeof(Kit_ImageSubtitleRenderer));
if(img_ren == NULL) {
Kit_SetError("Unable to allocate image subtitle renderer");
- goto exit_1;
+ goto EXIT_1;
}
// Only renderer required, no other data.
@@ -139,8 +139,8 @@ Kit_SubtitleRenderer* Kit_CreateImageSubtitleRenderer(Kit_Decoder *dec, int vide
ren->userdata = img_ren;
return ren;
-exit_1:
+EXIT_1:
Kit_CloseSubtitleRenderer(ren);
-exit_0:
+EXIT_0:
return NULL;
}
diff --git a/src/internal/subtitle/renderers/kitsubrenderer.c b/src/internal/subtitle/renderers/kitsubrenderer.c
index d41d61d..1509b4c 100644
--- a/src/internal/subtitle/renderers/kitsubrenderer.c
+++ b/src/internal/subtitle/renderers/kitsubrenderer.c
@@ -1,5 +1,4 @@
#include <stdlib.h>
-#include <assert.h>
#include "kitchensink/kiterror.h"
#include "kitchensink/internal/subtitle/kitsubtitlepacket.h"
diff --git a/src/internal/utils/kithelpers.c b/src/internal/utils/kithelpers.c
index c68f1c7..0108f1b 100644
--- a/src/internal/utils/kithelpers.c
+++ b/src/internal/utils/kithelpers.c
@@ -17,8 +17,8 @@ double _GetSystemTime() {
return (double)av_gettime() / 1000000.0;
}
-bool attachment_is_font(AVStream *stream) {
- AVDictionaryEntry *tag = av_dict_get(stream->metadata, "mimetype", NULL, AV_DICT_MATCH_CASE);
+bool attachment_is_font(const AVStream *stream) {
+ const AVDictionaryEntry *tag = av_dict_get(stream->metadata, "mimetype", NULL, AV_DICT_MATCH_CASE);
if(tag) {
for(int n = 0; font_mime[n]; n++) {
if(av_strcasecmp(font_mime[n], tag->value) == 0) {
diff --git a/src/internal/utils/kitringbuffer.c b/src/internal/utils/kitringbuffer.c
index e6fa136..3b4c91e 100644
--- a/src/internal/utils/kitringbuffer.c
+++ b/src/internal/utils/kitringbuffer.c
@@ -7,8 +7,6 @@
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-#include <assert.h>
#include "kitchensink/internal/utils/kitringbuffer.h"
diff --git a/src/internal/video/kitvideo.c b/src/internal/video/kitvideo.c
index 1f2bed9..2e53d58 100644
--- a/src/internal/video/kitvideo.c
+++ b/src/internal/video/kitvideo.c
@@ -8,9 +8,7 @@
#include "kitchensink/internal/kitlibstate.h"
#include "kitchensink/internal/kitdecoder.h"
#include "kitchensink/internal/utils/kithelpers.h"
-#include "kitchensink/internal/utils/kitbuffer.h"
#include "kitchensink/internal/video/kitvideo.h"
-#include "kitchensink/internal/utils/kitlog.h"
#define KIT_VIDEO_SYNC_THRESHOLD 0.02
@@ -86,6 +84,34 @@ static enum AVPixelFormat _FindAVPixelFormat(unsigned int fmt) {
}
}
+static struct SwsContext* _GetSwsContext(
+ struct SwsContext *old_context,
+ int src_w,
+ int src_h,
+ int dst_w,
+ int dst_h,
+ enum AVPixelFormat in_fmt,
+ enum AVPixelFormat out_fmt
+) {
+ struct SwsContext* new_context = sws_getCachedContext(
+ old_context,
+ src_w,
+ src_h,
+ in_fmt,
+ dst_w,
+ dst_h,
+ out_fmt,
+ SWS_BILINEAR,
+ NULL,
+ NULL,
+ NULL
+ );
+ if(new_context == NULL) {
+ Kit_SetError("Unable to initialize video converter context");
+ }
+ return new_context;
+}
+
static void free_out_video_packet_cb(void *packet) {
Kit_VideoPacket *p = packet;
av_freep(&p->frame->data[0]);
@@ -93,68 +119,7 @@ static void free_out_video_packet_cb(void *packet) {
free(p);
}
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
-static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
- assert(dec != NULL);
-
- if(in_packet == NULL) {
- return 0;
- }
-
- Kit_VideoDecoder *video_dec = dec->userdata;
- AVFrame *out_frame = NULL;
- Kit_VideoPacket *out_packet = NULL;
- int frame_finished;
- int len;
- double pts;
-
- while(in_packet->size > 0) {
- len = avcodec_decode_video2(dec->codec_ctx, video_dec->scratch_frame, &frame_finished, in_packet);
- if(len < 0) {
- return 0;
- }
-
- if(frame_finished) {
- // Target frame
- out_frame = av_frame_alloc();
- av_image_alloc(
- out_frame->data,
- out_frame->linesize,
- dec->codec_ctx->width,
- dec->codec_ctx->height,
- _FindAVPixelFormat(dec->output.format),
- 1);
-
- // Scale from source format to target format, don't touch the size
- sws_scale(
- video_dec->sws,
- (const unsigned char * const *)video_dec->scratch_frame->data,
- video_dec->scratch_frame->linesize,
- 0,
- dec->codec_ctx->height,
- out_frame->data,
- out_frame->linesize);
-
- // Get presentation timestamp
-#ifndef FF_API_FRAME_GET_SET
- pts = av_frame_get_best_effort_timestamp(video_dec->scratch_frame);
-#else
- pts = video_dec->scratch_frame->best_effort_timestamp;
-#endif
- pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
-
- // Lock, write to audio buffer, unlock
- out_packet = _CreateVideoPacket(out_frame, pts);
- Kit_WriteDecoderOutput(dec, out_packet);
- }
- in_packet->size -= len;
- in_packet->data += len;
- }
-
- return 0;
-}
-#else
-static void dec_read_video(Kit_Decoder *dec) {
+static void dec_read_video(const Kit_Decoder *dec) {
Kit_VideoDecoder *video_dec = dec->userdata;
AVFrame *out_frame = NULL;
Kit_VideoPacket *out_packet = NULL;
@@ -174,15 +139,28 @@ static void dec_read_video(Kit_Decoder *dec) {
1);
// Scale from source format to target format, don't touch the size
+ video_dec->sws = _GetSwsContext(
+ video_dec->sws,
+ video_dec->scratch_frame->width,
+ video_dec->scratch_frame->height,
+ video_dec->scratch_frame->width,
+ video_dec->scratch_frame->height,
+ dec->codec_ctx->pix_fmt,
+ _FindAVPixelFormat(dec->output.format));
sws_scale(
video_dec->sws,
(const unsigned char * const *)video_dec->scratch_frame->data,
video_dec->scratch_frame->linesize,
0,
- dec->codec_ctx->height,
+ video_dec->scratch_frame->height,
out_frame->data,
out_frame->linesize);
+ // Copy required props to safety
+ out_frame->width = video_dec->scratch_frame->width;
+ out_frame->height = video_dec->scratch_frame->height;
+ out_frame->sample_aspect_ratio = video_dec->scratch_frame->sample_aspect_ratio;
+
// Get presentation timestamp
pts = video_dec->scratch_frame->best_effort_timestamp;
pts *= av_q2d(dec->format_ctx->streams[dec->stream_index]->time_base);
@@ -199,7 +177,7 @@ static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
assert(in_packet != NULL);
// Try to clear the buffer first. We might have too much content in the ffmpeg buffer,
- /// so we want to clear it of outgoing data if we can.
+ // so we want to clear it of outgoing data if we can.
dec_read_video(dec);
// Write packet to the decoder for handling.
@@ -207,11 +185,10 @@ static int dec_decode_video_cb(Kit_Decoder *dec, AVPacket *in_packet) {
return 1;
}
- // Some input data was put in succesfully, so try again to get frames.
+ // Some input data was put in successfully, so try again to get frames.
dec_read_video(dec);
return 0;
}
-#endif
static void dec_close_video_cb(Kit_Decoder *dec) {
if(dec == NULL) return;
@@ -232,7 +209,7 @@ Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, int stream_index) {
return NULL;
}
- Kit_LibraryState *state = Kit_GetLibraryState();
+ const Kit_LibraryState *state = Kit_GetLibraryState();
// First the generic decoder component ...
Kit_Decoder *dec = Kit_CreateDecoder(
@@ -242,20 +219,20 @@ Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, int stream_index) {
free_out_video_packet_cb,
state->thread_count);
if(dec == NULL) {
- goto exit_0;
+ goto EXIT_0;
}
// ... then allocate the video decoder
Kit_VideoDecoder *video_dec = calloc(1, sizeof(Kit_VideoDecoder));
if(video_dec == NULL) {
- goto exit_1;
+ goto EXIT_1;
}
// Create temporary video frame
video_dec->scratch_frame = av_frame_alloc();
if(video_dec->scratch_frame == NULL) {
Kit_SetError("Unable to initialize temporary video frame");
- goto exit_2;
+ goto EXIT_2;
}
// Find best output format for us
@@ -270,18 +247,17 @@ Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, int stream_index) {
output.format = _FindSDLPixelFormat(output_format);
// Create scaler for handling format changes
- video_dec->sws = sws_getContext(
- dec->codec_ctx->width, // Source w
- dec->codec_ctx->height, // Source h
- dec->codec_ctx->pix_fmt, // Source fmt
- dec->codec_ctx->width, // Target w
- dec->codec_ctx->height, // Target h
- _FindAVPixelFormat(output.format), // Target fmt
- SWS_BILINEAR,
- NULL, NULL, NULL);
+ video_dec->sws = _GetSwsContext(
+ video_dec->sws,
+ dec->codec_ctx->width,
+ dec->codec_ctx->height,
+ dec->codec_ctx->width,
+ dec->codec_ctx->height,
+ dec->codec_ctx->pix_fmt,
+ _FindAVPixelFormat(output.format)
+ );
if(video_dec->sws == NULL) {
- Kit_SetError("Unable to initialize video converter context");
- goto exit_3;
+ goto EXIT_3;
}
// Set callbacks and userdata, and we're go
@@ -291,25 +267,25 @@ Kit_Decoder* Kit_CreateVideoDecoder(const Kit_Source *src, int stream_index) {
dec->output = output;
return dec;
-exit_3:
+EXIT_3:
av_frame_free(&video_dec->scratch_frame);
-exit_2:
+EXIT_2:
free(video_dec);
-exit_1:
+EXIT_1:
Kit_CloseDecoder(dec);
-exit_0:
+EXIT_0:
return NULL;
}
-double Kit_GetVideoDecoderPTS(Kit_Decoder *dec) {
- Kit_VideoPacket *packet = Kit_PeekDecoderOutput(dec);
+double Kit_GetVideoDecoderPTS(const Kit_Decoder *dec) {
+ const Kit_VideoPacket *packet = Kit_PeekDecoderOutput(dec);
if(packet == NULL) {
return -1.0;
}
return packet->pts;
}
-int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
+int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture, SDL_Rect *area) {
assert(dec != NULL);
assert(texture != NULL);
@@ -342,19 +318,23 @@ int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
}
// Update output texture with current video data.
- // Take formats into account.
+ // Note that frame size may change on the fly. Take that into account.
+ area->w = packet->frame->width;
+ area->h = packet->frame->height;
+ area->x = 0;
+ area->y = 0;
switch(dec->output.format) {
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
SDL_UpdateYUVTexture(
- texture, NULL,
+ texture, area,
packet->frame->data[0], packet->frame->linesize[0],
packet->frame->data[1], packet->frame->linesize[1],
packet->frame->data[2], packet->frame->linesize[2]);
break;
default:
SDL_UpdateTexture(
- texture, NULL,
+ texture, area,
packet->frame->data[0],
packet->frame->linesize[0]);
break;
@@ -363,6 +343,7 @@ int Kit_GetVideoDecoderData(Kit_Decoder *dec, SDL_Texture *texture) {
// Advance buffer, and free the decoded frame.
Kit_AdvanceDecoderOutput(dec);
dec->clock_pos = packet->pts;
+ dec->aspect_ratio = packet->frame->sample_aspect_ratio;
free_out_video_packet_cb(packet);
return 0;
diff --git a/src/kiterror.c b/src/kiterror.c
index 9ed0081..5731afa 100644
--- a/src/kiterror.c
+++ b/src/kiterror.c
@@ -1,4 +1,3 @@
-#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdbool.h>
@@ -23,7 +22,7 @@ void Kit_SetError(const char* fmt, ...) {
assert(fmt != NULL);
va_list args;
va_start(args, fmt);
- vsnprintf(_error_message, KIT_ERRBUFSIZE, (char*)fmt, args);
+ vsnprintf(_error_message, KIT_ERRBUFSIZE, fmt, args);
va_end(args);
_error_available = true;
}
diff --git a/src/kitlib.c b/src/kitlib.c
index e823c52..190e41f 100644
--- a/src/kitlib.c
+++ b/src/kitlib.c
@@ -1,16 +1,18 @@
#include <assert.h>
+#ifdef USE_DYNAMIC_LIBASS
#include <SDL_loadso.h>
+#endif
#include <libavformat/avformat.h>
+#include "libavcodec/avcodec.h"
-#include "kitchensink/internal/utils/kitlog.h"
#include "kitchensink/kitchensink.h"
#include "kitchensink/internal/kitlibstate.h"
static void _libass_msg_callback(int level, const char *fmt, va_list va, void *data) {}
-static int max(int a, int b) { return a > b ? a : b; }
-static int min(int a, int b) { return a < b ? a : b; }
+static int Kit_max(int a, int b) { return a > b ? a : b; }
+static int Kit_min(int a, int b) { return a < b ? a : b; }
int Kit_InitASS(Kit_LibraryState *state) {
#ifdef USE_DYNAMIC_LIBASS
@@ -45,7 +47,7 @@ int Kit_Init(unsigned int flags) {
if(state->init_flags != 0) {
Kit_SetError("SDL_kitchensink is already initialized");
- goto exit_0;
+ goto EXIT_0;
}
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 9, 100)
@@ -58,17 +60,17 @@ int Kit_Init(unsigned int flags) {
if(flags & KIT_INIT_ASS) {
if(Kit_InitASS(state) != 0) {
Kit_SetError("Failed to initialize libass");
- goto exit_1;
+ goto EXIT_1;
}
}
state->init_flags = flags;
return 0;
-exit_1:
+EXIT_1:
avformat_network_deinit();
-exit_0:
+EXIT_0:
return 1;
}
@@ -88,25 +90,25 @@ void Kit_SetHint(Kit_HintType type, int value) {
Kit_LibraryState *state = Kit_GetLibraryState();
switch(type) {
case KIT_HINT_THREAD_COUNT:
- state->thread_count = max(value, 1);
+ state->thread_count = Kit_max(value, 0);
break;
case KIT_HINT_FONT_HINTING:
- state->font_hinting = max(min(value, KIT_FONT_HINTING_COUNT), 0);
+ state->font_hinting = Kit_max(Kit_min(value, KIT_FONT_HINTING_COUNT), 0);
break;
case KIT_HINT_VIDEO_BUFFER_FRAMES:
- state->video_buf_frames = max(value, 1);
+ state->video_buf_frames = Kit_max(value, 1);
break;
case KIT_HINT_AUDIO_BUFFER_FRAMES:
- state->audio_buf_frames = max(value, 1);
+ state->audio_buf_frames = Kit_max(value, 1);
break;
case KIT_HINT_SUBTITLE_BUFFER_FRAMES:
- state->subtitle_buf_frames = max(value, 1);
+ state->subtitle_buf_frames = Kit_max(value, 1);
break;
}
}
int Kit_GetHint(Kit_HintType type) {
- Kit_LibraryState *state = Kit_GetLibraryState();
+ const Kit_LibraryState *state = Kit_GetLibraryState();
switch(type) {
case KIT_HINT_THREAD_COUNT:
return state->thread_count;
diff --git a/src/kitplayer.c b/src/kitplayer.c
index 2135a65..68f5de3 100644
--- a/src/kitplayer.c
+++ b/src/kitplayer.c
@@ -9,7 +9,6 @@
#include "kitchensink/internal/audio/kitaudio.h"
#include "kitchensink/internal/subtitle/kitsubtitle.h"
#include "kitchensink/internal/utils/kithelpers.h"
-#include "kitchensink/internal/utils/kitlog.h"
enum DecoderIndex {
KIT_VIDEO_DEC = 0,
@@ -24,12 +23,13 @@ enum DecoderIndex {
static int _DemuxStream(const Kit_Player *player) {
assert(player != NULL);
AVFormatContext *format_ctx = player->src->format_ctx;
+ const Kit_Decoder *dec = NULL;
// If any buffer is full, just stop here for now.
// Since we don't know what kind of data is going to come out of av_read_frame, we really
// want to make sure we are prepared for everything :)
for(int i = 0; i < KIT_DEC_COUNT; i++) {
- Kit_Decoder *dec = player->decoders[i];
+ dec = player->decoders[i];
if(dec == NULL)
continue;
if(!Kit_CanWriteDecoderInput(dec))
@@ -45,7 +45,7 @@ static int _DemuxStream(const Kit_Player *player) {
// Check if this is a packet we need to handle and pass it on
for(int i = 0; i < KIT_DEC_COUNT; i++) {
- Kit_Decoder *dec = player->decoders[i];
+ dec = player->decoders[i];
if(dec == NULL)
continue;
if(dec->stream_index == packet->stream_index) {
@@ -61,8 +61,9 @@ static int _DemuxStream(const Kit_Player *player) {
}
static bool _IsOutputEmpty(const Kit_Player *player) {
+ const Kit_Decoder *dec = NULL;
for(int i = 0; i < KIT_DEC_COUNT; i++) {
- Kit_Decoder *dec = player->decoders[i];
+ dec = player->decoders[i];
if(dec == NULL)
continue;
if(Kit_PeekDecoderOutput(dec))
@@ -71,9 +72,10 @@ static bool _IsOutputEmpty(const Kit_Player *player) {
return true;
}
-static int _RunDecoder(Kit_Player *player) {
+static int _RunDecoder(const Kit_Player *player) {
int got;
bool has_room = true;
+ const Kit_Decoder *dec = NULL;
do {
while((got = _DemuxStream(player)) == -1);
@@ -88,7 +90,7 @@ static int _RunDecoder(Kit_Player *player) {
// If there is no room in any decoder input, just stop here since it likely means that
// at least some decoder output is full.
for(int i = 0; i < KIT_DEC_COUNT; i++) {
- Kit_Decoder *dec = player->decoders[i];
+ dec = player->decoders[i];
if(dec == NULL)
continue;
if(!Kit_CanWriteDecoderInput(dec) || got == 1) {
@@ -101,42 +103,38 @@ static int _RunDecoder(Kit_Player *player) {
return 0;
}
+static void _TryWork(Kit_Player *player) {
+ /**
+ * \brief Run the decoders and demuxer as long as there is work. Returns when playback stops.
+ */
+ while(player->state == KIT_PLAYING || player->state == KIT_PAUSED) {
+ // Grab the decoder lock, and run demuxer & decoders for a bit.
+ if(SDL_LockMutex(player->dec_lock) == 0) {
+ if(_RunDecoder(player) == 1) {
+ player->state = KIT_STOPPED;
+ }
+ SDL_UnlockMutex(player->dec_lock);
+ }
+
+ // Delay to make sure this thread does not hog all cpu
+ SDL_Delay(2);
+ }
+}
+
static int _DecoderThread(void *ptr) {
+ /**
+ * \brief Decoder thread main, which runs as long as the player exists.
+ */
Kit_Player *player = ptr;
- bool is_running = true;
- bool is_playing = true;
- while(is_running) {
+ while(true) {
if(player->state == KIT_CLOSED) {
- is_running = false;
- continue;
- }
- if(player->state == KIT_PLAYING) {
- is_playing = true;
- }
- while(is_running && is_playing) {
- // Grab the decoder lock, and run demuxer & decoders for a bit.
- if(SDL_LockMutex(player->dec_lock) == 0) {
- if(player->state == KIT_CLOSED) {
- is_running = false;
- goto end_block;
- }
- if(player->state == KIT_STOPPED) {
- is_playing = false;
- goto end_block;
- }
- if(_RunDecoder(player) == 1) {
- player->state = KIT_STOPPED;
- goto end_block;
- }
-
-end_block:
- SDL_UnlockMutex(player->dec_lock);
- }
-
- // Delay to make sure this thread does not hog all cpu
- SDL_Delay(2);
+ break;
}
+
+ // This will block as long as there is something to demux/decode
+ // Returns when playback stops.
+ _TryWork(player);
// Just idle while waiting for work.
SDL_Delay(25);
@@ -157,25 +155,25 @@ Kit_Player* Kit_CreatePlayer(const Kit_Source *src,
if(video_stream_index < 0 && subtitle_stream_index >= 0) {
Kit_SetError("Subtitle stream selected without video stream");
- goto exit_0;
+ goto EXIT_0;
}
Kit_Player *player = calloc(1, sizeof(Kit_Player));
if(player == NULL) {
Kit_SetError("Unable to allocate player");
- goto exit_0;
+ goto EXIT_0;
}
// Initialize audio decoder
player->decoders[KIT_AUDIO_DEC] = Kit_CreateAudioDecoder(src, audio_stream_index);
if(player->decoders[KIT_AUDIO_DEC] == NULL && audio_stream_index >= 0) {
- goto exit_1;
+ goto EXIT_1;
}
// Initialize video decoder
player->decoders[KIT_VIDEO_DEC] = Kit_CreateVideoDecoder(src, video_stream_index);
if(player->decoders[KIT_VIDEO_DEC] == NULL && video_stream_index >= 0) {
- goto exit_2;
+ goto EXIT_2;
}
// Initialize subtitle decoder.
@@ -184,35 +182,35 @@ Kit_Player* Kit_CreatePlayer(const Kit_Source *src,
player->decoders[KIT_SUBTITLE_DEC] = Kit_CreateSubtitleDecoder(
src, subtitle_stream_index, output.width, output.height, screen_w, screen_h);
if(player->decoders[KIT_SUBTITLE_DEC] == NULL && subtitle_stream_index >= 0) {
- goto exit_2;
+ goto EXIT_2;
}
// Decoder thread lock
player->dec_lock = SDL_CreateMutex();
if(player->dec_lock == NULL) {
Kit_SetError("Unable to create a decoder thread lock mutex: %s", SDL_GetError());
- goto exit_2;
+ goto EXIT_2;
}
// Decoder thread
player->dec_thread = SDL_CreateThread(_DecoderThread, "Kit Decoder Thread", player);
if(player->dec_thread == NULL) {
Kit_SetError("Unable to create a decoder thread: %s", SDL_GetError());
- goto exit_3;
+ goto EXIT_3;
}
player->src = src;
return player;
-exit_3:
+EXIT_3:
SDL_DestroyMutex(player->dec_lock);
-exit_2:
+EXIT_2:
for(int i = 0; i < KIT_DEC_COUNT; i++) {
Kit_CloseDecoder(player->decoders[i]);
}
-exit_1:
+EXIT_1:
free(player);
-exit_0:
+EXIT_0:
return NULL;
}
@@ -238,7 +236,7 @@ void Kit_ClosePlayer(Kit_Player *player) {
void Kit_SetPlayerScreenSize(Kit_Player *player, int w, int h) {
assert(player != NULL);
- Kit_Decoder *dec = player->decoders[KIT_SUBTITLE_DEC];
+ const Kit_Decoder *dec = player->decoders[KIT_SUBTITLE_DEC];
if(dec == NULL)
return;
Kit_SetSubtitleDecoderSize(dec, w, h);
@@ -259,7 +257,7 @@ int Kit_GetPlayerSubtitleStream(const Kit_Player *player) {
return Kit_GetDecoderStreamIndex(player->decoders[KIT_SUBTITLE_DEC]);
}
-int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture) {
+int Kit_GetPlayerVideoDataArea(Kit_Player *player, SDL_Texture *texture, SDL_Rect *area) {
assert(player != NULL);
Kit_Decoder *dec = player->decoders[KIT_VIDEO_DEC];
@@ -275,7 +273,13 @@ int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture) {
return 0;
}
- return Kit_GetVideoDecoderData(dec, texture);
+ return Kit_GetVideoDecoderData(dec, texture, area);
+}
+
+int Kit_GetPlayerVideoData(Kit_Player *player, SDL_Texture *texture) {
+ assert(player != NULL);
+ SDL_Rect area;
+ return Kit_GetPlayerVideoDataArea(player, texture, &area);
}
int Kit_GetPlayerAudioData(Kit_Player *player, unsigned char *buffer, int length) {
@@ -310,8 +314,8 @@ int Kit_GetPlayerSubtitleData(Kit_Player *player, SDL_Texture *texture, SDL_Rect
assert(targets != NULL);
assert(limit >= 0);
- Kit_Decoder *sub_dec = player->decoders[KIT_SUBTITLE_DEC];
- Kit_Decoder *video_dec = player->decoders[KIT_VIDEO_DEC];
+ const Kit_Decoder *sub_dec = player->decoders[KIT_SUBTITLE_DEC];
+ const Kit_Decoder *video_dec = player->decoders[KIT_VIDEO_DEC];
if(sub_dec == NULL || video_dec == NULL) {
return 0;
}
@@ -334,24 +338,24 @@ int Kit_GetPlayerSubtitleData(Kit_Player *player, SDL_Texture *texture, SDL_Rect
void Kit_GetPlayerInfo(const Kit_Player *player, Kit_PlayerInfo *info) {
assert(player != NULL);
assert(info != NULL);
+ const Kit_Decoder *dec = NULL;
+ Kit_PlayerStreamInfo *streams[] = {&info->video, &info->audio, &info->subtitle};
- void *streams[] = {&info->video, &info->audio, &info->subtitle};
for(int i = 0; i < KIT_DEC_COUNT; i++) {
- Kit_Decoder *dec = player->decoders[i];
- Kit_PlayerStreamInfo *stream = streams[i];
- Kit_GetDecoderCodecInfo(dec, &stream->codec);
- Kit_GetDecoderOutputFormat(dec, &stream->output);
+ dec = player->decoders[i];
+ Kit_GetDecoderCodecInfo(dec, &streams[i]->codec);
+ Kit_GetDecoderOutputFormat(dec, &streams[i]->output);
}
}
-static void _SetClockSync(Kit_Player *player) {
+static void _SetClockSync(const Kit_Player *player) {
double sync = _GetSystemTime();
for(int i = 0; i < KIT_DEC_COUNT; i++) {
Kit_SetDecoderClockSync(player->decoders[i], sync);
}
}
-static void _ChangeClockSync(Kit_Player *player, double delta) {
+static void _ChangeClockSync(const Kit_Player *player, double delta) {
for(int i = 0; i < KIT_DEC_COUNT; i++) {
Kit_ChangeDecoderClockSync(player->decoders[i], delta);
}
@@ -476,7 +480,7 @@ int Kit_PlayerSeek(Kit_Player *player, double seek_set) {
double Kit_GetPlayerDuration(const Kit_Player *player) {
assert(player != NULL);
- AVFormatContext *fmt_ctx = player->src->format_ctx;
+ const AVFormatContext *fmt_ctx = player->src->format_ctx;
return (fmt_ctx->duration / AV_TIME_BASE);
}
@@ -491,3 +495,43 @@ double Kit_GetPlayerPosition(const Kit_Player *player) {
}
return 0;
}
+
+#define IS_RATIONAL_DEFINED(rational) (rational.num > 0 && rational.den > 0)
+
+int Kit_GetPlayerAspectRatio(const Kit_Player *player, int *num, int *den) {
+ assert(player != NULL);
+ const Kit_Decoder *decoder = player->decoders[KIT_VIDEO_DEC];
+ if(!decoder) {
+ Kit_SetError("Unable to find aspect ratio; no video stream selected");
+ return 1;
+ }
+
+ // First off, try to get the aspect ratio of the currently showing frame.
+ // This may change frame-to-frame.
+ if(IS_RATIONAL_DEFINED(decoder->aspect_ratio)) {
+ *num = decoder->aspect_ratio.num;
+ *den = decoder->aspect_ratio.den;
+ return 0;
+ }
+
+ // Then, try to find aspect ratio from the decoder itself
+ const AVCodecContext *codec_ctx = decoder->codec_ctx;
+ if(IS_RATIONAL_DEFINED(codec_ctx->sample_aspect_ratio)) {
+ *num = codec_ctx->sample_aspect_ratio.num;
+ *den = codec_ctx->sample_aspect_ratio.den;
+ return 0;
+ }
+
+ // Then, try the stream (demuxer) data
+ const AVFormatContext *fmt_ctx = player->src->format_ctx;
+ const AVStream *stream = fmt_ctx->streams[decoder->stream_index];
+ if(IS_RATIONAL_DEFINED(stream->sample_aspect_ratio)) {
+ *num = stream->sample_aspect_ratio.num;
+ *den = stream->sample_aspect_ratio.den;
+ return 0;
+ }
+
+ // No data found anywhere, give up.
+ Kit_SetError("Unable to find aspect ratio; no data from demuxer or codec");
+ return 1;
+}
diff --git a/src/kitsource.c b/src/kitsource.c
index 1a3bb00..622987e 100644
--- a/src/kitsource.c
+++ b/src/kitsource.c
@@ -1,8 +1,6 @@
#include <stdlib.h>
-#include <string.h>
#include <assert.h>
-#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
@@ -34,19 +32,19 @@ Kit_Source* Kit_CreateSourceFromUrl(const char *url) {
// Attempt to open source
if(avformat_open_input((AVFormatContext **)&src->format_ctx, url, NULL, NULL) < 0) {
Kit_SetError("Unable to open source Url");
- goto exit_0;
+ goto EXIT_0;
}
// Scan source information (may seek forwards)
if(_ScanSource(src->format_ctx)) {
- goto exit_1;
+ goto EXIT_1;
}
return src;
-exit_1:
+EXIT_1:
avformat_close_input((AVFormatContext **)&src->format_ctx);
-exit_0:
+EXIT_0:
free(src);
return NULL;
}
@@ -63,20 +61,20 @@ Kit_Source* Kit_CreateSourceFromCustom(Kit_ReadCallback read_cb, Kit_SeekCallbac
uint8_t *avio_buf = av_malloc(AVIO_BUF_SIZE);
if(avio_buf == NULL) {
Kit_SetError("Unable to allocate avio buffer");
- goto exit_0;
+ goto EXIT_0;
}
AVFormatContext *format_ctx = avformat_alloc_context();
if(format_ctx == NULL) {
Kit_SetError("Unable to allocate format context");
- goto exit_1;
+ goto EXIT_1;
}
AVIOContext *avio_ctx = avio_alloc_context(
avio_buf, AVIO_BUF_SIZE, 0, userdata, read_cb, 0, seek_cb);
if(avio_ctx == NULL) {
Kit_SetError("Unable to allocate avio context");
- goto exit_2;
+ goto EXIT_2;
}
// Set the format as AVIO format
@@ -85,12 +83,12 @@ Kit_Source* Kit_CreateSourceFromCustom(Kit_ReadCallback read_cb, Kit_SeekCallbac
// Attempt to open source
if(avformat_open_input(&format_ctx, "", NULL, NULL) < 0) {
Kit_SetError("Unable to open custom source");
- goto exit_3;
+ goto EXIT_3;
}
// Scan source information (may seek forwards)
if(_ScanSource(format_ctx)) {
- goto exit_4;
+ goto EXIT_4;
}
// Set internals
@@ -98,21 +96,22 @@ Kit_Source* Kit_CreateSourceFromCustom(Kit_ReadCallback read_cb, Kit_SeekCallbac
src->avio_ctx = avio_ctx;
return src;
-exit_4:
+EXIT_4:
avformat_close_input(&format_ctx);
-exit_3:
+EXIT_3:
av_freep(&avio_ctx);
-exit_2:
+EXIT_2:
avformat_free_context(format_ctx);
-exit_1:
+EXIT_1:
av_freep(&avio_buf);
-exit_0:
+EXIT_0:
free(src);
return NULL;
}
static int _RWReadCallback(void *userdata, uint8_t *buf, int size) {
- return SDL_RWread((SDL_RWops*)userdata, buf, 1, size);
+ size_t bytes_read = SDL_RWread((SDL_RWops*)userdata, buf, 1, size);
+ return bytes_read == 0 ? AVERROR_EOF : bytes_read;
}
static int64_t _RWGetSize(SDL_RWops *rw_ops) {
@@ -170,19 +169,14 @@ int Kit_GetSourceStreamInfo(const Kit_Source *src, Kit_SourceStreamInfo *info, i
assert(src != NULL);
assert(info != NULL);
- AVFormatContext *format_ctx = (AVFormatContext *)src->format_ctx;
+ const AVFormatContext *format_ctx = (AVFormatContext *)src->format_ctx;
if(index < 0 || index >= format_ctx->nb_streams) {
Kit_SetError("Invalid stream index");
return 1;
}
- AVStream *stream = format_ctx->streams[index];
- enum AVMediaType codec_type;
-#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
- codec_type = stream->codec->codec_type;
-#else
- codec_type = stream->codecpar->codec_type;
-#endif
+ const AVStream *stream = format_ctx->streams[index];
+ enum AVMediaType codec_type = stream->codecpar->codec_type;
switch(codec_type) {
case AVMEDIA_TYPE_UNKNOWN: info->type = KIT_STREAMTYPE_UNKNOWN; break;
case AVMEDIA_TYPE_DATA: info->type = KIT_STREAMTYPE_DATA; break;