Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 170 additions & 0 deletions .github/workflows/cmake-multi-platform.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform.
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
name: CMake on multiple platforms

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
build:
runs-on: ${{ matrix.os }}
permissions:
id-token: write
contents: read
attestations: write
strategy:
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable.
fail-fast: false

# Set up a matrix to run the following 3 configurations:
# 1. <Windows, Release, latest MSVC compiler toolchain on the default runner image, default generator>
# 2. <Linux, Release, latest GCC compiler toolchain on the default runner image, default generator>
# 3. <Linux, Release, latest Clang compiler toolchain on the default runner image, default generator>
#
# To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list.
matrix:
os: [ubuntu-26.04, windows-latest]
build_type: [Release]
c_compiler: [gcc, clang, cl]
ffmpeg_from_vcpkg: [ON, OFF]
ffmpeg_from_pkgconfig: [ON, OFF]
include:
- os: windows-latest
c_compiler: cl
cpp_compiler: cl
use_pthreads: ON
- os: ubuntu-26.04
c_compiler: gcc
cpp_compiler: g++
use_pthreads: OFF
- os: ubuntu-26.04
c_compiler: clang
cpp_compiler: clang++
use_pthreads: OFF
exclude:
- os: windows-latest
c_compiler: gcc
- os: windows-latest
c_compiler: clang
- os: ubuntu-26.04
c_compiler: cl
- ffmpeg_from_vcpkg: ON
ffmpeg_from_pkgconfig: ON
- ffmpeg_from_vcpkg: OFF
ffmpeg_from_pkgconfig: OFF
os: ubuntu-26.04
# VCPKG is fucking broken on this pos github runner.
- ffmpeg_from_vcpkg: ON
- os: windows-latest
ffmpeg_from_pkgconfig: ON

steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Set reusable strings
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
id: strings
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
echo "vcpkg-toolchain=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" >> "$GITHUB_OUTPUT"

- name: Install prereqs on linux
if: ${{ contains(matrix.os, 'ubuntu') }}
id: install
run: >
sudo apt-get update

sudo apt-get install libavutil-dev libavcodec-dev
libswresample-dev libavformat-dev nasm libasound2-dev libx11-dev libxrandr-dev
libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxinerama-dev
libxkbcommon-dev autoconf autoconf-archive automake libtool

# git clone https://github.com/microsoft/vcpkg.git
#
# cd vcpkg
#
# echo "vcpkg-toolchain=$(pwd)/scripts/buildsystems/vcpkg.cmake" >> "$GITHUB_OUTPUT"
#
# ./bootstrap-vcpkg.sh
# - name: Install ffmpeg binaries on windows
# if: ${{ contains(matrix.os, 'windows') }}
# id: ffmp
# shell: powershell
# run: |
# Invoke-WebRequest -Uri https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full-shared.7z -OutFile ffmpeg-shared.7z
# & 7z x .\ffmpeg-shared.7z -y
# (Get-ChildItem -Directory | Where-Object {$_.Name -like "*ffmpeg*"} | Select-Object -First 1 | ForEach-Object { "ffmp-dir=$($_.Name)" }) >> $GITHUB_OUTPUT

# - name: Update vcpkg root
# shell: bash
# run: |
# cd $VCPKG_INSTALLATION_ROOT
# git reset --hard
# git pull
# cd -

- name: download ffmpeg from github
uses: robinraju/release-downloader@v1
if: ${{ contains(matrix.os, 'windows') }}
id: ffmp
with:
repository: 'GyanD/codexffmpeg'
tag: '9.0.1'
fileName: 'ffmpeg-9.0.1-full_build-shared.zip'
extract: true

- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: >
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_TOOLCHAIN_FILE=${{ steps.strings.outputs.vcpkg-toolchain }}
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
${{ case ( contains(matrix.os, 'windows'), '-DFFMPEG_DIR="./ffmpeg-9.0.1-full_build-shared"', '') }}
-DUSE_FFMPEG_FROM_VCPKG=${{ matrix.ffmpeg_from_vcpkg }}
-DUSE_FFMPEG_FROM_PKGCONFIG=${{ matrix.ffmpeg_from_pkgconfig }}
-DUSE_PTHREADS4W=${{ matrix.use_pthreads }}
-DVCPKG_TARGET_TRIPLET=${{ case( matrix.os == 'ubuntu-26.04', 'x64-linux',
matrix.os == 'windows-latest', 'x64-windows-static-md-release',
'' ) }}
-S ${{ github.workspace }}

- name: Build
# Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
run: |
cmake --build ${{ steps.strings.outputs.build-output-dir }} --config Release

- name: Generate attestation
if: ${{ contains(matrix.os, 'windows') }}
uses: actions/attest@v4
with:
subject-path: ${{ steps.strings.outputs.build-output-dir }}\Release\player.exe

- name: move files into publish folder
if: ${{ contains(matrix.os, 'windows') }}
shell: bash
run: |
mkdir publish
mv "${{ steps.strings.outputs.build-output-dir }}"/Release/*.exe publish/
mv ffmpeg-9.0.1-full_build-shared/bin/{avcodec-63,avformat-63,avutil-61,swresample-7}.dll publish/

- name: Upload windows build
if: ${{ contains(matrix.os, 'windows') }}
uses: actions/upload-artifact@v7
with:
name: avrays
path: publish/

# - name: Test
# working-directory: ${{ steps.strings.outputs.build-output-dir }}
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
# run: ctest --build-config ${{ matrix.build_type }}
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
*.mkv
*.webm
*.mp4
.vs
player*
build/
/build*/
vcpkg_installed/
CMakeFiles/
build_tests/
CMakeUserPresets.json
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "vendor/raygui"]
path = vendor/raygui
url = git@github.com:raysan5/raygui.git
[submodule "vendor/raylib"]
path = vendor/raylib
url = git@github.com:raysan5/raylib.git
89 changes: 80 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,85 @@
cmake_minimum_required(VERSION 4.4)
# 4.3 is what VS ships with now, we use it as a baseline
# (but will probably work with lower versions, too)
cmake_minimum_required(VERSION 4.2)

# The options logic has to be made before project(...)
# since that's when vcpkg install runs.
option(USE_FFMPEG_FROM_VCPKG "Install ffmpeg from vcpkg" ON)
option(USE_FFMPEG_FROM_PKGCONFIG "Use ffmpeg installed on the system" OFF)
option(LIBRARY_ONLY "Don't build player exe" OFF)
if("${USE_FFMPEG_FROM_VCPKG}")
list(APPEND VCPKG_MANIFEST_FEATURES "ffmpeg")
endif()
if (MSVC)
option(USE_PTHREADS4W "Use pthreads4w lib" ON)
else()
option(USE_PTHREADS4W "Use pthreads4w lib" OFF)
endif()

set(CACHE{RAYLIB_DIR} HELP "raylib base directory to use" TYPE PATH VALUE "./vendor/raylib")
set(CACHE{FFMPEG_DIR} HELP "base directory of libav pre-compiled files" TYPE PATH VALUE "")
message(STATUS "Raylib dir is set to ${RAYLIB_DIR}")
message(STATUS "FFMPEG base dir is set to ${FFMPEG_DIR}")

if(USE_PTHREADS4W)
message(STATUS "Activating pthreads4w")
list(APPEND VCPKG_MANIFEST_FEATURES "pthreads")
endif()

project(avrays)
cmake_pkg_config(IMPORT libavcodec REQUIRED)
cmake_pkg_config(IMPORT libavutil REQUIRED)
cmake_pkg_config(IMPORT libavformat REQUIRED)
cmake_pkg_config(IMPORT libswresample REQUIRED)

# We want a release build of Raylib no matter what.
set(OLD_BUILD_TYPE "${CMAKE_BUILD_TYPE}")
set(CMAKE_BUILD_TYPE Release)
add_subdirectory("${RAYLIB_DIR}")
set(CMAKE_BUILD_TYPE "${OLD_BUILD_TYPE}")

# Pthreads4w is only for microsoft's compiler, mingw has its own implementation of
# pthreads calls.
if(USE_PTHREADS4W)
find_package(PThreads4W REQUIRED)
endif()

# Now try to find FFMPEG library.
if("${USE_FFMPEG_FROM_VCPKG}")
find_package(FFMPEG REQUIRED)
elseif("${USE_FFMPEG_FROM_PKGCONFIG}")
message(STATUS "Using ffmpeg from pkgconfig")
cmake_pkg_config(IMPORT libavcodec REQUIRED)
cmake_pkg_config(IMPORT libavutil REQUIRED)
cmake_pkg_config(IMPORT libavformat REQUIRED)
cmake_pkg_config(IMPORT libswresample REQUIRED)
list(APPEND FFMPEG_LIBRARIES PkgConfig::libavcodec PkgConfig::libavutil PkgConfig::libavformat PkgConfig::libswresample)
elseif(FFMPEG_DIR)
if(NOT EXISTS "${FFMPEG_DIR}/include/libavcodec/avcodec.h")
message(FATAL_ERROR "ffmpeg's directory doesn't seem to have necessary files")
endif()
list(APPEND FFMPEG_INCLUDE_DIRS "${FFMPEG_DIR}/include")
list(APPEND FFMPEG_LIBRARY_DIRS "${FFMPEG_DIR}/lib")
list(APPEND FFMPEG_LIBRARIES "${FFMPEG_DIR}/lib/avcodec.lib" "${FFMPEG_DIR}/lib/avutil.lib" "${FFMPEG_DIR}/lib/avformat.lib" "${FFMPEG_DIR}/lib/swresample.lib")
else()
message(FATAL_ERROR "ffmpeg's libav libraries are required to build this.
Set USE_FFMPEG_FROM_PKGCONFIG or USE_FFMPEG_FROM_VCPKG variable to ON, or provide FFMPEG_DIR.")
endif()

add_library(avrays STATIC)
target_sources(avrays PUBLIC avlib.h PRIVATE avlib.c)
target_link_libraries(avrays PRIVATE PkgConfig::libavcodec PkgConfig::libavutil PkgConfig::libavformat PkgConfig::libswresample)
target_include_directories(avrays PRIVATE ${FFMPEG_INCLUDE_DIRS})
target_link_directories(avrays PRIVATE ${FFMPEG_LIBRARY_DIRS})
target_link_libraries(avrays PRIVATE raylib ${FFMPEG_LIBRARIES})
if(USE_PTHREADS4W)
target_link_libraries(avrays PRIVATE PThreads4W::PThreads4W)
endif()

add_executable(player)
target_sources(player PRIVATE main.c)
target_link_libraries(player PRIVATE avrays raylib m X11)
if(NOT LIBRARY_ONLY)
add_executable(player)
target_sources(player PRIVATE main.c)
if(MSVC)
target_sources(player PRIVATE winstuff.c)
endif()
target_include_directories(player PRIVATE ${FFMPEG_INCLUDE_DIRS})
target_link_libraries(player PRIVATE avrays raylib)
if(USE_PTHREADS4W)
target_link_libraries(player PRIVATE PThreads4W::PThreads4W)
endif()
endif()
13 changes: 13 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": 2,
"configurePresets": [
{
"name": "vcpkg",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
}
]
}
72 changes: 71 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ If you don't wish to use stb_avray.h, then you will need the following files: `a
- make_stb is a bash script that generates stb_avray.h file.
- stb_avray.h is a single header version of the library. You can include it instead of the avlib.c/avlib.h/utils.h combo.

## Where do I get ffmpeg/libav from?

On linux, look for packages named `ffmpeg`, `libav*-dev` or similar. Run `pkg-config --list-package-names | grep -E 'lib(av|sw)'` to see which of the libav* libraries you have installed. At the minimum, you need libavcodec, libavutil, libavformat and libswresample to compile avray.

On windows, you can download and use precompiled binaries gyan [gyan](https://www.gyan.dev/ffmpeg/builds/) or [BtbN](https://github.com/BtbN/FFmpeg-Builds/releases). Make sure that what you downloaded actually contains dev files(headers and `*.lib`s) and not just executables for ffmpeg and friends.

As an alternative, you can download and compile these libraries with vcpkg. If you go with this route, make sure you have enough space on your hard drive (10 Gb at the very least)

## How to pause, or note about how video/audio sync works

AVRay assumes that the audio stream will be continously pulled in raylib's audio stream callback function, and calculates current timestamps/syncs video playback based on that. This has a couple of consequences:
Expand Down Expand Up @@ -51,6 +59,66 @@ The player has the following controls:
- Double click switches borderless fullscreen mode on/off
- `Esc` closes the window, as is tradition in raylib.

### CMake presets and options

cmake builds can be configured with the following options:

```bash
-DUSE_FFMPEG_FROM_VCPKG=ON # uses vcpkg to download and build libav libraries, default ON
-DUSE_FFMPEG_FROM_PKGCONFIG=OFF # uses pkgconfig to find libav on your system
-LIBRARY_ONLY=OFF # build only the library .a .lib
```

It's recommended to create `CMakeUserPresets.json` file to store build configurations.

It could look like this

```json
{
"version": 2,
"configurePresets": [
{
"name": "linux",
"inherits": "vcpkg",
"cacheVariables": {
"VCPKG_TARGET_TRIPLET": "x64-linux",
"USE_FFMPEG_FROM_VCPKG": "OFF",
"USE_FFMPEG_FROM_PKGCONFIG": "ON"
}
},
{
"name": "windows",
"inherits": "vcpkg",
"binaryDir": "${sourceDir}/build_win",
"cacheVariables": {
"VCPKG_TARGET_TRIPLET": "x64-windows-static-md-release",
"USE_FFMPEG_FROM_VCPKG": "OFF",
"CMAKE_BUILD_TYPE": <Release or Debug>,
"FFMPEG_DIR": <ffmpeg folder with headers and precompiled libraries>,
"USE_PTHREADS4W": "ON"
}
}
],
"buildPresets": [
{
"name": "windows",
"configurePreset": "windows"
},
{
"name": "linux",
"configurePreset": "linux"
}
]
}
```

With `CMakeUserPresets.json` file the configure and compile steps can be as easy as:

```bash
cmake --preset=windows
cmake --build --preset=windows
```

## Minimal example

A minimal program that uses AVRay could look something like this(see main_minimal.c):
Expand Down Expand Up @@ -85,7 +153,7 @@ int main(int argc, char **argv) {
DecoderState state = ctx.state;
// Exit when the playback is finished
if (state == DS_FINISHED) {
break;
break;
}
// Update textures checks the current timestamp(driven by the audio stream)
// and updates the textures if it's time to show the next video frame.
Expand Down Expand Up @@ -208,3 +276,5 @@ static void thread_create(ThreadType *t, void *(*thread_proc)(void *),
static void thread_join(ThreadType *t) { pthread_join(*t, NULL); }
static void thread_sleep_ms(unsigned int ms) { usleep(ms * 1000); }
```

See also open issues on the github's issue tracker.
Loading
Loading