mirror of
https://github.com/outbackdingo/UltraGrid.git
synced 2026-03-22 08:40:28 +00:00
Merge branch 'master' into vr-devel
This commit is contained in:
18
.github/scripts/Linux/arm/bootstrap.sh
vendored
18
.github/scripts/Linux/arm/bootstrap.sh
vendored
@@ -5,21 +5,21 @@
|
||||
ARCH=$1
|
||||
BUILD_DIR=$2
|
||||
|
||||
sudo chroot $BUILD_DIR /bin/sh -c 'if grep -q Raspbian /etc/os-release; then sed -i s-http://deb.debian.org/debian-http://mirrordirector.raspbian.org/raspbian/- /etc/apt/sources.list && apt-get -y update; fi' # https://bugs.launchpad.net/ubuntu/+source/qemu/+bug/1670905 workaround
|
||||
sudo chroot $BUILD_DIR /bin/sh -c 'apt-get -y install build-essential git pkg-config autoconf automake libtool'
|
||||
sudo chroot $BUILD_DIR /bin/sh -c 'apt-get -y install portaudio19-dev libsdl2-dev libglib2.0-dev libglew-dev libcurl4-openssl-dev freeglut3-dev libssl-dev libjack-dev libasound2-dev'
|
||||
sudo chroot $BUILD_DIR /bin/sh -ec 'if grep -q Raspbian /etc/os-release; then sed -i s-http://deb.debian.org/debian-http://mirrordirector.raspbian.org/raspbian/- /etc/apt/sources.list; apt-get -y update; fi' # https://bugs.launchpad.net/ubuntu/+source/qemu/+bug/1670905 workaround
|
||||
sudo chroot $BUILD_DIR /bin/sh -ec 'apt-get -y install build-essential git pkg-config autoconf automake libtool'
|
||||
sudo chroot $BUILD_DIR /bin/sh -ec 'apt-get -y install portaudio19-dev libsdl2-dev libglib2.0-dev libglew-dev libcurl4-openssl-dev freeglut3-dev libssl-dev libjack-dev libasound2-dev'
|
||||
if [ $ARCH = armhf ]; then # Raspbian - build own FFmpeg with OMX camera patch
|
||||
sudo chroot $BUILD_DIR /bin/sh -c "git clone --depth 1 https://github.com/raspberrypi/firmware.git firmware && mv firmware/* / && echo /opt/vc/lib > /etc/ld.so.conf.d/00-vmcs.conf && ldconfig"\
|
||||
sudo chroot $BUILD_DIR /bin/sh -ec "git clone --depth 1 https://github.com/raspberrypi/firmware.git firmware && mv firmware/* / && echo /opt/vc/lib > /etc/ld.so.conf.d/00-vmcs.conf && ldconfig"\
|
||||
"&& sed -i '/^deb /p;s/deb/deb-src/' /etc/apt/sources.list "\
|
||||
"&& apt-get -y update && apt-get -y build-dep ffmpeg"\
|
||||
"&& apt-get -y remove libavcodec58 && apt-get -y autoremove"\
|
||||
"&& git clone --depth 1 https://github.com/FFmpeg/FFmpeg.git && cd FFmpeg"\
|
||||
"&& git fetch --depth 2 https://github.com/Serveurperso/FFmpeg.git && git cherry-pick FETCH_HEAD"\
|
||||
"&& ./configure --enable-gpl --disable-stripping --enable-libaom --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libspeex --enable-libvpx --enable-libwebp --enable-libx265 --enable-omx --enable-neon --enable-libx264 --enable-mmal --enable-omx-rpi --cpu=arm1176jzf-s --enable-shared --disable-static && make -j 3 && make install"\
|
||||
"&& cd .. && rm -rf FFmpeg"
|
||||
"&& cd .. && rm -rf FFmpeg || exit 1"
|
||||
else
|
||||
sudo chroot $BUILD_DIR /bin/sh -c 'apt-get -y install libavcodec-dev libavformat-dev libswscale-dev'
|
||||
sudo chroot $BUILD_DIR /bin/sh -ec 'apt-get -y install libavcodec-dev libavformat-dev libswscale-dev'
|
||||
fi
|
||||
sudo chroot $BUILD_DIR /bin/sh -c 'apt-get -y install desktop-file-utils git-core libfuse-dev libcairo2-dev cmake wget zsync' # to build appimagetool
|
||||
sudo chroot $BUILD_DIR /bin/sh -c 'git clone https://github.com/AppImage/AppImageKit.git && cd AppImageKit && ./build.sh && cd build && cmake -DAUXILIARY_FILES_DESTINATION= .. && make install'
|
||||
sudo chroot $BUILD_DIR /bin/sh -c 'rm -rf AppImageKit; apt-get -y clean'
|
||||
sudo chroot $BUILD_DIR /bin/sh -ec 'apt-get -y install desktop-file-utils git-core libfuse-dev libcairo2-dev cmake wget zsync' # to build appimagetool
|
||||
sudo chroot $BUILD_DIR /bin/sh -ec 'git clone https://github.com/AppImage/AppImageKit.git && cd AppImageKit && ./build.sh && cd build && cmake -DAUXILIARY_FILES_DESTINATION= .. && make install || exit 1'
|
||||
sudo chroot $BUILD_DIR /bin/sh -ec 'rm -rf AppImageKit; apt-get -y clean'
|
||||
|
||||
2
.github/scripts/Linux/arm/build.sh
vendored
2
.github/scripts/Linux/arm/build.sh
vendored
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh -eux
|
||||
|
||||
export CPATH=/usr/local/include${CPATH:+":$CPATH"}
|
||||
export EXTRA_LIB_PATH=/usr/local/cuda/lib64:/usr/local/lib
|
||||
EXTRA_LIB_PATH=/usr/local/cuda/lib64:/usr/local/lib
|
||||
export LIBRARY_PATH=$EXTRA_LIB_PATH${LIBRARY_PATH:+":$LIBRARY_PATH"}
|
||||
export LD_LIBRARY_PATH=$EXTRA_LIB_PATH${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"}
|
||||
export PATH=/usr/local/bin:$PATH
|
||||
|
||||
13
.github/scripts/Linux/download_build_ffmpeg.sh
vendored
13
.github/scripts/Linux/download_build_ffmpeg.sh
vendored
@@ -1,18 +1,19 @@
|
||||
#!/bin/bash -eux
|
||||
|
||||
install_svt() {
|
||||
( git clone --depth 1 https://github.com/OpenVisualCloud/SVT-HEVC && cd SVT-HEVC/Build/linux && ./build.sh release && cd Release && make && sudo make install )
|
||||
( git clone --depth 1 -b v0.8.4 https://github.com/OpenVisualCloud/SVT-AV1 && cd SVT-AV1 && cd Build && cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release && make -j $(nproc) && sudo make install )
|
||||
( git clone --depth 1 https://github.com/OpenVisualCloud/SVT-HEVC && cd SVT-HEVC/Build/linux && ./build.sh release && cd Release && make && sudo make install || exit 1 )
|
||||
( git clone --depth 1 -b v0.8.4 https://github.com/OpenVisualCloud/SVT-AV1 && cd SVT-AV1 && cd Build && cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release && make -j $(nproc) && sudo make install || exit 1 )
|
||||
git apply SVT-HEVC/ffmpeg_plugin/0001*.patch
|
||||
git apply SVT-AV1/ffmpeg_plugin/0001-Add-ability-for-ffmpeg-to-run-svt-av1.patch
|
||||
}
|
||||
|
||||
git clone -b n4.3 --depth 1 https://git.ffmpeg.org/ffmpeg.git /var/tmp/ffmpeg # n4.3 is needed for SVT HEVC patch
|
||||
cd /var/tmp/ffmpeg
|
||||
( git clone --depth 1 -b nasm-2.13.xx https://github.com/sezero/nasm.git && cd nasm && ./autogen.sh && ./configure && make nasm.1 && make ndisasm.1 && make && sudo make install )
|
||||
( git clone --depth 1 http://git.videolan.org/git/x264.git && cd x264 && ./configure --disable-static --enable-shared && make && sudo make install )
|
||||
( git clone -b sdk/8.1 https://git.videolan.org/git/ffmpeg/nv-codec-headers.git && cd nv-codec-headers && make && sudo make install )
|
||||
( git clone --depth 1 https://aomedia.googlesource.com/aom && mkdir -p aom/build && cd aom/build && cmake -DBUILD_SHARED_LIBS=1 .. && make && sudo make install )
|
||||
sed -i '1,/sliceModeData = 1;/s/sliceModeData = 1;/sliceModeData = 8;/' libavcodec/nvenc.c # only first occurence - for H.264, not HEVC
|
||||
( git clone --depth 1 -b nasm-2.13.xx https://github.com/sezero/nasm.git && cd nasm && ./autogen.sh && ./configure && make nasm.1 && make ndisasm.1 && make && sudo make install || exit 1 )
|
||||
( git clone --depth 1 http://git.videolan.org/git/x264.git && cd x264 && ./configure --disable-static --enable-shared && make && sudo make install || exit 1 )
|
||||
( git clone -b sdk/8.1 https://git.videolan.org/git/ffmpeg/nv-codec-headers.git && cd nv-codec-headers && make && sudo make install || exit 1 )
|
||||
( git clone --depth 1 https://aomedia.googlesource.com/aom && mkdir -p aom/build && cd aom/build && cmake -DBUILD_SHARED_LIBS=1 .. && make && sudo make install || exit 1 )
|
||||
install_svt
|
||||
./configure --disable-static --enable-shared --enable-gpl --enable-libx264 --enable-libx265 --enable-libopus --enable-nonfree --enable-nvenc --enable-libaom --enable-libvpx --enable-libspeex --enable-libmp3lame --enable-libsvthevc --enable-libsvtav1
|
||||
make
|
||||
|
||||
18
.github/scripts/Linux/prepare.sh
vendored
18
.github/scripts/Linux/prepare.sh
vendored
@@ -1,17 +1,17 @@
|
||||
#!/bin/bash -eux
|
||||
|
||||
echo "::set-env name=AJA_DIRECTORY::/var/tmp/ntv2sdk"
|
||||
echo "::set-env name=CPATH::/usr/local/qt/include"
|
||||
echo "::set-env name=LIBRARY_PATH::/usr/local/qt/lib"
|
||||
echo "::set-env name=PKG_CONFIG_PATH::/usr/local/qt/lib/pkgconfig"
|
||||
echo "::add-path::/usr/local/qt/bin"
|
||||
echo "AJA_DIRECTORY=/var/tmp/ntv2sdk" >> $GITHUB_ENV
|
||||
echo "CPATH=/usr/local/qt/include" >> $GITHUB_ENV
|
||||
echo "LIBRARY_PATH=/usr/local/qt/lib" >> $GITHUB_ENV
|
||||
echo "PKG_CONFIG_PATH=/usr/local/qt/lib/pkgconfig" >> $GITHUB_ENV
|
||||
echo "/usr/local/qt/bin" >> $GITHUB_PATH
|
||||
|
||||
if command -v gcc-5; then
|
||||
CUDA_HOST_COMPILER=gcc-5
|
||||
else
|
||||
CUDA_HOST_COMPILER=gcc-6
|
||||
fi
|
||||
echo "::set-env name=CUDA_HOST_COMPILER::$CUDA_HOST_COMPILER"
|
||||
echo "CUDA_HOST_COMPILER=$CUDA_HOST_COMPILER" >> $GITHUB_ENV
|
||||
|
||||
sudo sed -n 'p; /^deb /s/^deb /deb-src /p' -i /etc/apt/sources.list # for build-dep ffmpeg
|
||||
sudo apt update
|
||||
@@ -24,13 +24,13 @@ sudo apt install portaudio19-dev libjack-jackd2-dev libasound-dev libv4l-dev
|
||||
|
||||
# for FFmpeg
|
||||
sudo apt build-dep ffmpeg
|
||||
sudo apt-get remove 'libx264*' nasm
|
||||
sudo apt-get -y remove 'libavcodec*' 'libavutil*' 'libswscale*' 'libx264*' nasm
|
||||
sudo apt --no-install-recommends install asciidoc xmlto
|
||||
|
||||
sudo apt install libopencv-dev
|
||||
sudo apt install libglib2.0-dev libcurl4-nss-dev
|
||||
( mkdir gpujpeg/build && cd gpujpeg/build && CC=$CUDA_HOST_COMPILER cmake .. && make && sudo make install && sudo ldconfig )
|
||||
( sudo apt install uuid-dev && cd cineform-sdk/ && cmake -DBUILD_TOOLS=OFF . && make CFHDCodecStatic )
|
||||
( mkdir gpujpeg/build && cd gpujpeg/build && CC=$CUDA_HOST_COMPILER cmake .. && make && sudo make install && sudo ldconfig || exit 1 )
|
||||
( sudo apt install uuid-dev && cd cineform-sdk/ && cmake -DBUILD_TOOLS=OFF . && make CFHDCodecStatic || exit 1 )
|
||||
sudo apt install qtbase5-dev
|
||||
sudo chmod 777 /usr/local
|
||||
|
||||
|
||||
6
.github/scripts/Windows/find_msvc.ps1
vendored
6
.github/scripts/Windows/find_msvc.ps1
vendored
@@ -16,7 +16,7 @@ if (-Not $version) {
|
||||
throw "Cannot get MSVS version"
|
||||
}
|
||||
$version = $version.Trim()
|
||||
echo "::add-path::$installDir\VC\Tools\MSVC\$version\bin\HostX64\x64" # cl
|
||||
echo "::add-path::$installDir\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin"
|
||||
echo "::add-path::$installDir\MSBuild\Current\Bin"
|
||||
echo "$installDir\VC\Tools\MSVC\$version\bin\HostX64\x64" >> ${env:GITHUB_PATH} # cl
|
||||
echo "$installDir\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin" >> ${env:GITHUB_PATH}
|
||||
echo "$installDir\MSBuild\Current\Bin" >> ${env:GITHUB_PATH}
|
||||
|
||||
|
||||
4
.github/scripts/Windows/prepare.ps1
vendored
4
.github/scripts/Windows/prepare.ps1
vendored
@@ -9,7 +9,7 @@ if (!${env:no_cuda}) {
|
||||
Invoke-WebRequest https://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_441.22_win10.exe -OutFile cuda_inst.exe
|
||||
Start-Process -FilePath "cuda_inst.exe" -ArgumentList "-s nvcc_10.2" -Wait -NoNewWindow
|
||||
Remove-Item cuda_inst.exe
|
||||
echo "::add-path::C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin"
|
||||
echo "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.2\bin" >> ${env:GITHUB_PATH}
|
||||
}
|
||||
|
||||
# Install XIMEA
|
||||
@@ -28,7 +28,7 @@ if (${env:SDK_URL} -and ${env:GITHUB_REF} -eq "refs/heads/ndi-build") {
|
||||
Start-Process -FilePath "C:\ndi.exe" -ArgumentList "/VERYSILENT"
|
||||
Sleep 10
|
||||
$sdk=(dir "C:\Program Files\NewTek" -Filter *SDK -Name)
|
||||
echo "::add-path::C:\Program Files\NewTek\$sdk\Bin\x64"
|
||||
echo "C:\Program Files\NewTek\$sdk\Bin\x64" >> ${env:GITHUB_PATH}
|
||||
#Remove-Item C:\ndi.exe
|
||||
}
|
||||
|
||||
|
||||
4
.github/scripts/Windows/prepare_msys.sh
vendored
4
.github/scripts/Windows/prepare_msys.sh
vendored
@@ -71,8 +71,8 @@ data/scripts/build_spout64.sh src/SpoutSDK/VS2012/x64/Release
|
||||
wget --no-verbose https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full-shared.7z && 7z x ffmpeg-release-full-shared.7z && cp -r ffmpeg-*build-shared/{bin,lib,include} /usr/local && rm -rf ffmpeg-* || exit 1
|
||||
|
||||
# Install GPUJPEG
|
||||
( wget --no-verbose https://github.com/CESNET/GPUJPEG/releases/download/continuous/GPUJPEG.zip && unzip GPUJPEG.zip && cp -r GPUJPEG/* /usr/local )
|
||||
( wget --no-verbose https://github.com/CESNET/GPUJPEG/releases/download/continuous/GPUJPEG.zip && unzip GPUJPEG.zip && cp -r GPUJPEG/* /usr/local || exit 1 )
|
||||
|
||||
# Build CineForm
|
||||
( git submodule update --init cineform-sdk && cd cineform-sdk && cmake -DBUILD_STATIC=false -DBUILD_TOOLS=false -A x64 && MSBuild.exe CineFormSDK.sln -property:Configuration=Release && cp Release/CFHDCodec.dll /usr/local/bin && cp Release/CFHDCodec.lib /usr/local/lib && cp Common/* /usr/local/include && cp libcineformsdk.pc /usr/local/lib/pkgconfig )
|
||||
( git submodule update --init cineform-sdk && cd cineform-sdk && cmake -DBUILD_STATIC=false -DBUILD_TOOLS=false -A x64 && MSBuild.exe CineFormSDK.sln -property:Configuration=Release && cp Release/CFHDCodec.dll /usr/local/bin && cp Release/CFHDCodec.lib /usr/local/lib && cp Common/* /usr/local/include && cp libcineformsdk.pc /usr/local/lib/pkgconfig || exit 1 )
|
||||
|
||||
|
||||
4
.github/scripts/environment.sh
vendored
4
.github/scripts/environment.sh
vendored
@@ -13,5 +13,5 @@ fi
|
||||
|
||||
export VERSION TAG
|
||||
|
||||
echo "::set-env name=VERSION::$VERSION"
|
||||
echo "::set-env name=TAG::$TAG"
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
echo "TAG=$TAG" >> $GITHUB_ENV
|
||||
|
||||
22
.github/scripts/macOS/prepare.sh
vendored
22
.github/scripts/macOS/prepare.sh
vendored
@@ -5,19 +5,19 @@ TEMP_INST=/tmp/install
|
||||
|
||||
CPATH=/usr/local/include:/usr/local/opt/qt/include
|
||||
LIBRARY_PATH=/usr/local/lib:/usr/local/opt/qt/lib
|
||||
echo "::set-env name=AJA_DIRECTORY::$AJA_INST"
|
||||
echo "::set-env name=UG_SKIP_NET_TESTS::1"
|
||||
echo "::set-env name=CPATH::$CPATH"
|
||||
echo "::set-env name=LIBRARY_PATH::$LIBRARY_PATH"
|
||||
echo "AJA_DIRECTORY=$AJA_INST" >> $GITHUB_ENV
|
||||
echo "UG_SKIP_NET_TESTS=1" >> $GITHUB_ENV
|
||||
echo "CPATH=$CPATH" >> $GITHUB_ENV
|
||||
echo "LIBRARY_PATH=$LIBRARY_PATH" >> $GITHUB_ENV
|
||||
# libcrypto.pc (and other libcrypto files) is not linked to /usr/local/{lib,include} because conflicting with system libcrypto
|
||||
echo "::set-env name=PKG_CONFIG_PATH::/usr/local/lib/pkgconfig:/usr/local/opt/qt/lib/pkgconfig:/usr/local/opt/openssl/lib/pkgconfig"
|
||||
echo "::add-path::/usr/local/opt/qt/bin"
|
||||
echo "PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/opt/qt/lib/pkgconfig:/usr/local/opt/openssl/lib/pkgconfig" >> $GITHUB_ENV
|
||||
echo "/usr/local/opt/qt/bin" >> $GITHUB_PATH
|
||||
|
||||
brew install autoconf automake cppunit libtool pkg-config
|
||||
brew install ffmpeg portaudio sdl2
|
||||
brew install imagemagick jack opencv openssl
|
||||
brew install ossp-uuid # for cineform
|
||||
( cd cineform-sdk/ && cmake -DBUILD_TOOLS=OFF . && make CFHDCodecStatic )
|
||||
( cd cineform-sdk/ && cmake -DBUILD_TOOLS=OFF . && make CFHDCodecStatic || exit 1 )
|
||||
brew install qt
|
||||
|
||||
.github/scripts/macOS/install_dylibbundler_v2.sh
|
||||
@@ -57,10 +57,10 @@ if [ -f /var/tmp/sdks/NDISDK_Apple.pkg ]; then
|
||||
export DYLIBBUNDLER_FLAGS="${DYLIBBUNDLER_FLAGS:+$DYLIBBUNDLER_FLAGS }-s /Library/NDI/lib/x64"
|
||||
export LIBRARY_PATH=${LIBRARY_PATH:+"$LIBRARY_PATH:"}/Library/NDI/lib/x64
|
||||
export MY_DYLD_LIBRARY_PATH="${MY_DYLD_LIBRARY_PATH:+$MY_DYLD_LIBRARY_PATH:}/Library/NDI/lib/x64"
|
||||
echo "::set-env name=CPATH::$CPATH"
|
||||
echo "::set-env name=DYLIBBUNDLER_FLAGS::$DYLIBBUNDLER_FLAGS"
|
||||
echo "::set-env name=LIBRARY_PATH::$LIBRARY_PATH"
|
||||
echo "::set-env name=MY_DYLD_LIBRARY_PATH::$MY_DYLD_LIBRARY_PATH"
|
||||
echo "CPATH=$CPATH" >> $GITHUB_ENV
|
||||
echo "DYLIBBUNDLER_FLAGS=$DYLIBBUNDLER_FLAGS" >> $GITHUB_ENV
|
||||
echo "LIBRARY_PATH=$LIBRARY_PATH" >> $GITHUB_ENV
|
||||
echo "MY_DYLD_LIBRARY_PATH=$MY_DYLD_LIBRARY_PATH" >> $GITHUB_ENV
|
||||
cd $TEMP_INST
|
||||
fi
|
||||
|
||||
|
||||
21
.github/workflows/ccpp.yml
vendored
21
.github/workflows/ccpp.yml
vendored
@@ -81,19 +81,14 @@ jobs:
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: '/var/tmp/ffmpeg'
|
||||
key: cache-ffmpeg-8
|
||||
key: cache-ffmpeg-9
|
||||
- name: Build FFmpeg
|
||||
if: steps.cache-ffmpeg.outputs.cache-hit != 'true'
|
||||
run: .github/scripts/Linux/download_build_ffmpeg.sh
|
||||
- name: Install FFmpeg
|
||||
run: .github/scripts/Linux/install_ffmpeg.sh
|
||||
- name: configure
|
||||
env:
|
||||
CC: clang-9
|
||||
CXX: clang++-9
|
||||
CPP: clang-cpp-9
|
||||
LDFLAGS: -static-libstdc++
|
||||
run: "[ ${{ github.ref }} != refs/heads/ndi-build ] && NDI=-disable-ndi; ./autogen.sh --enable-qt --with-cuda-host-compiler=$CUDA_HOST_COMPILER --enable-plugins --enable-jack-transport=force --with-live555=/usr/local $NDI"
|
||||
run: "[ ${{ github.ref }} != refs/heads/ndi-build ] && NDI=-disable-ndi; ./autogen.sh --enable-qt --with-cuda-host-compiler=$CUDA_HOST_COMPILER --enable-plugins --with-live555=/usr/local $NDI"
|
||||
- name: make
|
||||
run: make -j4
|
||||
- name: make check
|
||||
@@ -245,7 +240,7 @@ jobs:
|
||||
- name: bootsrap MSYS2
|
||||
run: C:\msys64\usr\bin\bash -cel '$GITHUB_WORKSPACE/.github/scripts/Windows/prepare_msys.sh'
|
||||
- name: configure
|
||||
run: C:\msys64\usr\bin\bash -cel '[ ${{ github.ref }} != refs/heads/ndi-build ] && NDI=-disable-ndi; ./autogen.sh --enable-qt $NDI --with-live555=/usr/local'
|
||||
run: C:\msys64\usr\bin\bash -cel '[ ${{ github.ref }} != refs/heads/ndi-build ] && NDI=-disable-ndi; ./autogen.sh --prefix=/ --bindir=/ --docdir=/doc --enable-qt $NDI --with-live555=/usr/local'
|
||||
- name: make
|
||||
run: C:\msys64\usr\bin\bash -cel "make -j4"
|
||||
- name: make check
|
||||
@@ -255,11 +250,11 @@ jobs:
|
||||
C:\msys64\usr\bin\bash -cel '
|
||||
cp gui/QT/uv-qt.exe bin
|
||||
rm bin/run_tests.exe
|
||||
IFS=\"|\"; for exe in bin/*exe; do for n in `data/scripts/get_dll_depends.sh \"$exe\" | tr \"\n\" \"|\"`; do cp \"$n\" bin; done; done
|
||||
windeployqt bin/uv-qt.exe
|
||||
cp data/update.ps1 bin
|
||||
mkdir build
|
||||
mv bin build/UltraGrid-$VERSION-win64'
|
||||
export DESTDIR=build/UltraGrid-$VERSION-win64
|
||||
make install
|
||||
IFS=\"|\"; for exe in $DESTDIR/*exe; do for n in `data/scripts/get_dll_depends.sh \"$exe\" | tr \"\n\" \"|\"`; do cp \"$n\" $DESTDIR; done; done
|
||||
windeployqt $DESTDIR/uv-qt.exe
|
||||
cp data/update.ps1 $DESTDIR'
|
||||
- name: make dist-check
|
||||
run: C:\msys64\usr\bin\bash -cel 'PATH=
|
||||
/usr/bin/make distcheck TARGET=build/UltraGrid-$VERSION-win64/uv.exe GUI_EXE=build/UltraGrid-$VERSION-win64/uv-qt.exe'
|
||||
|
||||
@@ -18,7 +18,7 @@ way or extend this document.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Adding modules HOWTO](ADDING-MODULES.md)
|
||||
- [Adding modules HOWTO](doc/ADDING-MODULES.md)
|
||||
- [Doxygen](https://frakira.fi.muni.cz/~xpulec/ultragrid-doxygen/html/)
|
||||
- [GitHub devel page](https://github.com/CESNET/UltraGrid/wiki/Developer-Documentation)
|
||||
- [Trello board](https://trello.com/b/PjZW4sas/ultragrid-development) tracking the development
|
||||
@@ -27,7 +27,7 @@ way or extend this document.
|
||||
You can either fill an issue at GitHub or contact our development team directly
|
||||
with the e-mail or use a chat. If you suspect that the issue may not be always
|
||||
replicable, you can use a script `ultragrid-bugreport-collect.sh` to collect
|
||||
data about a computer and attach its result. See also [here](REPORTING-BUGS.md).
|
||||
data about a computer and attach its result. See also [here](doc/REPORTING-BUGS.md).
|
||||
|
||||
Especially for various questions about UltraGrid usage you may also use our Matrix chat
|
||||
[](https://matrix.to/#/!IrTYOLJOmZIoTBiITI:matrix.org?via=matrix.org).
|
||||
|
||||
74
MODS
74
MODS
@@ -1,74 +0,0 @@
|
||||
MODIFICATIONS FILE
|
||||
------------------
|
||||
|
||||
$Revision: 1.1 $
|
||||
$Date: 2007/11/08 09:48:58 $
|
||||
|
||||
Copyright (c) 2001-2004 University of Southern California
|
||||
Copyright (c) 2003-2004 University of Glasgow
|
||||
All rights reserved.
|
||||
|
||||
This software is distributed under license, see the file COPYRIGHT for full
|
||||
terms and conditions.
|
||||
|
||||
v0.0.1 - Initial version, HDTV receiver
|
||||
* 14 August 2002
|
||||
|
||||
v0.0.2 - Fix builds with --enable-debug
|
||||
- Update display code
|
||||
- Update capture code
|
||||
* 26 August 2002
|
||||
|
||||
v0.0.3 - Add "-d <display>" option to select display device
|
||||
- Add "-t <capture>" option to select capture device, and enable transmit
|
||||
- Reduce RTCP housekeeping frequency
|
||||
- Disable UI for now
|
||||
* 27 August 2002
|
||||
|
||||
v0.1.0 - Add "-m <mtu>" option to select transmit MTU
|
||||
- Add TFRC code
|
||||
- Display in a window using Xvideo (not cleanly implemented)
|
||||
- Initial test suite (incomplete)
|
||||
* 8 October 2002
|
||||
|
||||
v0.1.1 - Performance optimizations for Xvideo display device
|
||||
* 28 November 2002 (demonstrated at SuperComputing 2002)
|
||||
|
||||
v0.2.0 - Source code reorganization; add audio code (unused)
|
||||
* 18 August 2003
|
||||
|
||||
v0.2.1 - Cleanup configure script, removing duplicate tests
|
||||
- Update configure script to explicitly test for sched_setscheduler()
|
||||
since some platforms (e.g. MacOS X) don't have it.
|
||||
- Update configure script and video display routines to partially
|
||||
support the case where X11 is not present.
|
||||
- Fix -v option
|
||||
- Rewrite playout buffer code
|
||||
- Rewrite video display probing
|
||||
- Removing scatter-read from the RTP code
|
||||
- Framerate now tunable using "-f <rate>"
|
||||
* 2 May 2004
|
||||
|
||||
v0.2.2 - Check reported loss fraction, and abort if excessive
|
||||
- Playout buffer now uses a fixed 32ms playout delay, equivalent
|
||||
to 2 frames at 60fps, instead of decoding frames immediately.
|
||||
* 10 May 2004
|
||||
|
||||
v0.3.0 - Update documentation
|
||||
- Add initial FireWire/DV support
|
||||
- Add initial video codec API
|
||||
- Add initial MacOS X audio driver (contributed to rat by Juraj Sucik)
|
||||
- Add initial AccessGrid service plugins
|
||||
- Add initial participant database framework, to eventually allow
|
||||
multiple participants
|
||||
* 13 August 2004
|
||||
|
||||
v0.3.1 - Fix crash in RTP code if getpwuid() fails (patch contributed to
|
||||
rat by <Grant.Likely@gdcanada.com>, and adapted for UltraGrid)
|
||||
- Update AES code code to rijndael-fst-3.0.zip, taken from:
|
||||
http://www.esat.kuleuven.ac.be/~rijmen/rijndael/
|
||||
This now passes the official NIST AES test suite (included).
|
||||
- Add initial TFRC code to RTP library
|
||||
- Update ALSA code with Steve Smith's ALSA 0.9+/final audio driver
|
||||
* 26 October 2004
|
||||
|
||||
26
Makefile.in
26
Makefile.in
@@ -13,10 +13,9 @@ CXXFLAGS = @CXXFLAGS@ $(COMMON_FLAGS) -D_GNU_SOURCE
|
||||
MKDIR_P = mkdir -p
|
||||
CUDA_FLAGS = @CUDA_FLAGS@ @CUDA_COMPUTE_ARGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS += @LIBS@ @JACK_TRANS_LIB@ @MATHLIBS@ -lm -pthread
|
||||
LIBS += @LIBS@ @MATHLIBS@ -lm -pthread
|
||||
INC = -Isrc -I$(srcdir) -I$(srcdir)/src -I$(srcdir)/test -Idxt_compress \
|
||||
@JACK_TRANS_INC@ @SPEEX_INC@ \
|
||||
@CUDA_INC@ @INC@
|
||||
@SPEEX_INC@ @CUDA_INC@ @INC@
|
||||
DECKLINK_PATH = @DECKLINK_PATH@
|
||||
DYLIBBUNDLER = @DYLIBBUNDLER@
|
||||
DYLIBBUNDLER_FLAGS += @DYLIBBUNDLER_FLAGS@
|
||||
@@ -28,13 +27,13 @@ GUI_BUNDLE = gui/QT/uv-qt.app
|
||||
DXT_GLSL_CFLAGS = @DXT_GLSL_CFLAGS@
|
||||
CUDA_COMPILER = @CUDA_COMPILER@
|
||||
SYSTEM = @system@
|
||||
APPEXT = @APPEXT@
|
||||
|
||||
GUI_EXE = @GUI_EXE@
|
||||
GUI_TARGET = @GUI_TARGET@
|
||||
REFLECTOR_TARGET = bin/hd-rum-transcode$(EXEEXT)
|
||||
TEST_TARGET = bin/run_tests$(EXEEXT)
|
||||
|
||||
PACKAGE_TARNAME ?= @PACKAGE_TARNAME@
|
||||
PREFIX = @prefix@
|
||||
prefix = $(PREFIX)
|
||||
exec_prefix = @exec_prefix@
|
||||
@@ -43,14 +42,13 @@ bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@/ultragrid
|
||||
uv_datadir = @datadir@/ultragrid
|
||||
docdir = @docdir@
|
||||
mandir = @mandir@
|
||||
man1dir = @mandir@/man1
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
DOCS = $(srcdir)/CONTRIBUTING.md $(srcdir)/README.md $(srcdir)/REPORTING-BUGS.md
|
||||
DOCS = $(srcdir)/CONTRIBUTING.md $(srcdir)/README.md $(wildcard $(srcdir)/doc/*)
|
||||
|
||||
# autogenerated headers
|
||||
GENERATED_HEADERS = @GENERATED_HEADERS@
|
||||
@@ -464,7 +462,7 @@ dxt_compress/dxt_glsl.h:dxt_compress/compress_vp.glsl \
|
||||
#cat dxt_compress/rgba_to_yuv422_vp.glsl | sed 's/\(.*\)/ \"\1\\n\"/' >> $@
|
||||
#echo ";" >> $@
|
||||
|
||||
gui/QT/uv-qt$(APPEXT): $(wildcard $(srcdir)/gui/QT/*.cpp $(srcdir)/gui/QT/*.hpp) $(srcdir)/src/shared_mem_frame.cpp $(srcdir)/tools/astat.h
|
||||
$(GUI_TARGET): $(wildcard $(srcdir)/gui/QT/*.cpp $(srcdir)/gui/QT/*.hpp) $(srcdir)/src/shared_mem_frame.cpp $(srcdir)/tools/astat.h
|
||||
$(MKDIR_P) $(dir $@)
|
||||
if test -z "$(QMAKE)"; then echo "Reconfigure with '--enable-qt'"; exit 1; fi
|
||||
cd gui/QT && $(QMAKE) "DESTDIR+=./" $(srcdir)/../../gui/QT && make -j 4
|
||||
@@ -667,12 +665,11 @@ install: all
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(libdir)/ultragrid;\
|
||||
$(INSTALL) -m 755 @MODULES@ $(DESTDIR)$(libdir)/ultragrid;\
|
||||
fi
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(uv_datadir)
|
||||
$(INSTALL) -m 755 $(srcdir)/data/ultragrid-bugreport-collect.sh $(DESTDIR)$(uv_datadir)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(docdir)
|
||||
$(INSTALL) -m 644 $(DOCS) $(DESTDIR)$(docdir)
|
||||
$(INSTALL) -m 644 $(srcdir)/COPYRIGHT $(DESTDIR)$(docdir)
|
||||
$(INSTALL) -m 644 $(srcdir)/CONTRIBUTING.md $(srcdir)/COPYRIGHT $(srcdir)/INSTALL $(srcdir)/NEWS $(srcdir)/README.md $(DESTDIR)$(docdir)
|
||||
$(CP) $(srcdir)/speex-1.2rc1/COPYING $(DESTDIR)$(docdir)/COPYING.speex
|
||||
$(INSTALL) -m 755 $(srcdir)/data/ultragrid-bugreport-collect.sh $(DESTDIR)$(docdir)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
|
||||
$(INSTALL) -m 644 $(srcdir)/data/uv.1 $(srcdir)/data/hd-rum-transcode.1 $(DESTDIR)$(man1dir)
|
||||
if [ -n '@DLL_LIBS@' ]; then $(INSTALL) -m 644 @DLL_LIBS@ $(DESTDIR)$(bindir); fi
|
||||
@@ -681,11 +678,10 @@ uninstall:
|
||||
$(RM) $(DESTDIR)$(bindir)/uv
|
||||
$(RM) $(DESTDIR)$(bindir)/hd-rum-transcode
|
||||
if [ -n "@MODULES@" ]; then for n in @MODULES@; do $(RM) $(DESTDIR)$(libdir)/ultragrid/`basename $$n`; done; fi
|
||||
$(RM) $(DESTDIR)$(uv_datadir)/ultragrid-bugreport-collect.sh
|
||||
for n in $(DOCS); do $(RM) $(DESTDIR)$(docdir)$$n; done;
|
||||
$(RM) $(DESTDIR)$(docdir)COPYRIGHT
|
||||
$(RM) $(DESTDIR)$(docdir)COPYING.speex
|
||||
$(RM) $(DESTDIR)$(uv_datadir)ultragrid-bugreport-collect.sh
|
||||
$(RM) $(DESTDIR)$(docdir)/CONTRIBUTING.md $(DESTDIR)$(docdir)/COPYRIGHT $(DESTDIR)$(docdir)/INSTALL $(DESTDIR)$(docdir)/NEWS $(DESTDIR)$(docdir)/README.md
|
||||
$(RM) $(DESTDIR)$(docdir)/COPYING.speex
|
||||
$(RM) $(DESTDIR)$(docdir)/ultragrid-bugreport-collect.sh
|
||||
if [ -f "$(GUI_TARGET)" ]; then \
|
||||
$(RM) $(DESTDIR)$(bindir)/`basename $(GUI_TARGET)`;\
|
||||
$(RM) $(DESTDIR)$(datadir)/applications/uv-qt.desktop;\
|
||||
|
||||
82
NEWS
82
NEWS
@@ -146,3 +146,85 @@ next
|
||||
target system has installed CUDA Toolkit.
|
||||
* format detection for DVS cards
|
||||
* DVS support for Mac OS X
|
||||
|
||||
0.3.1
|
||||
=====
|
||||
* Fix crash in RTP code if getpwuid() fails (patch contributed to
|
||||
rat by <Grant.Likely@gdcanada.com>, and adapted for UltraGrid)
|
||||
* Update AES code code to rijndael-fst-3.0.zip, taken from:
|
||||
http://www.esat.kuleuven.ac.be/~rijmen/rijndael/
|
||||
This now passes the official NIST AES test suite (included).
|
||||
* Add initial TFRC code to RTP library
|
||||
* Update ALSA code with Steve Smith's ALSA 0.9+/final audio driver
|
||||
* 26 October 2004
|
||||
|
||||
0.3.0
|
||||
=====
|
||||
* Update documentation
|
||||
* Add initial FireWire/DV support
|
||||
* Add initial video codec API
|
||||
* Add initial MacOS X audio driver (contributed to rat by Juraj Sucik)
|
||||
* Add initial AccessGrid service plugins
|
||||
* Add initial participant database framework, to eventually allow
|
||||
multiple participants
|
||||
* 13 August 2004
|
||||
|
||||
0.2.2
|
||||
=====
|
||||
* Check reported loss fraction, and abort if excessive
|
||||
* Playout buffer now uses a fixed 32ms playout delay, equivalent
|
||||
to 2 frames at 60fps, instead of decoding frames immediately.
|
||||
* 10 May 2004
|
||||
|
||||
v0.2.1
|
||||
======
|
||||
* Cleanup configure script, removing duplicate tests
|
||||
* Update configure script to explicitly test for sched_setscheduler()
|
||||
since some platforms (e.g. MacOS X) don't have it.
|
||||
* Update configure script and video display routines to partially
|
||||
support the case where X11 is not present.
|
||||
* Fix -v option
|
||||
* Rewrite playout buffer code
|
||||
* Rewrite video display probing
|
||||
* Removing scatter-read from the RTP code
|
||||
* Framerate now tunable using "-f <rate>"
|
||||
* 2 May 2004
|
||||
|
||||
0.2.0
|
||||
=====
|
||||
* Source code reorganization; add audio code (unused)
|
||||
* 18 August 2003
|
||||
|
||||
0.1.1
|
||||
=====
|
||||
* Performance optimizations for Xvideo display device
|
||||
* 28 November 2002 (demonstrated at SuperComputing 2002)
|
||||
|
||||
0.1.0
|
||||
=====
|
||||
* Add "-m <mtu>" option to select transmit MTU
|
||||
* Add TFRC code
|
||||
* Display in a window using Xvideo (not cleanly implemented)
|
||||
* Initial test suite (incomplete)
|
||||
* 8 October 2002
|
||||
|
||||
0.0.3
|
||||
=====
|
||||
* Add "-d <display>" option to select display device
|
||||
* Add "-t <capture>" option to select capture device, and enable transmit
|
||||
* Reduce RTCP housekeeping frequency
|
||||
* Disable UI for now
|
||||
* 27 August 2002
|
||||
|
||||
0.0.2
|
||||
=====
|
||||
* Fix builds with --enable-debug
|
||||
* Update display code
|
||||
* Update capture code
|
||||
* 26 August 2002
|
||||
|
||||
0.0.1
|
||||
=====
|
||||
* Initial version, HDTV receiver
|
||||
* 14 August 2002
|
||||
|
||||
|
||||
127
README.md
127
README.md
@@ -20,6 +20,15 @@ UltraGrid - A High Definition Collaboratory
|
||||
[COPYRIGHT](COPYRIGHT) for full terms and conditions.
|
||||
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
- [About UltraGrid](#about-ultragrid)
|
||||
- [Hardware and Software Requirements](#hardware-and-software-requirements)
|
||||
* [Required Software Preliminaries](#required-software-preliminaries)
|
||||
- [Using the UltraGrid System](#using-the-ultragrid-system)
|
||||
- [Documentation](#documentation)
|
||||
|
||||
About UltraGrid
|
||||
---------------
|
||||
|
||||
@@ -63,8 +72,8 @@ About UltraGrid
|
||||
INSTALL Installation instructions
|
||||
NEWS Change log and modification history
|
||||
README.md This file
|
||||
REPORTING-BUGS.md Recommendations for reporting bugs
|
||||
bin/ Compiled binaries
|
||||
doc/ Documentation
|
||||
src/ Source code for the UltraGrid system
|
||||
test/ Source code and binaries for test routines
|
||||
Makefile.in Build script
|
||||
@@ -150,109 +159,23 @@ Using the UltraGrid System
|
||||
Using different supported compression schemes, the needed network capacity
|
||||
can be as low as 10 Megabits per second for a high definition video.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
Documentation can be found either _offline_ (apart from this document) and
|
||||
_online_. The online documentation is more comprehensive and up-to-date,
|
||||
offline is rather complementary.
|
||||
|
||||
Performance Tuning: Network
|
||||
---------------------------
|
||||
The **online** documentation is available in our GitHub
|
||||
[wiki](https://github.com/CESNET/UltraGrid/wiki).
|
||||
|
||||
If transmitting *uncompressed video* stream to achieve optimal performance
|
||||
with high definition video, it may be necessary to tune your system's
|
||||
network parameters to more aggressive values than used by default.
|
||||
UltraGrid _built-in_ documentation can be found in [doc](doc) subdirectory,
|
||||
these documents are available:
|
||||
|
||||
A key factor affecting performance is the path MTU. It is unlikely that
|
||||
the system will sustain gigabit rates with the 1500 octet Ethernet MTU.
|
||||
If using a gigabit Ethernet you may be able to improve performance by
|
||||
setting an 8192 octet MTU on the interface, provided all intermediate
|
||||
hops on the path from sender to receiver support the large MTU.
|
||||
|
||||
UltraGrid attempts to increase the UDP receive socket buffer from the
|
||||
default value (typically 64 kilobytes) to 4/6 megabytes. If successful,
|
||||
this will make the system more robust to scheduling variations and
|
||||
better able to accept bursty packet arrivals. UltraGrid will notify
|
||||
you if it cannot increase buffers. You should follow those instructions
|
||||
and set your system according to it.
|
||||
|
||||
Interrupt processing load on the receiver host may be significant when
|
||||
running at high rates. Depending on your network interface hardware it
|
||||
may be possible to coalesce interrupts to reduce this load, although
|
||||
the settings to do this are highly driver dependent. On FreeBSD, the
|
||||
use of network device polling may also help performance: see the man
|
||||
page for "polling" in section 4 of the manual.
|
||||
|
||||
In many cases, the performance of your network interface card may be
|
||||
limited by host bus performance (this is particularly an issue at high
|
||||
rates, for example when using HD format video).
|
||||
- [Adding modules](doc/ADDING-MODULES.md) (**developers only**) - information
|
||||
how to add new UltraGrid modules
|
||||
- [Performance tuning](doc/PERFORMANCE-TUNING.md) - various tweaks to improve
|
||||
UltraGrid performance
|
||||
- [Reporting bugs](doc/REPORTING_BUGS.md) - recommended steps for reporting
|
||||
bugs
|
||||
|
||||
|
||||
Performance Tuning: Display devices
|
||||
-----------------------------------
|
||||
|
||||
If using a HW grabbing card (eg. DVS) as a display device, the
|
||||
key factor limiting performance is PCI bus contention. Ensure that
|
||||
the grabbing card is on a separate PCI bus to the network card --
|
||||
this typically requires a server class motherboard. On Linux, the
|
||||
PCI bus topology can be displayed using "lspci -tv", for example:
|
||||
|
||||
[root@ormal root]# lspci -tv
|
||||
-+-[03]---06.0 Xilinx, Inc.: Unknown device d150
|
||||
+-[01]-+-02.0-[02]--+-04.0 Adaptec 7899P
|
||||
| | \-04.1 Adaptec 7899P
|
||||
| \-0e.0 3Com Corporation 3c985 1000BaseSX
|
||||
\-[00]-+-00.0 ServerWorks CNB20HE
|
||||
+-00.1 ServerWorks CNB20HE
|
||||
+-00.2 ServerWorks: Unknown device 0006
|
||||
+-00.3 ServerWorks: Unknown device 0006
|
||||
+-04.0 Intel Corporation 82557 [Ethernet Pro 100]
|
||||
+-0e.0 ATI Technologies Inc Rage XL
|
||||
+-0f.0 ServerWorks OSB4
|
||||
\-0f.1 ServerWorks: Unknown device 0211
|
||||
[root@ormal root]#
|
||||
|
||||
showing an DVS card on PCI bus [03] (the card shows as a Xilinx
|
||||
device) and a gigabit Ethernet card on PCI bus [02] (the 3Com entry).
|
||||
|
||||
For software display, you can use SDL or OpenGL display. Both are
|
||||
accelerated (Mac and Linux) if you have properly configured video
|
||||
drivers. On Linux, basic operability can be checked with following
|
||||
commands. If configured properly, both should display driver
|
||||
properties:
|
||||
[root@ormal root]# glxinfo
|
||||
<-- output omitted -->
|
||||
and for SDL (accelerated through XVideo:
|
||||
[root@ormal root]# xvinfo
|
||||
<-- output omitted -->
|
||||
|
||||
If you intend to use some of DXT compressions, recommended driver
|
||||
is OpenGL, which can display it natively. When using other display
|
||||
drivers, decompression is still done throught OpenGL and then displayed
|
||||
with requested video driver.
|
||||
|
||||
|
||||
Performance Tuning: Other Factors
|
||||
---------------------------------
|
||||
|
||||
The UltraGrid system will attempt to enable POSIX real-time scheduling
|
||||
to improve performance. This behaviour is disabled by default now, because
|
||||
it can occupy the whole system when enabled, but it can be stil enabled by
|
||||
'--enable-rt' configure option. If you see the message:
|
||||
|
||||
WARNING: Unable to set real-time scheduling
|
||||
|
||||
when starting the application, this means that the operating system did
|
||||
not permit it to enable real-time scheduling. The application will run,
|
||||
but with reduced performance. The most likely reason for failure to set
|
||||
realtime scheduling is that the application has insufficient privilege:
|
||||
it should either be run by root, or be made setuid root. A similar
|
||||
message:
|
||||
|
||||
WARNING: System does not support real-time scheduling
|
||||
|
||||
indicates that your operating system does not support POSIX real-time
|
||||
scheduling. The application will still run, but performance may be less
|
||||
than desired.
|
||||
|
||||
|
||||
You can find more operating system tweaks at this page:
|
||||
https://github.com/CESNET/UltraGrid/wiki/OS-Setup-UltraGrid
|
||||
|
||||
- * -
|
||||
|
||||
|
||||
32
configure.ac
32
configure.ac
@@ -132,9 +132,9 @@ if expr "$host_os" : ".*darwin.*" > /dev/null; then
|
||||
system=MacOSX
|
||||
AC_DEFINE([HAVE_MACOSX], [1], [This is Mac X OS])
|
||||
APPEXT=.app
|
||||
AC_SUBST(APPEXT)
|
||||
elif expr "$host_os" : ".*mingw32.*" > /dev/null || expr "$host_os" : ".*msys.*" > /dev/null; then
|
||||
system=Windows
|
||||
APPEXT=.exe
|
||||
AC_DEFINE([WIN32], [1], [This is an Windows OS])
|
||||
else
|
||||
system=Linux
|
||||
@@ -2290,10 +2290,10 @@ fi
|
||||
# -------------------------------------------------------------------------------------------------
|
||||
gpujpeg_to_dxt=no
|
||||
AC_ARG_ENABLE(gpujpeg_to_dxt,
|
||||
[ --disable-jpeg-to-dxt disable GPUJPEG DXT transcoder (default is auto)]
|
||||
[ --disable-jpeg-to-dxt disable GPUJPEG DXT transcoder (default is disable)]
|
||||
[ Requires: CUDA libgpujpeg],
|
||||
[gpujpeg_to_dxt_req=$enableval],
|
||||
[gpujpeg_to_dxt_req=$build_default])
|
||||
[gpujpeg_to_dxt_req=no])
|
||||
|
||||
if test $gpujpeg_to_dxt_req != no -a $FOUND_CUDA = yes -a \
|
||||
"$found_gpujpeg" = yes
|
||||
@@ -2302,7 +2302,7 @@ then
|
||||
DEFINE_CUDA_DXT
|
||||
gpujpeg_to_dxt=yes
|
||||
GPUJPEG_TO_DXT_INC=" $CUDA_INC"
|
||||
GPUJPEG_TO_DXT_LIB="$CUDA_DXT_COMMON_LIB $CUDA_COMMON_LIB $CUDA_LIB $JPEG_LIB"
|
||||
GPUJPEG_TO_DXT_LIB="$CUDA_DXT_COMMON_LIB $CUDA_COMMON_LIB $CUDA_LIB $GPUJPEG_LIB"
|
||||
GPUJPEG_TO_DXT_OBJ="src/video_decompress/gpujpeg_to_dxt.o $CUDA_COMMON_OBJ $CUDA_DXT_COMMON_OBJ"
|
||||
ADD_MODULE("vdecompress_gpujpeg_to_dxt", $GPUJPEG_TO_DXT_OBJ, "$GPUJPEG_TO_DXT_LIB")
|
||||
AC_DEFINE([HAVE_GPUJPEG_TO_DXT], [1], [Build with GPUJPEG DXT transcode support])
|
||||
@@ -2444,35 +2444,21 @@ jack_trans=no
|
||||
jack=no
|
||||
|
||||
AC_ARG_ENABLE(jack-transport,
|
||||
[ --enable-jack-transport[=force] enable JACK transport (default is auto; disabled in modular build, can be forced)]
|
||||
[ --enable-jack-transport[=force] enable JACK transport (default is auto)]
|
||||
[ Requires: jack],
|
||||
[jack_trans_req=$enableval],
|
||||
[jack_trans_req=$build_default])
|
||||
|
||||
if test $jack_trans_req = yes -a $build_libraries = yes
|
||||
then
|
||||
AC_MSG_ERROR([JACK transport is currently incompatible with modular build]);
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADER(jack/jack.h, FOUND_JACK_H=yes, FOUND_JACK_H=no)
|
||||
AC_CHECK_LIB(jack, jack_client_new, [FOUND_JACK_L=yes]
|
||||
[JACK_LIB=-ljack], FOUND_JACK_L=no)
|
||||
if test $FOUND_JACK_L = no; then
|
||||
# Windows
|
||||
AC_CHECK_LIB(libjack64, jack_client_new, [FOUND_JACK_L=yes]
|
||||
[JACK_LIB=-llibjack64], FOUND_JACK_L=no)
|
||||
fi
|
||||
|
||||
if test $jack_trans_req != no -a $FOUND_JACK_H = yes -a $FOUND_JACK_L = yes -a \( $build_libraries = no -o $jack_trans_req = force \)
|
||||
if test $jack_trans_req != no -a $FOUND_JACK_H = yes
|
||||
then
|
||||
JACK_TRANS_OBJ="src/audio/jack.o"
|
||||
JACK_TRANS_LIB="$JACK_LIB"
|
||||
AC_DEFINE([HAVE_JACK_TRANS], [1], [Build with JACK transport support])
|
||||
jack_trans=yes
|
||||
fi
|
||||
AC_SUBST(JACK_TRANS_OBJ)
|
||||
AC_SUBST(JACK_TRANS_LIB)
|
||||
AC_SUBST(JACK_TRANS_INC)
|
||||
|
||||
# sound system
|
||||
AC_ARG_ENABLE(jack,
|
||||
@@ -2481,14 +2467,14 @@ AC_ARG_ENABLE(jack,
|
||||
[jack_req=$enableval],
|
||||
[jack_req=$build_default])
|
||||
|
||||
if test $jack_req != no -a $FOUND_JACK_H = yes -a $FOUND_JACK_L = yes
|
||||
if test $jack_req != no -a $FOUND_JACK_H = yes
|
||||
then
|
||||
JACK_CAP_OBJ="src/audio/capture/jack.o"
|
||||
JACK_PLAY_OBJ="src/audio/playback/jack.o"
|
||||
AC_DEFINE([HAVE_JACK], [1], [Build with JACK support])
|
||||
jack=yes
|
||||
ADD_MODULE("acap_jack", "$JACK_CAP_OBJ", "$JACK_LIB")
|
||||
ADD_MODULE("aplay_jack", "$JACK_PLAY_OBJ", "$JACK_LIB")
|
||||
ADD_MODULE("acap_jack", "$JACK_CAP_OBJ", "")
|
||||
ADD_MODULE("aplay_jack", "$JACK_PLAY_OBJ", "")
|
||||
fi
|
||||
|
||||
if test $jack = yes -a $speex = no
|
||||
|
||||
@@ -44,9 +44,6 @@ while read -r x; do
|
||||
continue
|
||||
fi
|
||||
NAME=$(echo "$x" | awk '{ print $1 }')
|
||||
if [ "$NAME" = libjack.so.0 ]; then # JACK is currently handled in AppRun
|
||||
continue
|
||||
fi
|
||||
EXCLUDE_LIST="$EXCLUDE_LIST $NAME"
|
||||
done < excludelist
|
||||
for n in $EXCLUDE_LIST; do
|
||||
|
||||
@@ -2,40 +2,10 @@
|
||||
|
||||
set -u
|
||||
|
||||
get_loader() {
|
||||
LOADERS='/lib64/ld-linux-*so* /lib/ld-linux-*so* /lib*/ld-linux-*so*'
|
||||
for n in $LOADERS; do
|
||||
for m in `ls $n`; do
|
||||
if [ -x $m ]; then
|
||||
echo $m
|
||||
return
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
set_ld_preload() {
|
||||
if [ ! -f $DIR/lib/ultragrid/ultragrid_aplay_jack.so ]; then
|
||||
return
|
||||
fi
|
||||
local LOADER=$(get_loader)
|
||||
if [ ! -x "$LOADER" ]; then
|
||||
return
|
||||
fi
|
||||
S_LD_LIBRARY_PATH=$LD_LIBRARY_PATH
|
||||
LD_LIBRARY_PATH=
|
||||
JACK_LIB=$(LD_TRACE_LOADED_OBJECTS=1 $LOADER $DIR/lib/ultragrid/ultragrid_aplay_jack.so | grep libjack | grep -v 'not found' | awk '{print $3}')
|
||||
LD_LIBRARY_PATH=$S_LD_LIBRARY_PATH
|
||||
if [ -n "$JACK_LIB" ]; then
|
||||
export LD_PRELOAD=$JACK_LIB${LD_PRELOAD:+" $LD_PRELOAD"}
|
||||
fi
|
||||
}
|
||||
|
||||
DIR=`dirname $0`
|
||||
export LD_LIBRARY_PATH=$DIR/lib${LD_LIBRARY_PATH:+":$LD_LIBRARY_PATH"}
|
||||
# there is an issue with running_from_path() which evaluates this executable
|
||||
# as being system-installed
|
||||
#export PATH=$DIR/bin:$PATH
|
||||
set_ld_preload
|
||||
|
||||
exec $DIR/bin/uv "$@"
|
||||
|
||||
111
doc/PERFORMANCE-TUNING.md
Normal file
111
doc/PERFORMANCE-TUNING.md
Normal file
@@ -0,0 +1,111 @@
|
||||
Performance Tuning
|
||||
==================
|
||||
|
||||
Network
|
||||
-------
|
||||
|
||||
If transmitting *uncompressed video* stream to achieve optimal performance
|
||||
with high definition video, it may be necessary to tune your system's
|
||||
network parameters to more aggressive values than used by default.
|
||||
|
||||
A key factor affecting performance is the path MTU. It is unlikely that
|
||||
the system will sustain gigabit rates with the 1500 octet Ethernet MTU.
|
||||
If using a gigabit Ethernet you may be able to improve performance by
|
||||
setting an 8192 octet MTU on the interface, provided all intermediate
|
||||
hops on the path from sender to receiver support the large MTU.
|
||||
|
||||
UltraGrid attempts to increase the UDP receive socket buffer from the
|
||||
default value (typically 64 kilobytes) to 4/6 megabytes. If successful,
|
||||
this will make the system more robust to scheduling variations and
|
||||
better able to accept bursty packet arrivals. UltraGrid will notify
|
||||
you if it cannot increase buffers. You should follow those instructions
|
||||
and set your system according to it.
|
||||
|
||||
Interrupt processing load on the receiver host may be significant when
|
||||
running at high rates. Depending on your network interface hardware it
|
||||
may be possible to coalesce interrupts to reduce this load, although
|
||||
the settings to do this are highly driver dependent. On FreeBSD, the
|
||||
use of network device polling may also help performance: see the man
|
||||
page for "polling" in section 4 of the manual.
|
||||
|
||||
In many cases, the performance of your network interface card may be
|
||||
limited by host bus performance (this is particularly an issue at high
|
||||
rates, for example when using HD format video).
|
||||
|
||||
|
||||
Display devices
|
||||
---------------
|
||||
|
||||
If using a HW grabbing card (eg. DVS) as a display device, the
|
||||
key factor limiting performance is PCI bus contention. Ensure that
|
||||
the grabbing card is on a separate PCI bus to the network card --
|
||||
this typically requires a server class motherboard. On Linux, the
|
||||
PCI bus topology can be displayed using "lspci -tv", for example:
|
||||
|
||||
[root@ormal root]# lspci -tv
|
||||
-+-[03]---06.0 Xilinx, Inc.: Unknown device d150
|
||||
+-[01]-+-02.0-[02]--+-04.0 Adaptec 7899P
|
||||
| | \-04.1 Adaptec 7899P
|
||||
| \-0e.0 3Com Corporation 3c985 1000BaseSX
|
||||
\-[00]-+-00.0 ServerWorks CNB20HE
|
||||
+-00.1 ServerWorks CNB20HE
|
||||
+-00.2 ServerWorks: Unknown device 0006
|
||||
+-00.3 ServerWorks: Unknown device 0006
|
||||
+-04.0 Intel Corporation 82557 [Ethernet Pro 100]
|
||||
+-0e.0 ATI Technologies Inc Rage XL
|
||||
+-0f.0 ServerWorks OSB4
|
||||
\-0f.1 ServerWorks: Unknown device 0211
|
||||
[root@ormal root]#
|
||||
|
||||
showing an DVS card on PCI bus [03] (the card shows as a Xilinx
|
||||
device) and a gigabit Ethernet card on PCI bus [02] (the 3Com entry).
|
||||
|
||||
For software display, you can use SDL or OpenGL display. Both are
|
||||
accelerated (Mac and Linux) if you have properly configured video
|
||||
drivers. On Linux, basic operability can be checked with following
|
||||
commands. If configured properly, both should display driver
|
||||
properties:
|
||||
[root@ormal root]# glxinfo
|
||||
<-- output omitted -->
|
||||
and for SDL (accelerated through XVideo:
|
||||
[root@ormal root]# xvinfo
|
||||
<-- output omitted -->
|
||||
|
||||
If you intend to use some of DXT compressions, recommended driver
|
||||
is OpenGL, which can display it natively. When using other display
|
||||
drivers, decompression is still done throught OpenGL and then displayed
|
||||
with requested video driver.
|
||||
|
||||
|
||||
Other Factors
|
||||
-------------
|
||||
|
||||
**Note:** This is left only as a legacy behavior - currently UltraGrid
|
||||
is intended to run without _real-time_ priority (although still being
|
||||
able to compiled with it). This may not be recommended in a general case,
|
||||
however.
|
||||
|
||||
The UltraGrid system will attempt to enable POSIX real-time scheduling
|
||||
to improve performance. This behaviour is disabled by default now, because
|
||||
it can occupy the whole system when enabled, but it can be stil enabled by
|
||||
'--enable-rt' configure option. If you see the message:
|
||||
|
||||
WARNING: Unable to set real-time scheduling
|
||||
|
||||
when starting the application, this means that the operating system did
|
||||
not permit it to enable real-time scheduling. The application will run,
|
||||
but with reduced performance. The most likely reason for failure to set
|
||||
realtime scheduling is that the application has insufficient privilege:
|
||||
it should either be run by root, or be made setuid root. A similar
|
||||
message:
|
||||
|
||||
WARNING: System does not support real-time scheduling
|
||||
|
||||
indicates that your operating system does not support POSIX real-time
|
||||
scheduling. The application will still run, but performance may be less
|
||||
than desired.
|
||||
|
||||
|
||||
You can find more operating system tweaks at this page:
|
||||
https://github.com/CESNET/UltraGrid/wiki/OS-Setup-UltraGrid
|
||||
|
||||
@@ -1,35 +1,26 @@
|
||||
/**
|
||||
* @file audio/capture/jack.c
|
||||
* @author Martin Pulec <pulec@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* FILE: audio/capture/jack.c
|
||||
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
|
||||
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
|
||||
* Petr Holub <hopet@ics.muni.cz>
|
||||
* Milos Liska <xliska@fi.muni.cz>
|
||||
* Jiri Matela <matela@ics.muni.cz>
|
||||
* Dalibor Matura <255899@mail.muni.cz>
|
||||
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
|
||||
*
|
||||
* Copyright (c) 2005-2010 CESNET z.s.p.o.
|
||||
* Copyright (c) 2012-2020 CESNET z.s.p.o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, is permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
*
|
||||
* 2. 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.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
*
|
||||
* This product includes software developed by CESNET z.s.p.o.
|
||||
*
|
||||
* 4. Neither the name of CESNET nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific
|
||||
* prior written permission.
|
||||
*
|
||||
*
|
||||
* 3. Neither the name of CESNET nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
@@ -42,8 +33,6 @@
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -51,6 +40,10 @@
|
||||
#include "config_unix.h"
|
||||
#include "config_win32.h"
|
||||
#endif
|
||||
|
||||
#define MAX_PORTS 64
|
||||
#define MOD_NAME "[JACK capture] "
|
||||
|
||||
#include "debug.h"
|
||||
#include "host.h"
|
||||
|
||||
@@ -65,13 +58,12 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_PORTS 64
|
||||
#define MOD_NAME "[JACK capture] "
|
||||
|
||||
static int jack_samplerate_changed_callback(jack_nframes_t nframes, void *arg);
|
||||
static int jack_process_callback(jack_nframes_t nframes, void *arg);
|
||||
|
||||
struct state_jack_capture {
|
||||
struct libjack_connection *libjack;
|
||||
|
||||
struct audio_frame frame;
|
||||
jack_client_t *client;
|
||||
jack_port_t *input_ports[MAX_PORTS];
|
||||
@@ -103,7 +95,7 @@ static int jack_process_callback(jack_nframes_t nframes, void *arg)
|
||||
}
|
||||
|
||||
for (i = 0; i < s->frame.ch_count; ++i) {
|
||||
jack_default_audio_sample_t *in = jack_port_get_buffer(s->input_ports[i], nframes);
|
||||
jack_default_audio_sample_t *in = s->libjack->port_get_buffer(s->input_ports[i], nframes);
|
||||
mux_channel(s->tmp, (char *) in, sizeof(int32_t), channel_size, s->frame.ch_count, i, 1.0);
|
||||
}
|
||||
|
||||
@@ -160,6 +152,11 @@ static void * audio_cap_jack_init(const char *cfg)
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to allocate memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
s->libjack = open_libjack();
|
||||
if (s->libjack == NULL) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *dup = strdup(cfg);
|
||||
assert(dup != NULL);
|
||||
@@ -191,13 +188,13 @@ static void * audio_cap_jack_init(const char *cfg)
|
||||
free(dup);
|
||||
dup = NULL;
|
||||
|
||||
s->client = jack_client_open(client_name, JackNullOption, &status);
|
||||
s->client = s->libjack->client_open(client_name, JackNullOption, &status);
|
||||
if(status & JackFailure) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Opening JACK client failed.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ports = jack_get_ports(s->client, source_name, NULL, JackPortIsOutput);
|
||||
ports = s->libjack->get_ports(s->client, source_name, NULL, JackPortIsOutput);
|
||||
if(ports == NULL) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to output ports matching \"%s\".\n", source_name);
|
||||
goto release_client;
|
||||
@@ -218,7 +215,7 @@ static void * audio_cap_jack_init(const char *cfg)
|
||||
if (audio_capture_sample_rate) {
|
||||
log_msg(LOG_LEVEL_WARNING, "[JACK capture] Ignoring user specified sample rate!\n");
|
||||
}
|
||||
s->frame.sample_rate = jack_get_sample_rate (s->client);
|
||||
s->frame.sample_rate = s->libjack->get_sample_rate (s->client);
|
||||
s->frame.max_size = s->frame.ch_count * s->frame.bps * s->frame.sample_rate;
|
||||
s->frame.data = malloc(s->frame.max_size);
|
||||
|
||||
@@ -226,17 +223,17 @@ static void * audio_cap_jack_init(const char *cfg)
|
||||
|
||||
s->data = ring_buffer_init(s->frame.max_size);
|
||||
|
||||
if(jack_set_sample_rate_callback(s->client, jack_samplerate_changed_callback, (void *) s)) {
|
||||
if (s->libjack->set_sample_rate_callback(s->client, jack_samplerate_changed_callback, (void *) s)) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Registring callback problem.\n");
|
||||
goto release_client;
|
||||
}
|
||||
|
||||
if(jack_set_process_callback(s->client, jack_process_callback, (void *) s) != 0) {
|
||||
if (s->libjack->set_process_callback(s->client, jack_process_callback, (void *) s) != 0) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Process callback registration problem.\n");
|
||||
goto release_client;
|
||||
}
|
||||
|
||||
if(jack_activate(s->client)) {
|
||||
if (s->libjack->activate(s->client)) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot activate client.\n");
|
||||
goto release_client;
|
||||
}
|
||||
@@ -247,9 +244,9 @@ static void * audio_cap_jack_init(const char *cfg)
|
||||
|
||||
for(port = 0; port < s->frame.ch_count; port++) {
|
||||
snprintf(name, 32, "capture_%02u", port);
|
||||
s->input_ports[port] = jack_port_register(s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
|
||||
s->input_ports[port] = s->libjack->port_register(s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
|
||||
/* attach ports */
|
||||
if(jack_connect(s->client, ports[port], jack_port_name(s->input_ports[port]))) {
|
||||
if (s->libjack->connect(s->client, ports[port], s->libjack->port_name(s->input_ports[port]))) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot connect input ports.\n");
|
||||
}
|
||||
}
|
||||
@@ -262,8 +259,9 @@ static void * audio_cap_jack_init(const char *cfg)
|
||||
return s;
|
||||
|
||||
release_client:
|
||||
jack_client_close(s->client);
|
||||
s->libjack->client_close(s->client);
|
||||
error:
|
||||
close_libjack(s->libjack);
|
||||
free(dup);
|
||||
free(s);
|
||||
return NULL;
|
||||
@@ -286,10 +284,11 @@ static void audio_cap_jack_done(void *state)
|
||||
{
|
||||
struct state_jack_capture *s = (struct state_jack_capture *) state;
|
||||
|
||||
jack_client_close(s->client);
|
||||
s->libjack->client_close(s->client);
|
||||
free(s->tmp);
|
||||
ring_buffer_destroy(s->data);
|
||||
free(s->frame.data);
|
||||
close_libjack(s->libjack);
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @author Martin Pulec <pulec@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2011-2019 CESNET, z. s. p. o.
|
||||
* Copyright (c) 2011-2020 CESNET, z. s. p. o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -34,6 +34,11 @@
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @todo
|
||||
* It looks like there is no jack_stop()?
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
@@ -49,6 +54,7 @@
|
||||
|
||||
#include "audio/audio.h"
|
||||
#include "audio/jack.h"
|
||||
#include "jack_common.h"
|
||||
#include "pthread.h"
|
||||
#include "rtp/rtp.h"
|
||||
#include "rtp/pbuf.h"
|
||||
@@ -57,8 +63,11 @@
|
||||
#define BUFF_ELEM (1<<16)
|
||||
#define BUFF_SIZE (BUFF_ELEM * sizeof(float))
|
||||
#define MAX_PORTS 8
|
||||
#define MOD_NAME "[JACK trans.] "
|
||||
|
||||
struct state_jack {
|
||||
struct libjack_connection *libjack;
|
||||
|
||||
unsigned int sender:1,
|
||||
receiver:1;
|
||||
|
||||
@@ -102,7 +111,7 @@ int jack_process_callback(jack_nframes_t nframes, void *arg) {
|
||||
|
||||
int to_end = BUFF_SIZE - s->play_buffer_start;
|
||||
jack_default_audio_sample_t *out =
|
||||
jack_port_get_buffer (s->output_port[i], nframes);
|
||||
s->libjack->port_get_buffer (s->output_port[i], nframes);
|
||||
if(to_end > send_b) {
|
||||
memcpy (out, s->play_buffer[i] + s->play_buffer_start,
|
||||
send_b);
|
||||
@@ -119,7 +128,7 @@ int jack_process_callback(jack_nframes_t nframes, void *arg) {
|
||||
for(i = 0; i < s->record.ch_count; ++i) {
|
||||
int j;
|
||||
jack_default_audio_sample_t *in =
|
||||
jack_port_get_buffer (s->input_port[i], nframes);
|
||||
s->libjack->port_get_buffer (s->input_port[i], nframes);
|
||||
for(j = 0; j < (int) nframes; ++j) {
|
||||
*(int *)(void *)(s->rec_buffer + ((s->rec_buffer_end + (j * s->record.ch_count + i) * sizeof(int32_t)) % BUFF_SIZE)) =
|
||||
in[j] * INT_MAX;
|
||||
@@ -146,13 +155,13 @@ void reconfigure_send_ch_count(struct state_jack *s, int ch_count)
|
||||
|
||||
s->out_channel_count = s->out_channel_count_req = ch_count;
|
||||
|
||||
if ((ports = jack_get_ports (s->client, s->out_port_pattern, NULL, JackPortIsInput)) == NULL) {
|
||||
fprintf(stderr, "Cannot find any ports matching pattern '%s'\n", s->out_port_pattern);
|
||||
if ((ports = s->libjack->get_ports (s->client, s->out_port_pattern, NULL, JackPortIsInput)) == NULL) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot find any ports matching pattern '%s'\n", s->out_port_pattern);
|
||||
s->out_channel_count = 0;
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < s->record.ch_count; ++i) {
|
||||
jack_disconnect(s->client, jack_port_name (s->output_port[i]), ports[i]);
|
||||
s->libjack->disconnect(s->client, s->libjack->port_name (s->output_port[i]), ports[i]);
|
||||
free(s->play_buffer[i]);
|
||||
}
|
||||
|
||||
@@ -160,21 +169,20 @@ void reconfigure_send_ch_count(struct state_jack *s, int ch_count)
|
||||
while (ports[i]) ++i;
|
||||
|
||||
if(i < s->out_channel_count) {
|
||||
fprintf(stderr, "Not enought output ports found matching pattern '%s': "
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Not enought output ports found matching pattern '%s': "
|
||||
"%d requested, %d found\n", s->out_port_pattern, s->record.ch_count, i);
|
||||
fprintf(stderr, "Reducing port count to %d\n", i);
|
||||
log_msg(LOG_LEVEL_WARNING, MOD_NAME "Reducing port count to %d\n", i);
|
||||
s->out_channel_count = i;
|
||||
}
|
||||
|
||||
for(i = 0; i < s->out_channel_count; ++i) {
|
||||
fprintf(stderr, "%s\n\n\n", ports[i]);
|
||||
if (jack_connect (s->client, jack_port_name (s->output_port[i]), ports[i])) {
|
||||
fprintf (stderr, "cannot connect output ports\n");
|
||||
if (s->libjack->connect (s->client, s->libjack->port_name (s->output_port[i]), ports[i])) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot connect output ports: %s\n", ports[i]);
|
||||
}
|
||||
s->play_buffer[i] = malloc(BUFF_SIZE);
|
||||
}
|
||||
|
||||
fprintf(stderr, "[JACK] Sending %d output audio streams (ports).\n", s->out_channel_count);
|
||||
log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Sending %d output audio streams (ports).\n", s->out_channel_count);
|
||||
|
||||
free (ports);
|
||||
}
|
||||
@@ -234,21 +242,21 @@ static int attach_input_ports(struct state_jack *s)
|
||||
{
|
||||
int i = 0;
|
||||
const char **ports;
|
||||
if ((ports = jack_get_ports (s->client, s->in_port_pattern, NULL, JackPortIsOutput)) == NULL) {
|
||||
fprintf(stderr, "Cannot find any ports matching pattern '%s'\n", s->in_port_pattern);
|
||||
if ((ports = s->libjack->get_ports (s->client, s->in_port_pattern, NULL, JackPortIsOutput)) == NULL) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot find any ports matching pattern '%s'\n", s->in_port_pattern);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (ports[i]) ++i;
|
||||
if(i < s->record.ch_count) {
|
||||
fprintf(stderr, "Not enought input ports found matching pattern '%s': "
|
||||
"%d requested, %d found\n", s->in_port_pattern, s->record.ch_count, i);
|
||||
fprintf(stderr, "Reducing port count to %d\n", i);
|
||||
s->record.ch_count = i;
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Not enought input ports found matching pattern '%s': "
|
||||
"%d requested, %d found\n", s->in_port_pattern, s->record.ch_count, i);
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Reducing port count to %d\n", i);
|
||||
s->record.ch_count = i;
|
||||
}
|
||||
|
||||
for(i = 0; i < s->in_ch_count; ++i) {
|
||||
if (jack_connect (s->client, ports[i], jack_port_name (s->input_port[i]))) {
|
||||
if (s->libjack->connect (s->client, ports[i], s->libjack->port_name (s->input_port[i]))) {
|
||||
fprintf (stderr, "cannot connect input ports\n");
|
||||
}
|
||||
}
|
||||
@@ -262,6 +270,12 @@ void * jack_start(const char *cfg)
|
||||
struct state_jack *s;
|
||||
|
||||
s = (struct state_jack *) malloc(sizeof(struct state_jack));
|
||||
assert (s != NULL);
|
||||
s->libjack = open_libjack();
|
||||
if (s->libjack == NULL) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->in_port_pattern = NULL;
|
||||
s->out_port_pattern = NULL;
|
||||
@@ -276,25 +290,23 @@ void * jack_start(const char *cfg)
|
||||
int ret = settings_init(s, cfg_copy);
|
||||
free(cfg_copy);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Setting JACK failed. Check configuration ('-j' option).\n");
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!s->sender && !s->receiver) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->client = jack_client_open(CLIENT_NAME, JackNullOption, NULL);
|
||||
if(jack_set_process_callback(s->client, jack_process_callback, (void *) s) != 0) {
|
||||
fprintf(stderr, "[jack] Callback initialization problem.\n");
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Setting JACK failed. Check configuration ('-j' option).\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(jack_set_sample_rate_callback(s->client,
|
||||
if(!s->sender && !s->receiver) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
s->client = s->libjack->client_open(CLIENT_NAME, JackNullOption, NULL);
|
||||
if(s->libjack->set_process_callback(s->client, jack_process_callback, (void *) s) != 0) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Callback initialization problem.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(s->libjack->set_sample_rate_callback(s->client,
|
||||
jack_samplerate_changed_callback, (void *) s)) {
|
||||
fprintf(stderr, "[jack] Callback initialization problem.\n");
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Sample rate callback initialization problem.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -306,7 +318,7 @@ void * jack_start(const char *cfg)
|
||||
|
||||
for(i = 0; i < MAX_PORTS; ++i) {
|
||||
snprintf(name, 30, "out_%02u", i);
|
||||
s->output_port[i] = jack_port_register (s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
||||
s->output_port[i] = s->libjack->port_register (s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
||||
}
|
||||
|
||||
s->out_channel_count = s->out_channel_count_req = 0;
|
||||
@@ -318,16 +330,16 @@ void * jack_start(const char *cfg)
|
||||
|
||||
for(i = 0; i < s->in_ch_count; ++i) {
|
||||
snprintf(name, 30, "in_%02u", i);
|
||||
s->input_port[i] = jack_port_register (s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
|
||||
s->input_port[i] = s->libjack->port_register (s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
|
||||
}
|
||||
|
||||
s->record.sample_rate = jack_get_sample_rate (s->client);
|
||||
s->record.sample_rate = s->libjack->get_sample_rate (s->client);
|
||||
s->record.bps = sizeof(int32_t);
|
||||
s->record.ch_count = s->in_ch_count;
|
||||
s->rec_buffer = s->record.data = (void *) malloc(BUFF_SIZE);
|
||||
}
|
||||
|
||||
if (jack_activate (s->client)) {
|
||||
if (s->libjack->activate (s->client)) {
|
||||
fprintf (stderr, "cannot activate client");
|
||||
goto error;
|
||||
}
|
||||
@@ -338,7 +350,9 @@ void * jack_start(const char *cfg)
|
||||
}
|
||||
|
||||
return s;
|
||||
error:
|
||||
error:
|
||||
close_libjack(s->libjack);
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @author Martin Pulec <pulec@cesnet.cz>
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2012-2019 CESNET z.s.p.o.
|
||||
* Copyright (c) 2012-2020 CESNET z.s.p.o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -41,6 +41,11 @@
|
||||
#include "config_win32.h"
|
||||
#endif
|
||||
|
||||
#define DEFAULT_AUDIO_BUF_LEN_MS 50
|
||||
#define MAX_LEN_MS 1000
|
||||
#define MAX_PORTS 64
|
||||
#define MOD_NAME "[JACK playback] "
|
||||
|
||||
#include "audio/audio.h"
|
||||
#include "audio/audio_playback.h"
|
||||
#include "audio/utils.h"
|
||||
@@ -56,13 +61,9 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEFAULT_AUDIO_BUF_LEN_MS 50
|
||||
#define MAX_LEN_MS 1000
|
||||
#define MAX_PORTS 64
|
||||
#define MOD_NAME "[JACK playback] "
|
||||
|
||||
|
||||
struct state_jack_playback {
|
||||
struct libjack_connection *libjack;
|
||||
|
||||
char *jack_ports_pattern;
|
||||
int jack_sample_rate;
|
||||
jack_client_t *client;
|
||||
@@ -116,7 +117,7 @@ static int jack_process_callback(jack_nframes_t nframes, void *arg)
|
||||
|
||||
for (int i = 0; i < s->desc.ch_count; ++i) {
|
||||
jack_default_audio_sample_t *out =
|
||||
jack_port_get_buffer (s->output_port[i], nframes_available);
|
||||
s->libjack->port_get_buffer (s->output_port[i], nframes_available);
|
||||
assert(out != NULL);
|
||||
demux_channel((char *) out, s->tmp, sizeof(float), len, s->desc.ch_count, i);
|
||||
}
|
||||
@@ -172,6 +173,12 @@ static void * audio_play_jack_init(const char *cfg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->libjack = open_libjack();
|
||||
if (s->libjack == NULL) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *dup = strdup(cfg);
|
||||
assert(dup != NULL);
|
||||
char *tmp = dup, *item, *save_ptr;
|
||||
@@ -203,28 +210,28 @@ static void * audio_play_jack_init(const char *cfg)
|
||||
|
||||
s->jack_ports_pattern = strdup(source_name);
|
||||
|
||||
s->client = jack_client_open(client_name, JackNullOption, &status);
|
||||
s->client = s->libjack->client_open(client_name, JackNullOption, &status);
|
||||
if(status & JackFailure) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Opening JACK client failed.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(jack_set_sample_rate_callback(s->client, jack_samplerate_changed_callback, (void *) s)) {
|
||||
if (s->libjack->set_sample_rate_callback(s->client, jack_samplerate_changed_callback, (void *) s)) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Registering callback problem.\n");
|
||||
goto release_client;
|
||||
}
|
||||
|
||||
|
||||
if(jack_set_process_callback(s->client, jack_process_callback, (void *) s) != 0) {
|
||||
if (s->libjack->set_process_callback(s->client, jack_process_callback, (void *) s) != 0) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Process callback registration problem.\n");
|
||||
goto release_client;
|
||||
}
|
||||
|
||||
s->jack_sample_rate = jack_get_sample_rate (s->client);
|
||||
s->jack_sample_rate = s->libjack->get_sample_rate (s->client);
|
||||
log_msg(LOG_LEVEL_INFO, "JACK sample rate: %d\n", s->jack_sample_rate);
|
||||
|
||||
|
||||
ports = jack_get_ports(s->client, s->jack_ports_pattern, NULL, JackPortIsInput);
|
||||
ports = s->libjack->get_ports(s->client, s->jack_ports_pattern, NULL, JackPortIsInput);
|
||||
if(ports == NULL) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to input ports matching %s.\n", s->jack_ports_pattern);
|
||||
goto release_client;
|
||||
@@ -240,7 +247,7 @@ static void * audio_play_jack_init(const char *cfg)
|
||||
|
||||
for(i = 0; i < MAX_PORTS; ++i) {
|
||||
snprintf(name, 30, "playback_%02u", i);
|
||||
s->output_port[i] = jack_port_register (s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
||||
s->output_port[i] = s->libjack->port_register (s->client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,8 +255,9 @@ static void * audio_play_jack_init(const char *cfg)
|
||||
return s;
|
||||
|
||||
release_client:
|
||||
jack_client_close(s->client);
|
||||
s->libjack->client_close(s->client);
|
||||
error:
|
||||
close_libjack(s->libjack);
|
||||
free(dup);
|
||||
free(s);
|
||||
return NULL;
|
||||
@@ -296,9 +304,9 @@ static int audio_play_jack_reconfigure(void *state, struct audio_desc desc)
|
||||
|
||||
assert(desc.bps == 4 && desc.sample_rate == s->jack_sample_rate && desc.codec == AC_PCM);
|
||||
|
||||
jack_deactivate(s->client);
|
||||
s->libjack->deactivate(s->client);
|
||||
|
||||
ports = jack_get_ports(s->client, s->jack_ports_pattern, NULL, JackPortIsInput);
|
||||
ports = s->libjack->get_ports(s->client, s->jack_ports_pattern, NULL, JackPortIsInput);
|
||||
if(ports == NULL) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to input ports matching %s.\n", s->jack_ports_pattern);
|
||||
return FALSE;
|
||||
@@ -335,7 +343,7 @@ static int audio_play_jack_reconfigure(void *state, struct audio_desc desc)
|
||||
|
||||
/* for all channels previously connected */
|
||||
for(i = 0; i < desc.ch_count; ++i) {
|
||||
jack_disconnect(s->client, jack_port_name (s->output_port[i]), ports[i]);
|
||||
s->libjack->disconnect(s->client, s->libjack->port_name (s->output_port[i]), ports[i]);
|
||||
log_msg(LOG_LEVEL_INFO, MOD_NAME "Port %d: %s\n", i, ports[i]);
|
||||
}
|
||||
free(s->tmp);
|
||||
@@ -348,13 +356,13 @@ static int audio_play_jack_reconfigure(void *state, struct audio_desc desc)
|
||||
s->tmp = malloc(s->max_channel_len);
|
||||
s->converted = malloc(desc.ch_count * s->max_channel_len);
|
||||
|
||||
if(jack_activate(s->client)) {
|
||||
if (s->libjack->activate(s->client)) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot activate client.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for(i = 0; i < desc.ch_count; ++i) {
|
||||
if (jack_connect (s->client, jack_port_name (s->output_port[i]), ports[i])) {
|
||||
if (s->libjack->connect (s->client, s->libjack->port_name (s->output_port[i]), ports[i])) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot connect output port: %d.\n", i);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -383,7 +391,7 @@ static void audio_play_jack_done(void *state)
|
||||
{
|
||||
struct state_jack_playback *s = (struct state_jack_playback *) state;
|
||||
|
||||
jack_client_close(s->client);
|
||||
s->libjack->client_close(s->client);
|
||||
free(s->tmp);
|
||||
free(s->converted);
|
||||
free(s->jack_ports_pattern);
|
||||
@@ -391,6 +399,8 @@ static void audio_play_jack_done(void *state)
|
||||
s->buffer_fns->destroy(s->data);
|
||||
}
|
||||
|
||||
close_libjack(s->libjack);
|
||||
|
||||
free(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,11 +39,117 @@
|
||||
#ifndef JACK_COMMON_H
|
||||
#define JACK_COMMON_H
|
||||
|
||||
#include <stdio.h>
|
||||
#ifndef _WIN32
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <jack/jack.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "lib_common.h"
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef int (*jack_activate_t)(jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef int (*jack_client_close_t)(jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef jack_client_t *(*jack_client_open_t)(const char *client_name,
|
||||
jack_options_t options,
|
||||
jack_status_t *status, ...) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef int (*jack_connect_t)(jack_client_t *client,
|
||||
const char *source_port,
|
||||
const char *destination_port) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef int (*jack_deactivate_t)(jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef int (*jack_disconnect_t)(jack_client_t *client,
|
||||
const char *source_port,
|
||||
const char *destination_port) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef void (*jack_free_t)(void* ptr) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef const char **(*jack_get_ports_t)(jack_client_t *client,
|
||||
const char *port_name_pattern,
|
||||
const char *type_name_pattern,
|
||||
unsigned long flags) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef jack_nframes_t (*jack_get_sample_rate_t)(jack_client_t *) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef void * (*jack_port_get_buffer_t)(jack_port_t *port, jack_nframes_t) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef const char * (*jack_port_name_t)(const jack_port_t *port) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef jack_port_t * (*jack_port_register_t)(jack_client_t *client,
|
||||
const char *port_name,
|
||||
const char *port_type,
|
||||
unsigned long flags,
|
||||
unsigned long buffer_size) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef int (*jack_set_process_callback_t)(jack_client_t *client,
|
||||
JackProcessCallback process_callback,
|
||||
void *arg) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
typedef int (*jack_set_sample_rate_callback_t)(jack_client_t *client,
|
||||
JackSampleRateCallback srate_callback,
|
||||
void *arg) JACK_OPTIONAL_WEAK_EXPORT;
|
||||
|
||||
struct libjack_connection {
|
||||
LIB_HANDLE libjack; ///< lib connection
|
||||
|
||||
jack_activate_t activate;
|
||||
jack_client_close_t client_close;
|
||||
jack_client_open_t client_open;
|
||||
jack_connect_t connect;
|
||||
jack_deactivate_t deactivate;
|
||||
jack_disconnect_t disconnect;
|
||||
jack_free_t free;
|
||||
jack_get_ports_t get_ports;
|
||||
jack_get_sample_rate_t get_sample_rate;
|
||||
jack_port_get_buffer_t port_get_buffer;
|
||||
jack_port_name_t port_name;
|
||||
jack_port_register_t port_register;
|
||||
jack_set_process_callback_t set_process_callback;
|
||||
jack_set_sample_rate_callback_t set_sample_rate_callback;
|
||||
};
|
||||
|
||||
static void close_libjack(struct libjack_connection *s)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
dlclose(s->libjack);
|
||||
free(s);
|
||||
}
|
||||
|
||||
#define JACK_DLSYM(sym) s->sym = (void *) dlsym(s->libjack, "jack_" #sym); if (s->sym == NULL) { log_msg(LOG_LEVEL_ERROR, "JACK symbol %s not found: %s\n", "jack_" #sym, dlerror()); close_libjack(s); return NULL; }
|
||||
|
||||
static struct libjack_connection *open_libjack(void)
|
||||
{
|
||||
struct libjack_connection *s = calloc(1, sizeof(struct libjack_connection));
|
||||
const char *shlib =
|
||||
#ifdef _WIN32
|
||||
"C:/Windows/libjack64.dll";
|
||||
#elif defined (__APPLE__)
|
||||
"libjack.dylib";
|
||||
#elif defined (__linux__)
|
||||
"libjack.so";
|
||||
#else
|
||||
"";
|
||||
#endif
|
||||
s->libjack = dlopen(shlib, RTLD_NOW);
|
||||
if (s->libjack == NULL) {
|
||||
log_msg(LOG_LEVEL_ERROR, "JACK library \"%s\" opening failed: %s\n", shlib, dlerror());
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
JACK_DLSYM(activate);
|
||||
JACK_DLSYM(client_close)
|
||||
JACK_DLSYM(client_open)
|
||||
JACK_DLSYM(connect);
|
||||
JACK_DLSYM(deactivate);
|
||||
JACK_DLSYM(disconnect);
|
||||
JACK_DLSYM(free)
|
||||
JACK_DLSYM(get_ports)
|
||||
JACK_DLSYM(get_sample_rate);
|
||||
JACK_DLSYM(set_sample_rate_callback);
|
||||
JACK_DLSYM(port_get_buffer);
|
||||
JACK_DLSYM(port_name);
|
||||
JACK_DLSYM(port_register);
|
||||
JACK_DLSYM(set_process_callback);
|
||||
return s;
|
||||
}
|
||||
|
||||
static inline struct device_info *audio_jack_probe(const char *client_name,
|
||||
unsigned long port_flags,
|
||||
int *count)
|
||||
@@ -52,29 +158,33 @@ static inline struct device_info *audio_jack_probe(const char *client_name,
|
||||
jack_status_t status;
|
||||
char *last_name = NULL;
|
||||
int i;
|
||||
int channel_count;
|
||||
const char **ports;
|
||||
int port_count = 0;
|
||||
struct device_info *available_devices = NULL;
|
||||
|
||||
*count = 0;
|
||||
client = jack_client_open(client_name, JackNullOption, &status);
|
||||
if(status & JackFailure) {
|
||||
fprintf(stderr, "[JACK playback] Opening JACK client failed.\n");
|
||||
struct libjack_connection *libjack = open_libjack();
|
||||
if (!libjack) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ports = jack_get_ports(client, NULL, NULL, port_flags);
|
||||
*count = 0;
|
||||
client = libjack->client_open(client_name, JackNullOption, &status);
|
||||
if(status & JackFailure) {
|
||||
log_msg(LOG_LEVEL_ERROR, "Opening JACK client failed.\n");
|
||||
close_libjack(libjack);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ports = libjack->get_ports(client, NULL, NULL, port_flags);
|
||||
if(ports == NULL) {
|
||||
fprintf(stderr, "[JACK playback] Unable to enumerate ports.\n");
|
||||
log_msg(LOG_LEVEL_ERROR, "Unable to enumerate JACK ports.\n");
|
||||
close_libjack(libjack);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(port_count = 0; ports[port_count] != NULL; port_count++);
|
||||
|
||||
available_devices = calloc(port_count, sizeof(struct device_info));
|
||||
struct device_info *available_devices = port_count > 0 ? calloc(port_count, sizeof(struct device_info)) : NULL;
|
||||
|
||||
channel_count = 0;
|
||||
int channel_count = 0;
|
||||
for(i = 0; ports[i] != NULL; i++) {
|
||||
char *item = strdup(ports[i]);
|
||||
assert(item != NULL);
|
||||
@@ -104,8 +214,9 @@ static inline struct device_info *audio_jack_probe(const char *client_name,
|
||||
(*count)++;
|
||||
}
|
||||
free(last_name);
|
||||
jack_free(ports);
|
||||
jack_client_close(client);
|
||||
libjack->free(ports);
|
||||
libjack->client_close(client);
|
||||
close_libjack(libjack);
|
||||
|
||||
return available_devices;
|
||||
}
|
||||
|
||||
@@ -38,8 +38,36 @@
|
||||
#ifndef LIB_COMMON_H
|
||||
#define LIB_COMMON_H
|
||||
|
||||
#include "config_unix.h"
|
||||
#include "config_win32.h"
|
||||
|
||||
#include "host.h" // UNIQUE_NAME
|
||||
|
||||
#ifdef _WIN32
|
||||
#define LIB_HANDLE HMODULE
|
||||
#define dlopen(name, flags) LoadLibraryA(name)
|
||||
#define dlsym GetProcAddress
|
||||
#define dlclose FreeLibrary
|
||||
#if !defined __cplusplus && !defined thread_local
|
||||
#define thread_local _Thread_local
|
||||
#endif
|
||||
static char *dlerror(void) ATTRIBUTE(unused);
|
||||
|
||||
static char *dlerror(void) {
|
||||
thread_local static char buf[1024] = "(unknown)";
|
||||
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, // flags
|
||||
NULL, // lpsource
|
||||
GetLastError(), // message id
|
||||
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // languageid
|
||||
buf, // output buffer
|
||||
sizeof buf, // size of msgbuf, bytes
|
||||
NULL); // va_list of arguments
|
||||
return buf;
|
||||
}
|
||||
#else // ! defined _WIN32
|
||||
#define LIB_HANDLE void *
|
||||
#endif // defined _WIN32
|
||||
|
||||
/** @brief This macro causes that this module will be statically linked with UltraGrid. */
|
||||
#define MK_STATIC(A) A, NULL
|
||||
#define MK_STATIC_REF(A) &A, NULL
|
||||
|
||||
@@ -1624,6 +1624,29 @@ static void yuv444p_to_uyvy(char * __restrict dst_buffer, AVFrame * __restrict i
|
||||
}
|
||||
}
|
||||
|
||||
static void yuv444p16le_to_uyvy(char * __restrict dst_buffer, AVFrame * __restrict in_frame,
|
||||
int width, int height, int pitch, int * __restrict rgb_shift)
|
||||
{
|
||||
UNUSED(rgb_shift);
|
||||
for(int y = 0; y < height; ++y) {
|
||||
unsigned char *src_y = (unsigned char *) in_frame->data[0] + in_frame->linesize[0] * y + 1;
|
||||
unsigned char *src_cb = (unsigned char *) in_frame->data[1] + in_frame->linesize[1] * y + 1;
|
||||
unsigned char *src_cr = (unsigned char *) in_frame->data[2] + in_frame->linesize[2] * y + 1;
|
||||
unsigned char *dst = (unsigned char *) dst_buffer + pitch * y;
|
||||
|
||||
OPTIMIZED_FOR (int x = 0; x < width / 2; ++x) {
|
||||
*dst++ = (*src_cb + *(src_cb + 2)) / 2;
|
||||
src_cb += 4;
|
||||
*dst++ = *src_y;
|
||||
src_y += 2;
|
||||
*dst++ = (*src_cr + *(src_cr + 2)) / 2;
|
||||
src_cr += 4;
|
||||
*dst++ = *src_y;
|
||||
src_y += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void yuv444p_to_v210(char * __restrict dst_buffer, AVFrame * __restrict in_frame,
|
||||
int width, int height, int pitch, int * __restrict rgb_shift)
|
||||
{
|
||||
@@ -1667,7 +1690,6 @@ static void yuv444p_to_v210(char * __restrict dst_buffer, AVFrame * __restrict i
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Changes pixel format from planar YUV 422 to packed RGB/A.
|
||||
* Color space is assumed ITU-T Rec. 609. YUV is expected to be full scale (aka in JPEG).
|
||||
@@ -2314,19 +2336,19 @@ static void p010le_to_uyvy(char * __restrict dst_buffer, AVFrame * __restrict in
|
||||
OPTIMIZED_FOR (int x = 0; x < width / 2; ++x) {
|
||||
uint8_t tmp;
|
||||
// U
|
||||
tmp = *src_cbcr++ >> 2;
|
||||
tmp = *src_cbcr++ >> 8;
|
||||
*dst1++ = tmp;
|
||||
*dst2++ = tmp;
|
||||
// Y
|
||||
*dst1++ = *src_y1++ >> 2;
|
||||
*dst2++ = *src_y2++ >> 2;
|
||||
*dst1++ = *src_y1++ >> 8;
|
||||
*dst2++ = *src_y2++ >> 8;
|
||||
// V
|
||||
tmp = *src_cbcr++ >> 2;
|
||||
tmp = *src_cbcr++ >> 8;
|
||||
*dst1++ = tmp;
|
||||
*dst2++ = tmp;
|
||||
// Y
|
||||
*dst1++ = *src_y1++ >> 2;
|
||||
*dst2++ = *src_y2++ >> 2;
|
||||
*dst1++ = *src_y1++ >> 8;
|
||||
*dst2++ = *src_y2++ >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2376,8 +2398,8 @@ const struct uv_to_av_conversion *get_uv_to_av_conversions() {
|
||||
{ R10k, AV_PIX_FMT_YUV444P10LE, AVCOL_SPC_BT709, AVCOL_RANGE_MPEG, r10k_to_yuv444p10le },
|
||||
{ R10k, AV_PIX_FMT_YUV444P12LE, AVCOL_SPC_BT709, AVCOL_RANGE_MPEG, r10k_to_yuv444p12le },
|
||||
{ R10k, AV_PIX_FMT_YUV444P16LE, AVCOL_SPC_BT709, AVCOL_RANGE_MPEG, r10k_to_yuv444p16le },
|
||||
{ R12L, AV_PIX_FMT_YUV444P16LE, AVCOL_SPC_BT709, AVCOL_RANGE_MPEG, r12l_to_yuv444p10le },
|
||||
{ R12L, AV_PIX_FMT_YUV444P16LE, AVCOL_SPC_BT709, AVCOL_RANGE_MPEG, r12l_to_yuv444p12le },
|
||||
{ R12L, AV_PIX_FMT_YUV444P10LE, AVCOL_SPC_BT709, AVCOL_RANGE_MPEG, r12l_to_yuv444p10le },
|
||||
{ R12L, AV_PIX_FMT_YUV444P12LE, AVCOL_SPC_BT709, AVCOL_RANGE_MPEG, r12l_to_yuv444p12le },
|
||||
{ R12L, AV_PIX_FMT_YUV444P16LE, AVCOL_SPC_BT709, AVCOL_RANGE_MPEG, r12l_to_yuv444p16le },
|
||||
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 15, 100) // FFMPEG commit c2869b4640f
|
||||
{ v210, AV_PIX_FMT_P010LE, AVCOL_SPC_BT709, AVCOL_RANGE_MPEG, v210_to_p010le },
|
||||
@@ -2443,12 +2465,11 @@ const struct av_to_uv_conversion *get_av_to_uv_conversions() {
|
||||
{AV_PIX_FMT_YUV422P10LE, RGB, yuv422p10le_to_rgb24, false},
|
||||
{AV_PIX_FMT_YUV422P10LE, RGBA, yuv422p10le_to_rgb32, false},
|
||||
{AV_PIX_FMT_YUV444P10LE, v210, yuv444p10le_to_v210, true},
|
||||
{AV_PIX_FMT_YUV444P16LE, v210, yuv444p16le_to_v210, true},
|
||||
{AV_PIX_FMT_YUV444P10LE, UYVY, yuv444p10le_to_uyvy, false},
|
||||
{AV_PIX_FMT_YUV444P10LE, R10k, yuv444p10le_to_r10k, false},
|
||||
{AV_PIX_FMT_YUV444P10LE, RGB, yuv444p10le_to_rgb24, false},
|
||||
{AV_PIX_FMT_YUV444P10LE, RGBA, yuv444p10le_to_rgb32, false},
|
||||
{AV_PIX_FMT_YUV444P16LE, R12L, yuv444p10le_to_r12l, false},
|
||||
{AV_PIX_FMT_YUV444P10LE, R12L, yuv444p10le_to_r12l, false},
|
||||
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 15, 100) // FFMPEG commit c2869b4640f
|
||||
{AV_PIX_FMT_P010LE, v210, p010le_to_v210, true},
|
||||
{AV_PIX_FMT_P010LE, UYVY, p010le_to_uyvy, true},
|
||||
@@ -2484,13 +2505,15 @@ const struct av_to_uv_conversion *get_av_to_uv_conversions() {
|
||||
// 8-bit YUV (NV12)
|
||||
{AV_PIX_FMT_NV12, UYVY, nv12_to_uyvy, true},
|
||||
{AV_PIX_FMT_NV12, RGB, nv12_to_rgb24, false},
|
||||
{AV_PIX_FMT_NV12, RGB, nv12_to_rgb32, false},
|
||||
{AV_PIX_FMT_NV12, RGBA, nv12_to_rgb32, false},
|
||||
// 12-bit YUV
|
||||
{AV_PIX_FMT_YUV444P12LE, R10k, yuv444p12le_to_r10k, false},
|
||||
{AV_PIX_FMT_YUV444P16LE, R12L, yuv444p12le_to_r12l, false},
|
||||
{AV_PIX_FMT_YUV444P12LE, R12L, yuv444p12le_to_r12l, false},
|
||||
// 16-bit YUV
|
||||
{AV_PIX_FMT_YUV444P16LE, R10k, yuv444p16le_to_r10k, false},
|
||||
{AV_PIX_FMT_YUV444P16LE, R12L, yuv444p16le_to_r12l, false},
|
||||
{AV_PIX_FMT_YUV444P16LE, UYVY, yuv444p16le_to_uyvy, false},
|
||||
{AV_PIX_FMT_YUV444P16LE, v210, yuv444p16le_to_v210, false},
|
||||
// RGB
|
||||
{AV_PIX_FMT_GBRP, RGB, gbrp_to_rgb, true},
|
||||
{AV_PIX_FMT_GBRP, RGBA, gbrp_to_rgba, true},
|
||||
@@ -2539,14 +2562,17 @@ av_to_uv_convert_p get_av_to_uv_conversion(int av_codec, codec_t uv_codec) {
|
||||
*/
|
||||
struct SwsContext *getSwsContext(unsigned int SrcW, unsigned int SrcH, enum AVPixelFormat SrcFormat, unsigned int DstW, unsigned int DstH, enum AVPixelFormat DstFormat, int64_t Flags) {
|
||||
struct SwsContext *Context = sws_alloc_context();
|
||||
// 0 = limited range, 1 = full range
|
||||
int SrcRange = 1;
|
||||
int DstRange = 1;
|
||||
|
||||
if (!Context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct AVPixFmtDescriptor *SrcFormatDesc = av_pix_fmt_desc_get(SrcFormat);
|
||||
const struct AVPixFmtDescriptor *DstFormatDesc = av_pix_fmt_desc_get(DstFormat);
|
||||
|
||||
// 0 = limited range, 1 = full range
|
||||
int SrcRange = SrcFormatDesc != NULL && (SrcFormatDesc->flags & AV_PIX_FMT_FLAG_RGB) != 0 ? 1 : 0;
|
||||
int DstRange = DstFormatDesc != NULL && (DstFormatDesc->flags & AV_PIX_FMT_FLAG_RGB) != 0 ? 1 : 0;
|
||||
|
||||
av_opt_set_int(Context, "sws_flags", Flags, 0);
|
||||
av_opt_set_int(Context, "srcw", SrcW, 0);
|
||||
av_opt_set_int(Context, "srch", SrcH, 0);
|
||||
|
||||
@@ -292,7 +292,7 @@ static void crash_signal_handler(int sig)
|
||||
*ptr++ = PACKAGE_BUGREPORT[i];
|
||||
}
|
||||
*ptr++ = '.'; *ptr++ = '\n';
|
||||
const char message3[] = "You may find some tips how to report bugs in file REPORTING-BUGS distributed with ";
|
||||
const char message3[] = "You may find some tips how to report bugs in file doc/reporting_bugs.md distributed with ";
|
||||
for (size_t i = 0; i < sizeof message3 - 1; ++i) {
|
||||
*ptr++ = message3[i];
|
||||
}
|
||||
|
||||
@@ -526,6 +526,7 @@ int
|
||||
pbuf_decode(struct pbuf *playout_buf, std::chrono::high_resolution_clock::time_point const & curr_time,
|
||||
decode_frame_t decode_func, void *data)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
/* Find the first complete frame that has reached it's playout */
|
||||
/* time, and decode it into the framebuffer. Mark the frame as */
|
||||
/* decoded, but otherwise leave it in the playout buffer. */
|
||||
@@ -545,6 +546,9 @@ pbuf_decode(struct pbuf *playout_buf, std::chrono::high_resolution_clock::time_p
|
||||
curr->decoded = 1;
|
||||
return ret;
|
||||
} else {
|
||||
if (curr_time > curr->playout_time + 1s) {
|
||||
curr->completed = true;
|
||||
}
|
||||
debug_msg
|
||||
("Unable to decode frame due to missing data (RTP TS=%u)\n",
|
||||
curr->rtp_timestamp);
|
||||
|
||||
@@ -64,24 +64,15 @@
|
||||
#define MOD_NAME "[XIMEA] "
|
||||
#define MICROSEC_IN_SEC 1000000.0
|
||||
|
||||
#ifdef WIN32
|
||||
#define LIB_HANDLE HINSTANCE
|
||||
#define dlopen(name, flags) LoadLibraryA(name)
|
||||
#define dlsym GetProcAddress
|
||||
#define dlclose FreeLibrary
|
||||
#else
|
||||
#define LIB_HANDLE void *
|
||||
#endif
|
||||
|
||||
struct ximea_functions {
|
||||
XIAPI XI_RETURN __cdecl (*xiGetNumberDevices)(OUT PDWORD pNumberDevices);
|
||||
XIAPI XI_RETURN __cdecl (*xiGetDeviceInfoString)(IN DWORD DevId, const char* prm, char* value, DWORD value_size);
|
||||
XIAPI XI_RETURN __cdecl (*xiOpenDevice)(IN DWORD DevId, OUT PHANDLE hDevice);
|
||||
XIAPI XI_RETURN __cdecl (*xiSetParamInt)(IN HANDLE hDevice, const char* prm, const int val);
|
||||
XIAPI XI_RETURN __cdecl (*xiStartAcquisition)(IN HANDLE hDevice);
|
||||
XIAPI XI_RETURN __cdecl (*xiGetImage)(IN HANDLE hDevice, IN DWORD timeout, OUT LPXI_IMG img);
|
||||
XIAPI XI_RETURN __cdecl (*xiStopAcquisition)(IN HANDLE hDevice);
|
||||
XIAPI XI_RETURN __cdecl (*xiCloseDevice)(IN HANDLE hDevice);
|
||||
XI_RETURN __cdecl (*xiGetNumberDevices)(OUT PDWORD pNumberDevices);
|
||||
XI_RETURN __cdecl (*xiGetDeviceInfoString)(IN DWORD DevId, const char* prm, char* value, DWORD value_size);
|
||||
XI_RETURN __cdecl (*xiOpenDevice)(IN DWORD DevId, OUT PHANDLE hDevice);
|
||||
XI_RETURN __cdecl (*xiSetParamInt)(IN HANDLE hDevice, const char* prm, const int val);
|
||||
XI_RETURN __cdecl (*xiStartAcquisition)(IN HANDLE hDevice);
|
||||
XI_RETURN __cdecl (*xiGetImage)(IN HANDLE hDevice, IN DWORD timeout, OUT LPXI_IMG img);
|
||||
XI_RETURN __cdecl (*xiStopAcquisition)(IN HANDLE hDevice);
|
||||
XI_RETURN __cdecl (*xiCloseDevice)(IN HANDLE hDevice);
|
||||
LIB_HANDLE handle;
|
||||
};
|
||||
|
||||
@@ -95,9 +86,9 @@ struct state_vidcap_ximea {
|
||||
};
|
||||
|
||||
#define GET_SYMBOL(sym) do {\
|
||||
f->sym = dlsym(f->handle, #sym);\
|
||||
f->sym = (void *) dlsym(f->handle, #sym);\
|
||||
if (f->sym == NULL) {\
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to find symbol %s\n", #sym);\
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to find symbol %s: %s\n", #sym, dlerror());\
|
||||
return false;\
|
||||
}\
|
||||
} while(0)
|
||||
|
||||
@@ -143,6 +143,9 @@ static void deconfigure(struct state_libavcodec_decompress *s)
|
||||
#ifdef HAVE_SWSCALE
|
||||
s->sws.ctx = NULL;
|
||||
sws_freeContext(s->sws.ctx);
|
||||
if (s->sws.frame) {
|
||||
av_freep(s->sws.frame->data);
|
||||
}
|
||||
av_frame_free(&s->sws.frame);
|
||||
#endif // defined HAVE_SWSCALE
|
||||
}
|
||||
@@ -423,6 +426,13 @@ static int libavcodec_decompress_reconfigure(void *state, struct video_desc desc
|
||||
}
|
||||
|
||||
static bool has_conversion(enum AVPixelFormat pix_fmt, codec_t *ug_pix_fmt) {
|
||||
{
|
||||
codec_t mapped_pix_fmt = get_av_to_ug_pixfmt(pix_fmt);
|
||||
if (mapped_pix_fmt != VIDEO_CODEC_NONE) {
|
||||
*ug_pix_fmt = mapped_pix_fmt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const struct av_to_uv_conversion *c = get_av_to_uv_conversions(); c->uv_codec != VIDEO_CODEC_NONE; c++) {
|
||||
if (c->av_codec != pix_fmt) { // this conversion is not valid
|
||||
@@ -497,8 +507,21 @@ static enum AVPixelFormat get_format_callback(struct AVCodecContext *s __attribu
|
||||
}
|
||||
#endif
|
||||
|
||||
// directly mapped UG codecs
|
||||
for (const enum AVPixelFormat *fmt_it = fmt; *fmt_it != AV_PIX_FMT_NONE; fmt_it++) {
|
||||
codec_t mapped_pix_fmt = get_av_to_ug_pixfmt(*fmt_it);
|
||||
if (mapped_pix_fmt != VIDEO_CODEC_NONE) {
|
||||
if (state->out_codec == VIDEO_CODEC_NONE) { // just probing internal format
|
||||
state->internal_codec = mapped_pix_fmt;
|
||||
return AV_PIX_FMT_NONE;
|
||||
}
|
||||
if (state->out_codec == mapped_pix_fmt) {
|
||||
state->internal_codec = mapped_pix_fmt;
|
||||
return *fmt_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool use_native[] = { true, false }; // try native first
|
||||
|
||||
for (const bool *use_native_it = use_native; use_native_it !=
|
||||
use_native + sizeof use_native / sizeof use_native[0]; ++use_native_it) {
|
||||
for (const enum AVPixelFormat *fmt_it = fmt; *fmt_it != AV_PIX_FMT_NONE; fmt_it++) {
|
||||
@@ -542,40 +565,56 @@ static enum AVPixelFormat get_format_callback(struct AVCodecContext *s __attribu
|
||||
}
|
||||
|
||||
#ifdef HAVE_SWSCALE
|
||||
static bool lavd_sws_convert_reconfigure(struct state_libavcodec_decompress_sws *sws, enum AVPixelFormat sws_in_codec,
|
||||
enum AVPixelFormat sws_out_codec, int width, int height)
|
||||
{
|
||||
if (sws->width == width && sws->height == height && sws->in_codec == sws_in_codec && sws->ctx != NULL) {
|
||||
return true;
|
||||
}
|
||||
log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Using swscale to convert from %s to %s.\n",
|
||||
av_get_pix_fmt_name(sws_in_codec), av_get_pix_fmt_name(sws_out_codec));
|
||||
sws_freeContext(sws->ctx);
|
||||
if (sws->frame) {
|
||||
av_freep(sws->frame->data);
|
||||
}
|
||||
av_frame_free(&sws->frame);
|
||||
sws->ctx = getSwsContext(width, height, sws_in_codec,
|
||||
width, height, sws_out_codec,
|
||||
SWS_POINT);
|
||||
if(!sws->ctx){
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to init sws context.\n");
|
||||
return false;
|
||||
}
|
||||
sws->frame = av_frame_alloc();
|
||||
if (!sws->frame) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Could not allocate sws frame\n");
|
||||
return false;
|
||||
}
|
||||
sws->frame->width = width;
|
||||
sws->frame->height = height;
|
||||
sws->frame->format = sws_out_codec;
|
||||
int ret = av_image_alloc(sws->frame->data, sws->frame->linesize,
|
||||
sws->frame->width, sws->frame->height,
|
||||
sws_out_codec, 32);
|
||||
if (ret < 0) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Could not allocate raw picture buffer for sws\n");
|
||||
return false;
|
||||
}
|
||||
sws->width = width;
|
||||
sws->height = height;
|
||||
sws->in_codec = sws_in_codec;
|
||||
sws->out_codec = sws_out_codec;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lavd_sws_convert(struct state_libavcodec_decompress_sws *sws, enum AVPixelFormat sws_in_codec,
|
||||
enum AVPixelFormat sws_out_codec, int width, int height, AVFrame *in_frame)
|
||||
{
|
||||
if (sws->width != width || sws->height != height|| sws->in_codec != sws_in_codec || sws->ctx == NULL) {
|
||||
log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Attempting to use swscale to convert.\n");
|
||||
sws_freeContext(sws->ctx);
|
||||
av_frame_free(&sws->frame);
|
||||
sws->ctx = getSwsContext(width, height, sws_in_codec,
|
||||
width, height, sws_out_codec,
|
||||
SWS_POINT);
|
||||
if(!sws->ctx){
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to init sws context.\n");
|
||||
return false;
|
||||
}
|
||||
sws->frame = av_frame_alloc();
|
||||
if (!sws->frame) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Could not allocate sws frame\n");
|
||||
return false;
|
||||
}
|
||||
sws->frame->width = width;
|
||||
sws->frame->height = height;
|
||||
sws->frame->format = sws_out_codec;
|
||||
int ret = av_image_alloc(sws->frame->data, sws->frame->linesize,
|
||||
sws->frame->width, sws->frame->height,
|
||||
sws_out_codec, 32);
|
||||
if (ret < 0) {
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Could not allocate raw picture buffer for sws\n");
|
||||
return false;
|
||||
}
|
||||
sws->width = width;
|
||||
sws->height = height;
|
||||
sws->in_codec = sws_in_codec;
|
||||
sws->out_codec = sws_out_codec;
|
||||
if (!lavd_sws_convert_reconfigure(sws, sws_in_codec, sws_out_codec, width, height)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sws_scale(sws->ctx,
|
||||
(const uint8_t * const *) in_frame->data,
|
||||
in_frame->linesize,
|
||||
@@ -584,6 +623,36 @@ static bool lavd_sws_convert(struct state_libavcodec_decompress_sws *sws, enum A
|
||||
sws->frame->data,
|
||||
sws->frame->linesize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Converts directly to out_buffer (instead to sws->frame). This is used for directly mapped
|
||||
/// UltraGrid pixel formats that can be decoded directly to framebuffer.
|
||||
static bool lavd_sws_convert_to_buffer(struct state_libavcodec_decompress_sws *sws, enum AVPixelFormat sws_in_codec,
|
||||
enum AVPixelFormat sws_out_codec, int width, int height, AVFrame *in_frame, char *out_buffer)
|
||||
{
|
||||
if (!lavd_sws_convert_reconfigure(sws, sws_in_codec, sws_out_codec, width, height)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct AVFrame *out = av_frame_alloc();
|
||||
codec_t ug_out_pixfmt = get_av_to_ug_pixfmt(sws_out_codec);
|
||||
if (codec_is_planar(ug_out_pixfmt)) {
|
||||
buf_get_planes(width, height, ug_out_pixfmt, out_buffer, (char **) out->data);
|
||||
buf_get_linesizes(width, ug_out_pixfmt, out->linesize);
|
||||
} else {
|
||||
out->data[0] = (unsigned char *) out_buffer;
|
||||
out->linesize[0] = vc_get_linesize(width, ug_out_pixfmt);
|
||||
}
|
||||
|
||||
sws_scale(sws->ctx,
|
||||
(const uint8_t * const *) in_frame->data,
|
||||
in_frame->linesize,
|
||||
0,
|
||||
in_frame->height,
|
||||
out->data,
|
||||
out->linesize);
|
||||
av_frame_free(&out);
|
||||
return true;
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -608,6 +677,15 @@ static int change_pixfmt(AVFrame *frame, unsigned char *dst, int av_codec, codec
|
||||
int pitch, int rgb_shift[static restrict 3], struct state_libavcodec_decompress_sws *sws) {
|
||||
av_to_uv_convert_p convert = NULL;
|
||||
|
||||
if (get_av_to_ug_pixfmt(av_codec) == out_codec) {
|
||||
if (!codec_is_planar(out_codec)) {
|
||||
memcpy(dst, frame->data[0], vc_get_datalen(width, height, out_codec));
|
||||
return TRUE;
|
||||
}
|
||||
log_msg(LOG_LEVEL_ERROR, MOD_NAME "Planar pixfmts not support here, please report a bug!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (const struct av_to_uv_conversion *c = get_av_to_uv_conversions(); c->uv_codec != VIDEO_CODEC_NONE; c++) {
|
||||
if (c->av_codec == av_codec && c->uv_codec == out_codec) {
|
||||
convert = c->convert;
|
||||
@@ -620,8 +698,14 @@ static int change_pixfmt(AVFrame *frame, unsigned char *dst, int av_codec, codec
|
||||
}
|
||||
|
||||
#ifdef HAVE_SWSCALE
|
||||
if (get_ug_to_av_pixfmt(out_codec) != AV_PIX_FMT_NONE) {
|
||||
lavd_sws_convert_to_buffer(sws, av_codec, get_ug_to_av_pixfmt(out_codec), width, height, frame, (char *) dst);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// else try to find swscale
|
||||
enum AVPixelFormat sws_out_codec = 0;
|
||||
|
||||
bool native[2] = { true, false };
|
||||
for (int n = 0; n < 2; n++) {
|
||||
for (const struct av_to_uv_conversion *c = get_av_to_uv_conversions(); c->uv_codec != VIDEO_CODEC_NONE; c++) {
|
||||
|
||||
@@ -207,7 +207,7 @@ static int display_ndi_putf(void *state, struct video_frame *frame, int flag)
|
||||
NDI_video_frame.p_data = (uint8_t *) frame->tiles[0].data;
|
||||
NDI_video_frame.frame_rate_N = get_framerate_n(frame->fps);
|
||||
NDI_video_frame.frame_rate_D = get_framerate_d(frame->fps);
|
||||
NDI_video_frame.frame_format_type = frame->interlacing = PROGRESSIVE ? NDIlib_frame_format_type_progressive : NDIlib_frame_format_type_interleaved;
|
||||
NDI_video_frame.frame_format_type = frame->interlacing == PROGRESSIVE ? NDIlib_frame_format_type_progressive : NDIlib_frame_format_type_interleaved;
|
||||
NDI_video_frame.timecode = NDIlib_send_timecode_synthesize;
|
||||
|
||||
NDIlib_send_send_video_v2(s->pNDI_send, &NDI_video_frame);
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <condition_variable>
|
||||
#include <cstdint>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
@@ -377,7 +377,8 @@ static int display_sdl2_reconfigure(void *state, struct video_desc desc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const unordered_map<codec_t, uint32_t, hash<int>> pf_mapping = {
|
||||
struct ug_to_sdl_pf { codec_t first; uint32_t second; };
|
||||
static const ug_to_sdl_pf pf_mapping[] = {
|
||||
{ I420, SDL_PIXELFORMAT_IYUV },
|
||||
{ UYVY, SDL_PIXELFORMAT_UYVY },
|
||||
{ YUYV, SDL_PIXELFORMAT_YUY2 },
|
||||
@@ -390,19 +391,42 @@ static const unordered_map<codec_t, uint32_t, hash<int>> pf_mapping = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool create_texture(struct state_sdl2 *s, struct video_desc desc) {
|
||||
uint32_t format;
|
||||
auto it = pf_mapping.find(desc.color_spec);
|
||||
if (it == pf_mapping.end()) {
|
||||
abort();
|
||||
static uint32_t get_ug_to_sdl_format(codec_t ug_codec) {
|
||||
if (ug_codec == R10k) {
|
||||
return SDL_PIXELFORMAT_ARGB2101010;
|
||||
}
|
||||
format = it->second;
|
||||
|
||||
const auto *it = find_if(begin(pf_mapping), end(pf_mapping), [ug_codec](const ug_to_sdl_pf &u) { return u.first == ug_codec; });
|
||||
if (it == end(pf_mapping)) {
|
||||
LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Wrong codec: " << get_codec_name(ug_codec) << "\n";
|
||||
return SDL_PIXELFORMAT_UNKNOWN;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ADD_TO_PARAM("sdl2-r10k",
|
||||
"* sdl2-r10k\n"
|
||||
" Enable 10-bit RGB support for SDL2 (EXPERIMENTAL)\n");
|
||||
|
||||
static auto get_supported_pfs() {
|
||||
vector<codec_t> codecs;
|
||||
codecs.reserve(sizeof pf_mapping / sizeof pf_mapping[0]);
|
||||
|
||||
for (auto item : pf_mapping) {
|
||||
codecs.push_back(item.first);
|
||||
}
|
||||
if (get_commandline_param("sdl2-r10k") != nullptr) {
|
||||
codecs.push_back(R10k);
|
||||
}
|
||||
return codecs;
|
||||
}
|
||||
|
||||
static bool create_texture(struct state_sdl2 *s, struct video_desc desc) {
|
||||
if (s->texture) {
|
||||
SDL_DestroyTexture(s->texture);
|
||||
}
|
||||
|
||||
s->texture = SDL_CreateTexture(s->renderer, format, SDL_TEXTUREACCESS_STREAMING, desc.width, desc.height);
|
||||
s->texture = SDL_CreateTexture(s->renderer, get_ug_to_sdl_format(desc.color_spec), SDL_TEXTUREACCESS_STREAMING, desc.width, desc.height);
|
||||
if (!s->texture) {
|
||||
log_msg(LOG_LEVEL_ERROR, "[SDL] Unable to create texture: %s\n", SDL_GetError());
|
||||
return false;
|
||||
@@ -693,18 +717,14 @@ static int display_sdl2_putf(void *state, struct video_frame *frame, int nonbloc
|
||||
static int display_sdl2_get_property(void *state, int property, void *val, size_t *len)
|
||||
{
|
||||
UNUSED(state);
|
||||
codec_t codecs[pf_mapping.size()];
|
||||
|
||||
int i = 0;
|
||||
for (auto item : pf_mapping) {
|
||||
codecs[i++] = item.first;
|
||||
}
|
||||
auto codecs = get_supported_pfs();
|
||||
size_t codecs_len = codecs.size() * sizeof(codec_t);
|
||||
|
||||
switch (property) {
|
||||
case DISPLAY_PROPERTY_CODECS:
|
||||
if (sizeof(codecs) <= *len) {
|
||||
memcpy(val, codecs, sizeof(codecs));
|
||||
*len = sizeof(codecs);
|
||||
if (codecs_len <= *len) {
|
||||
memcpy(val, codecs.data(), codecs_len);
|
||||
*len = codecs_len;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -456,3 +456,15 @@ void buf_get_planes(int width, int height, codec_t color_spec, char *data, char
|
||||
}
|
||||
}
|
||||
|
||||
void buf_get_linesizes(int width, codec_t color_spec, int *linesize)
|
||||
{
|
||||
int sub[8];
|
||||
codec_get_planes_subsampling(color_spec, sub);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (sub[2 * i] == 0) {
|
||||
break;
|
||||
}
|
||||
linesize[i] = (width + sub[2 * i] - 1) / sub[2 * i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -206,6 +206,7 @@ unsigned int vf_get_data_len(struct video_frame *f);
|
||||
* Works with planar pixel formats only.
|
||||
*/
|
||||
void buf_get_planes(int width, int height, codec_t color_spec, char *data, char **planes);
|
||||
void buf_get_linesizes(int width, codec_t color_spec, int *linesize);
|
||||
|
||||
/** @name Video Flags
|
||||
* @deprecated use rather video_frame or video_desc members
|
||||
|
||||
@@ -51,22 +51,22 @@ ff_codec_conversions_test::tearDown()
|
||||
|
||||
#define TIMER(t) struct timeval t{}; gettimeofday(&(t), nullptr)
|
||||
void
|
||||
ff_codec_conversions_test::test_yuv444p16le_from_to_r10k()
|
||||
ff_codec_conversions_test::test_yuv444pXXle_from_to_r10k()
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
constexpr int width = 1920;
|
||||
constexpr int height = 1080;
|
||||
constexpr int width = 320;
|
||||
constexpr int height = 240;
|
||||
vector <unsigned char> rgba_buf(width * height * 4);
|
||||
|
||||
/// @todo Use 10-bit natively
|
||||
auto test_pattern = [&] {
|
||||
auto test_pattern = [&](AVPixelFormat avfmt) {
|
||||
vector <unsigned char> r10k_buf(width * height * 4);
|
||||
copy(rgba_buf.begin(), rgba_buf.end(), r10k_buf.begin());
|
||||
toR10k(r10k_buf.data(), width, height);
|
||||
|
||||
AVFrame frame;
|
||||
frame.format = AV_PIX_FMT_YUV444P16LE;
|
||||
frame.format = avfmt;
|
||||
frame.width = width;
|
||||
frame.height = height;
|
||||
|
||||
@@ -112,36 +112,38 @@ ff_codec_conversions_test::test_yuv444p16le_from_to_r10k()
|
||||
CPPUNIT_ASSERT_MESSAGE("Maximal allowed difference 1, found "s + to_string(max_diff), max_diff <= 1);
|
||||
};
|
||||
|
||||
int i = 0;
|
||||
for_each(rgba_buf.begin(), rgba_buf.end(), [&](unsigned char & c) { c = (i++ / 4) % 0x100; });
|
||||
test_pattern();
|
||||
for (auto f : { AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_YUV444P12LE, AV_PIX_FMT_YUV444P16LE }) {
|
||||
int i = 0;
|
||||
for_each(rgba_buf.begin(), rgba_buf.end(), [&](unsigned char & c) { c = (i++ / 4) % 0x100; });
|
||||
test_pattern(f);
|
||||
|
||||
array<unsigned char, 4> pattern{ 0xFFU, 0, 0, 0xFFU };
|
||||
for_each(rgba_buf.begin(), rgba_buf.end(), [&](unsigned char & c) { c = pattern[i++ % 4]; });
|
||||
test_pattern();
|
||||
array<unsigned char, 4> pattern{ 0xFFU, 0, 0, 0xFFU };
|
||||
for_each(rgba_buf.begin(), rgba_buf.end(), [&](unsigned char & c) { c = pattern[i++ % 4]; });
|
||||
test_pattern(f);
|
||||
|
||||
default_random_engine rand_gen;
|
||||
for_each(rgba_buf.begin(), rgba_buf.end(), [&](unsigned char & c) { c = rand_gen() % 0x100; });
|
||||
test_pattern();
|
||||
default_random_engine rand_gen;
|
||||
for_each(rgba_buf.begin(), rgba_buf.end(), [&](unsigned char & c) { c = rand_gen() % 0x100; });
|
||||
test_pattern(f);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ff_codec_conversions_test::test_yuv444p16le_from_to_r12l()
|
||||
ff_codec_conversions_test::test_yuv444pXXle_from_to_r12l()
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
|
||||
constexpr int width = 1920;
|
||||
constexpr int height = 1080;
|
||||
constexpr int width = 320;
|
||||
constexpr int height = 240;
|
||||
vector <unsigned char> rgb_buf(width * height * 3);
|
||||
|
||||
/// @todo Use 12-bit natively
|
||||
auto test_pattern = [&] {
|
||||
auto test_pattern = [&](AVPixelFormat avfmt) {
|
||||
vector <unsigned char> r12l_buf(vc_get_datalen(width, height, R12L));
|
||||
decoder_t rgb_to_r12l = get_decoder_from_to(RGB, R12L, true);
|
||||
rgb_to_r12l(r12l_buf.data(), rgb_buf.data(), vc_get_datalen(width, height, R12L), 0, 8, 16);
|
||||
|
||||
AVFrame frame;
|
||||
frame.format = AV_PIX_FMT_YUV444P16LE;
|
||||
frame.format = avfmt;
|
||||
frame.width = width;
|
||||
frame.height = height;
|
||||
|
||||
@@ -186,17 +188,19 @@ ff_codec_conversions_test::test_yuv444p16le_from_to_r12l()
|
||||
CPPUNIT_ASSERT_MESSAGE("Maximal allowed difference 1, found "s + to_string(max_diff), max_diff <= 1);
|
||||
};
|
||||
|
||||
int i = 0;
|
||||
array<unsigned char, 3> pattern{ 0xFFU, 0, 0 };
|
||||
for_each(rgb_buf.begin(), rgb_buf.end(), [&](unsigned char & c) { c = pattern[i++ % 3]; });
|
||||
test_pattern();
|
||||
for (auto f : { AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_YUV444P12LE, AV_PIX_FMT_YUV444P16LE }) {
|
||||
int i = 0;
|
||||
array<unsigned char, 3> pattern{ 0xFFU, 0, 0 };
|
||||
for_each(rgb_buf.begin(), rgb_buf.end(), [&](unsigned char & c) { c = pattern[i++ % 3]; });
|
||||
test_pattern(f);
|
||||
|
||||
for_each(rgb_buf.begin(), rgb_buf.end(), [&](unsigned char & c) { c = (i++ / 3) % 0x100; });
|
||||
test_pattern();
|
||||
for_each(rgb_buf.begin(), rgb_buf.end(), [&](unsigned char & c) { c = (i++ / 3) % 0x100; });
|
||||
test_pattern(f);
|
||||
|
||||
default_random_engine rand_gen;
|
||||
for_each(rgb_buf.begin(), rgb_buf.end(), [&](unsigned char & c) { c = rand_gen() % 0x100; });
|
||||
test_pattern();
|
||||
default_random_engine rand_gen;
|
||||
for_each(rgb_buf.begin(), rgb_buf.end(), [&](unsigned char & c) { c = rand_gen() % 0x100; });
|
||||
test_pattern(f);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined HAVE_CPPUNIT && HAVE_LAVC
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
class ff_codec_conversions_test : public CPPUNIT_NS::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE( ff_codec_conversions_test );
|
||||
CPPUNIT_TEST( test_yuv444p16le_from_to_r10k );
|
||||
CPPUNIT_TEST( test_yuv444p16le_from_to_r12l );
|
||||
CPPUNIT_TEST( test_yuv444pXXle_from_to_r10k );
|
||||
CPPUNIT_TEST( test_yuv444pXXle_from_to_r12l );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
@@ -20,8 +20,8 @@ public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
void test_yuv444p16le_from_to_r10k();
|
||||
void test_yuv444p16le_from_to_r12l();
|
||||
void test_yuv444pXXle_from_to_r10k();
|
||||
void test_yuv444pXXle_from_to_r12l();
|
||||
};
|
||||
|
||||
#endif // defined HAVE_LAVC
|
||||
|
||||
Reference in New Issue
Block a user