diff --git a/.github/actions/download/action.yml b/.github/actions/download/action.yml index 13a8623a..570fdf0d 100644 --- a/.github/actions/download/action.yml +++ b/.github/actions/download/action.yml @@ -10,19 +10,19 @@ inputs: runs: using: composite steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: ${{ inputs.platform }}.env path: ${{ inputs.platform }}.env - name: Env to output shell: bash run: | - sed -i 's/\r//g' ${{ inputs.platform }}.env/${{ inputs.platform }}.env - source ${{ inputs.platform }}.env/${{ inputs.platform }}.env + sed -i 's/\r//g' ${{ inputs.platform }}.env/momo.env + source ${{ inputs.platform }}.env/momo.env echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT echo "$PACKAGE_NAME/$PACKAGE_NAME" >> package_paths.env id: env - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: ${{ steps.env.outputs.package_name }} path: ${{ steps.env.outputs.package_name }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 68b8e863..33dddb93 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,33 +1,28 @@ name: build-workflow on: + workflow_dispatch: push: paths-ignore: - - 'doc/**' - - 'html/**' - - '**.md' - - 'THANKS' - - 'LICENSE' - - 'NOTICE' + - "doc/**" + - "html/**" + - "**.md" + - "THANKS" + - "LICENSE" + - "NOTICE" jobs: build-windows: strategy: fail-fast: false matrix: - arch: - - x86_64 - name: Build momo for Windows_${{ matrix.arch }} - runs-on: windows-2019 + name: + - windows_x86_64 + name: Build momo for ${{ matrix.name }} + runs-on: windows-2022 steps: - uses: actions/checkout@v4 - - uses: microsoft/setup-msbuild@v1.3 - # - uses: GuillaumeFalourd/setup-windows10-sdk-action@v1.11 - # with: - # sdk-version: 20348 - - name: test - run: | - ls "C:\Program Files (x86)\Windows Kits\10\Include\" + - uses: microsoft/setup-msbuild@v2 - name: Get Versions run: | Get-Content "VERSION" | Foreach-Object { @@ -35,148 +30,166 @@ jobs: $var = $_.Split('=') New-Variable -Name $var[0] -Value $var[1] -Force } - echo "boost_version=${BOOST_VERSION}" >> $GITHUB_OUTPUT - echo "wincuda_version=${WINCUDA_VERSION}" >> $GITHUB_OUTPUT + echo "cuda_version=${CUDA_VERSION}" >> ${Env:GITHUB_OUTPUT} id: versions - # Boost はよくダウンロード先に繋がらずエラーになるのでキャッシュする - - name: Cache Boost ${{ steps.versions.outputs.boost_version }} - id: cache-boost - uses: actions/cache@v3 - with: - path: _cache\boost - key: windows-boost-${{ steps.versions.outputs.boost_version }}.zip.v6 # CUDA のインストールバイナリのダウンロードは 3GB ぐらいあって、 # ビルドの度に取得するのはつらいのでキャッシュする # (インストールする nvcc は解凍後で 100MB 程度なのでキャッシュ可能) - - name: Cache NVCC ${{ steps.versions.outputs.wincuda_version }} + - name: Cache CUDA ${{ steps.versions.outputs.cuda_version }} id: cache-cuda - uses: actions/cache@v3 - with: - path: build\windows_x86_64\_install\cuda\nvcc - key: windows-cuda-${{ steps.versions.outputs.wincuda_version }}.v2 - - run: "& .\\build.ps1 -package" - working-directory: build - timeout-minutes: 120 - - name: Output package name + uses: actions/cache@v4 + with: + path: _install\windows_x86_64\release\cuda + key: windows-cuda-${{ steps.versions.outputs.cuda_version }}.v1 + - run: echo "${CUDA_VERSION}" > _install\windows_x86_64\release\cuda.version + if: steps.cache-cuda.outputs.cache-hit == 'true' + - run: python3 run.py --package ${{ matrix.name }} + - name: Get package name run: | - Get-Content "VERSION" | Foreach-Object { + Get-Content "_package\${{ matrix.name }}\release\momo.env" | Foreach-Object { if (!$_) { continue } $var = $_.Split('=') New-Variable -Name $var[0] -Value $var[1] -Force } - $WINVER_MAJOR = [System.Environment]::OSVersion.Version.Major - $RELEASE_ID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseID - echo "PACKAGE_NAME=momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${{ matrix.arch }}.zip" >> windows_${{ matrix.arch }}.env - echo "CONTENT_TYPE=application/zip" >> windows_${{ matrix.arch }}.env - echo "name=momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${{ matrix.arch }}.zip" >> ${Env:GITHUB_OUTPUT} + echo "name=${PACKAGE_NAME}" >> ${Env:GITHUB_OUTPUT} id: package_name - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ steps.package_name.outputs.name }} - path: _package/${{ steps.package_name.outputs.name }} + path: _package/${{ matrix.name }}/release/${{ steps.package_name.outputs.name }} - name: Upload Environment - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: windows_${{ matrix.arch }}.env - path: windows_${{ matrix.arch }}.env + name: ${{ matrix.name }}.env + path: _package/${{ matrix.name }}/release/momo.env build-macos: strategy: fail-fast: false matrix: - arch: - - arm64 - name: Build momo for macOS_${{ matrix.arch }} - runs-on: macos-11.0 + name: + - macos_arm64 + name: Build momo for ${{ matrix.name }} + runs-on: macos-14 steps: - uses: actions/checkout@v4 - - name: Get Versions - run: | - source VERSION - echo "boost_version=${BOOST_VERSION}" >> $GITHUB_OUTPUT - id: versions - - name: Cache Boost ${{ steps.versions.outputs.boost_version }} - id: cache-boost - uses: actions/cache@v3 - with: - path: _cache/boost - key: macos-boost-${{ steps.versions.outputs.boost_version }}.tar.gz.v3 - - run: ./build.sh --package macos_${{ matrix.arch }} - working-directory: build - timeout-minutes: 120 - - name: Output package name - shell: bash + - run: python3 run.py --package ${{ matrix.name }} + - name: Get package name run: | - source VERSION - MACOS_VERSION=`sw_vers -productVersion | cut -d '.' -f-2` - echo "PACKAGE_NAME=momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${{ matrix.arch }}.tar.gz" >> macos_${{ matrix.arch }}.env - echo "CONTENT_TYPE=application/gzip" >> macos_${{ matrix.arch }}.env - echo "name=momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${{ matrix.arch }}.tar.gz" >> $GITHUB_OUTPUT + source _package/${{ matrix.name }}/release/momo.env + echo "name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT id: package_name - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ steps.package_name.outputs.name }} - path: _package/${{ steps.package_name.outputs.name }} + path: _package/${{ matrix.name }}/release/${{ steps.package_name.outputs.name }} - name: Upload Environment - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: macos_${{ matrix.arch }}.env - path: macos_${{ matrix.arch }}.env - build-linux: + name: ${{ matrix.name }}.env + path: _package/${{ matrix.name }}/release/momo.env + build-ubuntu: strategy: fail-fast: false matrix: name: - - raspberry-pi-os_armv6 - - raspberry-pi-os_armv7 - raspberry-pi-os_armv8 - - ubuntu-20.04_x86_64 - - ubuntu-20.04_armv8_jetson_xavier - ubuntu-22.04_x86_64 + - ubuntu-24.04_x86_64 + - ubuntu-22.04_armv8_jetson name: Build momo for ${{ matrix.name }} - runs-on: ubuntu-20.04 + runs-on: ${{ matrix.name == 'ubuntu-24.04_x86_64' && 'ubuntu-24.04' || 'ubuntu-22.04' }} steps: - uses: actions/checkout@v4 - - name: Get Versions + - name: Disk cleanup run: | - source VERSION - echo "boost_version=${BOOST_VERSION}" >> $GITHUB_OUTPUT - id: versions - - name: Cache Boost ${{ steps.versions.outputs.boost_version }} - id: cache-boost - uses: actions/cache@v3 - with: - path: _cache/boost - key: ${{ matrix.name }}-boost-${{ steps.versions.outputs.boost_version }}.tar.gz.v3 - - run: ./build.sh --no-tty --no-mount --package ${{ matrix.name }} - working-directory: build - timeout-minutes: 120 - - name: Output package name - shell: bash + set -x + df -h + sudo du -h -d1 /usr/local + sudo du -h -d1 /usr/local/share + sudo du -h -d1 /usr/local/lib + sudo du -h -d1 /usr/share + RMI=`docker images -q -a` + if [ -n "$RMI" ]; then + docker rmi $RMI + fi + # 4.6G + sudo rm -rf /usr/local/.ghcup + # 1.7G + sudo rm -rf /usr/share/swift + # 1.4G + sudo rm -rf /usr/share/dotnet + df -h + - name: Install deps for Jetson and Raspberry Pi OS series + if: matrix.name == 'ubuntu-22.04_armv8_jetson' || matrix.name == 'raspberry-pi-os_armv8' + run: | + sudo apt-get update + sudo apt-get -y install multistrap binutils-aarch64-linux-gnu + # multistrap に insecure なリポジトリからの取得を許可する設定を入れる + sudo sed -e 's/Apt::Get::AllowUnauthenticated=true/Apt::Get::AllowUnauthenticated=true";\n$config_str .= " -o Acquire::AllowInsecureRepositories=true/' -i /usr/sbin/multistrap + # Ubuntu 24.04 だと libtinfo5 が見つからない問題があるので、その修正 + # ref: https://qiita.com/gengen16k/items/88cf3c18a40a94205fab + - name: Fix CUDA issues for Ubuntu 24.04 + if: matrix.name == 'ubuntu-24.04_x86_64' + run: | + sudo tee /etc/apt/sources.list.d/jammy.list << EOF + deb http://archive.ubuntu.com/ubuntu/ jammy universe + EOF + + sudo tee /etc/apt/preferences.d/pin-jammy <> ${{ matrix.name }}.env - echo "CONTENT_TYPE=application/gzip" >> ${{ matrix.name }}.env - echo "name=momo-${MOMO_VERSION}_${{ matrix.name }}.tar.gz" >> $GITHUB_OUTPUT + # clang-18 と CUDA を入れる + sudo apt-get update + sudo apt-get install -y software-properties-common + + wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-keyring_1.0-1_all.deb + sudo dpkg -i cuda-keyring_*all.deb + sudo apt-get update + DEBIAN_FRONTEND=noninteractive sudo apt-get -y install cuda=$CUDA_VERSION + + wget https://apt.llvm.org/llvm.sh + chmod a+x llvm.sh + sudo ./llvm.sh 18 + + # Intel Media SDK のために libva-dev, libdrm-dev を入れる + DEBIAN_FRONTEND=noninteractive sudo apt-get -y install libva-dev libdrm-dev + # スクリーンキャプチャあたりのためのパッケージを入れる + DEBIAN_FRONTEND=noninteractive sudo apt-get -y install libxrandr-dev libxdamage-dev libxcomposite-dev libxtst-dev + - run: python3 run.py --package ${{ matrix.name }} + - name: Get package name + run: | + source _package/${{ matrix.name }}/release/momo.env + echo "name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT id: package_name - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ steps.package_name.outputs.name }} - path: _package/${{ steps.package_name.outputs.name }} + path: _package/${{ matrix.name }}/release/${{ steps.package_name.outputs.name }} - name: Upload Environment - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.name }}.env - path: ${{ matrix.name }}.env + path: _package/${{ matrix.name }}/release/momo.env + create-release: name: Create Release if: contains(github.ref, 'tags/202') needs: - build-windows - build-macos - - build-linux + - build-ubuntu runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -186,24 +199,18 @@ jobs: - uses: ./.github/actions/download with: platform: macos_arm64 - - uses: ./.github/actions/download - with: - platform: raspberry-pi-os_armv6 - - uses: ./.github/actions/download - with: - platform: raspberry-pi-os_armv7 - uses: ./.github/actions/download with: platform: raspberry-pi-os_armv8 - uses: ./.github/actions/download with: - platform: ubuntu-20.04_x86_64 + platform: ubuntu-22.04_x86_64 - uses: ./.github/actions/download with: - platform: ubuntu-20.04_armv8_jetson_xavier + platform: ubuntu-24.04_x86_64 - uses: ./.github/actions/download with: - platform: ubuntu-22.04_x86_64 + platform: ubuntu-22.04_armv8_jetson - name: Env to output run: | echo "package_paths<> $GITHUB_OUTPUT @@ -211,17 +218,17 @@ jobs: echo "EOF" >> $GITHUB_OUTPUT id: env - name: Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: - files: - ${{ steps.env.outputs.package_paths }} + files: ${{ steps.env.outputs.package_paths }} + prerelease: ${{ contains(github.ref, 'canary') }} notification: name: Slack Notification runs-on: ubuntu-latest needs: - build-windows - build-macos - - build-linux + - build-ubuntu - create-release if: always() steps: @@ -230,9 +237,8 @@ jobs: if: | needs.build-windows.result == 'failure' || needs.build-macos.result == 'failure' || - needs.build-linux.result == 'failure' || - needs.create-release.result == 'failure' || - needs.upload-assets.result == 'failure' + needs.build-ubuntu.result == 'failure' || + needs.create-release.result == 'failure' env: SLACK_CHANNEL: open-momo SLACK_COLOR: danger diff --git a/.github/workflows/daily_build.yml b/.github/workflows/daily_build.yml deleted file mode 100644 index dfb2e81e..00000000 --- a/.github/workflows/daily_build.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: daily-build-workflow -on: - schedule: - # UTCで記述する事、この場合は日本時間 9 時にしたいので -9 して 0 にしてある - - cron: "0 0 * * *" - # 明示的な branch の指定はできず、デフォルト branch の latest commit に対して実行される - # https://help.github.com/en/articles/workflow-syntax-for-github-actions#onschedule - -jobs: - build-windows: - strategy: - fail-fast: false - matrix: - arch: - - x86_64 - name: Build momo for Windows_${{ matrix.arch }} - runs-on: windows-2019 - steps: - - uses: actions/checkout@v4 - - uses: microsoft/setup-msbuild@v1.3 - - name: Get Versions - run: | - Get-Content "VERSION" | Foreach-Object { - if (!$_) { continue } - $var = $_.Split('=') - New-Variable -Name $var[0] -Value $var[1] -Force - } - echo "boost_version=${BOOST_VERSION}" >> ${Env:GITHUB_OUTPUT} - echo "wincuda_version=${WINCUDA_VERSION}" >> ${Env:GITHUB_OUTPUT} - id: versions - - name: Cache Boost ${{ steps.versions.outputs.boost_version }} - id: cache-boost - uses: actions/cache@v3 - with: - path: _cache\boost - key: windows-boost-${{ steps.versions.outputs.boost_version }}.zip.v5 - - name: Cache NVCC ${{ steps.versions.outputs.wincuda_version }} - id: cache-cuda - uses: actions/cache@v3 - with: - path: build\windows_x86_64\_install\cuda\nvcc - key: windows-cuda-${{ steps.versions.outputs.wincuda_version }}.v1 - - run: "& .\\build.ps1 -package" - working-directory: build - timeout-minutes: 120 - build-macos: - strategy: - fail-fast: false - matrix: - arch: - - arm64 - name: Build momo for macOS_${{ matrix.arch }} - runs-on: macos-11.0 - steps: - - uses: actions/checkout@v4 - - name: Get Versions - run: | - source VERSION - echo "boost_version=${BOOST_VERSION}" >> $GITHUB_OUTPUT - id: versions - - name: Cache Boost ${{ steps.versions.outputs.boost_version }} - id: cache-boost - uses: actions/cache@v3 - with: - path: _cache/boost - key: macos-boost-${{ steps.versions.outputs.boost_version }}.tar.gz.v2 - - run: ./build.sh macos_${{ matrix.arch }} - working-directory: build - timeout-minutes: 120 - build-linux: - strategy: - fail-fast: false - matrix: - name: - - raspberry-pi-os_armv6 - - raspberry-pi-os_armv7 - - raspberry-pi-os_armv8 - - ubuntu-20.04_x86_64 - - ubuntu-20.04_armv8_jetson_xavier - - ubuntu-22.04_x86_64 - name: Build momo for ${{ matrix.name }} - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v4 - - name: Get Versions - run: | - source VERSION - echo "boost_version=${BOOST_VERSION}" >> $GITHUB_OUTPUT - id: versions - - name: Cache Boost ${{ steps.versions.outputs.boost_version }} - id: cache-boost - uses: actions/cache@v3 - with: - path: _cache/boost - key: ${{ matrix.name }}-boost-${{ steps.versions.outputs.boost_version }}.tar.gz.v2 - - run: ./build.sh --no-tty --no-mount ${{ matrix.name }} - working-directory: build - timeout-minutes: 120 - notification: - name: Slack Notification - runs-on: ubuntu-latest - needs: - - build-windows - - build-macos - - build-linux - if: always() - steps: - - uses: actions/checkout@v4 - - uses: rtCamp/action-slack-notify@v2 - if: | - needs.build-windows.result == 'failure' || - needs.build-macos.result == 'failure' || - needs.build-linux.result == 'failure' - env: - SLACK_CHANNEL: open-momo - SLACK_COLOR: danger - SLACK_TITLE: Failure build - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.gitignore b/.gitignore index 53070f00..d9bb54c3 100644 --- a/.gitignore +++ b/.gitignore @@ -38,15 +38,8 @@ webrtc_logs_0 .DS_Store *.swp +/__pycache__ /_build /_source /_install /_package -/build/windows_*/_source -/build/windows_*/_build -/build/windows_*/_install -/build/macos_*/_source -/build/macos_*/_build -/build/macos_*/_install - -/src/hwenc_jetson/Nv* diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc new file mode 100644 index 00000000..0dc7f214 --- /dev/null +++ b/.markdownlint.jsonc @@ -0,0 +1,13 @@ +{ + "MD004": { + "style": "dash" + }, + "MD013": { + "line_length": 150, + "code_blocks": false + }, + "MD024": { + "siblings_only": true + }, + "MD036": false +} diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index d1c31daf..c3f1aa4e 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -4,137 +4,113 @@ "name": "Windows", "includePath": [ "${workspaceFolder}/src", - "${workspaceFolder}/NvCodec/include", - "${workspaceFolder}/NvCodec/NvCodec", - "${workspaceFolder}/build/windows_x86_64/_install/webrtc/include", - "${workspaceFolder}/build/windows_x86_64/_install/webrtc/include/third_party/abseil-cpp", - "${workspaceFolder}/build/windows_x86_64/_install/webrtc/include/third_party/boringssl/src/include", - "${workspaceFolder}/build/windows_x86_64/_install/webrtc/include/third_party/libyuv/include", - "${workspaceFolder}/build/windows_x86_64/_install/webrtc/include/third_party/zlib", - "${workspaceFolder}/build/windows_x86_64/_install/boost/include", - "${workspaceFolder}/build/windows_x86_64/_install/CLI11/include", - "${workspaceFolder}/build/windows_x86_64/_install/SDL2/include/SDL2", - "${workspaceFolder}/build/windows_x86_64/_install/cuda/nvcc/include", - "${workspaceFolder}/build/windows_x86_64/_install/msdk/include", - "${workspaceFolder}/_build/windows_x86_64" + "${workspaceFolder}/src/sora-cpp-sdk/include", + "${workspaceFolder}/third_party/NvCodec/include", + "${workspaceFolder}/third_party/NvCodec/NvCodec", + "${workspaceFolder}/_install/windows_x86_64/release/webrtc/include", + "${workspaceFolder}/_install/windows_x86_64/release/webrtc/include/third_party/abseil-cpp", + "${workspaceFolder}/_install/windows_x86_64/release/webrtc/include/third_party/boringssl/src/include", + "${workspaceFolder}/_install/windows_x86_64/release/webrtc/include/third_party/libyuv/include", + "${workspaceFolder}/_install/windows_x86_64/release/webrtc/include/third_party/zlib", + "${workspaceFolder}/_install/windows_x86_64/release/boost/include", + "${workspaceFolder}/_install/windows_x86_64/release/cli11/include", + "${workspaceFolder}/_install/windows_x86_64/release/sdl2/include/SDL2", + "${workspaceFolder}/_install/windows_x86_64/release/vpl/include", + "${workspaceFolder}/_install/windows_x86_64/release/cuda/include", + "${workspaceFolder}/_build/windows_x86_64/release/momo" ], "defines": [ "WIN32_LEAN_AND_MEAN", "NOMINMAX", - "WEBRTC_WINDOWS", - "USE_NVCODEC_ENCODER=1", - "USE_MMAL_ENCODER=0", - "USE_JETSON_ENCODER=0", - "USE_H264=1", - "USE_SDL2=1", - "USE_LINUX_PULSE_AUDIO=0", - "USE_SCREEN_CAPTURER=1" + "WEBRTC_WIN", + "USE_NVCODEC_ENCODER", + "USE_VPL_ENCODER", + "USE_SCREEN_CAPTURER", + "RTC_ENABLE_H265" ], "cStandard": "c11", - "cppStandard": "c++14", + "cppStandard": "c++17", "intelliSenseMode": "windows-msvc-x64" }, { - "name": "Ubuntu 20.04 x86_64", + "name": "Ubuntu 22.04 x86_64", "includePath": [ "${workspaceFolder}/src", - "${workspaceFolder}/NvCodec/include", - "${workspaceFolder}/NvCodec/NvCodec", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/webrtc/include", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/webrtc/include/third_party/abseil-cpp", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/webrtc/include/third_party/boringssl/src/include", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/webrtc/include/third_party/libyuv/include", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/webrtc/include/third_party/zlib", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/boost/include", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/CLI11/include", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/SDL2/include/SDL2", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/msdk/include", - "${workspaceFolder}/_install/ubuntu-20.04_x86_64/libva/include", - "${workspaceFolder}/_build/ubuntu-20.04_x86_64", + "${workspaceFolder}/src/sora-cpp-sdk/include", + "${workspaceFolder}/third_party/NvCodec/include", + "${workspaceFolder}/third_party/NvCodec/NvCodec", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/webrtc/include", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/webrtc/include/third_party/abseil-cpp", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/webrtc/include/third_party/boringssl/src/include", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/webrtc/include/third_party/libyuv/include", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/webrtc/include/third_party/zlib", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/boost/include", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/cli11/include", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/sdl2/include/SDL2", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/vpl/include", + "${workspaceFolder}/_install/ubuntu-22.04_x86_64/release/llvm/libcxx/include", + "${workspaceFolder}/_build/ubuntu-22.04_x86_64/release/momo", "/usr/local/cuda/include" ], "defines": [ + "WEBRTC_POSIX", "WEBRTC_LINUX", - "USE_NVCODEC_ENCODER=1", - "USE_MSDK_ENCODER=1", - "USE_MMAL_ENCODER=0", - "USE_JETSON_ENCODER=0", - "USE_H264=1", - "USE_SDL2=1", - "USE_LINUX_PULSE_AUDIO=0", - "USE_SCREEN_CAPTURER=1" - ], - "compilerPath": "/usr/bin/clang", - "cStandard": "c11", - "cppStandard": "c++14", - "intelliSenseMode": "linux-clang-x64" - }, - { - "name": "raspberry-pi-os_armv7 on Ubuntu 20.04 x86_64", - "includePath": [ - "${workspaceFolder}/src", - "${workspaceFolder}/NvCodec/include", - "${workspaceFolder}/NvCodec/NvCodec", - "${workspaceFolder}/_install/raspberry-pi-os_armv7/webrtc/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv7/webrtc/include/third_party/abseil-cpp", - "${workspaceFolder}/_install/raspberry-pi-os_armv7/webrtc/include/third_party/boringssl/src/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv7/webrtc/include/third_party/libyuv/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv7/webrtc/include/third_party/zlib", - "${workspaceFolder}/_install/raspberry-pi-os_armv7/boost/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv7/CLI11/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv7/SDL2/include/SDL2", - "${workspaceFolder}/_install/raspberry-pi-os_armv7/rootfs/usr/include", - "${workspaceFolder}/_build/raspberry-pi-os_armv7" - ], - "defines": [ - "WEBRTC_LINUX", - "USE_NVCODEC_ENCODER=0", - "USE_MMAL_ENCODER=1", - "USE_JETSON_ENCODER=0", - "USE_H264=1", - "USE_SDL2=1", - "USE_LINUX_PULSE_AUDIO=0", - "USE_SCREEN_CAPTURER=0" + "USE_NVCODEC_ENCODER", + "USE_VPL_ENCODER", + "USE_SCREEN_CAPTURER", + "_LIBCPP_ABI_NAMESPACE=Cr", + "_LIBCPP_ABI_VERSION=2", + "_LIBCPP_DISABLE_AVAILABILITY", + "_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE", + "BOOST_NO_CXX98_FUNCTION_BASE", + "RTC_ENABLE_H265" ], - "compilerPath": "${workspaceFolder}/_install/raspberry-pi-os_armv7/llvm/clang/bin/clang", + // "compilerPath": "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/llvm/clang/bin/clang++", + "compilerPath": "/usr/bin/clang++-18", + "compilerArgs": ["-nostdinc++"], "cStandard": "c11", - "cppStandard": "c++14", + "cppStandard": "c++17", "intelliSenseMode": "linux-clang-x64" }, { - "name": "raspberry-pi-os_armv8 on Ubuntu 20.04 x86_64", + "name": "Jetson", "includePath": [ "${workspaceFolder}/src", - "${workspaceFolder}/NvCodec/include", - "${workspaceFolder}/NvCodec/NvCodec", - "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/webrtc/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/webrtc/include/third_party/abseil-cpp", - "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/webrtc/include/third_party/boringssl/src/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/webrtc/include/third_party/libyuv/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/webrtc/include/third_party/zlib", - "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/boost/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/CLI11/include", - // "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/SDL2/include/SDL2", - "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/rootfs/usr/include", - "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/rootfs/usr/include/libcamera", - "${workspaceFolder}/_build/raspberry-pi-os_armv8" + "${workspaceFolder}/src/sora-cpp-sdk/include", + "${workspaceFolder}/third_party/NvCodec/include", + "${workspaceFolder}/third_party/NvCodec/NvCodec", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/webrtc/include", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/webrtc/include/third_party/abseil-cpp", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/webrtc/include/third_party/boringssl/src/include", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/webrtc/include/third_party/libyuv/include", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/webrtc/include/third_party/zlib", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/boost/include", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/cli11/include", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/sdl2/include/SDL2", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/llvm/libcxx/include", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/rootfs/usr/src/jetson_multimedia_api/include", + "${workspaceFolder}/_install/ubuntu-22.04_armv8_jetson/release/rootfs/usr/src/jetson_multimedia_api/include/libjpeg-8b", + "${workspaceFolder}/_build/ubuntu-22.04_armv8_jetson/release/momo" ], "defines": [ + "WEBRTC_POSIX", "WEBRTC_LINUX", - "USE_NVCODEC_ENCODER=0", - "USE_MMAL_ENCODER=0", - "USE_JETSON_ENCODER=0", - "USE_V4L2_ENCODER=1", - "USE_H264=1", - "USE_SDL2=0", - "USE_LINUX_PULSE_AUDIO=0", - "USE_SCREEN_CAPTURER=0" + "USE_JETSON_ENCODER", + "USE_SCREEN_CAPTURER", + "_LIBCPP_ABI_NAMESPACE=Cr", + "_LIBCPP_ABI_VERSION=2", + "_LIBCPP_DISABLE_AVAILABILITY", + "_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE", + "BOOST_NO_CXX98_FUNCTION_BASE", + "RTC_ENABLE_H265" ], - "compilerPath": "${workspaceFolder}/_install/raspberry-pi-os_armv8/Release/llvm/clang/bin/clang", + // "compilerPath": "${workspaceFolder}/_install/ubuntu-20.04_x86_64/release/llvm/clang/bin/clang++", + "compilerPath": "/usr/bin/clang++-18", + "compilerArgs": ["-nostdinc++"], "cStandard": "c11", "cppStandard": "c++17", "intelliSenseMode": "linux-clang-x64" } ], "version": 4 -} \ No newline at end of file +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..8dca3717 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["charliermarsh.ruff", "ms-python.mypy-type-checker"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 39d5b3d9..0a6d0388 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,14 @@ { + "[python]": { + "editor.formatOnSave": true, + "editor.formatOnSaveMode": "file", + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.autoIndent": "full", + "editor.codeActionsOnSave": { + "source.fixAll.ruff": "always", + "source.organizeImports.ruff": "explicit" + } + }, "[cpp]": { "editor.formatOnSave": true }, diff --git a/CHANGES.md b/CHANGES.md index a788d838..2758339a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,98 @@ ## develop +## 2024.1.0 + +**リリース日**: 2024-09-18 + +- [CHANGE] `--video-device` の指定を `/dev/video0` のようなファイル名ではなく `MX Brio` のようなデバイス名を指定するようにする + - @melpon +- [CHANGE] ビルド周りを完全にリニューアルする + - @melpon +- [CHANGE] raspberry-pi-os_armv6 と raspberry-pi-os_armv7 を削除 + - @melpon +- [CHANGE] ubuntu-20.04_x86_64 を削除 + - @melpon +- [CHANGE] ubuntu-20.04_armv8_jetson_xavier のパッケージを削除 + - NVIDIA JetPack SDK JetPack 5 系を対象外とする + - @melpon +- [CHANGE] JetPack 5.1.2 に対応 + - JetPack 5.1.1, 5.1.2 で動作を確認 + - JetPack 5.1 では、互換性の問題で JetsonJpegDecoder がエラーになることを確認 + - @enm10k +- [CHANGE] libwebrtc に定義されている継承元クラスが変更されたため `CreateVideoEncoder` と `CreateVideoDecoder` を `Create` に変更 + - @melpon +- [CHANGE] hwenc_nvcodec 部分を Sora C++ SDK から移植 + - @melpon +- [UPDATE] VPL を 2.13.0 に上げる + - @voluntas +- [UPDATE] CLI11 を 2.4.2 に上げる + - @voluntas @torikizi +- [UPDATE] SDL を 2.30.7 に上げる + - @voluntas @torikizi +- [UPDATE] Boost を 1.86.0 に上げる + - @torikizi @voluntas +- [UPDATE] WebRTC を m128.6613.2.0 に上げる + - m128.6613.2.0 での変更点は以下の通り + - libwebrtc から helpers が削除され `crypto_random` に分割されたため、`rtc::CreateRandomString` を利用するために `crypto_random.h` を追加 + - 参考 : + - libwebrtc から削除されたために webrtc-build で復活させた `proxy_info_revive.h` と `crypt_string_revive.h` を利用するように修正 + - `init_allocator` の引数変更に追従 + - webrtc-build の H.265 パッチの変更に追従し、`packetization_mode` とヘッダーを削除 + - m128 以降は新規追加された ScreenCaptureKit の framework が必要となったため、`CMakeLists.txt` に追加 + - 参考 : + - @torikizi @melpon +- [UPDATE] WebRTC を m119 に上げたことで必要になった関連するライブラリもバージョンを上げる + - CMAKE_VERSION を 3.30.3 に上げる + - clang や CXX_STANDARD のバージョンアップに合わせ最新のバージョンに上げる + - すべてのプラットフォームで set_target_properties の CXX_STANDARD を 20 にアップデート + - Ubuntu で使用する clang のバージョンを 15 にアップデート + - @torikizi +- [UPDATE] パッケージディレクトリ変更に追従する + - WebRTC を m118 に上げた際にパッケージディレクトリが変更されたのでそれに追従する + - @torikizi +- [UPDATE] Raspberry Pi OS のビルドを bullseye から bookworm にアップデート + - multistrap の suite を bullseye から bookworm に修正 + - libstdc++-11-dev をインストールするように修正 + - @torikizi +- [UPDATE] CMakeList.txt の修正 + - STL が要求する CUDA のバージョンが 12.4 以上であるため、他のプラットフォームに影響が出ないように無視するように修正 + - 参考: + - @torikizi +- [ADD] ubuntu-22.04_armv8_jetson のパッケージを追加 + - @melpon +- [ADD] Intel VPL の H.265 ハードウェアエンコーダ/デコーダに対応する + - @melpon +- [ADD] NVIDIA Video Codec SDK の H.265 ハードウェアエンコーダ/デコーダに対応する + - @melpon +- [ADD] videoToolbox の H.265 ハードウェアエンコーダ/デコーダに対応する + - @melpon +- [ADD] Jetson の H.265 ハードウェアエンコーダ/デコーダに対応する + - @melpon +- [ADD] OpenH264 を使った H.264 ソフトウェアエンコーダに対応する + - @melpon +- [ADD] Ubuntu 24.04 対応 + - @melpon +- [ADD] Intel VPL の AV1 ハードウェアエンコーダに対応する + - @tnoho +- [ADD] Intel VPL の VP9 ハードウェアエンコーダに対応する + - @tnoho +- [FIX] macOS で USB 接続されたカメラが取得できなくなっていたのを修正 + - macOS で USB デバイスが取得できなくなっていたため、取得するように修正 + - macOS 14 以降では従来の API では取得できなくなっていたため API を新たに用意し、macOS 14 以降で新しい API を利用する + - @torikizi + +### misc + +- [CHANGE] SDL2 のダウンロード先を GitHub に変更する + - @voluntas +- [UPDATE] Github Actions の actions/download-artifact をアップデート + - Node.js 16 の Deprecated に伴うアップデート + - actions/download-artifact@v3 から actions/download-artifact@v4 にアップデート + - @torikizi +- [UPDATE] Github Actions で使用する Windows を 2022 にアップデート + - @melpon + ## 2023.1.0 - [CHANGE] --show-me オプションの削除 @@ -508,14 +600,14 @@ - [ADD] Raspberry Pi で SDL 利用時に H264 ハードウェアデコーダを利用するようにする - @tnoho - [FIX] Jetson Nano で --use-native を使った際に FHD 設定で下部に緑の帯が出るのを修正 - - https://github.com/shiguredo/momo/issues/124 + - - @tetsu-koba @tnoho - [FIX] Jetson Nano で H264 デコーダを止める際にハングしてしまう問題を修正 - @soudegesu @tnoho - [FIX] macOS で WebRTC のバージョンが埋め込まれていなかった問題を修正 - @melpon - [FIX] Jetson Nano で RTP タイムスタンプが 90kHz になっていなかったのを修正 - - https://github.com/shiguredo/momo/pull/137 + - - @tetsu-koba @tnoho ## 2020.2.1 @@ -523,7 +615,7 @@ **hotfix** - [FIX] macOS で --use-sdl オプションを利用すると落ちていたのを修正する - - https://bugzilla.libsdl.org/show_bug.cgi?id=4617 + - - @melpon ## 2020.2 @@ -609,7 +701,7 @@ ## 19.12.1 - [UPDATE] libwebrtc を時前ビルドしないようにする - - https://github.com/shiguredo-webrtc-build/webrtc-build を利用する + - を利用する - @melpon - [FIX] momo + ayame モードで再接続時に delay してしまう問題を解決 - @kdxu @@ -839,7 +931,7 @@ - [UPDATE] WebRTC Signaling Server Ayame 19.07.0 に追従する - @kdxu - [ADD] WebRTC Signaling Server Ayame に対応しました - - https://github.com/OpenAyame/ayame + - - @kdxu - [ADD] Circle CI で Linux 版を毎日 22:00 に自動ビルドする - @voluntas @@ -912,7 +1004,7 @@ - [CHANGE] libwebrtc が 4K に対応していないため解像度指定から 4K を削除する - 将来的に対応していく予定 - - https://github.com/shiguredo/momo/issues/21 + - - [FIX] P2P モードのサンプルで映像を有効にした場合、音声が正常に流れない問題を修正 ## 18.10.0-rc1 diff --git a/CMakeLists.txt b/CMakeLists.txt index e7b18e64..80d82a4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,26 +1,30 @@ -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.27) # Only interpret if() arguments as variables or keywords when unquoted. cmake_policy(SET CMP0054 NEW) # MSVC runtime library flags are selected by an abstraction. cmake_policy(SET CMP0091 NEW) - -set(MOMO_PACKAGE_NAME "" CACHE STRING "ビルド設定を自動化するパッケージ名") +# find_package() uses upper-case _ROOT variables. +cmake_policy(SET CMP0144 NEW) +# The FindCUDA module is removed. +cmake_policy(SET CMP0146 OLD) +# Visual Studio Generators build custom commands in parallel. +cmake_policy(SET CMP0147 OLD) + +set(MOMO_TARGET "" CACHE STRING "ビルド設定を自動化するパッケージ名") set(TARGET_OS "" CACHE STRING "ビルド対象の動作する OS。\n有効な値は windows, macos, linux") set(TARGET_OS_LINUX "" CACHE STRING "TARGET_OS が linux の場合の詳細な OS の情報。") set(TARGET_ARCH "" CACHE STRING "ビルド対象の動作する CPU。\n有効な値は x86_64, arm") -set(TARGET_ARCH_ARM "" CACHE STRING "TARGET_ARCH が arm の場合の詳細な CPU の情報。\n有効な値は armv6, armv7, armv8") +set(TARGET_ARCH_ARM "" CACHE STRING "TARGET_ARCH が arm の場合の詳細な CPU の情報。\n有効な値は armv8") set(USE_NVCODEC_ENCODER OFF CACHE BOOL "NVIDIA VIDEO CODEC SDK のハードウェアエンコーダを利用するかどうか") -set(USE_MMAL_ENCODER OFF CACHE BOOL "MMAL ハードウェアエンコーダを利用するかどうか") set(USE_JETSON_ENCODER OFF CACHE BOOL "Jetson のハードウェアエンコーダを利用するかどうか") -set(USE_MSDK_ENCODER OFF CACHE BOOL "Intel Media SDK のハードウェアエンコーダを利用するかどうか") -set(USE_H264 OFF CACHE BOOL "H264 を利用するかどうか") -set(USE_SDL2 OFF CACHE BOOL "SDL2 による画面出力を利用するかどうか") +set(USE_VPL_ENCODER OFF CACHE BOOL "oneVPL のハードウェアエンコーダを利用するかどうか") set(USE_LINUX_PULSE_AUDIO OFF CACHE BOOL "Linux で ALSA の代わりに PulseAudio を利用するか") set(USE_SCREEN_CAPTURER OFF CACHE BOOL "スクリーンキャプチャラを利用するかどうか") -set(BOOST_ROOT_DIR "" CACHE PATH "Boost のインストール先ディレクトリ\n空文字だった場合はデフォルト検索パスの Boost を利用する") +set(BOOST_ROOT "" CACHE PATH "Boost のインストール先ディレクトリ\n空文字だった場合はデフォルト検索パスの Boost を利用する") set(SDL2_ROOT_DIR "" CACHE PATH "SDL2 のインストール先ディレクトリ\n空文字だった場合はデフォルト検索パスの SDL2 を利用する") set(CLI11_ROOT_DIR "" CACHE PATH "CLI11 のインストール先ディレクトリ") +set(OPENH264_ROOT_DIR "" CACHE PATH "OpenH264 のインストール先ディレクトリ") set(NVCODEC_ROOT_DIR "" CACHE PATH "NVIDIA VIDEO CODEC SDK のインストール先ディレクトリ") set(WEBRTC_INCLUDE_DIR "" CACHE PATH "WebRTC のインクルードディレクトリ") set(WEBRTC_LIBRARY_DIR "" CACHE PATH "WebRTC のライブラリディレクトリ") @@ -35,246 +39,61 @@ set(WEBRTC_BUILD_VERSION "unspecified" CACHE STRING "webrtc-build のバージ set(WEBRTC_READABLE_VERSION "unspecified" CACHE STRING "WebRTC の読みやすいバージョン") set(WEBRTC_COMMIT "" CACHE STRING "WebRTC のコミットハッシュ") -if(MOMO_PACKAGE_NAME STREQUAL "windows_x86_64") - set(_INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build/windows_x86_64/_install) - +if(MOMO_TARGET STREQUAL "windows_x86_64") set(TARGET_OS "windows") set(TARGET_ARCH "x86_64") - set(USE_NVCODEC_ENCODER ON) - set(USE_MSDK_ENCODER ON) - set(USE_H264 ON) - set(USE_SDL2 ON) - set(USE_SCREEN_CAPTURER ON) - set(BOOST_ROOT_DIR ${_INSTALL_DIR}/boost) - set(SDL2_ROOT_DIR ${_INSTALL_DIR}/SDL2) - set(CLI11_ROOT_DIR ${_INSTALL_DIR}/CLI11) - set(WEBRTC_INCLUDE_DIR ${_INSTALL_DIR}/webrtc/include) - set(WEBRTC_LIBRARY_DIR ${_INSTALL_DIR}/webrtc/lib) - - list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${SDL2_ROOT_DIR}/cmake) - list(APPEND CMAKE_PREFIX_PATH ${BOOST_ROOT_DIR} ${SDL2_ROOT_DIR}) - -elseif(MOMO_PACKAGE_NAME STREQUAL "macos_arm64") - - set(_INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build/macos_arm64/_install) - +elseif(MOMO_TARGET STREQUAL "macos_arm64") set(TARGET_OS "macos") set(TARGET_ARCH "arm64") - set(USE_H264 ON) - set(USE_SDL2 ON) - set(USE_SCREEN_CAPTURER ON) - set(BOOST_ROOT_DIR ${_INSTALL_DIR}/boost) - set(SDL2_ROOT_DIR ${_INSTALL_DIR}/SDL2) - set(CLI11_ROOT_DIR ${_INSTALL_DIR}/CLI11) - set(WEBRTC_INCLUDE_DIR ${_INSTALL_DIR}/webrtc/include) - set(WEBRTC_LIBRARY_DIR ${_INSTALL_DIR}/webrtc/lib) - -elseif(MOMO_PACKAGE_NAME STREQUAL "raspberry-pi-os_armv6") - - set(TARGET_OS "linux") - set(TARGET_OS_LINUX "raspberry-pi-os") - set(TARGET_ARCH "arm") - set(TARGET_ARCH_ARM "armv6") - set(USE_MMAL_ENCODER ON) - set(USE_H264 ON) - set(BOOST_ROOT_DIR /root/boost) - set(CLI11_ROOT_DIR /root/CLI11) - set(WEBRTC_INCLUDE_DIR /root/webrtc/include) - set(WEBRTC_LIBRARY_DIR /root/webrtc/lib) - set(CLANG_ROOT /root/llvm/clang) - set(SYSROOT /root/rootfs) - - set(USE_LIBCXX ON) - set(LIBCXX_INCLUDE_DIR /root/llvm/libcxx/include) - - set(Boost_ARCHITECTURE 32) - -elseif(MOMO_PACKAGE_NAME STREQUAL "raspberry-pi-os_armv7") - - set(TARGET_OS "linux") - set(TARGET_OS_LINUX "raspberry-pi-os") - set(TARGET_ARCH "arm") - set(TARGET_ARCH_ARM "armv7") - set(USE_MMAL_ENCODER ON) - set(USE_H264 ON) - set(USE_SDL2 ON) - set(BOOST_ROOT_DIR /root/boost) - set(SDL2_ROOT_DIR /root/SDL2) - set(CLI11_ROOT_DIR /root/CLI11) - set(WEBRTC_INCLUDE_DIR /root/webrtc/include) - set(WEBRTC_LIBRARY_DIR /root/webrtc/lib) - set(CLANG_ROOT /root/llvm/clang) - set(SYSROOT /root/rootfs) - - set(USE_LIBCXX ON) - set(LIBCXX_INCLUDE_DIR /root/llvm/libcxx/include) - - set(Boost_ARCHITECTURE 32) - -elseif(MOMO_PACKAGE_NAME STREQUAL "raspberry-pi-os_armv8") - +elseif(MOMO_TARGET STREQUAL "raspberry-pi-os_armv8") set(TARGET_OS "linux") set(TARGET_OS_LINUX "raspberry-pi-os") set(TARGET_ARCH "arm") set(TARGET_ARCH_ARM "armv8") - set(USE_V4L2_ENCODER ON) - set(USE_H264 ON) - set(USE_SDL2 ON) - set(USE_LINUX_PULSE_AUDIO ON) - set(BOOST_ROOT_DIR /root/boost) - set(SDL2_ROOT_DIR /root/SDL2) - set(CLI11_ROOT_DIR /root/CLI11) - set(WEBRTC_INCLUDE_DIR /root/webrtc/include) - set(WEBRTC_LIBRARY_DIR /root/webrtc/lib) - set(CLANG_ROOT /root/llvm/clang) - set(SYSROOT /root/rootfs) - - set(USE_LIBCXX ON) - set(LIBCXX_INCLUDE_DIR /root/llvm/libcxx/include) - -elseif(MOMO_PACKAGE_NAME STREQUAL "ubuntu-20.04_x86_64") - +elseif(MOMO_TARGET STREQUAL "ubuntu-22.04_x86_64") set(TARGET_OS "linux") - set(TARGET_OS_LINUX "ubuntu-20.04") + set(TARGET_OS_LINUX "ubuntu-22.04") set(TARGET_ARCH "x86_64") - set(USE_H264 ON) - set(USE_SDL2 ON) - set(USE_NVCODEC_ENCODER ON) - set(USE_MSDK_ENCODER ON) - set(USE_SCREEN_CAPTURER ON) - set(BOOST_ROOT_DIR /root/boost) - set(CLI11_ROOT_DIR /root/CLI11) - set(SDL2_ROOT_DIR /root/SDL2) - set(LIBVA_ROOT_DIR /root/libva) - set(MSDK_ROOT_DIR /root/msdk) - set(WEBRTC_INCLUDE_DIR /root/webrtc/include) - set(WEBRTC_LIBRARY_DIR /root/webrtc/lib) - - # /root/llvm/clang にあるコンパイラは使わず、apt でインストールした clang-10 を利用する - set(CMAKE_C_COMPILER clang-10) - set(CMAKE_CXX_COMPILER clang++-10) - - set(USE_LIBCXX ON) - set(LIBCXX_INCLUDE_DIR /root/llvm/libcxx/include) - -elseif(MOMO_PACKAGE_NAME STREQUAL "ubuntu-20.04_armv8_jetson_xavier") - +elseif(MOMO_TARGET STREQUAL "ubuntu-24.04_x86_64") set(TARGET_OS "linux") - set(TARGET_OS_LINUX "ubuntu-20.04") - set(TARGET_ARCH "arm") - set(TARGET_ARCH_ARM "armv8") - set(USE_JETSON_ENCODER ON) - set(USE_H264 ON) - set(USE_SDL2 ON) - set(USE_LINUX_PULSE_AUDIO ON) - set(BOOST_ROOT_DIR /root/boost) - set(CLI11_ROOT_DIR /root/CLI11) - set(SDL2_ROOT_DIR /root/SDL2) - set(WEBRTC_INCLUDE_DIR /root/webrtc/include) - set(WEBRTC_LIBRARY_DIR /root/webrtc/lib) - set(CLANG_ROOT /root/llvm/clang) - set(SYSROOT /root/rootfs) - - set(USE_LIBCXX ON) - set(LIBCXX_INCLUDE_DIR /root/llvm/libcxx/include) - -elseif(MOMO_PACKAGE_NAME STREQUAL "ubuntu-22.04_x86_64") - + set(TARGET_OS_LINUX "ubuntu-24.04") + set(TARGET_ARCH "x86_64") +elseif(MOMO_TARGET STREQUAL "ubuntu-22.04_armv8_jetson") set(TARGET_OS "linux") set(TARGET_OS_LINUX "ubuntu-22.04") - set(TARGET_ARCH "x86_64") - set(USE_H264 ON) - set(USE_SDL2 ON) - set(USE_NVCODEC_ENCODER ON) - set(USE_MSDK_ENCODER ON) - set(USE_SCREEN_CAPTURER ON) - set(BOOST_ROOT_DIR /root/boost) - set(CLI11_ROOT_DIR /root/CLI11) - set(SDL2_ROOT_DIR /root/SDL2) - set(LIBVA_ROOT_DIR /root/libva) - set(MSDK_ROOT_DIR /root/msdk) - set(WEBRTC_INCLUDE_DIR /root/webrtc/include) - set(WEBRTC_LIBRARY_DIR /root/webrtc/lib) - - # /root/llvm/clang にあるコンパイラは使わず、apt でインストールした clang-12 を利用する - set(CMAKE_C_COMPILER clang-12) - set(CMAKE_CXX_COMPILER clang++-12) - - set(USE_LIBCXX ON) - set(LIBCXX_INCLUDE_DIR /root/llvm/libcxx/include) - -else() -endif() - -if (NOT "${CLANG_ROOT}" STREQUAL "") - set(CMAKE_C_COMPILER ${CLANG_ROOT}/bin/clang) - set(CMAKE_CXX_COMPILER ${CLANG_ROOT}/bin/clang++) -endif() - -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) - -if (NOT "${BOOST_ROOT_DIR}" STREQUAL "") - list(APPEND CMAKE_PREFIX_PATH ${BOOST_ROOT_DIR}) -endif() - -if (USE_SDL2 AND (NOT "${SDL2_ROOT_DIR}" STREQUAL "")) - list(APPEND CMAKE_MODULE_PATH ${SDL2_ROOT_DIR}/cmake) - list(APPEND CMAKE_PREFIX_PATH ${SDL2_ROOT_DIR}) -endif() - -# SYSROOT とかの設定 -# これらの設定は project の前に行う必要がある -if (TARGET_OS STREQUAL "linux") - if (TARGET_ARCH STREQUAL "arm") - if (TARGET_ARCH_ARM STREQUAL "armv8") - set(ARCH_NAME aarch64-linux-gnu) - else() - set(ARCH_NAME arm-linux-gnueabihf) - endif() - - set(CMAKE_SYSTEM_NAME Linux) - if (TARGET_ARCH_ARM STREQUAL "armv8") - set(CMAKE_SYSTEM_PROCESSOR aarch64) - else() - set(CMAKE_SYSTEM_PROCESSOR arm) - endif() - set(CMAKE_SYSROOT ${SYSROOT}) - set(CMAKE_C_COMPILER_TARGET ${ARCH_NAME}) - set(CMAKE_CXX_COMPILER_TARGET ${ARCH_NAME}) - - set(CMAKE_FIND_ROOT_PATH ${SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) - endif() + set(TARGET_ARCH "arm") + set(TARGET_ARCH_ARM "armv8") endif() -if (TARGET_OS STREQUAL "macos") - set(ARCH_NAME aarch64-apple-darwin) - set(CMAKE_SYSTEM_PROCESSOR arm64) - - set(CMAKE_C_COMPILER_TARGET ${ARCH_NAME}) - set(CMAKE_CXX_COMPILER_TARGET ${ARCH_NAME}) -endif() +# ubuntu-22.04_armv8_jetson 対応時に追加 +# rootfs 上のプログラムが利用されることを防ぐ +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) project(momo C CXX) -list(APPEND MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +list(APPEND CMAKE_PREFIX_PATH ${SDL2_ROOT_DIR}) +if (USE_VPL_ENCODER) + list(APPEND CMAKE_PREFIX_PATH ${VPL_ROOT_DIR}/lib/cmake/vpl) +endif() set(Boost_USE_STATIC_LIBS ON) -if ("${TARGET_OS}" STREQUAL "windows") +if (WIN32) set(Boost_USE_STATIC_RUNTIME ON) -else() - set(Boost_USE_STATIC_RUNTIME OFF) endif() +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER) + find_package(WebRTC REQUIRED) find_package(Boost REQUIRED COMPONENTS filesystem json) find_package(CLI11 REQUIRED) -if (USE_SDL2) - find_package(SDL2 REQUIRED) -endif() +find_package(SDL2 REQUIRED) + +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) add_executable(momo) @@ -282,15 +101,16 @@ string(SUBSTRING "${MOMO_COMMIT}" 0 8 MOMO_COMMIT_SHORT) string(SUBSTRING "${WEBRTC_COMMIT}" 0 8 WEBRTC_COMMIT_SHORT) configure_file(src/momo_version.gen.h.template ${CMAKE_CURRENT_BINARY_DIR}/momo_version.gen.h) target_include_directories(momo PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(momo PRIVATE src/sora-cpp-sdk/include) +target_include_directories(momo PRIVATE ${OPENH264_ROOT_DIR}/include) target_sources(momo PRIVATE + src/ayame/ayame_client.cpp src/main.cpp + src/metrics/metrics_server.cpp + src/metrics/metrics_session.cpp src/momo_version.cpp - src/util.cpp - src/watchdog.cpp - src/ssl_verifier.cpp - src/ayame/ayame_client.cpp src/p2p/p2p_server.cpp src/p2p/p2p_session.cpp src/p2p/p2p_websocket_session.cpp @@ -303,24 +123,22 @@ target_sources(momo src/rtc/rtc_connection.cpp src/rtc/rtc_manager.cpp src/rtc/rtc_ssl_verifier.cpp - src/rtc/scalable_track_source.cpp src/serial_data_channel/serial_data_channel.cpp src/serial_data_channel/serial_data_manager.cpp + src/sora-cpp-sdk/src/open_h264_video_encoder.cpp + src/sora-cpp-sdk/src/scalable_track_source.cpp + src/sora/sora_client.cpp src/sora/sora_server.cpp src/sora/sora_session.cpp - src/sora/sora_client.cpp + src/ssl_verifier.cpp + src/util.cpp + src/watchdog.cpp src/websocket.cpp - src/metrics/metrics_server.cpp - src/metrics/metrics_session.cpp ) target_include_directories(momo PRIVATE src) -if (WIN32) - set_target_properties(momo PROPERTIES CXX_STANDARD 20 C_STANDARD 99) -else() - set_target_properties(momo PROPERTIES CXX_STANDARD 17 C_STANDARD 99) -endif() +set_target_properties(momo PROPERTIES CXX_STANDARD 20 C_STANDARD 99) target_link_libraries(momo PRIVATE @@ -336,58 +154,52 @@ target_compile_definitions(momo # しかし、 libwebrtc の libc++ では std::filesystem が提供されていないため下記のオプションを追加して利用しないようにする。 CLI11_HAS_FILESYSTEM=0 OPENSSL_IS_BORINGSSL - USE_NVCODEC_ENCODER=$ - USE_MMAL_ENCODER=$ - USE_V4L2_ENCODER=$ - USE_JETSON_ENCODER=$ - USE_MSDK_ENCODER=$ - USE_H264=$ - USE_SDL2=$ - USE_LINUX_PULSE_AUDIO=$ - USE_SCREEN_CAPTURER=$ + $<$:USE_NVCODEC_ENCODER> + $<$:USE_V4L2_ENCODER> + $<$:USE_JETSON_ENCODER> + $<$:USE_VPL_ENCODER> + $<$:USE_LINUX_PULSE_AUDIO> + $<$:USE_SCREEN_CAPTURER> # https://github.com/boostorg/container_hash/issues/22 と同じ問題が clang-15 でも起きるので、これを手動で定義して回避する BOOST_NO_CXX98_FUNCTION_BASE ) -if (USE_SDL2) - target_sources(momo - PRIVATE - src/sdl_renderer/sdl_renderer.cpp - ) - target_compile_definitions(momo +# SDL2 のための設定 +target_sources(momo + PRIVATE + src/sdl_renderer/sdl_renderer.cpp +) +target_compile_definitions(momo + PRIVATE + _THREAD_SAFE +) +if ("${TARGET_OS}" STREQUAL "windows" OR "${TARGET_OS}" STREQUAL "macos") + target_link_libraries(momo PRIVATE - _THREAD_SAFE + SDL2::SDL2-static + SDL2::SDL2main ) - - - if ("${TARGET_OS}" STREQUAL "windows" OR "${TARGET_OS}" STREQUAL "macos") +else() + if (TARGET SDL2::SDL2Config) target_link_libraries(momo PRIVATE - SDL2::SDL2-static - SDL2::SDL2main + SDL2::SDL2Config ) else() - if (TARGET SDL2::SDL2Config) - target_link_libraries(momo - PRIVATE - SDL2::SDL2Config - ) - else() - target_link_directories(momo PRIVATE ${SDL2_LIBDIR}) - target_link_libraries(momo PRIVATE SDL2) - target_include_directories(momo PRIVATE "${SYSROOT}${SDL2_INCLUDE_DIRS}") - endif() + target_link_directories(momo PRIVATE ${SDL2_LIBDIR}) + target_link_libraries(momo PRIVATE SDL2) + target_include_directories(momo PRIVATE "${SYSROOT}${SDL2_INCLUDE_DIRS}") endif() +endif() - if ("${TARGET_OS}" STREQUAL "macos") - target_link_libraries(momo - PRIVATE - iconv - "-framework Carbon" - "-framework IOKit" - "-framework ForceFeedback" - ) - endif() +if ("${TARGET_OS}" STREQUAL "macos") + target_link_libraries(momo + PRIVATE + iconv + "-framework Carbon" + "-framework IOKit" + "-framework ForceFeedback" + ) endif() if (USE_LIBCXX) @@ -430,28 +242,27 @@ if ("${TARGET_OS}" STREQUAL "windows") set_target_properties(momo PROPERTIES # CRTライブラリを静的リンクさせる - # CMake 3.15 以上なら MSVC_RUNTIME_LIBRARY が使える - MSVC_RUNTIME_LIBRARY "MultiThreaded" + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" ) target_link_libraries(momo PRIVATE - dbghelp.lib - delayimp.lib - dnsapi.lib - msimg32.lib - oleaut32.lib - psapi.lib - shell32.lib - shlwapi.lib - usp10.lib - version.lib - wininet.lib + # dbghelp.lib + # delayimp.lib + # dnsapi.lib + # msimg32.lib + # oleaut32.lib + # psapi.lib + # shell32.lib + # shlwapi.lib + # usp10.lib + # version.lib + # wininet.lib winmm.lib ws2_32.lib - amstrmid.lib + # amstrmid.lib Strmiids.lib - crypt32.lib + # crypt32.lib dmoguids.lib iphlpapi.lib msdmo.lib @@ -470,20 +281,21 @@ if ("${TARGET_OS}" STREQUAL "windows") WIN32_LEAN_AND_MEAN UNICODE _UNICODE + RTC_ENABLE_H265 ) # NVIDIA Video Codec SDK if (USE_NVCODEC_ENCODER) target_sources(momo PRIVATE - src/hwenc_nvcodec/nvcodec_h264_encoder.cpp - NvCodec/NvCodec/NvEncoder/NvEncoder.cpp - NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.cpp - src/hwenc_nvcodec/nvcodec_video_decoder.cpp) + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder.cpp + third_party/NvCodec/NvCodec/NvEncoder/NvEncoder.cpp + third_party/NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_decoder.cpp) target_include_directories(momo PRIVATE - NvCodec/include - NvCodec/NvCodec) + third_party/NvCodec/include + third_party/NvCodec/NvCodec) target_link_libraries(momo PRIVATE DXGI.lib @@ -495,25 +307,48 @@ if ("${TARGET_OS}" STREQUAL "windows") # enable_language(CUDA) は利用できない。 # なので(deprecated だけど)FindCUDA を利用してコンパイルする。 - set(CUDA_TOOLKIT_ROOT_DIR ${_INSTALL_DIR}/cuda/nvcc) find_package(CUDA REQUIRED) set_source_files_properties( - src/cuda/cuda_context_cuda.cpp - NvCodec/NvCodec/NvDecoder/NvDecoder.cpp - src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp + src/sora-cpp-sdk/src/cuda_context_cuda.cpp + third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ ) cuda_compile(CUDA_FILES - src/cuda/cuda_context_cuda.cpp - NvCodec/NvCodec/NvDecoder/NvDecoder.cpp - src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp + src/sora-cpp-sdk/src/cuda_context_cuda.cpp + third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp OPTIONS + # VS 2022 の 17.10.x 以上に上げると、ツールセットのバージョンが 14.40 以上になってしまい、以下のエラーが出るため -allow-unsupported-compiler を指定する + # + # G:\dev\sora-cpp-sdk\_install\windows_x86_64\release\cuda\include\crt/host_config.h(153): fatal error C1189: #error: -- unsupported Microsoft Visual Studio version! Only the versions between 20 17 and 2022 (inclusive) are supported! The nvcc flag '-allow-unsupported-compiler' can be used to override this version check; however, using an unsupported host compiler may cause compilation failure or incorrect run time execution. Use at your own risk. [G:\dev\sora-cpp-sdk\_build\windows_x86_64\release\sora\sora.vcxproj] + # + # host_config.h では以下のような記述になっている + # + # ``` + # #if _MSC_VER < 1910 || _MSC_VER >= 1940 + # + # #error -- unsupported Microsoft Visual Studio version! Only the versions between 2017 and 2022 (inclusive) are supported! (...snip...) + # ``` + # + # 17.10 は _MSC_VER が 1940 になるため、このエラーが出る。 + # + # VS のバージョンと _MSC_VER のリストは以下を参照: + # https://devblogs.microsoft.com/cppblog/msvc-toolset-minor-version-number-14-40-in-vs-2022-v17-10/ + -allow-unsupported-compiler + # 更に STL が CUDA 12.4 以上のバージョンを要求するため、STL のバージョンも無視する + # ref: https://stackoverflow.com/questions/78515942/cuda-compatibility-with-visual-studio-2022-version-17-10 + -Xcompiler /D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH -Xcompiler /utf-8 - -Xcompiler /I${CMAKE_CURRENT_SOURCE_DIR}/NvCodec/include - -Xcompiler /I${CMAKE_CURRENT_SOURCE_DIR}/NvCodec/NvCodec + -Xcompiler /I${CMAKE_CURRENT_SOURCE_DIR}/third_party/NvCodec/include + -Xcompiler /I${CMAKE_CURRENT_SOURCE_DIR}/third_party/NvCodec/NvCodec -Xcompiler /I${CMAKE_CURRENT_SOURCE_DIR}/src + -Xcompiler /I${CMAKE_CURRENT_SOURCE_DIR}/src/sora-cpp-sdk/include + -Xcompiler "/MT$<$:d>" + -Xcompiler /D_HAS_ITERATOR_DEBUGGING=0 + -Xcompiler /DUSE_NVCODEC_ENCODER ) target_sources(momo PRIVATE ${CUDA_FILES}) target_include_directories(momo PRIVATE ${CUDA_INCLUDE_DIRS}) @@ -524,18 +359,18 @@ if ("${TARGET_OS}" STREQUAL "windows") ) endif() - # Intel Media SDK - if (USE_MSDK_ENCODER) + # oneVPL + if (USE_VPL_ENCODER) target_sources(momo PRIVATE - src/hwenc_msdk/msdk_session.cpp - src/hwenc_msdk/msdk_video_decoder.cpp - src/hwenc_msdk/msdk_video_encoder.cpp + src/sora-cpp-sdk/src/hwenc_vpl/vpl_session_impl.cpp + src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_decoder.cpp + src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_encoder.cpp ) - target_include_directories(momo PRIVATE ${_INSTALL_DIR}/msdk/include) + target_include_directories(momo PRIVATE ${VPL_ROOT_DIR}/include) target_link_libraries(momo PRIVATE - ${_INSTALL_DIR}/msdk/lib/libmfx.lib + ${VPL_ROOT_DIR}/lib/vpl$<$:d>.lib ) endif() elseif (TARGET_OS STREQUAL "macos") @@ -550,29 +385,33 @@ elseif (TARGET_OS STREQUAL "macos") target_link_options(momo PRIVATE -ObjC) set_target_properties(momo PROPERTIES CXX_VISIBILITY_PRESET hidden) + target_compile_definitions(momo + PRIVATE + WEBRTC_POSIX + WEBRTC_MAC + RTC_ENABLE_H265 + ) + target_link_libraries(momo PRIVATE - "-framework Foundation" + #"-framework Foundation" "-framework AVFoundation" - "-framework CoreServices" - "-framework CoreFoundation" - "-framework AudioUnit" + #"-framework CoreServices" + #"-framework CoreFoundation" + #"-framework AudioUnit" "-framework AudioToolbox" "-framework CoreAudio" - "-framework CoreGraphics" + "-framework QuartzCore" + #"-framework CoreGraphics" "-framework CoreMedia" - "-framework CoreVideo" + #"-framework CoreVideo" "-framework VideoToolbox" "-framework AppKit" "-framework Metal" "-framework MetalKit" "-framework OpenGL" - ) - - target_compile_definitions(momo - PRIVATE - WEBRTC_POSIX - WEBRTC_MAC + "-framework IOSurface" + "-framework ScreenCaptureKit" ) elseif (TARGET_OS STREQUAL "linux") @@ -580,15 +419,20 @@ elseif (TARGET_OS STREQUAL "linux") target_sources(momo PRIVATE - src/v4l2_video_capturer/v4l2_video_capturer.cpp + src/sora-cpp-sdk/src/v4l2/v4l2_video_capturer.cpp ) target_compile_definitions(momo PRIVATE WEBRTC_POSIX WEBRTC_LINUX + _LIBCPP_ABI_NAMESPACE=Cr + _LIBCPP_ABI_VERSION=2 + _LIBCPP_DISABLE_AVAILABILITY + _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE + # https://github.com/boostorg/container_hash/issues/22 と同じ問題が clang-15 でも起きるので、これを手動で定義して回避する + BOOST_NO_CXX98_FUNCTION_BASE + RTC_ENABLE_H265 ) - # Linux 系の場合はカスタムされた libc++ を使っているためオプション追加 - target_compile_definitions(momo PRIVATE _LIBCPP_ABI_NAMESPACE=Cr _LIBCPP_ABI_VERSION=2 _LIBCPP_DISABLE_AVAILABILITY) set_target_properties(momo PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(momo @@ -614,63 +458,61 @@ elseif (TARGET_OS STREQUAL "linux") if (USE_NVCODEC_ENCODER) target_sources(momo PRIVATE - src/cuda/cuda_context_cuda.cpp - src/hwenc_nvcodec/nvcodec_h264_encoder.cpp - src/hwenc_nvcodec/nvcodec_v4l2_capturer.cpp - src/hwenc_nvcodec/nvcodec_h264_encoder_cuda.cpp - src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp - src/hwenc_nvcodec/nvcodec_video_decoder.cpp - NvCodec/NvCodec/NvDecoder/NvDecoder.cpp - NvCodec/NvCodec/NvEncoder/NvEncoder.cpp - NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp) + third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp + third_party/NvCodec/NvCodec/NvEncoder/NvEncoder.cpp + third_party/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp + src/sora-cpp-sdk/src/cuda_context_cuda.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder_cuda.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_v4l2_capturer.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_decoder.cpp) target_include_directories(momo PRIVATE - NvCodec/include - NvCodec/NvCodec + third_party/NvCodec/include + third_party/NvCodec/NvCodec /usr/local/cuda/include) - if (WIN32) - set(_CUDA_COMPILE_OPTIONS "-xcuda;--cuda-gpu-arch=sm_35;-std=gnu++20") - else() - set(_CUDA_COMPILE_OPTIONS "-xcuda;--cuda-gpu-arch=sm_35;-std=gnu++17") - endif() - # これらのソースは CUDA としてコンパイルする set_source_files_properties( - src/cuda/cuda_context_cuda.cpp - src/hwenc_nvcodec/nvcodec_h264_encoder_cuda.cpp - src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp - NvCodec/NvCodec/NvDecoder/NvDecoder.cpp - NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp + src/sora-cpp-sdk/src/cuda_context_cuda.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder_cuda.cpp + src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp + third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp + third_party/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp PROPERTIES - COMPILE_OPTIONS "${_CUDA_COMPILE_OPTIONS}" + COMPILE_OPTIONS "-xcuda;--cuda-gpu-arch=sm_35;-std=gnu++17" ) target_link_directories(momo PRIVATE /usr/local/cuda/lib64) target_link_libraries(momo PRIVATE cudart_static dl rt) endif() - # Intel Media SDK - if (USE_MSDK_ENCODER) - find_package(MSDK REQUIRED) + # oneVPL + if (USE_VPL_ENCODER) + find_package(Libdrm REQUIRED) + find_package(Libva REQUIRED) + find_package(VPL REQUIRED) target_sources(momo PRIVATE - src/hwenc_msdk/msdk_session.cpp - src/hwenc_msdk/msdk_video_decoder.cpp - src/hwenc_msdk/msdk_video_encoder.cpp - src/hwenc_msdk/vaapi_utils_drm.cpp - src/hwenc_msdk/vaapi_utils.cpp + src/sora-cpp-sdk/src/hwenc_vpl/vpl_session_impl.cpp + src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_decoder.cpp + src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_encoder.cpp + src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils_drm.cpp + src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils.cpp ) target_link_libraries(momo PRIVATE - MSDK::MSDK) + VPL::dispatcher + Libdrm::drm + Libva::va + Libva::va_drm + ) endif() if (TARGET_ARCH STREQUAL "arm") - if (USE_LIBCXX) - target_include_directories(momo PRIVATE ${SYSROOT}/usr/include/${ARCH_NAME}) - target_link_directories(momo PRIVATE ${SYSROOT}/usr/lib/${ARCH_NAME}) - endif() + target_include_directories(momo PRIVATE ${CMAKE_SYSROOT}/usr/include/${ARCH_NAME}) + target_link_directories(momo PRIVATE ${CMAKE_SYSROOT}/usr/lib/${ARCH_NAME}) if (TARGET_ARCH_ARM STREQUAL "armv8") # Jetson の設定 @@ -678,40 +520,40 @@ elseif (TARGET_OS STREQUAL "linux") target_sources(momo PRIVATE - src/hwenc_jetson/jetson_buffer.cpp - src/hwenc_jetson/jetson_jpeg_decoder.cpp - src/hwenc_jetson/jetson_jpeg_decoder_pool.cpp - src/hwenc_jetson/jetson_v4l2_capturer.cpp - src/hwenc_jetson/jetson_video_encoder.cpp - src/hwenc_jetson/jetson_video_decoder.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvBufSurface.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvBuffer.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvElement.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvElementProfiler.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvJpegDecoder.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvJpegEncoder.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvLogging.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvV4l2Element.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvV4l2ElementPlane.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvVideoEncoder.cpp - ${SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvVideoDecoder.cpp + src/sora-cpp-sdk/src/hwenc_jetson/jetson_buffer.cpp + src/sora-cpp-sdk/src/hwenc_jetson/jetson_jpeg_decoder.cpp + src/sora-cpp-sdk/src/hwenc_jetson/jetson_jpeg_decoder_pool.cpp + src/sora-cpp-sdk/src/hwenc_jetson/jetson_v4l2_capturer.cpp + src/sora-cpp-sdk/src/hwenc_jetson/jetson_video_encoder.cpp + src/sora-cpp-sdk/src/hwenc_jetson/jetson_video_decoder.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvBufSurface.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvBuffer.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvElement.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvElementProfiler.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvJpegDecoder.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvJpegEncoder.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvLogging.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvV4l2Element.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvV4l2ElementPlane.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvVideoEncoder.cpp + ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/samples/common/classes/NvVideoDecoder.cpp ) - target_include_directories(momo PRIVATE ${SYSROOT}/usr/src/jetson_multimedia_api/include) - target_include_directories(momo PRIVATE ${SYSROOT}/usr/src/jetson_multimedia_api/include/libjpeg-8b) - target_link_directories(momo PRIVATE ${SYSROOT}/usr/lib/aarch64-linux-gnu/tegra) + target_include_directories(momo PRIVATE ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/include) + target_include_directories(momo PRIVATE ${CMAKE_SYSROOT}/usr/src/jetson_multimedia_api/include/libjpeg-8b) + target_link_directories(momo PRIVATE ${CMAKE_SYSROOT}/usr/lib/aarch64-linux-gnu/nvidia) target_link_options(momo PRIVATE - "-Wl,-rpath-link=${SYSROOT}/lib/aarch64-linux-gnu" - "-Wl,-rpath-link=${SYSROOT}/usr/lib/aarch64-linux-gnu" - "-Wl,-rpath-link=${SYSROOT}/usr/lib/aarch64-linux-gnu/tegra" + "-Wl,-rpath-link=${CMAKE_SYSROOT}/lib/aarch64-linux-gnu" + "-Wl,-rpath-link=${CMAKE_SYSROOT}/usr/lib/aarch64-linux-gnu" + "-Wl,-rpath-link=${CMAKE_SYSROOT}/usr/lib/aarch64-linux-gnu/nvidia" ) target_link_libraries(momo PRIVATE nvv4l2 nvv4lconvert - nvbuf_utils - #nvbuf_fdmap + #nvbuf_utils + nvbuf_fdmap #nvddk_vic #nvddk_2d_v2 nvjpeg @@ -721,11 +563,11 @@ elseif (TARGET_OS STREQUAL "linux") #nvrm_graphics #nvos ) - endif(USE_JETSON_ENCODER) + endif() if (USE_V4L2_ENCODER) add_library(camerac SHARED) - target_include_directories(camerac PRIVATE ${SYSROOT}/usr/include/libcamera) + target_include_directories(camerac PRIVATE ${CMAKE_SYSROOT}/usr/include/libcamera) set_target_properties(camerac PROPERTIES CXX_STANDARD 17 C_STANDARD 99) target_sources(camerac PRIVATE @@ -750,71 +592,7 @@ elseif (TARGET_OS STREQUAL "linux") ) target_link_libraries(momo PRIVATE camerac) set_target_properties(momo PROPERTIES BUILD_RPATH_USE_ORIGIN ON) - endif(USE_V4L2_ENCODER) - else() - # armv6, armv7 用 - if (TARGET_ARCH_ARM STREQUAL "armv6") - target_compile_options(momo PRIVATE -mfloat-abi=hard -mcpu=arm1176jzf-s -mfpu=vfp) - else() - target_compile_options(momo PRIVATE -mfloat-abi=hard -march=armv7-a -mtune=generic-armv7-a -mfpu=neon -mthumb) endif() - - if (USE_MMAL_ENCODER) - target_sources(momo - PRIVATE - src/hwenc_mmal/mmal_h264_decoder.cpp - src/hwenc_mmal/mmal_buffer.cpp - src/hwenc_mmal/mmal_h264_encoder.cpp - src/hwenc_mmal/mmal_v4l2_capturer.cpp - ) - - if (TARGET_OS_LINUX STREQUAL "raspberry-pi-os") - set(_VC_PATH ${SYSROOT}/opt/vc) - else() - set(_VC_PATH ${SYSROOT}/usr) - endif() - - target_include_directories(momo PRIVATE ${_VC_PATH}/include) - target_compile_options(momo PRIVATE -ftree-vectorize -pipe) - target_compile_definitions(momo - PRIVATE - STANDALONE - __STDC_CONSTANT_MACROS - __STDC_LIMIT_MACROS - TARGET_POSIX - _LINUX - PIC - _REENTRANT - _LARGEFILE64_SOURCE - _FILE_OFFSET_BITS=64 - _FORTIFY_SOURCE - HAVE_LIBOPENMAX=2 - OMX - OMX_SKIP64BIT - USE_EXTERNAL_OMX - HAVE_LIBBCM_HOST - USE_EXTERNAL_LIBBCM_HOST - USE_VCHIQ_ARM - ) - target_link_directories(momo PRIVATE ${_VC_PATH}/lib) - target_link_libraries(momo - PRIVATE - GLESv2 - EGL - bcm_host - containers - vcos - vcsm - vchiq_arm - mmal - mmal_core - mmal_components - mmal_util - mmal_vc_client - m - ) - - endif(USE_MMAL_ENCODER) - endif(TARGET_ARCH_ARM STREQUAL "armv8") - endif(TARGET_ARCH STREQUAL "arm") + endif() + endif() endif() diff --git a/NOTICE b/NOTICE index 68d2b4b9..6b651c2c 100644 --- a/NOTICE +++ b/NOTICE @@ -1301,10 +1301,14 @@ violation of the foregoing will be null and void. The terms of this Agreement shall be binding upon assignees. ``` -## Intel Media SDK +## oneVPL + +https://github.com/intel/libvpl ``` -Copyright (c) 2017 Intel Corporation +MIT License + +Copyright (c) 2020 Intel Corporation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -1324,3 +1328,33 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` + +# OpenH264 + +https://github.com/cisco/openh264 + +``` +Copyright (c) 2013, Cisco Systems +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +``` diff --git a/README.en.md b/README.en.md index 4d90c856..0ca975db 100644 --- a/README.en.md +++ b/README.en.md @@ -8,7 +8,7 @@ We will not respond to PRs or issues that have not been discussed on Discord. Also, Discord is only available in Japanese. -Please read https://github.com/shiguredo/oss before use. +Please read before use. ## About WebRTC Native Client Momo @@ -18,7 +18,7 @@ When Momo runs on Jetson Xavier NX / AGX, it is possible to deliver 4K video com ## Binary for Jetson Xavier NX / AGX Download the latest version of the binary for Jetson Xavier NX / AGX from below. -https://github.com/shiguredo/momo/releases + ``` momo-_ubuntu-20.04_armv8_jetson_xavier.tar.gz @@ -28,13 +28,13 @@ momo-_ubuntu-20.04_armv8_jetson_xavier.tar.gz First, try "test mode", where Momo itself has a function as a signaling server. -```shell -$ ./momo --no-audio-device --port 8080 test +```bash +./momo --no-audio-device --port 8080 test ``` If momo's IP address is 192.0.2.100, access the following URL and try to connect from WebRTC-compatible browser. -http://192.0.2.100:8080/html/test + ## Use "Ayame mode" @@ -42,8 +42,8 @@ http://192.0.2.100:8080/html/test The room ID is "open-momo-en" in the sample, but it is recommended to use an ID that is difficult to guess. -```shell -$ ./momo --no-audio-device ayame wss://ayame-labo.shiguredo.jp/signaling open-momo-en +```bash +./momo --no-audio-device ayame wss://ayame-labo.shiguredo.jp/signaling open-momo-en ``` Check with the online sample of Ayame Web SDK. diff --git a/README.md b/README.md index 6032cbc5..f0948e5f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # WebRTC Native Client Momo -[![libwebrtc](https://img.shields.io/badge/libwebrtc-m117.5938-blue.svg)](https://chromium.googlesource.com/external/webrtc/+/branch-heads/5938) +[![libwebrtc](https://img.shields.io/badge/libwebrtc-m128.6613-blue.svg)](https://chromium.googlesource.com/external/webrtc/+/branch-heads/6613) [![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/shiguredo/momo.svg)](https://github.com/shiguredo/momo) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Actions Status](https://github.com/shiguredo/momo/workflows/daily-build-workflow/badge.svg)](https://github.com/shiguredo/momo/actions) @@ -9,29 +9,44 @@ We will not respond to PRs or issues that have not been discussed on Discord. Also, Discord is only available in Japanese. -Please read https://github.com/shiguredo/oss/blob/master/README.en.md before use. +Please read before use. ## 時雨堂のオープンソースソフトウェアについて -利用前に https://github.com/shiguredo/oss をお読みください。 +利用前に をお読みください。 ## WebRTC Native Client Momo について WebRTC Native Client Momo は libwebrtc を利用しブラウザなしで様々な環境で動作する WebRTC ネイティブクライアントです。 -https://momo.shiguredo.jp/ + -### ハードウェアエンコーダーへの対応 +### ハードウェアアクセラレーターへの対応 -- [NVIDIA Jetson](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/) に搭載されている VP8 や VP9 や H.264 ハードウェアエンコーダー機能を利用することで 4K@30 での配信が可能です -- [Raspberry Pi](https://www.raspberrypi.org/) の GPU に積まれている H.264 ハードウェアエンコーダー機能を利用することが可能です -- Apple macOS に搭載されている H.264 ハードウェアアクセラレーター機能を [VideoToolbox](https://developer.apple.com/documentation/videotoolbox) 経由で利用することが可能です -- NVIDIA グラフィックスカードに搭載されているハードウェアアクセラレーター機能を [NVIDIA VIDEO CODEC SDK](https://developer.nvidia.com/nvidia-video-codec-sdk) 経由で利用することが可能です -- [Intel Quick Sync Video](https://www.intel.co.jp/content/www/jp/ja/architecture-and-technology/quick-sync-video/quick-sync-video-general.html) を [Intel Media SDK](https://www.intel.com/content/www/us/en/developer/tools/media-sdk/overview.html) 経由で Windows x86_64 と Ubuntu x86_64 にて VP9 / H.264 ハードウェアアクセラレーター機能を利用することが可能です +- Intel グラフィックスチップに搭載されているハードウェアアクセラレーター機能を [Intel VPL](https://www.intel.com/content/www/us/en/developer/tools/vpl/overview.html) 経由で Windows x86_64 と Ubuntu x86_64 にてハードウェアアクセラレーター機能を利用することが可能です + - VP9 /AV1 の送信時、[既知の問題](https://github.com/shiguredo/momo/issues/357) がありますのでご確認ください + - ハードウェアエンコーダー: VP9 / AV1 / H.264 / H.265 + - ハードウェアデコーダー: VP9 / AV1 / H.264 / H.265 +- Apple macOS に搭載されているハードウェアアクセラレーター機能を [Apple VideoToolbox](https://developer.apple.com/documentation/videotoolbox) 経由で利用することができます + - ハードウェアエンコーダー: H.264 / H.265 + - ハードウェアデコーダー: H.264 / H.265 +- NVIDIA グラフィックスカードに搭載されているハードウェアアクセラレーター機能を [NVIDIA Video Codec SDK](https://developer.nvidia.com/nvidia-video-codec-sdk) 経由で利用することができます + - ハードウェアエンコーダー: VP9 / AV1 / H.264 / H.265 + - ハードウェアデコーダー: VP9 / AV1 / H.264 / H.265 +- [NVIDIA Jetson](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/) に搭載されているハードウェアアクセラレーター機能を [Jetson JetPack SDK](https://developer.nvidia.com/embedded/jetpack) 経由で利用することができます + - ハードウェアエンコーダー: VP9 / AV1 / H.264 / H.265 + - ハードウェアデコーダー: VP9 / AV1 / H.264 / H.265 +- [Raspberry Pi](https://www.raspberrypi.org/) の GPU に積まれているハードウェアアクセラレーター機能を利用することができます + - ハードウェアエンコーダー: H.264 + - ハードウェアデコーダー: H.264 -### 4K 30fps での配信 +### 4K の配信 -Momo はハードウェアエンコーダーを利用することで WebRTC で 4K 60fps の配信を実現可能です +Momo はハードウェアエンコーダーを利用することで WebRTC で 4K の配信を実現可能です + +### 4K の視聴 + +Momo はハードウェアデコーダーを利用することで WebRTC で 4K の配信を実現可能です ### サイマルキャストへの対応 @@ -53,6 +68,10 @@ AV1 の送受信に対応済みです。 Momo は Sora モード利用時にクライアント証明書に対応しています。 +### OpenH264 の利用 + +Momo は OpenH264 を利用して H.264 のソフトウェアのエンコード/デコードを行うことができます。 + ## 動画 [WebRTC Native Client Momo と Jetson Nano で 4K@30 配信](https://www.youtube.com/watch?v=z05bWtsgDPY) @@ -68,7 +87,7 @@ OpenMomo は WebRTC Native Client Momo をオープンソースとして公開 また Momo についてのつぶやきは以下にまとめてあります。 -https://gist.github.com/voluntas/51c67d0d8ce7af9f24655cee4d7dd253#twitter + ## 既知の問題について @@ -78,41 +97,37 @@ https://gist.github.com/voluntas/51c67d0d8ce7af9f24655cee4d7dd253#twitter 以下からダウンロードが可能です。 -https://github.com/shiguredo/momo/releases + ## 動作環境 -- Raspberry Pi OS (64bit) ARMv8 - - Raspberry Pi 4 - - Raspberry Pi 3 - - Raspberry Pi 2 -- Raspberry Pi OS (32bit) ARMv7 - - Raspberry Pi 4 - - Raspberry Pi 3 - - Raspberry Pi 2 - - Raspberry Pi Zero 2 -- Raspberry Pi OS (32bit) ARMv6 - - Raspberry Pi Zero - - Raspberry Pi 1 -- Ubuntu 20.04 x86_64 +- Windows 11 x86_64 +- macOS 14 arm64 +- Ubuntu 24.04 x86_64 - Ubuntu 22.04 x86_64 -- Ubuntu 20.04 ARMv8 Jetson - - [NVIDIA Jetson AGX Orin](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-orin/) - - [NVIDIA Jetson AGX Xavier](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-agx-xavier/) - - [NVIDIA Jetson Xavier NX](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-xavier-nx/) -- macOS 12 arm64 以降 -- Windows 10.1809 x86_64 以降 +- Ubuntu 22.04 ARMv8 (NVIDIA Jetson JetPack 6) + - [NVIDIA Jetson AGX Orin](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-orin/) + - [NVIDIA Jetson Orin NX](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-orin/) +- Raspberry Pi OS (64bit) + - Raspberry Pi 4 + - Raspberry Pi 3 + - Raspberry Pi 2 Model B v1.2 + - Raspberry Pi Zero 2 W + +### 対応終了 -### 非対応 +**優先実装にて対応することができます** - macOS x86_64 -- Ubuntu 20.04 ARMv8 Jetson - - [NVIDIA Jetson Orin Nano](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-orin/) - - Jetson Orin Nano は HWA を詰んでいないので対応はしません -- Ubuntu 18.04 ARMv8 Jetson - - [NVIDIA Jetson Nano](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/) - - [NVIDIA Jetson Xavier NX](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-xavier-nx/) - - [NVIDIA Jetson AGX Xavier](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-agx-xavier/) +- Ubuntu 20.04 ARMv8 (NVIDIA Jetson JetPack 5) + - [NVIDIA Jetson AGX Orin](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-orin/) + - [NVIDIA Jetson AGX Xavier](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-agx-xavier/) + - [NVIDIA Jetson Xavier NX](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-xavier-nx/) +- Ubuntu 18.04 ARMv8 (NVIDIA Jetson JetPack 4) + - [NVIDIA Jetson Nano](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-nano/) + - [NVIDIA Jetson Xavier NX](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-xavier-nx/) + - [NVIDIA Jetson AGX Xavier](https://www.nvidia.com/ja-jp/autonomous-machines/embedded-systems/jetson-agx-xavier/) +- Raspberry Pi OS (32bit) ## 使ってみる @@ -120,13 +135,7 @@ Momo を使ってみたい人は [USE.md](doc/USE.md) をお読みください ## ビルドする -- Linux 版 Momo のビルドしたい人は [BUILD_LINUX.md](doc/BUILD_LINUX.md) をお読みください -- macOS 版 Momo のビルドしたい人は [BUILD_MACOS.md](doc/BUILD_MACOS.md) をお読みください -- Windows 版 Momo のビルドしたい人は [BUILD_WINDOWS.md](doc/BUILD_WINDOWS.md) をお読みください - -## パッケージを作成する - -パッケージ作成したい人は [PACKAGE.md](doc/PACKAGE.md) をお読みください。 +- Momo をビルドしたい、またはパッケージ作成したい人は [BUILD.md](doc/BUILD.md) をお読みください ## FAQ @@ -136,9 +145,9 @@ Momo を使ってみたい人は [USE.md](doc/USE.md) をお読みください Apache License 2.0 -``` -Copyright 2015-2022, tnoho (Original Author) -Copyright 2018-2022, Shiguredo Inc. +```text +Copyright 2015-2024, tnoho (Original Author) +Copyright 2018-2024, Shiguredo Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -153,42 +162,41 @@ See the License for the specific language governing permissions and limitations under the License. ``` +## OpenH264 + + + +```text +"OpenH264 Video Codec provided by Cisco Systems, Inc." +``` + ## 優先実装 優先実装とは Sora のライセンスを契約頂いているお客様限定で Momo の実装予定機能を有償にて前倒しで実装することです。 - Windows 版 OSS 化 - - [スロースネットワークス株式会社](http://www.sloth-networks.co.jp) 様 + - [スロースネットワークス株式会社](http://www.sloth-networks.co.jp) 様 - WebRTC's Statistics 対応 - - 現時点では企業名非公開 -- Windows 版 Momo NVIDIA VIDEO CODEC SDK 対応 - - [スロースネットワークス株式会社](http://www.sloth-networks.co.jp) 様 -- Linux 版 Momo NVIDIA VIDEO CODEC SDK 対応 - - [株式会社オプティム](https://www.optim.co.jp/) 様 + - 現時点では企業名非公開 +- Windows 版 Momo NVIDIA Video Codec SDK 対応 + - [スロースネットワークス株式会社](http://www.sloth-networks.co.jp) 様 +- Linux 版 Momo NVIDIA Video Codec SDK 対応 + - [株式会社オプティム](https://www.optim.co.jp/) 様 - Windows / Linux 版 スクリーンキャプチャ対応 - - [スロースネットワークス株式会社](http://www.sloth-networks.co.jp) 様 + - [スロースネットワークス株式会社](http://www.sloth-networks.co.jp) 様 ### 優先実装が可能な機能一覧 -**詳細は Discord やメールなどでお気軽にお問い合わせください** +**こちらに掲載していない機能でも対応できる場合がありますのでまずはお問い合わせください** -- oneVPL 対応 -- AV1 対応 - - Windows -- 統計機能 - - Ayame のシグナリング 経由での出力 -- 録画対応 - - MP4 形式での出力 - - WebM 形式での出力 -- 録画合成対応 -- Sora モード利用時の E2EE 機能 -- Windows / macOS 署名対応 +- Windows 11 arm64 +- Ubuntu 20.04 arm64 (NVIDIA Jetson JetPack 5) ## Momo についての電子書籍 Momo の原作者である @tnoho が書いた Momo のノウハウが沢山詰まった本が販売されています。 -[WebRTCをブラウザ外で使ってブラウザでできることを増やしてみませんか?\(電子版\) \- でんでんらぼ \- BOOTH](https://tnoho.booth.pm/items/1572872) +[WebRTC をブラウザ外で使ってブラウザでできることを増やしてみませんか?\(電子版\) \- でんでんらぼ \- BOOTH](https://tnoho.booth.pm/items/1572872) ## サポートについて @@ -200,7 +208,7 @@ Momo の原作者である @tnoho が書いた Momo のノウハウが沢山詰 最新の状況などは Discord で共有しています。質問や相談も Discord でのみ受け付けています。 -https://discord.gg/shiguredo + ### バグ報告 @@ -221,18 +229,36 @@ H.264 ハードウェアエンコーダー **のみ** を利用している Momo ただし、 Raspberry Pi においては H.264 のライセンスがハードウェア費用に含まれているため、 配布時にライセンス費用を支払う必要はありません。 -詳細については [MPEG LA](https://www.mpegla.com/) まで問い合わせる事をおすすめします。 +詳細については [Via LA Licensing](https://www.via-la.com/) まで問い合わせる事をおすすめします。 + +Momo の H.264 対応は [Via LA Licensing](https://www.via-la.com/) (旧 MPEG-LA) に連絡を取り、ロイヤリティの対象にならないことを確認しています。 + +> 時雨堂がエンドユーザーの PC /デバイスに既に存在する AVC / H.264 エンコーダー/デコーダーに依存する製品を提供する場合は、 +> ソフトウェア製品は AVC ライセンスの対象外となり、ロイヤリティの対象にもなりません。 - Raspberry Pi のハードウェアエンコーダーのライセンス費用は Raspberry Pi の価格に含まれています - - https://www.raspberrypi.org/forums/viewtopic.php?t=200855 + - - Apple のライセンス費用は個人利用および非商用利用目的に限るため、配布においては別途、団体との契約が必要 - - https://store.apple.com/Catalog/Japan/Images/EA0270_QTMPEG2.html + - - AMD ビデオカードのハードウェアエンコーダーのライセンス費用は別途、団体との契約が必要 - - https://github.com/GPUOpen-LibrariesAndSDKs/AMF/blob/master/amf/doc/AMF_API_Reference.pdf + - - NVIDIA ビデオカードのハードウェアエンコーダーのライセンス費用は別途、団体との契約が必要 - - https://developer.download.nvidia.com/designworks/DesignWorks_SDKs_Samples_Tools_License_distrib_use_rights_2017_06_13.pdf + - - NVIDIA Jetson Nano のハードウェアエンコーダーのライセンス費用は別途、団体との契約が必要 - - [NVIDIA Jetson Nano 搭載の H\.264/H\.265 ハードウェアエンコーダーのライセンスについて](https://medium.com/@voluntas/nvidia-jetson-nano-%E6%90%AD%E8%BC%89%E3%81%AE-h-264-h-265-%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%80%E3%81%AE%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6-ca207af302ee) + - [NVIDIA Jetson Nano 搭載の H\.264/H\.265 ハードウェアエンコーダーのライセンスについて](https://medium.com/@voluntas/nvidia-jetson-nano-%E6%90%AD%E8%BC%89%E3%81%AE-h-264-h-265-%E3%83%8F%E3%83%BC%E3%83%89%E3%82%A6%E3%82%A7%E3%82%A2%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%80%E3%81%AE%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6-ca207af302ee) - Intel Quick Sync Video のハードウェアエンコーダーライセンス費用は別途、団体との契約が必要 - - [QuickSync \- H\.264 patent licensing fees \- Intel Community](https://community.intel.com/t5/Media-Intel-oneAPI-Video/QuickSync-H-264-patent-licensing-fees/td-p/921396) + - [QuickSync \- H\.264 patent licensing fees \- Intel Community](https://community.intel.com/t5/Media-Intel-oneAPI-Video/QuickSync-H-264-patent-licensing-fees/td-p/921396) + +## H.265 のライセンス費用について + +H.265 ハードウェアエンコーダー **のみ** を利用している Momo 単体の配布においてはライセンス費用は不要ですが、 +ハードウェアとセットで配布する場合はライセンス費用を支払う必要があります。 + +Momo の H.265 対応は以下の二つの団体に連絡を取り、H.265 ハードウェアアクセラレーターのみを利用し、 +H.265 が利用可能なバイナリを配布する事は、ライセンスが不要であることを確認しています。 + +また、H.265 のハードウェアアクセラレーターのみを利用した H.265 対応の Momo を OSS で公開し、 +ビルド済みバイナリを配布する事は、ライセンスが不要であることも確認しています。 +- [Access Advance](https://accessadvance.com/ja/) +- [Via LA Licensing](https://www.via-la.com/) diff --git a/VERSION b/VERSION index 50f88400..43b44cb7 100644 --- a/VERSION +++ b/VERSION @@ -1,10 +1,9 @@ -MOMO_VERSION=2023.1.0 -WEBRTC_BUILD_VERSION=117.5938.2.0 -BOOST_VERSION=1.83.0 -CLI11_VERSION=2.3.2 -SDL2_VERSION=2.28.3 -CMAKE_VERSION=3.27.6 -CUDA_VERSION=11.0.2-1 -WINCUDA_VERSION=10.2 -LIBVA_VERSION=2.7.0 -MSDK_VERSION=20.1.1 +MOMO_VERSION=2024.1.0 +WEBRTC_BUILD_VERSION=m128.6613.2.0 +BOOST_VERSION=1.86.0 +CLI11_VERSION=v2.4.2 +SDL2_VERSION=2.30.7 +CMAKE_VERSION=3.30.3 +CUDA_VERSION=11.8.0-1 +VPL_VERSION=v2.13.0 +OPENH264_VERSION=v2.4.1 diff --git a/build/TRIGGER b/build/TRIGGER deleted file mode 100644 index 136c7d54..00000000 --- a/build/TRIGGER +++ /dev/null @@ -1,3 +0,0 @@ -# CI を走らせるためだけに存在するファイル - -trigger diff --git a/build/build.bat b/build/build.bat deleted file mode 100644 index e46eaade..00000000 --- a/build/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -powershell -NoProfile -ExecutionPolicy Unrestricted .\build.ps1 %* -pause \ No newline at end of file diff --git a/build/build.ps1 b/build/build.ps1 deleted file mode 100644 index 55eb2da8..00000000 --- a/build/build.ps1 +++ /dev/null @@ -1,80 +0,0 @@ -Param([switch]$clean, [switch]$package) - -$WINDOWS_ARCH = "x86_64" - -$ErrorActionPreference = 'Stop' - -if ($clean) { - if (Test-Path "windows_${WINDOWS_ARCH}\_source") { - Remove-Item "windows_${WINDOWS_ARCH}\_source" -Force -Recurse - } - if (Test-Path "windows_${WINDOWS_ARCH}\_build") { - Remove-Item "windows_${WINDOWS_ARCH}\_build" -Force -Recurse - } - if (Test-Path "windows_${WINDOWS_ARCH}\_install") { - Remove-Item "windows_${WINDOWS_ARCH}\_install" -Force -Recurse - } - if (Test-Path "..\_build\windows_${WINDOWS_ARCH}") { - Remove-Item "..\_build\windows_${WINDOWS_ARCH}" -Force -Recurse - } - exit 0 -} - -Push-Location "windows_${WINDOWS_ARCH}" - .\install_deps.ps1 -Pop-Location - -$WEBRTC_VERSION_FILE = Join-Path (Resolve-Path ".").Path "windows_${WINDOWS_ARCH}\_install\webrtc\VERSIONS" -Get-Content $WEBRTC_VERSION_FILE | Foreach-Object { - if (!$_) { - continue - } - $var = $_.Split('=') - New-Variable -Name $var[0] -Value $var[1] -Force -} -$MOMO_VERSION_FILE = Join-Path (Resolve-Path ".").Path "..\VERSION" -Get-Content $MOMO_VERSION_FILE | Foreach-Object { - if (!$_) { - continue - } - $var = $_.Split('=') - New-Variable -Name $var[0] -Value $var[1] -Force -} - -$MOMO_COMMIT = "$(git rev-parse HEAD)" - -mkdir "..\_build\windows_${WINDOWS_ARCH}" -Force -ErrorAction Ignore -Push-Location "..\_build\windows_${WINDOWS_ARCH}" - cmake ..\.. -G "Visual Studio 16 2019" ` - -DCMAKE_SYSTEM_VERSION=10.0.20348.0 ` - -DMOMO_PACKAGE_NAME="windows_${WINDOWS_ARCH}" ` - -DMOMO_VERSION="$MOMO_VERSION" ` - -DMOMO_COMMIT="$MOMO_COMMIT" ` - -DWEBRTC_BUILD_VERSION="$WEBRTC_BUILD_VERSION" ` - -DWEBRTC_READABLE_VERSION="$WEBRTC_READABLE_VERSION" ` - -DWEBRTC_COMMIT="$WEBRTC_COMMIT" - cmake --build . --config Release -Pop-Location - -if ($package) { - # パッケージのバイナリを作る - Push-Location .. - $WINVER_MAJOR = [System.Environment]::OSVersion.Version.Major - $RELEASE_ID = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseId).ReleaseID - if (Test-Path "_package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}.zip") { - Remove-Item "_package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}.zip" -Force - } - if (Test-Path "_package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}") { - Remove-Item "_package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}" -Force -Recurse - } - mkdir -Force "_package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}" - Copy-Item _build\windows_${WINDOWS_ARCH}\Release\momo.exe _package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}\ - Copy-Item LICENSE _package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}\ - Copy-Item NOTICE _package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}\ - Copy-Item html _package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}\html\ -Recurse - Push-Location _package - Compress-Archive -Path "momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}" -DestinationPath "momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}.zip" - Pop-Location - Remove-Item "_package\momo-${MOMO_VERSION}_windows-${WINVER_MAJOR}.${RELEASE_ID}_${WINDOWS_ARCH}" -Force -Recurse - Pop-Location -} \ No newline at end of file diff --git a/build/build.sh b/build/build.sh deleted file mode 100755 index f942087d..00000000 --- a/build/build.sh +++ /dev/null @@ -1,234 +0,0 @@ -#!/bin/bash - -cd "`dirname $0`" - -# 引数の処理 - -PROGRAM="$0" - -_PACKAGES=" \ - windows \ - macos_arm64 \ - raspberry-pi-os_armv6 \ - raspberry-pi-os_armv7 \ - raspberry-pi-os_armv8 \ - ubuntu-20.04_armv8_jetson_xavier \ - ubuntu-20.04_x86_64 \ - ubuntu-22.04_x86_64 \ -" - -function show_help() { - echo "$PROGRAM [--clean] [--package] [--no-cache] [--no-tty] [--no-mount] [--debug] " - echo ":" - for package in $_PACKAGES; do - echo " - $package" - done -} - -PACKAGE="" -FLAG_CLEAN=0 -FLAG_PACKAGE=0 -DOCKER_BUILD_FLAGS="" -DOCKER_MOUNT_TYPE=mount -DEBUG=0 - -while [ $# -ne 0 ]; do - case "$1" in - "--clean" ) FLAG_CLEAN=1 ;; - "--package" ) FLAG_PACKAGE=1 ;; - "--no-cache" ) DOCKER_BUILD_FLAGS="$DOCKER_BUILD_FLAGS --no-cache" ;; - "--no-tty" ) DOCKER_BUILD_FLAGS="$DOCKER_BUILD_FLAGS --progress=plain" ;; - "--no-mount" ) DOCKER_MOUNT_TYPE=nomount ;; - "--debug" ) DEBUG=1 ;; - --* ) - show_help - exit 1 - ;; - * ) - if [ -n "$PACKAGE" ]; then - show_help - exit 1 - fi - PACKAGE="$1" - ;; - esac - shift 1 -done - -DOCKER_PLATFORM="" -if [ "`uname -sm`" = "Darwin arm64" ]; then - # M1 Mac の場合は --platform を指定する - DOCKER_PLATFORM="--platform=linux/amd64" -fi - -_FOUND=0 -for package in $_PACKAGES; do - if [ "$PACKAGE" = "$package" ]; then - _FOUND=1 - break - fi -done - -if [ $_FOUND -eq 0 ]; then - show_help - exit 1 -fi - -echo "--clean: " $FLAG_CLEAN -echo "--package: " $FLAG_PACKAGE -echo ": " $PACKAGE - -set -ex - -pushd .. - MOMO_COMMIT="`git rev-parse HEAD`" - MOMO_COMMIT_SHORT="`cat $MOMO_COMMIT | cut -b 1-8`" -popd - -source ../VERSION - -case "$PACKAGE" in - "windows_x86_64" ) - echo "Windows では build.bat を利用してください。" - exit 1 - ;; - macos_arm64 ) - if [ $FLAG_CLEAN -eq 1 ]; then - rm -rf ../_build/$PACKAGE - rm -rf $PACKAGE/_source - rm -rf $PACKAGE/_build - rm -rf $PACKAGE/_install - exit 0 - fi - - ./$PACKAGE/install_deps.sh - - source ./$PACKAGE/_install/webrtc/VERSIONS - - if [ -z "$JOBS" ]; then - JOBS=`sysctl -n hw.logicalcpu_max` - if [ -z "$JOBS" ]; then - JOBS=1 - fi - fi - - if [ $DEBUG -eq 1 ]; then - BUILD_TYPE=Debug - else - BUILD_TYPE=Release - fi - - mkdir -p ../_build/$PACKAGE - pushd ../_build/$PACKAGE - cmake \ - -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ - -DMOMO_PACKAGE_NAME="$PACKAGE" \ - -DMOMO_VERSION="$MOMO_VERSION" \ - -DMOMO_COMMIT="$MOMO_COMMIT" \ - -DWEBRTC_BUILD_VERSION="$WEBRTC_BUILD_VERSION" \ - -DWEBRTC_READABLE_VERSION="$WEBRTC_READABLE_VERSION" \ - -DWEBRTC_COMMIT="$WEBRTC_COMMIT" \ - ../.. - cmake --build . -j$JOBS - popd - - if [ $FLAG_PACKAGE -eq 1 ]; then - MACOS_VERSION=`sw_vers -productVersion | cut -d '.' -f-2` - - pushd .. - # パッケージのバイナリを作る - MACOS_ARCH=${PACKAGE#"macos_"} - rm -rf _package/momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH} - rm -f _package/momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH}.tar.gz - mkdir -p _package/momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH} - cp _build/${PACKAGE}/momo _package/momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH}/ - cp LICENSE _package/momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH}/ - cp NOTICE _package/momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH}/ - cp -r html _package/momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH}/html - pushd _package - tar czf momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH}.tar.gz momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH} - popd - - rm -rf _package/momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH} - echo "" - echo "パッケージが _package/momo-${MOMO_VERSION}_macos-${MACOS_VERSION}_${MACOS_ARCH}.tar.gz に生成されました。" - popd - fi - - ;; - * ) - if [ $FLAG_CLEAN -eq 1 ]; then - rm -rf ../_build/$PACKAGE - IMAGES="`docker image ls -q momo/$PACKAGE`" - if [ -n "$IMAGES" ]; then - docker image rm $IMAGES - fi - docker builder prune -f --filter=label=jp.shiguredo.momo=$PACKAGE - exit 0 - fi - - rm -rf $PACKAGE/script - cp -r ../script $PACKAGE/script - rm -rf $PACKAGE/patch - cp -r ../patch $PACKAGE/patch - - # 可能な限りキャッシュを利用する - mkdir -p $PACKAGE/_cache/boost/ - if [ -e ../_cache/boost/ ]; then - cp -r ../_cache/boost/* $PACKAGE/_cache/boost/ - fi - - DOCKER_BUILDKIT=1 docker build $DOCKER_PLATFORM \ - -t momo/$PACKAGE:m$WEBRTC_BUILD_VERSION \ - $DOCKER_BUILD_FLAGS \ - --build-arg WEBRTC_BUILD_VERSION=$WEBRTC_BUILD_VERSION \ - --build-arg BOOST_VERSION=$BOOST_VERSION \ - --build-arg SDL2_VERSION=$SDL2_VERSION \ - --build-arg CLI11_VERSION=$CLI11_VERSION \ - --build-arg CMAKE_VERSION=$CMAKE_VERSION \ - --build-arg CUDA_VERSION=$CUDA_VERSION \ - --build-arg LIBVA_VERSION=$LIBVA_VERSION \ - --build-arg MSDK_VERSION=$MSDK_VERSION \ - --build-arg PACKAGE_NAME=$PACKAGE \ - $PACKAGE - - rm -rf $PACKAGE/_cache/boost/ - - # キャッシュしたデータを取り出す - set +e - docker $DOCKER_PLATFORM container create -it --name momo-$PACKAGE momo/$PACKAGE:m$WEBRTC_BUILD_VERSION - docker container start momo-$PACKAGE - mkdir -p ../_cache/boost/ - docker container cp momo-$PACKAGE:/root/_cache/boost/. ../_cache/boost/ - docker container stop momo-$PACKAGE - docker container rm momo-$PACKAGE - set -e - - rm -r $PACKAGE/script - rm -r $PACKAGE/patch - - ../script/docker_run.sh `pwd` `pwd`/.. $DOCKER_MOUNT_TYPE $PACKAGE momo/$PACKAGE:m$WEBRTC_BUILD_VERSION $MOMO_COMMIT - - if [ $FLAG_PACKAGE -eq 1 ]; then - pushd .. - rm -rf _package/momo-${MOMO_VERSION}_${PACKAGE} - rm -f _package/momo-${MOMO_VERSION}_${PACKAGE}.tar.gz - mkdir -p _package/momo-${MOMO_VERSION}_${PACKAGE} - cp _build/${PACKAGE}/momo _package/momo-${MOMO_VERSION}_${PACKAGE}/ - cp LICENSE _package/momo-${MOMO_VERSION}_${PACKAGE}/ - cp NOTICE _package/momo-${MOMO_VERSION}_${PACKAGE}/ - cp -r html _package/momo-${MOMO_VERSION}_${PACKAGE}/html - if [ -e _build/${PACKAGE}/libcamerac.so ]; then - cp _build/${PACKAGE}/libcamerac.so _package/momo-${MOMO_VERSION}_${PACKAGE}/ - fi - pushd _package - tar czf momo-${MOMO_VERSION}_${PACKAGE}.tar.gz momo-${MOMO_VERSION}_${PACKAGE} - popd - - rm -rf _package/momo-${MOMO_VERSION}_${PACKAGE} - echo "" - echo "パッケージが _package/momo-${MOMO_VERSION}_${PACKAGE}.tar.gz に生成されました。" - popd - fi - ;; -esac diff --git a/build/macos_arm64/install_deps.sh b/build/macos_arm64/install_deps.sh deleted file mode 100755 index d4856cf0..00000000 --- a/build/macos_arm64/install_deps.sh +++ /dev/null @@ -1,166 +0,0 @@ -#!/bin/bash - -cd "`dirname $0`" - -set -ex - -ARCH_NAME="aarch64-apple-darwin" - -SOURCE_DIR="`pwd`/_source" -BUILD_DIR="`pwd`/_build" -INSTALL_DIR="`pwd`/_install" -CACHE_DIR="`pwd`/../../_cache" - -mkdir -p $SOURCE_DIR -mkdir -p $BUILD_DIR -mkdir -p $INSTALL_DIR -mkdir -p $CACHE_DIR - -source ../../VERSION - -if [ -z "$JOBS" ]; then - JOBS=`sysctl -n hw.logicalcpu_max` - if [ -z "$JOBS" ]; then - JOBS=1 - fi -fi - -# CLI11 -CLI11_VERSION_FILE="$INSTALL_DIR/cli11.version" -CLI11_CHANGED=0 -if [ ! -e $CLI11_VERSION_FILE -o "$CLI11_VERSION" != "`cat $CLI11_VERSION_FILE`" ]; then - CLI11_CHANGED=1 -fi - -if [ $CLI11_CHANGED -eq 1 -o ! -e $INSTALL_DIR/CLI11/include/CLI/Version.hpp ]; then - pushd $INSTALL_DIR - rm -rf CLI11 - git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git - popd -fi -echo $CLI11_VERSION > $CLI11_VERSION_FILE - -# WebRTC -WEBRTC_VERSION_FILE="$INSTALL_DIR/webrtc.version" -WEBRTC_CHANGED=0 -if [ ! -e $WEBRTC_VERSION_FILE -o "$WEBRTC_BUILD_VERSION" != "`cat $WEBRTC_VERSION_FILE`" ]; then - WEBRTC_CHANGED=1 -fi - -if [ $WEBRTC_CHANGED -eq 1 -o ! -e $INSTALL_DIR/webrtc/lib/libwebrtc.a ]; then - rm -rf $INSTALL_DIR/webrtc - ../../script/get_webrtc.sh $WEBRTC_BUILD_VERSION macos_arm64 $INSTALL_DIR $SOURCE_DIR -fi -echo $WEBRTC_BUILD_VERSION > $WEBRTC_VERSION_FILE - -# LLVM -if [ ! -e $INSTALL_DIR/llvm/clang/bin/clang++ ]; then - rm -rf $INSTALL_DIR/llvm - ../../script/get_llvm.sh $INSTALL_DIR/webrtc $INSTALL_DIR -fi - -# Boost -BOOST_VERSION_FILE="$INSTALL_DIR/boost.version" -BOOST_CHANGED=0 -if [ ! -e $BOOST_VERSION_FILE -o "$BOOST_VERSION" != "`cat $BOOST_VERSION_FILE`" ]; then - BOOST_CHANGED=1 -fi - -CLANG="`xcodebuild -find clang`" -CLANGPP="`xcodebuild -find clang++`" - -if [ $BOOST_CHANGED -eq 1 -o ! -e $INSTALL_DIR/boost/lib/libboost_filesystem.a ]; then - rm -rf $SOURCE_DIR/boost - rm -rf $BUILD_DIR/boost - rm -rf $INSTALL_DIR/boost - ../../script/setup_boost.sh $BOOST_VERSION $SOURCE_DIR/boost $CACHE_DIR/boost - pushd $SOURCE_DIR/boost/source - echo "using clang : : $CLANGPP : ;" > project-config.jam - SYSROOT="`xcrun --sdk macosx --show-sdk-path`" - ./b2 \ - cxxstd=17 \ - cflags=" \ - -target $ARCH_NAME \ - -mmacosx-version-min=11.0 \ - --sysroot=$SYSROOT \ - " \ - cxxflags=" \ - -target $ARCH_NAME \ - -mmacosx-version-min=11.0 \ - --sysroot=$SYSROOT \ - " \ - toolset=clang \ - visibility=hidden \ - link=static \ - variant=release \ - install \ - -d+0 \ - -j$JOBS \ - --build-dir=$BUILD_DIR/boost \ - --prefix=$INSTALL_DIR/boost \ - --ignore-site-config \ - --with-filesystem \ - --with-json - popd -fi -echo $BOOST_VERSION > $BOOST_VERSION_FILE - -# SDL2 -SDL2_VERSION_FILE="$INSTALL_DIR/sdl2.version" -SDL2_CHANGED=0 -if [ ! -e $SDL2_VERSION_FILE -o "$SDL2_VERSION" != "`cat $SDL2_VERSION_FILE`" ]; then - SDL2_CHANGED=1 -fi - -if [ $SDL2_CHANGED -eq 1 -o ! -e $INSTALL_DIR/SDL2/lib/libSDL2.a ]; then - rm -rf $SOURCE_DIR/SDL2 - rm -rf $BUILD_DIR/SDL2 - rm -rf $INSTALL_DIR/SDL2 - mkdir -p $SOURCE_DIR/SDL2 - mkdir -p $BUILD_DIR/SDL2 - ../../script/setup_sdl2.sh $SDL2_VERSION $SOURCE_DIR/SDL2 - pushd $BUILD_DIR/SDL2 - SYSROOT="`xcrun --sdk macosx --show-sdk-path`" - # システムでインストール済みかによって ON/OFF が切り替わってしまうため、 - # どの環境でも同じようにインストールされるようにするため全部 ON/OFF を明示的に指定する - cmake $SOURCE_DIR/SDL2/source \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/SDL2 \ - -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_SYSTEM_PROCESSOR=arm64 \ - -DCMAKE_OSX_ARCHITECTURES=arm64 \ - -DCMAKE_C_COMPILER=clang \ - -DCMAKE_C_COMPILER_TARGET=aarch64-apple-darwin \ - -DCMAKE_CXX_COMPILER=clang++ \ - -DCMAKE_CXX_COMPILER_TARGET=aarch64-apple-darwin \ - -DCMAKE_SYSROOT=$SYSROOT \ - -DSDL_ATOMIC=OFF \ - -DSDL_AUDIO=OFF \ - -DSDL_VIDEO=ON \ - -DSDL_RENDER=ON \ - -DSDL_EVENTS=ON \ - -DSDL_JOYSTICK=ON \ - -DSDL_HAPTIC=ON \ - -DSDL_POWER=ON \ - -DSDL_THREADS=ON \ - -DSDL_TIMERS=OFF \ - -DSDL_FILE=OFF \ - -DSDL_LOADSO=ON \ - -DSDL_CPUINFO=OFF \ - -DSDL_FILESYSTEM=OFF \ - -DSDL_SENSOR=ON \ - -DSDL_OPENGL=ON \ - -DSDL_OPENGLES=ON \ - -DSDL_RPI=OFF \ - -DSDL_WAYLAND=OFF \ - -DSDL_X11=OFF \ - -DSDL_VULKAN=OFF \ - -DSDL_VIVANTE=OFF \ - -DSDL_COCOA=ON \ - -DSDL_METAL=ON \ - -DSDL_KMSDRM=OFF - cmake --build . --config Release -j$JOBS - cmake --install . --config Release - popd -fi -echo $SDL2_VERSION > $SDL2_VERSION_FILE diff --git a/build/raspberry-pi-os_armv6/Dockerfile b/build/raspberry-pi-os_armv6/Dockerfile deleted file mode 100644 index 12969499..00000000 --- a/build/raspberry-pi-os_armv6/Dockerfile +++ /dev/null @@ -1,86 +0,0 @@ -# syntax = docker/dockerfile:1.1.1-experimental -FROM ubuntu:18.04 - -ARG PACKAGE_NAME - -LABEL jp.shiguredo.momo=$PACKAGE_NAME - -RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache - -# パッケージのインストール - -COPY script/apt_install_arm.sh /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/apt_install_arm.sh - -# RootFS の構築 - -COPY script/init_rootfs_armhf.sh /root/ -COPY rpi-raspbian.conf /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/init_rootfs_armhf.sh /root/rootfs /root/rpi-raspbian.conf - -# WebRTC の取得 - -ARG WEBRTC_BUILD_VERSION - -COPY script/get_webrtc.sh /root/ -RUN /root/get_webrtc.sh "$WEBRTC_BUILD_VERSION" raspberry-pi-os_armv6 /root /root - -# コンパイラの取得 - -COPY script/get_llvm.sh /root/ -RUN /root/get_llvm.sh /root/webrtc /root - -# Boost のビルド - -ARG BOOST_VERSION - -COPY _cache/boost/ /root/_cache/boost/ -COPY script/setup_boost.sh /root/ -RUN \ - set -ex \ - && /root/setup_boost.sh "$BOOST_VERSION" /root/boost-source /root/_cache/boost \ - && cd /root/boost-source/source \ - && echo 'using clang : : /root/llvm/clang/bin/clang++ : ;' > project-config.jam \ - && ./b2 \ - cxxstd=17 \ - cxxflags=' \ - -D_LIBCPP_ABI_NAMESPACE=Cr \ - -D_LIBCPP_ABI_VERSION=2 \ - -D_LIBCPP_DISABLE_AVAILABILITY \ - -nostdinc++ \ - -isystem/root/llvm/libcxx/include \ - --target=arm-linux-gnueabihf \ - --sysroot=/root/rootfs \ - -I/root/rootfs/usr/include/arm-linux-gnueabihf \ - ' \ - linkflags=' \ - -L/root/rootfs/usr/lib/arm-linux-gnueabihf \ - -B/root/rootfs/usr/lib/arm-linux-gnueabihf \ - ' \ - toolset=clang \ - visibility=global \ - target-os=linux \ - architecture=arm \ - address-model=32 \ - link=static \ - variant=release \ - install \ - -d+0 \ - -j`nproc` \ - --ignore-site-config \ - --prefix=/root/boost \ - --with-filesystem \ - --with-json - -# CLI11 の取得 - -ARG CLI11_VERSION -RUN git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git /root/CLI11 - -# CMake のインストール -ARG CMAKE_VERSION -COPY script/get_cmake.sh /root/ -RUN /root/get_cmake.sh "$CMAKE_VERSION" linux /root -ENV PATH "/root/cmake/bin:$PATH" diff --git a/build/raspberry-pi-os_armv6/rpi-raspbian.conf b/build/raspberry-pi-os_armv6/rpi-raspbian.conf deleted file mode 100644 index 0adf69ec..00000000 --- a/build/raspberry-pi-os_armv6/rpi-raspbian.conf +++ /dev/null @@ -1,19 +0,0 @@ -[General] -unpack=true -bootstrap=Ports Ports2 Rasp -aptsources=Ports Ports2 Rasp - -[Ports] -packages=libc6-dev libstdc++-10-dev libasound2-dev libpulse-dev libudev-dev libexpat1-dev libnss3-dev libxtst-dev libsdl2-dev -source=http://ftp.jaist.ac.jp/raspbian -suite=bullseye - -[Ports2] -packages=libc6-dev libstdc++-10-dev libasound2-dev libpulse-dev libudev-dev libexpat1-dev libnss3-dev libxtst-dev libsdl2-dev -source=http://ftp.tsukuba.wide.ad.jp/Linux/raspbian/raspbian -suite=bullseye - -[Rasp] -packages=libraspberrypi-bin libraspberrypi-dev -source=http://archive.raspberrypi.org/debian -suite=bullseye diff --git a/build/raspberry-pi-os_armv7/Dockerfile b/build/raspberry-pi-os_armv7/Dockerfile deleted file mode 100644 index 28a3f241..00000000 --- a/build/raspberry-pi-os_armv7/Dockerfile +++ /dev/null @@ -1,151 +0,0 @@ -# syntax = docker/dockerfile:1.1.1-experimental -FROM ubuntu:18.04 - -ARG PACKAGE_NAME - -LABEL jp.shiguredo.momo=$PACKAGE_NAME - -RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache - -# パッケージのインストール - -COPY script/apt_install_arm.sh /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/apt_install_arm.sh - -# RootFS の構築 - -COPY script/init_rootfs_armhf.sh /root/ -COPY rpi-raspbian.conf /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/init_rootfs_armhf.sh /root/rootfs /root/rpi-raspbian.conf - -# WebRTC の取得 - -ARG WEBRTC_BUILD_VERSION - -COPY script/get_webrtc.sh /root/ -RUN /root/get_webrtc.sh "$WEBRTC_BUILD_VERSION" raspberry-pi-os_armv7 /root /root - -# コンパイラの取得 - -COPY script/get_llvm.sh /root/ -RUN /root/get_llvm.sh /root/webrtc /root - -# Boost のビルド - -ARG BOOST_VERSION - -COPY _cache/boost/ /root/_cache/boost/ -COPY script/setup_boost.sh /root/ -RUN \ - set -ex \ - && /root/setup_boost.sh "$BOOST_VERSION" /root/boost-source /root/_cache/boost \ - && cd /root/boost-source/source \ - && echo 'using clang : : /root/llvm/clang/bin/clang++ : ;' > project-config.jam \ - && ./b2 \ - cxxstd=17 \ - cxxflags=' \ - -D_LIBCPP_ABI_NAMESPACE=Cr \ - -D_LIBCPP_ABI_VERSION=2 \ - -D_LIBCPP_DISABLE_AVAILABILITY \ - -nostdinc++ \ - -isystem/root/llvm/libcxx/include \ - --target=arm-linux-gnueabihf \ - --sysroot=/root/rootfs \ - -I/root/rootfs/usr/include/arm-linux-gnueabihf \ - ' \ - linkflags=' \ - -L/root/rootfs/usr/lib/arm-linux-gnueabihf \ - -B/root/rootfs/usr/lib/arm-linux-gnueabihf \ - ' \ - toolset=clang \ - visibility=global \ - target-os=linux \ - architecture=arm \ - address-model=32 \ - link=static \ - variant=release \ - install \ - -d+0 \ - -j`nproc` \ - --ignore-site-config \ - --prefix=/root/boost \ - --with-filesystem \ - --with-json - -# CLI11 の取得 - -ARG CLI11_VERSION -RUN git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git /root/CLI11 - -# CMake のインストール -ARG CMAKE_VERSION -COPY script/get_cmake.sh /root/ -RUN /root/get_cmake.sh "$CMAKE_VERSION" linux /root -ENV PATH "/root/cmake/bin:$PATH" - -# SDL2 のビルド - -ARG SDL2_VERSION - -COPY script/setup_sdl2.sh /root/ -RUN \ - set -ex \ - && /root/setup_sdl2.sh "$SDL2_VERSION" /root/sdl2-source \ - && mkdir -p /root/sdl2-source/build \ - && cd /root/sdl2-source/build \ - && cmake ../source \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/root/SDL2 \ - -DCMAKE_SYSTEM_NAME=Linux \ - -DCMAKE_SYSTEM_PROCESSOR=arm \ - -DCMAKE_C_COMPILER=/root/llvm/clang/bin/clang \ - -DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabihf \ - -DCMAKE_CXX_COMPILER=/root/llvm/clang/bin/clang++ \ - -DCMAKE_CXX_COMPILER_TARGET=arm-linux-gnueabihf \ - -DCMAKE_FIND_ROOT_PATH=/root/rootfs \ - -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ - -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ - -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH \ - -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \ - -DCMAKE_SYSROOT=/root/rootfs \ - -DSDL_STATIC=ON \ - -DSDL_SHARED=OFF \ - -DSDL_ATOMIC=OFF \ - -DSDL_AUDIO=OFF \ - -DSDL_VIDEO=ON \ - -DSDL_RENDER=ON \ - -DSDL_EVENTS=ON \ - -DSDL_JOYSTICK=ON \ - -DSDL_HAPTIC=ON \ - -DSDL_POWER=ON \ - -DSDL_THREADS=ON \ - -DSDL_TIMERS=OFF \ - -DSDL_FILE=OFF \ - -DSDL_LOADSO=ON \ - -DSDL_CPUINFO=OFF \ - -DSDL_FILESYSTEM=OFF \ - -DSDL_DLOPEN=ON \ - -DSDL_SENSOR=ON \ - -DSDL_COCOA=OFF \ - -DSDL_KMSDRM=OFF \ - -DSDL_METAL=OFF \ - -DSDL_OPENGL=ON \ - -DSDL_OPENGLES=ON \ - -DSDL_RPI=OFF \ - -DSDL_VIVANTE=OFF \ - -DSDL_VULKAN=OFF \ - -DSDL_WAYLAND=OFF \ - -DSDL_X11=ON \ - -DSDL_X11_SHARED=OFF \ - -DSDL_X11_XCURSOR=OFF \ - -DSDL_X11_XFIXES=OFF \ - -DSDL_X11_XINERAMA=OFF \ - -DSDL_X11_XINPUT=OFF \ - -DSDL_X11_XRANDR=OFF \ - -DSDL_X11_XSCRNSAVER=OFF \ - -DSDL_X11_XSHAPE=OFF \ - -DSDL_X11_XVM=OFF \ - && make -j`nproc` \ - && make install diff --git a/build/raspberry-pi-os_armv7/rpi-raspbian.conf b/build/raspberry-pi-os_armv7/rpi-raspbian.conf deleted file mode 100644 index 0adf69ec..00000000 --- a/build/raspberry-pi-os_armv7/rpi-raspbian.conf +++ /dev/null @@ -1,19 +0,0 @@ -[General] -unpack=true -bootstrap=Ports Ports2 Rasp -aptsources=Ports Ports2 Rasp - -[Ports] -packages=libc6-dev libstdc++-10-dev libasound2-dev libpulse-dev libudev-dev libexpat1-dev libnss3-dev libxtst-dev libsdl2-dev -source=http://ftp.jaist.ac.jp/raspbian -suite=bullseye - -[Ports2] -packages=libc6-dev libstdc++-10-dev libasound2-dev libpulse-dev libudev-dev libexpat1-dev libnss3-dev libxtst-dev libsdl2-dev -source=http://ftp.tsukuba.wide.ad.jp/Linux/raspbian/raspbian -suite=bullseye - -[Rasp] -packages=libraspberrypi-bin libraspberrypi-dev -source=http://archive.raspberrypi.org/debian -suite=bullseye diff --git a/build/raspberry-pi-os_armv8/Dockerfile b/build/raspberry-pi-os_armv8/Dockerfile deleted file mode 100644 index f29debf8..00000000 --- a/build/raspberry-pi-os_armv8/Dockerfile +++ /dev/null @@ -1,151 +0,0 @@ -# syntax = docker/dockerfile:1.1.1-experimental -FROM ubuntu:18.04 - -ARG PACKAGE_NAME - -LABEL jp.shiguredo.momo=$PACKAGE_NAME - -RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache - -# パッケージのインストール - -COPY script/apt_install_arm.sh /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/apt_install_arm.sh - -# RootFS の構築 - -COPY script/init_rootfs_arm64.sh /root/ -COPY rpi-raspbian.conf /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/init_rootfs_arm64.sh /root/rootfs /root/rpi-raspbian.conf - -# WebRTC の取得 - -ARG WEBRTC_BUILD_VERSION - -COPY script/get_webrtc.sh /root/ -RUN /root/get_webrtc.sh "$WEBRTC_BUILD_VERSION" raspberry-pi-os_armv8 /root /root - -# コンパイラの取得 - -COPY script/get_llvm.sh /root/ -RUN /root/get_llvm.sh /root/webrtc /root - -# Boost のビルド - -ARG BOOST_VERSION - -COPY _cache/boost/ /root/_cache/boost/ -COPY script/setup_boost.sh /root/ -RUN \ - set -ex \ - && /root/setup_boost.sh "$BOOST_VERSION" /root/boost-source /root/_cache/boost \ - && cd /root/boost-source/source \ - && echo 'using clang : : /root/llvm/clang/bin/clang++ : ;' > project-config.jam \ - && ./b2 \ - cxxstd=17 \ - cxxflags=' \ - -D_LIBCPP_ABI_NAMESPACE=Cr \ - -D_LIBCPP_ABI_VERSION=2 \ - -D_LIBCPP_DISABLE_AVAILABILITY \ - -nostdinc++ \ - -isystem/root/llvm/libcxx/include \ - --target=aarch64-linux-gnu \ - --sysroot=/root/rootfs \ - -I/root/rootfs/usr/include/aarch64-linux-gnu \ - ' \ - linkflags=' \ - -L/root/rootfs/usr/lib/aarch64-linux-gnu \ - -B/root/rootfs/usr/lib/aarch64-linux-gnu \ - ' \ - toolset=clang \ - visibility=global \ - target-os=linux \ - architecture=arm \ - address-model=64 \ - link=static \ - variant=release \ - install \ - -d+0 \ - -j`nproc` \ - --ignore-site-config \ - --prefix=/root/boost \ - --with-filesystem \ - --with-json - -# CLI11 の取得 - -ARG CLI11_VERSION -RUN git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git /root/CLI11 - -# CMake のインストール -ARG CMAKE_VERSION -COPY script/get_cmake.sh /root/ -RUN /root/get_cmake.sh "$CMAKE_VERSION" linux /root -ENV PATH "/root/cmake/bin:$PATH" - -# SDL2 のビルド - -ARG SDL2_VERSION - -COPY script/setup_sdl2.sh /root/ -RUN \ - set -ex \ - && /root/setup_sdl2.sh "$SDL2_VERSION" /root/sdl2-source \ - && mkdir -p /root/sdl2-source/build \ - && cd /root/sdl2-source/build \ - && cmake ../source \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/root/SDL2 \ - -DCMAKE_SYSTEM_NAME=Linux \ - -DCMAKE_SYSTEM_PROCESSOR=aarch64 \ - -DCMAKE_C_COMPILER=/root/llvm/clang/bin/clang \ - -DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu \ - -DCMAKE_CXX_COMPILER=/root/llvm/clang/bin/clang++ \ - -DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu \ - -DCMAKE_FIND_ROOT_PATH=/root/rootfs \ - -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ - -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ - -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH \ - -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \ - -DCMAKE_SYSROOT=/root/rootfs \ - -DSDL_STATIC=ON \ - -DSDL_SHARED=OFF \ - -DSDL_ATOMIC=OFF \ - -DSDL_AUDIO=OFF \ - -DSDL_VIDEO=ON \ - -DSDL_RENDER=ON \ - -DSDL_EVENTS=ON \ - -DSDL_JOYSTICK=ON \ - -DSDL_HAPTIC=ON \ - -DSDL_POWER=ON \ - -DSDL_THREADS=ON \ - -DSDL_TIMERS=OFF \ - -DSDL_FILE=OFF \ - -DSDL_LOADSO=ON \ - -DSDL_CPUINFO=OFF \ - -DSDL_FILESYSTEM=OFF \ - -DSDL_DLOPEN=ON \ - -DSDL_SENSOR=ON \ - -DSDL_COCOA=OFF \ - -DSDL_KMSDRM=OFF \ - -DSDL_METAL=OFF \ - -DSDL_OPENGL=ON \ - -DSDL_OPENGLES=ON \ - -DSDL_RPI=OFF \ - -DSDL_VIVANTE=OFF \ - -DSDL_VULKAN=OFF \ - -DSDL_WAYLAND=OFF \ - -DSDL_X11=ON \ - -DSDL_X11_SHARED=OFF \ - -DSDL_X11_XCURSOR=OFF \ - -DSDL_X11_XFIXES=OFF \ - -DSDL_X11_XINERAMA=OFF \ - -DSDL_X11_XINPUT=OFF \ - -DSDL_X11_XRANDR=OFF \ - -DSDL_X11_XSCRNSAVER=OFF \ - -DSDL_X11_XSHAPE=OFF \ - -DSDL_X11_XVM=OFF \ - && make -j`nproc` \ - && make install diff --git a/build/ubuntu-20.04_armv8_jetson_xavier/Dockerfile b/build/ubuntu-20.04_armv8_jetson_xavier/Dockerfile deleted file mode 100644 index f1c218bd..00000000 --- a/build/ubuntu-20.04_armv8_jetson_xavier/Dockerfile +++ /dev/null @@ -1,153 +0,0 @@ -# syntax = docker/dockerfile:1.1.1-experimental -FROM ubuntu:20.04 - -ARG PACKAGE_NAME - -LABEL jp.shiguredo.momo=$PACKAGE_NAME - -RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache - -# パッケージのインストール - -COPY script/apt_install_arm.sh /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/apt_install_arm.sh - -# RootFS の構築 - -COPY script/init_rootfs_arm64.sh /root/ -COPY arm64.conf /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/init_rootfs_arm64.sh /root/rootfs /root/arm64.conf - -COPY jetson.sh /root/ -RUN /root/jetson.sh - -# WebRTC の取得 - -ARG WEBRTC_BUILD_VERSION - -COPY script/get_webrtc.sh /root/ -RUN /root/get_webrtc.sh "$WEBRTC_BUILD_VERSION" ubuntu-20.04_armv8 /root /root - -# コンパイラの取得 - -COPY script/get_llvm.sh /root/ -RUN /root/get_llvm.sh /root/webrtc /root - -# Boost のビルド - -ARG BOOST_VERSION - -COPY _cache/boost/ /root/_cache/boost/ -COPY script/setup_boost.sh /root/ -RUN \ - set -ex \ - && /root/setup_boost.sh "$BOOST_VERSION" /root/boost-source /root/_cache/boost \ - && cd /root/boost-source/source \ - && echo 'using clang : : /root/llvm/clang/bin/clang++ : ;' > project-config.jam \ - && ./b2 \ - cxxstd=17 \ - cxxflags=' \ - -D_LIBCPP_ABI_NAMESPACE=Cr \ - -D_LIBCPP_ABI_VERSION=2 \ - -D_LIBCPP_DISABLE_AVAILABILITY \ - -nostdinc++ \ - -isystem/root/llvm/libcxx/include \ - --target=aarch64-linux-gnu \ - --sysroot=/root/rootfs \ - -I/root/rootfs/usr/include/aarch64-linux-gnu \ - ' \ - linkflags=' \ - -L/root/rootfs/usr/lib/aarch64-linux-gnu \ - -B/root/rootfs/usr/lib/aarch64-linux-gnu \ - ' \ - toolset=clang \ - visibility=global \ - target-os=linux \ - architecture=arm \ - address-model=64 \ - link=static \ - variant=release \ - install \ - -d+0 \ - -j`nproc` \ - --ignore-site-config \ - --prefix=/root/boost \ - --with-filesystem \ - --with-json - -# CLI11 の取得 - -ARG CLI11_VERSION -RUN git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git /root/CLI11 - -# CMake のインストール -ARG CMAKE_VERSION -COPY script/get_cmake.sh /root/ -RUN /root/get_cmake.sh "$CMAKE_VERSION" linux /root -ENV PATH "/root/cmake/bin:$PATH" - -# SDL2 のビルド - -ARG SDL2_VERSION - -COPY script/setup_sdl2.sh /root/ -RUN \ - set -ex \ - && /root/setup_sdl2.sh "$SDL2_VERSION" /root/sdl2-source \ - && mkdir -p /root/sdl2-source/build \ - && cd /root/sdl2-source/build \ - && cmake ../source \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/root/SDL2 \ - -DCMAKE_SYSTEM_NAME=Linux \ - -DCMAKE_SYSTEM_PROCESSOR=aarch64 \ - -DCMAKE_C_COMPILER=/root/llvm/clang/bin/clang \ - -DCMAKE_C_COMPILER_TARGET=aarch64-linux-gnu \ - -DCMAKE_CXX_COMPILER=/root/llvm/clang/bin/clang++ \ - -DCMAKE_CXX_COMPILER_TARGET=aarch64-linux-gnu \ - -DCMAKE_FIND_ROOT_PATH=/root/rootfs \ - -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ - -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ - -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH \ - -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \ - -DCMAKE_SYSROOT=/root/rootfs \ - -DBUILD_SHARED_LIBS=OFF \ - -DSDL_STATIC_PIC=ON \ - -DSDL_ATOMIC=OFF \ - -DSDL_AUDIO=OFF \ - -DSDL_VIDEO=ON \ - -DSDL_RENDER=ON \ - -DSDL_EVENTS=ON \ - -DSDL_JOYSTICK=ON \ - -DSDL_HAPTIC=ON \ - -DSDL_POWER=ON \ - -DSDL_THREADS=ON \ - -DSDL_TIMERS=OFF \ - -DSDL_FILE=OFF \ - -DSDL_LOADSO=ON \ - -DSDL_CPUINFO=OFF \ - -DSDL_FILESYSTEM=OFF \ - -DSDL_SENSOR=ON \ - -DSDL_OPENGL=ON \ - -DSDL_OPENGLES=ON \ - -DSDL_RPI=OFF \ - -DSDL_WAYLAND=OFF \ - -DSDL_X11=ON \ - -DSDL_X11_SHARED=OFF \ - -DSDL_X11_XCURSOR=OFF \ - -DSDL_X11_XDBE=OFF \ - -DSDL_X11_XINPUT=OFF \ - -DSDL_X11_XFIXES=OFF \ - -DSDL_X11_XRANDR=OFF \ - -DSDL_X11_XSCRNSAVER=OFF \ - -DSDL_X11_XSHAPE=OFF \ - -DSDL_VULKAN=OFF \ - -DSDL_VIVANTE=OFF \ - -DSDL_COCOA=OFF \ - -DSDL_METAL=OFF \ - -DSDL_KMSDRM=OFF \ - && make -j`nproc` \ - && make install - diff --git a/build/ubuntu-20.04_armv8_jetson_xavier/arm64.conf b/build/ubuntu-20.04_armv8_jetson_xavier/arm64.conf deleted file mode 100644 index 4f2dd3ad..00000000 --- a/build/ubuntu-20.04_armv8_jetson_xavier/arm64.conf +++ /dev/null @@ -1,23 +0,0 @@ -[General] -noauth=true -unpack=true -bootstrap=Ports Jetson T194 -aptsources=Ports Jetson T194 - -[Ports] -packages=libc6-dev libstdc++-10-dev libxext-dev libxtst-dev -source=http://ports.ubuntu.com -suite=focal -components=main universe - -[Jetson] -packages= -source=https://repo.download.nvidia.com/jetson/common -suite=r35.3 -components=main - -[T194] -packages=nvidia-l4t-camera nvidia-l4t-jetson-multimedia-api -source=https://repo.download.nvidia.com/jetson/t194 -suite=r35.3 -components=main \ No newline at end of file diff --git a/build/ubuntu-20.04_armv8_jetson_xavier/jetson.sh b/build/ubuntu-20.04_armv8_jetson_xavier/jetson.sh deleted file mode 100755 index 336da5ce..00000000 --- a/build/ubuntu-20.04_armv8_jetson_xavier/jetson.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -set -ex - -SYSDIR=/root/rootfs - -pushd $SYSDIR/usr/lib/aarch64-linux-gnu/tegra/ - ln -sf libnvbuf_utils.so.1.0.0 libnvbuf_utils.so - ln -s libnvbuf_fdmap.so.1.0.0 libnvbuf_fdmap.so -popd diff --git a/build/ubuntu-20.04_x86_64/Dockerfile b/build/ubuntu-20.04_x86_64/Dockerfile deleted file mode 100644 index 0c47a728..00000000 --- a/build/ubuntu-20.04_x86_64/Dockerfile +++ /dev/null @@ -1,181 +0,0 @@ -# syntax = docker/dockerfile:1.1.1-experimental -FROM ubuntu:20.04 - -ARG PACKAGE_NAME - -LABEL jp.shiguredo.momo=$PACKAGE_NAME - -RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache - -# パッケージのインストール - -COPY script/apt_install_x86_64.sh /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/apt_install_x86_64.sh \ - && apt-get -y install libdrm-dev - -# WebRTC の取得 - -ARG WEBRTC_BUILD_VERSION - -COPY script/get_webrtc.sh /root/ -RUN /root/get_webrtc.sh "$WEBRTC_BUILD_VERSION" ubuntu-20.04_x86_64 /root /root -# COPY webrtc/ /root/webrtc/ - -# コンパイラの取得 - -COPY script/get_llvm.sh /root/ -RUN /root/get_llvm.sh /root/webrtc /root - -# Boost のビルド - -ARG BOOST_VERSION - -COPY _cache/boost/ /root/_cache/boost/ -COPY script/setup_boost.sh /root/ -RUN \ - set -ex \ - && /root/setup_boost.sh "$BOOST_VERSION" /root/boost-source /root/_cache/boost \ - && cd /root/boost-source/source \ - && echo 'using clang : : /root/llvm/clang/bin/clang++ : ;' > project-config.jam \ - && ./b2 \ - cxxstd=17 \ - cxxflags=' \ - -D_LIBCPP_ABI_NAMESPACE=Cr \ - -D_LIBCPP_ABI_VERSION=2 \ - -D_LIBCPP_DISABLE_AVAILABILITY \ - -nostdinc++ \ - -isystem/root/llvm/libcxx/include \ - ' \ - linkflags=' \ - ' \ - toolset=clang \ - visibility=global \ - target-os=linux \ - address-model=64 \ - link=static \ - variant=release \ - install \ - -d+0 \ - -j`nproc` \ - --ignore-site-config \ - --prefix=/root/boost \ - --with-filesystem \ - --with-json - -# CLI11 の取得 - -ARG CLI11_VERSION -RUN git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git /root/CLI11 - -# CMake のインストール -ARG CMAKE_VERSION -COPY script/get_cmake.sh /root/ -RUN /root/get_cmake.sh "$CMAKE_VERSION" linux /root -ENV PATH "/root/cmake/bin:$PATH" - -# SDL2 のビルド - -ARG SDL2_VERSION - -COPY script/setup_sdl2.sh /root/ -RUN \ - set -ex \ - && /root/setup_sdl2.sh "$SDL2_VERSION" /root/sdl2-source \ - && mkdir -p /root/sdl2-source/build \ - && cd /root/sdl2-source/build \ - && cmake ../source \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/root/SDL2 \ - -DCMAKE_C_COMPILER=/root/llvm/clang/bin/clang \ - -DCMAKE_CXX_COMPILER=/root/llvm/clang/bin/clang++ \ - -DBUILD_SHARED_LIBS=OFF \ - -DSDL_ATOMIC=OFF \ - -DSDL_AUDIO=OFF \ - -DSDL_VIDEO=ON \ - -DSDL_RENDER=ON \ - -DSDL_EVENTS=ON \ - -DSDL_JOYSTICK=ON \ - -DSDL_HAPTIC=ON \ - -DSDL_POWER=ON \ - -DSDL_THREADS=ON \ - -DSDL_TIMERS=OFF \ - -DSDL_FILE=OFF \ - -DSDL_LOADSO=ON \ - -DSDL_CPUINFO=OFF \ - -DSDL_FILESYSTEM=OFF \ - -DSDL_DLOPEN=ON \ - -DSDL_SENSOR=ON \ - -DVIDEO_OPENGL=ON \ - -DVIDEO_OPENGLES=ON \ - -DVIDEO_RPI=OFF \ - -DVIDEO_WAYLAND=OFF \ - -DVIDEO_X11=ON \ - -DX11_SHARED=OFF \ - -DVIDEO_X11_XCURSOR=OFF \ - -DVIDEO_X11_XINERAMA=OFF \ - -DVIDEO_X11_XINPUT=OFF \ - -DVIDEO_X11_XRANDR=OFF \ - -DVIDEO_X11_XSCRNSAVER=OFF \ - -DVIDEO_X11_XSHAPE=OFF \ - -DVIDEO_X11_XVM=OFF \ - -DVIDEO_VULKAN=OFF \ - -DVIDEO_VIVANTE=OFF \ - -DVIDEO_COCOA=OFF \ - -DVIDEO_METAL=OFF \ - -DVIDEO_KMSDRM=OFF \ - && make -j`nproc` \ - && make install - -# CUDA 周りのインストール -ARG CUDA_VERSION -RUN set -ex \ - && apt-get update \ - && apt-get install -y software-properties-common \ - && wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin \ - && mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600 \ - && apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/3bf863cc.pub \ - && add-apt-repository "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/ /" \ - && apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get -y install cuda=$CUDA_VERSION clang-10 - -# libva -ARG LIBVA_VERSION -RUN set -ex \ - && git clone --depth 1 --branch $LIBVA_VERSION https://github.com/intel/libva.git /root/libva-source \ - && mkdir -p /root/libva-build \ - && cd /root/libva-build \ - && CC=/root/llvm/clang/bin/clang \ - CXX=/root/llvm/clang/bin/clang++ \ - CFLAGS="-fPIC" \ - /root/libva-source/autogen.sh \ - --enable-static \ - --disable-shared \ - --with-drivers-path=/usr/lib/x86_64-linux-gnu/dri \ - --prefix /root/libva \ - && make -j`nproc` \ - && make install \ - && rm -rf /root/libva-build \ - && rm -rf /root/libva-source - -# Intel Media SDK -ARG MSDK_VERSION -RUN set -ex \ - && git clone --depth 1 --branch intel-mediasdk-$MSDK_VERSION https://github.com/Intel-Media-SDK/MediaSDK.git /root/msdk-source \ - && cd /root/msdk-source \ - && find . -name "CMakeLists.txt" | while read line; do sed -i 's/SHARED/STATIC/g' $line; done \ - && mkdir -p /root/msdk-build \ - && cd /root/msdk-build \ - && cmake \ - -DCMAKE_INSTALL_PREFIX=/root/msdk \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH=/root/libva \ - -DCMAKE_C_COMPILER=/root/llvm/clang/bin/clang \ - -DCMAKE_CXX_COMPILER=/root/llvm/clang/bin/clang++ \ - -DBUILD_SAMPLES=OFF \ - -DBUILD_TUTORIALS=OFF \ - /root/msdk-source \ - && cmake --build . -j`nproc` \ - && cmake --install . \ - && rm -rf /root/msdk-build \ - && rm -rf /root/msdk-source diff --git a/build/ubuntu-22.04_x86_64/Dockerfile b/build/ubuntu-22.04_x86_64/Dockerfile deleted file mode 100644 index ff541c47..00000000 --- a/build/ubuntu-22.04_x86_64/Dockerfile +++ /dev/null @@ -1,183 +0,0 @@ -# syntax = docker/dockerfile:1.1.1-experimental -FROM ubuntu:22.04 - -ARG PACKAGE_NAME - -LABEL jp.shiguredo.momo=$PACKAGE_NAME - -RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache - -# パッケージのインストール - -COPY script/apt_install_x86_64.sh /root/ -RUN --mount=type=cache,id=$PACKAGE_NAME,target=/var/cache/apt --mount=type=cache,id=$PACKAGE_NAME,target=/var/lib/apt \ - /root/apt_install_x86_64.sh \ - && apt-get -y install libdrm-dev libstdc++-12-dev - -# WebRTC の取得 - -ARG WEBRTC_BUILD_VERSION - -COPY script/get_webrtc.sh /root/ -RUN /root/get_webrtc.sh "$WEBRTC_BUILD_VERSION" ubuntu-22.04_x86_64 /root /root -# COPY webrtc/ /root/webrtc/ - -# コンパイラの取得 - -COPY script/get_llvm.sh /root/ -RUN /root/get_llvm.sh /root/webrtc /root - -# Boost のビルド - -ARG BOOST_VERSION - -COPY _cache/boost/ /root/_cache/boost/ -COPY script/setup_boost.sh /root/ -RUN \ - set -ex \ - && /root/setup_boost.sh "$BOOST_VERSION" /root/boost-source /root/_cache/boost \ - && cd /root/boost-source/source \ - && echo 'using clang : : /root/llvm/clang/bin/clang++ : ;' > project-config.jam \ - && ./b2 \ - cxxstd=17 \ - cxxflags=' \ - -D_LIBCPP_ABI_NAMESPACE=Cr \ - -D_LIBCPP_ABI_VERSION=2 \ - -D_LIBCPP_DISABLE_AVAILABILITY \ - -nostdinc++ \ - -isystem/root/llvm/libcxx/include \ - ' \ - linkflags=' \ - ' \ - toolset=clang \ - visibility=global \ - target-os=linux \ - address-model=64 \ - link=static \ - variant=release \ - install \ - -d+0 \ - -j`nproc` \ - --ignore-site-config \ - --prefix=/root/boost \ - --with-filesystem \ - --with-json - -# CLI11 の取得 - -ARG CLI11_VERSION -RUN git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git /root/CLI11 - -# CMake のインストール -ARG CMAKE_VERSION -COPY script/get_cmake.sh /root/ -RUN /root/get_cmake.sh "$CMAKE_VERSION" linux /root -ENV PATH "/root/cmake/bin:$PATH" - -# SDL2 のビルド - -ARG SDL2_VERSION - -COPY script/setup_sdl2.sh /root/ -RUN \ - set -ex \ - && /root/setup_sdl2.sh "$SDL2_VERSION" /root/sdl2-source \ - && mkdir -p /root/sdl2-source/build \ - && cd /root/sdl2-source/build \ - && cmake ../source \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=/root/SDL2 \ - -DCMAKE_C_COMPILER=/root/llvm/clang/bin/clang \ - -DCMAKE_CXX_COMPILER=/root/llvm/clang/bin/clang++ \ - -DBUILD_SHARED_LIBS=OFF \ - -DSDL_ATOMIC=OFF \ - -DSDL_AUDIO=OFF \ - -DSDL_VIDEO=ON \ - -DSDL_RENDER=ON \ - -DSDL_EVENTS=ON \ - -DSDL_JOYSTICK=ON \ - -DSDL_HAPTIC=ON \ - -DSDL_POWER=ON \ - -DSDL_THREADS=ON \ - -DSDL_TIMERS=OFF \ - -DSDL_FILE=OFF \ - -DSDL_LOADSO=ON \ - -DSDL_CPUINFO=OFF \ - -DSDL_FILESYSTEM=OFF \ - -DSDL_DLOPEN=ON \ - -DSDL_SENSOR=ON \ - -DVIDEO_OPENGL=ON \ - -DVIDEO_OPENGLES=ON \ - -DVIDEO_RPI=OFF \ - -DVIDEO_WAYLAND=OFF \ - -DVIDEO_X11=ON \ - -DX11_SHARED=OFF \ - -DVIDEO_X11_XCURSOR=OFF \ - -DVIDEO_X11_XINERAMA=OFF \ - -DVIDEO_X11_XINPUT=OFF \ - -DVIDEO_X11_XRANDR=OFF \ - -DVIDEO_X11_XSCRNSAVER=OFF \ - -DVIDEO_X11_XSHAPE=OFF \ - -DVIDEO_X11_XVM=OFF \ - -DVIDEO_VULKAN=OFF \ - -DVIDEO_VIVANTE=OFF \ - -DVIDEO_COCOA=OFF \ - -DVIDEO_METAL=OFF \ - -DVIDEO_KMSDRM=OFF \ - && make -j`nproc` \ - && make install - -# CUDA 周りのインストール -ARG CUDA_VERSION -RUN set -ex \ - && apt-get update \ - && apt-get install -y software-properties-common \ - && wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin \ - && mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600 \ - && apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/3bf863cc.pub \ - && add-apt-repository "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/ /" \ - && apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get -y install cuda=$CUDA_VERSION clang-12 - -# libva -ARG LIBVA_VERSION -RUN set -ex \ - && git clone --depth 1 --branch $LIBVA_VERSION https://github.com/intel/libva.git /root/libva-source \ - && mkdir -p /root/libva-build \ - && cd /root/libva-build \ - && CC=/root/llvm/clang/bin/clang \ - CXX=/root/llvm/clang/bin/clang++ \ - CFLAGS="-fPIC" \ - /root/libva-source/autogen.sh \ - --enable-static \ - --disable-shared \ - --with-drivers-path=/usr/lib/x86_64-linux-gnu/dri \ - --prefix /root/libva \ - && make -j`nproc` \ - && make install \ - && rm -rf /root/libva-build \ - && rm -rf /root/libva-source - -# Intel Media SDK -COPY patch/msdk_limits.patch /root/msdk_limits.patch -ARG MSDK_VERSION -RUN set -ex \ - && git clone --depth 1 --branch intel-mediasdk-$MSDK_VERSION https://github.com/Intel-Media-SDK/MediaSDK.git /root/msdk-source \ - && cd /root/msdk-source \ - && find . -name "CMakeLists.txt" | while read line; do sed -i 's/SHARED/STATIC/g' $line; done \ - && patch -p1 < /root/msdk_limits.patch \ - && mkdir -p /root/msdk-build \ - && cd /root/msdk-build \ - && cmake \ - -DCMAKE_INSTALL_PREFIX=/root/msdk \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH=/root/libva \ - -DCMAKE_C_COMPILER=/root/llvm/clang/bin/clang \ - -DCMAKE_CXX_COMPILER=/root/llvm/clang/bin/clang++ \ - -DBUILD_SAMPLES=OFF \ - -DBUILD_TUTORIALS=OFF \ - /root/msdk-source \ - && cmake --build . -j`nproc` \ - && cmake --install . \ - && rm -rf /root/msdk-build \ - && rm -rf /root/msdk-source diff --git a/build/windows_x86_64/install_deps.ps1 b/build/windows_x86_64/install_deps.ps1 deleted file mode 100644 index 422ec76a..00000000 --- a/build/windows_x86_64/install_deps.ps1 +++ /dev/null @@ -1,198 +0,0 @@ -$ErrorActionPreference = 'Stop' - -$SOURCE_DIR = Join-Path (Resolve-Path ".").Path "_source" -$BUILD_DIR = Join-Path (Resolve-Path ".").Path "_build" -$INSTALL_DIR = Join-Path (Resolve-Path ".").Path "_install" -$INSTALL_DIR_SLASH = $INSTALL_DIR.Replace("\", "/") -$CACHE_DIR = [IO.Path]::Combine((Resolve-Path ".").Path, "..", "..", "_cache") - -$VERSION_FILE = Join-Path (Resolve-Path ".").Path "..\..\VERSION" -Get-Content $VERSION_FILE | Foreach-Object{ - if (!$_) { - continue - } - $var = $_.Split('=') - New-Variable -Name $var[0] -Value $var[1] -} - -mkdir $SOURCE_DIR -ErrorAction Ignore -mkdir $BUILD_DIR -ErrorAction Ignore -mkdir $INSTALL_DIR -ErrorAction Ignore -mkdir $CACHE_DIR -ErrorAction Ignore - -# WebRTC の取得 - -if (!(Test-Path "$INSTALL_DIR\webrtc\lib\webrtc.lib")) { - # shiguredo-webrtc-windows のバイナリをダウンロードする - $_URL = "https://github.com/shiguredo-webrtc-build/webrtc-build/releases/download/m$WEBRTC_BUILD_VERSION/webrtc.windows_x86_64.zip" - $_FILE = "$SOURCE_DIR\webrtc-m$WEBRTC_BUILD_VERSION.zip" - Push-Location $SOURCE_DIR - if (!(Test-Path $_FILE)) { - Invoke-WebRequest -Uri $_URL -OutFile $_FILE - } - Pop-Location - # 展開 - Remove-Item $SOURCE_DIR\webrtc -Recurse -Force -ErrorAction Ignore - # Expand-Archive -Path $_FILE -DestinationPath "$SOURCE_DIR\webrtc" - Push-Location $SOURCE_DIR - 7z x $_FILE - Pop-Location - - # インストール - Remove-Item $INSTALL_DIR\webrtc -Recurse -Force -ErrorAction Ignore - Move-Item $SOURCE_DIR\webrtc $INSTALL_DIR\webrtc -} - -# Boost のビルド - -if (!(Test-Path "$INSTALL_DIR\boost\include\boost\version.hpp")) { - $_BOOST_UNDERSCORE_VERSION = $BOOST_VERSION.Replace(".", "_") - $_URL = "https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION}/source/boost_${_BOOST_UNDERSCORE_VERSION}.zip" - $_FILE = "$CACHE_DIR\boost\boost_${_BOOST_UNDERSCORE_VERSION}.zip" - mkdir "$CACHE_DIR\boost" -ErrorAction Ignore - # ダウンロードと展開 - Push-Location $SOURCE_DIR - if (!(Test-Path $_FILE)) { - # curl に擬態しないとアーカイブではなく HTML コンテンツが降ってきてしまう - Invoke-WebRequest -Headers @{"User-Agent"="curl/7.55.1"} -Uri $_URL -OutFile $_FILE - } - Remove-Item boost -Force -Recurse -ErrorAction Ignore - Remove-Item boost_${_BOOST_UNDERSCORE_VERSION} -Force -Recurse -ErrorAction Ignore - # Expand-Archive -Path $_FILE -DestinationPath . - 7z x $_FILE - Move-Item boost_${_BOOST_UNDERSCORE_VERSION} boost - Pop-Location - # ビルドとインストール - Push-Location $SOURCE_DIR\boost - Remove-Item $BUILD_DIR\boost -Force -Recurse -ErrorAction Ignore - .\bootstrap.bat - .\b2.exe install ` - -d+0 ` - -j8 ` - --prefix=$INSTALL_DIR\boost ` - --build-dir=$BUILD_DIR\boost ` - --with-filesystem ` - --with-json ` - --layout=system ` - address-model=64 ` - link=static ` - threading=multi ` - variant=release ` - runtime-link=static - Pop-Location -} - -# SDL2 のビルド - -if (!(Test-Path "$INSTALL_DIR\SDL2\include\SDL2\SDL.h")) { - $_URL = "http://www.libsdl.org/release/SDL2-$SDL2_VERSION.zip" - $_FILE = "SDL2.zip" - # ダウンロードと展開 - Push-Location $SOURCE_DIR - if (!(Test-Path $_FILE)) { - Invoke-WebRequest -Uri $_URL -OutFile $_FILE - } - Remove-Item SDL2 -Force -Recurse -ErrorAction Ignore - Remove-Item SDL2-$SDL2_VERSION -Force -Recurse -ErrorAction Ignore - # Expand-Archive -Path $_FILE -DestinationPath . - 7z x $_FILE - Move-Item SDL2-$SDL2_VERSION SDL2 - Pop-Location - - mkdir $BUILD_DIR\SDL2 -ErrorAction Ignore - Push-Location $BUILD_DIR\SDL2 - cmake ` - -G "Visual Studio 16 2019" ` - -DFORCE_STATIC_VCRT=ON ` - -DBUILD_SHARED_LIBS=OFF ` - -DHAVE_LIBC=ON ` - "-DCMAKE_INSTALL_PREFIX=${INSTALL_DIR_SLASH}/SDL2" ` - $SOURCE_DIR\SDL2 - - cmake --build . --config Release - cmake --build . --config Release --target INSTALL - Pop-Location -} - - -# CLI11 の取得 - -if (!(Test-Path "$INSTALL_DIR\CLI11\include\CLI\CLI.hpp")) { - $_URL = "https://github.com/CLIUtils/CLI11/archive/v${CLI11_VERSION}.zip" - $_FILE = "$SOURCE_DIR\CLI11.zip" - # ダウンロード - Push-Location $SOURCE_DIR - if (!(Test-Path $_FILE)) { - Invoke-WebRequest -Uri $_URL -OutFile $_FILE - } - Pop-Location - # 展開(=インストール) - Remove-Item $INSTALL_DIR\CLI11 -Recurse -Force -ErrorAction Ignore - Remove-Item $INSTALL_DIR\CLI11-${CLI11_VERSION} -Recurse -Force -ErrorAction Ignore - # Expand-Archive -Path $_FILE -DestinationPath "$INSTALL_DIR" - Push-Location $INSTALL_DIR - 7z x $_FILE - Move-Item CLI11-${CLI11_VERSION} CLI11 - Pop-Location -} - -if (!(Test-Path "$INSTALL_DIR\cuda\nvcc")) { - if ("$WINCUDA_VERSION" -eq "10.2") { - $_URL = "http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_441.22_win10.exe" - $_FILE = "$SOURCE_DIR\cuda_10.2.89_441.22_win10.exe" - } elseif ("$WINCUDA_VERSION" -eq "11.0.2") { - $_URL = "https://developer.download.nvidia.com/compute/cuda/11.0.2/local_installers/cuda_11.0.2_451.48_win10.exe" - $_FILE = "$SOURCE_DIR\cuda_11.0.2_451.48_win10.exe" - } else { - # バージョンが増えたらこの分岐を増やしていく - throw "CUDA-$WINCUDA_VERSION URL not specified" - } - - Push-Location $SOURCE_DIR - if (!(Test-Path $_FILE)) { - Invoke-WebRequest -Uri $_URL -OutFile $_FILE - } - Pop-Location - if (Test-Path "$BUILD_DIR\cuda") { - Remove-Item "$BUILD_DIR\cuda" -Recurse -Force - } - mkdir $BUILD_DIR\cuda -Force - Push-Location $BUILD_DIR\cuda - # サイレントインストールとかせずに、単に展開だけして nvcc を利用する - 7z x $_FILE - if (Test-Path "$INSTALL_DIR\cuda") { - Remove-Item $INSTALL_DIR\cuda -Recurse -Force - } - mkdir $INSTALL_DIR\cuda - Move-Item nvcc $INSTALL_DIR\cuda\nvcc - Pop-Location -} - -# Intel Media SDK -if (!(Test-Path "$INSTALL_DIR\msdk\lib\libmfx.lib")) { - if (Test-Path "$SOURCE_DIR\msdk") { - Remove-Item $SOURCE_DIR\msdk -Recurse -Force - } - if (Test-Path "$INSTALL_DIR\msdk") { - Remove-Item $INSTALL_DIR\msdk -Recurse -Force - } - mkdir $SOURCE_DIR\msdk - git clone --depth 1 --branch intel-mediasdk-$MSDK_VERSION https://github.com/Intel-Media-SDK/MediaSDK.git $SOURCE_DIR\msdk\MediaSDK - mkdir $INSTALL_DIR\msdk - mkdir $INSTALL_DIR\msdk\include - mkdir $INSTALL_DIR\msdk\lib - Copy-Item -Recurse $SOURCE_DIR\msdk\MediaSDK\api\include $INSTALL_DIR\msdk\include\mfx - $WSDK_VERSION = $(Get-Item "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Microsoft SDKs\Windows\v10.0").GetValue("ProductVersion") - if (Test-Path "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe") { - & "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe" ` - /t:build ` - "/p:Configuration=Release;Platform=x64;PlatformToolset=v142;SpectreMitigation=false;WindowsTargetPlatformVersion=$WSDK_VERSION.0" ` - $SOURCE_DIR\msdk\MediaSDK\api\mfx_dispatch\windows\libmfx_vs2015.vcxproj - } else { - MSBuild ` - /t:build ` - "/p:Configuration=Release;Platform=x64;PlatformToolset=v142;SpectreMitigation=false;WindowsTargetPlatformVersion=$WSDK_VERSION.0" ` - $SOURCE_DIR\msdk\MediaSDK\api\mfx_dispatch\windows\libmfx_vs2015.vcxproj - } - Copy-Item $SOURCE_DIR\msdk\build\win_x64\Release\lib\libmfx_vs2015.lib $INSTALL_DIR\msdk\lib\libmfx.lib -} \ No newline at end of file diff --git a/buildbase.py b/buildbase.py new file mode 100644 index 00000000..45c00569 --- /dev/null +++ b/buildbase.py @@ -0,0 +1,1866 @@ +# buildbase.py はビルドスクリプトのテンプレートとなるファイル +# +# 自身のリポジトリにコピーして利用する。 +# +# 元のファイルは以下のリポジトリにある: +# https://github.com/melpon/buildbase +# +# 更新する場合は以下のコマンドを利用する: +# curl -LO https://raw.githubusercontent.com/melpon/buildbase/master/buildbase.py +# +# ライセンス: Apache License 2.0 +# +# Copyright 2024 melpon (Wandbox) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import filecmp +import glob +import logging +import multiprocessing +import os +import platform +import shlex +import shutil +import stat +import subprocess +import tarfile +import urllib.parse +import zipfile +from typing import Dict, List, NamedTuple, Optional + +if platform.system() == "Windows": + import winreg + + +class ChangeDirectory(object): + def __init__(self, cwd): + self._cwd = cwd + + def __enter__(self): + self._old_cwd = os.getcwd() + logging.debug(f"pushd {self._old_cwd} --> {self._cwd}") + os.chdir(self._cwd) + + def __exit__(self, exctype, excvalue, trace): + logging.debug(f"popd {self._old_cwd} <-- {self._cwd}") + os.chdir(self._old_cwd) + return False + + +def cd(cwd): + return ChangeDirectory(cwd) + + +def cmd(args, **kwargs): + logging.debug(f"+{args} {kwargs}") + if "check" not in kwargs: + kwargs["check"] = True + if "resolve" in kwargs: + resolve = kwargs["resolve"] + del kwargs["resolve"] + else: + resolve = True + if resolve: + args = [shutil.which(args[0]), *args[1:]] + return subprocess.run(args, **kwargs) + + +# 標準出力をキャプチャするコマンド実行。シェルの `cmd ...` や $(cmd ...) と同じ +def cmdcap(args, **kwargs): + # 3.7 でしか使えない + # kwargs['capture_output'] = True + kwargs["stdout"] = subprocess.PIPE + kwargs["stderr"] = subprocess.PIPE + kwargs["encoding"] = "utf-8" + return cmd(args, **kwargs).stdout.strip() + + +# https://stackoverflow.com/a/2656405 +def onerror(func, path, exc_info): + """ + Error handler for ``shutil.rmtree``. + If the error is due to an access error (read only file) + it attempts to add write permission and then retries. + If the error is for another reason it re-raises the error. + + Usage : ``shutil.rmtree(path, onerror=onerror)`` + """ + import stat + + # Is the error an access error? + if not os.access(path, os.W_OK): + os.chmod(path, stat.S_IWUSR) + func(path) + else: + raise + + +def rm_rf(path: str): + if not os.path.exists(path): + logging.debug(f"rm -rf {path} => path not found") + return + if os.path.isfile(path) or os.path.islink(path): + os.remove(path) + logging.debug(f"rm -rf {path} => file removed") + if os.path.isdir(path): + shutil.rmtree(path, onerror=onerror) + logging.debug(f"rm -rf {path} => directory removed") + + +def mkdir_p(path: str): + if os.path.exists(path): + logging.debug(f"mkdir -p {path} => already exists") + return + os.makedirs(path, exist_ok=True) + logging.debug(f"mkdir -p {path} => directory created") + + +if platform.system() == "Windows": + PATH_SEPARATOR = ";" +else: + PATH_SEPARATOR = ":" + + +def add_path(path: str, is_after=False): + logging.debug(f"add_path: {path}") + if "PATH" not in os.environ: + os.environ["PATH"] = path + return + + if is_after: + os.environ["PATH"] = os.environ["PATH"] + PATH_SEPARATOR + path + else: + os.environ["PATH"] = path + PATH_SEPARATOR + os.environ["PATH"] + + +def download(url: str, output_dir: Optional[str] = None, filename: Optional[str] = None) -> str: + if filename is None: + output_path = urllib.parse.urlparse(url).path.split("/")[-1] + else: + output_path = filename + + if output_dir is not None: + output_path = os.path.join(output_dir, output_path) + + if os.path.exists(output_path): + return output_path + + try: + if shutil.which("curl") is not None: + cmd(["curl", "-fLo", output_path, url]) + else: + cmd(["wget", "-cO", output_path, url]) + except Exception: + # ゴミを残さないようにする + if os.path.exists(output_path): + os.remove(output_path) + raise + + return output_path + + +def read_version_file(path: str) -> Dict[str, str]: + versions = {} + + lines = open(path).readlines() + for line in lines: + line = line.strip() + + # コメント行 + if line[:1] == "#": + continue + + # 空行 + if len(line) == 0: + continue + + [a, b] = map(lambda x: x.strip(), line.split("=", 2)) + versions[a] = b.strip('"') + + return versions + + +# dir 以下にある全てのファイルパスを、dir2 からの相対パスで返す +def enum_all_files(dir, dir2): + for root, _, files in os.walk(dir): + for file in files: + yield os.path.relpath(os.path.join(root, file), dir2) + + +def versioned(func): + def wrapper(version, version_file, *args, **kwargs): + if "ignore_version" in kwargs: + if kwargs.get("ignore_version"): + rm_rf(version_file) + del kwargs["ignore_version"] + + if os.path.exists(version_file): + ver = open(version_file).read() + if ver.strip() == version.strip(): + return + + r = func(version=version, *args, **kwargs) + + with open(version_file, "w") as f: + f.write(version) + + return r + + return wrapper + + +# アーカイブが単一のディレクトリに全て格納されているかどうかを調べる。 +# +# 単一のディレクトリに格納されている場合はそのディレクトリ名を返す。 +# そうでない場合は None を返す。 +def _is_single_dir(infos, get_name, is_dir) -> Optional[str]: + # tarfile: ['path', 'path/to', 'path/to/file.txt'] + # zipfile: ['path/', 'path/to/', 'path/to/file.txt'] + # どちらも / 区切りだが、ディレクトリの場合、後ろに / が付くかどうかが違う + dirname = None + for info in infos: + name = get_name(info) + n = name.rstrip("/").find("/") + if n == -1: + # ルートディレクトリにファイルが存在している + if not is_dir(info): + return None + dir = name.rstrip("/") + else: + dir = name[0:n] + # ルートディレクトリに2個以上のディレクトリが存在している + if dirname is not None and dirname != dir: + return None + dirname = dir + + return dirname + + +def is_single_dir_tar(tar: tarfile.TarFile) -> Optional[str]: + return _is_single_dir(tar.getmembers(), lambda t: t.name, lambda t: t.isdir()) + + +def is_single_dir_zip(zip: zipfile.ZipFile) -> Optional[str]: + return _is_single_dir(zip.infolist(), lambda z: z.filename, lambda z: z.is_dir()) + + +# 解凍した上でファイル属性を付与する +def _extractzip(z: zipfile.ZipFile, path: str): + z.extractall(path) + if platform.system() == "Windows": + return + for info in z.infolist(): + if info.is_dir(): + continue + filepath = os.path.join(path, info.filename) + mod = info.external_attr >> 16 + if (mod & 0o120000) == 0o120000: + # シンボリックリンク + with open(filepath, "r") as f: + src = f.read() + os.remove(filepath) + with cd(os.path.dirname(filepath)): + if os.path.exists(src): + os.symlink(src, filepath) + if os.path.exists(filepath): + # 普通のファイル + os.chmod(filepath, mod & 0o777) + + +# zip または tar.gz ファイルを展開する。 +# +# 展開先のディレクトリは {output_dir}/{output_dirname} となり、 +# 展開先のディレクトリが既に存在していた場合は削除される。 +# +# もしアーカイブの内容が単一のディレクトリであった場合、 +# そのディレクトリは無いものとして展開される。 +# +# つまりアーカイブ libsora-1.23.tar.gz の内容が +# ['libsora-1.23', 'libsora-1.23/file1', 'libsora-1.23/file2'] +# であった場合、extract('libsora-1.23.tar.gz', 'out', 'libsora') のようにすると +# - out/libsora/file1 +# - out/libsora/file2 +# が出力される。 +# +# また、アーカイブ libsora-1.23.tar.gz の内容が +# ['libsora-1.23', 'libsora-1.23/file1', 'libsora-1.23/file2', 'LICENSE'] +# であった場合、extract('libsora-1.23.tar.gz', 'out', 'libsora') のようにすると +# - out/libsora/libsora-1.23/file1 +# - out/libsora/libsora-1.23/file2 +# - out/libsora/LICENSE +# が出力される。 +def extract(file: str, output_dir: str, output_dirname: str, filetype: Optional[str] = None): + path = os.path.join(output_dir, output_dirname) + logging.info(f"Extract {file} to {path}") + if filetype == "gzip" or file.endswith(".tar.gz"): + rm_rf(path) + with tarfile.open(file) as t: + dir = is_single_dir_tar(t) + if dir is None: + os.makedirs(path, exist_ok=True) + t.extractall(path) + else: + logging.info(f"Directory {dir} is stripped") + path2 = os.path.join(output_dir, dir) + rm_rf(path2) + t.extractall(output_dir) + if path != path2: + logging.debug(f"mv {path2} {path}") + os.replace(path2, path) + elif filetype == "zip" or file.endswith(".zip"): + rm_rf(path) + with zipfile.ZipFile(file) as z: + dir = is_single_dir_zip(z) + if dir is None: + os.makedirs(path, exist_ok=True) + # z.extractall(path) + _extractzip(z, path) + else: + logging.info(f"Directory {dir} is stripped") + path2 = os.path.join(output_dir, dir) + rm_rf(path2) + # z.extractall(output_dir) + _extractzip(z, output_dir) + if path != path2: + logging.debug(f"mv {path2} {path}") + os.replace(path2, path) + else: + raise Exception("file should end with .tar.gz or .zip") + + +def clone_and_checkout(url, version, dir, fetch, fetch_force): + if fetch_force: + rm_rf(dir) + + if not os.path.exists(os.path.join(dir, ".git")): + cmd(["git", "clone", url, dir]) + fetch = True + + if fetch: + with cd(dir): + cmd(["git", "fetch"]) + cmd(["git", "reset", "--hard"]) + cmd(["git", "clean", "-df"]) + cmd(["git", "checkout", "-f", version]) + + +def git_clone_shallow(url, hash, dir, submodule=False): + rm_rf(dir) + mkdir_p(dir) + with cd(dir): + cmd(["git", "init"]) + cmd(["git", "remote", "add", "origin", url]) + cmd(["git", "fetch", "--depth=1", "origin", hash]) + cmd(["git", "reset", "--hard", "FETCH_HEAD"]) + if submodule: + cmd( + [ + "git", + "submodule", + "update", + "--init", + "--recursive", + "--recommend-shallow", + "--depth", + "1", + ] + ) + + +def apply_patch(patch, dir, depth): + with cd(dir): + logging.info(f"patch -p{depth} < {patch}") + if platform.system() == "Windows": + cmd( + [ + "git", + "apply", + f"-p{depth}", + "--ignore-space-change", + "--ignore-whitespace", + "--whitespace=nowarn", + patch, + ] + ) + else: + with open(patch) as stdin: + cmd(["patch", f"-p{depth}"], stdin=stdin) + + +def apply_patch_text(patch_text, dir, depth): + with cd(dir): + logging.info(f"echo '{patch_text[:100]}...' | patch -p{depth} -") + directory = cmdcap(["git", "rev-parse", "--show-prefix"]) + if platform.system() == "Windows": + cmd( + [ + "git", + "apply", + f"-p{depth}", + "--ignore-space-change", + "--ignore-whitespace", + "--whitespace=nowarn", + f"--directory={directory}", + "-", + ], + input=BOOST_PATCH_SUPPORT_14_4, + text=True, + encoding="utf-8", + ) + else: + cmd(["patch", f"-p{depth}"], input=patch_text, text=True, encoding="utf-8") + + +def copyfile_if_different(src, dst): + if os.path.exists(dst) and filecmp.cmp(src, dst, shallow=False): + return + shutil.copyfile(src, dst) + + +# NOTE(enm10k): shutil.copytree に Python 3.8 で追加された dirs_exist_ok=True を指定して使いたかったが、 +# GitHub Actions の Windows のランナー (widnwos-2019) にインストールされている Python のバージョンが古くて利用できなかった +# actions/setup-python で Python 3.8 を設定してビルドしたところ、 Lyra のビルドがエラーになったためこの関数を自作した +# Windows のランナーを更新した場合は、この関数は不要になる可能性が高い +def copytree(src_dir, dst_dir): + for file_path in glob.glob(src_dir + "/**", recursive=True): + dest_path = os.path.join(dst_dir, os.path.relpath(file_path, src_dir)) + + if os.path.isdir(file_path): + os.makedirs(dest_path, exist_ok=True) + else: + shutil.copy2(file_path, dest_path) + + +def git_get_url_and_revision(dir): + with cd(dir): + rev = cmdcap(["git", "rev-parse", "HEAD"]) + url = cmdcap(["git", "remote", "get-url", "origin"]) + return url, rev + + +def replace_vcproj_static_runtime(project_file: str): + # なぜか MSVC_STATIC_RUNTIME が効かずに DLL ランタイムを使ってしまうので + # 生成されたプロジェクトに対して静的ランタイムを使うように変更する + s = open(project_file, "r", encoding="utf-8").read() + s = s.replace("MultiThreadedDLL", "MultiThreaded") + s = s.replace("MultiThreadedDebugDLL", "MultiThreadedDebug") + open(project_file, "w", encoding="utf-8").write(s) + + +@versioned +def install_webrtc(version, source_dir, install_dir, platform: str): + win = platform.startswith("windows_") + filename = f'webrtc.{platform}.{"zip" if win else "tar.gz"}' + rm_rf(os.path.join(source_dir, filename)) + archive = download( + f"https://github.com/shiguredo-webrtc-build/webrtc-build/releases/download/{version}/{filename}", + output_dir=source_dir, + ) + rm_rf(os.path.join(install_dir, "webrtc")) + extract(archive, output_dir=install_dir, output_dirname="webrtc") + + +def build_webrtc(platform, local_webrtc_build_dir, local_webrtc_build_args, debug): + with cd(local_webrtc_build_dir): + args = ["--webrtc-nobuild-ios-framework", "--webrtc-nobuild-android-aar"] + if debug: + args += ["--debug"] + + args += local_webrtc_build_args + + cmd(["python3", "run.py", "build", platform, *args]) + + # インクルードディレクトリを増やしたくないので、 + # __config_site を libc++ のディレクトリにコピーしておく + webrtc_source_dir = os.path.join(local_webrtc_build_dir, "_source", platform, "webrtc") + src_config = os.path.join( + webrtc_source_dir, "src", "buildtools", "third_party", "libc++", "__config_site" + ) + dst_config = os.path.join( + webrtc_source_dir, "src", "third_party", "libc++", "src", "include", "__config_site" + ) + copyfile_if_different(src_config, dst_config) + + # __assertion_handler をコピーする + src_assertion = os.path.join( + webrtc_source_dir, + "src", + "buildtools", + "third_party", + "libc++", + "__assertion_handler", + ) + dst_assertion = os.path.join( + webrtc_source_dir, + "src", + "third_party", + "libc++", + "src", + "include", + "__assertion_handler", + ) + copyfile_if_different(src_assertion, dst_assertion) + + +class WebrtcInfo(NamedTuple): + version_file: str + deps_file: str + webrtc_include_dir: str + webrtc_source_dir: Optional[str] + webrtc_library_dir: str + clang_dir: str + libcxx_dir: str + + +def get_webrtc_info( + platform: str, local_webrtc_build_dir: Optional[str], install_dir: str, debug: bool +) -> WebrtcInfo: + webrtc_install_dir = os.path.join(install_dir, "webrtc") + + if local_webrtc_build_dir is None: + return WebrtcInfo( + version_file=os.path.join(webrtc_install_dir, "VERSIONS"), + deps_file=os.path.join(webrtc_install_dir, "DEPS"), + webrtc_include_dir=os.path.join(webrtc_install_dir, "include"), + webrtc_source_dir=None, + webrtc_library_dir=os.path.join(webrtc_install_dir, "lib"), + clang_dir=os.path.join(install_dir, "llvm", "clang"), + libcxx_dir=os.path.join(install_dir, "llvm", "libcxx"), + ) + else: + webrtc_build_source_dir = os.path.join( + local_webrtc_build_dir, "_source", platform, "webrtc" + ) + configuration = "debug" if debug else "release" + webrtc_build_build_dir = os.path.join( + local_webrtc_build_dir, "_build", platform, configuration, "webrtc" + ) + + return WebrtcInfo( + version_file=os.path.join(local_webrtc_build_dir, "VERSION"), + deps_file=os.path.join(local_webrtc_build_dir, "DEPS"), + webrtc_include_dir=os.path.join(webrtc_build_source_dir, "src"), + webrtc_source_dir=os.path.join(webrtc_build_source_dir, "src"), + webrtc_library_dir=webrtc_build_build_dir, + clang_dir=os.path.join( + webrtc_build_source_dir, "src", "third_party", "llvm-build", "Release+Asserts" + ), + libcxx_dir=os.path.join(webrtc_build_source_dir, "src", "third_party", "libc++", "src"), + ) + + +@versioned +def install_boost(version, source_dir, install_dir, sora_version, platform: str): + win = platform.startswith("windows_") + filename = ( + f'boost-{version}_sora-cpp-sdk-{sora_version}_{platform}.{"zip" if win else "tar.gz"}' + ) + rm_rf(os.path.join(source_dir, filename)) + archive = download( + f"https://github.com/shiguredo/sora-cpp-sdk/releases/download/{sora_version}/{filename}", + output_dir=source_dir, + ) + rm_rf(os.path.join(install_dir, "boost")) + extract(archive, output_dir=install_dir, output_dirname="boost") + + +# 以下の問題を解決するためのパッチ +# +# No support for msvc-toolset 14.4x (VS 2022, 17.10.x): https://github.com/boostorg/boost/issues/914 +BOOST_PATCH_SUPPORT_14_4 = r""" +diff --git a/tools/build/src/engine/config_toolset.bat b/tools/build/src/engine/config_toolset.bat +index 4ba577cac..3e3f6a3a1 100644 +--- a/tools/build/src/engine/config_toolset.bat ++++ b/tools/build/src/engine/config_toolset.bat +@@ -157,7 +157,7 @@ pushd %CD% + if "_%VSINSTALLDIR%_" == "__" call :Call_If_Exists "%B2_TOOLSET_ROOT%Auxiliary\Build\vcvarsall.bat" %B2_BUILD_ARGS% + popd + @REM set "B2_CXX="%CXX%" /nologo /MP /MT /TP /Feb2 /wd4996 /O2 /GL /EHsc" +-set "B2_CXX="%CXX%" /nologo -TP /wd4996 /wd4675 /EHs /GR /Zc:throwingNew /O2 /Ob2 /W3 /MD /Zc:forScope /Zc:wchar_t /Zc:inline /Gw /favor:blend /Feb2" ++set "B2_CXX="%CXX%" /nologo -TP /wd4996 /wd4675 /EHs /GR /Zc:throwingNew /O2 /Ob2 /W3 /MT /Zc:forScope /Zc:wchar_t /Zc:inline /Gw /favor:blend /Feb2" + set "B2_CXX_LINK=/link kernel32.lib advapi32.lib user32.lib" + set "_known_=1" + goto :Embed_Minafest_Via_Link +diff --git a/tools/build/src/tools/msvc.jam b/tools/build/src/tools/msvc.jam +index 54a6ced32..4bb3810b3 100644 +--- a/tools/build/src/tools/msvc.jam ++++ b/tools/build/src/tools/msvc.jam +@@ -1137,7 +1137,15 @@ local rule generate-setup-cmd ( version : command : parent : options * : cpu : g + } + else + { +- if [ MATCH "(14.3)" : $(version) ] ++ if [ MATCH "(14.4)" : $(version) ] ++ { ++ if $(.debug-configuration) ++ { ++ ECHO "notice: [generate-setup-cmd] $(version) is 14.4" ; ++ } ++ parent = [ path.native [ path.join $(parent) "..\\..\\..\\..\\..\\Auxiliary\\Build" ] ] ; ++ } ++ else if [ MATCH "(14.3)" : $(version) ] + { + if $(.debug-configuration) + { +@@ -1316,7 +1324,11 @@ local rule configure-really ( version ? : options * ) + # version from the path. + # FIXME: We currently detect both Microsoft Visual Studio 9.0 and + # 9.0express as 9.0 here. +- if [ MATCH "(MSVC\\\\14.3)" : $(command) ] ++ if [ MATCH "(MSVC\\\\14.4)" : $(command) ] ++ { ++ version = 14.4 ; ++ } ++ else if [ MATCH "(MSVC\\\\14.3)" : $(command) ] + { + version = 14.3 ; + } +@@ -1745,13 +1757,17 @@ local rule default-path ( version ) + # And fortunately, forward slashes do also work in native Windows. + local vswhere = "$(root)/Microsoft Visual Studio/Installer/vswhere.exe" ; + # The check for $(root) is to avoid a segmentation fault if not found. +- if $(version) in 14.1 14.2 14.3 default && $(root) && [ path.exists $(vswhere) ] ++ if $(version) in 14.1 14.2 14.3 14.4 default && $(root) && [ path.exists $(vswhere) ] + { + local req = "-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64" ; + local prop = "-property installationPath" ; + local limit ; + +- if $(version) = 14.3 ++ if $(version) = 14.4 ++ { ++ limit = "-version \"[17.0,18.0)\" -prerelease" ; ++ } ++ else if $(version) = 14.3 + { + limit = "-version \"[17.0,18.0)\" -prerelease" ; + } +@@ -2174,7 +2190,7 @@ for local arch in [ MATCH "^\\.cpus-on-(.*)" : [ VARNAMES $(__name__) ] ] + armv7 armv7s ; + + # Known toolset versions, in order of preference. +-.known-versions = 14.3 14.2 14.1 14.0 12.0 11.0 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1 ++.known-versions = 14.4 14.3 14.2 14.1 14.0 12.0 11.0 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1 + 7.1toolkit 7.0 6.0 ; + + # Version aliases. +@@ -2226,6 +2242,11 @@ for local arch in [ MATCH "^\\.cpus-on-(.*)" : [ VARNAMES $(__name__) ] ] + "Microsoft Visual Studio/2022/*/VC/Tools/MSVC/*/bin/Host*/*" + ; + .version-14.3-env = VS170COMNTOOLS ProgramFiles ProgramFiles(x86) ; ++.version-14.4-path = ++ "../../VC/Tools/MSVC/*/bin/Host*/*" ++ "Microsoft Visual Studio/2022/*/VC/Tools/MSVC/*/bin/Host*/*" ++ ; ++.version-14.4-env = VS170COMNTOOLS ProgramFiles ProgramFiles(x86) ; + + # Auto-detect all the available msvc installations on the system. + auto-detect-toolset-versions ; +""" + + +@versioned +def build_and_install_boost( + version: str, + source_dir, + build_dir, + install_dir, + debug: bool, + cxx: str, + cflags: List[str], + cxxflags: List[str], + linkflags: List[str], + toolset, + visibility, + target_os, + architecture, + android_ndk, + native_api_level, + address_model="64", +): + version_underscore = version.replace(".", "_") + archive = download( + # XXX: ここ GitHub Releases に変更するのはダメなのだろうか? + f"https://boostorg.jfrog.io/artifactory/main/release/{version}/source/boost_{version_underscore}.tar.gz", + source_dir, + ) + extract(archive, output_dir=build_dir, output_dirname="boost") + with cd(os.path.join(build_dir, "boost")): + bootstrap = ".\\bootstrap.bat" if target_os == "windows" else "./bootstrap.sh" + b2 = "b2" if target_os == "windows" else "./b2" + runtime_link = "static" if target_os == "windows" else "shared" + + # Windows かつ Boost 1.85.0 の場合はパッチを当てる + if target_os == "windows" and version == "1.85.0": + apply_patch_text(BOOST_PATCH_SUPPORT_14_4, os.path.join(build_dir, "boost"), 1) + + cmd([bootstrap]) + + if target_os == "iphone": + IOS_BUILD_TARGETS = [("arm64", "iphoneos")] + for arch, sdk in IOS_BUILD_TARGETS: + clangpp = cmdcap(["xcodebuild", "-find", "clang++"]) + sysroot = cmdcap(["xcrun", "--sdk", sdk, "--show-sdk-path"]) + boost_arch = "x86" if arch == "x86_64" else "arm" + with open("project-config.jam", "w") as f: + f.write( + f"using clang \ + : iphone \ + : {clangpp} -arch {arch} -isysroot {sysroot} \ + -fembed-bitcode \ + -mios-version-min=10.0 \ + -fvisibility=hidden \ + : {sysroot} \ + ; \ + " + ) + cmd( + [ + b2, + "install", + "-d+0", + f'--build-dir={os.path.join(build_dir, "boost", f"build-{arch}-{sdk}")}', + f'--prefix={os.path.join(build_dir, "boost", f"install-{arch}-{sdk}")}', + "--with-json", + "--with-filesystem", + "--layout=system", + "--ignore-site-config", + f'variant={"debug" if debug else "release"}', + f'cflags={" ".join(cflags)}', + f'cxxflags={" ".join(cxxflags)}', + f'linkflags={" ".join(linkflags)}', + f"toolset={toolset}", + f"visibility={visibility}", + f"target-os={target_os}", + f"address-model={address_model}", + "link=static", + f"runtime-link={runtime_link}", + "threading=multi", + f"architecture={boost_arch}", + ] + ) + arch, sdk = IOS_BUILD_TARGETS[0] + installed_path = os.path.join(build_dir, "boost", f"install-{arch}-{sdk}") + rm_rf(os.path.join(install_dir, "boost")) + cmd(["cp", "-r", installed_path, os.path.join(install_dir, "boost")]) + + for lib in enum_all_files( + os.path.join(installed_path, "lib"), os.path.join(installed_path, "lib") + ): + if not lib.endswith(".a"): + continue + files = [ + os.path.join(build_dir, "boost", f"install-{arch}-{sdk}", "lib", lib) + for arch, sdk in IOS_BUILD_TARGETS + ] + if len(files) == 1: + shutil.copyfile(files[0], os.path.join(install_dir, "boost", "lib", lib)) + else: + cmd( + [ + "lipo", + "-create", + "-output", + os.path.join(install_dir, "boost", "lib", lib), + ] + + files + ) + elif target_os == "android": + # Android の場合、android-ndk を使ってビルドする + with open("project-config.jam", "w") as f: + bin = os.path.join( + android_ndk, "toolchains", "llvm", "prebuilt", "linux-x86_64", "bin" + ) + sysroot = os.path.join( + android_ndk, "toolchains", "llvm", "prebuilt", "linux-x86_64", "sysroot" + ) + f.write( + f"using clang \ + : android \ + : {os.path.join(bin, 'clang++')} \ + --target=aarch64-none-linux-android{native_api_level} \ + --sysroot={sysroot} \ + : {os.path.join(bin, 'llvm-ar')} \ + {os.path.join(bin, 'llvm-ranlib')} \ + ; \ + " + ) + cmd( + [ + b2, + "install", + "-d+0", + f'--prefix={os.path.join(install_dir, "boost")}', + "--with-json", + "--with-filesystem", + "--layout=system", + "--ignore-site-config", + f'variant={"debug" if debug else "release"}', + f"compileflags=--sysroot={sysroot}", + f'cflags={" ".join(cflags)}', + f'cxxflags={" ".join(cxxflags)}', + f'linkflags={" ".join(linkflags)}', + f"toolset={toolset}", + f"visibility={visibility}", + f"target-os={target_os}", + f"address-model={address_model}", + "link=static", + f"runtime-link={runtime_link}", + "threading=multi", + "architecture=arm", + ] + ) + else: + if len(cxx) != 0: + with open("project-config.jam", "w") as f: + f.write(f"using {toolset} : : {cxx} : ;") + cmd( + [ + b2, + "install", + "-d+0", + f'--prefix={os.path.join(install_dir, "boost")}', + "--with-json", + "--with-filesystem", + "--layout=system", + "--ignore-site-config", + f'variant={"debug" if debug else "release"}', + f'cflags={" ".join(cflags)}', + f'cxxflags={" ".join(cxxflags)}', + f'linkflags={" ".join(linkflags)}', + f"toolset={toolset}", + f"visibility={visibility}", + f"target-os={target_os}", + f"address-model={address_model}", + "link=static", + f"runtime-link={runtime_link}", + "threading=multi", + f"architecture={architecture}", + ] + ) + + +@versioned +def install_sora(version, source_dir, install_dir, platform: str): + win = platform.startswith("windows_") + filename = f'sora-cpp-sdk-{version}_{platform}.{"zip" if win else "tar.gz"}' + rm_rf(os.path.join(source_dir, filename)) + archive = download( + f"https://github.com/shiguredo/sora-cpp-sdk/releases/download/{version}/{filename}", + output_dir=source_dir, + ) + rm_rf(os.path.join(install_dir, "sora")) + extract(archive, output_dir=install_dir, output_dirname="sora") + + +def install_sora_and_deps(platform: str, source_dir: str, install_dir: str): + version = read_version_file("VERSION") + + # Boost + install_boost_args = { + "version": version["BOOST_VERSION"], + "version_file": os.path.join(install_dir, "boost.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "sora_version": version["SORA_CPP_SDK_VERSION"], + "platform": platform, + } + install_boost(**install_boost_args) + + # Sora C++ SDK + install_sora_args = { + "version": version["SORA_CPP_SDK_VERSION"], + "version_file": os.path.join(install_dir, "sora.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": platform, + } + install_sora(**install_sora_args) + + +def build_sora( + platform: str, + local_sora_cpp_sdk_dir: str, + local_sora_cpp_sdk_args: List[str], + debug: bool, + local_webrtc_build_dir: Optional[str], +): + if debug and "--debug" not in local_sora_cpp_sdk_args: + local_sora_cpp_sdk_args = ["--debug", *local_sora_cpp_sdk_args] + if local_webrtc_build_dir is not None: + local_sora_cpp_sdk_args = [ + "--local-webrtc-build-dir", + local_webrtc_build_dir, + *local_sora_cpp_sdk_args, + ] + + with cd(local_sora_cpp_sdk_dir): + cmd(["python3", "run.py", platform, *local_sora_cpp_sdk_args]) + + +class SoraInfo(NamedTuple): + sora_install_dir: str + boost_install_dir: str + + +def get_sora_info( + platform: str, local_sora_cpp_sdk_dir: Optional[str], install_dir: str, debug: bool +) -> SoraInfo: + if local_sora_cpp_sdk_dir is not None: + configuration = "debug" if debug else "release" + install_dir = os.path.join(local_sora_cpp_sdk_dir, "_install", platform, configuration) + + return SoraInfo( + sora_install_dir=os.path.join(install_dir, "sora"), + boost_install_dir=os.path.join(install_dir, "boost"), + ) + + +@versioned +def install_rootfs(version, install_dir, conf, arch="arm64"): + rootfs_dir = os.path.join(install_dir, "rootfs") + rm_rf(rootfs_dir) + cmd(["multistrap", "--no-auth", "-a", arch, "-d", rootfs_dir, "-f", conf]) + # 絶対パスのシンボリックリンクを相対パスに置き換えていく + for dir, _, filenames in os.walk(rootfs_dir): + for filename in filenames: + linkpath = os.path.join(dir, filename) + # symlink かどうか + if not os.path.islink(linkpath): + continue + target = os.readlink(linkpath) + # 絶対パスかどうか + if not os.path.isabs(target): + continue + # rootfs_dir を先頭に付けることで、 + # rootfs の外から見て正しい絶対パスにする + targetpath = rootfs_dir + target + # 参照先の絶対パスが存在するかどうか + if not os.path.exists(targetpath): + continue + # 相対パスに置き換える + relpath = os.path.relpath(targetpath, dir) + logging.debug(f"{linkpath[len(rootfs_dir):]} targets {target} to {relpath}") + os.remove(linkpath) + os.symlink(relpath, linkpath) + + # なぜかシンボリックリンクが登録されていないので作っておく + link = os.path.join(rootfs_dir, "usr", "lib", "aarch64-linux-gnu", "tegra", "libnvbuf_fdmap.so") + file = os.path.join( + rootfs_dir, "usr", "lib", "aarch64-linux-gnu", "tegra", "libnvbuf_fdmap.so.1.0.0" + ) + if os.path.exists(file) and not os.path.exists(link): + os.symlink(os.path.basename(file), link) + + # JetPack 6 から tegra → nvidia になった + link = os.path.join( + rootfs_dir, "usr", "lib", "aarch64-linux-gnu", "nvidia", "libnvbuf_fdmap.so" + ) + file = os.path.join( + rootfs_dir, "usr", "lib", "aarch64-linux-gnu", "nvidia", "libnvbuf_fdmap.so.1.0.0" + ) + if os.path.exists(file) and not os.path.exists(link): + os.symlink(os.path.basename(file), link) + + +@versioned +def install_android_ndk(version, install_dir, source_dir, platform="linux"): + if platform not in ("darwin", "linux"): + raise Exception(f"Not supported platform: {platform}") + + if platform == "darwin": + url = f"https://dl.google.com/android/repository/android-ndk-{version}-{platform}.dmg" + file = f"android-ndk-{version}-{platform}.dmg" + else: + url = f"https://dl.google.com/android/repository/android-ndk-{version}-{platform}.zip" + archive = download(url, source_dir) + rm_rf(os.path.join(install_dir, "android-ndk")) + if platform == "darwin": + cap = cmdcap(["hdiutil", "attach", os.path.join(source_dir, file)]) + # 以下のような結果が得られるはずなので、ここから /Volumes/Android NDK r26 のところだけ取り出す + # /dev/disk4 GUID_partition_scheme + # /dev/disk4s1 EFI + # /dev/disk4s2 Apple_HFS /Volumes/Android NDK r26 + volume = cap.split("\n")[-1].split("\t")[-1] + # AndroidNDK10792818.app みたいな感じの app があるはず + app = glob.glob("AndroidNDK*.app", root_dir=volume)[0] + # NDK ディレクトリをコピー + cmd( + [ + "cp", + "-r", + os.path.join(volume, app, "Contents", "NDK"), + os.path.join(install_dir, "android-ndk"), + ] + ) + cmdcap(["hdiutil", "detach", volume]) + else: + extract(archive, output_dir=install_dir, output_dirname="android-ndk") + + +@versioned +def install_android_sdk_cmdline_tools(version, install_dir, source_dir): + archive = download( + f"https://dl.google.com/android/repository/commandlinetools-linux-{version}_latest.zip", + source_dir, + ) + tools_dir = os.path.join(install_dir, "android-sdk-cmdline-tools") + rm_rf(tools_dir) + extract(archive, output_dir=tools_dir, output_dirname="cmdline-tools") + sdkmanager = os.path.join(tools_dir, "cmdline-tools", "bin", "sdkmanager") + # ライセンスを許諾する + cmd(["/bin/bash", "-c", f"yes | {sdkmanager} --sdk_root={tools_dir} --licenses"]) + + +@versioned +def install_llvm( + version, + install_dir, + tools_url, + tools_commit, + libcxx_url, + libcxx_commit, + buildtools_url, + buildtools_commit, +): + llvm_dir = os.path.join(install_dir, "llvm") + rm_rf(llvm_dir) + mkdir_p(llvm_dir) + with cd(llvm_dir): + # tools の update.py を叩いて特定バージョンの clang バイナリを拾う + git_clone_shallow(tools_url, tools_commit, "tools") + with cd("tools"): + cmd( + [ + "python3", + os.path.join("clang", "scripts", "update.py"), + "--output-dir", + os.path.join(llvm_dir, "clang"), + ] + ) + + # 特定バージョンの libcxx を利用する + git_clone_shallow(libcxx_url, libcxx_commit, "libcxx") + + # __config_site のために特定バージョンの buildtools を取得する + git_clone_shallow(buildtools_url, buildtools_commit, "buildtools") + with cd("buildtools"): + cmd(["git", "reset", "--hard", buildtools_commit]) + shutil.copyfile( + os.path.join(llvm_dir, "buildtools", "third_party", "libc++", "__config_site"), + os.path.join(llvm_dir, "libcxx", "include", "__config_site"), + ) + + # __assertion_handler をコピーする + # 背景: https://source.chromium.org/chromium/_/chromium/external/github.com/llvm/llvm-project/libcxx.git/+/1e5bda0d1ce8e346955aa4a85eaab258785f11f7 + shutil.copyfile( + # NOTE(enm10k): 最初は default_assertion_handler.in をコピーしていたが、 buildtools 以下に + # default_assertion_handler.in から生成されたと思われる __assertion_handler が存在するため、それをコピーする + # os.path.join(llvm_dir, "libcxx", "vendor", "llvm", "default_assertion_handler.in"), + os.path.join(llvm_dir, "buildtools", "third_party", "libc++", "__assertion_handler"), + os.path.join(llvm_dir, "libcxx", "include", "__assertion_handler"), + ) + + +def cmake_path(path: str) -> str: + return path.replace("\\", "/") + + +@versioned +def install_cmake(version, source_dir, install_dir, platform: str, ext): + url = f"https://github.com/Kitware/CMake/releases/download/v{version}/cmake-{version}-{platform}.{ext}" + path = download(url, source_dir) + extract(path, install_dir, "cmake") + # Android で自前の CMake を利用する場合、ninja へのパスが見つけられない問題があるので、同じディレクトリに symlink を貼る + # https://issuetracker.google.com/issues/206099937 + if platform.startswith("linux"): + with cd(os.path.join(install_dir, "cmake", "bin")): + cmd(["ln", "-s", "/usr/bin/ninja", "ninja"]) + + +@versioned +def install_sdl2( + version, source_dir, build_dir, install_dir, debug: bool, platform: str, cmake_args: List[str] +): + url = ( + f"https://github.com/libsdl-org/SDL/releases/download/release-{version}/SDL2-{version}.zip" + ) + path = download(url, source_dir) + sdl2_source_dir = os.path.join(source_dir, "sdl2") + sdl2_build_dir = os.path.join(build_dir, "sdl2") + sdl2_install_dir = os.path.join(install_dir, "sdl2") + rm_rf(sdl2_source_dir) + rm_rf(sdl2_build_dir) + rm_rf(sdl2_install_dir) + extract(path, source_dir, "sdl2") + + mkdir_p(sdl2_build_dir) + with cd(sdl2_build_dir): + configuration = "Debug" if debug else "Release" + cmake_args = cmake_args[:] + cmake_args += [ + sdl2_source_dir, + f"-DCMAKE_BUILD_TYPE={configuration}", + f"-DCMAKE_INSTALL_PREFIX={cmake_path(sdl2_install_dir)}", + "-DBUILD_SHARED_LIBS=OFF", + ] + if platform == "windows": + cmake_args += [ + "-DSDL_FORCE_STATIC_VCRT=ON", + "-DHAVE_LIBC=ON", + ] + elif platform == "macos": + # システムでインストール済みかによって ON/OFF が切り替わってしまうため、 + # どの環境でも同じようにインストールされるようにするため全部 ON/OFF を明示的に指定する + cmake_args += [ + "-DSDL_ATOMIC=OFF", + "-DSDL_AUDIO=OFF", + "-DSDL_VIDEO=ON", + "-DSDL_RENDER=ON", + "-DSDL_EVENTS=ON", + "-DSDL_JOYSTICK=ON", + "-DSDL_HAPTIC=ON", + "-DSDL_POWER=ON", + "-DSDL_THREADS=ON", + "-DSDL_TIMERS=OFF", + "-DSDL_FILE=OFF", + "-DSDL_LOADSO=ON", + "-DSDL_CPUINFO=OFF", + "-DSDL_FILESYSTEM=OFF", + "-DSDL_SENSOR=ON", + "-DSDL_OPENGL=ON", + "-DSDL_OPENGLES=ON", + "-DSDL_RPI=OFF", + "-DSDL_WAYLAND=OFF", + "-DSDL_X11=OFF", + "-DSDL_VULKAN=OFF", + "-DSDL_VIVANTE=OFF", + "-DSDL_COCOA=ON", + "-DSDL_METAL=ON", + "-DSDL_KMSDRM=OFF", + ] + elif platform == "linux": + # システムでインストール済みかによって ON/OFF が切り替わってしまうため、 + # どの環境でも同じようにインストールされるようにするため全部 ON/OFF を明示的に指定する + cmake_args += [ + "-DSDL_ATOMIC=OFF", + "-DSDL_AUDIO=OFF", + "-DSDL_VIDEO=ON", + "-DSDL_RENDER=ON", + "-DSDL_EVENTS=ON", + "-DSDL_JOYSTICK=ON", + "-DSDL_HAPTIC=ON", + "-DSDL_POWER=ON", + "-DSDL_THREADS=ON", + "-DSDL_TIMERS=OFF", + "-DSDL_FILE=OFF", + "-DSDL_LOADSO=ON", + "-DSDL_CPUINFO=OFF", + "-DSDL_FILESYSTEM=OFF", + "-DSDL_SENSOR=ON", + "-DSDL_OPENGL=ON", + "-DSDL_OPENGLES=ON", + "-DSDL_RPI=OFF", + "-DSDL_WAYLAND=OFF", + "-DSDL_X11=ON", + "-DSDL_X11_SHARED=OFF", + "-DSDL_X11_XCURSOR=OFF", + "-DSDL_X11_XDBE=OFF", + "-DSDL_X11_XFIXES=OFF", + "-DSDL_X11_XINERAMA=OFF", + "-DSDL_X11_XINPUT=OFF", + "-DSDL_X11_XRANDR=OFF", + "-DSDL_X11_XSCRNSAVER=OFF", + "-DSDL_X11_XSHAPE=OFF", + "-DSDL_X11_XVM=OFF", + "-DSDL_VULKAN=OFF", + "-DSDL_VIVANTE=OFF", + "-DSDL_COCOA=OFF", + "-DSDL_METAL=OFF", + "-DSDL_KMSDRM=OFF", + ] + cmd(["cmake"] + cmake_args) + + cmd( + ["cmake", "--build", ".", "--config", configuration, f"-j{multiprocessing.cpu_count()}"] + ) + cmd(["cmake", "--install", ".", "--config", configuration]) + + +@versioned +def install_cli11(version, install_dir): + cli11_install_dir = os.path.join(install_dir, "cli11") + rm_rf(cli11_install_dir) + cmd( + [ + "git", + "clone", + "--branch", + version, + "--depth", + "1", + "https://github.com/CLIUtils/CLI11.git", + cli11_install_dir, + ] + ) + + +@versioned +def install_cuda_windows(version, source_dir, build_dir, install_dir): + rm_rf(os.path.join(build_dir, "cuda")) + rm_rf(os.path.join(install_dir, "cuda")) + if version == "10.2.89-1": + url = "http://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_441.22_win10.exe" # noqa: E501 + elif version == "11.8.0-1": + url = "https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda_11.8.0_522.06_windows.exe" # noqa: E501 + else: + raise Exception(f"Unknown CUDA version {version}") + file = download(url, source_dir) + + mkdir_p(os.path.join(build_dir, "cuda")) + mkdir_p(os.path.join(install_dir, "cuda")) + with cd(os.path.join(build_dir, "cuda")): + cmd(["7z", "x", file]) + copytree( + os.path.join(build_dir, "cuda", "cuda_nvcc", "nvcc"), os.path.join(install_dir, "cuda") + ) + copytree( + os.path.join(build_dir, "cuda", "cuda_cudart", "cudart"), os.path.join(install_dir, "cuda") + ) + + +@versioned +def install_vpl(version, configuration, source_dir, build_dir, install_dir, cmake_args): + vpl_source_dir = os.path.join(source_dir, "vpl") + vpl_build_dir = os.path.join(build_dir, "vpl") + vpl_install_dir = os.path.join(install_dir, "vpl") + rm_rf(vpl_source_dir) + rm_rf(vpl_build_dir) + rm_rf(vpl_install_dir) + git_clone_shallow("https://github.com/intel/libvpl.git", version, vpl_source_dir) + + mkdir_p(vpl_build_dir) + with cd(vpl_build_dir): + cmd( + [ + "cmake", + f"-DCMAKE_INSTALL_PREFIX={cmake_path(vpl_install_dir)}", + f"-DCMAKE_BUILD_TYPE={configuration}", + "-DBUILD_SHARED_LIBS=OFF", + "-DBUILD_TOOLS=OFF", + "-DBUILD_EXAMPLES=OFF", + "-DBUILD_PREVIEW=OFF", + "-DINSTALL_EXAMPLE_CODE=OFF", + "-DBUILD_TOOLS_ONEVPL_EXPERIMENTAL=OFF", + "-DUSE_MSVC_STATIC_RUNTIME=ON", + vpl_source_dir, + *cmake_args, + ] + ) + # 生成されたプロジェクトに対して静的ランタイムを使うように変更する + vpl_path = os.path.join("libvpl", "VPL.vcxproj") + if os.path.exists(vpl_path): + replace_vcproj_static_runtime(vpl_path) + + cmd( + ["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}", "--config", configuration] + ) + cmd(["cmake", "--install", ".", "--config", configuration]) + + +@versioned +def install_blend2d( + version, + configuration, + source_dir, + build_dir, + install_dir, + blend2d_version, + asmjit_version, + ios, + cmake_args, +): + rm_rf(os.path.join(source_dir, "blend2d")) + rm_rf(os.path.join(build_dir, "blend2d")) + rm_rf(os.path.join(install_dir, "blend2d")) + + git_clone_shallow( + "https://github.com/blend2d/blend2d", blend2d_version, os.path.join(source_dir, "blend2d") + ) + mkdir_p(os.path.join(source_dir, "blend2d", "3rdparty")) + git_clone_shallow( + "https://github.com/asmjit/asmjit", + asmjit_version, + os.path.join(source_dir, "blend2d", "3rdparty", "asmjit"), + ) + + mkdir_p(os.path.join(build_dir, "blend2d")) + with cd(os.path.join(build_dir, "blend2d")): + cmd( + [ + "cmake", + os.path.join(source_dir, "blend2d"), + f"-DCMAKE_BUILD_TYPE={configuration}", + f"-DCMAKE_INSTALL_PREFIX={cmake_path(os.path.join(install_dir, 'blend2d'))}", + "-DBLEND2D_STATIC=ON", + *cmake_args, + ] + ) + # 生成されたプロジェクトに対して静的ランタイムを使うように変更する + project_path = os.path.join(build_dir, "blend2d", "blend2d.vcxproj") + if os.path.exists(project_path): + replace_vcproj_static_runtime(project_path) + + if ios: + cmd( + [ + "cmake", + "--build", + ".", + f"-j{multiprocessing.cpu_count()}", + "--config", + configuration, + "--target", + "blend2d", + "--", + "-arch", + "arm64", + "-sdk", + "iphoneos", + ] + ) + cmd(["cmake", "--build", ".", "--target", "install", "--config", configuration]) + else: + cmd( + [ + "cmake", + "--build", + ".", + f"-j{multiprocessing.cpu_count()}", + "--config", + configuration, + ] + ) + cmd(["cmake", "--build", ".", "--target", "install", "--config", configuration]) + + +@versioned +def install_openh264(version, source_dir, install_dir, is_windows): + rm_rf(os.path.join(source_dir, "openh264")) + rm_rf(os.path.join(install_dir, "openh264")) + git_clone_shallow( + "https://github.com/cisco/openh264.git", version, os.path.join(source_dir, "openh264") + ) + with cd(os.path.join(source_dir, "openh264")): + if is_windows: + # Windows は make が無いので手動でコピーする + # install-headers: + # mkdir -p $(DESTDIR)$(PREFIX)/include/wels + # install -m 644 $(SRC_PATH)/codec/api/wels/codec*.h $(DESTDIR)$(PREFIX)/include/wels + mkdir_p(os.path.join(install_dir, "openh264", "include", "wels")) + with cd(os.path.join("codec", "api", "wels")): + for file in glob.glob("codec*.h"): + shutil.copyfile( + file, os.path.join(install_dir, "openh264", "include", "wels", file) + ) + else: + cmd(["make", f'PREFIX={os.path.join(install_dir, "openh264")}', "install-headers"]) + + +@versioned +def install_yaml(version, source_dir, build_dir, install_dir, cmake_args): + rm_rf(os.path.join(source_dir, "yaml")) + rm_rf(os.path.join(install_dir, "yaml")) + rm_rf(os.path.join(build_dir, "yaml")) + git_clone_shallow( + "https://github.com/jbeder/yaml-cpp.git", version, os.path.join(source_dir, "yaml") + ) + + mkdir_p(os.path.join(build_dir, "yaml")) + with cd(os.path.join(build_dir, "yaml")): + cmd( + [ + "cmake", + os.path.join(source_dir, "yaml"), + "-DCMAKE_BUILD_TYPE=Release", + f"-DCMAKE_INSTALL_PREFIX={install_dir}/yaml", + "-DYAML_CPP_BUILD_TESTS=OFF", + "-DYAML_CPP_BUILD_TOOLS=OFF", + *cmake_args, + ] + ) + cmd(["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}"]) + cmd(["cmake", "--build", ".", "--target", "install"]) + + +@versioned +def install_catch2(version, source_dir, build_dir, install_dir, configuration, cmake_args): + rm_rf(os.path.join(source_dir, "catch2")) + rm_rf(os.path.join(install_dir, "catch2")) + rm_rf(os.path.join(build_dir, "catch2")) + git_clone_shallow( + "https://github.com/catchorg/Catch2.git", version, os.path.join(source_dir, "catch2") + ) + + mkdir_p(os.path.join(build_dir, "catch2")) + with cd(os.path.join(build_dir, "catch2")): + cmd( + [ + "cmake", + os.path.join(source_dir, "catch2"), + f"-DCMAKE_BUILD_TYPE={configuration}", + f"-DCMAKE_INSTALL_PREFIX={install_dir}/catch2", + "-DCATCH_BUILD_TESTING=OFF", + *cmake_args, + ] + ) + # 生成されたプロジェクトに対して静的ランタイムを使うように変更する + project_path = os.path.join("src", "Catch2.vcxproj") + if os.path.exists(project_path): + replace_vcproj_static_runtime(project_path) + project_path = os.path.join("src", "Catch2WithMain.vcxproj") + if os.path.exists(project_path): + replace_vcproj_static_runtime(project_path) + cmd( + ["cmake", "--build", ".", "--config", configuration, f"-j{multiprocessing.cpu_count()}"] + ) + cmd(["cmake", "--build", ".", "--config", configuration, "--target", "install"]) + + +@versioned +def install_protobuf(version, source_dir, install_dir, platform: str): + # platform: + # - linux-aarch_64 + # - linux-ppcle_64 + # - linux-s390_64 + # - linux-x86_32 + # - linux-x86_64 + # - osx-aarch_64 + # - osx-universal_binary + # - osx-x86_64 + # - win32 + # - win64 + url = f"https://github.com/protocolbuffers/protobuf/releases/download/v{version}/protoc-{version}-{platform}.zip" + path = download(url, source_dir) + rm_rf(os.path.join(install_dir, "protobuf")) + extract(path, install_dir, "protobuf") + # なぜか実行属性が消えてるので入れてやる + for file in os.scandir(os.path.join(install_dir, "protobuf", "bin")): + if file.is_file(): + os.chmod(file.path, file.stat().st_mode | stat.S_IXUSR) + + +@versioned +def install_protoc_gen_jsonif(version, source_dir, install_dir, platform: str): + # platform: + # - darwin-amd64 + # - darwin-arm64 + # - linux-amd64 + # - windows-amd64 + url = f"https://github.com/melpon/protoc-gen-jsonif/releases/download/{version}/protoc-gen-jsonif.tar.gz" + rm_rf(os.path.join(source_dir, "protoc-gen-jsonif.tar.gz")) + path = download(url, source_dir) + jsonif_install_dir = os.path.join(install_dir, "protoc-gen-jsonif") + rm_rf(jsonif_install_dir) + extract(path, install_dir, "protoc-gen-jsonif") + # 自分の環境のバイナリを /bin に配置する + shutil.copytree( + os.path.join(jsonif_install_dir, *platform.split("-")), + os.path.join(jsonif_install_dir, "bin"), + ) + # なぜか実行属性が消えてるので入れてやる + for file in os.scandir(os.path.join(jsonif_install_dir, "bin")): + if file.is_file(): + os.chmod(file.path, file.stat().st_mode | stat.S_IXUSR) + + +# iOS, Android などのクロスコンパイル環境で実行可能ファイルを生成しようとしてエラーになるのを防止するパッチ +# +# v1.64.1 をベースにパッチを当てている +# +# MEMO: gRPC の、submodule を含めて全ての diff を取得するコマンド +# git --no-pager diff --ignore-submodules && git submodule foreach --recursive 'git --no-pager diff --ignore-submodules --src-prefix a/$path/ --dst-prefix b/$path/' | grep -v '^Entering' +GRPC_PATCH_NO_EXECUTABLE = r""" +diff --git a/third_party/boringssl-with-bazel/CMakeLists.txt b/third_party/boringssl-with-bazel/CMakeLists.txt +index 6464e200f..c7bc417a1 100644 +--- a/third_party/boringssl-with-bazel/CMakeLists.txt ++++ b/third_party/boringssl-with-bazel/CMakeLists.txt +@@ -543,30 +543,6 @@ add_library( + + target_link_libraries(ssl crypto) + +-add_executable( +- bssl +- +- src/tool/args.cc +- src/tool/ciphers.cc +- src/tool/client.cc +- src/tool/const.cc +- src/tool/digest.cc +- src/tool/fd.cc +- src/tool/file.cc +- src/tool/generate_ech.cc +- src/tool/generate_ed25519.cc +- src/tool/genrsa.cc +- src/tool/pkcs12.cc +- src/tool/rand.cc +- src/tool/server.cc +- src/tool/sign.cc +- src/tool/speed.cc +- src/tool/tool.cc +- src/tool/transport_common.cc +-) +- +-target_link_libraries(bssl ssl crypto) +- + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android") + find_package(Threads REQUIRED) + target_link_libraries(crypto Threads::Threads) +diff --git a/third_party/zlib/CMakeLists.txt b/third_party/zlib/CMakeLists.txt +index 7f1b69f..bcf5577 100644 +--- a/third_party/zlib/CMakeLists.txt ++++ b/third_party/zlib/CMakeLists.txt +@@ -147,10 +147,7 @@ if(MINGW) + set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) + endif(MINGW) + +-add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) + add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +-set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) +-set_target_properties(zlib PROPERTIES SOVERSION 1) + + if(NOT CYGWIN) + # This property causes shared libraries on Linux to have the full version +@@ -160,22 +157,16 @@ if(NOT CYGWIN) + # + # This has no effect with MSVC, on that platform the version info for + # the DLL comes from the resource file win32/zlib1.rc +- set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) + endif() + + if(UNIX) + # On unix-like platforms the library is almost always called libz +- set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z) +- if(NOT APPLE) +- set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") +- endif() + elseif(BUILD_SHARED_LIBS AND WIN32) + # Creates zlib1.dll when building shared library version +- set_target_properties(zlib PROPERTIES SUFFIX "1.dll") + endif() + + if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) +- install(TARGETS zlib zlibstatic ++ install(TARGETS zlibstatic + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" + ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ) +@@ -193,21 +184,3 @@ endif() + #============================================================================ + # Example binaries + #============================================================================ +- +-add_executable(example test/example.c) +-target_link_libraries(example zlib) +-add_test(example example) +- +-add_executable(minigzip test/minigzip.c) +-target_link_libraries(minigzip zlib) +- +-if(HAVE_OFF64_T) +- add_executable(example64 test/example.c) +- target_link_libraries(example64 zlib) +- set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") +- add_test(example64 example64) +- +- add_executable(minigzip64 test/minigzip.c) +- target_link_libraries(minigzip64 zlib) +- set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") +-endif() +""" + + +@versioned +def install_grpc(version, source_dir, build_dir, install_dir, debug: bool, cmake_args: List[str]): + grpc_source_dir = os.path.join(source_dir, "grpc") + grpc_build_dir = os.path.join(build_dir, "grpc") + grpc_install_dir = os.path.join(install_dir, "grpc") + rm_rf(grpc_source_dir) + rm_rf(grpc_build_dir) + rm_rf(grpc_install_dir) + git_clone_shallow("https://github.com/grpc/grpc.git", version, grpc_source_dir, submodule=True) + apply_patch_text(GRPC_PATCH_NO_EXECUTABLE, grpc_source_dir, 1) + mkdir_p(grpc_build_dir) + with cd(grpc_build_dir): + configuration = "Debug" if debug else "Release" + cmd( + [ + "cmake", + grpc_source_dir, + f"-DCMAKE_INSTALL_PREFIX={cmake_path(grpc_install_dir)}", + f"-DCMAKE_BUILD_TYPE={configuration}", + *cmake_args, + ] + ) + cmd( + ["cmake", "--build", ".", f"-j{multiprocessing.cpu_count()}", "--config", configuration] + ) + cmd(["cmake", "--install", ".", "--config", configuration]) + + +@versioned +def install_ggrpc(version, install_dir): + ggrpc_install_dir = os.path.join(install_dir, "ggrpc") + rm_rf(ggrpc_install_dir) + git_clone_shallow("https://github.com/melpon/ggrpc.git", version, ggrpc_install_dir) + + +@versioned +def install_spdlog(version, install_dir): + spdlog_install_dir = os.path.join(install_dir, "spdlog") + rm_rf(spdlog_install_dir) + git_clone_shallow("https://github.com/gabime/spdlog.git", version, spdlog_install_dir) + + +class PlatformTarget(object): + def __init__(self, os, osver, arch, extra=None): + self.os = os + self.osver = osver + self.arch = arch + self.extra = extra + + @property + def package_name(self): + if self.os == "windows": + return f"windows_{self.arch}" + if self.os == "macos": + return f"macos_{self.arch}" + if self.os == "ubuntu": + return f"ubuntu-{self.osver}_{self.arch}" + if self.os == "ios": + return "ios" + if self.os == "android": + return "android" + if self.os == "raspberry-pi-os": + return f"raspberry-pi-os_{self.arch}" + if self.os == "jetson": + if self.extra is None: + return f"ubuntu-20.04_{self.arch}_jetson" + return f"{self.extra}_{self.arch}_jetson" + raise Exception("error") + + +def get_windows_osver(): + osver = platform.release() + # Windows 以外の環境だと reportAttributeAccessIssue を報告されてしまうので ignore する + with winreg.OpenKeyEx( # type: ignore[reportAttributeAccessIssue] + winreg.HKEY_LOCAL_MACHINE, # type: ignore[reportAttributeAccessIssue] + "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + ) as key: + return osver + "." + winreg.QueryValueEx(key, "ReleaseId")[0] # type: ignore[reportAttributeAccessIssue] + + +def get_macos_osver(): + platform.mac_ver()[0] + + +def get_build_platform() -> PlatformTarget: + os = platform.system() + if os == "Windows": + os = "windows" + osver = get_windows_osver() + elif os == "Darwin": + os = "macos" + osver = get_macos_osver() + elif os == "Linux": + release = read_version_file("/etc/os-release") + os = release["NAME"] + if os == "Ubuntu": + os = "ubuntu" + osver = release["VERSION_ID"] + else: + raise Exception(f"OS {os} not supported") + pass + else: + raise Exception(f"OS {os} not supported") + + arch = platform.machine() + if arch in ("AMD64", "x86_64"): + arch = "x86_64" + elif arch in ("aarch64", "arm64"): + arch = "arm64" + else: + raise Exception(f"Arch {arch} not supported") + + return PlatformTarget(os, osver, arch) + + +def get_clang_version(clang): + version_str = cmdcap([clang, "--version"]) + + # version_str は以下のような文字列になっているので、ここからバージョンを取る + # + # clang version 16.0.0 (...) + # Target: x86_64-unknown-linux-gnu + # Thread model: posix + # InstalledDir: /path/to/clang/bin + # + # Android 版だと以下のような文字列になっている + # + # Android (8490178, based on r450784d) clang version 14.0.6 (...) + # Target: aarch64-unknown-linux-android29 + # Thread model: posix + # InstalledDir: /path/to/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin + + # clang version の次の文字列を取る + xs = version_str.split("\n")[0].split(" ") + for i in range(2, len(xs)): + if xs[i - 2] == "clang" and xs[i - 1] == "version": + return xs[i] + + raise Exception("Failed to get clang version") + + +def fix_clang_version(clang_dir, clang_version): + # /lib/clang//include または + # /lib64/clang//include が存在するか調べて、 + # 存在しない場合は clang_version を調節して、存在するバージョンに変換する + # + # /lib/clang/16.0.0/include になっている場合と + # /lib/clang/16/include になっている場合があるため + paths = [os.path.join(clang_dir, "lib", "clang"), os.path.join(clang_dir, "lib64", "clang")] + exists = any(map(lambda x: os.path.exists(os.path.join(x, clang_version, "include")), paths)) + if exists: + return clang_version + + fixed_clang_version = clang_version.split(".")[0] + exists = any( + map(lambda x: os.path.exists(os.path.join(x, fixed_clang_version, "include")), paths) + ) + if exists: + return fixed_clang_version + + raise Exception( + f"Failed to fix clang version: clang_dir={clang_dir} clang_version={clang_version}" + ) + + +class Platform(object): + def _check(self, flag): + if not flag: + raise Exception("Not supported") + + def _check_platform_target(self, p: PlatformTarget): + if p.os == "raspberry-pi-os": + self._check(p.arch in ("armv6", "armv7", "armv8")) + elif p.os == "jetson": + self._check(p.arch == "armv8") + elif p.os in ("ios", "android"): + self._check(p.arch is None) + else: + self._check(p.arch in ("x86_64", "arm64")) + + def __init__(self, target_os, target_osver, target_arch, extra=None): + build = get_build_platform() + target = PlatformTarget(target_os, target_osver, target_arch, extra) + + self._check_platform_target(build) + self._check_platform_target(target) + + if target.os == "windows": + self._check(target.arch == "x86_64") + self._check(build.os == "windows") + self._check(build.arch == "x86_64") + if target.os == "macos": + self._check(build.os == "macos") + self._check(build.arch in ("x86_64", "arm64")) + if target.os == "ios": + self._check(build.os == "macos") + self._check(build.arch in ("x86_64", "arm64")) + if target.os == "android": + self._check(build.os in ("ubuntu", "macos")) + if build.os == "ubuntu": + self._check(build.arch == "x86_64") + elif build.os == "macos": + self._check(build.arch in ("x86_64", "arm64")) + if target.os == "ubuntu": + self._check(build.os == "ubuntu") + self._check(build.arch == "x86_64") + self._check(build.osver == target.osver) + if target.os == "raspberry-pi-os": + self._check(build.os == "ubuntu") + self._check(build.arch == "x86_64") + if target.os == "jetson": + self._check(build.os == "ubuntu") + self._check(build.arch == "x86_64") + + self.build = build + self.target = target + + +def get_webrtc_platform(platform: Platform) -> str: + # WebRTC + if platform.target.os == "windows": + return f"windows_{platform.target.arch}" + elif platform.target.os == "macos": + return f"macos_{platform.target.arch}" + elif platform.target.os == "ios": + return "ios" + elif platform.target.os == "android": + return "android" + elif platform.target.os == "ubuntu": + return f"ubuntu-{platform.target.osver}_{platform.target.arch}" + elif platform.target.os == "raspberry-pi-os": + return f"raspberry-pi-os_{platform.target.arch}" + elif platform.target.os == "jetson": + return "ubuntu-20.04_armv8" + else: + raise Exception(f"Unknown platform {platform.target.os}") + + +# 内部で os.path.abspath() を利用しており、 os.path.abspath() はカレントディレクトリに依存するため、 +# この関数を利用する場合は ArgumentParser.parse_args() 実行前にカレントディレクトリを変更してはならない +# +# また、 --sora-args の指定には `--sora-args='--test'` のように `=` を使う必要がある +# `--sora-args '--test'` のようにスペースを使うと、ハイフンから始まるオプションが正しく解釈されない +def add_sora_arguments(parser): + parser.add_argument( + "--local-sora-cpp-sdk-dir", + type=os.path.abspath, + default=None, + help="Refer to local Sora C++ SDK. " + "When this option is specified, Sora C++ SDK will also be built.", + ) + parser.add_argument( + "--local-sora-cpp-sdk-args", + type=shlex.split, + default=[], + help="Options for building local Sora C++ SDK when `--local-sora-cpp-sdk-dir` is specified.", + ) + + +# add_sora_arguments と同様の注意点があるので注意すること +def add_webrtc_build_arguments(parser): + parser.add_argument( + "--local-webrtc-build-dir", + type=os.path.abspath, + default=None, + help="Refer to local webrtc-build. " + "When this option is specified, webrtc-build will also be built.", + ) + parser.add_argument( + "--local-webrtc-build-args", + type=shlex.split, + default=[], + help="Options for building local webrtc-build when `--local-webrtc-build-dir` is specified.", + ) diff --git a/cmake.ps1 b/cmake.ps1 deleted file mode 100644 index a57f09d1..00000000 --- a/cmake.ps1 +++ /dev/null @@ -1,41 +0,0 @@ -$ErrorActionPreference = 'Stop' - -$WEBRTC_VERSION_FILE = Join-Path (Resolve-Path ".").Path "build\windows_x86_64\_install\webrtc\VERSIONS" -Get-Content $WEBRTC_VERSION_FILE | Foreach-Object{ - if (!$_) { - continue - } - $var = $_.Split('=') - New-Variable -Name $var[0] -Value $var[1] -Force -} -$MOMO_VERSION_FILE = Join-Path (Resolve-Path ".").Path "VERSION" -Get-Content $MOMO_VERSION_FILE | Foreach-Object{ - if (!$_) { - continue - } - $var = $_.Split('=') - New-Variable -Name $var[0] -Value $var[1] -Force -} - -$MOMO_COMMIT = "$(git rev-parse HEAD)" - -$INSTALL_DIR = (Join-Path (Resolve-Path ".").Path "build\windows_x86_64\_install").Replace("\", "/") -$MODULE_PATH = (Join-Path (Resolve-Path ".").Path "cmake").Replace("\", "/") -$SDL_MODULE_PATH = (Join-Path (Resolve-Path ".").Path "build\windows_x86_64\_install\SDL2\cmake").Replace("\", "/") - -mkdir _build\windows_x86_64 -Force -ErrorAction Ignore -Push-Location _build\windows_x86_64 - cmake ..\.. -G "Visual Studio 16 2019" ` - -DMOMO_VERSION="$MOMO_VERSION" ` - -DMOMO_COMMIT="$MOMO_COMMIT" ` - -DWEBRTC_BUILD_VERSION="$WEBRTC_BUILD_VERSION" ` - -DWEBRTC_READABLE_VERSION="$WEBRTC_READABLE_VERSION" ` - -DWEBRTC_COMMIT="$WEBRTC_COMMIT" ` - -DWEBRTC_ROOT_DIR="$INSTALL_DIR/webrtc" ` - -DNVCODEC_ROOT_DIR="$INSTALL_DIR/Video_Codec_SDK" ` - -DJSON_ROOT_DIR="$INSTALL_DIR/json" ` - -DCLI11_ROOT_DIR="$INSTALL_DIR/CLI11" ` - -DCMAKE_MODULE_PATH="$MODULE_PATH;$SDL_MODULE_PATH" ` - -DCMAKE_PREFIX_PATH="$INSTALL_DIR/boost;$INSTALL_DIR/SDL2" - cmake --build . --config Release -Pop-Location \ No newline at end of file diff --git a/cmake/FindLIBVA.cmake b/cmake/FindLIBVA.cmake deleted file mode 100644 index 591a6551..00000000 --- a/cmake/FindLIBVA.cmake +++ /dev/null @@ -1,38 +0,0 @@ -find_package(PkgConfig) -pkg_check_modules(LIBDRM libdrm) -if(LIBDRM_FOUND) - if(NOT TARGET LIBDRM::LIBDRM) - add_library(LIBDRM::LIBDRM UNKNOWN IMPORTED) - - set_target_properties(LIBDRM::LIBDRM PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${LIBDRM_INCLUDE_DIRS}" - IMPORTED_LOCATION "${LIBDRM_LINK_LIBRARIES}") - endif() -endif() - -find_path(LIBVA_INCLUDE_DIR NAMES va/va.h PATHS "${LIBVA_ROOT_DIR}/include" NO_DEFAULT_PATH) -find_library(LIBVA_LIBRARY NAMES va PATHS "${LIBVA_ROOT_DIR}/lib" NO_DEFAULT_PATH) -find_library(LIBVA_DRM_LIBRARY NAMES va-drm PATHS "${LIBVA_ROOT_DIR}/lib" NO_DEFAULT_PATH) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(LIBVA DEFAULT_MSG LIBVA_LIBRARY LIBVA_DRM_LIBRARY LIBVA_INCLUDE_DIR) - -mark_as_advanced(LIBVA_INCLUDE_DIR LIBVA_LIBRARY LIBVA_DRM_LIBRARY) - -if(LIBVA_FOUND) - if(NOT TARGET LIBVA::LIBVA) - add_library(LIBVA::LIBVA UNKNOWN IMPORTED) - - set_target_properties(LIBVA::LIBVA PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${LIBVA_INCLUDE_DIR}" - IMPORTED_LOCATION "${LIBVA_LIBRARY}") - endif() - if(NOT TARGET LIBVA::LIBVA_DRM) - add_library(LIBVA::LIBVA_DRM UNKNOWN IMPORTED) - - target_link_libraries(LIBVA::LIBVA_DRM INTERFACE LIBDRM::LIBDRM) - set_target_properties(LIBVA::LIBVA_DRM PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${LIBVA_INCLUDE_DIR}" - IMPORTED_LOCATION "${LIBVA_DRM_LIBRARY}") - endif() -endif() \ No newline at end of file diff --git a/cmake/FindLibdrm.cmake b/cmake/FindLibdrm.cmake new file mode 100644 index 00000000..649441a1 --- /dev/null +++ b/cmake/FindLibdrm.cmake @@ -0,0 +1,12 @@ +find_package(PkgConfig) + +pkg_check_modules(Libdrm libdrm) +if(Libdrm_FOUND) + if(NOT TARGET Libdrm::drm) + add_library(Libdrm::drm UNKNOWN IMPORTED) + + set_target_properties(Libdrm::drm PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIRS}" + IMPORTED_LOCATION "${Libdrm_LINK_LIBRARIES}") + endif() +endif() diff --git a/cmake/FindLibva.cmake b/cmake/FindLibva.cmake new file mode 100644 index 00000000..872eb8f2 --- /dev/null +++ b/cmake/FindLibva.cmake @@ -0,0 +1,28 @@ +find_package(Libdrm REQUIRED) + +find_path(LIBVA_INCLUDE_DIR NAMES va/va.h) +find_library(LIBVA_LIBRARY NAMES va) +find_library(LIBVA_DRM_LIBRARY NAMES va-drm) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Libva DEFAULT_MSG LIBVA_INCLUDE_DIR LIBVA_LIBRARY LIBVA_DRM_LIBRARY) + +mark_as_advanced(LIBVA_INCLUDE_DIR LIBVA_LIBRARY LIBVA_DRM_LIBRARY) + +if(Libva_FOUND) + if(NOT TARGET Libva::va) + add_library(Libva::va UNKNOWN IMPORTED) + + set_target_properties(Libva::va PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${LIBVA_INCLUDE_DIR}" + IMPORTED_LOCATION "${LIBVA_LIBRARY}") + endif() + if(NOT TARGET Libva::va_drm) + add_library(Libva::va_drm UNKNOWN IMPORTED) + + target_link_libraries(Libva::va_drm INTERFACE Libdrm::drm) + set_target_properties(Libva::va_drm PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${LIBVA_INCLUDE_DIR}" + IMPORTED_LOCATION "${LIBVA_DRM_LIBRARY}") + endif() +endif() \ No newline at end of file diff --git a/cmake/FindMSDK.cmake b/cmake/FindMSDK.cmake deleted file mode 100644 index 43bcc1ce..00000000 --- a/cmake/FindMSDK.cmake +++ /dev/null @@ -1,20 +0,0 @@ -find_package(LIBVA REQUIRED) - -find_path(MSDK_INCLUDE_DIR NAMES mfx/mfxenc.h PATHS "${MSDK_ROOT_DIR}/include" NO_DEFAULT_PATH) -find_library(MSDK_LIBRARY NAMES mfx PATHS "${MSDK_ROOT_DIR}/lib" NO_DEFAULT_PATH) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(MSDK DEFAULT_MSG MSDK_LIBRARY MSDK_INCLUDE_DIR) - -mark_as_advanced(MSDK_INCLUDE_DIR MSDK_LIBRARY) - -if(MSDK_FOUND) - if(NOT TARGET MSDK::MSDK) - add_library(MSDK::MSDK UNKNOWN IMPORTED) - - target_link_libraries(MSDK::MSDK INTERFACE LIBVA::LIBVA LIBVA::LIBVA_DRM) - set_target_properties(MSDK::MSDK PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${MSDK_INCLUDE_DIR}" - IMPORTED_LOCATION "${MSDK_LIBRARY}") - endif() -endif() \ No newline at end of file diff --git a/doc/BUILD.md b/doc/BUILD.md new file mode 100644 index 00000000..9f5c8a02 --- /dev/null +++ b/doc/BUILD.md @@ -0,0 +1,81 @@ +# Momo をビルドする + +まずは Momo のリポジトリをダウンロードします。 + +```bash +git clone https://github.com/shiguredo/momo.git +``` + +## 事前準備 (Windows) + +Windows 向けの Momo をビルドするには、以下の OS とアプリケーションが必要になります。 + +- 最新バージョンの Windows +- [Visual Studio 2022](https://visualstudio.microsoft.com/ja/downloads/) (どのエディションでも化) + - C++ に関するコンポーネントを入れておいて下さい。特に MSVC, MSBuild は必須です。 +- [Python](https://www.python.org/downloads/) + - 最新バージョンをインストールして下さい。 + +## 事前準備 (macOS) + +macOS 向けの Momo をビルドするには、以下の OS とアプリケーションが必要になります。 + +- 最新バージョンの macOS +- Xcode + +Xcode に関しては、最低1回は単体で起動してライセンスに同意しておく必要があります。 + +## 事前準備 (Ubuntu) + +Ubuntu、Raspberry OS、Jetson 向けの Momo をビルドするには、以下の OS が必要になります。 + +- Ubuntu 22.04 LTS + +また、CUDA や Clang など、追加でいくつかのパッケージを入れておく必要があります。 + +必要なパッケージの詳細は [build.yml](../.github/workflows/build.yml) を参照してください。 + +## ビルドする + +`python3 run.py ` というコマンドで、各ターゲット向けの Momo を生成できます。 + +```bash +# このコマンドは Windows 上でしか動作しません。 +# また、コマンドプロンプトや PowerShell 上で実行して下さい。 +# Git Bash や Cygwin などのシェル上では動作しません。 +python3 run.py windows_x86_64 + +# このコマンドは macOS 上でしか動作しません +python3 run.py macos_arm64 + +# このコマンドは Ubuntu 上でしか動作しません +python3 run.py raspberry-pi-os_armv8 +python3 run.py ubuntu-22.04_x86_64 +python3 run.py ubuntu-22.04_jetson +``` + +生成された Momo の実行バイナリは `_build//release/momo` ディレクトリにあります。 + +## パッケージを作成する + +ビルド時に `--package` オプションを指定することで、各ターゲット向けのパッケージを生成できます。 + +```bash +# windows_x86_64 の部分はビルドするターゲットに合わせて変更してください。 +python3 run.py windows_x86_64 --package +``` + +生成されたパッケージは `_package//release` ディレクトリに `momo-2023.1.0_raspberry-pi-os_armv8.tar.gz` のような名前で保存されています。 + +## パッケージ解凍後の構成 + +```console +$ tree +momo +├── LICENSE +├── NOTICE +├── html +│ ├── test.html +│ └── webrtc.js +└── momo +``` diff --git a/doc/BUILD_LINUX.md b/doc/BUILD_LINUX.md deleted file mode 100644 index d3a35d13..00000000 --- a/doc/BUILD_LINUX.md +++ /dev/null @@ -1,78 +0,0 @@ -# Linux 版 Momo をビルドする - -まずは momo のリポジトリをダウンロードします。 - -```shell -$ git clone git@github.com:shiguredo/momo.git -``` - -## 環境について - -## Docker の利用について - -Linux 版 Momo をビルドする際には Docker 19.03 以降が必要になりますので、事前にインストールしておいてください。 - -Docker for Windows や Arm 上でのビルドは未検証です。 **Linux x86_64 版、または Docker for Mac をご利用ください** 。 - -また、./build.sh 実行時に --no-mount オプションを指定することで、 -マウントを利用しないモードで docker container を動作させることができます。何らかの理由でマウントがうまく動作しない場合に使って下さい。 - -## Raspberry Pi OS 32bit (armv6) 向けバイナリを作成する - -build ディレクトリ以下で ./build.sh raspberry-pi-os_armv6 と打つことで Momo の Raspberry Pi OS armv6 向けバイナリが生成されます。 - -```shell -$ ./build.sh raspberry-pi-os_armv6 -``` - -うまくいかない場合は `./build.sh --clean raspberry-pi-os_armv6 && ./build.sh raspberry-pi-os_armv6` を試してみてください。 - -## Raspberry Pi OS 32bit (armv7) 向けバイナリを作成する - -build ディレクトリ以下で ./build.sh raspberry-pi-os_armv7 と打つことで Momo の Raspberry-Pi-OS armv7 向けバイナリが生成されます。 - -```shell -$ ./build.sh raspberry-pi-os_armv7 -``` - -うまくいかない場合は `./build.sh --clean raspberry-pi-os_armv7 && ./build.sh raspberry-pi-os_armv7` を試してみてください。 - -## Raspberry Pi OS 64bit (armv8) 向けバイナリを作成する - -build ディレクトリ以下で ./build.sh raspberry-pi-os_armv8 と打つことで Momo の Raspberry Pi OS armv8 向けバイナリが生成されます。 - -```shell -$ ./build.sh raspberry-pi-os_armv8 -``` - -うまくいかない場合は `./build.sh --clean raspberry-pi-os_armv8 && ./build.sh raspberry-pi-os_armv8` を試してみてください。 - -## Ubuntu 20.04 (armv8) Jetson Xavier NX / AGX 向けバイナリを作成する - -build ディレクトリ以下で ./build.sh ubuntu-20.04_armv8_jetson_xavier と打つことで Momo の Ubuntu 20.04 armv8 Jetson Xavier NX / AGX 向けバイナリが生成されます。 - -```shell -$ ./build.sh ubuntu-20.04_armv8_jetson_xavier -``` - -うまくいかない場合は `./build.sh --clean ubuntu-20.04_armv8_jetson_xavier && ./build.sh ubuntu-20.04_armv8_jetson_xavier` を試してみてください。 - -## Ubuntu 20.04 (x86_64) 向けバイナリを作成する - -build ディレクトリ以下で ./build.sh ubuntu-20.04_x86_64 と打つことで Momo の Ubuntu 20.04 (x86_64) 向けバイナリが生成されます。 - -```shell -$ ./build.sh ubuntu-20.04_x86_64 -``` - -うまくいかない場合は `./build.sh --clean ubuntu-20.04_x86_64 && ./build.sh ubuntu-20.04_x86_64` を試してみてください。 - -## Ubuntu 22.04 (x86_64) 向けバイナリを作成する - -build ディレクトリ以下で ./build.sh ubuntu-22.04_x86_64 と打つことで Momo の Ubuntu 22.04 (x86_64) 向けバイナリが生成されます。 - -```shell -$ ./build.sh ubuntu-22.04_x86_64 -``` - -うまくいかない場合は `./build.sh --clean ubuntu-22.04_x86_64 && ./build.sh ubuntu-22.04_x86_64` を試してみてください。 \ No newline at end of file diff --git a/doc/BUILD_LINUX_LOCAL.md b/doc/BUILD_LINUX_LOCAL.md deleted file mode 100644 index a28ec0e9..00000000 --- a/doc/BUILD_LINUX_LOCAL.md +++ /dev/null @@ -1,394 +0,0 @@ -# Linux 版 Momo をローカルでビルドする - -Momo や WebRTC をいろいろと弄って試すために、Linux のローカルで手動ビルドしたい人向けの内容です。 - -Docker を使って簡単にビルドする方法については [Linux 版 Momo をビルドする](BUILD_LINUX.md) を参照してください。 - -## WebRTC をカスタマイズしない場合 - -WebRTC 本体をカスタマイズ(パッチを当てたりなど)をしない場合、[shiguredo-webrtc-build/webrtc-build](https://github.com/shiguredo-webrtc-build/webrtc-build) にある事前にビルドされた WebRTC を利用できるので、環境構築にそこまで時間が掛かりません - -この場合は Dockerfile でやっていた内容をローカルに構築するだけになります。 -例えば Ubuntu 20.04 で x86_64 向けのビルドを行う場合は [build/ubuntu-20.04_x86_64/Dockerfile](/build/ubuntu-20.04_x86_64/Dockerfile) を参照して構築スクリプトを記述していきます。 - -また、CMake での構築は `MOMO_PACKAGE_NAME` が利用できないので、それぞれの設定を自分の手で設定する必要があります。 - -以下は参考用の構築スクリプトになります。 - -このスクリプトは Ubuntu 20.04 で x86_64 向けの Momo バイナリを生成します。 - -`build/local/install_deps_local.sh`: - -```bash -#!/bin/bash - -cd "`dirname $0`" - -set -ex - -SOURCE_DIR="`pwd`/_source" -BUILD_DIR="`pwd`/_build" -INSTALL_DIR="`pwd`/_install" - -mkdir -p $SOURCE_DIR -mkdir -p $BUILD_DIR -mkdir -p $INSTALL_DIR - -source ../../VERSION - -if [ -z "$JOBS" ]; then - JOBS=`nproc` - if [ -z "$JOBS" ]; then - JOBS=1 - fi -fi - -# CLI11 -if [ ! -e $INSTALL_DIR/CLI11/include/CLI/Version.hpp ]; then - pushd $INSTALL_DIR - rm -rf CLI11 - git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git - popd -fi - -# nlohmann/json -if [ ! -e $INSTALL_DIR/json/include/nlohmann/json.hpp ]; then - pushd $INSTALL_DIR - rm -rf json - git clone --branch v$JSON_VERSION --depth 1 https://github.com/nlohmann/json.git - popd -fi - -# WebRTC -if [ ! -e $INSTALL_DIR/webrtc/lib/libwebrtc.a ]; then - rm -rf $INSTALL_DIR/webrtc - ../../script/get_webrtc.sh $WEBRTC_BUILD_VERSION ubuntu-20.04_x86_64 $INSTALL_DIR $SOURCE_DIR -fi - -# LLVM -if [ ! -e $INSTALL_DIR/llvm/clang/bin/clang++ ]; then - rm -rf $INSTALL_DIR/llvm - ../../script/get_llvm.sh $INSTALL_DIR/webrtc $INSTALL_DIR -fi - -# Boost -if [ ! -e $INSTALL_DIR/boost/lib/libboost_filesystem.a ]; then - rm -rf $SOURCE_DIR/boost - rm -rf $BUILD_DIR/boost - rm -rf $INSTALL_DIR/boost - mkdir -p $SOURCE_DIR/boost - ../../script/setup_boost.sh $BOOST_VERSION $SOURCE_DIR/boost - pushd $SOURCE_DIR/boost/source - echo "using clang : : $INSTALL_DIR/llvm/clang/bin/clang++ : ;" > project-config.jam - ./b2 \ - cxxstd=17 \ - cxxflags=" \ - -D_LIBCPP_ABI_UNSTABLE \ - -nostdinc++ \ - -isystem$INSTALL_DIR/llvm/libcxx/include \ - " \ - toolset=clang \ - visibility=global \ - target-os=linux \ - address-model=64 \ - link=static \ - variant=release \ - install \ - -j$JOBS \ - --build-dir=$BUILD_DIR/boost \ - --prefix=$INSTALL_DIR/boost \ - --ignore-site-config \ - --with-filesystem - popd -fi - -# SDL2 -if [ ! -e $INSTALL_DIR/SDL2/lib/libSDL2.a ]; then - rm -rf $SOURCE_DIR/SDL2 - rm -rf $BUILD_DIR/SDL2 - rm -rf $INSTALL_DIR/SDL2 - mkdir -p $SOURCE_DIR/SDL2 - mkdir -p $BUILD_DIR/SDL2 - ../../script/setup_sdl2.sh $SDL2_VERSION $SOURCE_DIR/SDL2 - pushd $BUILD_DIR/SDL2 - CC=$INSTALL_DIR/llvm/clang/bin/clang \ - CXX=$INSTALL_DIR/llvm/clang/bin/clang++ \ - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/SDL2 \ - $SOURCE_DIR/SDL2/source - - cmake --build . -j$JOBS - cmake --build . --target install - popd -fi -``` - -`build/build_local.sh`: - -```bash -#!/bin/bash - -cd "`dirname $0`" - -INSTALL_DIR="`pwd`/local/_install" - -./local/install_deps_local.sh - -source ../VERSION - -if [ -z "$JOBS" ]; then - JOBS=`nproc` - if [ -z "$JOBS" ]; then - JOBS=1 - fi -fi - -mkdir -p ../_build/local -pushd ../_build/local - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DMOMO_VERSION="$MOMO_VERSION" \ - -DMOMO_COMMIT="$MOMO_COMMIT" \ - -DWEBRTC_BUILD_VERSION="$WEBRTC_BUILD_VERSION" \ - -DWEBRTC_READABLE_VERSION="$WEBRTC_READABLE_VERSION" \ - -DWEBRTC_COMMIT="$WEBRTC_COMMIT" \ - -DTARGET_OS="linux" \ - -DTARGET_OS_LINUX="ubuntu-20.04" \ - -DTARGET_ARCH="x86_64" \ - -DUSE_SDL2=ON \ - -DBOOST_ROOT_DIR=$INSTALL_DIR/boost \ - -DJSON_ROOT_DIR=$INSTALL_DIR/json \ - -DCLI11_ROOT_DIR=$INSTALL_DIR/CLI11 \ - -DSDL2_ROOT_DIR=$INSTALL_DIR/SDL2 \ - -DWEBRTC_INCLUDE_DIR=$INSTALL_DIR/webrtc/include \ - -DWEBRTC_LIBRARY_DIR=$INSTALL_DIR/webrtc/lib \ - -DCLANG_ROOT=$INSTALL_DIR/llvm/clang \ - -DUSE_LIBCXX=ON \ - -DLIBCXX_INCLUDE_DIR=$INSTALL_DIR/llvm/libcxx/include \ - ../.. - - cmake --build . -j$JOBS -popd -``` - -`./build/build_local.sh` を実行すると、WebRTC, Boost, SDL といった依存ライブラリを `build/local/_install` 以下にインストールし、`_build/local` に momo バイナリを生成します。 - -注意点として、Momo のバージョンが上がるにつれて依存ライブラリや引数が増えていきますが、このスクリプトが更新されていない可能性があります。 -その場合には Dockerfile や [CMakeLists.txt](/CMakeLists.txt) を参照してうまく動かして下さい。 - -## WebRTC をカスタマイズする場合 - -WebRTC をカスタマイズする場合、自前で WebRTC をビルドし、それを利用する必要があります。 -そのため時間も掛かるし、ビルドの難易度も上がります。 - -ビルド環境やターゲットによってやり方が変わってくるので、リファレンスだけ示します。 - -- [Chromium のビルド方法](https://www.chromium.org/developers/how-tos/get-the-code) -- [shiguredo-webrtc-build/webrtc-build](https://github.com/shiguredo-webrtc-build/webrtc-build) リポジトリのビルドスクリプト -- shiguredo/momo の [build ディレクトリ](/build) 以下にある Dockerfile -- WebRTC をカスタマイズしない場合の参考用スクリプト - -参考用に、Ubuntu 20.04 の x86_64 環境で WebRTC をローカルでビルドして Momo をビルドするスクリプトを以下に載せています。 -ビルド環境やターゲットに合わせて変更してみて下さい。 - -`build/local_webrtc/install_deps_local_webrtc.sh`: - -```bash -#!/bin/bash - -cd "`dirname $0`" - -SOURCE_DIR="`pwd`/_source" -BUILD_DIR="`pwd`/_build" -INSTALL_DIR="`pwd`/_install" - -set -ex - -mkdir -p $SOURCE_DIR -mkdir -p $BUILD_DIR -mkdir -p $INSTALL_DIR - -source ../../VERSION - -if [ -z "$JOBS" ]; then - JOBS=`nproc` - if [ -z "$JOBS" ]; then - JOBS=1 - fi -fi - -# depot_tools 取得 -pushd $SOURCE_DIR - if [ -e depot_tools/.git ]; then - pushd depot_tools - git fetch - git checkout -f origin/HEAD - popd - else - git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git - fi -popd - -export PATH="$SOURCE_DIR/depot_tools:$PATH" - - -# WebRTC のソースを取得 -mkdir -p $SOURCE_DIR/webrtc - -pushd $SOURCE_DIR/webrtc - gclient - - if [ ! -e src ]; then - fetch webrtc - - # 依存ライブラリの取得 - bash ./src/build/install-build-deps.sh --no-arm --no-chromeos-fonts - fi -popd - -# WebRTC のビルド -pushd $SOURCE_DIR/webrtc/src - if [ ! -e $BUILD_DIR/webrtc ]; then - gn gen $BUILD_DIR/webrtc --args=' - target_os="linux" - is_debug=false - rtc_include_tests=false - rtc_use_h264=false - is_component_build=false - use_rtti=true - ' - fi - ninja -C $BUILD_DIR/webrtc -popd - -# ar で .o ファイルを固める -pushd $BUILD_DIR/webrtc/obj - mkdir -p $INSTALL_DIR/webrtc/lib - $SOURCE_DIR/webrtc/src/third_party/llvm-build/Release+Asserts/bin/llvm-ar -rc $INSTALL_DIR/webrtc/lib/libwebrtc.a `find . -name '*.o'` -popd - -# CLI11 -if [ ! -e $INSTALL_DIR/CLI11/include/CLI/Version.hpp ]; then - pushd $INSTALL_DIR - rm -rf CLI11 - git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git - popd -fi - -# nlohmann/json -if [ ! -e $INSTALL_DIR/json/include/nlohmann/json.hpp ]; then - pushd $INSTALL_DIR - rm -rf json - git clone --branch v$JSON_VERSION --depth 1 https://github.com/nlohmann/json.git - popd -fi - -# Boost -if [ ! -e $INSTALL_DIR/boost/lib/libboost_filesystem.a ]; then - rm -rf $SOURCE_DIR/boost - rm -rf $BUILD_DIR/boost - rm -rf $INSTALL_DIR/boost - mkdir -p $SOURCE_DIR/boost - ../../script/setup_boost.sh $BOOST_VERSION $SOURCE_DIR/boost - pushd $SOURCE_DIR/boost/source - echo "using clang : : $SOURCE_DIR/webrtc/src/third_party/llvm-build/Release+Asserts/bin/clang++ : ;" > project-config.jam - ./b2 \ - cxxstd=17 \ - cxxflags=" \ - -D_LIBCPP_ABI_UNSTABLE \ - -nostdinc++ \ - -isystem$SOURCE_DIR/webrtc/src/buildtools/third_party/libc++/trunk/include \ - " \ - toolset=clang \ - visibility=global \ - target-os=linux \ - address-model=64 \ - link=static \ - variant=release \ - install \ - -j$JOBS \ - --build-dir=$BUILD_DIR/boost \ - --prefix=$INSTALL_DIR/boost \ - --ignore-site-config \ - --with-filesystem - popd -fi - -# SDL2 -if [ ! -e $INSTALL_DIR/SDL2/lib/libSDL2.a ]; then - rm -rf $SOURCE_DIR/SDL2 - rm -rf $BUILD_DIR/SDL2 - rm -rf $INSTALL_DIR/SDL2 - mkdir -p $SOURCE_DIR/SDL2 - mkdir -p $BUILD_DIR/SDL2 - ../../script/setup_sdl2.sh $SDL2_VERSION $SOURCE_DIR/SDL2 - pushd $BUILD_DIR/SDL2 - CC=$SOURCE_DIR/webrtc/src/third_party/llvm-build/Release+Asserts/bin/clang \ - CXX=$SOURCE_DIR/webrtc/src/third_party/llvm-build/Release+Asserts/bin/clang++ \ - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_SHARED_LIBS=OFF \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/SDL2 \ - $SOURCE_DIR/SDL2/source - - cmake --build . -j$JOBS - cmake --build . --target install - popd -fi -``` - -`build/build_local_webrtc.sh`: - -```bash -#!/bin/bash - -cd "`dirname $0`" - -INSTALL_DIR="`pwd`/local_webrtc/_install" -SOURCE_DIR="`pwd`/local_webrtc/_source" - -./local_webrtc/install_deps_local_webrtc.sh - -source ../VERSION - -if [ -z "$JOBS" ]; then - JOBS=`nproc` - if [ -z "$JOBS" ]; then - JOBS=1 - fi -fi - -mkdir -p ../_build/local_webrtc -pushd ../_build/local_webrtc - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DMOMO_VERSION="$MOMO_VERSION" \ - -DMOMO_COMMIT="$MOMO_COMMIT" \ - -DWEBRTC_BUILD_VERSION="$WEBRTC_BUILD_VERSION" \ - -DWEBRTC_READABLE_VERSION="$WEBRTC_READABLE_VERSION" \ - -DWEBRTC_COMMIT="$WEBRTC_COMMIT" \ - -DTARGET_OS="linux" \ - -DTARGET_OS_LINUX="ubuntu-20.04" \ - -DTARGET_ARCH="x86_64" \ - -DUSE_SDL2=ON \ - -DBOOST_ROOT_DIR=$INSTALL_DIR/boost \ - -DJSON_ROOT_DIR=$INSTALL_DIR/json \ - -DCLI11_ROOT_DIR=$INSTALL_DIR/CLI11 \ - -DSDL2_ROOT_DIR=$INSTALL_DIR/SDL2 \ - -DWEBRTC_INCLUDE_DIR=$SOURCE_DIR/webrtc/src \ - -DWEBRTC_LIBRARY_DIR=$INSTALL_DIR/webrtc/lib \ - -DCLANG_ROOT=$SOURCE_DIR/webrtc/src/third_party/llvm-build/Release+Asserts \ - -DUSE_LIBCXX=ON \ - -DLIBCXX_INCLUDE_DIR=$SOURCE_DIR/webrtc/src/buildtools/third_party/libc++/trunk/include \ - ../.. - - cmake --build . -j$JOBS -popd -``` - -これで `./build/build_local_webrtc.sh` を実行すれば、`./build/local_webrtc/_source/webrtc` 以下に WebRTC のソースが、`./build/local_webrtc/_install` 以下に各ライブラリがインストールされます。 -また、WebRTC のソースを書き換えると、WebRTC のビルドを実行した上で Momo のビルドが行われます。 - -初回のソース取得時は `bash ./src/build/install-build-deps.sh` によって `sudo apt-get install` が走るので注意して下さい。 diff --git a/doc/BUILD_MACOS.md b/doc/BUILD_MACOS.md deleted file mode 100644 index a01db7ee..00000000 --- a/doc/BUILD_MACOS.md +++ /dev/null @@ -1,63 +0,0 @@ -# macOS 版 Momo をビルドする - -まずは Momo のリポジトリをダウンロードします。 - -```shell -$ git clone git@github.com:shiguredo/momo.git -``` - -## macOS 12 - -### 事前確認 - -Momo をビルドするためには、Xcode をインストールし、最低1回は起動してライセンスに同意しておく必要があります。 -現時点では、開発ツールのスタンドアローンインストール(`/Library/Developer/CommandLineTools` にインストールされるもの)はサポートされていません。 -詳細は、次のリンク先をご覧ください。 - -https://bugs.chromium.org/p/chromium/issues/detail?id=729990#c1 - -開発マシンがどちらを使っているかは xcode-select --print-path で確かめることができます。 -Xcode のものが利用されている場合は、次のような出力になります。 - -```shell -$ xcode-select --print-path -/Applications/Xcode.app/Contents/Developer -``` - -ここでは AppStore から Xcode をインストールしたケースを想定しています。 -もし Xcode の beta 版をインストールしている場合は、`/Applications/Xcode.app` の部分を適宜読み替えてください。 - -スタンドアローンインストールされたものが利用されている場合は、次のような出力になります。 - -```shell -$ xcode-select --print-path -/Library/Developer/CommandLineTools -``` - -この場合、次のコマンドを入力し、ビルド前に使用される CLI のパスを切り替えてください。 - -```shell -$ sudo xcode-select -s /Applications/Xcode.app -``` - -### CMake - -ビルドには CMake 3.16 以上が必要になります。 - -Homebrew が入っている場合は `brew install cmake` するか、あるいは公式サイトからダウンロードして PATH を通しておいてください。 - -### ビルド方法 - -build ディレクトリ以下で ./build.sh macos_arm64 と打つことで Momo の macOS 向けバイナリが生成されます。 - -```shell -$ ./build.sh macos_arm64 -``` - -## 中間ファイルのクリーンアップ - -ビルド中にできた中間ファイルを削除するには、次のようにターゲットを指定して ./build.sh --clean macos_arm64 を実行することでクリーンアップできます。 - -```shell -$ ./build.sh --clean macos_arm64 -``` diff --git a/doc/BUILD_WINDOWS.md b/doc/BUILD_WINDOWS.md deleted file mode 100644 index a9c3c310..00000000 --- a/doc/BUILD_WINDOWS.md +++ /dev/null @@ -1,36 +0,0 @@ -# Windows 版 Momo をビルドする - -まずは Momo のリポジトリをダウンロードします。 - -```shell -$ git clone git@github.com:shiguredo/momo.git -``` - -### 事前準備 - -ビルドには以下のアプリケーションが必要になります。 - -- [Visual Studio 2019](https://visualstudio.microsoft.com/ja/downloads/) (どのエディションでも化) - - C++ に関するコンポーネントを入れておいて下さい。特に MSVC, MSBuild は必須です。 -- [CMake](https://cmake.org/download/) - - バージョン 3.24.1 以上をインストールして下さい。 -- [7zip](https://www.7-zip.org/) - - 最新バージョンをインストールしてパスを通しておいて下さい。 - -### ビルド方法 - -build ディレクトリにある ./build.bat を起動することで Momo の Windows 向けバイナリが生成されます。 - -``` -.\build.bat -``` - -生成されたバイナリは `_build\windows\Release\momo.exe` にあります。 - -### 中間ファイルのクリーンアップ - -ビルド中にできた中間ファイルを削除するには、次のように -clean 引数を指定することでクリーンアップできます。 - -```shell -.\build.bat -clean -``` diff --git a/doc/BUY_JETSON.md b/doc/BUY_JETSON.md index 12e15cc5..fbef7d50 100644 --- a/doc/BUY_JETSON.md +++ b/doc/BUY_JETSON.md @@ -2,22 +2,20 @@ NVIDIA Jetson を購入する場合のオススメリンクです。 -## Momo の Jetson シリーズへの対応について +## Momo の NVIDIA Jetson シリーズへの対応について -- Jetpack 5 系のみの対応とします。 -- Jetpack 4 系への対応を終了しました。 - - 上記に伴い Jetpack 4 系のみに対応している Jetson Nano の対応を終了しました。 +- Jetpack 6 系のみの対応とします +- Jetpack 5 と 4 系への対応を終了しました + - 優先実装にて対応できます - ハードウェアエンコードに対応しない Jetson Orin Nano への対応は行いません -- Jetson Orin NX への対応は優先実装とします。 - - Xavier と同じパターンだと Jetson Orin Nano より JPEG のハードウェア処理が劣る可能性があるため ## Jetson AGX Orin **以下で買われることをオススメします** -- [NVIDIA Jetson AGX Orin 開発者キット 商品・個数選択](https://ryoyo-direct.jp/shopping/jetson-orin/jetson-orin) +[NVIDIA JETSON AGX ORIN 64GB 開発者キット 商品・個数選択](https://ryoyo-direct.jp/shopping/jetson-orin/jetson-orin64) -## 4K@30 出るカメラを購入する +## 4K@30 のカメラを購入する 実際に Jetson で検証して 4K で 30fps の出力動作確認が取れているカメラです。 @@ -25,9 +23,9 @@ NVIDIA Jetson を購入する場合のオススメリンクです。 以下は上のタイプのケースありやレンズが色々選べるタイプです。 -- https://ja.aliexpress.com/item/33013268769.html -- https://ja.aliexpress.com/item/33016603918.html -- https://ja.aliexpress.com/item/33012473257.html +- +- +- 色々 4K で 30fps が出せるカメラを試してきましたが、このカメラが一番安定しています。 @@ -35,10 +33,9 @@ NVIDIA Jetson を購入する場合のオススメリンクです。 [4K webcam について \- Qiita](https://qiita.com/tetsu_koba/items/8b4921f257a46a15d2a7) - ## Jetson 関連リンク - Jetson ロードマップ - - [Jetson Roadmap \| NVIDIA Developer](https://developer.nvidia.com/embedded/develop/roadmap) + - [Jetson Roadmap \| NVIDIA Developer](https://developer.nvidia.com/embedded/develop/roadmap) - Jetson ライフサイクル - - [Jetson Product Lifecycle \| NVIDIA Developer](https://developer.nvidia.com/embedded/lifecycle) + - [Jetson Product Lifecycle \| NVIDIA Developer](https://developer.nvidia.com/embedded/lifecycle) diff --git a/doc/FAQ.md b/doc/FAQ.md index b3b13f24..fbc44c49 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -1,51 +1,51 @@ # FAQ -## 商用利用は可能ですか? +## 商用利用はできますか? Momo のライセンスは [Apache License, Version 2\.0](http://www.apache.org/licenses/LICENSE-2.0) で公開しております。 ## コーデックの指定やビットレートを利用できますか? -Momo 側からの指定は WebRTC SFU Sora を利用したときだけ可能です。 +Momo 側からの指定は WebRTC SFU Sora を利用したときだけ利用できます。 ## サイマルキャストは利用できますか? -Sora モードでのみ利用可能です。利用可能な映像コーデックは VP8 と H.264 です。 +Sora モードでのみ利用できます。利用できる映像コーデックは VP8 / VP9 / AV1 / H.264 / H.265 です。 利用する場合は `--simulcast` を指定してください。 ## AV1 は利用できますか? -利用可能です。 +利用できます。 ## データチャネルは利用できますか? -シリアル経由でのみデータチャネルが利用可能です。 +シリアル経由でのみデータチャネルが利用できます。 [USE_SERIAL.md](USE_SERIAL.md) ## 認証局の証明書を追加できますか? -`SSL_CERT_DIR` または `SSL_CERT_FILE` 環境変数に CA 証明書のパスを指定することで、サーバ証明書の検証に利用するための CA 証明書を追加することが可能です。 +`SSL_CERT_DIR` または `SSL_CERT_FILE` 環境変数に CA 証明書のパスを指定することで、サーバ証明書の検証に利用するための CA 証明書を追加することができます。 -``` -$ export SSL_CERT_FILE=/path/to/cert.pem -$ ./momo sora ... +```bash +export SSL_CERT_FILE=/path/to/cert.pem +./momo sora ... ``` ## サーバ証明書を無視できますか? -`--insecure` オプションを指定することで、クライアント側でサーバ証明書の検証を行わないようにすることが可能です。 +`--insecure` オプションを指定することで、クライアント側でサーバ証明書の検証を行わないようにすることができます。 -``` -$ ./momo --insecure sora ... +```bash +./momo --insecure sora ... ``` ## NVIDIA ビデオカードに搭載されている NVENC を利用できますか? -Windows と Linux で利用可能です。 +Windows と Ubuntu で利用できます。 NVIDIA ビデオカードドライバーは最新版にしてください。 -NVENC が利用可能なビデオカードは以下で確認してください。 +NVENC が利用できるビデオカードは以下で確認してください。 [Video Encode and Decode GPU Support Matrix \| NVIDIA Developer](https://developer.nvidia.com/video-encode-decode-gpu-support-matrix#Encoder) @@ -71,6 +71,8 @@ NVENC が利用可能なビデオカードは以下で確認してください - @msnoigrs - GeForce RTX 2080 - @shirokunet +- GeForce RTX 3080 + - @torikizi ## 4K カメラのオススメはありますか? @@ -122,7 +124,7 @@ Mac (arm64) から FHD でスクリーンキャプチャを配信したい場合 ## Windows で H.264 を利用できますか? -NVIDIA のビデオカードの NVENC を利用することで H.264 が利用可能になります。 +NVIDIA のビデオカードの NVENC を利用することで H.264 が利用できるようになります。 ご利用の環境で H.264 が利用できるかどうかは `./momo --video-codec-engines` を使用して H264 の項目をご確認ください。 ## Sora モードを利用するときに Sora の TURN 機能を無効にして利用することはできますか? @@ -135,20 +137,20 @@ Momo の Sora モードではマルチストリーム機能を無効にして利 ## Proxy を設定して利用することはできますか? -以下に示すオプションを指定することで利用可能です。 +以下に示すオプションを指定することで利用できます。 - `--proxy-url` : プロキシの URL - - 例) http://proxy.example.com:3128 + - 例: - `--proxy-username` : プロキシ認証に使用するユーザー名 - `--proxy-password` : プロキシ認証に使用するパスワード ## Raspberry Pi (Raspberry-Pi-OS) 64 bit で H.264 を利用できますか? -Release 2023.1.0 以降から利用可能です。 +Release 2023.1.0 以降から利用できます。 ## Momo のオプションで指定した解像度で映像の送信はできますか? -`--resolution` オプションを使用することで解像度の設定が可能です。 +`--resolution` オプションを使用することで解像度の設定ができます。 しかしこれはあくまでも Momo からカメラデバイスに対して送るリクエストであり、最終的な解像度はカメラデバイスの仕様に依存します。 @@ -172,10 +174,14 @@ Jetson Orin 以外の Jetson をご利用の場合は `--av1-decoder` オプシ ## Raspberry Pi カメラモジュール V3 は利用できますか? -Release 2023.1.0 以降から利用可能です。 +Release 2023.1.0 以降から利用できます。 ## 利用できる JetPack のバージョンはいくつですか? -JetPack 5.1.1 のみで利用可能です。 +JetPack 5.1.1 のみで利用できます。 JetPack 5.1.1 以外のバージョンでは利用できません。 + +## Momo は Sora C++ SDK や Sora C SDK をベースにしないのですか? + +現在はその予定はありません。 diff --git a/doc/INTEL_MEDIA_SDK.md b/doc/INTEL_MEDIA_SDK.md deleted file mode 100644 index cfacc5bb..00000000 --- a/doc/INTEL_MEDIA_SDK.md +++ /dev/null @@ -1,139 +0,0 @@ -# Momo で Intel Media SDK を利用したハードウェアエンコーダー / デコーダーを利用する - -Intel Media SDK を利用して Intel Quick Sync Video の HWA 機能を使った Momo で HWA を利用することが可能になります。 - -このドキュメントでは Intel Media SDK を使用するためのセットアップ方法を記載します。 - -## Intel Media SDK について - -Intel Media SDK の詳細については以下のリンクをご確認ください。 - -- デコーダーとエンコーダーの対応しているコーデックとチップセットの組み合わせ表 - - https://github.com/intel/media-driver#decodingencoding-features -- Intel Media SDK の Github - - https://github.com/Intel-Media-SDK/MediaSDK#intel-media-sdk -- Intel 公式ドキュメント - - https://www.intel.com/content/www/us/en/developer/tools/media-sdk/documentation.html - -## 対応プラットフォーム - -- Windows 10 x86_64 -- Ubuntu 20.04 x86_64 -- Ubuntu 22.04 x86_64 - -## Windows 10 での利用方法 - -### ドライバーのインストール - -Windows 10 ではインストール作業は必要ありません。 - -## Intel Media SDK が認識できているか確認 - -Momo を `--video-codec-engines` オプションを指定して実行することで利用可能なエンコーダーとデコーダー一覧が出力されます。 `Encoder` と `Decoder` に `Intel Media SDK [intel]` が表示されているコーデックで利用可能です。 - -PowerShell での実行コマンド例: -``` -.\momo.exe --video-codec-engines -``` - -PowerShell での実行結果例: -``` -> .\momo.exe --video-codec-engines -VP8: - Encoder: - - Software [software] (default) - Decoder: - - Software [software] (default) - -VP9: - Encoder: - - Software [software] (default) - Decoder: - - Intel Media SDK [intel] (default) - - Software [software] - -AV1: - Encoder: - - Software [software] (default) - Decoder: - - Software [software] (default) - -H264: - Encoder: - - Intel Media SDK [intel] (default) - Decoder: - - Intel Media SDK [intel] (default) -``` - -## Ubuntu 20.04、 Ubuntu 22.04 での利用方法 - -### ドライバーのインストール∂ - -- Ubuntu の最新化を実行します - - `sudo apt-get update` - - `sudo apt-get upgrade` -- ドライバー確認ツールをインストールします - - `sudo apt-get install vainfo` -- ドライバーをインストールします。 - - 以下のコマンドのいずれでも問題ありません。フル機能版は `intel-media-va-driver-non-free` でコア機能版は `intel-media-va-driver` になります。 - - `sudo apt-get install intel-media-va-driver-non-free` - - `sudo apt-get install intel-media-va-driver` -- 関連ライブラリをインストールします - - `sudo apt install libmfx1` - -以上でインストールが完了します。 - -## Intel Media SDK が認識できているか確認 - -Momo を `--video-codec-engines` オプションを指定して実行することで利用可能なエンコーダーとデコーダー一覧が出力されます。 `Encoder` と `Decoder` に `Intel Media SDK [intel]` が表示されているコーデックで利用可能です。 - -実行コマンド例: -``` -./momo --video-codec-engines -``` - -実行結果例: -``` -$ ./momo --video-codec-engines -VP8: - Encoder: - - Software [software] (default) - Decoder: - - Software [software] (default) - -VP9: - Encoder: - - Software [software] (default) - Decoder: - - Intel Media SDK [intel] (default) - - Software [software] - -AV1: - Encoder: - - Software [software] (default) - Decoder: - - Software [software] (default) - -H264: - Encoder: - - Intel Media SDK [intel] (default) - Decoder: - - Intel Media SDK [intel] (default) -``` - -## 動作確認ができたチップセット - -現在動作確認ができているチップセットは以下になります。 - -- Intel(R) Core(TM) i9-9980HK -- Intel(R) Core(TM) i7-1195G7 -- Intel(R) Core(TM) i5-10210U - -## エンコーダーが複数ある場合 - -NVIDIA と共存させた環境の場合 INTEL と NVIDIA のエンコーダーが表示されます。 -Momo では NVIDIA を優先して使用するようになっていますが `--h264-encoder` オプションを使用して `intel` を指定することで Intel Media SDK を使用することができます。 - -## Intel Media SDK を認識できない場合 - -NVIDIA を利用している環境では Intel Media SDK を認識できないことがあります。その場合は NVIDIA のドライバーを削除し Intel のグラフィックドライバーに切り替えると認識する場合があります。 \ No newline at end of file diff --git a/doc/LINUX_VIDEO_DEVICE.md b/doc/LINUX_VIDEO_DEVICE.md index eb16ef11..36e5f80b 100644 --- a/doc/LINUX_VIDEO_DEVICE.md +++ b/doc/LINUX_VIDEO_DEVICE.md @@ -1,65 +1,56 @@ # Linux でビデオデバイスを指定する -## --video-device - -`--video-device` は linux 端末でビデオデバイス(つまりカメラ)を指定する機能です。 1 台の Raspberry Pi で複数の Momo を起動し、ビデオデバイスが複数あり、それぞれここに割り当てたい時に利用できます。 - -```shell -$ ./momo --video-device /dev/video0 test -``` - -### デバイス名の固定 +Momo ではデバイスを指定する際、デバイスファイルではなくデバイス名を指定します。 -Linux 端末で USB カメラを接続した場合に、デバイス名が前回の接続時と異なるデバイス名になることがあります。 -デバイス名が変更された場合は、--video-device に指定するデバイス名も合わせて修正する必要があるため、 -例えば、Linux 端末の起動時に自動で momo を起動させたい場合等に不便です。 - -ここでは、同じデバイス名を使用できるように、USB カメラのデバイス名を接続するカメラごとに固定して、 -同一の USB カメラでは常に同じデバイス名を使用できるように設定します。 - -#### udev ルールの設定 - -udev ルールを設定してデバイス名を固定します。 +## --video-device -まず、接続した USB カメラの SERIAL を取得します +`--video-device` は linux 端末でビデオデバイス(つまりカメラ)を指定する機能です。 +1 台の Raspberry Pi で複数のカメラを利用して複数の Momo を起動する時に、カメラデバイスを個別に割り当てることができます。 -``` -$ udevadm info --query=all --name=/dev/video0 | grep ID_SERIAL_SHORT -E: ID_SERIAL_SHORT=8E40F950 +```bash +./momo --video-device "MX Brio" test ``` -次に、/etc/udev/rules.d/ 以下にルールファイルを作成(例: /etc/udev/rules.d/70-usb.rules)して下記のように設定します。 +### デバイス名を取得する -ATTRS{serial} には上記で取得した SERIAL を指定します。 +デバイス名は、`v4l2-ctl` コマンドで取得できます。 +例えば以下のような実行結果の場合、デバイス名は `HD USB CAMERA: HD USB CAMERA` と `Integrated_Webcam: Integrate` です。 -SYMLINK には固定するデバイス名を指定します。 +```bash +v4l2-ctl --list-devices +HD USB CAMERA: HD USB CAMERA (usb-0000:00:00.0-1): + /dev/video0 + /dev/video1 + /dev/media0 +Integrated_Webcam: Integrate (usb-0000:00:00.0-12): + /dev/video2 + /dev/video3 + /dev/media1 ``` -KERNEL=="video[0-9]*", MODE="0666", ATTRS{serial}=="8E40F950", SYMLINK+="video_101" -``` - -#### デバイス名が複数ある場合 -1 つの USB カメラにデバイス名が複数ある場合は、指定するデバイスの ATTR{index} も udev ルールに指定します。 +### 同一カメラデバイスを複数接続している場合 -ATTR{index} は下記の方法で取得します。 +同一カメラデバイスを複数接続している場合、デバイス名が同じであるため、個別に指定することができません。 +その場合は、デバイス名を指定する代わりに、`Bus info` を指定することができます。 -``` -$ udevadm info --attribute-walk --path $( udevadm info --query=path --name=/dev/video0 ) | grep index - ATTR{index}=="0" -``` +例えば以下のような `v4l2-ctl` コマンド の実行結果の場合、`Bus info` は `usb-0000:00:00.0-1` と `usb-0000:00:00.0-12` です。 -ATTR{index}=="0" を含めた場合の設定例は下記の通りです。 +```bash +v4l2-ctl --list-devices +HD USB CAMERA: HD USB CAMERA (usb-0000:00:00.0-1): + /dev/video0 + /dev/video1 + /dev/media0 +Integrated_Webcam: Integrate (usb-0000:00:00.0-12): + /dev/video2 + /dev/video3 + /dev/media1 ``` -KERNEL=="video[0-9]*", MODE="0666", ATTRS{serial}=="8E40F950", ATTR{index}=="0", SYMLINK+="video_101" -``` - -### momo の実行 -設定したデバイス名を使用するために、USB カメラを Linux 端末から外して、 -すぐに再度接続して、上記で SYMLINK に設定したデバイス名を --video-device に指定して momo を実行します。 +`Bus info` を指定する実行例は以下の通りです。 -``` -$ ./momo --video-device /dev/video_101 test -``` +```bash +./momo --video-device "usb-0000:00:00.0-1" test +``` \ No newline at end of file diff --git a/doc/PACKAGE.md b/doc/PACKAGE.md deleted file mode 100644 index 6d3cebb0..00000000 --- a/doc/PACKAGE.md +++ /dev/null @@ -1,41 +0,0 @@ -# パッケージを作成する - -## Raspberry Pi OS 32bit (armv6) 向けパッケージの作成例 - -raspberry-pi-os_armv6 パッケージを作成する場合は build ディレクトリで ./build.sh --package raspberry-pi-os_armv6 と打つことでパッケージが作成されます。 - -```shell -$ ./build.sh --package raspberry-pi-os_armv6 -``` - -Windows の場合は以下のコマンドになります。 - -```powershell -.\build.bat -package -``` - -パッケージは `_package` 以下に作成されます。 - -### 作成可能なパッケージ一覧 - -- windows -- macos_arm64 -- raspberry-pi-os_armv6 -- raspberry-pi-os_armv7 -- raspberry-pi-os_armv8 -- ubuntu-20.04_armv8_jetson_xavier -- ubuntu-20.04_x86_64 -- ubuntu-22.04_x86_64 - -## パッケージ解凍後の構成 - -``` -$ tree -. -├── html -│   ├── test.html -│   └── webrtc.js -├── LICENSE -├── momo -└── NOTICE -``` diff --git a/doc/SETUP_JETSON.md b/doc/SETUP_JETSON.md index 8fd16008..e5922d17 100644 --- a/doc/SETUP_JETSON.md +++ b/doc/SETUP_JETSON.md @@ -1,21 +1,26 @@ -# Jetson シリーズで Momo を使ってみる +# NVIDIA Jetson シリーズで Momo を使ってみる もし Jetson シリーズを購入する場合は [BUY_JETSON.md](BUY_JETSON.md) を参考にしてください。 -## Jetson シリーズでは JetPack 5.1.1 のみの利用を前提としています +NVIDIA Jetson シリーズでは JetPack 6.0.0 のみの利用を前提としています。 -[JetPack 5.1.1 is now live \- Jetson & Embedded Systems / Announcements \- NVIDIA Developer Forums](https://forums.developer.nvidia.com/t/jetpack-5-1-1-is-now-live/247862/1) +## 既知の問題 + +現在 Jetpack 6 で --hw-mjpeg-decoder が有効だと H.264 が送信できない問題があります。 +Jetson 6 で H.264 を送信する場合は `--hw-mjpeg-decoder=false` を指定してください。 +詳細については https://github.com/shiguredo/momo/issues/355 をご確認ください。 ## Jetson シリーズ向けのバイナリは以下にて提供しています -https://github.com/shiguredo/momo/releases にて最新版のバイナリをダウンロードしてください。 + にて最新版のバイナリをダウンロードしてください。 -- `momo-_ubuntu-20.04_armv8_jetson_xavier.tar.gz` - - Jetson AGX Orin , Jetson AGX Xavier または Jetson Xavier NX +- `momo-_ubuntu-22.04_armv8_jetson.tar.gz` + - Jetson AGX Orin または Jetson NX Orin + - JetPack 6 の最新版に対応 ## ダウンロードしたパッケージ、解凍後の構成 -``` +```console $ tree . ├── html @@ -41,8 +46,8 @@ $ tree `--hw-mjpeg-decoder` は ハードウェアによるビデオのリサイズ と USB カメラ用の場合 MJPEG をハードウェアデコードします。 Jetson シリーズではデフォルトで `--hw-mjpeg-decoder=true` です。 ハードウェアデコードに対応していないコーデックを利用したい場合は `--hw-mjpeg-decoder=false` を指定してください。 -```shell -$ ./momo --hw-mjpeg-decoder=true --no-audio-device test +```bash +./momo --hw-mjpeg-decoder=true --no-audio-device test ``` ## 4K@30fps を出すためにやること @@ -61,7 +66,7 @@ $ ./momo --hw-mjpeg-decoder=true --no-audio-device test を実行してカメラの設定を変更してください。 4K 30fps が出力可能な設定は下記のとおりです -``` +```console $ v4l2-ctl --list-ctrls brightness 0x00980900 (int) : min=-64 max=64 step=1 default=0 value=0 contrast 0x00980901 (int) : min=0 max=95 step=1 default=1 value=1 @@ -103,9 +108,9 @@ Sora Labo の利用申請や使用方法については [Sora Labo のドキュ コマンド例を以下に記載します。 -```shell +```bash $ ./momo --hw-mjpeg-decoder true --framerate 30 --resolution 4K --log-level 2 sora \ - --signaling-url \ + --signaling-urls \ wss://canary.sora-labo.shiguredo.app/signaling \ --channel-id shiguredo_0_sora \ --video true --audio true \ diff --git a/doc/SETUP_MAC.md b/doc/SETUP_MAC.md index 7595f211..de24f8d8 100644 --- a/doc/SETUP_MAC.md +++ b/doc/SETUP_MAC.md @@ -2,57 +2,60 @@ ## macOS 向けのバイナリは以下にて提供しています -https://github.com/shiguredo/momo/releases にて最新版のバイナリをダウンロードしてください。 + にて最新版のバイナリをダウンロードしてください。 ## 動かしてみる 動かし方については [USE_TEST.md](USE_TEST.md) を御覧ください。 -## macOS 向けの追加のオプション - -### --video-device +## --video-device `--video-device` は macOS でビデオデバイス(つまりカメラ)を指定する機能です。 1 台の macOS で複数の Momo を起動し、ビデオデバイスが複数あり、それぞれ個々に割り当てたい時に利用できます。 +```bash +./momo --video-device 0 test +``` + +### デバイス一覧を取得する -```shell -$ ./momo --video-device 0 test +```bash +system_profiler SPCameraDataType ``` -#### ビデオデバイスの指定方法 +### ビデオデバイスの指定方法 ビデオデバイスの指定には、デバイス番号、またはデバイス名を指定することができます。 -* 指定がない場合は、デバイス番号が 0 のものが選択されます -* デバイス番号 0 のエイリアスとして、`default` が使えます -* デバイス名を指定した場合は、デバイス番号 0 から順番に検索していき、前方一致検索で最初にマッチしたものが選択されます +- 指定がない場合は、デバイス番号が 0 のものが選択されます +- デバイス番号 0 のエイリアスとして、`default` が使えます +- デバイス名を指定した場合は、デバイス番号 0 から順番に検索していき、前方一致検索で最初にマッチしたものが選択されます なお、デバイス番号は接続する順番によって変動するため、同じデバイス番号を指定しても異なるデバイスが選択されることがあります。 このため、使用するデバイスを固定したい場合は、デバイス名で指定するようにしてください。 -##### デフォルトデバイス指定 +#### デフォルトデバイス指定 下記は全て同じデフォルトデバイスが選択されます。 ```console -$ ./momo test -$ ./momo --video-device 0 test -$ ./momo --video-device default test -$ ./momo --video-device "default" test +./momo test +./momo --video-device 0 test +./momo --video-device default test +./momo --video-device "default" test ``` -##### デバイス番号で指定 +#### デバイス番号で指定 ```console -$ ./momo --video-device 1 test +./momo --video-device 1 test ``` -##### デバイス名で指定 +#### デバイス名で指定 前方一致検索でマッチさせるため、下記は全て同じデバイスが選択されます。 ```console -$ ./momo --video-device FaceTime test -$ ./momo --video-device "FaceTime HD" 1 test -$ ./momo --video-device "FaceTime HD Camera (Built-in)" test +./momo --video-device FaceTime test +./momo --video-device "FaceTime HD" 1 test +./momo --video-device "FaceTime HD Camera (Built-in)" test ``` diff --git a/doc/SETUP_RASPBERRY_PI.md b/doc/SETUP_RASPBERRY_PI.md index 20d333a9..2f2c3a73 100644 --- a/doc/SETUP_RASPBERRY_PI.md +++ b/doc/SETUP_RASPBERRY_PI.md @@ -6,15 +6,13 @@ Raspberry Pi OS のレガシー版には対応しておりません。最新版 ## Raspberry Pi 向けのバイナリは以下にて提供しています -https://github.com/shiguredo/momo/releases にて最新版のバイナリをダウンロードしてください。 + にて最新版のバイナリをダウンロードしてください。 - Raspberry Pi OS 64 bit を利用する場合は、 `momo-_raspberry-pi-os_armv8.tar.gz` を利用してください -- Raspberry Pi 2 や 3 や 4 を利用する場合は、 `momo-_raspberry-pi-os_armv7.tar.gz` を利用してください -- Raspberry Pi Zero や 1 を利用する場合は、 `momo-_raspberry-pi-os_armv6.tar.gz` を利用してください ## ダウンロードしたパッケージ、解凍後の構成 -``` +```console $ tree . ├── html @@ -31,10 +29,11 @@ $ tree 下記を実行してください。 -``` -$ sudo apt-get update -$ sudo apt-get upgrade -$ sudo apt-get install libnspr4 libnss3 +```bash +sudo apt-get update +sudo apt-get upgrade +sudo apt-get install libnspr4 libnss3 +sudo apt-get install libcamera0.3 ``` #### Raspberry Pi OS Lite を利用する場合 @@ -43,11 +42,10 @@ Raspberry Pi Lite では映像に関するパッケージが入っていない 下記に実行する一例を示します。 -``` -$ sudo apt-get install libSDL2-2.0 -$ sudo apt-get install libxtst6 -$ sudo apt-get install libegl1-mesa-dev -$ sudo apt-get install libgles2-mesa +```bash +sudo apt-get install libxtst6 +sudo apt-get install libegl1-mesa-dev +sudo apt-get install libgles2-mesa ``` ### Raspberry-Pi-OS で Raspberry Pi 用カメラなどの CSI カメラを利用する場合 @@ -58,8 +56,8 @@ raspi-config で Camera を Enable にしてください。 加えて、以下のコマンドを実行してください -``` -$ sudo modprobe bcm2835-v4l2 max_video_width=2592 max_video_height=1944 +```bash +sudo modprobe bcm2835-v4l2 max_video_width=2592 max_video_height=1944 ``` ## 使ってみる @@ -77,30 +75,44 @@ $ sudo modprobe bcm2835-v4l2 max_video_width=2592 max_video_height=1944 `--force-i420` は Raspberry Pi 専用カメラ用では MJPEG を使うとパフォーマンスが落ちるため HD 以上の解像度でも MJPEG にせず強制的に I420 でキャプチャーします。 USB カメラでは逆にフレームレートが落ちるため使わないでください。 -```shell -$ ./momo --force-i420 --no-audio-device test +```bash +./momo --force-i420 --no-audio-device test +``` + +## Raspberry Pi 専用カメラでが利用できない + +Momo 2023.1.0 から Raspberry Pi OS (64 bit) でのみ Raspberry Pi 専用カメラ(CSI 接続のカメラ)が利用できるようになりました。 + +### --use-libcamera + +`--use-libcamera` は Raspberry Pi 専用カメラを利用するためのオプションです。 + +```bash +./momo --use-libcamera --no-audio-device test ``` ## Raspberry Pi 専用カメラでパフォーマンスが出ない ### --hw-mjpeg-decoder +MJPEG のハードウェアデコーダーの利用を検討してみてください。 `--hw-mjpeg-decoder` は ハードウェアによるビデオのリサイズをします。 -```shell -$ ./momo --hw-mjpeg-decoder true --no-audio-device test +```bash +./momo --hw-mjpeg-decoder true --no-audio-device test ``` ### Raspberry Pi の設定を見直す -[Raspbian で Raspberry Pi の Raspberry Pi 用カメラを利用する場合](#raspbian-で-raspberry-pi-の-raspberry-pi-用カメラを利用する場合)通りに設定されているか確認してください。特に `max_video_width=2592 max_video_height=1944` が記載されていなければ高解像度時にフレームレートが出ません。 +[Raspberry-Pi-OS で Raspberry Pi 用カメラなどの CSI カメラを利用する場合](#raspberry-pi-os-で-raspberry-pi-用カメラなどの-csi-カメラを利用する場合) を確認してください。 +特に `max_video_width=2592 max_video_height=1944` が記載されていなければ高解像度時にフレームレートが出ません。 ### オプションを見直す Raspberry Pi 用カメラ利用時には `--hw-mjpeg-decoder=true --force-i420` オプションを併用すると CPU 使用率が下がりフレームレートが上がります。例えば、 Raspberry Pi Zero の場合には -```shell -$ ./momo --resolution=HD --force-i420 --hw-mjpeg-decoder=true test +```bash +./momo --resolution=HD --force-i420 --hw-mjpeg-decoder=true test ``` がリアルタイムでの最高解像度設定となります。 @@ -111,15 +123,19 @@ $ ./momo --resolution=HD --force-i420 --hw-mjpeg-decoder=true test 一部の MJPEG に対応した USB カメラを使用している場合、 `--hw-mjpeg-decoder` は ハードウェアによるビデオのリサイズ と MJPEG をハードウェアデコードします。 -```shell -$ ./momo --hw-mjpeg-decoder true --no-audio-device test +```bash +./momo --hw-mjpeg-decoder true --no-audio-device test ``` ### Raspberry Pi で USB カメラ利用時に --hw-mjpeg-decoder を使ってもフレームレートが出ない -USB カメラ利用時には `--hw-mjpeg-decoder` を使わない方がフレームレートは出ます。しかし `--hw-mjpeg-decoder` を使って CPU 使用率を下げた状態で利用したい場合は /boot/config.txt の末尾に下記を追記してください +USB カメラ利用時にフレームレートを出したい場合は `--hw-mjpeg-decoder` を使わないことをおすすめします。ただし CPU 使用率はあがってしまいます。 -``` +CPU 使用率を抑えつつフレームレートを出したい場合は、`/boot/firmware/config.txt` の末尾に下記を追記して `--hw-mjpeg-decoder` を指定することで改善することがあります。 + +bookworm より前のバージョンをご利用の場合は `/boot/config.txt` に追記してください。 + +```text gpu_mem=256 force_turbo=1 avoid_warnings=2 diff --git a/doc/SETUP_UBUNTU.md b/doc/SETUP_UBUNTU.md index ccd758cf..1f7db950 100644 --- a/doc/SETUP_UBUNTU.md +++ b/doc/SETUP_UBUNTU.md @@ -1,14 +1,14 @@ -# Ubuntu 20.04 x86_64、 Ubuntu 22.04 x86_64 で Momo を使ってみる +# Ubuntu 24.04 x86_64 で Momo を使ってみる -## Ubuntu 20.04 x86_64、 Ubuntu 22.04 x86_64 向けのバイナリは以下にて提供しています +## Ubuntu 24.04 x86_64 向けのバイナリは以下にて提供しています -https://github.com/shiguredo/momo/releases にて最新版のバイナリをダウンロードしてください。 + にて最新版のバイナリをダウンロードしてください。 -- バイナリは、 `momo-_ubuntu-20.04_x86_64.tar.gz` あるいは `momo-_ubuntu-22.04_x86_64.tar.gz` を利用してください +- バイナリは、 `momo-_ubuntu-24.04_x86_64.tar.gz` を利用してください ## ダウンロードしたパッケージ、解凍後の構成 -``` +```bash $ tree . ├── html @@ -25,13 +25,13 @@ $ tree 下記を実行してください -``` -$ sudo apt-get update -$ sudo apt-get upgrade -$ sudo apt-get install libdrm2 +```bash +sudo apt-get update +sudo apt-get upgrade +sudo apt-get install libdrm2 ``` -Intel Media SDK を利用したい場合は [INTEL_MEDIA_SDK.md](INTEL_MEDIA_SDK.md) を御覧ください。 +oneVPL を利用したい場合は [VPL.md](VPL.md) を御覧ください。 ## 動かしてみる diff --git a/doc/SETUP_WINDOWS.md b/doc/SETUP_WINDOWS.md index bad797bf..b1cffcee 100644 --- a/doc/SETUP_WINDOWS.md +++ b/doc/SETUP_WINDOWS.md @@ -2,7 +2,7 @@ ## Windows 向けのバイナリは以下にて提供しています -https://github.com/shiguredo/momo/releases にて最新版のバイナリをダウンロードしてください。 + にて最新版のバイナリをダウンロードしてください。 ## 動かしてみる @@ -14,10 +14,11 @@ PowerShellやコマンドプロンプトで実行する場合文字列エスケ metadataオプションのキーや値を囲む「"」を「\\\"」にする必要があります。 PowerShell での実行例: -``` + +```bash .\momo.exe --no-audio-device ` sora ` - --signaling-url ` + --signaling-urls ` wss://canary.sora-labo.shiguredo.app/signaling ` --channel-id shiguredo_0_sora ` --video-codec-type VP8 --video-bit-rate 500 ` diff --git a/doc/USE.md b/doc/USE.md index 0546f344..df359104 100644 --- a/doc/USE.md +++ b/doc/USE.md @@ -77,10 +77,8 @@ WebRTC Native Client Momo 2022.2.0 (8b57be45) WebRTC: Shiguredo-Build M102.5005@{#7} (102.5005.7.4 6ff73180) Environment: [arm64] macOS Version 12.3 (Build 21E230) -USE_MMAL_ENCODER=0 -USE_JETSON_ENCODER=0 -USE_NVCODEC_ENCODER=0 -USE_SDL2=1 +- USE_JETSON_ENCODER +- USE_NVCODEC_ENCODER ``` ### ヘルプ @@ -228,7 +226,7 @@ Usage: ./momo sora [OPTIONS] Options: -h,--help Print this help message and exit --help-all Print help message for all modes and exit - --signaling-url TEXT ... REQUIRED + --signaling-urls TEXT ... REQUIRED Signaling URLs --channel-id TEXT REQUIRED Channel ID --auto Connect to Sora automatically diff --git a/doc/USE_AYAME.md b/doc/USE_AYAME.md index 79954d73..353a0a23 100644 --- a/doc/USE_AYAME.md +++ b/doc/USE_AYAME.md @@ -10,7 +10,7 @@ Ayame を利用してシグナリングサーバを立てるのが面倒な人 Ayame Labo は時雨堂が提供している Ayame を利用したサービスです。無料で利用可能です。 -https://ayame-labo.shiguredo.app/ + ### Ayame Labo にサインアップしない場合 @@ -18,20 +18,19 @@ Ayame Labo はサインアップせずにシグナリングサーバを利用可 ここではルーム ID は `open-momo` としておりますが、必ず推測されにくい値に変更してください。 -```shell +```bash ./momo --no-audio-device ayame --signaling-url wss://ayame-labo.shiguredo.app/signaling --room-id open-momo ``` -Windows の場合: +#### Windows の場 -``` +```powershell .\momo.exe --no-audio-device ayame --signaling-url wss://ayame-labo.shiguredo.app/signaling --room-id open-momo ``` - Ayame SDK のオンラインサンプルを利用します。 URL の引数に `ルーム ID` を指定してアクセスします。 -https://openayame.github.io/ayame-web-sdk-samples/recvonly.html?roomId=open-momo + ### Ayame Labo にサインアップする場合 @@ -39,20 +38,20 @@ Ayame Labo にサインアップした場合はルーム ID に GitHub ユーザ 例えば GitHub ユーザ名が `shiguredo` の場合は `shiguredo@open-momo` となります。 - ルーム ID に `GitHub ユーザ名` を先頭に指定する必要があります - - ここでは `shiguredo@open-momo` をルーム ID としています。 + - ここでは `shiguredo@open-momo` をルーム ID としています。 - シグナリングキーを `--signaling-key` にて指定する必要があります - - ここではシグナリングキーを `xyz` としています + - ここではシグナリングキーを `xyz` としています -```shell +```bash ./momo --no-audio-device ayame --signaling-url wss://ayame-labo.shiguredo.app/signaling --room-id shiguredo@open-momo --signaling-key xyz ``` -Windows の場合: +#### Windows の場合 -``` +```powershell .\momo.exe --no-audio-device ayame --signaling-url wss://ayame-labo.shiguredo.app/signaling --room-id shiguredo@open-momo --signaling-key xyz ``` Ayame SDK のオンラインサンプルを利用します。 URL の引数にルーム ID とシグナリングキーを指定してアクセスします。 -https://openayame.github.io/ayame-web-sdk-samples/recvonly.html?roomId=shiguredo@open-momo&signalingKey=xyz + diff --git a/doc/USE_METRICS.md b/doc/USE_METRICS.md index 14c0a6b4..aaa0ea77 100644 --- a/doc/USE_METRICS.md +++ b/doc/USE_METRICS.md @@ -8,8 +8,8 @@ Momo には統計情報を HTTP API 経由で JSON 形式で取得すること デフォルトでは MetricsServer は起動しません。起動させたい場合は、`--metrics-port` オプションでポート番号を指定してください。8081 番ポートで起動させたい場合は、次のように指定してください。 -``` -$ ./momo --metrics-port 8081 +```bash +./momo --metrics-port 8081 ``` MetricsServer はデフォルトでループバック (127.0.0.1 で listen) アドレスからのみアクセス可能です。グローバル (0.0.0.0 で listen) アクセスを許可する場合は `--metrics-allow-external-ip` 引数を指定してください。 @@ -20,11 +20,11 @@ MetricsServer はデフォルトでループバック (127.0.0.1 で listen) ア 統計情報を取得するには HTTP の GET メソッドを利用して `/metrics` にアクセスしてください。例えば、次のオプションで Momo を起動した場合、 -``` -$ ./momo --metrics-port 8081 test +```bash +./momo --metrics-port 8081 test ``` -http://127.0.0.1:8081/metrics にブラウザ、または `curl` などの HTTP クライアントでアクセスすることで統計情報を取得することができます。 + にブラウザ、または `curl` などの HTTP クライアントでアクセスすることで統計情報を取得することができます。 ### 統計情報 JSON の仕様 @@ -710,4 +710,4 @@ http://127.0.0.1:8081/metrics にブラウザ、または `curl` などの HTTP ## 応用例 -* [自宅の Jetson で動いている WebRTC Native Client Momo を外出先でいい感じに監視する方法](https://zenn.dev/hakobera/articles/c0553faa1223324d6aff) +- [自宅の Jetson で動いている WebRTC Native Client Momo を外出先でいい感じに監視する方法](https://zenn.dev/hakobera/articles/c0553faa1223324d6aff) diff --git a/doc/USE_SDL.md b/doc/USE_SDL.md index ba05341c..e690b9a4 100644 --- a/doc/USE_SDL.md +++ b/doc/USE_SDL.md @@ -9,32 +9,32 @@ SDL (Simple DirectMedia Layer) を利用することで、 Momo 自体が受信 ## 注意 - この機能は ayame と sora モードでのみ利用できます - - test モードでは test.html が HTTPS ではないため getUserMedia を使用できません + - test モードでは test.html が HTTPS ではないため getUserMedia を使用できません - この機能は Windows または macOS または Linux で利用できます ## SDL コマンド引数 - --use-sdl - - SDL 機能を使う場合は指定します + - SDL 機能を使う場合は指定します - --window-width - - 映像を表示するウインドウの横幅を指定します + - 映像を表示するウインドウの横幅を指定します - --window-height - - 映像を表示するウインドウの縦幅を指定します + - 映像を表示するウインドウの縦幅を指定します - --fullscreen - - 映像を表示するウインドウをフルスクリーンにします + - 映像を表示するウインドウをフルスクリーンにします ### Sora モード - --role sendonly, --sora recvonly または --sora sendrecv - - Sora でロールを切り替える場合に指定します。送信専用にする場合は sendonly で、受信専用にする場合は recvonly、送受信する場合は sendrecv を指定します。sendrecv はマルチストリームの場合のみ利用可能です。デフォルトは sendonly です。 + - Sora でロールを切り替える場合に指定します。送信専用にする場合は sendonly で、受信専用にする場合は recvonly、送受信する場合は sendrecv を指定します。sendrecv はマルチストリームの場合のみ利用可能です。デフォルトは sendonly です。 - --spotlight - - Sora でスポットライト機能を利用する場合に指定します + - Sora でスポットライト機能を利用する場合に指定します ## Ayame を利用した 1:1 の双方向 - ルーム ID を推測されにくい値に変更して下さい -``` +```bash ./momo --resolution VGA --no-audio-device --use-sdl ayame --signaling-url wss://ayame-labo.shiguredo.jp/signaling --room-id momo-sdl-ayame ``` @@ -42,16 +42,14 @@ SDL (Simple DirectMedia Layer) を利用することで、 Momo 自体が受信 ## Sora を利用したマルチストリームでの双方向 - - Signaling サーバの URL はダミーです -``` -./momo --resolution VGA --no-audio-device --use-sdl sora --video-codec-type VP8 --video-bit-rate 1000 --audio false --signaling-url wss://example.com/signaling --channel-id momo-sdl-sora +```bash +./momo --resolution VGA --no-audio-device --use-sdl sora --video-codec-type VP8 --video-bit-rate 1000 --audio false --signaling-urls wss://example.com/signaling --channel-id momo-sdl-sora ``` [![Image from Gyazo](https://i.gyazo.com/abdb1802bd66440ef32e75da6842f0cf.png)](https://gyazo.com/abdb1802bd66440ef32e75da6842f0cf) - ## 全画面 - f を押すと全画面になります、もう一度 f を押すと戻ります diff --git a/doc/USE_SERIAL.md b/doc/USE_SERIAL.md index 688d61b5..d2f44591 100644 --- a/doc/USE_SERIAL.md +++ b/doc/USE_SERIAL.md @@ -10,7 +10,7 @@ socat はインストールされている前提です。 仮想シリアルポートを2つ作成します。 -``` +```console $ socat -d -d pty,raw,echo=0 pty,raw,echo=0 2020/01/18 18:47:21 socat[71342] N PTY is /dev/ttys003 2020/01/18 18:47:21 socat[71342] N PTY is /dev/ttys004 @@ -21,31 +21,30 @@ $ socat -d -d pty,raw,echo=0 pty,raw,echo=0 次に /dev/ttys003 に Momo を繋ぎます。 -``` -$ ./momo --serial /dev/ttys003,9600 test +```bash +./momo --serial /dev/ttys003,9600 test ``` /dev/ttys004 に書かれたデータ表示するようにします。 -``` -$ cat < /dev/ttys004 +```bash +cat < /dev/ttys004 ``` -http://127.0.0.1:8080/html/test.html にアクセスします。 + にアクセスします。 send のところでなにか文字列を送って無事 ttys004 経由で表示される事を確認してください。 次に /dev/ttys004 に書き込んだら -``` -$ echo "Hello, world" > /dev/ttys004 +```bash +echo "Hello, world" > /dev/ttys004 ``` -http://127.0.0.1:8080/html/test.html の JavaScript Console に表示される事を確認してください。 + の JavaScript Console に表示される事を確認してください。 ## 参考動画 [![Image from Gyazo](https://i.gyazo.com/c1fb6696963e044a44576b1ddeffd0cb.gif)](https://gyazo.com/c1fb6696963e044a44576b1ddeffd0cb) - [![Image from Gyazo](https://i.gyazo.com/269ccc2290b43809a0e67e35c03e8601.gif)](https://gyazo.com/269ccc2290b43809a0e67e35c03e8601) diff --git a/doc/USE_SORA.md b/doc/USE_SORA.md index 5f31229b..ca5e5534 100644 --- a/doc/USE_SORA.md +++ b/doc/USE_SORA.md @@ -2,7 +2,7 @@ Sora は時雨堂が開発、販売している商用 WebRTC SFU 製品です。 -https://sora.shiguredo.jp/ + ここでは利用申請することで法人などで無料で検証可能な [Sora Labo](https://sora-labo.shiguredo.app/) を利用しています。 @@ -10,22 +10,22 @@ Sora Labo の利用申請や使用方法については [Sora Labo のドキュ ## Sora Labo を使う -GitHub アカウントを用意して https://sora-labo.shiguredo.app/ にサインアップしてください。 +GitHub アカウントを用意して にサインアップしてください。 ### 片方向配信をしてみる - チャネル名に `__<好きな文字列>` を指定してください - - 好きな文字列が sora 、GitHub ID が 0 、 GitHub ユーザ名が shiguredo とした場合は `shiguredo_0_sora` のように指定してください - - ここではチャネル ID を `shiguredo_0_sora` とします + - 好きな文字列が sora 、GitHub ID が 0 、 GitHub ユーザ名が shiguredo とした場合は `shiguredo_0_sora` のように指定してください + - ここではチャネル ID を `shiguredo_0_sora` とします - sora モードのオプションである --metadata を利用し生成したアクセストークンを `access_token` で指定します - - SoraLabo Home のアクセストークン生成にて先程の `<チャネル名>` を入力してアクセストークンを生成してください - - この指定は商用の Sora を利用する場合は不要です。Sora Labo 専用の機能になります - - ここではアクセストークンを `xyz` とします。 + - SoraLabo Home のアクセストークン生成にて先程の `<チャネル名>` を入力してアクセストークンを生成してください + - この指定は商用の Sora を利用する場合は不要です。Sora Labo 専用の機能になります + - ここではアクセストークンを `xyz` とします。 -```shell +```bash ./momo --no-audio-device \ sora \ - --signaling-url \ + --signaling-urls \ wss://canary.sora-labo.shiguredo.app/signaling \ --channel-id shiguredo_0_sora \ --video-codec-type VP8 --video-bit-rate 500 \ @@ -39,10 +39,10 @@ GitHub アカウントを用意して https://sora-labo.shiguredo.app/ にサイ GUI 環境で Momo を利用すると、 SDL を利用し音声や映像の受信が可能になります。 -```shell +```bash ./momo --resolution VGA --no-audio-device --use-sdl \ sora \ - --signaling-url \ + --signaling-urls \ wss://canary.sora-labo.shiguredo.app/signaling \ --channel-id shiguredo_0_sora \ --video-codec-type VP8 --video-bit-rate 1000 \ @@ -54,10 +54,10 @@ GUI 環境で Momo を利用すると、 SDL を利用し音声や映像の受 ### サイマルキャストで配信してみる -```shell +```bash ./momo --no-audio-device \ sora \ - --signaling-url \ + --signaling-urls \ wss://canary.sora-labo.shiguredo.app/signaling \ --channel-id shiguredo_0_sora \ --video-codec-type VP8 --video-bit-rate 500 \ diff --git a/doc/USE_TEST.md b/doc/USE_TEST.md index 7492e5a8..75f0293c 100644 --- a/doc/USE_TEST.md +++ b/doc/USE_TEST.md @@ -4,7 +4,7 @@ Momo 自体がシグナリングサーバの機能を持つ test モードを利 ## Momo で配信をしてみる -```shell +```bash ./momo --no-audio-device test ``` @@ -15,7 +15,7 @@ Windows の場合: ``` Momo の IP アドレスが 192.0.2.100 の場合は、 -http://192.0.2.100:8080/html/test.html に Chrome でアクセスして接続してみてください。 + に Chrome でアクセスして接続してみてください。 ## ローカルネットワークの Momo 同士で双方向配信をしてみる @@ -26,13 +26,13 @@ SDL についての詳細は [USE_SDL.md](USE_SDL.md) をお読みください Momo 1: -```shell +```bash ./momo --use-sdl test ``` Momo 2: -```shell +```bash ./momo --use-sdl ayame --signaling-url ws://[Momo 1 の IP アドレス]:8080/ws --room-id test ``` @@ -40,13 +40,13 @@ Google STUN を利用したくない場合は`--no-google-stun`をオプショ Momo 1: -```shell +```bash ./momo --no-google-stun --use-sdl test ``` Momo 2: -```shell +```bash ./momo --no-google-stun --use-sdl ayame --signaling-url ws://[Momo 1 の IP アドレス]:8080/ws --room-id test ``` diff --git a/doc/VPL.md b/doc/VPL.md new file mode 100644 index 00000000..e7549629 --- /dev/null +++ b/doc/VPL.md @@ -0,0 +1,159 @@ +# Momo で VPL を利用したハードウェアエンコーダー / デコーダーを利用する + +VPL を利用して Intel Quick Sync Video の HWA 機能を使った Momo で HWA を利用することが可能になります。 + +このドキュメントでは VPL を使用するためのセットアップ方法を記載します。 + +## 既知の問題 + +現在 VPL で VP9 と AV1 を送信するとき、受信に参加したクライアントが受信できない問題があります。 +`-vp9-encoder` と `--av1-encoder` で `software` を指定することで回避できます。 +詳細については https://github.com/shiguredo/momo/issues/357 をご確認ください。 + +## Intel Media SDK について + +VPL の詳細については以下のリンクをご確認ください。 + +- デコーダーとエンコーダーの対応しているコーデックとチップセットの組み合わせ表 + - +- VPL の Github + - +- Intel 公式ドキュメント + - + +## 対応プラットフォーム + +- Windows 11 x86_64 +- Ubuntu 24.04 x86_64 +- Ubuntu 22.04 x86_64 + +## Windows 11 での利用方法 + +### ドライバーのインストール + +Windows 11 では Intel の公式サイトからドライバーをインストールすることで VPL を利用することができます。 + +- Intel の公式サイトからドライバーをダウンロードします。 + - Intel ドライバーおよびソフトウェアのダウンロード + - +- インストーラーに従ってインストールを行います。 +- インストール後に再起動を行います。 + +### VPL が認識できているか確認 + +Momo を `--video-codec-engines` オプションを指定して実行することで利用可能なエンコーダーとデコーダー一覧が出力されます。 `Encoder` と `Decoder` に `oneVPL [vpl]` が表示されているコーデックで利用可能です。 + +PowerShell での実行コマンド例: + +```powershell +.\momo.exe --video-codec-engines +``` + +PowerShell での実行結果例: + +```powershell +> .\momo.exe --video-codec-engines +VP8: + Encoder: + - Software [software] (default) + Decoder: + - Software [software] (default) + +VP9: + Encoder: + - Software [software] (default) + Decoder: + - oneVPL [vpl] (default) + - Software [software] + +AV1: + Encoder: + - Software [software] (default) + Decoder: + - Software [software] (default) + +H264: + Encoder: + - oneVPL [vpl] (default) + Decoder: + - oneVPL [vpl] (default) +``` + +## Ubuntu 20.04、 Ubuntu 22.04 での利用方法 + +### ドライバーのインストール + +- Ubuntu の最新化を実行します + - `sudo apt-get update` + - `sudo apt-get upgrade` +- ドライバー確認ツールをインストールします + - `sudo apt-get install vainfo` +- ドライバーをインストールします。 + - 以下のコマンドのいずれでも問題ありません。フル機能版は `intel-media-va-driver-non-free` でコア機能版は `intel-media-va-driver` になります。 + - `sudo apt-get install intel-media-va-driver-non-free` + - `sudo apt-get install intel-media-va-driver` +- 関連ライブラリをインストールします + - `sudo apt install libmfx1` + +以上でインストールが完了します。 + +### VPL が認識できているか確認 + +Momo を `--video-codec-engines` オプションを指定して実行することで利用可能なエンコーダーとデコーダー一覧が出力されます。 `Encoder` と `Decoder` に `oneVPL [vpl]` が表示されているコーデックで利用可能です。 + +実行コマンド例: + +```bash +./momo --video-codec-engines +``` + +実行結果例: + +```bash +$ ./momo --video-codec-engines +VP8: + Encoder: + - Software [software] (default) + Decoder: + - Software [software] (default) + +VP9: + Encoder: + - Software [software] (default) + Decoder: + - oneVPL [vpl] (default) + - Software [software] + +AV1: + Encoder: + - Software [software] (default) + Decoder: + - Software [software] (default) + +H264: + Encoder: + - oneVPL [vpl] (default) + Decoder: + - oneVPL [vpl] (default) +``` + +## 動作確認ができたチップセット + +現在動作確認ができているチップセットは以下になります。 + +- Intel(R) Core(TM) Ultra 5 Processor 125H +- Intel(R) Core(TM) i9-9980HK +- Intel(R) Core(TM) i7-1195G7 +- Intel(R) Core(TM) i5-10210U +- Intel(R) Processor N97 +- Intel(R) Processor N100 +- Intel(R) Processor N95 + +## エンコーダーが複数ある場合 + +NVIDIA と共存させた環境の場合 INTEL と NVIDIA のエンコーダーが表示されます。 +Momo では NVIDIA を優先して使用するようになっていますが `--h264-encoder` オプションを使用して `vpl` を指定することで oneVPL を使用することができます。 + +## VPL を認識できない場合 + +NVIDIA を利用している環境では VPL を認識できないことがあります。その場合は NVIDIA のドライバーを削除し Intel のグラフィックドライバーに切り替えると認識する場合があります。 diff --git a/format.sh b/format.sh deleted file mode 100755 index 09ababf2..00000000 --- a/format.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# src/ 以下の全てのファイルに clang-format を適用する - -set -e - -for file in `find src -type f \( -name '*.h' -o -name '*.cpp' -o -name '*.mm' \)`; do - echo applying $file - clang-format -i -style=file $file -done diff --git a/localbuild/build.raspberry-pi-os_armv7.sh b/localbuild/build.raspberry-pi-os_armv7.sh deleted file mode 100755 index f3050d61..00000000 --- a/localbuild/build.raspberry-pi-os_armv7.sh +++ /dev/null @@ -1,182 +0,0 @@ -#!/bin/bash - -# Ubuntu 20.04 x86_64 のローカルでビルドするスクリプト - -cd `dirname $0` - -set -ex - -# apt install curl git - -PACKAGE_NAME=raspberry-pi-os_armv7 -PROJECT_DIR=`pwd`/.. -SCRIPT_DIR=$PROJECT_DIR/script -BUILDBASE_DIR=$PROJECT_DIR/build/$PACKAGE_NAME -SOURCE_DIR=$PROJECT_DIR/_source/$PACKAGE_NAME -BUILD_DIR=$PROJECT_DIR/_build/$PACKAGE_NAME -INSTALL_DIR=$PROJECT_DIR/_install/$PACKAGE_NAME - -mkdir -p $SOURCE_DIR -mkdir -p $BUILD_DIR -mkdir -p $INSTALL_DIR - -source $PROJECT_DIR/VERSION -CURRENT_VERSION="`cat $PROJECT_DIR/VERSION`" -INSTALLED_VERSION="" -if [ -e $INSTALL_DIR/VERSION ]; then - INSTALLED_VERSION="`cat $INSTALL_DIR/VERSION`" -fi - -if [ "$CURRENT_VERSION" != "$INSTALLED_VERSION" ]; then - # RootFS の構築 - $SCRIPT_DIR/init_rootfs_armhf.sh $INSTALL_DIR/rootfs $BUILDBASE_DIR/rpi-raspbian.conf - - # WebRTC の取得 - $SCRIPT_DIR/get_webrtc.sh "$WEBRTC_BUILD_VERSION" raspberry-pi-os_armv7 $INSTALL_DIR $SOURCE_DIR - - # コンパイラの取得 - $SCRIPT_DIR/get_llvm.sh $INSTALL_DIR/webrtc $INSTALL_DIR - - # Boost のビルド - $SCRIPT_DIR/setup_boost.sh $BOOST_VERSION $SOURCE_DIR/boost $SOURCE_DIR - pushd $SOURCE_DIR/boost/source - mkdir -p $BUILD_DIR/boost - echo "using clang : : $INSTALL_DIR/llvm/clang/bin/clang++ : ;" > project-config.jam - ./b2 \ - cxxstd=17 \ - cxxflags=" \ - -D_LIBCPP_ABI_UNSTABLE \ - -D_LIBCPP_DISABLE_AVAILABILITY \ - -nostdinc++ \ - -isystem${INSTALL_DIR}/llvm/libcxx/include \ - --target=arm-linux-gnueabihf \ - --sysroot=$INSTALL_DIR/rootfs \ - -I$INSTALL_DIR/rootfs/usr/include/arm-linux-gnueabihf \ - " \ - linkflags=' \ - ' \ - toolset=clang \ - visibility=global \ - target-os=linux \ - architecture=arm \ - address-model=32 \ - link=static \ - variant=release \ - install \ - -j`nproc` \ - --build-dir=$BUILD_DIR/boost \ - --ignore-site-config \ - --prefix=$INSTALL_DIR/boost \ - --with-filesystem \ - --with-json - - # CLI11 の取得 - rm -rf $INSTALL_DIR/CLI11 - git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git $INSTALL_DIR/CLI11 - - # CMake のインストール - $SCRIPT_DIR/get_cmake.sh "$CMAKE_VERSION" linux $INSTALL_DIR - export PATH="$INSTALL_DIR/cmake/bin:$PATH" - - # SDL2 のビルド - $SCRIPT_DIR/setup_sdl2.sh "$SDL2_VERSION" $SOURCE_DIR/sdl2 - mkdir -p $BUILD_DIR/sdl2/ - pushd $BUILD_DIR/sdl2 - cmake $SOURCE_DIR/sdl2/source \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/SDL2 \ - -DCMAKE_C_COMPILER=$INSTALL_DIR/llvm/clang/bin/clang \ - -DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabihf \ - -DCMAKE_CXX_COMPILER=$INSTALL_DIR/llvm/clang/bin/clang++ \ - -DCMAKE_CXX_COMPILER_TARGET=arm-linux-gnueabihf \ - -DCMAKE_SYSTEM_NAME=Linux \ - -DCMAKE_SYSTEM_PROCESSOR=arm \ - -DCMAKE_FIND_ROOT_PATH=$INSTALL_DIR/rootfs \ - -DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \ - -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ - -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH \ - -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \ - -DCMAKE_SYSROOT=$INSTALL_DIR/rootfs \ - -DSDL_STATIC=ON \ - -DSDL_SHARED=OFF \ - -DSDL_ATOMIC=OFF \ - -DSDL_AUDIO=OFF \ - -DSDL_VIDEO=ON \ - -DSDL_RENDER=ON \ - -DSDL_EVENTS=ON \ - -DSDL_JOYSTICK=ON \ - -DSDL_HAPTIC=ON \ - -DSDL_POWER=ON \ - -DSDL_THREADS=ON \ - -DSDL_TIMERS=OFF \ - -DSDL_FILE=OFF \ - -DSDL_LOADSO=ON \ - -DSDL_CPUINFO=OFF \ - -DSDL_FILESYSTEM=OFF \ - -DSDL_DLOPEN=ON \ - -DSDL_SENSOR=ON \ - -DSDL_COCOA=OFF \ - -DSDL_KMSDRM=OFF \ - -DSDL_METAL=OFF \ - -DSDL_OPENGL=ON \ - -DSDL_OPENGLES=ON \ - -DSDL_RPI=OFF \ - -DSDL_VIVANTE=OFF \ - -DSDL_VULKAN=OFF \ - -DSDL_WAYLAND=OFF \ - -DSDL_X11=ON \ - -DSDL_X11_SHARED=OFF \ - -DSDL_X11_XCURSOR=OFF \ - -DSDL_X11_XFIXES=OFF \ - -DSDL_X11_XINERAMA=OFF \ - -DSDL_X11_XINPUT=OFF \ - -DSDL_X11_XRANDR=OFF \ - -DSDL_X11_XSCRNSAVER=OFF \ - -DSDL_X11_XSHAPE=OFF \ - -DSDL_X11_XVM=OFF - make -j`nproc` - make install - popd - - cp $PROJECT_DIR/VERSION $INSTALL_DIR/VERSION -fi - -source $INSTALL_DIR/webrtc/VERSIONS - -export PATH="$INSTALL_DIR/cmake/bin:$PATH" - -pushd $PROJECT_DIR - MOMO_COMMIT="`git rev-parse HEAD`" - MOMO_COMMIT_SHORT="`cat $MOMO_COMMIT | cut -b 1-8`" -popd - -mkdir -p $BUILD_DIR/momo -pushd $BUILD_DIR/momo - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DMOMO_VERSION=$MOMO_VERSION \ - -DMOMO_COMMIT=$MOMO_COMMIT \ - -DWEBRTC_BUILD_VERSION=$WEBRTC_BUILD_VERSION \ - -DWEBRTC_READABLE_VERSION="$WEBRTC_READABLE_VERSION" \ - -DWEBRTC_COMMIT="$WEBRTC_COMMIT" \ - -DBOOST_ROOT_DIR=$INSTALL_DIR/boost \ - -DCLI11_ROOT_DIR=$INSTALL_DIR/CLI11 \ - -DSDL2_ROOT_DIR=$INSTALL_DIR/SDL2 \ - -DWEBRTC_INCLUDE_DIR=$INSTALL_DIR/webrtc/include \ - -DWEBRTC_LIBRARY_DIR=$INSTALL_DIR/webrtc/lib \ - -DLIBCXX_INCLUDE_DIR=$INSTALL_DIR/llvm/libcxx/include \ - -DTARGET_OS="linux" \ - -DTARGET_OS_LINUX="raspberry-pi-os" \ - -DTARGET_ARCH="arm" \ - -DTARGET_ARCH_ARM="armv7" \ - -DUSE_MMAL_ENCODER=ON \ - -DUSE_H264=ON \ - -DUSE_SDL2=ON \ - -DCLANG_ROOT=$INSTALL_DIR/llvm/clang \ - -DUSE_LIBCXX=ON \ - -DSYSROOT=$INSTALL_DIR/rootfs \ - -DLIBCXX_INCLUDE_DIR=$INSTALL_DIR/llvm/libcxx/include \ - -DBoost_ARCHITECTURE=32 \ - $PROJECT_DIR - cmake --build . -j`nproc` -popd diff --git a/localbuild/build.ubuntu-20.04_x86_64.sh b/localbuild/build.ubuntu-20.04_x86_64.sh deleted file mode 100755 index f56332d4..00000000 --- a/localbuild/build.ubuntu-20.04_x86_64.sh +++ /dev/null @@ -1,217 +0,0 @@ -#!/bin/bash - -cd `dirname $0` - -set -ex - -# apt install cuda=$CUDA_VERSION clang-10 curl git libxtst-dev libxdamage-dev libxfixes-dev libxrandr-dev libxcomposite-dev -# apt install libtool libdrm-dev -# 実行時には (libdrm-dev の代わりに) libdrm2 を入れる -# intel-media-va-driver または intel-media-va-driver-non-free を入れる - -PACKAGE_NAME=ubuntu-20.04_x86_64 -PROJECT_DIR=`pwd`/.. -SCRIPT_DIR=$PROJECT_DIR/script -SOURCE_DIR=$PROJECT_DIR/_source/$PACKAGE_NAME -BUILD_DIR=$PROJECT_DIR/_build/$PACKAGE_NAME -INSTALL_DIR=$PROJECT_DIR/_install/$PACKAGE_NAME - -mkdir -p $SOURCE_DIR -mkdir -p $BUILD_DIR -mkdir -p $INSTALL_DIR - -source $PROJECT_DIR/VERSION -CURRENT_VERSION="`cat $PROJECT_DIR/VERSION`" -INSTALLED_VERSION="" -if [ -e $INSTALL_DIR/VERSION ]; then - INSTALLED_VERSION="`cat $INSTALL_DIR/VERSION`" -fi - -if [ "$CURRENT_VERSION" != "$INSTALLED_VERSION" ]; then - # WebRTC の取得 - $SCRIPT_DIR/get_webrtc.sh "$WEBRTC_BUILD_VERSION" ubuntu-20.04_x86_64 $INSTALL_DIR $SOURCE_DIR - - # コンパイラの取得 - $SCRIPT_DIR/get_llvm.sh $INSTALL_DIR/webrtc $INSTALL_DIR - - # Boost のビルド - $SCRIPT_DIR/setup_boost.sh $BOOST_VERSION $SOURCE_DIR/boost $SOURCE_DIR - pushd $SOURCE_DIR/boost/source - rm -rf $BUILD_DIR/boost - rm -rf $INSTALL_DIR/boost - mkdir -p $BUILD_DIR/boost - echo "using clang : : $INSTALL_DIR/llvm/clang/bin/clang++ : ;" > project-config.jam - ./b2 \ - cxxstd=17 \ - cxxflags=" \ - -D_LIBCPP_ABI_UNSTABLE \ - -D_LIBCPP_DISABLE_AVAILABILITY \ - -nostdinc++ \ - -isystem${INSTALL_DIR}/llvm/libcxx/include \ - " \ - linkflags=' \ - ' \ - toolset=clang \ - visibility=global \ - target-os=linux \ - address-model=64 \ - link=static \ - variant=release \ - install \ - -j`nproc` \ - --build-dir=$BUILD_DIR/boost \ - --ignore-site-config \ - --prefix=$INSTALL_DIR/boost \ - --with-filesystem \ - --with-json - - # CLI11 の取得 - rm -rf $INSTALL_DIR/CLI11 - git clone --branch v$CLI11_VERSION --depth 1 https://github.com/CLIUtils/CLI11.git $INSTALL_DIR/CLI11 - - # CMake のインストール - $SCRIPT_DIR/get_cmake.sh "$CMAKE_VERSION" linux $INSTALL_DIR - export PATH="$INSTALL_DIR/cmake/bin:$PATH" - - # SDL2 のビルド - $SCRIPT_DIR/setup_sdl2.sh "$SDL2_VERSION" $SOURCE_DIR/sdl2 - mkdir -p $BUILD_DIR/sdl2/ - pushd $BUILD_DIR/sdl2 - cmake $SOURCE_DIR/sdl2/source \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/SDL2 \ - -DCMAKE_C_COMPILER=$INSTALL_DIR/llvm/clang/bin/clang \ - -DCMAKE_CXX_COMPILER=$INSTALL_DIR/llvm/clang/bin/clang++ \ - -DBUILD_SHARED_LIBS=OFF \ - -DSDL_ATOMIC=OFF \ - -DSDL_AUDIO=OFF \ - -DSDL_VIDEO=ON \ - -DSDL_RENDER=ON \ - -DSDL_EVENTS=ON \ - -DSDL_JOYSTICK=ON \ - -DSDL_HAPTIC=ON \ - -DSDL_POWER=ON \ - -DSDL_THREADS=ON \ - -DSDL_TIMERS=OFF \ - -DSDL_FILE=OFF \ - -DSDL_LOADSO=ON \ - -DSDL_CPUINFO=OFF \ - -DSDL_FILESYSTEM=OFF \ - -DSDL_DLOPEN=ON \ - -DSDL_SENSOR=ON \ - -DVIDEO_OPENGL=ON \ - -DVIDEO_OPENGLES=ON \ - -DVIDEO_RPI=OFF \ - -DVIDEO_WAYLAND=OFF \ - -DVIDEO_X11=ON \ - -DX11_SHARED=OFF \ - -DVIDEO_X11_XCURSOR=OFF \ - -DVIDEO_X11_XINERAMA=OFF \ - -DVIDEO_X11_XINPUT=OFF \ - -DVIDEO_X11_XRANDR=OFF \ - -DVIDEO_X11_XSCRNSAVER=OFF \ - -DVIDEO_X11_XSHAPE=OFF \ - -DVIDEO_X11_XVM=OFF \ - -DVIDEO_VULKAN=OFF \ - -DVIDEO_VIVANTE=OFF \ - -DVIDEO_COCOA=OFF \ - -DVIDEO_METAL=OFF \ - -DVIDEO_KMSDRM=OFF - make -j`nproc` - make install - popd - -# CUDA 周りのインストール -# apt-get update -# apt-get install -y software-properties-common -# wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin -# mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600 -# apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub -# add-apt-repository "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/ /" -# apt-get update -# DEBIAN_FRONTEND=noninteractive apt-get -y install cuda=$CUDA_VERSION clang-10 - - # libva - rm -rf $SOURCE_DIR/libva - git clone --depth 1 --branch $LIBVA_VERSION https://github.com/intel/libva.git $SOURCE_DIR/libva - rm -rf $BUILD_DIR/libva - mkdir -p $BUILD_DIR/libva - pushd $BUILD_DIR/libva - CC=$INSTALL_DIR/llvm/clang/bin/clang \ - CXX=$INSTALL_DIR/llvm/clang/bin/clang++ \ - CFLAGS="-fPIC" \ - $SOURCE_DIR/libva/autogen.sh \ - --enable-static \ - --disable-shared \ - --with-drivers-path=/usr/lib/x86_64-linux-gnu/dri \ - --prefix $INSTALL_DIR/libva - make -j`nproc` - rm -rf $INSTALL_DIR/libva - make install - popd - - # Intel Media SDK - rm -rf $SOURCE_DIR/msdk - git clone --depth 1 --branch intel-mediasdk-$MSDK_VERSION https://github.com/Intel-Media-SDK/MediaSDK.git $SOURCE_DIR/msdk - pushd $SOURCE_DIR/msdk - find . -name "CMakeLists.txt" | while read line; do sed -i 's/SHARED/STATIC/g' $line; done - popd - rm -rf $BUILD_DIR/msdk - mkdir -p $BUILD_DIR/msdk - pushd $BUILD_DIR/msdk - cmake \ - -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR/msdk \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_PREFIX_PATH=$INSTALL_DIR/libva \ - -DCMAKE_C_COMPILER=$INSTALL_DIR/llvm/clang/bin/clang \ - -DCMAKE_CXX_COMPILER=$INSTALL_DIR/llvm/clang/bin/clang++ \ - -DBUILD_SAMPLES=OFF \ - -DBUILD_TUTORIALS=OFF \ - $SOURCE_DIR/msdk - cmake --build . -j`nproc` - cmake --install . - popd - - cp $PROJECT_DIR/VERSION $INSTALL_DIR/VERSION -fi - -source $INSTALL_DIR/webrtc/VERSIONS - -export PATH="$INSTALL_DIR/cmake/bin:$PATH" - -pushd $PROJECT_DIR - MOMO_COMMIT="`git rev-parse HEAD`" - MOMO_COMMIT_SHORT="`cat $MOMO_COMMIT | cut -b 1-8`" -popd - -mkdir -p $BUILD_DIR/momo -pushd $BUILD_DIR/momo - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DMOMO_VERSION=$MOMO_VERSION \ - -DMOMO_COMMIT=$MOMO_COMMIT \ - -DWEBRTC_BUILD_VERSION=$WEBRTC_BUILD_VERSION \ - -DWEBRTC_READABLE_VERSION="$WEBRTC_READABLE_VERSION" \ - -DWEBRTC_COMMIT="$WEBRTC_COMMIT" \ - -DBOOST_ROOT_DIR=$INSTALL_DIR/boost \ - -DCLI11_ROOT_DIR=$INSTALL_DIR/CLI11 \ - -DSDL2_ROOT_DIR=$INSTALL_DIR/SDL2 \ - -DWEBRTC_INCLUDE_DIR=$INSTALL_DIR/webrtc/include \ - -DWEBRTC_LIBRARY_DIR=$INSTALL_DIR/webrtc/lib \ - -DLIBCXX_INCLUDE_DIR=$INSTALL_DIR/llvm/libcxx/include \ - -DLIBVA_ROOT_DIR=$INSTALL_DIR/libva \ - -DMSDK_ROOT_DIR=$INSTALL_DIR/msdk \ - -DTARGET_OS="linux" \ - -DTARGET_OS_LINUX="ubuntu-20.04" \ - -DTARGET_ARCH="x86_64" \ - -DUSE_H264=ON \ - -DUSE_SDL2=ON \ - -DUSE_NVCODEC_ENCODER=ON \ - -DUSE_MSDK_ENCODER=ON \ - -DUSE_SCREEN_CAPTURER=ON \ - -DCMAKE_C_COMPILER=clang-10 \ - -DCMAKE_CXX_COMPILER=clang++-10 \ - -DUSE_LIBCXX=ON \ - $PROJECT_DIR - cmake --build . -j`nproc` -popd diff --git a/build/raspberry-pi-os_armv8/rpi-raspbian.conf b/multistrap/raspberry-pi-os_armv8.conf similarity index 51% rename from build/raspberry-pi-os_armv8/rpi-raspbian.conf rename to multistrap/raspberry-pi-os_armv8.conf index fe08b4d6..ecc62640 100644 --- a/build/raspberry-pi-os_armv8/rpi-raspbian.conf +++ b/multistrap/raspberry-pi-os_armv8.conf @@ -4,11 +4,11 @@ bootstrap=Deb Rasp aptsources=Deb Rasp [Deb] -packages=libc6-dev libstdc++-10-dev libasound2-dev libpulse-dev libudev-dev libexpat1-dev libnss3-dev libxext-dev libxtst-dev libsdl2-dev +packages=libc6-dev libstdc++-11-dev libasound2-dev libpulse-dev libudev-dev libexpat1-dev libnss3-dev libxext-dev libxtst-dev source=http://deb.debian.org/debian -suite=bullseye +suite=bookworm [Rasp] packages=libcamera-dev source=http://archive.raspberrypi.org/debian -suite=bullseye +suite=bookworm diff --git a/multistrap/ubuntu-22.04_armv8_jetson.conf b/multistrap/ubuntu-22.04_armv8_jetson.conf new file mode 100644 index 00000000..da2e6648 --- /dev/null +++ b/multistrap/ubuntu-22.04_armv8_jetson.conf @@ -0,0 +1,23 @@ +[General] +noauth=true +unpack=true +bootstrap=Ports Jetson T234 +aptsources=Ports Jetson T234 + +[Ports] +packages=libc6-dev libstdc++-10-dev libxext-dev libxtst-dev +source=http://ports.ubuntu.com +suite=jammy +components=main universe + +[Jetson] +packages=nvidia-jetpack +source=https://repo.download.nvidia.com/jetson/common +suite=r36.3 +components=main + +[T234] +packages=nvidia-l4t-camera nvidia-l4t-multimedia +source=https://repo.download.nvidia.com/jetson/t234 +suite=r36.3 +components=main diff --git a/patch/mac_sdl.patch b/patch/mac_sdl.patch deleted file mode 100644 index a5dcede3..00000000 --- a/patch/mac_sdl.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- configure 2022-03-17 22:42:21.470152564 +0900 -+++ configure 2022-03-17 22:44:00.181213036 +0900 -@@ -20459,9 +20459,9 @@ - $as_echo "$have_gcc_declaration_after_statement" >&6; } - CFLAGS="$save_CFLAGS" - -- if test x$have_gcc_declaration_after_statement = xyes; then -- EXTRA_CFLAGS="$EXTRA_CFLAGS -Wdeclaration-after-statement -Werror=declaration-after-statement" -- fi -+ #if test x$have_gcc_declaration_after_statement = xyes; then -+ # EXTRA_CFLAGS="$EXTRA_CFLAGS -Wdeclaration-after-statement -Werror=declaration-after-statement" -+ #fi - } - - CheckWarnAll() diff --git a/patch/msdk_limits.patch b/patch/msdk_limits.patch deleted file mode 100644 index 13fc9b33..00000000 --- a/patch/msdk_limits.patch +++ /dev/null @@ -1,15 +0,0 @@ -# https://github.com/Intel-Media-SDK/MediaSDK/commit/aa4dfc524e1dd4cb33a88fa453de1eef50a39ed7 -# Ubuntu 22.04 上でのビルドでエラーになったのでこのコミットを適用する - -diff --git a/_studio/mfx_lib/mctf_package/mctf/src/mctf_common.cpp b/_studio/mfx_lib/mctf_package/mctf/src/mctf_common.cpp -index 49f114c792..b2fb722872 100644 ---- a/_studio/mfx_lib/mctf_package/mctf/src/mctf_common.cpp -+++ b/_studio/mfx_lib/mctf_package/mctf/src/mctf_common.cpp -@@ -44,6 +44,7 @@ - #include - #include - #include -+#include - #include "cmrt_cross_platform.h" - - using std::min; \ No newline at end of file diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 00000000..71de8682 --- /dev/null +++ b/ruff.toml @@ -0,0 +1 @@ +line-length = 100 diff --git a/run.py b/run.py new file mode 100644 index 00000000..4ae39b82 --- /dev/null +++ b/run.py @@ -0,0 +1,604 @@ +import argparse +import hashlib +import logging +import multiprocessing +import os +import shutil +import tarfile +import zipfile +from typing import List, Optional + +from buildbase import ( + Platform, + add_path, + add_webrtc_build_arguments, + build_and_install_boost, + build_webrtc, + cd, + cmake_path, + cmd, + cmdcap, + enum_all_files, + get_macos_osver, + get_webrtc_info, + get_webrtc_platform, + get_windows_osver, + install_cli11, + install_cmake, + install_cuda_windows, + install_llvm, + install_openh264, + install_rootfs, + install_sdl2, + install_vpl, + install_webrtc, + mkdir_p, + read_version_file, + rm_rf, +) + +logging.basicConfig(level=logging.DEBUG) + + +BASE_DIR = os.path.abspath(os.path.dirname(__file__)) + + +def install_deps( + platform: Platform, + source_dir: str, + build_dir: str, + install_dir: str, + debug: bool, + local_webrtc_build_dir: Optional[str], + local_webrtc_build_args: List[str], +): + with cd(BASE_DIR): + version = read_version_file("VERSION") + + # multistrap を使った sysroot の構築 + if platform.target.os == "jetson" or platform.target.os == "raspberry-pi-os": + conf = os.path.join(BASE_DIR, "multistrap", f"{platform.target.package_name}.conf") + # conf ファイルのハッシュ値をバージョンとする + version_md5 = hashlib.md5(open(conf, "rb").read()).hexdigest() + install_rootfs_args = { + "version": version_md5, + "version_file": os.path.join(install_dir, "rootfs.version"), + "install_dir": install_dir, + "conf": conf, + "arch": "arm64", + } + install_rootfs(**install_rootfs_args) + + # WebRTC + webrtc_platform = get_webrtc_platform(platform) + + if local_webrtc_build_dir is None: + install_webrtc_args = { + "version": version["WEBRTC_BUILD_VERSION"], + "version_file": os.path.join(install_dir, "webrtc.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": webrtc_platform, + } + + install_webrtc(**install_webrtc_args) + else: + build_webrtc_args = { + "platform": webrtc_platform, + "local_webrtc_build_dir": local_webrtc_build_dir, + "local_webrtc_build_args": local_webrtc_build_args, + "debug": debug, + } + + build_webrtc(**build_webrtc_args) + + webrtc_info = get_webrtc_info(webrtc_platform, local_webrtc_build_dir, install_dir, debug) + webrtc_version = read_version_file(webrtc_info.version_file) + webrtc_deps = read_version_file(webrtc_info.deps_file) + + # Windows は MSVC を使うので不要 + # macOS は Apple Clang を使うので不要 + if platform.target.os not in ("windows", "macos") and local_webrtc_build_dir is None: + # LLVM + tools_url = webrtc_version["WEBRTC_SRC_TOOLS_URL"] + tools_commit = webrtc_version["WEBRTC_SRC_TOOLS_COMMIT"] + libcxx_url = webrtc_version["WEBRTC_SRC_THIRD_PARTY_LIBCXX_SRC_URL"] + libcxx_commit = webrtc_version["WEBRTC_SRC_THIRD_PARTY_LIBCXX_SRC_COMMIT"] + buildtools_url = webrtc_version["WEBRTC_SRC_BUILDTOOLS_URL"] + buildtools_commit = webrtc_version["WEBRTC_SRC_BUILDTOOLS_COMMIT"] + install_llvm_args = { + "version": f"{tools_url}.{tools_commit}." + f"{libcxx_url}.{libcxx_commit}." + f"{buildtools_url}.{buildtools_commit}", + "version_file": os.path.join(install_dir, "llvm.version"), + "install_dir": install_dir, + "tools_url": tools_url, + "tools_commit": tools_commit, + "libcxx_url": libcxx_url, + "libcxx_commit": libcxx_commit, + "buildtools_url": buildtools_url, + "buildtools_commit": buildtools_commit, + } + install_llvm(**install_llvm_args) + + # Boost + install_boost_args = { + "version": version["BOOST_VERSION"], + "version_file": os.path.join(install_dir, "boost.version"), + "source_dir": source_dir, + "build_dir": build_dir, + "install_dir": install_dir, + "cxx": "", + "cflags": [], + "cxxflags": [], + "linkflags": [], + "toolset": "", + "visibility": "global", + "target_os": "", + "debug": debug, + "android_ndk": "", + "native_api_level": "", + "architecture": "x86", + "address_model": "64", + } + if platform.target.os == "windows": + install_boost_args["cxxflags"] = ["-D_ITERATOR_DEBUG_LEVEL=0"] + install_boost_args["toolset"] = "msvc" + install_boost_args["target_os"] = "windows" + elif platform.target.os == "macos": + sysroot = cmdcap(["xcrun", "--sdk", "macosx", "--show-sdk-path"]) + install_boost_args["target_os"] = "darwin" + install_boost_args["toolset"] = "clang" + install_boost_args["cxx"] = "clang++" + install_boost_args["cflags"] = [ + f"--sysroot={sysroot}", + f"-mmacosx-version-min={webrtc_deps['MACOS_DEPLOYMENT_TARGET']}", + ] + install_boost_args["cxxflags"] = [ + "-fPIC", + f"--sysroot={sysroot}", + "-std=gnu++17", + f"-mmacosx-version-min={webrtc_deps['MACOS_DEPLOYMENT_TARGET']}", + ] + install_boost_args["visibility"] = "hidden" + if platform.target.arch == "x86_64": + install_boost_args["cflags"].extend(["-target", "x86_64-apple-darwin"]) + install_boost_args["cxxflags"].extend(["-target", "x86_64-apple-darwin"]) + install_boost_args["architecture"] = "x86" + if platform.target.arch == "arm64": + install_boost_args["cflags"].extend(["-target", "aarch64-apple-darwin"]) + install_boost_args["cxxflags"].extend(["-target", "aarch64-apple-darwin"]) + install_boost_args["architecture"] = "arm" + elif platform.target.os in ("jetson", "raspberry-pi-os"): + triplet = "aarch64-linux-gnu" + sysroot = os.path.join(install_dir, "rootfs") + install_boost_args["target_os"] = "linux" + install_boost_args["cxx"] = os.path.join(webrtc_info.clang_dir, "bin", "clang++") + install_boost_args["cflags"] = [ + "-fPIC", + f"--sysroot={sysroot}", + f"--target={triplet}", + f"-I{os.path.join(sysroot, 'usr', 'include', triplet)}", + ] + install_boost_args["cxxflags"] = [ + "-fPIC", + f"--target={triplet}", + f"--sysroot={sysroot}", + f"-I{os.path.join(sysroot, 'usr', 'include', triplet)}", + "-D_LIBCPP_ABI_NAMESPACE=Cr", + "-D_LIBCPP_ABI_VERSION=2", + "-D_LIBCPP_DISABLE_AVAILABILITY", + "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE", + "-nostdinc++", + "-std=gnu++17", + f"-isystem{os.path.join(webrtc_info.libcxx_dir, 'include')}", + ] + install_boost_args["linkflags"] = [ + f"-L{os.path.join(sysroot, 'usr', 'lib', triplet)}", + f"-B{os.path.join(sysroot, 'usr', 'lib', triplet)}", + ] + install_boost_args["toolset"] = "clang" + install_boost_args["architecture"] = "arm" + else: + install_boost_args["target_os"] = "linux" + install_boost_args["cxx"] = os.path.join(webrtc_info.clang_dir, "bin", "clang++") + install_boost_args["cxxflags"] = [ + "-D_LIBCPP_ABI_NAMESPACE=Cr", + "-D_LIBCPP_ABI_VERSION=2", + "-D_LIBCPP_DISABLE_AVAILABILITY", + "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE", + "-nostdinc++", + f"-isystem{os.path.join(webrtc_info.libcxx_dir, 'include')}", + "-fPIC", + ] + install_boost_args["toolset"] = "clang" + + build_and_install_boost(**install_boost_args) + + # CMake + install_cmake_args = { + "version": version["CMAKE_VERSION"], + "version_file": os.path.join(install_dir, "cmake.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "platform": "", + "ext": "tar.gz", + } + if platform.build.os == "windows" and platform.build.arch == "x86_64": + install_cmake_args["platform"] = "windows-x86_64" + install_cmake_args["ext"] = "zip" + elif platform.build.os == "macos": + install_cmake_args["platform"] = "macos-universal" + elif platform.build.os == "ubuntu" and platform.build.arch == "x86_64": + install_cmake_args["platform"] = "linux-x86_64" + elif platform.build.os == "ubuntu" and platform.build.arch == "arm64": + install_cmake_args["platform"] = "linux-aarch64" + else: + raise Exception("Failed to install CMake") + install_cmake(**install_cmake_args) + + if platform.build.os == "macos": + add_path(os.path.join(install_dir, "cmake", "CMake.app", "Contents", "bin")) + else: + add_path(os.path.join(install_dir, "cmake", "bin")) + + # CUDA + if platform.target.os == "windows": + install_cuda_args = { + "version": version["CUDA_VERSION"], + "version_file": os.path.join(install_dir, "cuda.version"), + "source_dir": source_dir, + "build_dir": build_dir, + "install_dir": install_dir, + } + install_cuda_windows(**install_cuda_args) + + # Intel oneVPL + if platform.target.os in ("windows", "ubuntu") and platform.target.arch == "x86_64": + install_vpl_args = { + "version": version["VPL_VERSION"], + "version_file": os.path.join(install_dir, "vpl.version"), + "configuration": "Debug" if debug else "Release", + "source_dir": source_dir, + "build_dir": build_dir, + "install_dir": install_dir, + "cmake_args": [], + } + if platform.target.os == "windows": + cxxflags = [ + "/DWIN32", + "/D_WINDOWS", + "/W3", + "/GR", + "/EHsc", + "/D_ITERATOR_DEBUG_LEVEL=0", + ] + install_vpl_args["cmake_args"].append(f"-DCMAKE_CXX_FLAGS={' '.join(cxxflags)}") + if platform.target.os == "ubuntu": + cmake_args = [] + cmake_args.append("-DCMAKE_C_COMPILER=clang-18") + cmake_args.append("-DCMAKE_CXX_COMPILER=clang++-18") + path = cmake_path(os.path.join(webrtc_info.libcxx_dir, "include")) + cmake_args.append(f"-DCMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES={path}") + flags = [ + "-nostdinc++", + "-D_LIBCPP_ABI_NAMESPACE=Cr", + "-D_LIBCPP_ABI_VERSION=2", + "-D_LIBCPP_DISABLE_AVAILABILITY", + "-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS", + "-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS", + "-D_LIBCPP_ENABLE_NODISCARD", + "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE", + ] + cmake_args.append(f"-DCMAKE_CXX_FLAGS={' '.join(flags)}") + install_vpl_args["cmake_args"] += cmake_args + install_vpl(**install_vpl_args) + + # SDL2 + install_sdl2_args = { + "version": version["SDL2_VERSION"], + "version_file": os.path.join(install_dir, "sdl2.version"), + "source_dir": source_dir, + "build_dir": build_dir, + "install_dir": install_dir, + "platform": "", + "debug": debug, + "cmake_args": [], + } + if platform.target.os == "windows": + install_sdl2_args["platform"] = "windows" + elif platform.target.os == "macos": + install_sdl2_args["platform"] = "macos" + elif platform.target.os == "ubuntu": + install_sdl2_args["platform"] = "linux" + elif platform.target.os in ("jetson", "raspberry-pi-os"): + install_sdl2_args["platform"] = "linux" + triplet = "aarch64-linux-gnu" + arch = "aarch64" + sysroot = os.path.join(install_dir, "rootfs") + install_sdl2_args["cmake_args"] = [ + "-DCMAKE_SYSTEM_NAME=Linux", + f"-DCMAKE_SYSTEM_PROCESSOR={arch}", + f"-DCMAKE_C_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang')}", + f"-DCMAKE_C_COMPILER_TARGET={triplet}", + f"-DCMAKE_CXX_COMPILER={os.path.join(webrtc_info.clang_dir, 'bin', 'clang++')}", + f"-DCMAKE_CXX_COMPILER_TARGET={triplet}", + f"-DCMAKE_FIND_ROOT_PATH={sysroot}", + "-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER", + "-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH", + "-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH", + "-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH", + f"-DCMAKE_SYSROOT={sysroot}", + ] + else: + raise Exception("Not supported platform") + + install_sdl2(**install_sdl2_args) + + # CLI11 + install_cli11_args = { + "version": version["CLI11_VERSION"], + "version_file": os.path.join(install_dir, "cli11.version"), + "install_dir": install_dir, + } + install_cli11(**install_cli11_args) + + # OpenH264 + install_openh264_args = { + "version": version["OPENH264_VERSION"], + "version_file": os.path.join(install_dir, "openh264.version"), + "source_dir": source_dir, + "install_dir": install_dir, + "is_windows": platform.target.os == 'windows', + } + install_openh264(**install_openh264_args) + + +AVAILABLE_TARGETS = [ + "windows_x86_64", + "macos_x86_64", + "macos_arm64", + "ubuntu-22.04_x86_64", + "ubuntu-24.04_x86_64", + "raspberry-pi-os_armv8", + "ubuntu-22.04_armv8_jetson", +] +WINDOWS_SDK_VERSION = "10.0.20348.0" + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("target", choices=AVAILABLE_TARGETS) + parser.add_argument("--debug", action="store_true") + parser.add_argument("--relwithdebinfo", action="store_true") + add_webrtc_build_arguments(parser) + parser.add_argument("--package", action="store_true") + + args = parser.parse_args() + if args.target == "windows_x86_64": + platform = Platform("windows", get_windows_osver(), "x86_64") + elif args.target == "macos_x86_64": + platform = Platform("macos", get_macos_osver(), "x86_64") + elif args.target == "macos_arm64": + platform = Platform("macos", get_macos_osver(), "arm64") + elif args.target == "ubuntu-22.04_x86_64": + platform = Platform("ubuntu", "22.04", "x86_64") + elif args.target == "ubuntu-24.04_x86_64": + platform = Platform("ubuntu", "24.04", "x86_64") + elif args.target == "raspberry-pi-os_armv8": + platform = Platform("raspberry-pi-os", None, "armv8") + elif args.target == "ubuntu-22.04_armv8_jetson": + platform = Platform("jetson", None, "armv8", extra="ubuntu-22.04") + else: + raise Exception(f"Unknown target {args.target}") + + logging.info(f"Build platform: {platform.build.package_name}") + logging.info(f"Target platform: {platform.target.package_name}") + + configuration = "debug" if args.debug else "release" + dir = platform.target.package_name + source_dir = os.path.join(BASE_DIR, "_source", dir, configuration) + build_dir = os.path.join(BASE_DIR, "_build", dir, configuration) + install_dir = os.path.join(BASE_DIR, "_install", dir, configuration) + package_dir = os.path.join(BASE_DIR, "_package", dir, configuration) + mkdir_p(source_dir) + mkdir_p(build_dir) + mkdir_p(install_dir) + + install_deps( + platform, + source_dir, + build_dir, + install_dir, + args.debug, + local_webrtc_build_dir=args.local_webrtc_build_dir, + local_webrtc_build_args=args.local_webrtc_build_args, + ) + + configuration = "Release" + if args.debug: + configuration = "Debug" + if args.relwithdebinfo: + configuration = "RelWithDebInfo" + + momo_build_dir = os.path.join(build_dir, "momo") + mkdir_p(momo_build_dir) + with cd(momo_build_dir): + cmake_args = [] + cmake_args.append(f"-DCMAKE_BUILD_TYPE={configuration}") + cmake_args.append(f"-DCMAKE_INSTALL_PREFIX={cmake_path(os.path.join(install_dir, 'momo'))}") + cmake_args.append(f"-DBOOST_ROOT={cmake_path(os.path.join(install_dir, 'boost'))}") + webrtc_platform = get_webrtc_platform(platform) + webrtc_info = get_webrtc_info( + webrtc_platform, args.local_webrtc_build_dir, install_dir, args.debug + ) + webrtc_version = read_version_file(webrtc_info.version_file) + webrtc_deps = read_version_file(webrtc_info.deps_file) + with cd(BASE_DIR): + version = read_version_file("VERSION") + momo_version = version["MOMO_VERSION"] + momo_commit = cmdcap(["git", "rev-parse", "HEAD"]) + cmake_args.append(f"-DWEBRTC_INCLUDE_DIR={cmake_path(webrtc_info.webrtc_include_dir)}") + cmake_args.append(f"-DWEBRTC_LIBRARY_DIR={cmake_path(webrtc_info.webrtc_library_dir)}") + cmake_args.append(f"-DMOMO_VERSION={momo_version}") + cmake_args.append(f"-DMOMO_COMMIT={momo_commit}") + cmake_args.append(f"-DMOMO_TARGET={platform.target.package_name}") + cmake_args.append(f"-DWEBRTC_BUILD_VERSION={webrtc_version['WEBRTC_BUILD_VERSION']}") + cmake_args.append(f"-DWEBRTC_READABLE_VERSION={webrtc_version['WEBRTC_READABLE_VERSION']}") + cmake_args.append(f"-DWEBRTC_COMMIT={webrtc_version['WEBRTC_COMMIT']}") + if platform.target.os == "windows": + cmake_args.append(f"-DCMAKE_SYSTEM_VERSION={WINDOWS_SDK_VERSION}") + if platform.target.os == "ubuntu": + if platform.target.package_name in ("ubuntu-22.04_x86_64", "ubuntu-24.04_x86_64"): + cmake_args.append("-DCMAKE_C_COMPILER=clang-18") + cmake_args.append("-DCMAKE_CXX_COMPILER=clang++-18") + else: + cmake_args.append( + f"-DCMAKE_C_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang'))}" + ) + cmake_args.append( + f"-DCMAKE_CXX_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang++'))}" + ) + cmake_args.append("-DUSE_LIBCXX=ON") + cmake_args.append( + f"-DLIBCXX_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxx_dir, 'include'))}" + ) + if platform.target.os == "macos": + sysroot = cmdcap(["xcrun", "--sdk", "macosx", "--show-sdk-path"]) + target = ( + "x86_64-apple-darwin" + if platform.target.arch == "x86_64" + else "aarch64-apple-darwin" + ) + cmake_args.append(f"-DCMAKE_SYSTEM_PROCESSOR={platform.target.arch}") + cmake_args.append(f"-DCMAKE_OSX_ARCHITECTURES={platform.target.arch}") + cmake_args.append( + f"-DCMAKE_OSX_DEPLOYMENT_TARGET={webrtc_deps['MACOS_DEPLOYMENT_TARGET']}" + ) + cmake_args.append(f"-DCMAKE_C_COMPILER_TARGET={target}") + cmake_args.append(f"-DCMAKE_CXX_COMPILER_TARGET={target}") + cmake_args.append(f"-DCMAKE_OBJCXX_COMPILER_TARGET={target}") + cmake_args.append(f"-DCMAKE_SYSROOT={sysroot}") + if platform.target.os in ("jetson", "raspberry-pi-os"): + triplet = "aarch64-linux-gnu" + arch = "aarch64" + sysroot = os.path.join(install_dir, "rootfs") + cmake_args.append("-DCMAKE_SYSTEM_NAME=Linux") + cmake_args.append(f"-DCMAKE_SYSTEM_PROCESSOR={arch}") + cmake_args.append(f"-DCMAKE_SYSROOT={sysroot}") + cmake_args.append(f"-DCMAKE_C_COMPILER_TARGET={triplet}") + cmake_args.append(f"-DCMAKE_CXX_COMPILER_TARGET={triplet}") + cmake_args.append(f"-DCMAKE_FIND_ROOT_PATH={sysroot}") + cmake_args.append("-DUSE_LIBCXX=ON") + cmake_args.append( + f"-DLIBCXX_INCLUDE_DIR={cmake_path(os.path.join(webrtc_info.libcxx_dir, 'include'))}" + ) + cmake_args.append( + f"-DCMAKE_C_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang'))}" + ) + cmake_args.append( + f"-DCMAKE_CXX_COMPILER={cmake_path(os.path.join(webrtc_info.clang_dir, 'bin', 'clang++'))}" + ) + if platform.target.os == "jetson": + cmake_args.append("-DUSE_JETSON_ENCODER=ON") + if platform.target.os == "raspberry-pi-os": + cmake_args.append("-DUSE_V4L2_ENCODER=ON") + + # スクリーンキャプチャ + if platform.target.package_name in ( + "windows_x86_64", + "macos_x86_64", + "macos_arm64", + "ubuntu-22.04_x86_64", + "ubuntu-24.04_x86_64", + ): + cmake_args.append("-DUSE_SCREEN_CAPTURER=ON") + + # NvCodec + if platform.target.os in ("windows", "ubuntu") and platform.target.arch == "x86_64": + cmake_args.append("-DUSE_NVCODEC_ENCODER=ON") + if platform.target.os == "windows": + cmake_args.append( + f"-DCUDA_TOOLKIT_ROOT_DIR={cmake_path(os.path.join(install_dir, 'cuda'))}" + ) + + if platform.target.os in ("windows", "ubuntu") and platform.target.arch == "x86_64": + cmake_args.append("-DUSE_VPL_ENCODER=ON") + cmake_args.append(f"-DVPL_ROOT_DIR={cmake_path(os.path.join(install_dir, 'vpl'))}") + + cmake_args.append(f"-DSDL2_ROOT_DIR={os.path.join(install_dir, 'sdl2')}") + cmake_args.append(f"-DCLI11_ROOT_DIR={os.path.join(install_dir, 'cli11')}") + cmake_args.append(f"-DOPENH264_ROOT_DIR={os.path.join(install_dir, 'openh264')}") + + cmd(["cmake", BASE_DIR] + cmake_args) + cmd( + [ + "cmake", + "--build", + ".", + f"-j{multiprocessing.cpu_count()}", + "--config", + configuration, + ] + ) + cmd(["cmake", "--install", ".", "--config", configuration]) + + if args.package: + # 必要なファイルをコピー + with cd(BASE_DIR): + momo_install_dir = os.path.join(install_dir, "momo") + momo_build_dir = os.path.join(build_dir, "momo") + rm_rf(momo_install_dir) + mkdir_p(momo_install_dir) + if platform.target.os == "windows": + shutil.copyfile( + os.path.join(momo_build_dir, "Release", "momo.exe"), + os.path.join(momo_install_dir, "momo.exe"), + ) + else: + shutil.copyfile( + os.path.join(momo_build_dir, "momo"), os.path.join(momo_install_dir, "momo") + ) + shutil.copyfile("LICENSE", os.path.join(momo_install_dir, "LICENSE")) + shutil.copyfile("NOTICE", os.path.join(momo_install_dir, "NOTICE")) + shutil.copytree("html", os.path.join(momo_install_dir, "html")) + if os.path.exists(os.path.join(momo_build_dir, "libcamerac.so")): + shutil.copyfile( + os.path.join(momo_build_dir, "libcamerac.so"), + os.path.join(momo_install_dir, "libcamerac.so"), + ) + + mkdir_p(package_dir) + rm_rf(os.path.join(package_dir, "momo")) + rm_rf(os.path.join(package_dir, "momo.env")) + + with cd(BASE_DIR): + version = read_version_file("VERSION") + momo_version = version["MOMO_VERSION"] + + def archive(archive_path, files, is_windows): + if is_windows: + with zipfile.ZipFile(archive_path, "w") as f: + for file in files: + f.write(filename=file, arcname=file) + else: + with tarfile.open(archive_path, "w:gz") as f: + for file in files: + f.add(name=file, arcname=file) + + ext = "zip" if platform.target.os == "windows" else "tar.gz" + is_windows = platform.target.os == "windows" + content_type = "application/zip" if platform.target.os == "windows" else "application/gzip" + + with cd(install_dir): + archive_name = f"momo-{momo_version}_{platform.target.package_name}.{ext}" + archive_path = os.path.join(package_dir, archive_name) + archive(archive_path, enum_all_files("momo", "."), is_windows) + + with open(os.path.join(package_dir, "momo.env"), "w") as f: + f.write(f"CONTENT_TYPE={content_type}\n") + f.write(f"PACKAGE_NAME={archive_name}\n") + + +if __name__ == "__main__": + main() diff --git a/script/apt_install_arm.sh b/script/apt_install_arm.sh deleted file mode 100755 index c4ef912b..00000000 --- a/script/apt_install_arm.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -apt-get update -apt-get -y upgrade - -# Ubuntu 18.04 では tzdata を noninteractive にしないと実行が止まってしまう -apt-get -y install tzdata -echo 'Asia/Tokyo' > /etc/timezone -dpkg-reconfigure -f noninteractive tzdata - -DEBIAN_FRONTEND=noninteractive apt-get -y install \ - binutils-aarch64-linux-gnu \ - binutils-arm-linux-gnueabi \ - binutils-arm-linux-gnueabihf \ - build-essential \ - curl \ - g++-multilib \ - git \ - gtk+-3.0 \ - lbzip2 \ - libgtk-3-dev \ - lsb-release \ - multistrap \ - python \ - rsync \ - sudo \ - vim \ - xz-utils - -# Ubuntu 18.04 で multistrap が動かない問題の修正。 -# https://github.com/volumio/Build/issues/348#issuecomment-462271607 を参照 -sed -e 's/Apt::Get::AllowUnauthenticated=true/Apt::Get::AllowUnauthenticated=true";\n$config_str .= " -o Acquire::AllowInsecureRepositories=true/' -i /usr/sbin/multistrap diff --git a/script/apt_install_x86_64.sh b/script/apt_install_x86_64.sh deleted file mode 100755 index 471c33ab..00000000 --- a/script/apt_install_x86_64.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -apt-get update -apt-get -y upgrade - -# Ubuntu 18.04 では tzdata を noninteractive にしないと実行が止まってしまう -apt-get -y install tzdata -echo 'Asia/Tokyo' > /etc/timezone -dpkg-reconfigure -f noninteractive tzdata - -# libtinfo5 は Ubuntu 20.04 のために入れたが将来的に不要になる可能性がある -DEBIAN_FRONTEND=noninteractive apt-get -y install \ - autoconf \ - automake \ - build-essential \ - curl \ - git \ - libasound2-dev \ - libc6-dev \ - libexpat1-dev \ - libgtk-3-dev \ - libnspr4-dev \ - libnss3-dev \ - libpulse-dev \ - libtinfo5 \ - libtool \ - libudev-dev \ - libxrandr-dev \ - lsb-release \ - python3 \ - python3-dev \ - rsync \ - sudo \ - vim \ - wget diff --git a/script/docker_run.sh b/script/docker_run.sh deleted file mode 100755 index 517d114a..00000000 --- a/script/docker_run.sh +++ /dev/null @@ -1,196 +0,0 @@ -#!/bin/bash - -set -e - -# ヘルプ表示 -function show_help() { - echo "" - echo "$0 <作業ディレクトリ> <マウントタイプ [mount | nomount]> <パッケージ名> " - echo "" -} - -# 引数のチェック -if [ $# -ne 6 ]; then - show_help - exit 1 -fi - -WORK_DIR="$1" -MOMO_DIR="$2" -MOUNT_TYPE="$3" -PACKAGE_NAME="$4" -DOCKER_IMAGE="$5" -MOMO_COMMIT="$6" - -if [ -z "$WORK_DIR" ]; then - echo "エラー: <作業ディレクトリ> が空です" - show_help - exit 1 -fi - -if [ -z "$MOMO_DIR" ]; then - echo "エラー: が空です" - show_help - exit 1 -fi - -if [ ! -e "$MOMO_DIR/.git" ]; then - echo "エラー: $MOMO_DIR は Git リポジトリのルートディレクトリではありません" - show_help - exit 1 -fi - -if [ "$MOUNT_TYPE" != "mount" -a "$MOUNT_TYPE" != "nomount" ]; then - echo "エラー: <マウントタイプ> は mount または nomount である必要があります" - show_help - exit 1 -fi - -if [ -z "$PACKAGE_NAME" ]; then - echo "エラー: <パッケージ名> が空です" - show_help - exit 1 -fi - -if [ -z "$(docker images -q $DOCKER_IMAGE)" ]; then - echo "エラー: $DOCKER_IMAGE が存在しません" - show_help - exit 1 -fi - -if [ -z "$MOMO_COMMIT" ]; then - echo "エラー: が空です" - show_help - exit 1 -fi - -if [ ! -e "$MOMO_DIR/VERSION" ]; then - echo "エラー: $MOMO_DIR/VERSION が存在しません" - exit 1 -fi - -source $MOMO_DIR/VERSION - -DOCKER_PLATFORM="" -if [ "`uname -sm`" = "Darwin arm64" ]; then - # M1 Mac の場合は --platform を指定する - DOCKER_PLATFORM="--platform=linux/amd64" -fi - - -# マウントするかどうかで大きく分岐する -if [ "$MOUNT_TYPE" = "mount" ]; then - # マウントする場合は、単純にマウントしてビルドするだけ - docker run \ - $DOCKER_PLATFORM \ - -it \ - --rm \ - -v "$WORK_DIR/..:/root/momo" \ - "$DOCKER_IMAGE" \ - /bin/bash -c " - set -ex - source /root/webrtc/VERSIONS - mkdir -p /root/momo/_build/$PACKAGE_NAME - pushd /root/momo/_build/$PACKAGE_NAME - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DMOMO_PACKAGE_NAME=$PACKAGE_NAME \ - -DMOMO_VERSION=$MOMO_VERSION \ - -DMOMO_COMMIT=$MOMO_COMMIT \ - -DWEBRTC_BUILD_VERSION=$WEBRTC_BUILD_VERSION \ - -DWEBRTC_READABLE_VERSION=\$WEBRTC_READABLE_VERSION \ - -DWEBRTC_COMMIT=\$WEBRTC_COMMIT \ - ../.. - if [ -n \"$VERBOSE\" ]; then - export VERBOSE=$VERBOSE - fi - cmake --build . -j\$(nproc) - popd - " -else - # マウントしない場合は、コンテナを起動して、コンテナに必要なファイルを転送して、コンテナ上でビルドして、生成されたファイルをコンテナから戻して、コンテナを終了する - - pushd $MOMO_DIR - if git diff-index --quiet HEAD --; then - : - else - # ローカルの変更があるので確認する - git status - read -p "ローカルの変更があります。これらの変更はビルドに反映されません。続行しますか? (y/N): " yn - case "$yn" in - [yY]*) - ;; - *) - exit 1 - ;; - esac - fi - popd - - pushd $WORK_DIR - # 途中でエラーが起きても確実にコンテナを後片付けする - trap "set +e; docker container stop momo-$PACKAGE_NAME; docker container rm momo-$PACKAGE_NAME" 0 - - # ベースイメージから構築したコンテナに転送してビルドし、 - # ビルドが完了したら成果物や中間ファイルを取り出す - docker container create $DOCKER_PLATFORM -it --name momo-$PACKAGE_NAME "$DOCKER_IMAGE" - docker container start momo-$PACKAGE_NAME - - # 転送用の momo のソースを生成(中間ファイルも含める) - rm -rf momo - git clone $MOMO_DIR momo - - # 中間ファイルのコピー - mkdir -p $MOMO_DIR/_build - if [ -e $MOMO_DIR/_build/$PACKAGE_NAME ]; then - mkdir -p momo/_build - cp -r $MOMO_DIR/_build/$PACKAGE_NAME momo/_build/$PACKAGE_NAME - fi - - # 更新日時を元ファイルに合わせる - pushd momo - find . -type f | while read file; do - if [ -e "$MOMO_DIR/$file" ]; then - # -c: ファイルを生成しない - # -m: 更新日時を更新 - # -r : このファイルの日時に合わせる - touch -c -m -r "$MOMO_DIR/$file" "$file" - fi - done - popd - - tar czf momo.tar.gz momo - rm -rf momo - - # ソースを転送して Docker の中でビルドする - docker container cp momo.tar.gz momo-$PACKAGE_NAME:/root/ - rm momo.tar.gz - - docker container exec momo-$PACKAGE_NAME /bin/bash -c 'cd /root && tar xf momo.tar.gz && rm momo.tar.gz' - docker container exec momo-$PACKAGE_NAME \ - /bin/bash -c " - set -ex - source /root/webrtc/VERSIONS - mkdir -p /root/momo/_build/$PACKAGE_NAME - pushd /root/momo/_build/$PACKAGE_NAME - cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DMOMO_PACKAGE_NAME=$PACKAGE_NAME \ - -DMOMO_VERSION=$MOMO_VERSION \ - -DMOMO_COMMIT=$MOMO_COMMIT \ - -DWEBRTC_BUILD_VERSION=$WEBRTC_BUILD_VERSION \ - -DWEBRTC_READABLE_VERSION=\$WEBRTC_READABLE_VERSION \ - -DWEBRTC_COMMIT=\$WEBRTC_COMMIT \ - ../.. - if [ -n \"$VERBOSE\" ]; then - export VERBOSE=$VERBOSE - fi - cmake --build . -j\$(nproc) - popd - " - - # 中間ファイル類を取り出す - rm -rf $MOMO_DIR/_build/$PACKAGE_NAME - docker container cp momo-$PACKAGE_NAME:/root/momo/_build/$PACKAGE_NAME/ $MOMO_DIR/_build/$PACKAGE_NAME - popd -fi diff --git a/script/get_cmake.sh b/script/get_cmake.sh deleted file mode 100755 index 869c230b..00000000 --- a/script/get_cmake.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -# には Linux か Darwin を指定する -# /cmake に CMake が配置される -if [ $# -lt 3 ]; then - echo "$0 " - exit 1 -fi - -CMAKE_VERSION=$1 -PLATFORM=$2 -OUTPUT_DIR=$3 - -set -ex - -pushd $OUTPUT_DIR - curl -LO https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}-${PLATFORM}-x86_64.tar.gz - tar xf cmake-${CMAKE_VERSION}-${PLATFORM}-x86_64.tar.gz - rm cmake-${CMAKE_VERSION}-${PLATFORM}-x86_64.tar.gz - rm -rf cmake - mv cmake-${CMAKE_VERSION}-${PLATFORM}-x86_64 cmake -popd diff --git a/script/get_llvm.sh b/script/get_llvm.sh deleted file mode 100755 index 410554a7..00000000 --- a/script/get_llvm.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash - -# WebRTC のビルドに使っていたのと同じバージョンの clang と libcxx を拾ってくる。 -# -# 以下の構成になる。 -# /llvm/clang -# /llvm/libcxx -# /llvm/tools -if [ $# -lt 2 ]; then - echo "$0 " - exit 1 -fi - -WEBRTC_DIR=$1 -OUTPUT_DIR=$2 - -set -ex - -if [ -e $WEBRTC_DIR/VERSIONS ]; then - . $WEBRTC_DIR/VERSIONS -else - . $WEBRTC_DIR/release/VERSIONS -fi - -# tools の update.py を叩いて特定バージョンの clang バイナリを拾う -mkdir -p $OUTPUT_DIR/llvm -pushd $OUTPUT_DIR/llvm - if [ ! -e tools/.git ]; then - git clone $WEBRTC_SRC_TOOLS_URL - fi - pushd tools - git fetch - git reset --hard $WEBRTC_SRC_TOOLS_COMMIT - python3 clang/scripts/update.py --output-dir=$OUTPUT_DIR/llvm/clang - popd -popd - -# 特定バージョンの libcxx を利用する -pushd $OUTPUT_DIR/llvm - if [ ! -e libcxx/.git ]; then - git clone $WEBRTC_SRC_BUILDTOOLS_THIRD_PARTY_LIBCXX_TRUNK_URL - fi - pushd libcxx - git fetch - git reset --hard $WEBRTC_SRC_BUILDTOOLS_THIRD_PARTY_LIBCXX_TRUNK_COMMIT - popd -popd - -# __config_site のために特定バージョンの buildtools を取得する -pushd $OUTPUT_DIR/llvm - if [ ! -e buildtools/.git ]; then - git clone $WEBRTC_SRC_BUILDTOOLS_URL - fi - pushd buildtools - git fetch - git reset --hard $WEBRTC_SRC_BUILDTOOLS_COMMIT - popd - cp $OUTPUT_DIR/llvm/buildtools/third_party/libc++/__config_site $OUTPUT_DIR/llvm/libcxx/include/ -popd diff --git a/script/get_webrtc.sh b/script/get_webrtc.sh deleted file mode 100755 index d4d5b1c9..00000000 --- a/script/get_webrtc.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# /webrtc に WebRTC ライブラリが配置される -# ダウンロードしたファイルは / に配置される -if [ $# -lt 4 ]; then - echo "$0 " - exit 1 -fi - -WEBRTC_BUILD_VERSION=$1 -PACKAGE_NAME=$2 -OUTPUT_DIR=$3 -SOURCE_DIR=$4 - -set -ex - -if [ ! -e $SOURCE_DIR/webrtc.${PACKAGE_NAME}.${WEBRTC_BUILD_VERSION}.tar.gz ]; then - curl -Lo $SOURCE_DIR/webrtc.${PACKAGE_NAME}.${WEBRTC_BUILD_VERSION}.tar.gz https://github.com/shiguredo-webrtc-build/webrtc-build/releases/download/m${WEBRTC_BUILD_VERSION}/webrtc.${PACKAGE_NAME}.tar.gz -fi - -pushd $OUTPUT_DIR - tar xf $SOURCE_DIR/webrtc.${PACKAGE_NAME}.${WEBRTC_BUILD_VERSION}.tar.gz -popd diff --git a/script/init_rootfs_arm64.sh b/script/init_rootfs_arm64.sh deleted file mode 100755 index 4eedfde5..00000000 --- a/script/init_rootfs_arm64.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -if [ $# -lt 2 ]; then - echo "$0 " - exit 1 -fi - -TARGET_DIR=$1 -CONFIG_FILE=$2 - -set -ex - -multistrap --no-auth -a arm64 -d $TARGET_DIR -f $CONFIG_FILE -find $TARGET_DIR/usr/lib/aarch64-linux-gnu -lname '/*' -printf '%p %l\n' | while read link target; do ln -snfv "../../..${target}" "${link}"; done -find $TARGET_DIR/usr/lib/aarch64-linux-gnu/pkgconfig -printf "%f\n" | while read target; do ln -snfv "../../lib/aarch64-linux-gnu/pkgconfig/${target}" $TARGET_DIR/usr/share/pkgconfig/${target}; done -if [ -L $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/5/libgcc_s.so ]; then - unlink $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/5/libgcc_s.so - ln -s ../../../../../lib64/aarch64-linux-gnu/libgcc_s.so.1 $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/5/libgcc_s.so -elif [ -L $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/6/libgcc_s.so ]; then - unlink $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/6/libgcc_s.so - ln -s ../../../../../lib64/aarch64-linux-gnu/libgcc_s.so.1 $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/6/libgcc_s.so -elif [ -L $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/7/libgcc_s.so ]; then - unlink $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/7/libgcc_s.so - ln -s ../../../../../lib64/aarch64-linux-gnu/libgcc_s.so.1 $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/7/libgcc_s.so -elif [ -L $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/8/libgcc_s.so ]; then - unlink $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/8/libgcc_s.so - if [ -e $TARGET_DIR/lib64/aarch64-linux-gnu/libgcc_s.so.1 ]; then - ln -s ../../../../../lib64/aarch64-linux-gnu/libgcc_s.so.1 $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/8/libgcc_s.so - elif [ -e $TARGET_DIR/lib/aarch64-linux-gnu/libgcc_s.so.1 ]; then - ln -s ../../../../../lib/aarch64-linux-gnu/libgcc_s.so.1 $TARGET_DIR/usr/lib/gcc/aarch64-linux-gnu/8/libgcc_s.so - fi -fi diff --git a/script/init_rootfs_armhf.sh b/script/init_rootfs_armhf.sh deleted file mode 100755 index 5762a896..00000000 --- a/script/init_rootfs_armhf.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -if [ $# -lt 2 ]; then - echo "$0 " - exit 1 -fi - -TARGET_DIR=$1 -CONFIG_FILE=$2 - -set -ex - -multistrap --no-auth -a armhf -d $TARGET_DIR -f $CONFIG_FILE - -find $TARGET_DIR/usr/lib/arm-linux-gnueabihf -lname '/*' -printf '%p %l\n' | while read link target; do ln -snfv "../../..${target}" "${link}"; done -find $TARGET_DIR/usr/lib/arm-linux-gnueabihf/pkgconfig -printf "%f\n" | while read target; do ln -snfv "../../lib/arm-linux-gnueabihf/pkgconfig/${target}" $TARGET_DIR/usr/share/pkgconfig/${target}; done diff --git a/script/setup_boost.sh b/script/setup_boost.sh deleted file mode 100755 index e90f56d7..00000000 --- a/script/setup_boost.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -# 指定した Boost のバージョンをダウンロードして、b2 を実行できる状態にする -# -# ソースコードは $2/source に配置される。 -# -# 引数: -# $1: Boost のバージョン -# $2: 出力ディレクトリ -# $3: キャッシュディレクトリ -if [ $# -lt 3 ]; then - echo "$0 " - exit 1 -fi - -BOOST_VERSION=$1 -BOOST_VERSION_UNDERSCORE=${BOOST_VERSION//./_} -OUTPUT_DIR=$2 -CACHE_DIR=$3 - -set -ex - -mkdir -p $OUTPUT_DIR -pushd $OUTPUT_DIR - if [ ! -e $CACHE_DIR/boost_$BOOST_VERSION_UNDERSCORE.tar.gz ]; then - mkdir -p $CACHE_DIR - curl -fLo $CACHE_DIR/boost_$BOOST_VERSION_UNDERSCORE.tar.gz https://boostorg.jfrog.io/artifactory/main/release/$BOOST_VERSION/source/boost_$BOOST_VERSION_UNDERSCORE.tar.gz - fi - - rm -rf source - rm -rf boost_$BOOST_VERSION_UNDERSCORE - tar xf $CACHE_DIR/boost_$BOOST_VERSION_UNDERSCORE.tar.gz - mv boost_$BOOST_VERSION_UNDERSCORE source - - pushd source - ./bootstrap.sh - popd -popd diff --git a/script/setup_sdl2.sh b/script/setup_sdl2.sh deleted file mode 100755 index 57c11cab..00000000 --- a/script/setup_sdl2.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# 指定した SDL2 のバージョンをダウンロードして、make を実行できる状態にする -# -# ソースコードは $2/source に配置される -# -# 引数: -# $1: SDL2 のバージョン -# $2: 出力ディレクトリ -if [ $# -lt 2 ]; then - echo "$0 " - exit 1 -fi - -SDL2_VERSION=$1 -OUTPUT_DIR=$2 - -mkdir -p $OUTPUT_DIR -pushd $OUTPUT_DIR - if [ ! -e SDL2-$SDL2_VERSION.tar.gz ]; then - curl -LO http://www.libsdl.org/release/SDL2-$SDL2_VERSION.tar.gz - fi - rm -rf source - rm -rf SDL2-$SDL2_VERSION - tar xf SDL2-$SDL2_VERSION.tar.gz - mv SDL2-$SDL2_VERSION source -popd diff --git a/src/cuda/cuda_context_cuda.cpp b/src/cuda/cuda_context_cuda.cpp deleted file mode 100644 index 6aece839..00000000 --- a/src/cuda/cuda_context_cuda.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "cuda_context_cuda.h" - -#include - -#include "dyn/cuda.h" - -// どこかにグローバルな logger の定義が必要 -simplelogger::Logger* logger = - simplelogger::LoggerFactory::CreateConsoleLogger(); - -CUcontext GetCudaContext(std::shared_ptr ctx) { - return static_cast(ctx->Context()); -} - -struct CudaContextImpl { - CUdevice device; - CUcontext context; - ~CudaContextImpl() { dyn::cuCtxDestroy(context); } -}; - -#define ckerror(call) \ - if (!ck(call)) \ - throw std::exception() - -std::shared_ptr CudaContext::Create() { - CUdevice device; - CUcontext context; - - if (!dyn::DynModule::Instance().IsLoadable(dyn::CUDA_SO)) { - throw std::exception(); - } - - ckerror(dyn::cuInit(0)); - ckerror(dyn::cuDeviceGet(&device, 0)); - char device_name[80]; - ckerror(dyn::cuDeviceGetName(device_name, sizeof(device_name), device)); - std::cout << "GPU in use: " << device_name << std::endl; - ckerror(dyn::cuCtxCreate(&context, 0, device)); - - std::shared_ptr impl(new CudaContextImpl()); - impl->device = device; - impl->context = context; - - std::shared_ptr ctx(new CudaContext()); - ctx->impl_ = impl; - - return ctx; -} - -void* CudaContext::Context() const { - return std::static_pointer_cast(impl_)->context; -} \ No newline at end of file diff --git a/src/cuda/cuda_context_cuda.h b/src/cuda/cuda_context_cuda.h deleted file mode 100644 index b63aee38..00000000 --- a/src/cuda/cuda_context_cuda.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CUDA_CONTEXT_CUDA_H_ -#define CUDA_CONTEXT_CUDA_H_ - -#include - -#include "cuda_context.h" - -CUcontext GetCudaContext(std::shared_ptr ctx); - -#endif \ No newline at end of file diff --git a/src/fix_cuda_noinline_macro_error.h b/src/fix_cuda_noinline_macro_error.h new file mode 100644 index 00000000..027fe4da --- /dev/null +++ b/src/fix_cuda_noinline_macro_error.h @@ -0,0 +1,22 @@ +/* +## 背景 + +WebRTC を M121 に更新した際に以下のビルド・エラーが発生した + +``` +error: use of undeclared identifier 'noinline'; did you mean 'inline' +``` + +WebRTC に含まれる libcxx のバージョンが更新されたことが原因だと思われる + +## 対応 + +同様の問題を解消したと思われる LLVM の [PR](https://github.com/llvm/llvm-project-release-prs/pull/698) を調査したところ、 PR で追加されたファイルは存在するにも関わらず、問題が継続して発生していることがわかった +(libcxx に bits/basic_string.h が含まれておらず、 cuda_wrappers 以下のファイルがインクルードされていないようだった) + +上記 PR を参考に、ファイルを直接修正したところエラーが解消したため、このヘッダー・ファイルをエラーが発生する箇所でインクルードすることにした +オリジナルのパッチには push_macro や pop_macro が含まれているが、省いても問題が無かったため省略している + +*/ + +#undef __noinline__ diff --git a/src/hwenc_jetson/jetson_jpeg_decoder_pool.cpp b/src/hwenc_jetson/jetson_jpeg_decoder_pool.cpp deleted file mode 100644 index 2050e3c8..00000000 --- a/src/hwenc_jetson/jetson_jpeg_decoder_pool.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "jetson_jpeg_decoder_pool.h" - -// WebRTC -#include - -std::shared_ptr JetsonJpegDecoderPool::Pop() { - std::unique_ptr nv_decoder; - - // プールを使うとなぜか実行時にクラッシュすることがあるのでコメントアウト - // 多分 nvjpeg のバグ - { - //std::lock_guard lock(mtx_); - //if (decoder_queue_.size() == 0) { - nv_decoder.reset(NvJPEGDecoder::createJPEGDecoder("jpegdec")); - //} else { - // nv_decoder = std::move(decoder_queue_.front()); - // decoder_queue_.pop(); - //} - } - - std::shared_ptr decoder( - new JetsonJpegDecoder(shared_from_this(), std::move(nv_decoder))); - return decoder; -} - -void JetsonJpegDecoderPool::Push(std::unique_ptr decoder) { - std::lock_guard lock(mtx_); - //decoder_queue_.push(std::move(decoder)); -} \ No newline at end of file diff --git a/src/hwenc_mmal/mmal_buffer.cpp b/src/hwenc_mmal/mmal_buffer.cpp deleted file mode 100644 index af7e0f90..00000000 --- a/src/hwenc_mmal/mmal_buffer.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "mmal_buffer.h" - -// WebRTC -#include -#include -#include - -rtc::scoped_refptr MMALBuffer::Create(MMAL_BUFFER_HEADER_T* buffer, - int width, - int height) { - return rtc::make_ref_counted(buffer, width, height); -} - -webrtc::VideoFrameBuffer::Type MMALBuffer::type() const { - return Type::kNative; -} - -int MMALBuffer::width() const { - return width_; -} - -int MMALBuffer::height() const { - return height_; -} - -int MMALBuffer::StrideY() const { - return width_; -} - -int MMALBuffer::StrideU() const { - return (width_ + 1) / 2; -} - -int MMALBuffer::StrideV() const { - return (width_ + 1) / 2; -} - -const uint8_t* MMALBuffer::DataY() const { - return buffer_->data; -} - -const uint8_t* MMALBuffer::DataU() const { - return DataY() + VCOS_ALIGN_UP(width_, 32) * VCOS_ALIGN_UP(height_, 16); -} - -const uint8_t* MMALBuffer::DataV() const { - return DataY() + VCOS_ALIGN_UP(width_, 32) * VCOS_ALIGN_UP(height_, 16) + - StrideU() * ((VCOS_ALIGN_UP(height_, 16) + 1) / 2); -} - -const size_t MMALBuffer::length() const { - return buffer_->length; -} - -MMALBuffer::MMALBuffer(MMAL_BUFFER_HEADER_T* buffer, int width, int height) - : buffer_(buffer), width_(width), height_(height) {} - -MMALBuffer::~MMALBuffer() { - mmal_buffer_header_release((MMAL_BUFFER_HEADER_T*)buffer_); -} diff --git a/src/hwenc_mmal/mmal_buffer.h b/src/hwenc_mmal/mmal_buffer.h deleted file mode 100644 index ac6f6c6b..00000000 --- a/src/hwenc_mmal/mmal_buffer.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef MMAL_BUFFER_H_ -#define MMAL_BUFFER_H_ - -extern "C" { -#include -} - -#include -#include -#include - -class MMALBuffer : public webrtc::I420BufferInterface { - public: - static rtc::scoped_refptr Create(MMAL_BUFFER_HEADER_T* buffer, - int width, - int height); - Type type() const override; - int width() const override; - int height() const override; - int StrideY() const override; - int StrideU() const override; - int StrideV() const override; - const uint8_t* DataY() const override; - const uint8_t* DataU() const override; - const uint8_t* DataV() const override; - - const size_t length() const; - - protected: - MMALBuffer(MMAL_BUFFER_HEADER_T* buffer, int width, int height); - ~MMALBuffer() override; - - private: - const MMAL_BUFFER_HEADER_T* buffer_; - const int width_; - const int height_; -}; -#endif // MMAL_BUFFER_H_ diff --git a/src/hwenc_mmal/mmal_h264_decoder.cpp b/src/hwenc_mmal/mmal_h264_decoder.cpp deleted file mode 100644 index 9ec00377..00000000 --- a/src/hwenc_mmal/mmal_h264_decoder.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - * - */ - -#include "mmal_h264_decoder.h" - -#include - -// WebRTC -#include -#include -#include -#include -#include -#include -#include - -MMALH264Decoder::MMALH264Decoder() - : decoder_(nullptr), - width_(0), - height_(0), - decode_complete_callback_(nullptr), - buffer_pool_(false, 300 /* max_number_of_buffers*/) { - bcm_host_init(); -} - -MMALH264Decoder::~MMALH264Decoder() { - Release(); -} - -bool MMALH264Decoder::Configure(const Settings& settings) { - RTC_LOG(LS_INFO) << __FUNCTION__; - if (MMALConfigure() != WEBRTC_VIDEO_CODEC_OK) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << "Failed to MMALConfigure"; - return false; - } - return true; -} - -int32_t MMALH264Decoder::Decode(const webrtc::EncodedImage& input_image, - bool missing_frames, - int64_t render_time_ms) { - if (decoder_ == nullptr) { - return WEBRTC_VIDEO_CODEC_UNINITIALIZED; - } - if (decode_complete_callback_ == NULL) { - return WEBRTC_VIDEO_CODEC_UNINITIALIZED; - } - if (input_image.data() == NULL && input_image.size() > 0) { - return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; - } - - webrtc::MutexLock lock(&config_lock_); - - RTC_LOG(LS_INFO) << __FUNCTION__; - - MMAL_BUFFER_HEADER_T* buffer; - if ((buffer = mmal_queue_get(pool_in_->queue)) != nullptr) { - buffer->pts = buffer->dts = input_image.Timestamp(); - buffer->offset = 0; - buffer->length = buffer->alloc_size = input_image.size(); - memcpy(buffer->data, input_image.data(), buffer->length); - if (mmal_port_send_buffer(decoder_->input[0], buffer) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to send input buffer"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - RTC_LOG(LS_INFO) << __FUNCTION__ << " timestamp:" << input_image.Timestamp() - << " size:" << input_image.size(); - return WEBRTC_VIDEO_CODEC_OK; - } else { - RTC_LOG(LS_ERROR) << "Failed to get buffer from input queue"; - return WEBRTC_VIDEO_CODEC_ERROR; - } -} - -int32_t MMALH264Decoder::RegisterDecodeCompleteCallback( - webrtc::DecodedImageCallback* callback) { - decode_complete_callback_ = callback; - return WEBRTC_VIDEO_CODEC_OK; -} - -int32_t MMALH264Decoder::Release() { - MMALRelease(); - buffer_pool_.Release(); - return WEBRTC_VIDEO_CODEC_OK; -} - -const char* MMALH264Decoder::ImplementationName() const { - return "MMAL H264"; -} - -void MMALH264Decoder::FillOutputBuffer() { - MMAL_BUFFER_HEADER_T* buffer; - while ((buffer = mmal_queue_get(pool_out_->queue)) != nullptr) { - mmal_port_send_buffer(decoder_->output[0], buffer); - } -} - -void MMALH264Decoder::MMALInputCallbackFunction(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - mmal_buffer_header_release(buffer); -} - -void MMALH264Decoder::MMALOutputCallbackFunction(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - RTC_LOG(LS_INFO) << __FUNCTION__; - ((MMALH264Decoder*)port->userdata)->MMALOutputCallback(port, buffer); -} - -void MMALH264Decoder::MMALOutputCallback(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - RTC_LOG(LS_INFO) << __FUNCTION__ << " cmd:" << buffer->cmd - << " length:" << buffer->length; - - if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED) { - webrtc::MutexLock lock(&config_lock_); - MMAL_EVENT_FORMAT_CHANGED_T* event = mmal_event_format_changed_get(buffer); - - width_ = event->format->es->video.width; - height_ = event->format->es->video.height; - - RTC_LOG(LS_INFO) << __FUNCTION__ << " width:" << width_ - << " height:" << height_; - - MMAL_PORT_T* port_out = decoder_->output[0]; - - mmal_format_full_copy(port_out->format, event->format); - port_out->format->encoding = MMAL_ENCODING_I420; - if (mmal_port_format_commit(port_out) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to commit output port format"; - return; - } - - port_out->buffer_size = port_out->buffer_size_recommended; - port_out->buffer_num = 3; - port_out->userdata = (MMAL_PORT_USERDATA_T*)this; - } else { - SendFrame(buffer); - } - - mmal_buffer_header_release(buffer); - FillOutputBuffer(); -} - -void MMALH264Decoder::SendFrame(MMAL_BUFFER_HEADER_T* buffer) { - rtc::scoped_refptr i420_buffer = - buffer_pool_.CreateI420Buffer(width_, height_); - if (!i420_buffer.get()) { - return; - } - - memcpy(i420_buffer->MutableDataY(), buffer->data, buffer->length); - - webrtc::VideoFrame decoded_image = webrtc::VideoFrame::Builder() - .set_video_frame_buffer(i420_buffer) - .set_timestamp_rtp(buffer->pts) - .build(); - decode_complete_callback_->Decoded(decoded_image, absl::nullopt, - absl::nullopt); -} - -int32_t MMALH264Decoder::MMALConfigure() { - if (mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &decoder_) != - MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to create mmal decoder"; - Release(); - return WEBRTC_VIDEO_CODEC_ERROR; - } - - MMAL_PORT_T* port_in = decoder_->input[0]; - port_in->format->type = MMAL_ES_TYPE_VIDEO; - port_in->format->encoding = MMAL_ENCODING_H264; - port_in->format->es->video.width = 0; - port_in->format->es->video.height = 0; - port_in->format->es->video.frame_rate.num = 0; - port_in->format->es->video.frame_rate.den = 1; - port_in->format->es->video.par.num = 1; - port_in->format->es->video.par.den = 1; - - if (mmal_port_format_commit(port_in) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to commit input port format"; - return -1; - } - - MMAL_PORT_T* port_out = decoder_->output[0]; - mmal_format_copy(port_out->format, port_in->format); - port_out->format->encoding = MMAL_ENCODING_I420; - - if (mmal_port_format_commit(port_out) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to commit output port format"; - return -1; - } - - port_in->buffer_num = 3; - port_in->buffer_size = 256 << 10; - port_out->buffer_num = 3; - port_out->buffer_size = 256; - - port_in->userdata = (MMAL_PORT_USERDATA_T*)this; - port_out->userdata = (MMAL_PORT_USERDATA_T*)this; - - if (mmal_port_parameter_set_boolean(port_in, MMAL_PARAMETER_ZERO_COPY, - MMAL_TRUE) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set resizer input zero copy"; - return -1; - } - - if (mmal_port_parameter_set_boolean(port_out, MMAL_PARAMETER_ZERO_COPY, - MMAL_TRUE) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set resizer output zero copy"; - return -1; - } - - if (mmal_port_enable(port_in, MMALInputCallbackFunction) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable input port"; - return -1; - } - - if (mmal_port_enable(port_out, MMALOutputCallbackFunction) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable output port"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - pool_in_ = - mmal_port_pool_create(port_in, port_in->buffer_num, port_in->buffer_size); - pool_out_ = mmal_port_pool_create( - port_out, port_out->buffer_num, - webrtc::CalcBufferSize(webrtc::VideoType::kI420, 1920, 1088)); - - if (mmal_component_enable(decoder_) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable component"; - return -1; - } - - FillOutputBuffer(); - - return WEBRTC_VIDEO_CODEC_OK; -} - -void MMALH264Decoder::MMALRelease() { - if (decoder_) { - mmal_component_disable(decoder_); - mmal_port_disable(decoder_->input[0]); - mmal_port_pool_destroy(decoder_->input[0], pool_in_); - mmal_port_disable(decoder_->output[0]); - mmal_port_pool_destroy(decoder_->output[0], pool_out_); - mmal_component_destroy(decoder_); - decoder_ = nullptr; - } -} diff --git a/src/hwenc_mmal/mmal_h264_decoder.h b/src/hwenc_mmal/mmal_h264_decoder.h deleted file mode 100644 index 883815b6..00000000 --- a/src/hwenc_mmal/mmal_h264_decoder.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - * - */ - -#ifndef MMAL_H264_DECODER_H_ -#define MMAL_H264_DECODER_H_ - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -} - -// WebRTC -#include -#include -#include - -class MMALH264Decoder : public webrtc::VideoDecoder { - public: - MMALH264Decoder(); - ~MMALH264Decoder() override; - - bool Configure(const Settings& settings) override; - - int32_t Decode(const webrtc::EncodedImage& input_image, - bool missing_frames, - int64_t render_time_ms) override; - - int32_t RegisterDecodeCompleteCallback( - webrtc::DecodedImageCallback* callback) override; - - int32_t Release() override; - - const char* ImplementationName() const override; - - private: - void FillOutputBuffer(); - static void MMALInputCallbackFunction(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer); - static void MMALOutputCallbackFunction(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer); - void MMALOutputCallback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer); - void SendFrame(MMAL_BUFFER_HEADER_T* buffer); - int32_t MMALConfigure(); - void MMALRelease(); - - webrtc::Mutex config_lock_; - MMAL_COMPONENT_T* decoder_; - MMAL_POOL_T* pool_in_; - MMAL_POOL_T* pool_out_; - int32_t width_; - int32_t height_; - webrtc::DecodedImageCallback* decode_complete_callback_; - webrtc::VideoFrameBufferPool buffer_pool_; -}; - -#endif // MMAL_H264_DECODER_H_ diff --git a/src/hwenc_mmal/mmal_h264_encoder.cpp b/src/hwenc_mmal/mmal_h264_encoder.cpp deleted file mode 100644 index c1a43c36..00000000 --- a/src/hwenc_mmal/mmal_h264_encoder.cpp +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - * - */ - -#include "mmal_h264_encoder.h" - -#include -#include - -// WebRTC -#include -#include -#include -#include -#include -#include -#include - -#include "mmal_buffer.h" - -#define H264HWENC_HEADER_DEBUG 0 - -namespace { -struct nal_entry { - size_t offset; - size_t size; -}; - -const int kLowH264QpThreshold = 34; -const int kHighH264QpThreshold = 40; - -int I420DataSize(const webrtc::I420BufferInterface& frame_buffer) { - return frame_buffer.StrideY() * frame_buffer.height() + - (frame_buffer.StrideU() + frame_buffer.StrideV()) * - ((frame_buffer.height() + 1) / 2); -} - -} // namespace - -MMALH264Encoder::MMALH264Encoder(const cricket::VideoCodec& codec) - : callback_(nullptr), - encoder_(nullptr), - encoder_pool_out_(nullptr), - bitrate_adjuster_(.5, .95), - target_framerate_fps_(30), - configured_framerate_fps_(30), - configured_width_(0), - configured_height_(0), - encoded_buffer_length_(0) {} - -MMALH264Encoder::~MMALH264Encoder() {} - -int32_t MMALH264Encoder::InitEncode(const webrtc::VideoCodec* codec_settings, - int32_t number_of_cores, - size_t max_payload_size) { - RTC_DCHECK(codec_settings); - RTC_DCHECK_EQ(codec_settings->codecType, webrtc::kVideoCodecH264); - - int32_t release_ret = Release(); - if (release_ret != WEBRTC_VIDEO_CODEC_OK) { - return release_ret; - } - - bcm_host_init(); - - width_ = codec_settings->width; - height_ = codec_settings->height; - target_bitrate_bps_ = codec_settings->startBitrate * 1000; - bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); - - RTC_LOG(LS_INFO) << "InitEncode " << target_bitrate_bps_ << "bit/sec"; - - // Initialize encoded image. Default buffer size: size of unencoded data. - encoded_image_._encodedWidth = 0; - encoded_image_._encodedHeight = 0; - encoded_image_.set_size(0); - encoded_image_.timing_.flags = - webrtc::VideoSendTiming::TimingFrameFlags::kInvalid; - encoded_image_.content_type_ = - (codec_settings->mode == webrtc::VideoCodecMode::kScreensharing) - ? webrtc::VideoContentType::SCREENSHARE - : webrtc::VideoContentType::UNSPECIFIED; - - return WEBRTC_VIDEO_CODEC_OK; -} - -int32_t MMALH264Encoder::Release() { - std::lock_guard lock(mtx_); - MMALRelease(); - return WEBRTC_VIDEO_CODEC_OK; -} - -int32_t MMALH264Encoder::MMALConfigure() { - if (mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder_) != - MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to create mmal encoder"; - Release(); - return WEBRTC_VIDEO_CODEC_ERROR; - } - - MMAL_PORT_T* encoder_port_in = encoder_->input[0]; - encoder_port_in->format->type = MMAL_ES_TYPE_VIDEO; - encoder_port_in->format->encoding = MMAL_ENCODING_I420; - encoder_port_in->format->es->video.width = VCOS_ALIGN_UP(width_, 32); - encoder_port_in->format->es->video.height = VCOS_ALIGN_UP(height_, 16); - encoder_port_in->format->es->video.crop.x = 0; - encoder_port_in->format->es->video.crop.y = 0; - encoder_port_in->format->es->video.crop.width = width_; - encoder_port_in->format->es->video.crop.height = height_; - - encoder_port_in->buffer_size = encoder_port_in->buffer_size_recommended; - if (encoder_port_in->buffer_size < encoder_port_in->buffer_size_min) - encoder_port_in->buffer_size = encoder_port_in->buffer_size_min; - encoder_port_in->buffer_num = 1; - encoder_port_in->userdata = (MMAL_PORT_USERDATA_T*)this; - - if (mmal_port_format_commit(encoder_port_in) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to commit encoder input port format"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - MMAL_PORT_T* encoder_port_out = encoder_->output[0]; - mmal_format_copy(encoder_port_out->format, encoder_port_in->format); - encoder_port_out->format->type = MMAL_ES_TYPE_VIDEO; - encoder_port_out->format->encoding = MMAL_ENCODING_H264; - encoder_port_out->format->es->video.frame_rate.num = 30; - encoder_port_out->format->es->video.frame_rate.den = 1; - encoder_port_out->format->bitrate = bitrate_adjuster_.GetAdjustedBitrateBps(); - - encoder_port_out->buffer_size = 256 << 10; - encoder_port_out->buffer_num = 4; - encoder_port_out->userdata = (MMAL_PORT_USERDATA_T*)this; - - if (mmal_port_format_commit(encoder_port_out) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to commit encoder output port format"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - MMAL_PARAMETER_VIDEO_PROFILE_T video_profile; - video_profile.hdr.id = MMAL_PARAMETER_PROFILE; - video_profile.hdr.size = sizeof(video_profile); - - video_profile.profile[0].profile = MMAL_VIDEO_PROFILE_H264_HIGH; - video_profile.profile[0].level = MMAL_VIDEO_LEVEL_H264_42; - - if (mmal_port_parameter_set(encoder_port_out, &video_profile.hdr) != - MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set H264 profile"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - if (mmal_port_parameter_set_uint32( - encoder_port_out, MMAL_PARAMETER_INTRAPERIOD, 500) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set intra period"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - if (mmal_port_parameter_set_boolean(encoder_port_out, - MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, - MMAL_TRUE) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set enable inline header"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - if (mmal_port_parameter_set_boolean(encoder_port_in, - MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, - MMAL_TRUE) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set enable immutable input"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - encoded_image_buffer_.reset(new uint8_t[encoder_port_out->buffer_size]); - - if (mmal_component_enable(encoder_) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable component"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - if (mmal_port_parameter_set_boolean(encoder_port_out, - MMAL_PARAMETER_ZERO_COPY, - MMAL_TRUE) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set encoder output zero copy"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - if (mmal_port_enable(encoder_port_in, EncoderInputCallbackFunction) != - MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable encoder input port"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - encoder_pool_in_ = - mmal_port_pool_create(encoder_port_in, encoder_port_in->buffer_num, - encoder_port_in->buffer_size); - - if (mmal_port_enable(encoder_port_out, EncoderOutputCallbackFunction) != - MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable encoder output port"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - encoder_pool_out_ = - mmal_port_pool_create(encoder_port_out, encoder_port_out->buffer_num, - encoder_port_out->buffer_size); - - EncoderFillBuffer(); - - configured_width_ = width_; - configured_height_ = height_; - stride_width_ = VCOS_ALIGN_UP(width_, 32); - stride_height_ = VCOS_ALIGN_UP(height_, 16); - - return WEBRTC_VIDEO_CODEC_OK; -} - -void MMALH264Encoder::MMALRelease() { - if (encoder_) { - mmal_component_disable(encoder_); - mmal_port_disable(encoder_->input[0]); - mmal_port_pool_destroy(encoder_->input[0], encoder_pool_in_); - mmal_port_disable(encoder_->output[0]); - mmal_port_pool_destroy(encoder_->output[0], encoder_pool_out_); - } - if (encoder_) { - mmal_component_destroy(encoder_); - encoder_ = nullptr; - } - while (!frame_params_.empty()) - frame_params_.pop(); - encoded_image_buffer_.reset(); - encoded_buffer_length_ = 0; -} - -void MMALH264Encoder::EncoderInputCallbackFunction( - MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - mmal_buffer_header_release(buffer); -} - -void MMALH264Encoder::EncoderOutputCallbackFunction( - MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - MMALH264Encoder* _this = (MMALH264Encoder*)port->userdata; - _this->EncoderOutputCallback(port, buffer); - mmal_buffer_header_release(buffer); - _this->EncoderFillBuffer(); -} - -void MMALH264Encoder::EncoderOutputCallback(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - if (buffer->length == 0) - return; - - if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG) { - memcpy(encoded_image_buffer_.get(), buffer->data, buffer->length); - encoded_buffer_length_ = buffer->length; - RTC_LOG(LS_INFO) << "MMAL_BUFFER_HEADER_FLAG_CONFIG"; - return; - } - - RTC_LOG(LS_INFO) << "pts:" << buffer->pts << " flags:" << buffer->flags - << " planes:" << buffer->type->video.planes - << " length:" << buffer->length; - - std::unique_ptr params; - { - webrtc::MutexLock lock(&frame_params_lock_); - do { - if (frame_params_.empty()) { - RTC_LOG(LS_WARNING) - << __FUNCTION__ - << "Frame parameter is empty. SkipFrame pts:" << buffer->pts; - return; - } - params = std::move(frame_params_.front()); - frame_params_.pop(); - } while (params->timestamp_us < buffer->pts); - if (params->timestamp_us != buffer->pts) { - RTC_LOG(LS_WARNING) << __FUNCTION__ - << "Frame parameter is not found. SkipFrame pts:" - << buffer->pts; - return; - } - } - - encoded_image_._encodedWidth = params->width; - encoded_image_._encodedHeight = params->height; - encoded_image_.capture_time_ms_ = params->render_time_ms; - encoded_image_.ntp_time_ms_ = params->ntp_time_ms; - encoded_image_.SetTimestamp(params->timestamp_rtp); - encoded_image_.rotation_ = params->rotation; - encoded_image_.SetColorSpace(params->color_space); - - if (encoded_buffer_length_ == 0) { - SendFrame(buffer->data, buffer->length); - } else { - memcpy(encoded_image_buffer_.get() + encoded_buffer_length_, buffer->data, - buffer->length); - encoded_buffer_length_ += buffer->length; - SendFrame(encoded_image_buffer_.get(), encoded_buffer_length_); - encoded_buffer_length_ = 0; - } -} - -void MMALH264Encoder::EncoderFillBuffer() { - MMAL_BUFFER_HEADER_T* buffer; - while ((buffer = mmal_queue_get(encoder_pool_out_->queue)) != nullptr) { - mmal_port_send_buffer(encoder_->output[0], buffer); - } -} - -int32_t MMALH264Encoder::RegisterEncodeCompleteCallback( - webrtc::EncodedImageCallback* callback) { - std::lock_guard lock(mtx_); - callback_ = callback; - return WEBRTC_VIDEO_CODEC_OK; -} - -void MMALH264Encoder::SetRates(const RateControlParameters& parameters) { - if (encoder_ == nullptr) - return; - if (parameters.bitrate.get_sum_bps() <= 0 || parameters.framerate_fps <= 0) - return; - - RTC_LOG(LS_INFO) << __FUNCTION__ - << " bitrate:" << parameters.bitrate.get_sum_bps() - << " fps:" << parameters.framerate_fps; - target_bitrate_bps_ = parameters.bitrate.get_sum_bps(); - bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); - target_framerate_fps_ = parameters.framerate_fps; - return; -} - -void MMALH264Encoder::SetBitrateBps(uint32_t bitrate_bps) { - if (bitrate_bps < 300000 || configured_bitrate_bps_ == bitrate_bps) { - return; - } - RTC_LOG(LS_INFO) << __FUNCTION__ << " " << bitrate_bps << " bit/sec"; - if (mmal_port_parameter_set_uint32(encoder_->output[0], - MMAL_PARAMETER_VIDEO_BIT_RATE, - bitrate_bps) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set bitrate"; - return; - } - configured_bitrate_bps_ = bitrate_bps; -} - -void MMALH264Encoder::SetFramerateFps(double framerate_fps) { - if (configured_framerate_fps_ == framerate_fps) { - return; - } - RTC_LOG(LS_INFO) << __FUNCTION__ << " " << framerate_fps << " fps"; - MMAL_PARAMETER_FRAME_RATE_T frame_rate; - frame_rate.hdr.id = MMAL_PARAMETER_VIDEO_FRAME_RATE; - frame_rate.hdr.size = sizeof(frame_rate); - frame_rate.frame_rate.num = framerate_fps; - frame_rate.frame_rate.den = 1; - if (mmal_port_parameter_set(encoder_->output[0], &frame_rate.hdr) != - MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set H264 framerate"; - return; - } - configured_framerate_fps_ = framerate_fps; -} - -webrtc::VideoEncoder::EncoderInfo MMALH264Encoder::GetEncoderInfo() const { - EncoderInfo info; - info.supports_native_handle = true; - info.implementation_name = "MMAL H264"; - info.scaling_settings = - VideoEncoder::ScalingSettings(kLowH264QpThreshold, kHighH264QpThreshold); - return info; -} - -int32_t MMALH264Encoder::Encode( - const webrtc::VideoFrame& input_frame, - const std::vector* frame_types) { - std::lock_guard lock(mtx_); - if (!callback_) { - RTC_LOG(LS_WARNING) - << "InitEncode() has been called, but a callback function " - << "has not been set with RegisterEncodeCompleteCallback()"; - return WEBRTC_VIDEO_CODEC_UNINITIALIZED; - } - - rtc::scoped_refptr frame_buffer = - input_frame.video_frame_buffer(); - - if (frame_buffer->width() != configured_width_ || - frame_buffer->height() != configured_height_) { - RTC_LOG(LS_INFO) << "Encoder reinitialized from " << configured_width_ - << "x" << configured_height_ << " to " - << frame_buffer->width() << "x" << frame_buffer->height(); - MMALRelease(); - if (MMALConfigure() != WEBRTC_VIDEO_CODEC_OK) { - RTC_LOG(LS_ERROR) << "Failed to MMALConfigure"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - } - - bool force_key_frame = false; - if (frame_types != nullptr) { - RTC_DCHECK_EQ(frame_types->size(), static_cast(1)); - if ((*frame_types)[0] == webrtc::VideoFrameType::kEmptyFrame) { - return WEBRTC_VIDEO_CODEC_OK; - } - force_key_frame = - (*frame_types)[0] == webrtc::VideoFrameType::kVideoFrameKey; - } - - if (force_key_frame) { - if (mmal_port_parameter_set_boolean(encoder_->output[0], - MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, - MMAL_TRUE) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to request I frame"; - } - } - - SetBitrateBps(bitrate_adjuster_.GetAdjustedBitrateBps()); - SetFramerateFps(target_framerate_fps_); - { - webrtc::MutexLock lock(&frame_params_lock_); - frame_params_.push(absl::make_unique( - frame_buffer->width(), frame_buffer->height(), - input_frame.render_time_ms(), input_frame.ntp_time_ms(), - input_frame.timestamp_us(), input_frame.timestamp(), - input_frame.rotation(), input_frame.color_space())); - } - - MMAL_BUFFER_HEADER_T* buffer; - if ((buffer = mmal_queue_get(encoder_pool_in_->queue)) != nullptr) { - buffer->pts = buffer->dts = input_frame.timestamp_us(); - buffer->offset = 0; - buffer->flags = MMAL_BUFFER_HEADER_FLAG_FRAME; - if (frame_buffer->type() == webrtc::VideoFrameBuffer::Type::kNative) { - MMALBuffer* mmal_buffer = dynamic_cast(frame_buffer.get()); - buffer->data = (uint8_t*)mmal_buffer->DataY(); - buffer->length = buffer->alloc_size = mmal_buffer->length(); - if (mmal_port_send_buffer(encoder_->input[0], buffer) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to send input native buffer"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - } else { - rtc::scoped_refptr i420_buffer = - frame_buffer->ToI420(); - size_t offset = 0; - for (size_t i = 0; i < i420_buffer->height(); i++) { - memcpy(buffer->data + offset, - (uint8_t*)i420_buffer->DataY() + (i420_buffer->StrideY() * i), - i420_buffer->StrideY()); - offset += stride_width_; - } - offset = 0; - size_t stride_uv = stride_width_ / 2; - size_t offset_u = stride_width_ * stride_height_; - size_t offset_v = offset_u + stride_uv * (stride_height_ / 2); - for (size_t i = 0; i < ((i420_buffer->height() + 1) / 2); i++) { - memcpy(buffer->data + offset_u + offset, - (uint8_t*)i420_buffer->DataU() + (i420_buffer->StrideU() * i), - stride_uv); - memcpy(buffer->data + offset_v + offset, - (uint8_t*)i420_buffer->DataV() + (i420_buffer->StrideV() * i), - stride_uv); - offset += stride_uv; - } - buffer->length = buffer->alloc_size = webrtc::CalcBufferSize( - webrtc::VideoType::kI420, stride_width_, stride_height_); - if (mmal_port_send_buffer(encoder_->input[0], buffer) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to send input i420 buffer"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - } - } - - return WEBRTC_VIDEO_CODEC_OK; -} - -int32_t MMALH264Encoder::SendFrame(unsigned char* buffer, size_t size) { - auto encoded_image_buffer = webrtc::EncodedImageBuffer::Create(buffer, size); - encoded_image_.SetEncodedData(encoded_image_buffer); - encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameDelta; - - uint8_t zero_count = 0; - size_t nal_start_idx = 0; - for (size_t i = 0; i < size; i++) { - uint8_t data = buffer[i]; - if ((i != 0) && (i == nal_start_idx)) { - if ((data & 0x1F) == 0x05) { - encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameKey; - } - } - if (data == 0x01 && zero_count >= 2) { - nal_start_idx = i + 1; - } - if (data == 0x00) { - zero_count++; - } else { - zero_count = 0; - } - } - - webrtc::CodecSpecificInfo codec_specific; - codec_specific.codecType = webrtc::kVideoCodecH264; - codec_specific.codecSpecific.H264.packetization_mode = - webrtc::H264PacketizationMode::NonInterleaved; - - h264_bitstream_parser_.ParseBitstream(encoded_image_); - encoded_image_.qp_ = h264_bitstream_parser_.GetLastSliceQp().value_or(-1); - RTC_LOG(LS_INFO) << __FUNCTION__ << " last slice qp:" << encoded_image_.qp_; - - webrtc::EncodedImageCallback::Result result = - callback_->OnEncodedImage(encoded_image_, &codec_specific); - if (result.error != webrtc::EncodedImageCallback::Result::OK) { - RTC_LOG(LS_ERROR) << __FUNCTION__ - << " OnEncodedImage failed error:" << result.error; - return WEBRTC_VIDEO_CODEC_ERROR; - } - bitrate_adjuster_.Update(size); - return WEBRTC_VIDEO_CODEC_OK; -} diff --git a/src/hwenc_mmal/mmal_h264_encoder.h b/src/hwenc_mmal/mmal_h264_encoder.h deleted file mode 100644 index 0bc5ef15..00000000 --- a/src/hwenc_mmal/mmal_h264_encoder.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - * - */ - -#ifndef MMAL_H264_ENCODER_H_ -#define MMAL_H264_ENCODER_H_ - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -} - -#include -#include -#include -#include - -// WebRTC -#include -#include -#include -#include -#include -#include - -class ProcessThread; - -class MMALH264Encoder : public webrtc::VideoEncoder { - public: - explicit MMALH264Encoder(const cricket::VideoCodec& codec); - ~MMALH264Encoder() override; - - int32_t InitEncode(const webrtc::VideoCodec* codec_settings, - int32_t number_of_cores, - size_t max_payload_size) override; - int32_t RegisterEncodeCompleteCallback( - webrtc::EncodedImageCallback* callback) override; - int32_t Release() override; - int32_t Encode( - const webrtc::VideoFrame& frame, - const std::vector* frame_types) override; - void SetRates(const RateControlParameters& parameters) override; - webrtc::VideoEncoder::EncoderInfo GetEncoderInfo() const override; - - private: - struct FrameParams { - FrameParams(int32_t w, - int32_t h, - int64_t rtms, - int64_t ntpms, - int64_t tsus, - int64_t rtpts, - webrtc::VideoRotation r, - absl::optional c) - : width(w), - height(h), - render_time_ms(rtms), - ntp_time_ms(ntpms), - timestamp_us(tsus), - timestamp_rtp(rtpts), - rotation(r), - color_space(c) {} - - int32_t width; - int32_t height; - int64_t render_time_ms; - int64_t ntp_time_ms; - int64_t timestamp_us; - int64_t timestamp_rtp; - webrtc::VideoRotation rotation; - absl::optional color_space; - }; - - int32_t MMALConfigure(); - void MMALRelease(); - static void EncoderInputCallbackFunction(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer); - static void EncoderOutputCallbackFunction(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer); - void EncoderOutputCallback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer); - void EncoderFillBuffer(); - void SetBitrateBps(uint32_t bitrate_bps); - void SetFramerateFps(double framerate_fps); - int32_t SendFrame(unsigned char* buffer, size_t size); - - std::mutex mtx_; - webrtc::EncodedImageCallback* callback_; - MMAL_COMPONENT_T* encoder_; - MMAL_POOL_T* encoder_pool_in_; - MMAL_POOL_T* encoder_pool_out_; - webrtc::BitrateAdjuster bitrate_adjuster_; - uint32_t target_bitrate_bps_; - uint32_t configured_bitrate_bps_; - double target_framerate_fps_; - int32_t configured_framerate_fps_; - int32_t width_; - int32_t height_; - int32_t configured_width_; - int32_t configured_height_; - int32_t stride_width_; - int32_t stride_height_; - - webrtc::H264BitstreamParser h264_bitstream_parser_; - - webrtc::Mutex frame_params_lock_; - std::queue> frame_params_; - webrtc::EncodedImage encoded_image_; - std::unique_ptr encoded_image_buffer_; - size_t encoded_buffer_length_; -}; - -#endif // MMAL_H264_ENCODER_H_ diff --git a/src/hwenc_mmal/mmal_v4l2_capturer.cpp b/src/hwenc_mmal/mmal_v4l2_capturer.cpp deleted file mode 100644 index f45cad00..00000000 --- a/src/hwenc_mmal/mmal_v4l2_capturer.cpp +++ /dev/null @@ -1,457 +0,0 @@ -#include "mmal_v4l2_capturer.h" - -// Linux -#include -#include - -// WebRTC -#include -#include -#include -#include - -#include "mmal_buffer.h" - -rtc::scoped_refptr MMALV4L2Capturer::Create( - MMALV4L2CapturerConfig config) { - rtc::scoped_refptr capturer; - std::unique_ptr device_info( - webrtc::VideoCaptureFactory::CreateDeviceInfo()); - if (!device_info) { - RTC_LOG(LS_ERROR) << "Failed to CreateDeviceInfo"; - return nullptr; - } - - LogDeviceList(device_info.get()); - - for (int i = 0; i < device_info->NumberOfDevices(); ++i) { - capturer = Create(device_info.get(), config, i); - if (capturer) { - RTC_LOG(LS_INFO) << "Get Capture"; - return capturer; - } - } - RTC_LOG(LS_ERROR) << "Failed to create V4L2VideoCapturer"; - return nullptr; -} - -rtc::scoped_refptr MMALV4L2Capturer::Create( - webrtc::VideoCaptureModule::DeviceInfo* device_info, - MMALV4L2CapturerConfig config, - size_t capture_device_index) { - char device_name[256]; - char unique_name[256]; - if (device_info->GetDeviceName(static_cast(capture_device_index), - device_name, sizeof(device_name), unique_name, - sizeof(unique_name)) != 0) { - RTC_LOG(LS_WARNING) << "Failed to GetDeviceName"; - return nullptr; - } - rtc::scoped_refptr v4l2_capturer( - new rtc::RefCountedObject(config)); - if (v4l2_capturer->Init((const char*)&unique_name, config.video_device) < 0) { - RTC_LOG(LS_WARNING) << "Failed to create MMALV4L2Capturer(" << unique_name - << ")"; - return nullptr; - } - if (v4l2_capturer->StartCapture(config) < 0) { - RTC_LOG(LS_WARNING) << "Failed to start MMALV4L2Capturer(w = " - << config.width << ", h = " << config.height - << ", fps = " << config.framerate << ")"; - return nullptr; - } - return v4l2_capturer; -} - -MMALV4L2Capturer::MMALV4L2Capturer(const MMALV4L2CapturerConfig& config) - : V4L2VideoCapturer(config), - component_in_(nullptr), - decoder_(nullptr), - resizer_(nullptr), - connection_(nullptr), - configured_width_(0), - configured_height_(0), - config_(config) { - bcm_host_init(); - decoded_buffer_num_ = 4; - decoded_buffer_size_ = - webrtc::CalcBufferSize(webrtc::VideoType::kI420, VCOS_ALIGN_UP(1920, 32), - VCOS_ALIGN_UP(1080, 16)); - // 出力のプールはまとめないと、リサイズ時にエンコーダに送ったフレームが破棄される場合がある - resizer_pool_out_ = - mmal_pool_create(decoded_buffer_num_, decoded_buffer_size_); -} - -MMALV4L2Capturer::~MMALV4L2Capturer() { - std::lock_guard lock(mtx_); - MMALRelease(); - mmal_pool_destroy(resizer_pool_out_); -} - -int32_t MMALV4L2Capturer::StartCapture(V4L2VideoCapturerConfig config) { - return V4L2VideoCapturer::StartCapture(config); -} - -int32_t MMALV4L2Capturer::StopCapture() { - return V4L2VideoCapturer::StopCapture(); -} - -bool MMALV4L2Capturer::UseNativeBuffer() { - return true; -} - -void MMALV4L2Capturer::OnCaptured(uint8_t* data, uint32_t bytesused) { - // やってくる MJPEG の種類によっては、MMAL が処理できないことがある。 - // その場合は APP0 マーカーを APP4 に書き換えると良いらしいので、 - // 適当に置き換えていく。 - // https://forums.raspberrypi.com/viewtopic.php?t=329233 - int n = 2; // SOI は飛ばす - while (n < bytesused - 1) { - // EOI または SOS マーカーが見つかったら終了する - if (data[n] == 0xff && data[n + 1] == 0xd9) { - break; - } - if (data[n] == 0xff && data[n + 1] == 0xda) { - break; - } - if (n >= bytesused - 3) { - break; - } - // APP0 マーカーだったら APP4 マーカーに置き換える - if (data[n] == 0xff && data[n + 1] == 0xe0) { - data[n + 1] = 0xe4; - } - int size = (int)data[n + 2] * 256 + (int)data[n + 3]; - n += 2 + size; - } - - const int64_t timestamp_us = rtc::TimeMicros(); - - int adapted_width; - int adapted_height; - int crop_width; - int crop_height; - int crop_x; - int crop_y; - if (!AdaptFrame(_currentWidth, _currentHeight, timestamp_us, &adapted_width, - &adapted_height, &crop_width, &crop_height, &crop_x, - &crop_y)) { - return; - } - std::lock_guard lock(mtx_); - - //{ - // static int n = 0; - // char file[255]; - // sprintf(file, "mjpeg/mjpeg%04d.jpg", n); - // n += 1; - // FILE* fp = fopen(file, "wb"); - // if (fp == NULL) { - // RTC_LOG(LS_ERROR) << "Failed to open " << file; - // return; - // } - // fwrite(data, 1, bytesused, fp); - // fclose(fp); - //} - - if (configured_width_ != adapted_width || - configured_height_ != adapted_height) { - RTC_LOG(LS_INFO) << "Resizer reinitialized from " << configured_width_ - << "x" << configured_height_ << " to " << adapted_width - << "x" << adapted_height << " (current " << _currentWidth - << "x" << _currentHeight << ")"; - MMALRelease(); - if (MMALConfigure(adapted_width, adapted_height) == -1) { - RTC_LOG(LS_ERROR) << "Failed to MMALConfigure"; - return; - } - } - - ResizerFillBuffer(); - - { - webrtc::MutexLock lock(&frame_params_lock_); - frame_params_.push(absl::make_unique( - configured_width_, configured_height_, timestamp_us)); - } - - MMAL_BUFFER_HEADER_T* buffer; - while ((buffer = mmal_queue_get(pool_in_->queue)) != nullptr) { - //RTC_LOG(LS_INFO) << "Got input buffer from queue: " << (void*)buffer; - buffer->pts = buffer->dts = timestamp_us; - buffer->offset = 0; - buffer->flags = MMAL_BUFFER_HEADER_FLAG_FRAME; - buffer->data = data; - buffer->length = buffer->alloc_size = bytesused; - if (mmal_port_send_buffer(component_in_->input[0], buffer) != - MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to send input buffer"; - return; - } - } -} - -void MMALV4L2Capturer::MMALInputCallbackFunction(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - ((MMALV4L2Capturer*)port->userdata)->MMALInputCallback(port, buffer); -} - -void MMALV4L2Capturer::MMALInputCallback(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - mmal_buffer_header_release(buffer); -} - -void MMALV4L2Capturer::ResizerFillBuffer() { - MMAL_BUFFER_HEADER_T* resizer_out; - while ((resizer_out = mmal_queue_get(resizer_pool_out_->queue)) != NULL) { - //RTC_LOG(LS_INFO) << "Got resizer_out from queue: " << (void*)resizer_out; - mmal_port_send_buffer(resizer_->output[0], resizer_out); - } -} - -void MMALV4L2Capturer::ResizerOutputCallbackFunction( - MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - ((MMALV4L2Capturer*)port->userdata)->ResizerOutputCallback(port, buffer); -} - -void MMALV4L2Capturer::ResizerOutputCallback(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer) { - std::unique_ptr params; - { - webrtc::MutexLock lock(&frame_params_lock_); - do { - if (frame_params_.empty()) { - RTC_LOG(LS_WARNING) - << __FUNCTION__ - << "Frame parameter is not found. SkipFrame pts:" << buffer->pts; - mmal_buffer_header_release(buffer); - return; - } - params = std::move(frame_params_.front()); - frame_params_.pop(); - } while (params->timestamp < buffer->pts); - if (params->timestamp != buffer->pts) { - RTC_LOG(LS_WARNING) << __FUNCTION__ - << "Frame parameter is not found. SkipFrame pts:" - << buffer->pts; - mmal_buffer_header_release(buffer); - return; - } - } - - if (config_.native_frame_output) { - rtc::scoped_refptr mmal_buffer( - MMALBuffer::Create(buffer, params->width, params->height)); - OnFrame(webrtc::VideoFrame::Builder() - .set_video_frame_buffer(mmal_buffer) - .set_timestamp_rtp(0) - .set_timestamp_us(buffer->pts) - .set_rotation(webrtc::kVideoRotation_0) - .build()); - } else { - auto i420_buffer = - webrtc::I420Buffer::Create(params->width, params->height); - std::memcpy(i420_buffer->MutableDataY(), buffer->data, buffer->length); - OnFrame(webrtc::VideoFrame::Builder() - .set_video_frame_buffer(i420_buffer) - .set_timestamp_rtp(0) - .set_timestamp_us(buffer->pts) - .set_rotation(webrtc::kVideoRotation_0) - .build()); - mmal_buffer_header_release(buffer); - } -} - -int32_t MMALV4L2Capturer::MMALConfigure(int32_t width, int32_t height) { - MMAL_PORT_T* port_in; - MMAL_FOURCC_T input_format; - - if (mmal_component_create("vc.ril.isp", &resizer_) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to create mmal resizer"; - Release(); - return -1; - } - - if (_captureVideoType == webrtc::VideoType::kMJPEG) { - if (mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, - &decoder_) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to create mmal decoder"; - Release(); - return -1; - } - component_in_ = decoder_; - port_in = decoder_->input[0]; - input_format = MMAL_ENCODING_MJPEG; - } else { - switch (_captureVideoType) { - case webrtc::VideoType::kI420: - input_format = MMAL_ENCODING_I420; - break; - case webrtc::VideoType::kUYVY: - input_format = MMAL_ENCODING_UYVY; - break; - case webrtc::VideoType::kYUY2: - input_format = MMAL_ENCODING_YUYV; - break; - default: - RTC_LOG(LS_ERROR) << "This video type is not supported in native " - "frame. video type : " - << _captureVideoType; - Release(); - return -1; - } - component_in_ = resizer_; - port_in = resizer_->input[0]; - port_in->format->es->video.crop.x = 0; - port_in->format->es->video.crop.y = 0; - port_in->format->es->video.crop.width = _currentWidth; - port_in->format->es->video.crop.height = _currentHeight; - } - - port_in->format->type = MMAL_ES_TYPE_VIDEO; - port_in->format->encoding = input_format; - port_in->format->es->video.width = _currentWidth; - port_in->format->es->video.height = _currentHeight; - - port_in->buffer_size = port_in->buffer_size_recommended; - if (port_in->buffer_size < port_in->buffer_size_min) - port_in->buffer_size = port_in->buffer_size_min; - if (_captureVideoType == webrtc::VideoType::kMJPEG) - port_in->buffer_size = 512 << 10; - // port_in->buffer_num を 2 にあげた方が VPX では 22fps レートは出るが H264 が詰まる - // port_in->buffer_num が 1 の時は 15fps 程度 - port_in->buffer_num = 1; - port_in->userdata = (MMAL_PORT_USERDATA_T*)this; - - if (mmal_port_format_commit(port_in) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to commit input port format"; - return -1; - } - - if (_captureVideoType == webrtc::VideoType::kMJPEG) { - MMAL_PORT_T* decoder_port_out = decoder_->output[0]; - mmal_format_copy(decoder_port_out->format, port_in->format); - decoder_port_out->format->type = MMAL_ES_TYPE_VIDEO; - decoder_port_out->format->encoding = MMAL_ENCODING_OPAQUE; - decoder_port_out->format->encoding_variant = MMAL_ENCODING_I420; - - if (mmal_port_format_commit(decoder_port_out) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to commit decoder output port format"; - return -1; - } - - if (mmal_connection_create( - &connection_, decoder_->output[0], resizer_->input[0], - MMAL_CONNECTION_FLAG_TUNNELLING) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to connect decoder to resizer"; - return -1; - } - } - - MMAL_PORT_T* resizer_port_out = resizer_->output[0]; - mmal_format_copy(resizer_port_out->format, resizer_->input[0]->format); - resizer_port_out->format->encoding = MMAL_ENCODING_I420; - resizer_port_out->format->es->video.width = VCOS_ALIGN_UP(width, 32); - resizer_port_out->format->es->video.height = VCOS_ALIGN_UP(height, 16); - resizer_port_out->format->es->video.crop.x = 0; - resizer_port_out->format->es->video.crop.y = 0; - resizer_port_out->format->es->video.crop.width = width; - resizer_port_out->format->es->video.crop.height = height; - - resizer_port_out->buffer_size = decoded_buffer_size_; - resizer_port_out->buffer_num = decoded_buffer_num_; - resizer_port_out->userdata = (MMAL_PORT_USERDATA_T*)this; - - if (mmal_port_format_commit(resizer_port_out) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to commit output port format"; - return -1; - } - - // mmal_pool_create で作った場合 mmal_component_enable 前に mmal_port_enable - if (mmal_port_enable(resizer_port_out, ResizerOutputCallbackFunction) != - MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable resizer output port"; - return -1; - } - - if (mmal_component_enable(resizer_) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable component"; - return -1; - } - - if (mmal_port_parameter_set_boolean(resizer_port_out, - MMAL_PARAMETER_ZERO_COPY, - MMAL_TRUE) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set resizer output zero copy"; - return -1; - } - - if (mmal_port_enable(port_in, MMALInputCallbackFunction) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable input port"; - return -1; - } - pool_in_ = - mmal_port_pool_create(port_in, port_in->buffer_num, port_in->buffer_size); - - ResizerFillBuffer(); - - if (_captureVideoType == webrtc::VideoType::kMJPEG) { - if (mmal_component_enable(decoder_) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable component"; - return -1; - } - - if (mmal_port_parameter_set_boolean(decoder_->output[0], - MMAL_PARAMETER_ZERO_COPY, - MMAL_TRUE) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set decoder output zero copy"; - return -1; - } - - if (mmal_port_parameter_set_boolean(resizer_->input[0], - MMAL_PARAMETER_ZERO_COPY, - MMAL_TRUE) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to set resizer input zero copy"; - return -1; - } - - if (mmal_connection_enable(connection_) != MMAL_SUCCESS) { - RTC_LOG(LS_ERROR) << "Failed to enable connection decoder to resizer"; - return -1; - } - } - - configured_width_ = width; - configured_height_ = height; - return 0; -} - -void MMALV4L2Capturer::MMALRelease() { - if (resizer_) { - mmal_component_disable(resizer_); - if (decoder_) { - mmal_component_disable(decoder_); - mmal_port_disable(decoder_->input[0]); - mmal_port_pool_destroy(decoder_->input[0], pool_in_); - } else { - mmal_port_disable(resizer_->input[0]); - mmal_port_pool_destroy(resizer_->input[0], pool_in_); - } - mmal_port_disable(resizer_->output[0]); - } - if (connection_) { - mmal_connection_destroy(connection_); - connection_ = nullptr; - } - if (resizer_) { - mmal_component_destroy(resizer_); - resizer_ = nullptr; - } - if (decoder_) { - mmal_component_destroy(decoder_); - decoder_ = nullptr; - } - while (!frame_params_.empty()) - frame_params_.pop(); -} diff --git a/src/hwenc_mmal/mmal_v4l2_capturer.h b/src/hwenc_mmal/mmal_v4l2_capturer.h deleted file mode 100644 index 2c80915d..00000000 --- a/src/hwenc_mmal/mmal_v4l2_capturer.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef MMAL_V4L2_CAPTURER_H_ -#define MMAL_V4L2_CAPTURER_H_ - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -} - -#include -#include - -#include -#include -#include - -// WebRTC -#include - -#include "v4l2_video_capturer/v4l2_video_capturer.h" - -struct MMALV4L2CapturerConfig : V4L2VideoCapturerConfig { - MMALV4L2CapturerConfig(const V4L2VideoCapturerConfig& config) { - *static_cast(this) = config; - } - // native_frame_output == true の場合、MMAL のデータを kNative なフレームとして渡す。 - // native_frame_output == false の場合、データをコピーして I420Buffer なフレームを作って渡す。 - // 前者の方が効率が良いけれども、kNative なフレームはサイマルキャスト時に自動で - // リサイズしてくれないので、状況に応じて使い分けるのが良い。 - bool native_frame_output = false; -}; - -class MMALV4L2Capturer : public V4L2VideoCapturer { - public: - static rtc::scoped_refptr Create( - MMALV4L2CapturerConfig config); - MMALV4L2Capturer(const MMALV4L2CapturerConfig& config); - ~MMALV4L2Capturer(); - - private: - struct FrameParams { - FrameParams(int32_t w, int32_t h, int64_t ts) - : width(w), height(h), timestamp(ts) {} - - int32_t width; - int32_t height; - int64_t timestamp; - }; - - static rtc::scoped_refptr Create( - webrtc::VideoCaptureModule::DeviceInfo* device_info, - MMALV4L2CapturerConfig config, - size_t capture_device_index); - int32_t StartCapture(V4L2VideoCapturerConfig config) override; - int32_t StopCapture() override; - bool UseNativeBuffer() override; - void OnCaptured(uint8_t* data, uint32_t bytesused) override; - static void MMALInputCallbackFunction(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer); - void MMALInputCallback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer); - void ResizerFillBuffer(); - static void ResizerOutputCallbackFunction(MMAL_PORT_T* port, - MMAL_BUFFER_HEADER_T* buffer); - void ResizerOutputCallback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer); - int32_t MMALConfigure(int32_t width, int32_t height); - void MMALRelease(); - - std::mutex mtx_; - MMAL_COMPONENT_T* component_in_; - MMAL_COMPONENT_T* decoder_; - MMAL_COMPONENT_T* resizer_; - MMAL_CONNECTION_T* connection_; - MMAL_POOL_T* pool_in_; - MMAL_POOL_T* resizer_pool_out_; - int32_t configured_width_; - int32_t configured_height_; - webrtc::Mutex frame_params_lock_; - std::queue> frame_params_; - unsigned int decoded_buffer_num_; - size_t decoded_buffer_size_; - MMALV4L2CapturerConfig config_; -}; - -#endif // MMAL_V4L2_CAPTURER_H_ diff --git a/src/hwenc_msdk/msdk_session.cpp b/src/hwenc_msdk/msdk_session.cpp deleted file mode 100644 index 0098a77c..00000000 --- a/src/hwenc_msdk/msdk_session.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "msdk_session.h" - -#include - -MsdkSession::~MsdkSession() { - session.Close(); -} - -std::shared_ptr MsdkSession::Create() { - std::shared_ptr session(new MsdkSession()); - - mfxStatus sts = MFX_ERR_NONE; - - mfxVersion ver = {{0, 1}}; - -#ifdef __linux__ - mfxIMPL impl = MFX_IMPL_HARDWARE_ANY; - sts = session->session.Init(impl, &ver); - if (sts != MFX_ERR_NONE) { - return nullptr; - } - - session->libva = CreateDRMLibVA(); - if (!session->libva) { - return nullptr; - } - - sts = session->session.SetHandle( - static_cast(MFX_HANDLE_VA_DISPLAY), - session->libva->GetVADisplay()); - if (sts != MFX_ERR_NONE) { - return nullptr; - } -#endif - -#ifdef _WIN32 - mfxIMPL impl = MFX_IMPL_VIA_D3D11 | MFX_IMPL_HARDWARE_ANY; - - sts = session->session.Init(impl, &ver); - if (sts != MFX_ERR_NONE) { - //std::cerr << "Failed to MFXInit: sts=" << sts << std::endl; - return nullptr; - } - -#endif - - // Query selected implementation and version - sts = session->session.QueryIMPL(&impl); - if (sts != MFX_ERR_NONE) { - //std::cerr << "Failed to MFXQueryIMPL: sts=" << sts << std::endl; - return nullptr; - } - - sts = session->session.QueryVersion(&ver); - if (sts != MFX_ERR_NONE) { - //std::cerr << "Failed to MFXQueryVersion: sts=" << sts << std::endl; - return nullptr; - } - - //RTC_LOG(LS_INFO) << "Intel Media SDK Implementation: " - // << (impl == MFX_IMPL_SOFTWARE ? "SOFTWARE" : "HARDWARE"); - //RTC_LOG(LS_INFO) << "Intel Media SDK API Version: " << ver.Major << "." - // << ver.Minor; - return session; -} \ No newline at end of file diff --git a/src/hwenc_msdk/msdk_session.h b/src/hwenc_msdk/msdk_session.h deleted file mode 100644 index 02d9625f..00000000 --- a/src/hwenc_msdk/msdk_session.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MSDK_SESSION_H_ -#define MSDK_SESSION_H_ - -#include - -// Intel Media SDK -#include - -#ifdef __linux__ -#include "vaapi_utils_drm.h" -#endif - -struct MsdkSession { - MFXVideoSession session; - - ~MsdkSession(); - -#ifdef __linux__ - std::unique_ptr libva; -#endif - - static std::shared_ptr Create(); -}; - -#endif \ No newline at end of file diff --git a/src/hwenc_msdk/msdk_utils.h b/src/hwenc_msdk/msdk_utils.h deleted file mode 100644 index 8ddeeadc..00000000 --- a/src/hwenc_msdk/msdk_utils.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef MSDK_UTILS_H_ -#define MSDK_UTILS_H_ - -#define MSDK_CHECK_RESULT(P, X, ERR) \ - { \ - if ((X) > (P)) { \ - RTC_LOG(LS_ERROR) << "Intel Media SDK Error: " << ERR; \ - throw ERR; \ - } \ - } - -#endif \ No newline at end of file diff --git a/src/hwenc_msdk/msdk_video_decoder.cpp b/src/hwenc_msdk/msdk_video_decoder.cpp deleted file mode 100644 index cf37c0d6..00000000 --- a/src/hwenc_msdk/msdk_video_decoder.cpp +++ /dev/null @@ -1,282 +0,0 @@ -#include "msdk_video_decoder.h" - -#include -#include - -// WebRTC -#include -#include -#include -#include -#include - -#include "msdk_utils.h" - -MsdkVideoDecoder::MsdkVideoDecoder(std::shared_ptr session, - mfxU32 codec) - : session_(session), - codec_(codec), - decoder_(nullptr), - decode_complete_callback_(nullptr), - buffer_pool_(false, 300 /* max_number_of_buffers*/) {} - -MsdkVideoDecoder::~MsdkVideoDecoder() { - Release(); -} - -std::unique_ptr MsdkVideoDecoder::CreateDecoder( - std::shared_ptr session, - mfxU32 codec, - int width, - int height, - bool init) { - std::unique_ptr decoder(new MFXVideoDECODE(session->session)); - - mfxStatus sts = MFX_ERR_NONE; - - mfxVideoParam param; - memset(¶m, 0, sizeof(param)); - - param.mfx.CodecId = codec; - param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; - param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; - param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; - param.mfx.FrameInfo.CropX = 0; - param.mfx.FrameInfo.CropY = 0; - param.mfx.FrameInfo.CropW = width; - param.mfx.FrameInfo.CropH = height; - param.mfx.FrameInfo.Width = (width + 15) / 16 * 16; - param.mfx.FrameInfo.Height = (height + 15) / 16 * 16; - - param.mfx.GopRefDist = 1; - param.AsyncDepth = 1; - param.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; - - //qmfxExtCodingOption ext_coding_option; - //qmemset(&ext_coding_option, 0, sizeof(ext_coding_option)); - //qext_coding_option.Header.BufferId = MFX_EXTBUFF_CODING_OPTION; - //qext_coding_option.Header.BufferSz = sizeof(ext_coding_option); - //qext_coding_option.MaxDecFrameBuffering = 1; - - //qmfxExtBuffer* ext_buffers[1]; - //qext_buffers[0] = (mfxExtBuffer*)&ext_coding_option; - //qparam.ExtParam = ext_buffers; - //qparam.NumExtParam = sizeof(ext_buffers) / sizeof(ext_buffers[0]); - - sts = decoder->Query(¶m, ¶m); - if (sts < 0) { - const char* codec_str = codec == MFX_CODEC_VP8 ? "MFX_CODEC_VP8" - : codec == MFX_CODEC_VP9 ? "MFX_CODEC_VP9" - : codec == MFX_CODEC_AV1 ? "MFX_CODEC_AV1" - : codec == MFX_CODEC_AVC ? "MFX_CODEC_AVC" - : "MFX_CODEC_UNKNOWN"; - //std::cerr << "Unsupported decoder codec: codec=" << codec_str << std::endl; - return nullptr; - } - - //if (sts != MFX_ERR_NONE) { - // std::cout << "Supported specified codec but has warning: sts=" << sts - // << std::endl; - //} - - // Query した上で Init しても MFX_ERR_UNSUPPORTED になることがあるので - // 本来 Init が不要な時も常に呼ぶようにして確認する - /*if (init)*/ { - // Initialize the Media SDK encoder - sts = decoder->Init(¶m); - if (sts != MFX_ERR_NONE) { - return nullptr; - } - } - - return decoder; -} - -bool MsdkVideoDecoder::IsSupported(std::shared_ptr session, - mfxU32 codec) { - int width = 640; - int height = 480; - - auto decoder = CreateDecoder(session, codec, 640, 480, false); - - return decoder != nullptr; -} - -bool MsdkVideoDecoder::Configure( - const webrtc::VideoDecoder::Settings& settings) { - width_ = settings.max_render_resolution().Width(); - height_ = settings.max_render_resolution().Height(); - - return InitMediaSDK(); -} - -int32_t MsdkVideoDecoder::Decode(const webrtc::EncodedImage& input_image, - bool missing_frames, - int64_t render_time_ms) { - if (decoder_ == nullptr) { - return WEBRTC_VIDEO_CODEC_UNINITIALIZED; - } - if (decode_complete_callback_ == nullptr) { - return WEBRTC_VIDEO_CODEC_UNINITIALIZED; - } - if (input_image.data() == nullptr && input_image.size() > 0) { - return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; - } - - if (bitstream_.MaxLength < bitstream_.DataLength + input_image.size()) { - bitstream_buffer_.resize(bitstream_.DataLength + input_image.size()); - bitstream_.MaxLength = bitstream_.DataLength + bitstream_buffer_.size(); - bitstream_.Data = bitstream_buffer_.data(); - } - //printf("size=%zu\n", input_image.size()); - //for (size_t i = 0; i < input_image.size(); i++) { - // const uint8_t* p = input_image.data(); - // if (i < 100) { - // printf(" %02x", p[i]); - // } else { - // printf("\n"); - // break; - // } - //} - - memmove(bitstream_.Data, bitstream_.Data + bitstream_.DataOffset, - bitstream_.DataLength); - bitstream_.DataOffset = 0; - memcpy(bitstream_.Data + bitstream_.DataLength, input_image.data(), - input_image.size()); - bitstream_.DataLength += input_image.size(); - - // 使ってない入力サーフェスを取り出す - auto surface = - std::find_if(surfaces_.begin(), surfaces_.end(), - [](const mfxFrameSurface1& s) { return !s.Data.Locked; }); - if (surface == surfaces_.end()) { - RTC_LOG(LS_ERROR) << "Surface not found"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - // これだとキューイングしたデータとずれるので、本当は surface と一緒に保存して利用するべき - uint64_t pts = input_image.Timestamp(); - - mfxStatus sts; - mfxSyncPoint syncp; - mfxFrameSurface1* out_surface = nullptr; - //RTC_LOG(LS_ERROR) << "before DataOffset=" << bitstream_.DataOffset - // << " DataLength=" << bitstream_.DataLength; - while (true) { - sts = decoder_->DecodeFrameAsync(&bitstream_, &*surface, &out_surface, - &syncp); - if (sts == MFX_WRN_DEVICE_BUSY) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - break; - } - //RTC_LOG(LS_ERROR) << "after DataOffset=" << bitstream_.DataOffset - // << " DataLength=" << bitstream_.DataLength; - if (sts == MFX_ERR_MORE_DATA) { - // もっと入力が必要なので出直す - return WEBRTC_VIDEO_CODEC_OK; - } - if (!syncp) { - return WEBRTC_VIDEO_CODEC_OK; - } - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - - sts = session_->session.SyncOperation(syncp, 600000); - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - - // NV12 から I420 に変換 - rtc::scoped_refptr i420_buffer = - buffer_pool_.CreateI420Buffer(width_, height_); - libyuv::NV12ToI420(out_surface->Data.Y, out_surface->Data.Pitch, - out_surface->Data.UV, out_surface->Data.Pitch, - i420_buffer->MutableDataY(), i420_buffer->StrideY(), - i420_buffer->MutableDataU(), i420_buffer->StrideU(), - i420_buffer->MutableDataV(), i420_buffer->StrideV(), - width_, height_); - - webrtc::VideoFrame decoded_image = webrtc::VideoFrame::Builder() - .set_video_frame_buffer(i420_buffer) - .set_timestamp_rtp(pts) - .build(); - decode_complete_callback_->Decoded(decoded_image, absl::nullopt, - absl::nullopt); - - return WEBRTC_VIDEO_CODEC_OK; -} - -int32_t MsdkVideoDecoder::RegisterDecodeCompleteCallback( - webrtc::DecodedImageCallback* callback) { - decode_complete_callback_ = callback; - return WEBRTC_VIDEO_CODEC_OK; -} - -int32_t MsdkVideoDecoder::Release() { - ReleaseMediaSDK(); - buffer_pool_.Release(); - return WEBRTC_VIDEO_CODEC_OK; -} - -const char* MsdkVideoDecoder::ImplementationName() const { - return "Intel Media SDK"; -} - -bool MsdkVideoDecoder::InitMediaSDK() { - decoder_ = CreateDecoder(session_, codec_, width_, height_, true); - - mfxStatus sts = MFX_ERR_NONE; - - mfxVideoParam param; - memset(¶m, 0, sizeof(param)); - sts = decoder_->GetVideoParam(¶m); - if (sts != MFX_ERR_NONE) { - return false; - } - - // Query number of required surfaces for encoder - memset(&alloc_request_, 0, sizeof(alloc_request_)); - sts = decoder_->QueryIOSurf(¶m, &alloc_request_); - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - - RTC_LOG(LS_INFO) << "Decoder NumFrameSuggested=" - << alloc_request_.NumFrameSuggested; - - // 入力ビットストリーム - bitstream_buffer_.resize(1024 * 1024); - memset(&bitstream_, 0, sizeof(bitstream_)); - bitstream_.MaxLength = bitstream_buffer_.size(); - bitstream_.Data = bitstream_buffer_.data(); - - // 必要な枚数分の出力サーフェスを作る - { - int width = (alloc_request_.Info.Width + 31) / 32 * 32; - int height = (alloc_request_.Info.Height + 31) / 32 * 32; - // 1枚あたりのバイト数 - // NV12 なので 1 ピクセルあたり 12 ビット - int size = width * height * 12 / 8; - surface_buffer_.resize(alloc_request_.NumFrameSuggested * size); - - surfaces_.clear(); - surfaces_.reserve(alloc_request_.NumFrameSuggested); - for (int i = 0; i < alloc_request_.NumFrameSuggested; i++) { - mfxFrameSurface1 surface; - memset(&surface, 0, sizeof(surface)); - surface.Info = param.mfx.FrameInfo; - surface.Data.Y = surface_buffer_.data() + i * size; - surface.Data.U = surface_buffer_.data() + i * size + width * height; - surface.Data.V = surface_buffer_.data() + i * size + width * height + 1; - surface.Data.Pitch = width; - surfaces_.push_back(surface); - } - } - - return true; -} - -void MsdkVideoDecoder::ReleaseMediaSDK() { - if (decoder_ != nullptr) { - decoder_->Close(); - } - decoder_.reset(); -} diff --git a/src/hwenc_msdk/msdk_video_decoder.h b/src/hwenc_msdk/msdk_video_decoder.h deleted file mode 100644 index f4bc9052..00000000 --- a/src/hwenc_msdk/msdk_video_decoder.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef MSDK_VIDEO_DECODER_H_ -#define MSDK_VIDEO_DECODER_H_ - -// WebRTC -#include -#include -#include - -// msdk -#include -#include -#include - -#include "msdk_session.h" - -class MsdkVideoDecoder : public webrtc::VideoDecoder { - public: - MsdkVideoDecoder(std::shared_ptr session, mfxU32 codec); - ~MsdkVideoDecoder() override; - - // MFX_CODEC_VP8 - // MFX_CODEC_VP9 - // MFX_CODEC_AVC - // MFX_CODEC_AV1 - static bool IsSupported(std::shared_ptr session, mfxU32 codec); - - bool Configure(const Settings& settings) override; - - int32_t Decode(const webrtc::EncodedImage& input_image, - bool missing_frames, - int64_t render_time_ms) override; - - int32_t RegisterDecodeCompleteCallback( - webrtc::DecodedImageCallback* callback) override; - - int32_t Release() override; - - const char* ImplementationName() const override; - - private: - static std::unique_ptr CreateDecoder( - std::shared_ptr session, - mfxU32 codec, - int width, - int height, - bool init); - - bool InitMediaSDK(); - void ReleaseMediaSDK(); - - int width_ = 0; - int height_ = 0; - webrtc::DecodedImageCallback* decode_complete_callback_ = nullptr; - webrtc::VideoFrameBufferPool buffer_pool_; - - mfxU32 codec_; - std::shared_ptr session_; - mfxFrameAllocRequest alloc_request_; - std::unique_ptr decoder_; - std::vector surface_buffer_; - std::vector surfaces_; - std::vector bitstream_buffer_; - mfxBitstream bitstream_; -}; - -#endif // MSDK_VIDEO_DECODER_H_ \ No newline at end of file diff --git a/src/hwenc_msdk/msdk_video_encoder.cpp b/src/hwenc_msdk/msdk_video_encoder.cpp deleted file mode 100644 index 622c8cf4..00000000 --- a/src/hwenc_msdk/msdk_video_encoder.cpp +++ /dev/null @@ -1,511 +0,0 @@ -#include "msdk_video_encoder.h" - -#include - -// libyuv -#include - -#include "msdk_utils.h" - -const int kLowH264QpThreshold = 34; -const int kHighH264QpThreshold = 40; - -MsdkVideoEncoder::MsdkVideoEncoder(std::shared_ptr session, - mfxU32 codec) - : session_(session), codec_(codec), bitrate_adjuster_(0.5, 0.95) {} -MsdkVideoEncoder::~MsdkVideoEncoder() {} - -std::unique_ptr MsdkVideoEncoder::CreateEncoder( - std::shared_ptr session, - mfxU32 codec, - int width, - int height, - int framerate, - int target_kbps, - int max_kbps, - bool init) { - mfxStatus sts = MFX_ERR_NONE; - - mfxVideoParam param; - memset(¶m, 0, sizeof(param)); - - param.mfx.CodecId = codec; - if (codec == MFX_CODEC_VP8) { - //param.mfx.CodecProfile = MFX_PROFILE_VP8_0; - } else if (codec == MFX_CODEC_VP9) { - //param.mfx.CodecProfile = MFX_PROFILE_VP9_0; - } else if (codec == MFX_CODEC_AVC) { - //param.mfx.CodecProfile = MFX_PROFILE_AVC_HIGH; - //param.mfx.CodecLevel = MFX_LEVEL_AVC_51; - //param.mfx.CodecProfile = MFX_PROFILE_AVC_MAIN; - //param.mfx.CodecLevel = MFX_LEVEL_AVC_1; - } else if (codec == MFX_CODEC_AV1) { - //param.mfx.CodecProfile = MFX_PROFILE_AV1_MAIN; - } - param.mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED; - //param.mfx.BRCParamMultiplier = 1; - //param.mfx.InitialDelayInKB = target_kbps; - param.mfx.TargetKbps = target_kbps; - param.mfx.MaxKbps = max_kbps; - param.mfx.RateControlMethod = MFX_RATECONTROL_VBR; - //param.mfx.NumSlice = 1; - //param.mfx.NumRefFrame = 1; - param.mfx.FrameInfo.FrameRateExtN = framerate; - param.mfx.FrameInfo.FrameRateExtD = 1; - param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; - param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; - param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; - param.mfx.FrameInfo.CropX = 0; - param.mfx.FrameInfo.CropY = 0; - param.mfx.FrameInfo.CropW = width; - param.mfx.FrameInfo.CropH = height; - // Width must be a multiple of 16 - // Height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture - param.mfx.FrameInfo.Width = (width + 15) / 16 * 16; - param.mfx.FrameInfo.Height = (height + 15) / 16 * 16; - - //param.mfx.GopOptFlag = MFX_GOP_STRICT | MFX_GOP_CLOSED; - //param.mfx.IdrInterval = codec_settings->H264().keyFrameInterval; - //param.mfx.IdrInterval = 0; - param.mfx.GopRefDist = 1; - //param.mfx.EncodedOrder = 0; - param.AsyncDepth = 1; - param.IOPattern = - MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY; - - mfxExtBuffer* ext_buffers[10]; - mfxExtCodingOption ext_coding_option; - mfxExtCodingOption2 ext_coding_option2; - int ext_buffers_size = 0; - if (codec == MFX_CODEC_AVC) { - memset(&ext_coding_option, 0, sizeof(ext_coding_option)); - ext_coding_option.Header.BufferId = MFX_EXTBUFF_CODING_OPTION; - ext_coding_option.Header.BufferSz = sizeof(ext_coding_option); - ext_coding_option.AUDelimiter = MFX_CODINGOPTION_OFF; - ext_coding_option.MaxDecFrameBuffering = 1; - //ext_coding_option.NalHrdConformance = MFX_CODINGOPTION_OFF; - //ext_coding_option.VuiVclHrdParameters = MFX_CODINGOPTION_ON; - //ext_coding_option.SingleSeiNalUnit = MFX_CODINGOPTION_ON; - //ext_coding_option.RefPicMarkRep = MFX_CODINGOPTION_OFF; - //ext_coding_option.PicTimingSEI = MFX_CODINGOPTION_OFF; - //ext_coding_option.RecoveryPointSEI = MFX_CODINGOPTION_OFF; - //ext_coding_option.FramePicture = MFX_CODINGOPTION_OFF; - //ext_coding_option.FieldOutput = MFX_CODINGOPTION_ON; - - memset(&ext_coding_option2, 0, sizeof(ext_coding_option2)); - ext_coding_option2.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; - ext_coding_option2.Header.BufferSz = sizeof(ext_coding_option2); - ext_coding_option2.RepeatPPS = MFX_CODINGOPTION_ON; - //ext_coding_option2.MaxSliceSize = 1; - //ext_coding_option2.AdaptiveI = MFX_CODINGOPTION_ON; - - ext_buffers[0] = (mfxExtBuffer*)&ext_coding_option; - ext_buffers[1] = (mfxExtBuffer*)&ext_coding_option2; - ext_buffers_size = 2; - } - - if (ext_buffers_size != 0) { - param.ExtParam = ext_buffers; - param.NumExtParam = ext_buffers_size; - } - - std::unique_ptr encoder(new MFXVideoENCODE(session->session)); - - // MFX_ERR_NONE The function completed successfully. - // MFX_ERR_UNSUPPORTED The function failed to identify a specific implementation for the required features. - // MFX_WRN_PARTIAL_ACCELERATION The underlying hardware does not fully support the specified video parameters; The encoding may be partially accelerated. Only SDK HW implementations may return this status code. - // MFX_WRN_INCOMPATIBLE_VIDEO_PARAM The function detected some video parameters were incompatible with others; incompatibility resolved. - mfxVideoParam bk_param; - memcpy(&bk_param, ¶m, sizeof(bk_param)); - sts = encoder->Query(¶m, ¶m); - if (sts < 0) { - memcpy(¶m, &bk_param, sizeof(bk_param)); - - // 失敗したら LowPower ON にした状態でもう一度確認する - param.mfx.LowPower = MFX_CODINGOPTION_ON; - if (codec == MFX_CODEC_AVC) { - param.mfx.RateControlMethod = MFX_RATECONTROL_CQP; - param.mfx.QPI = 25; - param.mfx.QPP = 33; - param.mfx.QPB = 40; - //param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; - } - memcpy(&bk_param, ¶m, sizeof(bk_param)); - sts = encoder->Query(¶m, ¶m); - if (sts < 0) { - const char* codec_str = codec == MFX_CODEC_VP8 ? "MFX_CODEC_VP8" - : codec == MFX_CODEC_VP9 ? "MFX_CODEC_VP9" - : codec == MFX_CODEC_AV1 ? "MFX_CODEC_AV1" - : codec == MFX_CODEC_AVC ? "MFX_CODEC_AVC" - : "MFX_CODEC_UNKNOWN"; - //std::cerr << "Unsupported encoder codec: codec=" << codec_str - // << std::endl; - return nullptr; - } - } - - //#define F(NAME) \ - // if (bk_param.NAME != param.NAME) \ - // std::cout << "param " << #NAME << " old=" << bk_param.NAME \ - // << " new=" << param.NAME << std::endl - // - // F(mfx.LowPower); - // F(mfx.BRCParamMultiplier); - // F(mfx.FrameInfo.FrameRateExtN); - // F(mfx.FrameInfo.FrameRateExtD); - // F(mfx.FrameInfo.FourCC); - // F(mfx.FrameInfo.ChromaFormat); - // F(mfx.FrameInfo.PicStruct); - // F(mfx.FrameInfo.CropX); - // F(mfx.FrameInfo.CropY); - // F(mfx.FrameInfo.CropW); - // F(mfx.FrameInfo.CropH); - // F(mfx.FrameInfo.Width); - // F(mfx.FrameInfo.Height); - // F(mfx.CodecId); - // F(mfx.CodecProfile); - // F(mfx.CodecLevel); - // F(mfx.GopPicSize); - // F(mfx.GopRefDist); - // F(mfx.GopOptFlag); - // F(mfx.IdrInterval); - // F(mfx.TargetUsage); - // F(mfx.RateControlMethod); - // F(mfx.InitialDelayInKB); - // F(mfx.TargetKbps); - // F(mfx.MaxKbps); - // F(mfx.BufferSizeInKB); - // F(mfx.NumSlice); - // F(mfx.NumRefFrame); - // F(mfx.EncodedOrder); - // F(mfx.DecodedOrder); - // F(mfx.ExtendedPicStruct); - // F(mfx.TimeStampCalc); - // F(mfx.SliceGroupsPresent); - // F(mfx.MaxDecFrameBuffering); - // F(mfx.EnableReallocRequest); - // F(AsyncDepth); - // F(IOPattern); - //#undef F - - //if (sts != MFX_ERR_NONE) { - // const char* codec_str = codec == MFX_CODEC_VP8 ? "MFX_CODEC_VP8" - // : codec == MFX_CODEC_VP9 ? "MFX_CODEC_VP9" - // : codec == MFX_CODEC_AV1 ? "MFX_CODEC_AV1" - // : codec == MFX_CODEC_AVC ? "MFX_CODEC_AVC" - // : "MFX_CODEC_UNKNOWN"; - // std::cerr << "Supported specified codec but has warning: codec=" - // << codec_str << " sts=" << sts << std::endl; - //} - - if (init) { - sts = encoder->Init(¶m); - if (sts != MFX_ERR_NONE) { - RTC_LOG(LS_ERROR) << "Failed to Init: sts=" << sts; - return nullptr; - } - } - - return encoder; -} - -bool MsdkVideoEncoder::IsSupported(std::shared_ptr session, - mfxU32 codec) { - auto encoder = CreateEncoder(session, codec, 1920, 1080, 30, 10, 20, false); - return encoder != nullptr; -} - -int32_t MsdkVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, - int32_t number_of_cores, - size_t max_payload_size) { - RTC_DCHECK(codec_settings); - RTC_DCHECK_EQ(codec_settings->codecType, webrtc::kVideoCodecH264); - - int32_t release_ret = Release(); - if (release_ret != WEBRTC_VIDEO_CODEC_OK) { - return release_ret; - } - - width_ = codec_settings->width; - height_ = codec_settings->height; - target_bitrate_bps_ = codec_settings->startBitrate * 1000; - max_bitrate_bps_ = codec_settings->maxBitrate * 1000; - bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); - framerate_ = codec_settings->maxFramerate; - mode_ = codec_settings->mode; - - RTC_LOG(LS_INFO) << "InitEncode " << target_bitrate_bps_ << "bit/sec"; - - // Initialize encoded image. Default buffer size: size of unencoded data. - encoded_image_._encodedWidth = 0; - encoded_image_._encodedHeight = 0; - encoded_image_.set_size(0); - encoded_image_.timing_.flags = - webrtc::VideoSendTiming::TimingFrameFlags::kInvalid; - encoded_image_.content_type_ = - (codec_settings->mode == webrtc::VideoCodecMode::kScreensharing) - ? webrtc::VideoContentType::SCREENSHARE - : webrtc::VideoContentType::UNSPECIFIED; - - return InitMediaSDK(); -} -int32_t MsdkVideoEncoder::RegisterEncodeCompleteCallback( - webrtc::EncodedImageCallback* callback) { - std::lock_guard lock(mutex_); - callback_ = callback; - return WEBRTC_VIDEO_CODEC_OK; -} -int32_t MsdkVideoEncoder::Release() { - return ReleaseMediaSDK(); -} -int32_t MsdkVideoEncoder::Encode( - const webrtc::VideoFrame& frame, - const std::vector* frame_types) { - bool send_key_frame = false; - - if (frame_types != nullptr) { - // We only support a single stream. - RTC_DCHECK_EQ(frame_types->size(), static_cast(1)); - // Skip frame? - if ((*frame_types)[0] == webrtc::VideoFrameType::kEmptyFrame) { - return WEBRTC_VIDEO_CODEC_OK; - } - // Force key frame? - send_key_frame = - (*frame_types)[0] == webrtc::VideoFrameType::kVideoFrameKey; - } - - // 使ってない入力サーフェスを取り出す - auto surface = - std::find_if(surfaces_.begin(), surfaces_.end(), - [](const mfxFrameSurface1& s) { return !s.Data.Locked; }); - if (surface == surfaces_.end()) { - RTC_LOG(LS_ERROR) << "Surface not found"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - // I420 から NV12 に変換 - rtc::scoped_refptr frame_buffer = - frame.video_frame_buffer()->ToI420(); - libyuv::I420ToNV12( - frame_buffer->DataY(), frame_buffer->StrideY(), frame_buffer->DataU(), - frame_buffer->StrideU(), frame_buffer->DataV(), frame_buffer->StrideV(), - surface->Data.Y, surface->Data.Pitch, surface->Data.U, - surface->Data.Pitch, frame_buffer->width(), frame_buffer->height()); - - mfxStatus sts; - - mfxEncodeCtrl ctrl; - memset(&ctrl, 0, sizeof(ctrl)); - //send_key_frame = true; - if (send_key_frame) { - ctrl.FrameType = MFX_FRAMETYPE_I | MFX_FRAMETYPE_IDR | MFX_FRAMETYPE_REF; - } else { - ctrl.FrameType = MFX_FRAMETYPE_UNKNOWN; - } - - if (reconfigure_needed_) { - auto start_time = std::chrono::system_clock::now(); - RTC_LOG(LS_INFO) << "Start reconfigure: bps=" - << (bitrate_adjuster_.GetAdjustedBitrateBps() / 1000) - << " framerate=" << framerate_; - // 今の設定を取得する - mfxVideoParam param; - memset(¶m, 0, sizeof(param)); - - sts = encoder_->GetVideoParam(¶m); - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - - // ビットレートとフレームレートを変更する。 - // なお、encoder_->Reset() はキューイングしているサーフェスを - // 全て処理してから呼び出す必要がある。 - // ここでは encoder_->Init() の時に - // param.mfx.GopRefDist = 1; - // param.AsyncDepth = 1; - // ext_coding_option.MaxDecFrameBuffering = 1; - // を設定して、そもそもキューイングが起きないようにすることで対処している。 - if (param.mfx.RateControlMethod == MFX_RATECONTROL_CQP) { - //param.mfx.QPI = h264_bitstream_parser_.GetLastSliceQp().value_or(30); - } else { - param.mfx.TargetKbps = bitrate_adjuster_.GetAdjustedBitrateBps() / 1000; - } - param.mfx.FrameInfo.FrameRateExtN = framerate_; - param.mfx.FrameInfo.FrameRateExtD = 1; - - sts = encoder_->Reset(¶m); - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - - reconfigure_needed_ = false; - - auto end_time = std::chrono::system_clock::now(); - RTC_LOG(LS_INFO) << "Finish reconfigure: " - << std::chrono::duration_cast( - end_time - start_time) - .count() - << " ms"; - } - - // NV12 をハードウェアエンコード - mfxSyncPoint syncp; - sts = encoder_->EncodeFrameAsync(&ctrl, &*surface, &bitstream_, &syncp); - // alloc_request_.NumFrameSuggested が 1 の場合は MFX_ERR_MORE_DATA は発生しない - if (sts == MFX_ERR_MORE_DATA) { - // もっと入力が必要なので出直す - return WEBRTC_VIDEO_CODEC_OK; - } - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - - sts = session_->session.SyncOperation(syncp, 600000); - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - - //RTC_LOG(LS_ERROR) << "SurfaceSize=" << (surface->Data.U - surface->Data.Y); - //RTC_LOG(LS_ERROR) << "DataLength=" << bitstream_.DataLength; - { - uint8_t* p = bitstream_.Data + bitstream_.DataOffset; - int size = bitstream_.DataLength; - bitstream_.DataLength = 0; - - //FILE* fp = fopen("test.mp4", "a+"); - //fwrite(p, 1, size, fp); - //fclose(fp); - - auto buf = webrtc::EncodedImageBuffer::Create(p, size); - encoded_image_.SetEncodedData(buf); - encoded_image_._encodedWidth = width_; - encoded_image_._encodedHeight = height_; - encoded_image_.content_type_ = - (mode_ == webrtc::VideoCodecMode::kScreensharing) - ? webrtc::VideoContentType::SCREENSHARE - : webrtc::VideoContentType::UNSPECIFIED; - encoded_image_.timing_.flags = webrtc::VideoSendTiming::kInvalid; - encoded_image_.SetTimestamp(frame.timestamp()); - encoded_image_.ntp_time_ms_ = frame.ntp_time_ms(); - encoded_image_.capture_time_ms_ = frame.render_time_ms(); - encoded_image_.rotation_ = frame.rotation(); - encoded_image_.SetColorSpace(frame.color_space()); - if (bitstream_.FrameType == MFX_FRAMETYPE_I || - bitstream_.FrameType == MFX_FRAMETYPE_IDR) { - encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameKey; - } else { - encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameDelta; - } - - webrtc::CodecSpecificInfo codec_specific; - if (codec_ == MFX_CODEC_AVC) { - codec_specific.codecType = webrtc::kVideoCodecH264; - codec_specific.codecSpecific.H264.packetization_mode = - webrtc::H264PacketizationMode::NonInterleaved; - } - - h264_bitstream_parser_.ParseBitstream(encoded_image_); - encoded_image_.qp_ = h264_bitstream_parser_.GetLastSliceQp().value_or(-1); - - webrtc::EncodedImageCallback::Result result = - callback_->OnEncodedImage(encoded_image_, &codec_specific); - if (result.error != webrtc::EncodedImageCallback::Result::OK) { - RTC_LOG(LS_ERROR) << __FUNCTION__ - << " OnEncodedImage failed error:" << result.error; - return WEBRTC_VIDEO_CODEC_ERROR; - } - bitrate_adjuster_.Update(size); - } - - return WEBRTC_VIDEO_CODEC_OK; -} -void MsdkVideoEncoder::SetRates(const RateControlParameters& parameters) { - if (parameters.framerate_fps < 1.0) { - RTC_LOG(LS_WARNING) << "Invalid frame rate: " << parameters.framerate_fps; - return; - } - - uint32_t new_framerate = (uint32_t)parameters.framerate_fps; - uint32_t new_bitrate = parameters.bitrate.get_sum_bps(); - RTC_LOG(LS_INFO) << __FUNCTION__ << " framerate_:" << framerate_ - << " new_framerate: " << new_framerate - << " target_bitrate_bps_:" << target_bitrate_bps_ - << " new_bitrate:" << new_bitrate - << " max_bitrate_bps_:" << max_bitrate_bps_; - framerate_ = new_framerate; - target_bitrate_bps_ = new_bitrate; - bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); - reconfigure_needed_ = true; -} -webrtc::VideoEncoder::EncoderInfo MsdkVideoEncoder::GetEncoderInfo() const { - webrtc::VideoEncoder::EncoderInfo info; - info.supports_native_handle = true; - info.implementation_name = "NvCodec H264"; - info.scaling_settings = webrtc::VideoEncoder::ScalingSettings( - kLowH264QpThreshold, kHighH264QpThreshold); - info.is_hardware_accelerated = true; - return info; -} - -int32_t MsdkVideoEncoder::InitMediaSDK() { - encoder_ = CreateEncoder(session_, codec_, width_, height_, framerate_, - bitrate_adjuster_.GetAdjustedBitrateBps() / 1000, - max_bitrate_bps_ / 1000, true); - if (encoder_ == nullptr) { - RTC_LOG(LS_ERROR) << "Failed to create encoder"; - return WEBRTC_VIDEO_CODEC_ERROR; - } - - mfxStatus sts = MFX_ERR_NONE; - - mfxVideoParam param; - memset(¶m, 0, sizeof(param)); - - // Retrieve video parameters selected by encoder. - // - BufferSizeInKB parameter is required to set bit stream buffer size - sts = encoder_->GetVideoParam(¶m); - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - RTC_LOG(LS_INFO) << "BufferSizeInKB=" << param.mfx.BufferSizeInKB; - - // Query number of required surfaces for encoder - memset(&alloc_request_, 0, sizeof(alloc_request_)); - sts = encoder_->QueryIOSurf(¶m, &alloc_request_); - MSDK_CHECK_RESULT(sts, MFX_ERR_NONE, sts); - - RTC_LOG(LS_INFO) << "Encoder NumFrameSuggested=" - << alloc_request_.NumFrameSuggested; - - frame_info_ = param.mfx.FrameInfo; - - // 出力ビットストリームの初期化 - bitstream_buffer_.resize(param.mfx.BufferSizeInKB * 1000); - - memset(&bitstream_, 0, sizeof(bitstream_)); - bitstream_.MaxLength = bitstream_buffer_.size(); - bitstream_.Data = bitstream_buffer_.data(); - - // 必要な枚数分の入力サーフェスを作る - { - int width = (alloc_request_.Info.Width + 31) / 32 * 32; - int height = (alloc_request_.Info.Height + 31) / 32 * 32; - // 1枚あたりのバイト数 - // NV12 なので 1 ピクセルあたり 12 ビット - int size = width * height * 12 / 8; - surface_buffer_.resize(alloc_request_.NumFrameSuggested * size); - - surfaces_.clear(); - surfaces_.reserve(alloc_request_.NumFrameSuggested); - for (int i = 0; i < alloc_request_.NumFrameSuggested; i++) { - mfxFrameSurface1 surface; - memset(&surface, 0, sizeof(surface)); - surface.Info = frame_info_; - surface.Data.Y = surface_buffer_.data() + i * size; - surface.Data.U = surface_buffer_.data() + i * size + width * height; - surface.Data.V = surface_buffer_.data() + i * size + width * height + 1; - surface.Data.Pitch = width; - surfaces_.push_back(surface); - } - } - - return WEBRTC_VIDEO_CODEC_OK; -} -int32_t MsdkVideoEncoder::ReleaseMediaSDK() { - if (encoder_ != nullptr) { - encoder_->Close(); - } - encoder_.reset(); - return WEBRTC_VIDEO_CODEC_OK; -} \ No newline at end of file diff --git a/src/hwenc_msdk/msdk_video_encoder.h b/src/hwenc_msdk/msdk_video_encoder.h deleted file mode 100644 index d0a3c3c2..00000000 --- a/src/hwenc_msdk/msdk_video_encoder.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef MSDK_VIDEO_ENCODER_H_ -#define MSDK_VIDEO_ENCODER_H_ - -#include -#include - -// WebRTC -#include -#include -#include -#include -#include -#include - -// msdk -#include -#include - -#include "msdk_session.h" - -class MsdkVideoEncoder : public webrtc::VideoEncoder { - public: - explicit MsdkVideoEncoder(std::shared_ptr session, mfxU32 codec); - ~MsdkVideoEncoder() override; - - // MFX_CODEC_VP8 - // MFX_CODEC_VP9 - // MFX_CODEC_AVC - // MFX_CODEC_AV1 - static bool IsSupported(std::shared_ptr session, mfxU32 codec); - - int32_t InitEncode(const webrtc::VideoCodec* codec_settings, - int32_t number_of_cores, - size_t max_payload_size) override; - int32_t RegisterEncodeCompleteCallback( - webrtc::EncodedImageCallback* callback) override; - int32_t Release() override; - int32_t Encode( - const webrtc::VideoFrame& frame, - const std::vector* frame_types) override; - void SetRates(const RateControlParameters& parameters) override; - webrtc::VideoEncoder::EncoderInfo GetEncoderInfo() const override; - - private: - static std::unique_ptr CreateEncoder( - std::shared_ptr session, - mfxU32 codec, - int width, - int height, - int framerate, - int target_kbps, - int max_kbps, - bool init); - - std::mutex mutex_; - webrtc::EncodedImageCallback* callback_ = nullptr; - webrtc::BitrateAdjuster bitrate_adjuster_; - uint32_t target_bitrate_bps_ = 0; - uint32_t max_bitrate_bps_ = 0; - bool reconfigure_needed_ = false; - bool use_native_ = false; - uint32_t width_ = 0; - uint32_t height_ = 0; - uint32_t framerate_ = 0; - webrtc::VideoCodecMode mode_ = webrtc::VideoCodecMode::kRealtimeVideo; - std::vector> v_packet_; - webrtc::EncodedImage encoded_image_; - webrtc::H264BitstreamParser h264_bitstream_parser_; - - int32_t InitMediaSDK(); - int32_t ReleaseMediaSDK(); - - std::vector surface_buffer_; - std::vector surfaces_; - - std::shared_ptr session_; - mfxU32 codec_; - mfxFrameAllocRequest alloc_request_; - std::unique_ptr encoder_; - std::vector bitstream_buffer_; - mfxBitstream bitstream_; - mfxFrameInfo frame_info_; -}; - -#endif // MSDK_VIDEO_ENCODER_H_ \ No newline at end of file diff --git a/src/hwenc_nvcodec/nvcodec_h264_encoder.h b/src/hwenc_nvcodec/nvcodec_h264_encoder.h deleted file mode 100644 index 209906bf..00000000 --- a/src/hwenc_nvcodec/nvcodec_h264_encoder.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef NVCODEC_H264_ENCODER_H_ -#define NVCODEC_H264_ENCODER_H_ - -#ifdef _WIN32 -#include -#include -#endif - -#include -#include -#include -#include - -// WebRTC -#include -#include -#include -#include - -// NvCodec -#ifdef _WIN32 -#include -#endif -#ifdef __linux__ -#include "cuda/cuda_context.h" -#include "nvcodec_h264_encoder_cuda.h" -#endif - -class NvCodecH264Encoder : public webrtc::VideoEncoder { - public: -#ifdef __linux__ - explicit NvCodecH264Encoder(const cricket::VideoCodec& codec, - std::shared_ptr cc); -#else - explicit NvCodecH264Encoder(const cricket::VideoCodec& codec); -#endif - ~NvCodecH264Encoder() override; - - static bool IsSupported(); - - int32_t InitEncode(const webrtc::VideoCodec* codec_settings, - int32_t number_of_cores, - size_t max_payload_size) override; - int32_t RegisterEncodeCompleteCallback( - webrtc::EncodedImageCallback* callback) override; - int32_t Release() override; - int32_t Encode( - const webrtc::VideoFrame& frame, - const std::vector* frame_types) override; - void SetRates( - const webrtc::VideoEncoder::RateControlParameters& parameters) override; - webrtc::VideoEncoder::EncoderInfo GetEncoderInfo() const override; - - private: - std::mutex mutex_; - webrtc::EncodedImageCallback* callback_ = nullptr; - webrtc::BitrateAdjuster bitrate_adjuster_; - uint32_t target_bitrate_bps_ = 0; - uint32_t max_bitrate_bps_ = 0; - - int32_t InitNvEnc(); - int32_t ReleaseNvEnc(); - webrtc::H264BitstreamParser h264_bitstream_parser_; - -#ifdef _WIN32 - Microsoft::WRL::ComPtr id3d11_device_; - Microsoft::WRL::ComPtr id3d11_context_; - Microsoft::WRL::ComPtr id3d11_texture_; - std::unique_ptr nv_encoder_; -#endif -#ifdef __linux__ - std::shared_ptr cuda_context_; - std::unique_ptr cuda_; - std::unique_ptr nv_encoder_; -#endif - bool reconfigure_needed_ = false; - bool use_native_ = false; - uint32_t width_ = 0; - uint32_t height_ = 0; - uint32_t framerate_ = 0; - webrtc::VideoCodecMode mode_ = webrtc::VideoCodecMode::kRealtimeVideo; - NV_ENC_INITIALIZE_PARAMS initialize_params_; - std::vector> v_packet_; - webrtc::EncodedImage encoded_image_; -}; - -#endif // NVCODEC_H264_ENCODER_H_ diff --git a/src/hwenc_nvcodec/nvcodec_h264_encoder_cuda.h b/src/hwenc_nvcodec/nvcodec_h264_encoder_cuda.h deleted file mode 100644 index 54c61aaf..00000000 --- a/src/hwenc_nvcodec/nvcodec_h264_encoder_cuda.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef NVCODEC_H264_ENCODER_CUDA_H_ -#define NVCODEC_H264_ENCODER_CUDA_H_ - -// CUDA と WebRTC のヘッダを混ぜてコンパイルすると酷いことになったので、 -// CUDA の処理だけさせる単純な CUDA ファイルを用意する - -// このヘッダーファイルは、外から呼ばれるので #include をしてはいけない -// また、CUDA 側に WebRTC のヘッダを混ぜることができないので WebRTC のヘッダも include してはいけない - -#include - -#include "cuda/cuda_context.h" - -class NvCodecH264EncoderCudaImpl; - -class NvCodecH264EncoderCuda { - public: - NvCodecH264EncoderCuda(std::shared_ptr ctx); - ~NvCodecH264EncoderCuda(); - - void Copy(NvEncoder* nv_encoder, const void* ptr, int width, int height); - // 念のため も include せずポインタを利用する - NvEncoder* CreateNvEncoder(int width, int height, bool use_native); - - private: - NvCodecH264EncoderCudaImpl* impl_; -}; - -#endif // NVCODEC_H264_ENCODER_CUDA_H_ diff --git a/src/hwenc_v4l2/libcamera_capturer.cpp b/src/hwenc_v4l2/libcamera_capturer.cpp index ffa71abf..58475a49 100644 --- a/src/hwenc_v4l2/libcamera_capturer.cpp +++ b/src/hwenc_v4l2/libcamera_capturer.cpp @@ -72,7 +72,7 @@ rtc::scoped_refptr LibcameraCapturer::Create( } LibcameraCapturer::LibcameraCapturer() - : ScalableVideoTrackSource(ScalableVideoTrackSourceConfig()), + : sora::ScalableVideoTrackSource(sora::ScalableVideoTrackSourceConfig()), acquired_(false), controls_(libcameracpp_ControlList_controls()), camera_started_(false) {} diff --git a/src/hwenc_v4l2/libcamera_capturer.h b/src/hwenc_v4l2/libcamera_capturer.h index d6a5ded8..fd94b3f0 100644 --- a/src/hwenc_v4l2/libcamera_capturer.h +++ b/src/hwenc_v4l2/libcamera_capturer.h @@ -5,15 +5,14 @@ #include #include -#include - #include "libcamerac/libcameracpp.h" -#include "rtc/scalable_track_source.h" +#include "sora/scalable_track_source.h" +#include "sora/v4l2/v4l2_video_capturer.h" -struct LibcameraCapturerConfig : V4L2VideoCapturerConfig { +struct LibcameraCapturerConfig : sora::V4L2VideoCapturerConfig { LibcameraCapturerConfig() {} - LibcameraCapturerConfig(const V4L2VideoCapturerConfig& config) { - *static_cast(this) = config; + LibcameraCapturerConfig(const sora::V4L2VideoCapturerConfig& config) { + *static_cast(this) = config; } LibcameraCapturerConfig(const LibcameraCapturerConfig& config) { *this = config; @@ -29,7 +28,7 @@ struct LibcameraCapturerConfig : V4L2VideoCapturerConfig { // 出力の形式として、fd そのままで取得する形式と、メモリ上にコピーして取得する形式がある // 渡されるフレームバッファは、fd そのままで取得する場合は V4L2NativeBuffer クラスになり、 // メモリ上にコピーする場合は webrtc::I420Buffer クラスになる。 -class LibcameraCapturer : public ScalableVideoTrackSource { +class LibcameraCapturer : public sora::ScalableVideoTrackSource { public: static rtc::scoped_refptr Create( LibcameraCapturerConfig config); diff --git a/src/hwenc_v4l2/v4l2_capturer.cpp b/src/hwenc_v4l2/v4l2_capturer.cpp index cedc9432..c8fddf55 100644 --- a/src/hwenc_v4l2/v4l2_capturer.cpp +++ b/src/hwenc_v4l2/v4l2_capturer.cpp @@ -10,8 +10,8 @@ #include "v4l2_native_buffer.h" -rtc::scoped_refptr V4L2Capturer::Create( - V4L2VideoCapturerConfig config) { +rtc::scoped_refptr V4L2Capturer::Create( + sora::V4L2VideoCapturerConfig config) { rtc::scoped_refptr capturer; std::unique_ptr device_info( webrtc::VideoCaptureFactory::CreateDeviceInfo()); @@ -33,16 +33,12 @@ rtc::scoped_refptr V4L2Capturer::Create( return nullptr; } -V4L2Capturer::V4L2Capturer(const V4L2VideoCapturerConfig& config) - : V4L2VideoCapturer(config) {} +V4L2Capturer::V4L2Capturer(const sora::V4L2VideoCapturerConfig& config) + : sora::V4L2VideoCapturer(config) {} -bool V4L2Capturer::UseNativeBuffer() { - return true; -} - -rtc::scoped_refptr V4L2Capturer::Create( +rtc::scoped_refptr V4L2Capturer::Create( webrtc::VideoCaptureModule::DeviceInfo* device_info, - V4L2VideoCapturerConfig config, + sora::V4L2VideoCapturerConfig config, size_t capture_device_index) { char device_name[256]; char unique_name[256]; @@ -57,7 +53,7 @@ rtc::scoped_refptr V4L2Capturer::Create( rtc::scoped_refptr v4l2_capturer = rtc::make_ref_counted(config); - if (v4l2_capturer->Init((const char*)&unique_name, config.video_device) < 0) { + if (v4l2_capturer->Init((const char*)&unique_name) < 0) { RTC_LOG(LS_WARNING) << "Failed to create V4L2Capturer(" << unique_name << ")"; return nullptr; diff --git a/src/hwenc_v4l2/v4l2_capturer.h b/src/hwenc_v4l2/v4l2_capturer.h index d6e102a3..e93f394c 100644 --- a/src/hwenc_v4l2/v4l2_capturer.h +++ b/src/hwenc_v4l2/v4l2_capturer.h @@ -1,20 +1,18 @@ #ifndef V4L2_CAPTURER_H_ #define V4L2_CAPTURER_H_ -#include "../v4l2_video_capturer/v4l2_video_capturer.h" +#include "sora/v4l2/v4l2_video_capturer.h" -class V4L2Capturer : public V4L2VideoCapturer { +class V4L2Capturer : public sora::V4L2VideoCapturer { public: - static rtc::scoped_refptr Create( - V4L2VideoCapturerConfig config); - V4L2Capturer(const V4L2VideoCapturerConfig& config); - - bool UseNativeBuffer() override; + static rtc::scoped_refptr Create( + sora::V4L2VideoCapturerConfig config); + V4L2Capturer(const sora::V4L2VideoCapturerConfig& config); private: - static rtc::scoped_refptr Create( + static rtc::scoped_refptr Create( webrtc::VideoCaptureModule::DeviceInfo* device_info, - V4L2VideoCapturerConfig config, + sora::V4L2VideoCapturerConfig config, size_t capture_device_index); void OnCaptured(uint8_t* data, uint32_t bytesused) override; diff --git a/src/hwenc_v4l2/v4l2_h264_decoder.cpp b/src/hwenc_v4l2/v4l2_h264_decoder.cpp index 9e94e8ce..d673e748 100644 --- a/src/hwenc_v4l2/v4l2_h264_decoder.cpp +++ b/src/hwenc_v4l2/v4l2_h264_decoder.cpp @@ -40,7 +40,7 @@ int32_t V4L2H264Decoder::Decode(const webrtc::EncodedImage& input_image, } decoder_->Decode( - input_image.data(), input_image.size(), input_image.Timestamp(), + input_image.data(), input_image.size(), input_image.RtpTimestamp(), [this](rtc::scoped_refptr buffer, int64_t timestamp_rtp) { webrtc::VideoFrame decoded_image = webrtc::VideoFrame::Builder() diff --git a/src/hwenc_v4l2/v4l2_h264_encoder.cpp b/src/hwenc_v4l2/v4l2_h264_encoder.cpp index f9379c14..8b164943 100644 --- a/src/hwenc_v4l2/v4l2_h264_encoder.cpp +++ b/src/hwenc_v4l2/v4l2_h264_encoder.cpp @@ -11,6 +11,9 @@ // WebRTC #include +#include +#include +#include #include #include #include @@ -306,7 +309,7 @@ int32_t V4L2H264Encoder::SendFrame(const webrtc::VideoFrame& frame, encoded_image_._encodedHeight = frame.height(); encoded_image_.capture_time_ms_ = frame.render_time_ms(); encoded_image_.ntp_time_ms_ = frame.ntp_time_ms(); - encoded_image_.SetTimestamp(frame.timestamp()); + encoded_image_.SetRtpTimestamp(frame.timestamp()); encoded_image_.rotation_ = frame.rotation(); encoded_image_.SetColorSpace(frame.color_space()); encoded_image_._frameType = is_key_frame diff --git a/src/hwenc_v4l2/v4l2_h264_encoder.h b/src/hwenc_v4l2/v4l2_h264_encoder.h index 24b7501b..6ebc9aed 100644 --- a/src/hwenc_v4l2/v4l2_h264_encoder.h +++ b/src/hwenc_v4l2/v4l2_h264_encoder.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/src/mac_helper/mac_capturer.h b/src/mac_helper/mac_capturer.h index 7e4c0430..21ad6a18 100644 --- a/src/mac_helper/mac_capturer.h +++ b/src/mac_helper/mac_capturer.h @@ -19,14 +19,14 @@ #include #include #include -#include +#include #include RTC_FWD_DECL_OBJC_CLASS(AVCaptureDevice); RTC_FWD_DECL_OBJC_CLASS(RTCCameraVideoCapturer); RTC_FWD_DECL_OBJC_CLASS(RTCVideoSourceAdapter); -class MacCapturer : public ScalableVideoTrackSource, +class MacCapturer : public sora::ScalableVideoTrackSource, public rtc::VideoSinkInterface { public: static rtc::scoped_refptr Create( diff --git a/src/mac_helper/mac_capturer.mm b/src/mac_helper/mac_capturer.mm index 5564416d..0baf0d1a 100644 --- a/src/mac_helper/mac_capturer.mm +++ b/src/mac_helper/mac_capturer.mm @@ -62,13 +62,29 @@ - (void)capturer:(RTCVideoCapturer*)capturer return selectedFormat; } +static NSArray* captureDevices() { + if (@available(macOS 14, *)) { + // macOS 14 以上では、新しい API を使用して外部カメラも取得する + AVCaptureDeviceDiscoverySession *session = [AVCaptureDeviceDiscoverySession + discoverySessionWithDeviceTypes:@[ + AVCaptureDeviceTypeBuiltInWideAngleCamera, + AVCaptureDeviceTypeExternal ] + mediaType:AVMediaTypeVideo + position:AVCaptureDevicePositionUnspecified]; + return session.devices; + } else { + // macOS 13 以下では、古い API を使用して内蔵カメラのみ取得する + return [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + } +} + } // namespace MacCapturer::MacCapturer(size_t width, size_t height, size_t target_fps, AVCaptureDevice* device) - : ScalableVideoTrackSource(ScalableVideoTrackSourceConfig()) { + : sora::ScalableVideoTrackSource(sora::ScalableVideoTrackSourceConfig()) { RTC_LOG(LS_INFO) << "MacCapturer width=" << width << ", height=" << height << ", target_fps=" << target_fps; @@ -100,7 +116,7 @@ - (void)capturer:(RTCVideoCapturer*)capturer // https://www.ffmpeg.org/ffmpeg-devices.html#avfoundation size_t capture_device_index = SIZE_T_MAX; - NSArray* devices = [RTCCameraVideoCapturer captureDevices]; + NSArray* devices = captureDevices(); [devices enumerateObjectsUsingBlock:^(AVCaptureDevice* device, NSUInteger i, BOOL* stop) { // 便利なのでデバイスの一覧をログに出力しておく @@ -136,8 +152,7 @@ - (void)capturer:(RTCVideoCapturer*)capturer } if (capture_device_index != SIZE_T_MAX) { - AVCaptureDevice* device = [[RTCCameraVideoCapturer captureDevices] - objectAtIndex:capture_device_index]; + AVCaptureDevice* device = [devices objectAtIndex:capture_device_index]; RTC_LOG(LS_INFO) << "selected video device: [" << capture_device_index << "] device_name=" << [device.localizedName UTF8String]; return device; diff --git a/src/main.cpp b/src/main.cpp index 1424710e..63573f17 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,33 +10,29 @@ #include #include -#if USE_SCREEN_CAPTURER +#if defined(USE_SCREEN_CAPTURER) #include "rtc/screen_video_capturer.h" #endif #if defined(__APPLE__) #include "mac_helper/mac_capturer.h" #elif defined(__linux__) -#if USE_MMAL_ENCODER -#include "hwenc_mmal/mmal_v4l2_capturer.h" -#elif USE_JETSON_ENCODER -#include "hwenc_jetson/jetson_v4l2_capturer.h" -#elif USE_NVCODEC_ENCODER -#include "hwenc_nvcodec/nvcodec_v4l2_capturer.h" -#elif USE_V4L2_ENCODER +#if defined(USE_JETSON_ENCODER) +#include "sora/hwenc_jetson/jetson_v4l2_capturer.h" +#elif defined(USE_NVCODEC_ENCODER) +#include "sora/hwenc_nvcodec/nvcodec_v4l2_capturer.h" +#elif defined(USE_V4L2_ENCODER) #include "hwenc_v4l2/libcamera_capturer.h" #include "hwenc_v4l2/v4l2_capturer.h" #endif -#include "v4l2_video_capturer/v4l2_video_capturer.h" +#include "sora/v4l2/v4l2_video_capturer.h" #else #include "rtc/device_video_capturer.h" #endif #include "serial_data_channel/serial_data_manager.h" -#if USE_SDL2 #include "sdl_renderer/sdl_renderer.h" -#endif #include "ayame/ayame_client.h" #include "metrics/metrics_server.h" @@ -50,8 +46,8 @@ #include #endif -#if defined(__linux__) && USE_NVCODEC_ENCODER -#include "cuda/cuda_context.h" +#if defined(USE_NVCODEC_ENCODER) +#include "sora/cuda_context.h" #endif const size_t kDefaultMaxLogFileSize = 10 * 1024 * 1024; @@ -89,15 +85,9 @@ int main(int argc, char* argv[]) { } rtc::LogMessage::AddLogToStream(log_sink.get(), rtc::LS_INFO); -#if USE_NVCODEC_ENCODER - std::shared_ptr cuda_context; - try { - cuda_context = CudaContext::Create(); - } catch (...) { - } -#endif +#if defined(USE_NVCODEC_ENCODER) + auto cuda_context = sora::CudaContext::Create(); -#if USE_NVCODEC_ENCODER // NvCodec が有効な環境で HW MJPEG デコーダを使う場合、CUDA が有効である必要がある if (args.hw_mjpeg_decoder && cuda_context == nullptr) { std::cerr << "Specified --hw-mjpeg-decoder=true but CUDA is invalid." @@ -106,12 +96,12 @@ int main(int argc, char* argv[]) { } #endif - auto capturer = ([&]() -> rtc::scoped_refptr { + auto capturer = ([&]() -> rtc::scoped_refptr { if (args.no_video_device) { return nullptr; } -#if USE_SCREEN_CAPTURER +#if defined(USE_SCREEN_CAPTURER) if (args.screen_capture) { RTC_LOG(LS_INFO) << "Screen capturer source list: " << ScreenVideoCapturer::GetSourceListString(); @@ -131,7 +121,7 @@ int main(int argc, char* argv[]) { return MacCapturer::Create(size.width, size.height, args.framerate, args.video_device); #elif defined(__linux__) - V4L2VideoCapturerConfig v4l2_config; + sora::V4L2VideoCapturerConfig v4l2_config; v4l2_config.video_device = args.video_device; v4l2_config.width = size.width; v4l2_config.height = size.height; @@ -139,30 +129,21 @@ int main(int argc, char* argv[]) { v4l2_config.force_i420 = args.force_i420; v4l2_config.use_native = args.hw_mjpeg_decoder; -#if USE_MMAL_ENCODER +#if defined(USE_JETSON_ENCODER) if (v4l2_config.use_native) { - MMALV4L2CapturerConfig mmal_config = v4l2_config; - // サイマルキャストの場合はネイティブフレームを出力しない - mmal_config.native_frame_output = !(use_sora && args.sora_simulcast); - return MMALV4L2Capturer::Create(std::move(mmal_config)); + return sora::JetsonV4L2Capturer::Create(std::move(v4l2_config)); } else { - return V4L2VideoCapturer::Create(std::move(v4l2_config)); + return sora::V4L2VideoCapturer::Create(std::move(v4l2_config)); } -#elif USE_JETSON_ENCODER +#elif defined(USE_NVCODEC_ENCODER) if (v4l2_config.use_native) { - return JetsonV4L2Capturer::Create(std::move(v4l2_config)); - } else { - return V4L2VideoCapturer::Create(std::move(v4l2_config)); - } -#elif USE_NVCODEC_ENCODER - if (v4l2_config.use_native) { - NvCodecV4L2CapturerConfig nvcodec_config = v4l2_config; + sora::NvCodecV4L2CapturerConfig nvcodec_config = v4l2_config; nvcodec_config.cuda_context = cuda_context; - return NvCodecV4L2Capturer::Create(std::move(nvcodec_config)); + return sora::NvCodecV4L2Capturer::Create(std::move(nvcodec_config)); } else { - return V4L2VideoCapturer::Create(std::move(v4l2_config)); + return sora::V4L2VideoCapturer::Create(std::move(v4l2_config)); } -#elif USE_V4L2_ENCODER +#elif defined(USE_V4L2_ENCODER) if (args.use_libcamera) { LibcameraCapturerConfig libcamera_config = v4l2_config; // use_libcamera_native == true でも、サイマルキャストの場合はネイティブフレームを出力しない @@ -172,10 +153,10 @@ int main(int argc, char* argv[]) { } else if (v4l2_config.use_native && !(use_sora && args.sora_simulcast)) { return V4L2Capturer::Create(std::move(v4l2_config)); } else { - return V4L2VideoCapturer::Create(std::move(v4l2_config)); + return sora::V4L2VideoCapturer::Create(std::move(v4l2_config)); } #else - return V4L2VideoCapturer::Create(std::move(v4l2_config)); + return sora::V4L2VideoCapturer::Create(std::move(v4l2_config)); #endif #else return DeviceVideoCapturer::Create(size.width, size.height, args.framerate, @@ -211,10 +192,18 @@ int main(int argc, char* argv[]) { rtcm_config.av1_decoder = args.av1_decoder; rtcm_config.h264_encoder = args.h264_encoder; rtcm_config.h264_decoder = args.h264_decoder; + rtcm_config.h265_encoder = args.h265_encoder; + rtcm_config.h265_decoder = args.h265_decoder; + + rtcm_config.openh264 = args.openh264; + if (!rtcm_config.openh264.empty()) { + // openh264 が指定されている場合は自動的に H264 ソフトウェアエンコーダを利用する + rtcm_config.h264_encoder = VideoCodecInfo::Type::Software; + } rtcm_config.priority = args.priority; -#if USE_NVCODEC_ENCODER +#if defined(USE_NVCODEC_ENCODER) rtcm_config.cuda_context = cuda_context; #endif @@ -222,7 +211,6 @@ int main(int argc, char* argv[]) { rtcm_config.proxy_username = args.proxy_username; rtcm_config.proxy_password = args.proxy_password; -#if USE_SDL2 std::unique_ptr sdl_renderer = nullptr; if (args.use_sdl) { sdl_renderer.reset(new SDLRenderer(args.window_width, args.window_height, @@ -231,10 +219,6 @@ int main(int argc, char* argv[]) { std::unique_ptr rtc_manager(new RTCManager( std::move(rtcm_config), std::move(capturer), sdl_renderer.get())); -#else - std::unique_ptr rtc_manager( - new RTCManager(std::move(rtcm_config), std::move(capturer), nullptr)); -#endif { boost::asio::io_context ioc{1}; @@ -357,7 +341,6 @@ int main(int argc, char* argv[]) { ->Run(); } -#if USE_SDL2 if (sdl_renderer) { sdl_renderer->SetDispatchFunction([&ioc](std::function f) { if (ioc.stopped()) @@ -371,16 +354,10 @@ int main(int argc, char* argv[]) { } else { ioc.run(); } -#else - ioc.run(); -#endif } //この順番は綺麗に落ちるけど、あまり安全ではない -#if USE_SDL2 sdl_renderer = nullptr; -#endif - rtc_manager = nullptr; return 0; } diff --git a/src/momo_args.h b/src/momo_args.h index f2915c2d..21c5f480 100644 --- a/src/momo_args.h +++ b/src/momo_args.h @@ -9,7 +9,8 @@ // WebRTC #include -#include +#include +#include #include "video_codec_info.h" @@ -19,12 +20,12 @@ struct MomoArgs { bool no_audio_device = false; bool force_i420 = false; // Jetson の場合だけデフォルト true -#if USE_JETSON_ENCODER +#if defined(USE_JETSON_ENCODER) bool hw_mjpeg_decoder = true; #else bool hw_mjpeg_decoder = false; #endif - // Raspberry Pi 4 の場合だけ使える + // Raspberry Pi OS 64bit の場合だけ使える bool use_libcamera = false; // use_libcamera == true の場合だけ使える。 // sora_video_codec_type == "H264" かつ sora_simulcast == false の場合だけしか機能しない。 @@ -91,6 +92,10 @@ struct MomoArgs { VideoCodecInfo::Type av1_decoder = VideoCodecInfo::Type::Default; VideoCodecInfo::Type h264_encoder = VideoCodecInfo::Type::Default; VideoCodecInfo::Type h264_decoder = VideoCodecInfo::Type::Default; + VideoCodecInfo::Type h265_encoder = VideoCodecInfo::Type::Default; + VideoCodecInfo::Type h265_decoder = VideoCodecInfo::Type::Default; + + std::string openh264; std::string proxy_url; std::string proxy_username; diff --git a/src/momo_version.cpp b/src/momo_version.cpp index 2a803470..ab531779 100644 --- a/src/momo_version.cpp +++ b/src/momo_version.cpp @@ -176,7 +176,7 @@ std::string MomoVersion::GetEnvironmentName() { break; } -#if USE_JETSON_ENCODER +#if defined(USE_JETSON_ENCODER) // Jetson 系の場合、更に詳細な情報を取得する // nvidia-l4t-core のバージョンを拾う diff --git a/src/p2p/p2p_websocket_session.cpp b/src/p2p/p2p_websocket_session.cpp index bdc88166..d6db43e6 100644 --- a/src/p2p/p2p_websocket_session.cpp +++ b/src/p2p/p2p_websocket_session.cpp @@ -89,7 +89,7 @@ void P2PWebsocketSession::OnRead(boost::system::error_code ec, RTC_LOG(LS_INFO) << __FUNCTION__ << ": recv_string=" << recv_string; - boost::json::error_code jec; + boost::system::error_code jec; boost::json::value recv_message = boost::json::parse(recv_string, jec); if (jec) { return; diff --git a/src/rtc/device_video_capturer.cpp b/src/rtc/device_video_capturer.cpp index 05bd1290..d1e12865 100644 --- a/src/rtc/device_video_capturer.cpp +++ b/src/rtc/device_video_capturer.cpp @@ -20,7 +20,7 @@ #include DeviceVideoCapturer::DeviceVideoCapturer() - : ScalableVideoTrackSource(ScalableVideoTrackSourceConfig()), + : sora::ScalableVideoTrackSource(sora::ScalableVideoTrackSourceConfig()), vcm_(nullptr) {} DeviceVideoCapturer::~DeviceVideoCapturer() { diff --git a/src/rtc/device_video_capturer.h b/src/rtc/device_video_capturer.h index 6b4b7ecb..f57a982f 100644 --- a/src/rtc/device_video_capturer.h +++ b/src/rtc/device_video_capturer.h @@ -18,9 +18,9 @@ #include #include -#include "rtc/scalable_track_source.h" +#include "sora/scalable_track_source.h" -class DeviceVideoCapturer : public ScalableVideoTrackSource, +class DeviceVideoCapturer : public sora::ScalableVideoTrackSource, public rtc::VideoSinkInterface { public: static rtc::scoped_refptr Create(size_t width, diff --git a/src/rtc/momo_video_decoder_factory.cpp b/src/rtc/momo_video_decoder_factory.cpp index 806757d9..13875f1f 100644 --- a/src/rtc/momo_video_decoder_factory.cpp +++ b/src/rtc/momo_video_decoder_factory.cpp @@ -20,19 +20,19 @@ #include "mac_helper/objc_codec_factory_helper.h" #endif -#if USE_JETSON_ENCODER -#include "hwenc_jetson/jetson_video_decoder.h" +#if defined(USE_JETSON_ENCODER) +#include "sora/hwenc_jetson/jetson_video_decoder.h" #endif -#if USE_MMAL_ENCODER -#include "hwenc_mmal/mmal_h264_decoder.h" +#if defined(USE_NVCODEC_ENCODER) +#include "sora/hwenc_nvcodec/nvcodec_video_decoder.h" #endif -#if USE_MSDK_ENCODER -#include "hwenc_msdk/msdk_video_decoder.h" +#if defined(USE_VPL_ENCODER) +#include "sora/hwenc_vpl/vpl_video_decoder.h" #endif -#if USE_V4L2_ENCODER +#if defined(USE_V4L2_ENCODER) #include "hwenc_v4l2/v4l2_h264_decoder.h" #endif @@ -63,190 +63,297 @@ std::vector MomoVideoDecoderFactory::GetSupportedFormats() const { std::vector supported_codecs; - // VP8 - if (config_.vp8_decoder == VideoCodecInfo::Type::Software || - config_.vp8_decoder == VideoCodecInfo::Type::Jetson || - config_.vp8_decoder == VideoCodecInfo::Type::NVIDIA || - config_.vp8_decoder == VideoCodecInfo::Type::Intel) { + auto add_vp8 = [&supported_codecs]() { supported_codecs.push_back(webrtc::SdpVideoFormat(cricket::kVp8CodecName)); - } - - // VP9 - if (config_.vp9_decoder == VideoCodecInfo::Type::Software || - config_.vp9_decoder == VideoCodecInfo::Type::Jetson || - config_.vp9_decoder == VideoCodecInfo::Type::NVIDIA || - config_.vp9_decoder == VideoCodecInfo::Type::Intel) { + }; + auto add_vp9 = [&supported_codecs]() { for (const webrtc::SdpVideoFormat& format : webrtc::SupportedVP9Codecs(true)) { supported_codecs.push_back(format); } - } - -#if !defined(__arm__) || defined(__aarch64__) || defined(__ARM_NEON__) - // AV1 - if (config_.av1_decoder == VideoCodecInfo::Type::Software || - config_.av1_decoder == VideoCodecInfo::Type::Jetson || - config_.av1_decoder == VideoCodecInfo::Type::Intel) { + }; + auto add_av1 = [&supported_codecs]() { supported_codecs.push_back(webrtc::SdpVideoFormat( cricket::kAv1CodecName, webrtc::SdpVideoFormat::Parameters(), webrtc::LibaomAv1EncoderSupportedScalabilityModes())); + }; + auto add_h264 = [&supported_codecs]() { + std::vector h264_codecs = { + CreateH264Format(webrtc::H264Profile::kProfileBaseline, + webrtc::H264Level::kLevel3_1, "1"), + CreateH264Format(webrtc::H264Profile::kProfileBaseline, + webrtc::H264Level::kLevel3_1, "0"), + CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline, + webrtc::H264Level::kLevel3_1, "1"), + CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline, + webrtc::H264Level::kLevel3_1, "0")}; + + for (const webrtc::SdpVideoFormat& format : h264_codecs) { + supported_codecs.push_back(format); + } + }; + auto add_h265 = [&supported_codecs]() { + supported_codecs.push_back(webrtc::SdpVideoFormat(cricket::kH265CodecName)); + }; + +#if defined(USE_NVCODEC_ENCODER) + if (config_.vp8_decoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoDecoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::VP8)) { + add_vp8(); + } + if (config_.vp9_decoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoDecoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::VP9)) { + add_vp9(); + } + if (config_.av1_decoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoDecoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::AV1)) { + add_av1(); + } + if (config_.h264_decoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoDecoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::H264)) { + add_h264(); + } + if (config_.h265_decoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoDecoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::H265)) { + add_h265(); + } +#endif + +#if defined(USE_VPL_ENCODER) + auto session = sora::VplSession::Create(); + if (config_.vp8_decoder == VideoCodecInfo::Type::Intel && + sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecVP8)) { + add_vp8(); + } + if (config_.vp9_decoder == VideoCodecInfo::Type::Intel && + sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecVP9)) { + add_vp9(); + } + if (config_.av1_decoder == VideoCodecInfo::Type::Intel && + sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecAV1)) { + add_av1(); + } + if (config_.h264_decoder == VideoCodecInfo::Type::Intel && + sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecH264)) { + add_h264(); + } + if (config_.h265_decoder == VideoCodecInfo::Type::Intel && + sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecH265)) { + add_h265(); } #endif - // H264 - std::vector h264_codecs = { - CreateH264Format(webrtc::H264Profile::kProfileBaseline, - webrtc::H264Level::kLevel3_1, "1"), - CreateH264Format(webrtc::H264Profile::kProfileBaseline, - webrtc::H264Level::kLevel3_1, "0"), - CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline, - webrtc::H264Level::kLevel3_1, "1"), - CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline, - webrtc::H264Level::kLevel3_1, "0")}; +#if defined(USE_V4L2_ENCODER) + if (config_.h264_decoder == VideoCodecInfo::Type::V4L2) { + add_h264(); + } +#endif +#if defined(USE_JETSON_ENCODER) + if (config_.vp8_decoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecVP8)) { + add_vp8(); + } + if (config_.vp9_decoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecVP9)) { + add_vp9(); + } + if (config_.av1_decoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecAV1)) { + add_av1(); + } + if (config_.h264_decoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecH264)) { + add_h264(); + } + if (config_.h265_decoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecH265)) { + add_h265(); + } +#endif + +#if defined(__APPLE__) + // VideoToolbox の場合は video_decoder_factory_ から拾ってくる + auto formats = video_decoder_factory_->GetSupportedFormats(); + if (config_.vp8_decoder == VideoCodecInfo::Type::VideoToolbox) { + for (auto format : formats) { + if (absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName)) { + supported_codecs.push_back(format); + } + } + } + if (config_.vp9_decoder == VideoCodecInfo::Type::VideoToolbox) { + for (auto format : formats) { + if (absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName)) { + supported_codecs.push_back(format); + } + } + } + if (config_.av1_decoder == VideoCodecInfo::Type::VideoToolbox) { + for (auto format : formats) { + if (absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName)) { + supported_codecs.push_back(format); + } + } + } if (config_.h264_decoder == VideoCodecInfo::Type::VideoToolbox) { - // VideoToolbox の場合は video_decoder_factory_ から H264 を拾ってくる - for (auto format : video_decoder_factory_->GetSupportedFormats()) { + for (auto format : formats) { if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName)) { supported_codecs.push_back(format); } } - } else if (config_.h264_decoder != VideoCodecInfo::Type::NotSupported) { - // その他のデコーダの場合は手動で追加 - for (const webrtc::SdpVideoFormat& h264_format : h264_codecs) { - supported_codecs.push_back(h264_format); + } + if (config_.h265_decoder == VideoCodecInfo::Type::VideoToolbox) { + for (auto format : formats) { + if (absl::EqualsIgnoreCase(format.name, cricket::kH265CodecName)) { + supported_codecs.push_back(format); + } } } +#endif + + if (config_.vp8_decoder == VideoCodecInfo::Type::Software) { + add_vp8(); + } + if (config_.vp9_decoder == VideoCodecInfo::Type::Software) { + add_vp9(); + } + if (config_.av1_decoder == VideoCodecInfo::Type::Software) { + add_av1(); + } + if (config_.h264_decoder == VideoCodecInfo::Type::Software) { + add_h264(); + } + if (config_.h265_decoder == VideoCodecInfo::Type::Software) { + add_h265(); + } return supported_codecs; } -std::unique_ptr -MomoVideoDecoderFactory::CreateVideoDecoder( +std::unique_ptr MomoVideoDecoderFactory::Create( + const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) { if (!IsFormatSupported(GetSupportedFormats(), format)) { RTC_LOG(LS_ERROR) << "Trying to create decoder for unsupported format"; return nullptr; } - if (absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName)) { -#if USE_NVCODEC_ENCODER - if (config_.vp8_decoder == VideoCodecInfo::Type::NVIDIA) { - return std::unique_ptr( - absl::make_unique(config_.cuda_context, - CudaVideoCodec::VP8)); - } -#endif -#if USE_MSDK_ENCODER - if (config_.vp8_decoder == VideoCodecInfo::Type::Intel) { - return std::unique_ptr( - absl::make_unique(MsdkSession::Create(), - MFX_CODEC_VP8)); - } -#endif -#if USE_JETSON_ENCODER - if (config_.vp8_decoder == VideoCodecInfo::Type::Jetson && - JetsonVideoDecoder::IsSupportedVP8()) { - return std::unique_ptr( - absl::make_unique(webrtc::kVideoCodecVP8)); - } -#endif + auto is_vp8 = absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName); + auto is_vp9 = absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName); + auto is_av1 = absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName); + auto is_h264 = absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName); + auto is_h265 = absl::EqualsIgnoreCase(format.name, cricket::kH265CodecName); - if (config_.vp8_decoder == VideoCodecInfo::Type::Software) { - return webrtc::VP8Decoder::Create(); - } +#if defined(USE_NVCODEC_ENCODER) + if (is_vp8 && config_.vp8_decoder == VideoCodecInfo::Type::NVIDIA) { + return std::make_unique( + config_.cuda_context, sora::CudaVideoCodec::VP8); + } + if (is_vp9 && config_.vp9_decoder == VideoCodecInfo::Type::NVIDIA) { + return std::make_unique( + config_.cuda_context, sora::CudaVideoCodec::VP9); + } + if (is_av1 && config_.av1_decoder == VideoCodecInfo::Type::NVIDIA) { + return std::make_unique( + config_.cuda_context, sora::CudaVideoCodec::AV1); + } + if (is_h264 && config_.h264_decoder == VideoCodecInfo::Type::NVIDIA) { + return std::make_unique( + config_.cuda_context, sora::CudaVideoCodec::H264); + } + if (is_h265 && config_.h265_decoder == VideoCodecInfo::Type::NVIDIA) { + return std::make_unique( + config_.cuda_context, sora::CudaVideoCodec::H265); } - - if (absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName)) { -#if USE_NVCODEC_ENCODER - if (config_.vp9_decoder == VideoCodecInfo::Type::NVIDIA) { - return std::unique_ptr( - absl::make_unique(config_.cuda_context, - CudaVideoCodec::VP9)); - } -#endif -#if USE_MSDK_ENCODER - if (config_.vp9_decoder == VideoCodecInfo::Type::Intel) { - return std::unique_ptr( - absl::make_unique(MsdkSession::Create(), - MFX_CODEC_VP9)); - } -#endif -#if USE_JETSON_ENCODER - if (config_.vp9_decoder == VideoCodecInfo::Type::Jetson) { - return std::unique_ptr( - absl::make_unique(webrtc::kVideoCodecVP9)); - } #endif - if (config_.vp9_decoder == VideoCodecInfo::Type::Software) { - return webrtc::VP9Decoder::Create(); - } +#if defined(USE_VPL_ENCODER) + auto session = sora::VplSession::Create(); + if (is_vp8 && config_.vp8_decoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoDecoder::Create(session, webrtc::kVideoCodecVP8); } - - if (absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName)) { -#if USE_MSDK_ENCODER - if (config_.av1_decoder == VideoCodecInfo::Type::Intel) { - return std::unique_ptr( - absl::make_unique(MsdkSession::Create(), - MFX_CODEC_AV1)); - } -#endif -#if USE_JETSON_ENCODER - if (config_.av1_decoder == VideoCodecInfo::Type::Jetson && - JetsonVideoDecoder::IsSupportedAV1()) { - return std::unique_ptr( - absl::make_unique(webrtc::kVideoCodecAV1)); - } -#endif -#if !defined(__arm__) || defined(__aarch64__) || defined(__ARM_NEON__) - if (config_.av1_decoder == VideoCodecInfo::Type::Software) { - return webrtc::CreateDav1dDecoder(); - } -#endif + if (is_vp9 && config_.vp9_decoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoDecoder::Create(session, webrtc::kVideoCodecVP9); + } + if (is_av1 && config_.av1_decoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoDecoder::Create(session, webrtc::kVideoCodecAV1); + } + if (is_h264 && config_.h264_decoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoDecoder::Create(session, webrtc::kVideoCodecH264); + } + if (is_h265 && config_.h265_decoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoDecoder::Create(session, webrtc::kVideoCodecH265); } - - if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName)) { -#if defined(__APPLE__) - if (config_.h264_decoder == VideoCodecInfo::Type::VideoToolbox) { - return video_decoder_factory_->CreateVideoDecoder(format); - } #endif -#if USE_NVCODEC_ENCODER - if (config_.h264_decoder == VideoCodecInfo::Type::NVIDIA) { - return std::unique_ptr( - absl::make_unique(config_.cuda_context, - CudaVideoCodec::H264)); - } -#endif -#if USE_MSDK_ENCODER - if (config_.h264_decoder == VideoCodecInfo::Type::Intel) { - return std::unique_ptr( - absl::make_unique(MsdkSession::Create(), - MFX_CODEC_AVC)); - } -#endif -#if USE_JETSON_ENCODER - if (config_.h264_decoder == VideoCodecInfo::Type::Jetson) { - return std::unique_ptr( - absl::make_unique(webrtc::kVideoCodecH264)); - } +#if defined(USE_V4L2_ENCODER) + if (is_h264 && config_.h264_decoder == VideoCodecInfo::Type::V4L2) { + return std::unique_ptr( + std::make_unique(webrtc::kVideoCodecH264)); + } #endif -#if USE_MMAL_ENCODER - if (config_.h264_decoder == VideoCodecInfo::Type::MMAL) { - return std::unique_ptr( - absl::make_unique()); - } +#if defined(USE_JETSON_ENCODER) + if (is_vp8 && config_.vp8_decoder == VideoCodecInfo::Type::Jetson) { + return std::unique_ptr( + std::make_unique(webrtc::kVideoCodecVP8)); + } + if (is_vp9 && config_.vp9_decoder == VideoCodecInfo::Type::Jetson) { + return std::unique_ptr( + std::make_unique(webrtc::kVideoCodecVP9)); + } + if (is_av1 && config_.av1_decoder == VideoCodecInfo::Type::Jetson) { + return std::unique_ptr( + std::make_unique(webrtc::kVideoCodecAV1)); + } + if (is_h264 && config_.h264_decoder == VideoCodecInfo::Type::Jetson) { + return std::unique_ptr( + std::make_unique(webrtc::kVideoCodecH264)); + } + if (is_h265 && config_.h265_decoder == VideoCodecInfo::Type::Jetson) { + return std::unique_ptr( + std::make_unique(webrtc::kVideoCodecH265)); + } #endif -#if USE_V4L2_ENCODER - if (config_.h264_decoder == VideoCodecInfo::Type::V4L2) { - return std::unique_ptr( - absl::make_unique(webrtc::kVideoCodecH264)); - } +#if defined(__APPLE__) + if (is_vp8 && config_.vp8_decoder == VideoCodecInfo::Type::VideoToolbox) { + return video_decoder_factory_->Create(env, format); + } + if (is_vp9 && config_.vp9_decoder == VideoCodecInfo::Type::VideoToolbox) { + return video_decoder_factory_->Create(env, format); + } + if (is_av1 && config_.av1_decoder == VideoCodecInfo::Type::VideoToolbox) { + return video_decoder_factory_->Create(env, format); + } + if (is_h264 && config_.h264_decoder == VideoCodecInfo::Type::VideoToolbox) { + return video_decoder_factory_->Create(env, format); + } + if (is_h265 && config_.h265_decoder == VideoCodecInfo::Type::VideoToolbox) { + return video_decoder_factory_->Create(env, format); + } #endif + + if (is_vp8 && config_.vp8_decoder == VideoCodecInfo::Type::Software) { + return webrtc::CreateVp8Decoder(env); + } + if (is_vp9 && config_.vp9_decoder == VideoCodecInfo::Type::Software) { + return webrtc::VP9Decoder::Create(); + } + if (is_av1 && config_.av1_decoder == VideoCodecInfo::Type::Software) { + return webrtc::CreateDav1dDecoder(); + } + if (is_h264 && config_.h264_decoder == VideoCodecInfo::Type::Software) { + return nullptr; + } + if (is_h265 && config_.h265_decoder == VideoCodecInfo::Type::Software) { + return nullptr; } RTC_DCHECK_NOTREACHED(); diff --git a/src/rtc/momo_video_decoder_factory.h b/src/rtc/momo_video_decoder_factory.h index a6534250..35cf7469 100644 --- a/src/rtc/momo_video_decoder_factory.h +++ b/src/rtc/momo_video_decoder_factory.h @@ -5,15 +5,16 @@ #include // WebRTC +#include #include #include "video_codec_info.h" -#if USE_NVCODEC_ENCODER -#include "cuda/cuda_context.h" +#if defined(USE_NVCODEC_ENCODER) +#include "sora/cuda_context.h" #endif -#if USE_MSDK_ENCODER -#include "hwenc_msdk/msdk_session.h" +#if defined(USE_VPL_ENCODER) +#include "sora/hwenc_vpl/vpl_session.h" #endif struct MomoVideoDecoderFactoryConfig { @@ -21,8 +22,9 @@ struct MomoVideoDecoderFactoryConfig { VideoCodecInfo::Type vp9_decoder; VideoCodecInfo::Type av1_decoder; VideoCodecInfo::Type h264_decoder; -#if USE_NVCODEC_ENCODER - std::shared_ptr cuda_context; + VideoCodecInfo::Type h265_decoder; +#if defined(USE_NVCODEC_ENCODER) + std::shared_ptr cuda_context; #endif }; @@ -36,7 +38,8 @@ class MomoVideoDecoderFactory : public webrtc::VideoDecoderFactory { std::vector GetSupportedFormats() const override; - std::unique_ptr CreateVideoDecoder( + std::unique_ptr Create( + const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) override; }; diff --git a/src/rtc/momo_video_encoder_factory.cpp b/src/rtc/momo_video_encoder_factory.cpp index f3db1e57..16d19fd4 100644 --- a/src/rtc/momo_video_encoder_factory.cpp +++ b/src/rtc/momo_video_encoder_factory.cpp @@ -5,6 +5,7 @@ // WebRTC #include #include +#include #include #include #include @@ -25,22 +26,21 @@ #include "mac_helper/objc_codec_factory_helper.h" #endif -#if USE_MMAL_ENCODER -#include "hwenc_mmal/mmal_h264_encoder.h" +#if defined(USE_JETSON_ENCODER) +#include "sora/hwenc_jetson/jetson_video_encoder.h" #endif -#if USE_JETSON_ENCODER -#include "hwenc_jetson/jetson_video_encoder.h" +#if defined(USE_NVCODEC_ENCODER) +#include "sora/hwenc_nvcodec/nvcodec_video_encoder.h" #endif -#if USE_NVCODEC_ENCODER -#include "hwenc_nvcodec/nvcodec_h264_encoder.h" +#if defined(USE_VPL_ENCODER) +#include "sora/hwenc_vpl/vpl_video_encoder.h" #endif -#if USE_MSDK_ENCODER -#include "hwenc_msdk/msdk_video_encoder.h" -#endif -#if USE_V4L2_ENCODER +#if defined(USE_V4L2_ENCODER) #include "hwenc_v4l2/v4l2_h264_encoder.h" #endif +#include "sora/open_h264_video_encoder.h" + #include "rtc/aligned_encoder_adapter.h" MomoVideoEncoderFactory::MomoVideoEncoderFactory( @@ -55,115 +55,218 @@ MomoVideoEncoderFactory::MomoVideoEncoderFactory( internal_encoder_factory_.reset(new MomoVideoEncoderFactory(config2)); } } + std::vector MomoVideoEncoderFactory::GetSupportedFormats() const { std::vector supported_codecs; - // VP8 - if (config_.vp8_encoder == VideoCodecInfo::Type::Software || - config_.vp8_encoder == VideoCodecInfo::Type::Jetson || - config_.vp8_encoder == VideoCodecInfo::Type::Intel) { + auto add_vp8 = [&supported_codecs]() { supported_codecs.push_back(webrtc::SdpVideoFormat(cricket::kVp8CodecName)); - } - - // VP9 - if (config_.vp9_encoder == VideoCodecInfo::Type::Software) { + }; + auto add_vp9 = [&supported_codecs]() { for (const webrtc::SdpVideoFormat& format : webrtc::SupportedVP9Codecs(true)) { supported_codecs.push_back(format); } - } else if (config_.vp9_encoder == VideoCodecInfo::Type::Jetson || - config_.vp9_encoder == VideoCodecInfo::Type::Intel) { - supported_codecs.push_back(webrtc::SdpVideoFormat( - cricket::kVp9CodecName, - {{webrtc::kVP9FmtpProfileId, - webrtc::VP9ProfileToString(webrtc::VP9Profile::kProfile0)}})); - } - -#if !defined(__arm__) || defined(__aarch64__) || defined(__ARM_NEON__) - // AV1 - if (config_.av1_encoder == VideoCodecInfo::Type::Software || - config_.av1_encoder == VideoCodecInfo::Type::Jetson || - config_.av1_encoder == VideoCodecInfo::Type::Intel) { + }; + auto add_av1 = [&supported_codecs]() { supported_codecs.push_back(webrtc::SdpVideoFormat( cricket::kAv1CodecName, webrtc::SdpVideoFormat::Parameters(), webrtc::LibaomAv1EncoderSupportedScalabilityModes())); + }; + auto add_h264 = [&supported_codecs]() { + std::vector h264_codecs = { + CreateH264Format(webrtc::H264Profile::kProfileBaseline, + webrtc::H264Level::kLevel3_1, "1"), + CreateH264Format(webrtc::H264Profile::kProfileBaseline, + webrtc::H264Level::kLevel3_1, "0"), + CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline, + webrtc::H264Level::kLevel3_1, "1"), + CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline, + webrtc::H264Level::kLevel3_1, "0")}; + + for (const webrtc::SdpVideoFormat& format : h264_codecs) { + supported_codecs.push_back(format); + } + }; + auto add_h265 = [&supported_codecs]() { + supported_codecs.push_back(webrtc::SdpVideoFormat(cricket::kH265CodecName)); + }; + +#if defined(USE_NVCODEC_ENCODER) + if (config_.vp8_encoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoEncoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::VP8)) { + add_vp8(); + } + if (config_.vp9_encoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoEncoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::VP9)) { + add_vp9(); + } + if (config_.av1_encoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoEncoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::AV1)) { + add_av1(); + } + if (config_.h264_encoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoEncoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::H264)) { + add_h264(); + } + if (config_.h265_encoder == VideoCodecInfo::Type::NVIDIA && + sora::NvCodecVideoEncoder::IsSupported(config_.cuda_context, + sora::CudaVideoCodec::H265)) { + add_h265(); } #endif - // H264 - std::vector h264_codecs = { - CreateH264Format(webrtc::H264Profile::kProfileBaseline, - webrtc::H264Level::kLevel3_1, "1"), - CreateH264Format(webrtc::H264Profile::kProfileBaseline, - webrtc::H264Level::kLevel3_1, "0"), - CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline, - webrtc::H264Level::kLevel3_1, "1"), - CreateH264Format(webrtc::H264Profile::kProfileConstrainedBaseline, - webrtc::H264Level::kLevel3_1, "0")}; +#if defined(USE_VPL_ENCODER) + auto session = sora::VplSession::Create(); + if (config_.vp8_encoder == VideoCodecInfo::Type::Intel && + sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecVP8)) { + add_vp8(); + } + if (config_.vp9_encoder == VideoCodecInfo::Type::Intel && + sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecVP9)) { + add_vp9(); + } + if (config_.av1_encoder == VideoCodecInfo::Type::Intel && + sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecAV1)) { + add_av1(); + } + if (config_.h264_encoder == VideoCodecInfo::Type::Intel && + sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecH264)) { + add_h264(); + } + if (config_.h265_encoder == VideoCodecInfo::Type::Intel && + sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecH265)) { + add_h265(); + } +#endif - if (config_.h264_encoder == VideoCodecInfo::Type::VideoToolbox) { - // VideoToolbox の場合は video_encoder_factory_ から H264 を拾ってくる - for (auto format : video_encoder_factory_->GetSupportedFormats()) { - if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName)) { +#if defined(USE_V4L2_ENCODER) + if (config_.h264_encoder == VideoCodecInfo::Type::V4L2) { + add_h264(); + } +#endif + +#if defined(USE_JETSON_ENCODER) + if (config_.vp8_encoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecVP8)) { + add_vp8(); + } + if (config_.vp9_encoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecVP9)) { + add_vp9(); + } + if (config_.av1_encoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecAV1)) { + add_av1(); + } + if (config_.h264_encoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecH264)) { + add_h264(); + } + if (config_.h265_encoder == VideoCodecInfo::Type::Jetson && + sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecH265)) { + add_h265(); + } +#endif + +#if defined(__APPLE__) + // VideoToolbox の場合は video_encoder_factory_ から拾ってくる + auto formats = video_encoder_factory_->GetSupportedFormats(); + if (config_.vp8_encoder == VideoCodecInfo::Type::VideoToolbox) { + for (auto format : formats) { + if (absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName)) { supported_codecs.push_back(format); } } - } else if (config_.h264_encoder == VideoCodecInfo::Type::NVIDIA) { -#if USE_NVCODEC_ENCODER - // NVIDIA の場合は対応してる場合のみ追加 - if (NvCodecH264Encoder::IsSupported()) { - for (const webrtc::SdpVideoFormat& format : h264_codecs) { + } + if (config_.vp9_encoder == VideoCodecInfo::Type::VideoToolbox) { + for (auto format : formats) { + if (absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName)) { supported_codecs.push_back(format); } } -#endif - } else if (config_.h264_encoder == VideoCodecInfo::Type::Intel) { -#if USE_MSDK_ENCODER - // Intel Media SDK の場合は対応してる場合のみ追加 - if (MsdkVideoEncoder::IsSupported(MsdkSession::Create(), MFX_CODEC_AVC)) { - for (const webrtc::SdpVideoFormat& format : h264_codecs) { + } + if (config_.av1_encoder == VideoCodecInfo::Type::VideoToolbox) { + for (auto format : formats) { + if (absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName)) { supported_codecs.push_back(format); } } -#endif - } else if (config_.h264_encoder == VideoCodecInfo::Type::V4L2) { -#if USE_V4L2_ENCODER - for (const webrtc::SdpVideoFormat& format : h264_codecs) { - supported_codecs.push_back(format); + } + if (config_.h264_encoder == VideoCodecInfo::Type::VideoToolbox) { + for (auto format : formats) { + if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName)) { + supported_codecs.push_back(format); + } } -#endif - } else if ((config_.h264_encoder == VideoCodecInfo::Type::Software) || - config_.h264_encoder != VideoCodecInfo::Type::NotSupported) { - // その他のエンコーダの場合は手動で追加 - for (const webrtc::SdpVideoFormat& format : h264_codecs) { - supported_codecs.push_back(format); + } + if (config_.h265_encoder == VideoCodecInfo::Type::VideoToolbox) { + for (auto format : formats) { + if (absl::EqualsIgnoreCase(format.name, cricket::kH265CodecName)) { + supported_codecs.push_back(format); + } } } +#endif + + if (config_.vp8_encoder == VideoCodecInfo::Type::Software) { + add_vp8(); + } + if (config_.vp9_encoder == VideoCodecInfo::Type::Software) { + add_vp9(); + } + if (config_.av1_encoder == VideoCodecInfo::Type::Software) { + add_av1(); + } + if (config_.h264_encoder == VideoCodecInfo::Type::Software) { + add_h264(); + } + if (config_.h265_encoder == VideoCodecInfo::Type::Software) { + add_h265(); + } return supported_codecs; } -std::unique_ptr -MomoVideoEncoderFactory::CreateVideoEncoder( +std::unique_ptr MomoVideoEncoderFactory::Create( + const webrtc::Environment& env, + const webrtc::SdpVideoFormat& format) { + return WithSimulcast(format, + [this, &env](const webrtc::SdpVideoFormat& format) { + return CreateInternal(env, format); + }); +} + +std::unique_ptr MomoVideoEncoderFactory::CreateInternal( + const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) { + auto is_vp8 = absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName); + auto is_vp9 = absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName); + auto is_av1 = absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName); + auto is_h264 = absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName); + auto is_h265 = absl::EqualsIgnoreCase(format.name, cricket::kH265CodecName); + // hardware_encoder_only == true の場合、Software なコーデックだったら強制終了する if (config_.hardware_encoder_only) { bool use_software = false; - if (absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName) && - config_.vp8_encoder == VideoCodecInfo::Type::Software) { + if (is_vp8 && config_.vp8_encoder == VideoCodecInfo::Type::Software) { + use_software = true; + } + if (is_vp9 && config_.vp9_encoder == VideoCodecInfo::Type::Software) { use_software = true; } - if (absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName) && - config_.vp9_encoder == VideoCodecInfo::Type::Software) { + if (is_av1 && config_.av1_encoder == VideoCodecInfo::Type::Software) { use_software = true; } - if (absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName) && - config_.av1_encoder == VideoCodecInfo::Type::Software) { + if (is_h264 && config_.h264_encoder == VideoCodecInfo::Type::Software) { use_software = true; } - if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName) && - config_.h264_encoder == VideoCodecInfo::Type::Software) { + if (is_h265 && config_.h265_encoder == VideoCodecInfo::Type::Software) { use_software = true; } @@ -181,155 +284,107 @@ MomoVideoEncoderFactory::CreateVideoEncoder( } } - if (absl::EqualsIgnoreCase(format.name, cricket::kVp8CodecName)) { - if (config_.vp8_encoder == VideoCodecInfo::Type::Software) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return webrtc::VP8Encoder::Create(); - }); - } -#if USE_JETSON_ENCODER - if (config_.vp8_encoder == VideoCodecInfo::Type::Jetson && - JetsonVideoEncoder::IsSupportedVP8()) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(cricket::CreateVideoCodec(format))); - }); - } -#endif -#if USE_MSDK_ENCODER - if (config_.vp8_encoder == VideoCodecInfo::Type::Intel) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(MsdkSession::Create(), - MFX_CODEC_VP8)); - }); - } -#endif +#if defined(USE_NVCODEC_ENCODER) + if (is_vp8 && config_.vp8_encoder == VideoCodecInfo::Type::NVIDIA) { + return sora::NvCodecVideoEncoder::Create(config_.cuda_context, + sora::CudaVideoCodec::VP8); } - - if (absl::EqualsIgnoreCase(format.name, cricket::kVp9CodecName)) { - if (config_.vp9_encoder == VideoCodecInfo::Type::Software) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return webrtc::VP9Encoder::Create(cricket::CreateVideoCodec(format)); - }); - } -#if USE_JETSON_ENCODER - if (config_.vp9_encoder == VideoCodecInfo::Type::Jetson && - JetsonVideoEncoder::IsSupportedVP9()) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(cricket::CreateVideoCodec(format))); - }); - } -#endif -#if USE_MSDK_ENCODER - if (config_.vp9_encoder == VideoCodecInfo::Type::Intel) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(MsdkSession::Create(), - MFX_CODEC_VP9)); - }); - } -#endif + if (is_vp9 && config_.vp9_encoder == VideoCodecInfo::Type::NVIDIA) { + return sora::NvCodecVideoEncoder::Create(config_.cuda_context, + sora::CudaVideoCodec::VP9); } - - if (absl::EqualsIgnoreCase(format.name, cricket::kAv1CodecName)) { -#if !defined(__arm__) || defined(__aarch64__) || defined(__ARM_NEON__) - if (config_.av1_encoder == VideoCodecInfo::Type::Software) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return webrtc::CreateLibaomAv1Encoder(); - }); - } -#endif -#if USE_MSDK_ENCODER - if (config_.av1_encoder == VideoCodecInfo::Type::Intel) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(MsdkSession::Create(), - MFX_CODEC_AV1)); - }); - } -#endif -#if USE_JETSON_ENCODER - if (config_.av1_encoder == VideoCodecInfo::Type::Jetson && - JetsonVideoEncoder::IsSupportedAV1()) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(cricket::CreateVideoCodec(format))); - }); - } -#endif + if (is_av1 && config_.av1_encoder == VideoCodecInfo::Type::NVIDIA) { + return sora::NvCodecVideoEncoder::Create(config_.cuda_context, + sora::CudaVideoCodec::AV1); + } + if (is_h264 && config_.h264_encoder == VideoCodecInfo::Type::NVIDIA) { + return sora::NvCodecVideoEncoder::Create(config_.cuda_context, + sora::CudaVideoCodec::H264); + } + if (is_h265 && config_.h265_encoder == VideoCodecInfo::Type::NVIDIA) { + return sora::NvCodecVideoEncoder::Create(config_.cuda_context, + sora::CudaVideoCodec::H265); } - - if (absl::EqualsIgnoreCase(format.name, cricket::kH264CodecName)) { -#if defined(__APPLE__) - if (config_.h264_encoder == VideoCodecInfo::Type::VideoToolbox) { - return WithSimulcast( - format, [this](const webrtc::SdpVideoFormat& format) { - return video_encoder_factory_->CreateVideoEncoder(format); - }); - } #endif -#if USE_MMAL_ENCODER - if (config_.h264_encoder == VideoCodecInfo::Type::MMAL) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(cricket::CreateVideoCodec(format))); - }); - } +#if defined(USE_VPL_ENCODER) + auto session = sora::VplSession::Create(); + if (is_vp8 && config_.vp8_encoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoEncoder::Create(session, webrtc::kVideoCodecVP8); + } + if (is_vp9 && config_.vp9_encoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoEncoder::Create(session, webrtc::kVideoCodecVP9); + } + if (is_av1 && config_.av1_encoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoEncoder::Create(session, webrtc::kVideoCodecAV1); + } + if (is_h264 && config_.h264_encoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoEncoder::Create(session, webrtc::kVideoCodecH264); + } + if (is_h265 && config_.h265_encoder == VideoCodecInfo::Type::Intel) { + return sora::VplVideoEncoder::Create(session, webrtc::kVideoCodecH265); + } #endif -#if USE_JETSON_ENCODER - if (config_.h264_encoder == VideoCodecInfo::Type::Jetson) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(cricket::CreateVideoCodec(format))); - }); - } +#if defined(USE_V4L2_ENCODER) + auto codec = cricket::CreateVideoCodec(format); + if (is_h264 && config_.h264_encoder == VideoCodecInfo::Type::V4L2) { + return std::make_unique(codec); + } #endif -#if USE_NVCODEC_ENCODER - if (config_.h264_encoder == VideoCodecInfo::Type::NVIDIA && - NvCodecH264Encoder::IsSupported()) { - return WithSimulcast( -#if defined(__linux__) - format, - [cuda_context = - config_.cuda_context](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique( - cricket::CreateVideoCodec(format), cuda_context)); - } -#else - format, - [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique( - cricket::CreateVideoCodec(format))); - } -#endif - ); - } -#endif -#if USE_MSDK_ENCODER - if (config_.h264_encoder == VideoCodecInfo::Type::Intel) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(MsdkSession::Create(), - MFX_CODEC_AVC)); - }); - } +#if defined(USE_JETSON_ENCODER) + auto codec = cricket::CreateVideoCodec(format); + if (is_vp8 && config_.vp8_encoder == VideoCodecInfo::Type::Jetson) { + return std::make_unique(codec); + } + if (is_vp9 && config_.vp9_encoder == VideoCodecInfo::Type::Jetson) { + return std::make_unique(codec); + } + if (is_av1 && config_.av1_encoder == VideoCodecInfo::Type::Jetson) { + return std::make_unique(codec); + } + if (is_h264 && config_.h264_encoder == VideoCodecInfo::Type::Jetson) { + return std::make_unique(codec); + } + if (is_h265 && config_.h265_encoder == VideoCodecInfo::Type::Jetson) { + return std::make_unique(codec); + } #endif -#if USE_V4L2_ENCODER - if (config_.h264_encoder == VideoCodecInfo::Type::V4L2) { - return WithSimulcast(format, [](const webrtc::SdpVideoFormat& format) { - return std::unique_ptr( - absl::make_unique(cricket::CreateVideoCodec(format))); - }); - } + +#if defined(__APPLE__) + if (is_vp8 && config_.vp8_encoder == VideoCodecInfo::Type::VideoToolbox) { + return video_encoder_factory_->Create(env, format); + } + if (is_vp9 && config_.vp9_encoder == VideoCodecInfo::Type::VideoToolbox) { + return video_encoder_factory_->Create(env, format); + } + if (is_av1 && config_.av1_encoder == VideoCodecInfo::Type::VideoToolbox) { + return video_encoder_factory_->Create(env, format); + } + if (is_h264 && config_.h264_encoder == VideoCodecInfo::Type::VideoToolbox) { + return video_encoder_factory_->Create(env, format); + } + if (is_h265 && config_.h265_encoder == VideoCodecInfo::Type::VideoToolbox) { + return video_encoder_factory_->Create(env, format); + } #endif + + if (is_vp8 && config_.vp8_encoder == VideoCodecInfo::Type::Software) { + return webrtc::CreateVp8Encoder(env); + } + if (is_vp9 && config_.vp9_encoder == VideoCodecInfo::Type::Software) { + return webrtc::CreateVp9Encoder(env); + } + if (is_av1 && config_.av1_encoder == VideoCodecInfo::Type::Software) { + return webrtc::CreateLibaomAv1Encoder(env); + } + if (is_h264 && config_.h264_encoder == VideoCodecInfo::Type::Software) { + return sora::CreateOpenH264VideoEncoder(format, config_.openh264); } + // if (is_h265 && config_.h265_encoder == VideoCodecInfo::Type::Software) { + // return nullptr; + // } RTC_LOG(LS_ERROR) << "Trying to created encoder of unsupported format " << format.name; @@ -343,7 +398,8 @@ std::unique_ptr MomoVideoEncoderFactory::WithSimulcast( std::shared_ptr encoder; if (internal_encoder_factory_) { encoder = std::make_shared( - internal_encoder_factory_.get(), format); + webrtc::CreateEnvironment(), internal_encoder_factory_.get(), nullptr, + format); } else { encoder.reset(create(format).release()); } diff --git a/src/rtc/momo_video_encoder_factory.h b/src/rtc/momo_video_encoder_factory.h index 3be280b1..0de7be27 100644 --- a/src/rtc/momo_video_encoder_factory.h +++ b/src/rtc/momo_video_encoder_factory.h @@ -5,18 +5,19 @@ #include // WebRTC +#include #include #include #include #include "video_codec_info.h" -#if defined(__linux__) && USE_NVCODEC_ENCODER -#include "cuda/cuda_context.h" +#if defined(USE_NVCODEC_ENCODER) +#include "sora/cuda_context.h" #endif -#if USE_MSDK_ENCODER -#include "hwenc_msdk/msdk_session.h" +#if defined(USE_VPL_ENCODER) +#include "sora/hwenc_vpl/vpl_session.h" #endif struct MomoVideoEncoderFactoryConfig { @@ -24,11 +25,13 @@ struct MomoVideoEncoderFactoryConfig { VideoCodecInfo::Type vp9_encoder; VideoCodecInfo::Type av1_encoder; VideoCodecInfo::Type h264_encoder; + VideoCodecInfo::Type h265_encoder; bool simulcast; bool hardware_encoder_only; -#if defined(__linux__) && USE_NVCODEC_ENCODER - std::shared_ptr cuda_context; +#if defined(USE_NVCODEC_ENCODER) + std::shared_ptr cuda_context; #endif + std::string openh264; }; class MomoVideoEncoderFactory : public webrtc::VideoEncoderFactory { @@ -42,10 +45,14 @@ class MomoVideoEncoderFactory : public webrtc::VideoEncoderFactory { std::vector GetSupportedFormats() const override; - std::unique_ptr CreateVideoEncoder( + std::unique_ptr Create( + const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) override; private: + std::unique_ptr CreateInternal( + const webrtc::Environment& env, + const webrtc::SdpVideoFormat& format); std::unique_ptr WithSimulcast( const webrtc::SdpVideoFormat& format, std::function( diff --git a/src/rtc/rtc_manager.cpp b/src/rtc/rtc_manager.cpp index a64da7b7..0b03b1b8 100644 --- a/src/rtc/rtc_manager.cpp +++ b/src/rtc/rtc_manager.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -25,13 +26,13 @@ #include "momo_video_encoder_factory.h" #include "peer_connection_observer.h" #include "rtc_ssl_verifier.h" -#include "scalable_track_source.h" +#include "sora/scalable_track_source.h" #include "url_parts.h" #include "util.h" RTCManager::RTCManager( RTCManagerConfig config, - rtc::scoped_refptr video_track_source, + rtc::scoped_refptr video_track_source, VideoTrackReceiver* receiver) : config_(std::move(config)), receiver_(receiver) { rtc::InitializeSSL(); @@ -45,7 +46,7 @@ RTCManager::RTCManager( #if defined(__linux__) -#if USE_LINUX_PULSE_AUDIO +#if defined(USE_LINUX_PULSE_AUDIO) webrtc::AudioDeviceModule::AudioLayer audio_layer = webrtc::AudioDeviceModule::kLinuxPulseAudio; #else @@ -66,30 +67,26 @@ RTCManager::RTCManager( dependencies.worker_thread = worker_thread_.get(); dependencies.signaling_thread = signaling_thread_.get(); dependencies.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory(); - dependencies.call_factory = webrtc::CreateCallFactory(); dependencies.event_log_factory = absl::make_unique( dependencies.task_queue_factory.get()); - // media_dependencies - cricket::MediaEngineDependencies media_dependencies; - media_dependencies.task_queue_factory = dependencies.task_queue_factory.get(); #if defined(_WIN32) - media_dependencies.adm = worker_thread_->BlockingCall( + dependencies.adm = worker_thread_->BlockingCall( [&]() -> rtc::scoped_refptr { return webrtc::CreateWindowsCoreAudioAudioDeviceModule( dependencies.task_queue_factory.get()); }); #else - media_dependencies.adm = worker_thread_->BlockingCall( + dependencies.adm = worker_thread_->BlockingCall( [&]() -> rtc::scoped_refptr { return webrtc::AudioDeviceModule::Create( audio_layer, dependencies.task_queue_factory.get()); }); #endif - media_dependencies.audio_encoder_factory = + dependencies.audio_encoder_factory = webrtc::CreateBuiltinAudioEncoderFactory(); - media_dependencies.audio_decoder_factory = + dependencies.audio_decoder_factory = webrtc::CreateBuiltinAudioDecoderFactory(); { @@ -102,12 +99,14 @@ RTCManager::RTCManager( ec.vp9_encoder = resolve(cf.vp9_encoder, info.vp9_encoders); ec.av1_encoder = resolve(cf.av1_encoder, info.av1_encoders); ec.h264_encoder = resolve(cf.h264_encoder, info.h264_encoders); + ec.h265_encoder = resolve(cf.h265_encoder, info.h265_encoders); ec.simulcast = cf.simulcast; ec.hardware_encoder_only = cf.hardware_encoder_only; -#if defined(__linux__) && USE_NVCODEC_ENCODER +#if defined(USE_NVCODEC_ENCODER) ec.cuda_context = cf.cuda_context; #endif - media_dependencies.video_encoder_factory = + ec.openh264 = cf.openh264; + dependencies.video_encoder_factory = std::unique_ptr( absl::make_unique(ec)); MomoVideoDecoderFactoryConfig dc; @@ -115,20 +114,19 @@ RTCManager::RTCManager( dc.vp9_decoder = resolve(cf.vp9_decoder, info.vp9_decoders); dc.av1_decoder = resolve(cf.av1_decoder, info.av1_decoders); dc.h264_decoder = resolve(cf.h264_decoder, info.h264_decoders); -#if USE_NVCODEC_ENCODER + dc.h265_decoder = resolve(cf.h265_decoder, info.h265_decoders); +#if defined(USE_NVCODEC_ENCODER) dc.cuda_context = cf.cuda_context; #endif - media_dependencies.video_decoder_factory = + dependencies.video_decoder_factory = std::unique_ptr( absl::make_unique(dc)); } - media_dependencies.audio_mixer = nullptr; - media_dependencies.audio_processing = - webrtc::AudioProcessingBuilder().Create(); + dependencies.audio_mixer = nullptr; + dependencies.audio_processing = webrtc::AudioProcessingBuilder().Create(); - dependencies.media_engine = - cricket::CreateMediaEngine(std::move(media_dependencies)); + webrtc::EnableMedia(dependencies); //factory_ = // webrtc::CreateModularPeerConnectionFactory(std::move(dependencies)); @@ -211,7 +209,7 @@ void RTCManager::AddDataManager(std::shared_ptr data_manager) { data_manager_dispatcher_.Add(data_manager); } -class RawCryptString : public rtc::CryptStringImpl { +class RawCryptString : public rtc::revive::CryptStringImpl { public: RawCryptString(const std::string& str) : str_(str) {} size_t GetLength() const override { return str_.size(); } @@ -257,11 +255,11 @@ std::shared_ptr RTCManager::CreateConnection( dependencies.allocator->set_flags(rtc_config.port_allocator_config.flags); if (!config_.proxy_url.empty()) { RTC_LOG(LS_INFO) << "Set Proxy: type=" - << rtc::ProxyToString(rtc::PROXY_HTTPS) + << rtc::revive::ProxyToString(rtc::revive::PROXY_HTTPS) << " url=" << config_.proxy_url << " username=" << config_.proxy_username; - rtc::ProxyInfo pi; - pi.type = rtc::PROXY_HTTPS; + rtc::revive::ProxyInfo pi; + pi.type = rtc::revive::PROXY_HTTPS; URLParts parts; if (!URLParts::Parse(config_.proxy_url, parts)) { RTC_LOG(LS_ERROR) << "Failed to parse: proxy_url=" << config_.proxy_url; @@ -272,7 +270,8 @@ std::shared_ptr RTCManager::CreateConnection( pi.username = config_.proxy_username; } if (!config_.proxy_password.empty()) { - pi.password = rtc::CryptString(RawCryptString(config_.proxy_password)); + pi.password = + rtc::revive::CryptString(RawCryptString(config_.proxy_password)); } dependencies.allocator->set_proxy("WebRTC Native Client Momo", pi); } diff --git a/src/rtc/rtc_manager.h b/src/rtc/rtc_manager.h index 2a75378c..d4cacf7a 100644 --- a/src/rtc/rtc_manager.h +++ b/src/rtc/rtc_manager.h @@ -4,16 +4,17 @@ #include // WebRTC +#include #include #include #include #include -#include "cuda/cuda_context.h" #include "rtc_connection.h" #include "rtc_data_manager_dispatcher.h" #include "rtc_message_sender.h" -#include "scalable_track_source.h" +#include "sora/cuda_context.h" +#include "sora/scalable_track_source.h" #include "video_codec_info.h" #include "video_track_receiver.h" @@ -24,7 +25,8 @@ class CustomPeerConnectionFactory : public webrtc::PeerConnectionFactory { CustomPeerConnectionFactory( webrtc::PeerConnectionFactoryDependencies dependencies) : CustomPeerConnectionFactory( - webrtc::ConnectionContext::Create(&dependencies), + webrtc::ConnectionContext::Create(webrtc::CreateEnvironment(), + &dependencies), &dependencies) {} CustomPeerConnectionFactory( rtc::scoped_refptr context, @@ -69,6 +71,10 @@ struct RTCManagerConfig { VideoCodecInfo::Type av1_decoder = VideoCodecInfo::Type::Default; VideoCodecInfo::Type h264_encoder = VideoCodecInfo::Type::Default; VideoCodecInfo::Type h264_decoder = VideoCodecInfo::Type::Default; + VideoCodecInfo::Type h265_encoder = VideoCodecInfo::Type::Default; + VideoCodecInfo::Type h265_decoder = VideoCodecInfo::Type::Default; + + std::string openh264; std::string priority = "FRAMERATE"; @@ -81,8 +87,8 @@ struct RTCManagerConfig { return webrtc::DegradationPreference::BALANCED; } -#if USE_NVCODEC_ENCODER - std::shared_ptr cuda_context; +#if defined(USE_NVCODEC_ENCODER) + std::shared_ptr cuda_context; #endif std::string proxy_url; @@ -92,9 +98,10 @@ struct RTCManagerConfig { class RTCManager { public: - RTCManager(RTCManagerConfig config, - rtc::scoped_refptr video_track_source, - VideoTrackReceiver* receiver); + RTCManager( + RTCManagerConfig config, + rtc::scoped_refptr video_track_source, + VideoTrackReceiver* receiver); ~RTCManager(); void AddDataManager(std::shared_ptr data_manager); std::shared_ptr CreateConnection( diff --git a/src/rtc/screen_video_capturer.cpp b/src/rtc/screen_video_capturer.cpp index 925f4f99..430ab1d0 100644 --- a/src/rtc/screen_video_capturer.cpp +++ b/src/rtc/screen_video_capturer.cpp @@ -55,7 +55,7 @@ ScreenVideoCapturer::ScreenVideoCapturer( size_t max_width, size_t max_height, size_t target_fps) - : ScalableVideoTrackSource(ScalableVideoTrackSourceConfig()), + : sora::ScalableVideoTrackSource(sora::ScalableVideoTrackSourceConfig()), max_width_(max_width), max_height_(max_height), requested_frame_duration_((int)(1000.0f / target_fps)), diff --git a/src/rtc/screen_video_capturer.h b/src/rtc/screen_video_capturer.h index f6233a6d..8e6dc84a 100644 --- a/src/rtc/screen_video_capturer.h +++ b/src/rtc/screen_video_capturer.h @@ -10,9 +10,9 @@ #include #include -#include "scalable_track_source.h" +#include "sora/scalable_track_source.h" -class ScreenVideoCapturer : public ScalableVideoTrackSource, +class ScreenVideoCapturer : public sora::ScalableVideoTrackSource, public webrtc::DesktopCapturer::Callback { public: static bool GetSourceList(webrtc::DesktopCapturer::SourceList* sources); diff --git a/src/sora-cpp-sdk/README.md b/src/sora-cpp-sdk/README.md new file mode 100644 index 00000000..678d0ab6 --- /dev/null +++ b/src/sora-cpp-sdk/README.md @@ -0,0 +1 @@ +# Sora C++ SDK から持ってきたソースコードを配置するディレクトリ diff --git a/src/cuda/cuda_context.h b/src/sora-cpp-sdk/include/sora/cuda_context.h similarity index 65% rename from src/cuda/cuda_context.h rename to src/sora-cpp-sdk/include/sora/cuda_context.h index a136a3a5..0fe455ab 100644 --- a/src/cuda/cuda_context.h +++ b/src/sora-cpp-sdk/include/sora/cuda_context.h @@ -3,9 +3,13 @@ #include +namespace sora { + // に依存せずに CUDA のコンテキストを表す class CudaContext { public: + // CUDA コンテキスト生成する。 + // CUDA に対応していないプラットフォームでは nullptr を返す。 static std::shared_ptr Create(); void* Context() const; @@ -15,9 +19,13 @@ class CudaContext { enum class CudaVideoCodec { H264, + H265, VP8, VP9, + AV1, JPEG, }; +} // namespace sora + #endif \ No newline at end of file diff --git a/src/dyn/cuda.h b/src/sora-cpp-sdk/include/sora/dyn/cuda.h similarity index 95% rename from src/dyn/cuda.h rename to src/sora-cpp-sdk/include/sora/dyn/cuda.h index d2798501..ac4e51e4 100644 --- a/src/dyn/cuda.h +++ b/src/sora-cpp-sdk/include/sora/dyn/cuda.h @@ -1,34 +1,35 @@ -#ifndef DYN_CUDA_H_ -#define DYN_CUDA_H_ - -#include - -#include "dyn.h" - -namespace dyn { - -#if defined(WIN32) -static const char CUDA_SO[] = "nvcuda.dll"; -#else -static const char CUDA_SO[] = "libcuda.so.1"; -#endif -DYN_REGISTER(CUDA_SO, cuInit); -DYN_REGISTER(CUDA_SO, cuDeviceGet); -DYN_REGISTER(CUDA_SO, cuDeviceGetCount); -DYN_REGISTER(CUDA_SO, cuDeviceGetName); -DYN_REGISTER(CUDA_SO, cuCtxCreate); -DYN_REGISTER(CUDA_SO, cuCtxDestroy); -DYN_REGISTER(CUDA_SO, cuCtxPushCurrent); -DYN_REGISTER(CUDA_SO, cuCtxPopCurrent); -DYN_REGISTER(CUDA_SO, cuGetErrorName); -DYN_REGISTER(CUDA_SO, cuMemAlloc); -DYN_REGISTER(CUDA_SO, cuMemAllocPitch); -DYN_REGISTER(CUDA_SO, cuMemFree); -DYN_REGISTER(CUDA_SO, cuMemcpy2D); -DYN_REGISTER(CUDA_SO, cuMemcpy2DAsync); -DYN_REGISTER(CUDA_SO, cuMemcpy2DUnaligned); -DYN_REGISTER(CUDA_SO, cuStreamSynchronize); - -} // namespace dyn - +#ifndef DYN_CUDA_H_ +#define DYN_CUDA_H_ + +#include + +#include "dyn.h" + +namespace dyn { + +#if defined(WIN32) +static const char CUDA_SO[] = "nvcuda.dll"; +#else +static const char CUDA_SO[] = "libcuda.so.1"; +#endif +DYN_REGISTER(CUDA_SO, cuInit); +DYN_REGISTER(CUDA_SO, cuDeviceGet); +DYN_REGISTER(CUDA_SO, cuDeviceGetCount); +DYN_REGISTER(CUDA_SO, cuDeviceGetName); +DYN_REGISTER(CUDA_SO, cuCtxCreate); +DYN_REGISTER(CUDA_SO, cuCtxDestroy); +DYN_REGISTER(CUDA_SO, cuCtxPushCurrent); +DYN_REGISTER(CUDA_SO, cuCtxPopCurrent); +DYN_REGISTER(CUDA_SO, cuGetErrorName); +DYN_REGISTER(CUDA_SO, cuMemAlloc); +DYN_REGISTER(CUDA_SO, cuMemAllocPitch); +DYN_REGISTER(CUDA_SO, cuMemFree); +DYN_REGISTER(CUDA_SO, cuMemcpy2D); +DYN_REGISTER(CUDA_SO, cuMemcpy2DAsync); +DYN_REGISTER(CUDA_SO, cuMemcpy2DUnaligned); +DYN_REGISTER(CUDA_SO, cuStreamSynchronize); +DYN_REGISTER(CUDA_SO, cuStreamCreate); + +} // namespace dyn + #endif // DYN_CUDA_H_ \ No newline at end of file diff --git a/src/dyn/dyn.h b/src/sora-cpp-sdk/include/sora/dyn/dyn.h similarity index 88% rename from src/dyn/dyn.h rename to src/sora-cpp-sdk/include/sora/dyn/dyn.h index 3b65df63..867ecf08 100644 --- a/src/dyn/dyn.h +++ b/src/sora-cpp-sdk/include/sora/dyn/dyn.h @@ -8,7 +8,7 @@ #if defined(_WIN32) #include -#elif defined(__linux__) +#else // Linux #include #endif @@ -28,7 +28,7 @@ class DynModule { typedef void* module_ptr_t; #endif - bool IsLoadable(const char* name) { + static bool IsLoadable(const char* name) { #if defined(_WIN32) module_ptr_t module = LoadLibraryA(name); if (module == nullptr) { @@ -36,15 +36,13 @@ class DynModule { } FreeLibrary(module); return true; -#elif defined(__linux__) +#else module_ptr_t module = dlopen(name, RTLD_LAZY); if (module == nullptr) { return false; } dlclose(module); return true; -#else - return false; #endif } @@ -55,10 +53,8 @@ class DynModule { } #if defined(_WIN32) module_ptr_t module = LoadLibraryA(name); -#elif defined(__linux__) - module_ptr_t module = dlopen(name, RTLD_LAZY); #else - module_ptr_t module = nullptr; + module_ptr_t module = dlopen(name, RTLD_LAZY); #endif if (module == nullptr) { return nullptr; @@ -75,10 +71,8 @@ class DynModule { } #if defined(_WIN32) return ::GetProcAddress(module, name); -#elif defined(__linux__) - return dlsym(module, name); #else - return nullptr; + return dlsym(module, name); #endif } @@ -88,9 +82,8 @@ class DynModule { if (p != nullptr) { #if defined(_WIN32) FreeLibrary(p); -#elif defined(__linux__) - ::dlclose(p); #else + ::dlclose(p); #endif } } @@ -118,8 +111,8 @@ class DynModule { auto f = \ (func_type)DynModule::Instance().GetFunc(soname, DYN_STRINGIZE(func)); \ if (f == nullptr) { \ - std::cerr << "Failed to load function " DYN_STRINGIZE(func) " in " \ - << soname << std::endl; \ + std::cerr << "Failed to GetFunc: " << DYN_STRINGIZE(func) \ + << " soname=" << soname << std::endl; \ exit(1); \ } \ return f(args...); \ diff --git a/src/dyn/nvcuvid.h b/src/sora-cpp-sdk/include/sora/dyn/nvcuvid.h similarity index 96% rename from src/dyn/nvcuvid.h rename to src/sora-cpp-sdk/include/sora/dyn/nvcuvid.h index 7cb33fca..70275938 100644 --- a/src/dyn/nvcuvid.h +++ b/src/sora-cpp-sdk/include/sora/dyn/nvcuvid.h @@ -1,32 +1,32 @@ -#ifndef DYN_NVCUVID_H_ -#define DYN_NVCUVID_H_ - -#include "dyn.h" - -// defs -#include - -namespace dyn { - -#if defined(WIN32) -static const char NVCUVID_SO[] = "nvcuvid.dll"; -#else -static const char NVCUVID_SO[] = "libnvcuvid.so.1"; -#endif -DYN_REGISTER(NVCUVID_SO, cuvidCreateDecoder); -DYN_REGISTER(NVCUVID_SO, cuvidReconfigureDecoder); -DYN_REGISTER(NVCUVID_SO, cuvidDestroyDecoder); -DYN_REGISTER(NVCUVID_SO, cuvidDecodePicture); -DYN_REGISTER(NVCUVID_SO, cuvidGetDecodeStatus); -DYN_REGISTER(NVCUVID_SO, cuvidGetDecoderCaps); -DYN_REGISTER(NVCUVID_SO, cuvidCreateVideoParser); -DYN_REGISTER(NVCUVID_SO, cuvidDestroyVideoParser); -DYN_REGISTER(NVCUVID_SO, cuvidParseVideoData); -DYN_REGISTER(NVCUVID_SO, cuvidMapVideoFrame); -DYN_REGISTER(NVCUVID_SO, cuvidUnmapVideoFrame); -DYN_REGISTER(NVCUVID_SO, cuvidCtxLockCreate); -DYN_REGISTER(NVCUVID_SO, cuvidCtxLockDestroy); - -} // namespace dyn - +#ifndef DYN_NVCUVID_H_ +#define DYN_NVCUVID_H_ + +#include "dyn.h" + +// defs +#include + +namespace dyn { + +#if defined(WIN32) +static const char NVCUVID_SO[] = "nvcuvid.dll"; +#else +static const char NVCUVID_SO[] = "libnvcuvid.so.1"; +#endif +DYN_REGISTER(NVCUVID_SO, cuvidCreateDecoder); +DYN_REGISTER(NVCUVID_SO, cuvidReconfigureDecoder); +DYN_REGISTER(NVCUVID_SO, cuvidDestroyDecoder); +DYN_REGISTER(NVCUVID_SO, cuvidDecodePicture); +DYN_REGISTER(NVCUVID_SO, cuvidGetDecodeStatus); +DYN_REGISTER(NVCUVID_SO, cuvidGetDecoderCaps); +DYN_REGISTER(NVCUVID_SO, cuvidCreateVideoParser); +DYN_REGISTER(NVCUVID_SO, cuvidDestroyVideoParser); +DYN_REGISTER(NVCUVID_SO, cuvidParseVideoData); +DYN_REGISTER(NVCUVID_SO, cuvidMapVideoFrame); +DYN_REGISTER(NVCUVID_SO, cuvidUnmapVideoFrame); +DYN_REGISTER(NVCUVID_SO, cuvidCtxLockCreate); +DYN_REGISTER(NVCUVID_SO, cuvidCtxLockDestroy); + +} // namespace dyn + #endif // DYN_NVCUVID_H_ \ No newline at end of file diff --git a/src/sora-cpp-sdk/include/sora/fix_cuda_noinline_macro_error.h b/src/sora-cpp-sdk/include/sora/fix_cuda_noinline_macro_error.h new file mode 100644 index 00000000..027fe4da --- /dev/null +++ b/src/sora-cpp-sdk/include/sora/fix_cuda_noinline_macro_error.h @@ -0,0 +1,22 @@ +/* +## 背景 + +WebRTC を M121 に更新した際に以下のビルド・エラーが発生した + +``` +error: use of undeclared identifier 'noinline'; did you mean 'inline' +``` + +WebRTC に含まれる libcxx のバージョンが更新されたことが原因だと思われる + +## 対応 + +同様の問題を解消したと思われる LLVM の [PR](https://github.com/llvm/llvm-project-release-prs/pull/698) を調査したところ、 PR で追加されたファイルは存在するにも関わらず、問題が継続して発生していることがわかった +(libcxx に bits/basic_string.h が含まれておらず、 cuda_wrappers 以下のファイルがインクルードされていないようだった) + +上記 PR を参考に、ファイルを直接修正したところエラーが解消したため、このヘッダー・ファイルをエラーが発生する箇所でインクルードすることにした +オリジナルのパッチには push_macro や pop_macro が含まれているが、省いても問題が無かったため省略している + +*/ + +#undef __noinline__ diff --git a/src/hwenc_jetson/jetson_buffer.h b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_buffer.h similarity index 94% rename from src/hwenc_jetson/jetson_buffer.h rename to src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_buffer.h index 4290eab3..3b41ecc8 100644 --- a/src/hwenc_jetson/jetson_buffer.h +++ b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_buffer.h @@ -1,5 +1,5 @@ -#ifndef JETSON_BUFFER_H_ -#define JETSON_BUFFER_H_ +#ifndef SORA_HWENC_JETSON_JETSON_BUFFER_H_ +#define SORA_HWENC_JETSON_JETSON_BUFFER_H_ #include #include @@ -10,11 +10,10 @@ #include #include -// Jetson Linux Multimedia API -#include "nvbuf_utils.h" - #include "jetson_jpeg_decoder.h" +namespace sora { + class JetsonBuffer : public webrtc::VideoFrameBuffer { public: static rtc::scoped_refptr Create( @@ -76,4 +75,7 @@ class JetsonBuffer : public webrtc::VideoFrameBuffer { const std::unique_ptr data_; size_t length_; }; -#endif // JETSON_BUFFER_H_ + +} // namespace sora + +#endif diff --git a/src/hwenc_jetson/jetson_jpeg_decoder.h b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_jpeg_decoder.h similarity index 64% rename from src/hwenc_jetson/jetson_jpeg_decoder.h rename to src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_jpeg_decoder.h index a9e4af65..7c2c9702 100644 --- a/src/hwenc_jetson/jetson_jpeg_decoder.h +++ b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_jpeg_decoder.h @@ -1,19 +1,20 @@ -#ifndef JETSON_JPEG_DECODER_H_ -#define JETSON_JPEG_DECODER_H_ +#ifndef SORA_HWENC_JETSON_JETSON_JPEG_DECODER_H_ +#define SORA_HWENC_JETSON_JETSON_JPEG_DECODER_H_ #include -// Jetson Linux Multimedia API -#include - #include "jetson_jpeg_decoder_pool.h" +class NvJPEGDecoder; + +namespace sora { + class JetsonJpegDecoderPool; class JetsonJpegDecoder { public: JetsonJpegDecoder(std::shared_ptr pool, - std::unique_ptr decoder); + std::shared_ptr decoder); ~JetsonJpegDecoder(); int DecodeToFd(int& fd, @@ -25,6 +26,9 @@ class JetsonJpegDecoder { private: std::shared_ptr pool_; - std::unique_ptr decoder_; + std::shared_ptr decoder_; }; -#endif // JETSON_JPEG_DECODER_H_ \ No newline at end of file + +} // namespace sora + +#endif \ No newline at end of file diff --git a/src/hwenc_jetson/jetson_jpeg_decoder_pool.h b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_jpeg_decoder_pool.h similarity index 50% rename from src/hwenc_jetson/jetson_jpeg_decoder_pool.h rename to src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_jpeg_decoder_pool.h index 699502bf..328e6f1d 100644 --- a/src/hwenc_jetson/jetson_jpeg_decoder_pool.h +++ b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_jpeg_decoder_pool.h @@ -1,25 +1,29 @@ -#ifndef JETSON_JPEG_DECODER_POOL_H_ -#define JETSON_JPEG_DECODER_POOL_H_ +#ifndef SORA_HWENC_JETSON_JETSON_JPEG_DECODER_POOL_H_ +#define SORA_HWENC_JETSON_JETSON_JPEG_DECODER_POOL_H_ #include #include #include -// Jetson Linux Multimedia API -#include - #include "jetson_jpeg_decoder.h" +class NvJPEGDecoder; + +namespace sora { + class JetsonJpegDecoder; class JetsonJpegDecoderPool : public std::enable_shared_from_this { public: std::shared_ptr Pop(); - void Push(std::unique_ptr decoder); + void Push(std::shared_ptr decoder); private: std::mutex mtx_; - std::queue> decoder_queue_; + std::queue> decoder_queue_; }; -#endif // JETSON_JPEG_DECODER_POOL_H_ \ No newline at end of file + +} // namespace sora + +#endif diff --git a/src/hwenc_jetson/jetson_v4l2_capturer.h b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_v4l2_capturer.h similarity index 89% rename from src/hwenc_jetson/jetson_v4l2_capturer.h rename to src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_v4l2_capturer.h index 6d91515d..fc01594d 100644 --- a/src/hwenc_jetson/jetson_v4l2_capturer.h +++ b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_v4l2_capturer.h @@ -1,5 +1,5 @@ -#ifndef HWENC_JETSON_JETSON_V4L2_CAPTURER_H_ -#define HWENC_JETSON_JETSON_V4L2_CAPTURER_H_ +#ifndef SORA_HWENC_JETSON_JETSON_V4L2_CAPTURER_H_ +#define SORA_HWENC_JETSON_JETSON_V4L2_CAPTURER_H_ #include #include @@ -16,8 +16,10 @@ #include #include "jetson_jpeg_decoder_pool.h" -#include "rtc/scalable_track_source.h" -#include "v4l2_video_capturer/v4l2_video_capturer.h" +#include "sora/scalable_track_source.h" +#include "sora/v4l2/v4l2_video_capturer.h" + +namespace sora { class JetsonV4L2Capturer : public ScalableVideoTrackSource { public: @@ -76,4 +78,6 @@ class JetsonV4L2Capturer : public ScalableVideoTrackSource { std::shared_ptr jpeg_decoder_pool_; }; +} // namespace sora + #endif diff --git a/src/hwenc_jetson/jetson_video_decoder.h b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_video_decoder.h similarity index 89% rename from src/hwenc_jetson/jetson_video_decoder.h rename to src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_video_decoder.h index c175bda1..e887b217 100644 --- a/src/hwenc_jetson/jetson_video_decoder.h +++ b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_video_decoder.h @@ -9,8 +9,8 @@ * */ -#ifndef HWENC_JETSON_JETSON_VIDEO_DECODER_H_ -#define HWENC_JETSON_JETSON_VIDEO_DECODER_H_ +#ifndef SORA_HWENC_JETSON_JETSON_VIDEO_DECODER_H_ +#define SORA_HWENC_JETSON_JETSON_VIDEO_DECODER_H_ // WebRTC #include @@ -21,13 +21,14 @@ struct v4l2_crop; class NvV4l2Element; class NvVideoDecoder; +namespace sora { + class JetsonVideoDecoder : public webrtc::VideoDecoder { public: JetsonVideoDecoder(webrtc::VideoCodecType codec); ~JetsonVideoDecoder() override; - static bool IsSupportedVP8(); - static bool IsSupportedAV1(); + static bool IsSupported(webrtc::VideoCodecType codec); bool Configure(const Settings& settings) override; @@ -61,4 +62,6 @@ class JetsonVideoDecoder : public webrtc::VideoDecoder { std::shared_ptr capture_crop_; }; +} // namespace sora + #endif diff --git a/src/hwenc_jetson/jetson_video_encoder.h b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_video_encoder.h similarity index 88% rename from src/hwenc_jetson/jetson_video_encoder.h rename to src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_video_encoder.h index 4cf75b90..1c732edb 100644 --- a/src/hwenc_jetson/jetson_video_encoder.h +++ b/src/sora-cpp-sdk/include/sora/hwenc_jetson/jetson_video_encoder.h @@ -9,8 +9,8 @@ * */ -#ifndef HWENC_JETSON_JETSON_VIDEO_ENCODER_H_ -#define HWENC_JETSON_JETSON_VIDEO_ENCODER_H_ +#ifndef SORA_HWENC_JETSON_JETSON_VIDEO_ENCODER_H_ +#define SORA_HWENC_JETSON_JETSON_VIDEO_ENCODER_H_ #include #include @@ -22,6 +22,7 @@ // WebRTC #include #include +#include #include #include #include @@ -36,14 +37,14 @@ class NvV4l2Element; class NvVideoEncoder; struct v4l2_ctrl_videoenc_outputbuf_metadata_; +namespace sora { + class JetsonVideoEncoder : public webrtc::VideoEncoder { public: - explicit JetsonVideoEncoder(const cricket::VideoCodec& codec); + explicit JetsonVideoEncoder(const cricket::Codec& codec); ~JetsonVideoEncoder() override; - static bool IsSupportedVP8(); - static bool IsSupportedVP9(); - static bool IsSupportedAV1(); + static bool IsSupported(webrtc::VideoCodecType codec); int32_t InitEncode(const webrtc::VideoCodec* codec_settings, int32_t number_of_cores, @@ -122,6 +123,7 @@ class JetsonVideoEncoder : public webrtc::VideoEncoder { int32_t height_; bool use_native_; bool use_dmabuff_; + int dmabuff_fd_[CONVERTER_CAPTURE_NUM]; webrtc::GofInfoVP9 gof_; size_t gof_idx_; @@ -130,8 +132,15 @@ class JetsonVideoEncoder : public webrtc::VideoEncoder { webrtc::Mutex frame_params_lock_; std::queue> frame_params_; + std::mutex enc0_buffer_mtx_; + std::condition_variable enc0_buffer_cond_; + std::queue* enc0_buffer_queue_; int output_plane_fd_[32]; webrtc::EncodedImage encoded_image_; + webrtc::ScalabilityMode scalability_mode_; + std::vector obu_seq_header_; }; +} // namespace sora + #endif diff --git a/src/hwenc_nvcodec/nvcodec_decoder_cuda.h b/src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_decoder_cuda.h similarity index 65% rename from src/hwenc_nvcodec/nvcodec_decoder_cuda.h rename to src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_decoder_cuda.h index 1b70817e..b2711a3c 100644 --- a/src/hwenc_nvcodec/nvcodec_decoder_cuda.h +++ b/src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_decoder_cuda.h @@ -1,10 +1,16 @@ -#ifndef NVCODEC_DECODER_CUDA_H_ -#define NVCODEC_DECODER_CUDA_H_ +#ifndef SORA_HWENC_NVCODEC_NVCODEC_DECODER_CUDA_H_ +#define SORA_HWENC_NVCODEC_NVCODEC_DECODER_CUDA_H_ #include + +// clang-format off +#include "sora/fix_cuda_noinline_macro_error.h" #include +// clang-format on + +#include "sora/cuda_context.h" -#include "cuda/cuda_context.h" +namespace sora { class NvCodecDecoderCuda { public: @@ -25,4 +31,6 @@ class NvCodecDecoderCuda { std::shared_ptr impl_; }; +} // namespace sora + #endif \ No newline at end of file diff --git a/src/hwenc_nvcodec/nvcodec_v4l2_capturer.h b/src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_v4l2_capturer.h similarity index 68% rename from src/hwenc_nvcodec/nvcodec_v4l2_capturer.h rename to src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_v4l2_capturer.h index 17ddb2de..d52e4a69 100644 --- a/src/hwenc_nvcodec/nvcodec_v4l2_capturer.h +++ b/src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_v4l2_capturer.h @@ -1,9 +1,10 @@ -#ifndef NVCODEC_V4L2_CAPTURER_H_ -#define NVCODEC_V4L2_CAPTURER_H_ +#ifndef SORA_HWENC_NVCODEC_NVCODEC_V4L2_CAPTURER_H_ +#define SORA_HWENC_NVCODEC_NVCODEC_V4L2_CAPTURER_H_ -#include "v4l2_video_capturer/v4l2_video_capturer.h" +#include "nvcodec_decoder_cuda.h" +#include "sora/v4l2/v4l2_video_capturer.h" -#include "./nvcodec_decoder_cuda.h" +namespace sora { struct NvCodecV4L2CapturerConfig : V4L2VideoCapturerConfig { NvCodecV4L2CapturerConfig(const V4L2VideoCapturerConfig& config) { @@ -15,15 +16,13 @@ struct NvCodecV4L2CapturerConfig : V4L2VideoCapturerConfig { class NvCodecV4L2Capturer : public V4L2VideoCapturer { public: static rtc::scoped_refptr Create( - NvCodecV4L2CapturerConfig config); + const NvCodecV4L2CapturerConfig& config); NvCodecV4L2Capturer(const NvCodecV4L2CapturerConfig& config); - bool UseNativeBuffer() override; - private: static rtc::scoped_refptr Create( webrtc::VideoCaptureModule::DeviceInfo* device_info, - NvCodecV4L2CapturerConfig config, + const NvCodecV4L2CapturerConfig& config, size_t capture_device_index); void OnCaptured(uint8_t* data, uint32_t bytesused) override; @@ -31,4 +30,6 @@ class NvCodecV4L2Capturer : public V4L2VideoCapturer { std::shared_ptr decoder_; }; -#endif // NVCODEC_V4L2_CAPTURER_H_ +} // namespace sora + +#endif diff --git a/src/hwenc_nvcodec/nvcodec_video_decoder.h b/src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_video_decoder.h similarity index 78% rename from src/hwenc_nvcodec/nvcodec_video_decoder.h rename to src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_video_decoder.h index e7ce883f..ceed5f93 100644 --- a/src/hwenc_nvcodec/nvcodec_video_decoder.h +++ b/src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_video_decoder.h @@ -1,13 +1,15 @@ -#ifndef NVCODEC_VIDEO_DECODER_H_ -#define NVCODEC_VIDEO_DECODER_H_ +#ifndef SORA_HWENC_NVCODEC_NVCODEC_VIDEO_DECODER_H_ +#define SORA_HWENC_NVCODEC_NVCODEC_VIDEO_DECODER_H_ // WebRTC #include #include #include -#include "cuda/cuda_context.h" #include "nvcodec_decoder_cuda.h" +#include "sora/cuda_context.h" + +namespace sora { class NvCodecVideoDecoder : public webrtc::VideoDecoder { public: @@ -15,7 +17,8 @@ class NvCodecVideoDecoder : public webrtc::VideoDecoder { CudaVideoCodec codec); ~NvCodecVideoDecoder() override; - static bool IsSupported(CudaVideoCodec codec); + static bool IsSupported(std::shared_ptr context, + CudaVideoCodec codec); bool Configure(const Settings& settings) override; @@ -43,4 +46,6 @@ class NvCodecVideoDecoder : public webrtc::VideoDecoder { bool output_info_ = false; }; -#endif // NVCODEC_VIDEO_DECODER_H_ +} // namespace sora + +#endif diff --git a/src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_video_encoder.h b/src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_video_encoder.h new file mode 100644 index 00000000..75b72abe --- /dev/null +++ b/src/sora-cpp-sdk/include/sora/hwenc_nvcodec/nvcodec_video_encoder.h @@ -0,0 +1,25 @@ +#ifndef SORA_HWENC_NVCODEC_NVCODEC_VIDEO_ENCODER_H_ +#define SORA_HWENC_NVCODEC_NVCODEC_VIDEO_ENCODER_H_ + +#include + +// WebRTC +#include +#include + +#include "sora/cuda_context.h" + +namespace sora { + +class NvCodecVideoEncoder : public webrtc::VideoEncoder { + public: + static bool IsSupported(std::shared_ptr cuda_context, + CudaVideoCodec codec); + static std::unique_ptr Create( + std::shared_ptr cuda_context, + CudaVideoCodec codec); +}; + +} // namespace sora + +#endif diff --git a/src/sora-cpp-sdk/include/sora/hwenc_vpl/vpl_session.h b/src/sora-cpp-sdk/include/sora/hwenc_vpl/vpl_session.h new file mode 100644 index 00000000..b026c464 --- /dev/null +++ b/src/sora-cpp-sdk/include/sora/hwenc_vpl/vpl_session.h @@ -0,0 +1,14 @@ +#ifndef SORA_HWENC_VPL_VPL_SESSION_H_ +#define SORA_HWENC_VPL_VPL_SESSION_H_ + +#include + +namespace sora { + +struct VplSession { + static std::shared_ptr Create(); +}; + +} // namespace sora + +#endif diff --git a/src/sora-cpp-sdk/include/sora/hwenc_vpl/vpl_video_decoder.h b/src/sora-cpp-sdk/include/sora/hwenc_vpl/vpl_video_decoder.h new file mode 100644 index 00000000..2ab8157a --- /dev/null +++ b/src/sora-cpp-sdk/include/sora/hwenc_vpl/vpl_video_decoder.h @@ -0,0 +1,25 @@ +#ifndef SORA_HWENC_VPL_VPL_VIDEO_DECODER_H_ +#define SORA_HWENC_VPL_VPL_VIDEO_DECODER_H_ + +#include + +// WebRTC +#include +#include + +#include "vpl_session.h" + +namespace sora { + +class VplVideoDecoder : public webrtc::VideoDecoder { + public: + static bool IsSupported(std::shared_ptr session, + webrtc::VideoCodecType codec); + static std::unique_ptr Create( + std::shared_ptr session, + webrtc::VideoCodecType codec); +}; + +} // namespace sora + +#endif diff --git a/src/sora-cpp-sdk/include/sora/hwenc_vpl/vpl_video_encoder.h b/src/sora-cpp-sdk/include/sora/hwenc_vpl/vpl_video_encoder.h new file mode 100644 index 00000000..354e0d0b --- /dev/null +++ b/src/sora-cpp-sdk/include/sora/hwenc_vpl/vpl_video_encoder.h @@ -0,0 +1,25 @@ +#ifndef SORA_HWENC_VPL_VPL_VIDEO_ENCODER_H_ +#define SORA_HWENC_VPL_VPL_VIDEO_ENCODER_H_ + +#include + +// WebRTC +#include +#include + +#include "vpl_session.h" + +namespace sora { + +class VplVideoEncoder : public webrtc::VideoEncoder { + public: + static bool IsSupported(std::shared_ptr session, + webrtc::VideoCodecType codec); + static std::unique_ptr Create( + std::shared_ptr session, + webrtc::VideoCodecType codec); +}; + +} // namespace sora + +#endif diff --git a/src/sora-cpp-sdk/include/sora/open_h264_video_encoder.h b/src/sora-cpp-sdk/include/sora/open_h264_video_encoder.h new file mode 100644 index 00000000..c30b8b4a --- /dev/null +++ b/src/sora-cpp-sdk/include/sora/open_h264_video_encoder.h @@ -0,0 +1,19 @@ +#ifndef SORA_OPEN_H264_VIDEO_ENCODER_H_ +#define SORA_OPEN_H264_VIDEO_ENCODER_H_ + +#include +#include + +// WebRTC +#include +#include + +namespace sora { + +std::unique_ptr CreateOpenH264VideoEncoder( + const webrtc::SdpVideoFormat& format, + std::string openh264); + +} + +#endif diff --git a/src/rtc/scalable_track_source.h b/src/sora-cpp-sdk/include/sora/scalable_track_source.h similarity index 90% rename from src/rtc/scalable_track_source.h rename to src/sora-cpp-sdk/include/sora/scalable_track_source.h index d5442445..c8c4d365 100644 --- a/src/rtc/scalable_track_source.h +++ b/src/sora-cpp-sdk/include/sora/scalable_track_source.h @@ -7,8 +7,8 @@ * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ -#ifndef SCALABLE_VIDEO_TRACK_SOURCE_H_ -#define SCALABLE_VIDEO_TRACK_SOURCE_H_ +#ifndef SORA_SCALABLE_VIDEO_TRACK_SOURCE_H_ +#define SORA_SCALABLE_VIDEO_TRACK_SOURCE_H_ #include @@ -19,6 +19,8 @@ #include #include +namespace sora { + struct ScalableVideoTrackSourceConfig { std::function on_frame; }; @@ -39,4 +41,6 @@ class ScalableVideoTrackSource : public rtc::AdaptedVideoTrackSource { rtc::TimestampAligner timestamp_aligner_; }; +} // namespace sora + #endif diff --git a/src/v4l2_video_capturer/v4l2_video_capturer.h b/src/sora-cpp-sdk/include/sora/v4l2/v4l2_video_capturer.h similarity index 81% rename from src/v4l2_video_capturer/v4l2_video_capturer.h rename to src/sora-cpp-sdk/include/sora/v4l2/v4l2_video_capturer.h index 8a36067a..96c4489c 100644 --- a/src/v4l2_video_capturer/v4l2_video_capturer.h +++ b/src/sora-cpp-sdk/include/sora/v4l2/v4l2_video_capturer.h @@ -8,8 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef V4L2_VIDEO_CAPTURER_H_ -#define V4L2_VIDEO_CAPTURER_H_ +#ifndef SORA_V4L2_VIDEO_CAPTURER_H_ +#define SORA_V4L2_VIDEO_CAPTURER_H_ #include #include @@ -19,10 +19,13 @@ // WebRTC #include #include -#include #include #include +#include "sora/scalable_track_source.h" + +namespace sora { + struct V4L2VideoCapturerConfig : ScalableVideoTrackSourceConfig { std::string video_device; int width = 640; @@ -35,16 +38,14 @@ struct V4L2VideoCapturerConfig : ScalableVideoTrackSourceConfig { class V4L2VideoCapturer : public ScalableVideoTrackSource { public: static rtc::scoped_refptr Create( - V4L2VideoCapturerConfig config); + const V4L2VideoCapturerConfig& config); static void LogDeviceList( webrtc::VideoCaptureModule::DeviceInfo* device_info); - V4L2VideoCapturer(V4L2VideoCapturerConfig config); + V4L2VideoCapturer(const V4L2VideoCapturerConfig& config); ~V4L2VideoCapturer(); - int32_t Init(const char* deviceUniqueId, - const std::string& specifiedVideoDevice); - virtual int32_t StartCapture(V4L2VideoCapturerConfig config); - virtual bool UseNativeBuffer(); + int32_t Init(const char* deviceUniqueId); + virtual int32_t StartCapture(const V4L2VideoCapturerConfig& config); protected: virtual int32_t StopCapture(); @@ -66,7 +67,7 @@ class V4L2VideoCapturer : public ScalableVideoTrackSource { private: static rtc::scoped_refptr Create( webrtc::VideoCaptureModule::DeviceInfo* device_info, - V4L2VideoCapturerConfig config, + const V4L2VideoCapturerConfig& config, size_t capture_device_index); bool FindDevice(const char* deviceUniqueIdUTF8, const std::string& device); @@ -85,4 +86,6 @@ class V4L2VideoCapturer : public ScalableVideoTrackSource { bool _captureStarted; }; -#endif // V4L2_VIDEO_CAPTURER_H_ +} // namespace sora + +#endif diff --git a/src/sora-cpp-sdk/src/cuda_context_cuda.cpp b/src/sora-cpp-sdk/src/cuda_context_cuda.cpp new file mode 100644 index 00000000..6a20f56e --- /dev/null +++ b/src/sora-cpp-sdk/src/cuda_context_cuda.cpp @@ -0,0 +1,84 @@ +#include "sora/fix_cuda_noinline_macro_error.h" + +#include "sora/cuda_context.h" + +#if !defined(USE_NVCODEC_ENCODER) + +namespace sora { + +std::shared_ptr CudaContext::Create() { + return nullptr; +} + +void* CudaContext::Context() const { + return nullptr; +} + +} // namespace sora + +#else + +#include "cuda_context_cuda.h" + +// NvCodec +#include + +#include "sora/dyn/cuda.h" + +// どこかにグローバルな logger の定義が必要 +simplelogger::Logger* logger = + simplelogger::LoggerFactory::CreateConsoleLogger(); + +namespace sora { + +CUcontext GetCudaContext(std::shared_ptr ctx) { + return static_cast(ctx->Context()); +} + +struct CudaContextImpl { + CUdevice device; + CUcontext context; + ~CudaContextImpl() { dyn::cuCtxDestroy(context); } +}; + +#define ckerror(call) \ + if (!ck(call)) \ + throw std::exception() + +std::shared_ptr CudaContext::Create() { + std::shared_ptr ctx; + try { + CUdevice device; + CUcontext context; + + if (!dyn::DynModule::Instance().IsLoadable(dyn::CUDA_SO)) { + throw std::exception(); + } + + ckerror(dyn::cuInit(0)); + ckerror(dyn::cuDeviceGet(&device, 0)); + char device_name[80]; + ckerror(dyn::cuDeviceGetName(device_name, sizeof(device_name), device)); + //RTC_LOG(LS_INFO) << "GPU in use: " << device_name; + ckerror(dyn::cuCtxCreate(&context, 0, device)); + + std::shared_ptr impl(new CudaContextImpl()); + impl->device = device; + impl->context = context; + + ctx.reset(new CudaContext()); + ctx->impl_ = impl; + } catch (std::exception&) { + return nullptr; + } + + return ctx; +} + +void* CudaContext::Context() const { + return std::static_pointer_cast(impl_)->context; +} + +} // namespace sora + +#endif diff --git a/src/sora-cpp-sdk/src/cuda_context_cuda.h b/src/sora-cpp-sdk/src/cuda_context_cuda.h new file mode 100644 index 00000000..25ffd2b8 --- /dev/null +++ b/src/sora-cpp-sdk/src/cuda_context_cuda.h @@ -0,0 +1,14 @@ +#ifndef SORA_CUDA_CONTEXT_CUDA_H_ +#define SORA_CUDA_CONTEXT_CUDA_H_ + +#include + +#include "sora/cuda_context.h" + +namespace sora { + +CUcontext GetCudaContext(std::shared_ptr ctx); + +} + +#endif \ No newline at end of file diff --git a/src/hwenc_jetson/jetson_buffer.cpp b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_buffer.cpp similarity index 70% rename from src/hwenc_jetson/jetson_buffer.cpp rename to src/sora-cpp-sdk/src/hwenc_jetson/jetson_buffer.cpp index 6d9d67ba..d1e41417 100644 --- a/src/hwenc_jetson/jetson_buffer.cpp +++ b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_buffer.cpp @@ -1,4 +1,4 @@ -#include "jetson_buffer.h" +#include "sora/hwenc_jetson/jetson_buffer.h" // Linux #include @@ -8,6 +8,12 @@ #include #include +// Jetson Linux Multimedia API +#include +#include + +namespace sora { + static const int kBufferAlignment = 64; rtc::scoped_refptr JetsonBuffer::Create( @@ -57,62 +63,65 @@ rtc::scoped_refptr JetsonBuffer::ToI420() { int32_t buffer_width = ((scaled_width_ + 15) / 16) * 16; int32_t buffer_height = ((scaled_height_ + 15) / 16) * 16; - NvBufferCreateParams input_params = {0}; - input_params.payloadType = NvBufferPayload_SurfArray; - input_params.width = buffer_width; - input_params.height = buffer_height; - input_params.layout = NvBufferLayout_Pitch; - input_params.colorFormat = NvBufferColorFormat_YUV420; - input_params.nvbuf_tag = NvBufferTag_NONE; - - int dmabuf_fd; - if (NvBufferCreateEx(&dmabuf_fd, &input_params) == -1) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << " Failed to NvBufferCreateEx"; - return scaled_buffer; - } - - NvBufferParams params = {0}; - if (NvBufferGetParams(fd_, ¶ms) == -1) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << " Failed to NvBufferGetParams"; + NvBufSurfaceAllocateParams input_params = {0}; + input_params.params.width = buffer_width; + input_params.params.height = buffer_height; + input_params.params.layout = NVBUF_LAYOUT_PITCH; + input_params.params.colorFormat = NVBUF_COLOR_FORMAT_YUV420; + input_params.params.memType = NVBUF_MEM_SURFACE_ARRAY; + input_params.memtag = NvBufSurfaceTag_NONE; + + NvBufSurface* dst_surf = 0; + + if (NvBufSurfaceAllocate( + &dst_surf, + 1, /* NvUtils では複数のバッファーを同時に初期化できるため、バッファーの数を指定する */ + &input_params) == -1) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << " Failed to NvBufSurfaceAllocate"; return scaled_buffer; } + NvBufSurfaceParams params = dst_surf->surfaceList[0]; - NvBufferRect src_rect, dest_rect; + NvBufSurfTransformRect src_rect, dest_rect; src_rect.top = 0; src_rect.left = 0; - src_rect.width = params.width[0]; - src_rect.height = params.height[0]; + src_rect.width = params.width; + src_rect.height = params.height; dest_rect.top = 0; dest_rect.left = 0; dest_rect.width = buffer_width; dest_rect.height = buffer_height; - NvBufferTransformParams trans_params; + NvBufSurfTransformParams trans_params; memset(&trans_params, 0, sizeof(trans_params)); - trans_params.transform_flag = NVBUFFER_TRANSFORM_FILTER; - trans_params.transform_flip = NvBufferTransform_None; - trans_params.transform_filter = NvBufferTransform_Filter_Smart; - trans_params.src_rect = src_rect; - trans_params.dst_rect = dest_rect; - - if (NvBufferTransform(fd_, dmabuf_fd, &trans_params) == -1) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << " Failed to NvBufferTransform"; + trans_params.transform_flag = NVBUFSURF_TRANSFORM_FILTER; + trans_params.transform_flip = NvBufSurfTransform_None; + trans_params.transform_filter = NvBufSurfTransformInter_Algo3; + trans_params.src_rect = &src_rect; + trans_params.dst_rect = &dest_rect; + + NvBufSurface* src_surf = 0; + if (NvBufSurfaceFromFd(fd_, (void**)(&src_surf)) == -1) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << " Failed to NvBufSurfaceFromFd"; return scaled_buffer; } - NvBufferParams dmabuf_params = {0}; - if (NvBufferGetParams(dmabuf_fd, &dmabuf_params) == -1) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << " Failed to NvBufferGetParams"; + if (NvBufSurfTransform(src_surf, dst_surf, &trans_params) != + NvBufSurfTransformError_Success) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << " Failed to NvBufSurfTransform"; return scaled_buffer; } int ret; void* data_addr; uint8_t* dest_addr; - for (int plane = 0; plane < dmabuf_params.num_planes; plane++) { - ret = NvBufferMemMap(dmabuf_fd, plane, NvBufferMem_Read, &data_addr); + int num_planes = dst_surf->surfaceList->planeParams.num_planes; + int index = 0; + for (int plane = 0; plane < num_planes; plane++) { + ret = NvBufSurfaceMap(dst_surf, index, plane, NVBUF_MAP_READ); if (ret == 0) { - NvBufferMemSyncForCpu(dmabuf_fd, plane, &data_addr); + NvBufSurfaceSyncForCpu(dst_surf, index, plane); + data_addr = dst_surf->surfaceList->mappedAddr.addr[plane]; int height, width; if (plane == 0) { dest_addr = scaled_buffer.get()->MutableDataY(); @@ -129,18 +138,20 @@ rtc::scoped_refptr JetsonBuffer::ToI420() { } for (int i = 0; i < height; i++) { memcpy(dest_addr + width * i, - (uint8_t*)data_addr + dmabuf_params.pitch[plane] * i, width); + (uint8_t*)data_addr + + dst_surf->surfaceList->planeParams.pitch[plane] * i, + width); } } - NvBufferMemUnMap(dmabuf_fd, plane, &data_addr); + NvBufSurfaceUnMap(dst_surf, index, plane); if (ret == -1) { RTC_LOG(LS_ERROR) << __FUNCTION__ - << " Failed to NvBufferMemMap plane=" << plane; + << " Failed to NvBufSurfaceMap plane=" << plane; return scaled_buffer; } } - NvBufferDestroy(dmabuf_fd); + NvBufSurfaceDestroy(dst_surf); return scaled_buffer; } else { @@ -228,3 +239,5 @@ JetsonBuffer::JetsonBuffer(webrtc::VideoType video_type, data_(static_cast(webrtc::AlignedMalloc( webrtc::CalcBufferSize(video_type, raw_width, raw_height), kBufferAlignment))) {} + +} // namespace sora diff --git a/src/hwenc_jetson/jetson_jpeg_decoder.cpp b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_jpeg_decoder.cpp similarity index 75% rename from src/hwenc_jetson/jetson_jpeg_decoder.cpp rename to src/sora-cpp-sdk/src/hwenc_jetson/jetson_jpeg_decoder.cpp index ea25f698..bfd048bd 100644 --- a/src/hwenc_jetson/jetson_jpeg_decoder.cpp +++ b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_jpeg_decoder.cpp @@ -1,8 +1,13 @@ -#include "jetson_jpeg_decoder.h" +#include "sora/hwenc_jetson/jetson_jpeg_decoder.h" + +// Jetson Linux Multimedia API +#include + +namespace sora { JetsonJpegDecoder::JetsonJpegDecoder( std::shared_ptr pool, - std::unique_ptr decoder) + std::shared_ptr decoder) : pool_(pool), decoder_(std::move(decoder)) {} JetsonJpegDecoder::~JetsonJpegDecoder() { @@ -16,4 +21,6 @@ int JetsonJpegDecoder::DecodeToFd(int& fd, uint32_t& width, uint32_t& height) { return decoder_->decodeToFd(fd, in_buf, in_buf_size, pixfmt, width, height); -} \ No newline at end of file +} + +} // namespace sora diff --git a/src/sora-cpp-sdk/src/hwenc_jetson/jetson_jpeg_decoder_pool.cpp b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_jpeg_decoder_pool.cpp new file mode 100644 index 00000000..f0b33176 --- /dev/null +++ b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_jpeg_decoder_pool.cpp @@ -0,0 +1,38 @@ +#include "sora/hwenc_jetson/jetson_jpeg_decoder_pool.h" + +// WebRTC +#include + +// Jetson Linux Multimedia API +#include + +namespace sora { + +std::shared_ptr JetsonJpegDecoderPool::Pop() { + std::shared_ptr nv_decoder; + + // JetPack 5.1.2 で同じフレームが送信され続ける問題が発生したため、キューを無効化した + // JetPack 5.1.1 では正常に動作していた + // momo で同様の問題に対応した際の PR: https://github.com/shiguredo/momo/pull/297/ + // { + // std::lock_guard lock(mtx_); + // if (decoder_queue_.size() == 0) { + // nv_decoder.reset(NvJPEGDecoder::createJPEGDecoder("jpegdec")); + // } else { + // nv_decoder = std::move(decoder_queue_.front()); + // decoder_queue_.pop(); + // } + // } + nv_decoder.reset(NvJPEGDecoder::createJPEGDecoder("jpegdec")); + + std::shared_ptr decoder( + new JetsonJpegDecoder(shared_from_this(), std::move(nv_decoder))); + return decoder; +} + +void JetsonJpegDecoderPool::Push(std::shared_ptr decoder) { + std::lock_guard lock(mtx_); + // decoder_queue_.push(std::move(decoder)); +} + +} // namespace sora diff --git a/src/sora-cpp-sdk/src/hwenc_jetson/jetson_util.h b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_util.h new file mode 100644 index 00000000..cd4debd9 --- /dev/null +++ b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_util.h @@ -0,0 +1,16 @@ +#ifndef SORA_HWENC_JETSON_JETSON_UTIL_H_ +#define SORA_HWENC_JETSON_JETSON_UTIL_H_ + +namespace sora { + +static int VideoCodecToV4L2Format(webrtc::VideoCodecType codec) { + return codec == webrtc::kVideoCodecVP8 ? V4L2_PIX_FMT_VP8 + : codec == webrtc::kVideoCodecVP9 ? V4L2_PIX_FMT_VP9 + : codec == webrtc::kVideoCodecAV1 ? V4L2_PIX_FMT_AV1 + : codec == webrtc::kVideoCodecH264 ? V4L2_PIX_FMT_H264 + : codec == webrtc::kVideoCodecH265 ? V4L2_PIX_FMT_H265 + : 0; +} + +} // namespace sora +#endif diff --git a/src/hwenc_jetson/jetson_v4l2_capturer.cpp b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_v4l2_capturer.cpp similarity index 97% rename from src/hwenc_jetson/jetson_v4l2_capturer.cpp rename to src/sora-cpp-sdk/src/hwenc_jetson/jetson_v4l2_capturer.cpp index a344ffd3..3aaf687d 100644 --- a/src/hwenc_jetson/jetson_v4l2_capturer.cpp +++ b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_v4l2_capturer.cpp @@ -1,4 +1,4 @@ -#include "jetson_v4l2_capturer.h" +#include "sora/hwenc_jetson/jetson_v4l2_capturer.h" // C #include @@ -31,10 +31,12 @@ // L4T Multimedia API #include -#include "jetson_buffer.h" +#include "sora/hwenc_jetson/jetson_buffer.h" #define MJPEG_EOS_SEARCH_SIZE 4096 +namespace sora { + rtc::scoped_refptr JetsonV4L2Capturer::Create( const V4L2VideoCapturerConfig& config) { rtc::scoped_refptr capturer; @@ -570,26 +572,17 @@ void JetsonV4L2Capturer::OnCaptured(v4l2_buffer* buf) { Search for EOF to get exact size */ if (eosSearchSize > bytesused) eosSearchSize = bytesused; - bool found = false; for (unsigned int i = 0; i < eosSearchSize; i++) { p = data + bytesused; if ((*(p - 2) == 0xff) && (*(p - 1) == 0xd9)) { - found = true; break; } bytesused--; } - if (!found) { - RTC_LOG(LS_WARNING) << __FUNCTION__ - << " Invalid JPEG buffer frame skipped"; - return; - } std::shared_ptr decoder = jpeg_decoder_pool_->Pop(); int fd = 0; uint32_t width, height, pixfmt; - RTC_LOG(LS_INFO) << "data: " << (void*)data << " (" << (int)data[0] << "," - << (int)data[1] << ") bytesused: " << bytesused; if (decoder->DecodeToFd(fd, data, bytesused, pixfmt, width, height) < 0) { RTC_LOG(LS_ERROR) << "decodeToFd Failed"; return; @@ -617,3 +610,5 @@ void JetsonV4L2Capturer::OnCaptured(v4l2_buffer* buf) { .build()); } } + +} // namespace sora \ No newline at end of file diff --git a/src/hwenc_jetson/jetson_video_decoder.cpp b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_video_decoder.cpp similarity index 80% rename from src/hwenc_jetson/jetson_video_decoder.cpp rename to src/sora-cpp-sdk/src/hwenc_jetson/jetson_video_decoder.cpp index f1a3cf45..b10fe04c 100644 --- a/src/hwenc_jetson/jetson_video_decoder.cpp +++ b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_video_decoder.cpp @@ -9,7 +9,7 @@ * */ -#include "jetson_video_decoder.h" +#include "sora/hwenc_jetson/jetson_video_decoder.h" #include @@ -22,11 +22,15 @@ #include // L4T Multimedia API -#include +#include +#include // Jetson Linux Multimedia API +#include #include +#include "jetson_util.h" + #define INIT_ERROR(cond, desc) \ if (cond) { \ RTC_LOG(LS_ERROR) << __FUNCTION__ << desc; \ @@ -35,12 +39,10 @@ } #define CHUNK_SIZE 4000000 +namespace sora { + JetsonVideoDecoder::JetsonVideoDecoder(webrtc::VideoCodecType codec) - : input_format_(codec == webrtc::kVideoCodecVP8 ? V4L2_PIX_FMT_VP8 - : codec == webrtc::kVideoCodecVP9 ? V4L2_PIX_FMT_VP9 - : codec == webrtc::kVideoCodecH264 ? V4L2_PIX_FMT_H264 - : codec == webrtc::kVideoCodecAV1 ? V4L2_PIX_FMT_AV1 - : 0), + : input_format_(VideoCodecToV4L2Format(codec)), decoder_(nullptr), decode_complete_callback_(nullptr), buffer_pool_(false, 300 /* max_number_of_buffers*/), @@ -52,20 +54,10 @@ JetsonVideoDecoder::~JetsonVideoDecoder() { Release(); } -bool JetsonVideoDecoder::IsSupportedVP8() { - //SuppressErrors sup; - - auto decoder = NvVideoDecoder::createVideoDecoder("dec0"); - auto ret = decoder->setOutputPlaneFormat(V4L2_PIX_FMT_VP8, CHUNK_SIZE); - delete decoder; - return ret >= 0; -} - -bool JetsonVideoDecoder::IsSupportedAV1() { - //SuppressErrors sup; - +bool JetsonVideoDecoder::IsSupported(webrtc::VideoCodecType codec) { auto decoder = NvVideoDecoder::createVideoDecoder("dec0"); - auto ret = decoder->setOutputPlaneFormat(V4L2_PIX_FMT_AV1, CHUNK_SIZE); + auto ret = + decoder->setOutputPlaneFormat(VideoCodecToV4L2Format(codec), CHUNK_SIZE); delete decoder; return ret >= 0; } @@ -99,10 +91,10 @@ int32_t JetsonVideoDecoder::Decode(const webrtc::EncodedImage& input_image, memset(planes, 0, sizeof(planes)); v4l2_buf.m.planes = planes; - // RTC_LOG(LS_INFO) << __FUNCTION__ << " output_plane.getNumBuffers: " - // << decoder_->output_plane.getNumBuffers() - // << " output_plane.getNumQueuedBuffers: " - // << decoder_->output_plane.getNumQueuedBuffers(); + RTC_LOG(LS_INFO) << __FUNCTION__ << " output_plane.getNumBuffers: " + << decoder_->output_plane.getNumBuffers() + << " output_plane.getNumQueuedBuffers: " + << decoder_->output_plane.getNumQueuedBuffers(); if (decoder_->output_plane.getNumQueuedBuffers() == decoder_->output_plane.getNumBuffers()) { @@ -123,17 +115,18 @@ int32_t JetsonVideoDecoder::Decode(const webrtc::EncodedImage& input_image, v4l2_buf.flags |= V4L2_BUF_FLAG_TIMESTAMP_COPY; v4l2_buf.timestamp.tv_sec = - input_image.Timestamp() / rtc::kNumMicrosecsPerSec; + input_image.RtpTimestamp() / rtc::kNumMicrosecsPerSec; v4l2_buf.timestamp.tv_usec = - input_image.Timestamp() % rtc::kNumMicrosecsPerSec; + input_image.RtpTimestamp() % rtc::kNumMicrosecsPerSec; if (decoder_->output_plane.qBuffer(v4l2_buf, nullptr) < 0) { RTC_LOG(LS_ERROR) << "Failed to qBuffer at encoder output_plane"; return WEBRTC_VIDEO_CODEC_ERROR; } - // RTC_LOG(LS_INFO) << __FUNCTION__ << " timestamp:" << input_image.Timestamp() - // << " bytesused:" << buffer->planes[0].bytesused; + RTC_LOG(LS_INFO) << __FUNCTION__ + << " timestamp:" << input_image.RtpTimestamp() + << " bytesused:" << buffer->planes[0].bytesused; return WEBRTC_VIDEO_CODEC_OK; } @@ -216,7 +209,7 @@ bool JetsonVideoDecoder::JetsonRelease() { decoder_ = nullptr; } if (dst_dma_fd_ != -1) { - NvBufferDestroy(dst_dma_fd_); + NvBufSurf::NvDestroy(dst_dma_fd_); dst_dma_fd_ = -1; } return true; @@ -280,6 +273,7 @@ void JetsonVideoDecoder::CaptureLoop() { } NvBuffer* buffer; + while (1) { struct v4l2_buffer v4l2_buf; struct v4l2_plane planes[MAX_PLANES]; @@ -303,26 +297,23 @@ void JetsonVideoDecoder::CaptureLoop() { uint64_t pts = v4l2_buf.timestamp.tv_sec * rtc::kNumMicrosecsPerSec + v4l2_buf.timestamp.tv_usec; - NvBufferRect src_rect, dest_rect; - src_rect.top = capture_crop_->c.top; - src_rect.left = capture_crop_->c.left; - src_rect.width = capture_crop_->c.width; - src_rect.height = capture_crop_->c.height; - dest_rect.top = 0; - dest_rect.left = 0; - dest_rect.width = capture_crop_->c.width; - dest_rect.height = capture_crop_->c.height; - - NvBufferTransformParams transform_params; + NvBufSurf::NvCommonTransformParams transform_params; memset(&transform_params, 0, sizeof(transform_params)); - transform_params.transform_flag = NVBUFFER_TRANSFORM_FILTER; - transform_params.transform_flip = NvBufferTransform_None; - transform_params.transform_filter = NvBufferTransform_Filter_Smart; - transform_params.src_rect = src_rect; - transform_params.dst_rect = dest_rect; + transform_params.src_top = capture_crop_->c.top; + transform_params.src_left = capture_crop_->c.left; + transform_params.src_width = capture_crop_->c.width; + transform_params.src_height = capture_crop_->c.height; + transform_params.dst_top = 0; + transform_params.dst_left = 0; + transform_params.dst_width = capture_crop_->c.width; + transform_params.dst_height = capture_crop_->c.height; + transform_params.flag = NVBUFSURF_TRANSFORM_FILTER; + transform_params.flip = NvBufSurfTransform_None; + transform_params.filter = NvBufSurfTransformInter_Algo3; + // 何が来ても YUV420 に変換する - ret = NvBufferTransform(buffer->planes[0].fd, dst_dma_fd_, - &transform_params); + ret = NvBufSurf::NvTransform(&transform_params, buffer->planes[0].fd, + dst_dma_fd_); if (ret == -1) { RTC_LOG(LS_ERROR) << __FUNCTION__ << " Transform failed"; break; @@ -339,9 +330,6 @@ void JetsonVideoDecoder::CaptureLoop() { break; } - NvBufferParams parm; - ret = NvBufferGetParams(dst_dma_fd_, &parm); - void* src_data; uint8_t* dst_data; int dst_stride; @@ -358,13 +346,23 @@ void JetsonVideoDecoder::CaptureLoop() { } else { break; } - ret = NvBufferMemMap(dst_dma_fd_, i, NvBufferMem_Read, &src_data); - NvBufferMemSyncForCpu(dst_dma_fd_, i, &src_data); - for (uint32_t j = 0; j < parm.height[i]; j++) { - memcpy(dst_data + j * dst_stride, (char*)src_data + j * parm.pitch[i], - parm.width[i]); + + NvBufSurface* dst_surf = 0; + if (NvBufSurfaceFromFd(dst_dma_fd_, (void**)(&dst_surf)) == -1) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << "Failed to NvBufSurfaceFromFd"; + break; } - NvBufferMemUnMap(dst_dma_fd_, i, &src_data); + + ret = NvBufSurfaceMap(dst_surf, 0, i, NVBUF_MAP_READ); + NvBufSurfaceSyncForCpu(dst_surf, 0, i); + src_data = dst_surf->surfaceList[0].mappedAddr.addr[i]; + + NvBufSurfacePlaneParams params = dst_surf->surfaceList[0].planeParams; + for (uint32_t j = 0; j < params.height[i]; j++) { + memcpy(dst_data + j * dst_stride, + (char*)src_data + j * params.pitch[i], params.width[i]); + } + NvBufSurfaceUnMap(dst_surf, 0, i); } webrtc::VideoFrame decoded_image = @@ -405,20 +403,20 @@ int JetsonVideoDecoder::SetCapture() { << "x" << format.fmt.pix_mp.height; if (dst_dma_fd_ != -1) { - NvBufferDestroy(dst_dma_fd_); + NvBufSurf::NvDestroy(dst_dma_fd_); dst_dma_fd_ = -1; } - NvBufferCreateParams input_params = {0}; - input_params.payloadType = NvBufferPayload_SurfArray; - input_params.width = capture_crop_->c.width; - input_params.height = capture_crop_->c.height; - input_params.layout = NvBufferLayout_Pitch; - input_params.colorFormat = NvBufferColorFormat_YUV420; - input_params.nvbuf_tag = NvBufferTag_VIDEO_DEC; + NvBufSurf::NvCommonAllocateParams cParams; + cParams.width = capture_crop_->c.width; + cParams.height = capture_crop_->c.height; + cParams.layout = NVBUF_LAYOUT_PITCH; + cParams.colorFormat = NVBUF_COLOR_FORMAT_YUV420; + cParams.memtag = NvBufSurfaceTag_VIDEO_DEC; + cParams.memType = NVBUF_MEM_SURFACE_ARRAY; - ret = NvBufferCreateEx(&dst_dma_fd_, &input_params); - INIT_ERROR(ret == -1, "create dmabuf failed"); + ret = NvBufSurf::NvAllocate(&cParams, 1, &dst_dma_fd_); + INIT_ERROR(ret == -1, "failed to NvBufSurfaceAllocate"); decoder_->capture_plane.deinitPlane(); @@ -453,3 +451,5 @@ int JetsonVideoDecoder::SetCapture() { return WEBRTC_VIDEO_CODEC_OK; } + +} // namespace sora diff --git a/src/hwenc_jetson/jetson_video_encoder.cpp b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_video_encoder.cpp similarity index 82% rename from src/hwenc_jetson/jetson_video_encoder.cpp rename to src/sora-cpp-sdk/src/hwenc_jetson/jetson_video_encoder.cpp index 22c6ae74..9f5c66b8 100644 --- a/src/hwenc_jetson/jetson_video_encoder.cpp +++ b/src/sora-cpp-sdk/src/hwenc_jetson/jetson_video_encoder.cpp @@ -9,28 +9,34 @@ * */ -#include "jetson_video_encoder.h" +#include "sora/hwenc_jetson/jetson_video_encoder.h" #include #include // WebRTC #include +#include +#include +#include #include #include #include #include #include -#include -#include -#include + +// libyuv +#include +#include +#include // L4T Multimedia API #include #include -#include +#include -#include "jetson_buffer.h" +#include "jetson_util.h" +#include "sora/hwenc_jetson/jetson_buffer.h" #define H264HWENC_HEADER_DEBUG 0 #define INIT_ERROR(cond, desc) \ @@ -40,6 +46,36 @@ return WEBRTC_VIDEO_CODEC_ERROR; \ } +static std::string hex_dump(const uint8_t* buf, size_t len) { + std::stringstream ss; + + for (size_t i = 0; i < len; ++i) { + // 行の先頭にオフセットを表示 + if (i % 16 == 0) { + ss << std::setw(8) << std::setfill('0') << std::hex << i << ": "; + } + + // 値を16進数で表示 + ss << std::setw(2) << std::setfill('0') << std::hex << (int)buf[i] << " "; + + // 16バイトごとに改行 + if ((i + 1) % 16 == 0 || i == len - 1) { + ss << "\n"; + } + } + + return ss.str(); +} + +static void save_to_file(const std::string& filename, + const uint8_t* buf, + size_t size) { + std::ofstream file(filename, std::ios::binary); + file.write((const char*)buf, size); +} + +namespace sora { + JetsonVideoEncoder::JetsonVideoEncoder(const cricket::VideoCodec& codec) : callback_(nullptr), encoder_(nullptr), @@ -73,34 +109,12 @@ JetsonVideoEncoder::~JetsonVideoEncoder() { // int old_log_level; //}; -bool JetsonVideoEncoder::IsSupportedVP8() { - //SuppressErrors sup; - - auto encoder = NvVideoEncoder::createVideoEncoder("enc0"); - auto ret = encoder->setCapturePlaneFormat(V4L2_PIX_FMT_VP8, 1024, 768, - 2 * 1024 * 1024); - delete encoder; - - return ret >= 0; -} - -bool JetsonVideoEncoder::IsSupportedVP9() { - //SuppressErrors sup; - - auto encoder = NvVideoEncoder::createVideoEncoder("enc0"); - auto ret = encoder->setCapturePlaneFormat(V4L2_PIX_FMT_VP9, 1024, 768, - 2 * 1024 * 1024); - delete encoder; - - return ret >= 0; -} - -bool JetsonVideoEncoder::IsSupportedAV1() { +bool JetsonVideoEncoder::IsSupported(webrtc::VideoCodecType codec) { //SuppressErrors sup; auto encoder = NvVideoEncoder::createVideoEncoder("enc0"); - auto ret = encoder->setCapturePlaneFormat(V4L2_PIX_FMT_AV1, 1024, 768, - 2 * 1024 * 1024); + auto ret = encoder->setCapturePlaneFormat(VideoCodecToV4L2Format(codec), 1024, + 768, 2 * 1024 * 1024); delete encoder; return ret >= 0; @@ -124,6 +138,9 @@ int32_t JetsonVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, target_bitrate_bps_ = codec_settings->startBitrate * 1000; if (codec_settings->codecType == webrtc::kVideoCodecH264) { key_frame_interval_ = codec_settings->H264().keyFrameInterval; + } else if (codec_settings->codecType == webrtc::kVideoCodecH265) { + // key_frame_interval_ = codec_settings->H265().keyFrameInterval; + key_frame_interval_ = 3000; } else if (codec_settings->codecType == webrtc::kVideoCodecVP8) { key_frame_interval_ = codec_settings->VP8().keyFrameInterval; } else if (codec_settings->codecType == webrtc::kVideoCodecVP9) { @@ -150,6 +167,12 @@ int32_t JetsonVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, RTC_LOG(LS_INFO) << "InitEncode scalability_mode:" << (int)*scalability_mode; svc_controller_ = webrtc::CreateScalabilityStructure(*scalability_mode); + scalability_mode_ = *scalability_mode; + + // codec_settings->AV1() にはキーフレームの設定が無いけれども、 + // key_frame_interval_ 自体は何らかの値で初期化しておかないと + // 不定値になってしまうので、適当な値を入れておく + key_frame_interval_ = 3000; } framerate_ = codec_settings->maxFramerate; @@ -185,19 +208,9 @@ int32_t JetsonVideoEncoder::JetsonConfigure() { encoder_ = NvVideoEncoder::createVideoEncoder("enc0"); INIT_ERROR(!encoder_, "Failed to createVideoEncoder"); - if (codec_.codecType == webrtc::kVideoCodecH264) { - ret = encoder_->setCapturePlaneFormat(V4L2_PIX_FMT_H264, width_, height_, - 2 * 1024 * 1024); - } else if (codec_.codecType == webrtc::kVideoCodecVP8) { - ret = encoder_->setCapturePlaneFormat(V4L2_PIX_FMT_VP8, width_, height_, - 2 * 1024 * 1024); - } else if (codec_.codecType == webrtc::kVideoCodecVP9) { - ret = encoder_->setCapturePlaneFormat(V4L2_PIX_FMT_VP9, width_, height_, - 2 * 1024 * 1024); - } else if (codec_.codecType == webrtc::kVideoCodecAV1) { - ret = encoder_->setCapturePlaneFormat(V4L2_PIX_FMT_AV1, width_, height_, - 2 * 1024 * 1024); - } + ret = + encoder_->setCapturePlaneFormat(VideoCodecToV4L2Format(codec_.codecType), + width_, height_, 2 * 1024 * 1024); INIT_ERROR(ret < 0, "Failed to encoder setCapturePlaneFormat"); ret = encoder_->setOutputPlaneFormat(V4L2_PIX_FMT_YUV420M, width_, height_); @@ -222,6 +235,25 @@ int32_t JetsonVideoEncoder::JetsonConfigure() { // V4L2_ENC_HW_PRESET_ULTRAFAST が推奨値だけど MEDIUM でも Nano, AGX では OK // NX は V4L2_ENC_HW_PRESET_FAST でないとフレームレートがでない + ret = encoder_->setHWPresetType(V4L2_ENC_HW_PRESET_FAST); + INIT_ERROR(ret < 0, "Failed to setHWPresetType"); + } else if (codec_.codecType == webrtc::kVideoCodecH265) { + // H264 の設定を真似する + ret = encoder_->setProfile(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); + INIT_ERROR(ret < 0, "Failed to setProfile"); + + ret = encoder_->setLevel(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1); + INIT_ERROR(ret < 0, "Failed to setLevel"); + + ret = encoder_->setNumBFrames(0); + INIT_ERROR(ret < 0, "Failed to setNumBFrames"); + + ret = encoder_->setInsertSpsPpsAtIdrEnabled(true); + INIT_ERROR(ret < 0, "Failed to setInsertSpsPpsAtIdrEnabled"); + + ret = encoder_->setInsertVuiEnabled(true); + INIT_ERROR(ret < 0, "Failed to setInsertSpsPpsAtIdrEnabled"); + ret = encoder_->setHWPresetType(V4L2_ENC_HW_PRESET_FAST); INIT_ERROR(ret < 0, "Failed to setHWPresetType"); } else if (codec_.codecType == webrtc::kVideoCodecVP8) { @@ -513,6 +545,11 @@ webrtc::VideoEncoder::EncoderInfo JetsonVideoEncoder::GetEncoderInfo() const { static const int kHighH264QpThreshold = 40; info.scaling_settings = VideoEncoder::ScalingSettings(kLowH264QpThreshold, kHighH264QpThreshold); + } else if (codec_.codecType == webrtc::kVideoCodecH265) { + static const int kLowH265QpThreshold = 34; + static const int kHighH265QpThreshold = 40; + info.scaling_settings = VideoEncoder::ScalingSettings(kLowH265QpThreshold, + kHighH265QpThreshold); } else if (codec_.codecType == webrtc::kVideoCodecVP8) { static const int kLowVp8QpThreshold = 29; static const int kHighVp8QpThreshold = 95; @@ -746,11 +783,20 @@ int32_t JetsonVideoEncoder::Encode( input_frame.timestamp_us() % rtc::kNumMicrosecsPerSec; for (int i = 0; i < MAX_PLANES; i++) { - if (NvBufferMemSyncForDevice(buffer->planes[i].fd, i, - (void**)&buffer->planes[i].data) < 0) { - RTC_LOG(LS_ERROR) << "Failed to NvBufferMemSyncForDevice"; + NvBufSurface* surf = 0; + if (NvBufSurfaceFromFd(buffer->planes[i].fd, (void**)(&surf)) == -1) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << "Failed to NvBufSurfaceFromFd"; return WEBRTC_VIDEO_CODEC_ERROR; } + + if (NvBufSurfaceSyncForDevice(surf, 0, i) == -1) { + RTC_LOG(LS_ERROR) << "Failed to NvBufSurfaceSyncForDevice"; + return WEBRTC_VIDEO_CODEC_ERROR; + } + + // ここで NvBufSurfaceDestroy が必要かなと思ったが、以下のサンプル・コードを確認したところ不要そうだった + // 参照: jetson_multimedia_api/samples/01_video_encode/video_encode_main.cpp + // NvBufSurfaceDestroy(surf); } if (encoder_->output_plane.qBuffer(v4l2_buf, nullptr) < 0) { @@ -774,7 +820,7 @@ int32_t JetsonVideoEncoder::SendFrame( return WEBRTC_VIDEO_CODEC_UNINITIALIZED; } - encoded_image_.SetTimestamp(params->timestamp_rtp); + encoded_image_.SetRtpTimestamp(params->timestamp_rtp); encoded_image_.SetColorSpace(params->color_space); encoded_image_._encodedWidth = params->width; encoded_image_._encodedHeight = params->height; @@ -783,9 +829,9 @@ int32_t JetsonVideoEncoder::SendFrame( encoded_image_.rotation_ = params->rotation; encoded_image_.qp_ = enc_metadata->AvgQP; if (enc_metadata->KeyFrame) { - encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameKey; + encoded_image_.SetFrameType(webrtc::VideoFrameType::kVideoFrameKey); } else { - encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameDelta; + encoded_image_.SetFrameType(webrtc::VideoFrameType::kVideoFrameDelta); } webrtc::CodecSpecificInfo codec_specific; @@ -797,6 +843,11 @@ int32_t JetsonVideoEncoder::SendFrame( codec_specific.codecSpecific.H264.packetization_mode = webrtc::H264PacketizationMode::NonInterleaved; + } else if (codec_.codecType == webrtc::kVideoCodecH265) { + auto encoded_image_buffer = + webrtc::EncodedImageBuffer::Create(buffer, size); + encoded_image_.SetEncodedData(encoded_image_buffer); + } else if (codec_.codecType == webrtc::kVideoCodecAV1 || codec_.codecType == webrtc::kVideoCodecVP9 || codec_.codecType == webrtc::kVideoCodecVP8) { @@ -809,8 +860,47 @@ int32_t JetsonVideoEncoder::SendFrame( buffer += 12; size -= 12; - auto encoded_image_buffer = - webrtc::EncodedImageBuffer::Create(buffer, size); + rtc::scoped_refptr encoded_image_buffer; + + if (codec_.codecType == webrtc::kVideoCodecAV1) { + // JetPack 5.1.1 以降、AV1 のエンコードフレームにシーケンスヘッダー(OBU_SEQUENCE_HEADER)が含まれなくなってしまった。 + // キーフレームには必ずシーケンスヘッダーを設定しておかないと、途中から受信したデコーダーでデコードができなくなってしまう。 + // そのため、初回のシーケンスヘッダーを保存しておき、キーフレームの前に挿入することで対応する。 + + // buffer の最初の 2 バイトは 0x12 0x00 で、これは OBU_TEMPORAL_DELIMITER なのでこれは無視して、その次の OBU を見る + if (buffer[2] == 0x0a) { + // 0x0a は OBU_SEQUENCE_HEADER なので、この OBU を保存しておく + // obu_size は本当は LEB128 だけど、128 バイト以上になることはなさそうなので、そのまま 1 バイトで取得する + int obu_size = buffer[3]; + obu_seq_header_.resize(obu_size + 2); + memcpy(obu_seq_header_.data(), buffer + 2, obu_size + 2); + } + + // キーフレームとしてマークされているのにシーケンスヘッダーが入っていない場合、 + // フレームの前にシーケンスヘッダーを入れる + if (enc_metadata->KeyFrame && buffer[2] != 0x0a) { + std::vector new_buffer; + new_buffer.resize(obu_seq_header_.size() + size); + uint8_t* p = new_buffer.data(); + // OBU_TEMPORAL_DELIMITER + memcpy(p, buffer, 2); + p += 2; + // OBU_SEQUENCE_HEADER + memcpy(p, obu_seq_header_.data(), obu_seq_header_.size()); + p += obu_seq_header_.size(); + // OBU_FRAME + memcpy(p, buffer + 2, size - 2); + + // RTC_LOG(LS_ERROR) << "\n" << hex_dump(new_buffer.data(), 64); + // save_to_file("keyframe2.obu", new_buffer.data(), new_buffer.size()); + encoded_image_buffer = webrtc::EncodedImageBuffer::Create( + new_buffer.data(), new_buffer.size()); + } else { + encoded_image_buffer = webrtc::EncodedImageBuffer::Create(buffer, size); + } + } else { + encoded_image_buffer = webrtc::EncodedImageBuffer::Create(buffer, size); + } encoded_image_.SetEncodedData(encoded_image_buffer); if (codec_.codecType == webrtc::kVideoCodecVP8) { @@ -844,17 +934,12 @@ int32_t JetsonVideoEncoder::SendFrame( codec_specific.codecSpecific.VP9.gof.CopyGofInfoVP9(gof_); } } else if (codec_.codecType == webrtc::kVideoCodecAV1) { - bool is_key = buffer[2] == 0x0a; - // v4l2_ctrl_videoenc_outputbuf_metadata.KeyFrame が効いていない - // キーフレームの時には OBU_SEQUENCE_HEADER が入っているために 0x0a になるためこれを使う - // キーフレームではない時には OBU_FRAME が入っていて 0x32 になっている - if (is_key) { - encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameKey; - } - + bool is_key = + encoded_image_._frameType == webrtc::VideoFrameType::kVideoFrameKey; std::vector layer_frames = svc_controller_->NextFrameConfig(is_key); codec_specific.end_of_picture = true; + codec_specific.scalability_mode = scalability_mode_; codec_specific.generic_frame_info = svc_controller_->OnEncodeDone(layer_frames[0]); if (is_key && codec_specific.generic_frame_info) { @@ -880,3 +965,5 @@ int32_t JetsonVideoEncoder::SendFrame( bitrate_adjuster_->Update(size); return WEBRTC_VIDEO_CODEC_OK; } + +} // namespace sora diff --git a/src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp similarity index 81% rename from src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp rename to src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp index 4eb1195a..da2e5849 100644 --- a/src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp +++ b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_decoder_cuda.cpp @@ -1,15 +1,19 @@ -#include "nvcodec_decoder_cuda.h" +#include "sora/hwenc_nvcodec/nvcodec_decoder_cuda.h" -// NvCodec #include -#include "cuda/cuda_context_cuda.h" +#include "../cuda_context_cuda.h" +#include "sora/dyn/cuda.h" + +namespace sora { static cudaVideoCodec ToCudaVideoCodec(CudaVideoCodec codec) { - return codec == CudaVideoCodec::H264 ? cudaVideoCodec_H264 - : codec == CudaVideoCodec::VP8 ? cudaVideoCodec_VP8 - : codec == CudaVideoCodec::VP9 ? cudaVideoCodec_VP9 - : cudaVideoCodec_JPEG; + return codec == CudaVideoCodec::H264 ? cudaVideoCodec_H264 + : codec == CudaVideoCodec::H265 ? cudaVideoCodec_HEVC + : codec == CudaVideoCodec::VP8 ? cudaVideoCodec_VP8 + : codec == CudaVideoCodec::VP9 ? cudaVideoCodec_VP9 + : codec == CudaVideoCodec::AV1 ? cudaVideoCodec_AV1 + : cudaVideoCodec_JPEG; } #define CUDA_DRVAPI_CALL(call) \ @@ -34,8 +38,11 @@ NvCodecDecoderCuda::NvCodecDecoderCuda(std::shared_ptr ctx, true, nullptr, nullptr, + false, + 3840, 3840, - 3840)) { + 1000, + true)) { // このコーデックでデコード可能かどうかを調べる CUVIDDECODECAPS decodecaps; memset(&decodecaps, 0, sizeof(decodecaps)); @@ -90,4 +97,6 @@ int NvCodecDecoderCuda::GetDeviceFramePitch() const { int NvCodecDecoderCuda::setReconfigParams() { return GetDecoder(impl_)->setReconfigParams(nullptr, nullptr); -} \ No newline at end of file +} + +} // namespace sora diff --git a/src/hwenc_nvcodec/nvcodec_v4l2_capturer.cpp b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_v4l2_capturer.cpp similarity index 88% rename from src/hwenc_nvcodec/nvcodec_v4l2_capturer.cpp rename to src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_v4l2_capturer.cpp index faedf5dc..ea3417b2 100644 --- a/src/hwenc_nvcodec/nvcodec_v4l2_capturer.cpp +++ b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_v4l2_capturer.cpp @@ -1,4 +1,4 @@ -#include "nvcodec_v4l2_capturer.h" +#include "sora/hwenc_nvcodec/nvcodec_v4l2_capturer.h" // Linux #include @@ -8,8 +8,14 @@ #include #include +namespace sora { + +NvCodecV4L2Capturer::NvCodecV4L2Capturer( + const NvCodecV4L2CapturerConfig& config) + : V4L2VideoCapturer(config) {} + rtc::scoped_refptr NvCodecV4L2Capturer::Create( - NvCodecV4L2CapturerConfig config) { + const NvCodecV4L2CapturerConfig& config) { rtc::scoped_refptr capturer; std::unique_ptr device_info( webrtc::VideoCaptureFactory::CreateDeviceInfo()); @@ -31,17 +37,9 @@ rtc::scoped_refptr NvCodecV4L2Capturer::Create( return nullptr; } -NvCodecV4L2Capturer::NvCodecV4L2Capturer( - const NvCodecV4L2CapturerConfig& config) - : V4L2VideoCapturer(config) {} - -bool NvCodecV4L2Capturer::UseNativeBuffer() { - return true; -} - rtc::scoped_refptr NvCodecV4L2Capturer::Create( webrtc::VideoCaptureModule::DeviceInfo* device_info, - NvCodecV4L2CapturerConfig config, + const NvCodecV4L2CapturerConfig& config, size_t capture_device_index) { char device_name[256]; char unique_name[256]; @@ -52,6 +50,11 @@ rtc::scoped_refptr NvCodecV4L2Capturer::Create( RTC_LOG(LS_WARNING) << "Failed to GetDeviceName"; return nullptr; } + // config.video_device が指定されている場合は、デバイス名かユニーク名と一致する必要がある + if (!(config.video_device.empty() || config.video_device == device_name || + config.video_device == unique_name)) { + return nullptr; + } rtc::scoped_refptr v4l2_capturer = rtc::make_ref_counted(config); @@ -59,7 +62,7 @@ rtc::scoped_refptr NvCodecV4L2Capturer::Create( v4l2_capturer->decoder_.reset( new NvCodecDecoderCuda(config.cuda_context, CudaVideoCodec::JPEG)); - if (v4l2_capturer->Init((const char*)&unique_name, config.video_device) < 0) { + if (v4l2_capturer->Init((const char*)&unique_name) < 0) { RTC_LOG(LS_WARNING) << "Failed to create NvCodecV4L2Capturer(" << unique_name << ")"; return nullptr; @@ -115,4 +118,6 @@ void NvCodecV4L2Capturer::OnCaptured(uint8_t* data, uint32_t bytesused) { .set_rotation(webrtc::kVideoRotation_0) .build()); } -} \ No newline at end of file +} + +} // namespace sora diff --git a/src/hwenc_nvcodec/nvcodec_video_decoder.cpp b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_decoder.cpp similarity index 74% rename from src/hwenc_nvcodec/nvcodec_video_decoder.cpp rename to src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_decoder.cpp index f4b08129..cd15b418 100644 --- a/src/hwenc_nvcodec/nvcodec_video_decoder.cpp +++ b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_decoder.cpp @@ -1,4 +1,4 @@ -#include "nvcodec_video_decoder.h" +#include "sora/hwenc_nvcodec/nvcodec_video_decoder.h" // WebRTC #include @@ -7,8 +7,13 @@ #include #include -#include "dyn/cuda.h" -#include "dyn/nvcuvid.h" +// NvCodec +#include + +#include "sora/dyn/cuda.h" +#include "sora/dyn/nvcuvid.h" + +namespace sora { NvCodecVideoDecoder::NvCodecVideoDecoder(std::shared_ptr ctx, CudaVideoCodec codec) @@ -21,7 +26,12 @@ NvCodecVideoDecoder::~NvCodecVideoDecoder() { Release(); } -bool NvCodecVideoDecoder::IsSupported(CudaVideoCodec codec) { +bool NvCodecVideoDecoder::IsSupported(std::shared_ptr context, + CudaVideoCodec codec) { + if (context == nullptr) { + return false; + } + // CUDA 周りのライブラリがロードできるか確認する if (!dyn::DynModule::Instance().IsLoadable(dyn::CUDA_SO)) { return false; @@ -29,9 +39,17 @@ bool NvCodecVideoDecoder::IsSupported(CudaVideoCodec codec) { if (!dyn::DynModule::Instance().IsLoadable(dyn::NVCUVID_SO)) { return false; } + // 関数が存在するかチェックする + if (dyn::DynModule::Instance().GetFunc(dyn::CUDA_SO, "cuDeviceGetName") == + nullptr) { + return false; + } + if (dyn::DynModule::Instance().GetFunc(dyn::NVCUVID_SO, + "cuvidMapVideoFrame") == nullptr) { + return false; + } try { - auto context = CudaContext::Create(); auto p = new NvCodecDecoderCuda(context, codec); delete p; return true; @@ -58,8 +76,13 @@ int32_t NvCodecVideoDecoder::Decode(const webrtc::EncodedImage& input_image, } uint8_t** frames = nullptr; - int frame_count = - decoder_->Decode(input_image.data(), (int)input_image.size()); + int frame_count; + try { + frame_count = decoder_->Decode(input_image.data(), (int)input_image.size()); + } catch (NVDECException& e) { + RTC_LOG(LS_ERROR) << e.getErrorString(); + return WEBRTC_VIDEO_CODEC_ERROR; + } if (frame_count == 0) { return WEBRTC_VIDEO_CODEC_OK; } @@ -70,10 +93,10 @@ int32_t NvCodecVideoDecoder::Decode(const webrtc::EncodedImage& input_image, output_info_ = true; } - uint32_t pts = input_image.Timestamp(); + uint32_t pts = input_image.RtpTimestamp(); for (int i = 0; i < frame_count; i++) { - const auto* frame = decoder_->GetFrame(); + auto* frame = decoder_->GetLockedFrame(); // NV12 から I420 に変換 rtc::scoped_refptr i420_buffer = buffer_pool_.CreateI420Buffer(decoder_->GetWidth(), @@ -93,9 +116,10 @@ int32_t NvCodecVideoDecoder::Decode(const webrtc::EncodedImage& input_image, decode_complete_callback_->Decoded(decoded_image, absl::nullopt, absl::nullopt); - // 次のフレームで縦横サイズが変わったときに追従するためのマジックコード - decoder_->setReconfigParams(); + decoder_->UnlockFrame(frame); } + // 次のフレームで縦横サイズが変わったときに追従するためのマジックコード + decoder_->setReconfigParams(); return WEBRTC_VIDEO_CODEC_OK; } @@ -125,3 +149,5 @@ bool NvCodecVideoDecoder::InitNvCodec() { void NvCodecVideoDecoder::ReleaseNvCodec() { decoder_.reset(); } + +} // namespace sora diff --git a/src/hwenc_nvcodec/nvcodec_h264_encoder.cpp b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder.cpp similarity index 52% rename from src/hwenc_nvcodec/nvcodec_h264_encoder.cpp rename to src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder.cpp index 442021ad..3ac6a6ad 100644 --- a/src/hwenc_nvcodec/nvcodec_h264_encoder.cpp +++ b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder.cpp @@ -1,478 +1,672 @@ -#include "nvcodec_h264_encoder.h" - -// WebRTC -#include -#include -#include -#include - -#include "rtc/native_buffer.h" - -#ifdef __linux__ -#include "dyn/cuda.h" -#include "dyn/nvcuvid.h" -#endif - -const int kLowH264QpThreshold = 34; -const int kHighH264QpThreshold = 40; - -struct nal_entry { - size_t offset; - size_t size; -}; - -#ifdef _WIN32 -using Microsoft::WRL::ComPtr; -#endif - -#ifdef __linux__ -NvCodecH264Encoder::NvCodecH264Encoder(const cricket::VideoCodec& codec, - std::shared_ptr cc) - : cuda_context_(cc), -#else -NvCodecH264Encoder::NvCodecH264Encoder(const cricket::VideoCodec& codec) - : -#endif - bitrate_adjuster_(0.5, 0.95) { -#ifdef _WIN32 - ComPtr idxgi_factory; - RTC_CHECK(!FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), - (void**)idxgi_factory.GetAddressOf()))); - ComPtr idxgi_adapter; - RTC_CHECK( - !FAILED(idxgi_factory->EnumAdapters(0, idxgi_adapter.GetAddressOf()))); - RTC_CHECK(!FAILED(D3D11CreateDevice( - idxgi_adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0, - D3D11_SDK_VERSION, id3d11_device_.GetAddressOf(), NULL, - id3d11_context_.GetAddressOf()))); - - // 以下デバイス名を取得するだけの処理 - DXGI_ADAPTER_DESC adapter_desc; - idxgi_adapter->GetDesc(&adapter_desc); - char szDesc[80]; - size_t result = 0; - wcstombs_s(&result, szDesc, adapter_desc.Description, sizeof(szDesc)); - RTC_LOG(LS_INFO) << __FUNCTION__ << "GPU in use: " << szDesc; -#endif -#ifdef __linux__ - cuda_.reset(new NvCodecH264EncoderCuda(cuda_context_)); -#endif -} - -NvCodecH264Encoder::~NvCodecH264Encoder() {} - -bool NvCodecH264Encoder::IsSupported() { - try { - NvEncoder::TryLoadNvEncApi(); - - // Linux の場合、cuda と nvcuvid のロードも必要なのでチェックする -#ifdef __linux__ - if (!dyn::DynModule::Instance().IsLoadable(dyn::CUDA_SO)) { - return false; - } - if (!dyn::DynModule::Instance().IsLoadable(dyn::NVCUVID_SO)) { - return false; - } -#endif - return true; - } catch (const NVENCException& e) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); - return false; - } -} - -int32_t NvCodecH264Encoder::InitEncode(const webrtc::VideoCodec* codec_settings, - int32_t number_of_cores, - size_t max_payload_size) { - RTC_DCHECK(codec_settings); - RTC_DCHECK_EQ(codec_settings->codecType, webrtc::kVideoCodecH264); - - int32_t release_ret = Release(); - if (release_ret != WEBRTC_VIDEO_CODEC_OK) { - return release_ret; - } - - width_ = codec_settings->width; - height_ = codec_settings->height; - target_bitrate_bps_ = codec_settings->startBitrate * 1000; - max_bitrate_bps_ = codec_settings->maxBitrate * 1000; - bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); - framerate_ = codec_settings->maxFramerate; - mode_ = codec_settings->mode; - - RTC_LOG(LS_INFO) << "InitEncode " << target_bitrate_bps_ << "bit/sec"; - - return InitNvEnc(); -} - -int32_t NvCodecH264Encoder::RegisterEncodeCompleteCallback( - webrtc::EncodedImageCallback* callback) { - std::lock_guard lock(mutex_); - callback_ = callback; - return WEBRTC_VIDEO_CODEC_OK; -} - -int32_t NvCodecH264Encoder::Release() { - return ReleaseNvEnc(); -} - -int32_t NvCodecH264Encoder::Encode( - const webrtc::VideoFrame& frame, - const std::vector* frame_types) { - //RTC_LOG(LS_ERROR) << __FUNCTION__ << " Start"; - if (!nv_encoder_) { - return WEBRTC_VIDEO_CODEC_UNINITIALIZED; - } - if (!callback_) { - RTC_LOG(LS_WARNING) - << "InitEncode() has been called, but a callback function " - << "has not been set with RegisterEncodeCompleteCallback()"; - return WEBRTC_VIDEO_CODEC_UNINITIALIZED; - } - -#if defined(__linux__) - if (frame.video_frame_buffer()->type() == - webrtc::VideoFrameBuffer::Type::kNV12) { - if (!use_native_) { - ReleaseNvEnc(); - use_native_ = true; - InitNvEnc(); - } - } else { - if (use_native_) { - ReleaseNvEnc(); - use_native_ = false; - InitNvEnc(); - } - } -#else - if (frame.video_frame_buffer()->type() == - webrtc::VideoFrameBuffer::Type::kNative) { - if (!use_native_) { - ReleaseNvEnc(); - use_native_ = true; - InitNvEnc(); - } - } else { - if (use_native_) { - ReleaseNvEnc(); - use_native_ = false; - InitNvEnc(); - } - } -#endif - - bool send_key_frame = false; - - if (reconfigure_needed_) { - NV_ENC_RECONFIGURE_PARAMS reconfigure_params = { - NV_ENC_RECONFIGURE_PARAMS_VER}; - NV_ENC_CONFIG encode_config = {NV_ENC_CONFIG_VER}; - reconfigure_params.reInitEncodeParams.encodeConfig = &encode_config; - nv_encoder_->GetInitializeParams(&reconfigure_params.reInitEncodeParams); - - reconfigure_params.reInitEncodeParams.frameRateNum = framerate_; - - encode_config.rcParams.averageBitRate = - bitrate_adjuster_.GetAdjustedBitrateBps(); - encode_config.rcParams.maxBitRate = max_bitrate_bps_; - encode_config.rcParams.vbvBufferSize = - encode_config.rcParams.averageBitRate * 1 / framerate_; - encode_config.rcParams.vbvInitialDelay = - encode_config.rcParams.vbvBufferSize; - try { - //RTC_LOG(LS_ERROR) << __FUNCTION__ << " Reconfigure"; - nv_encoder_->Reconfigure(&reconfigure_params); - } catch (const NVENCException& e) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); - return WEBRTC_VIDEO_CODEC_ERROR; - } - - reconfigure_needed_ = false; - } - - if (frame_types != nullptr) { - // We only support a single stream. - RTC_DCHECK_EQ(frame_types->size(), static_cast(1)); - // Skip frame? - if ((*frame_types)[0] == webrtc::VideoFrameType::kEmptyFrame) { - return WEBRTC_VIDEO_CODEC_OK; - } - // Force key frame? - send_key_frame = - (*frame_types)[0] == webrtc::VideoFrameType::kVideoFrameKey; - } - - NV_ENC_PIC_PARAMS pic_params = {NV_ENC_PIC_PARAMS_VER}; - pic_params.encodePicFlags = 0; - if (send_key_frame) { - pic_params.encodePicFlags = - NV_ENC_PIC_FLAG_FORCEINTRA | NV_ENC_PIC_FLAG_FORCEIDR; - } - pic_params.inputWidth = width_; - pic_params.inputHeight = height_; - - v_packet_.clear(); - -#ifdef _WIN32 - const NvEncInputFrame* input_frame = nv_encoder_->GetNextInputFrame(); - D3D11_MAPPED_SUBRESOURCE map; - id3d11_context_->Map(id3d11_texture_.Get(), D3D11CalcSubresource(0, 0, 1), - D3D11_MAP_WRITE, 0, &map); - if (use_native_) { - const NativeBuffer* frame_buffer = - dynamic_cast(frame.video_frame_buffer().get()); - for (int y = 0; y < frame_buffer->height(); y++) { - memcpy((uint8_t*)map.pData + y * map.RowPitch, - frame_buffer->Data() + frame_buffer->RawWidth() * y, - frame_buffer->RawWidth()); - } - } else { - rtc::scoped_refptr frame_buffer = - frame.video_frame_buffer()->ToI420(); - libyuv::I420ToNV12( - frame_buffer->DataY(), frame_buffer->StrideY(), frame_buffer->DataU(), - frame_buffer->StrideU(), frame_buffer->DataV(), frame_buffer->StrideV(), - (uint8_t*)map.pData, map.RowPitch, - ((uint8_t*)map.pData + height_ * map.RowPitch), map.RowPitch, - frame_buffer->width(), frame_buffer->height()); - } - id3d11_context_->Unmap(id3d11_texture_.Get(), D3D11CalcSubresource(0, 0, 1)); - ID3D11Texture2D* nv11_texture = - reinterpret_cast(input_frame->inputPtr); - id3d11_context_->CopyResource(nv11_texture, id3d11_texture_.Get()); -#endif -#ifdef __linux__ - - //RTC_LOG(LS_INFO) << "type=" - // << VideoFrameBufferTypeToString( - // frame.video_frame_buffer()->type()) - // << " width_=" << width_ << " height_=" << height_ - // << " frame_width=" << frame.video_frame_buffer()->width() - // << " frame_height=" << frame.video_frame_buffer()->height(); - - if (frame.video_frame_buffer()->type() == - webrtc::VideoFrameBuffer::Type::kNV12) { - webrtc::NV12Buffer* buffer = - static_cast(frame.video_frame_buffer().get()); - try { - cuda_->Copy(nv_encoder_.get(), buffer->DataY(), width_, height_); - } catch (const NVENCException& e) { - RTC_LOG(LS_ERROR) << e.what(); - return WEBRTC_VIDEO_CODEC_ERROR; - } - } else { - rtc::scoped_refptr frame_buffer = - frame.video_frame_buffer()->ToI420(); - cuda_->Copy(nv_encoder_.get(), frame_buffer->DataY(), frame_buffer->width(), - frame_buffer->height()); - } -#endif - - try { - nv_encoder_->EncodeFrame(v_packet_, &pic_params); - } catch (const NVENCException& e) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); - return WEBRTC_VIDEO_CODEC_ERROR; - } - - for (std::vector& packet : v_packet_) { - auto encoded_image_buffer = - webrtc::EncodedImageBuffer::Create(packet.data(), packet.size()); - encoded_image_.SetEncodedData(encoded_image_buffer); - encoded_image_._encodedWidth = width_; - encoded_image_._encodedHeight = height_; - encoded_image_.content_type_ = - (mode_ == webrtc::VideoCodecMode::kScreensharing) - ? webrtc::VideoContentType::SCREENSHARE - : webrtc::VideoContentType::UNSPECIFIED; - encoded_image_.timing_.flags = webrtc::VideoSendTiming::kInvalid; - encoded_image_.SetTimestamp(frame.timestamp()); - encoded_image_.ntp_time_ms_ = frame.ntp_time_ms(); - encoded_image_.capture_time_ms_ = frame.render_time_ms(); - encoded_image_.rotation_ = frame.rotation(); - encoded_image_.SetColorSpace(frame.color_space()); - encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameDelta; - - uint8_t zero_count = 0; - size_t nal_start_idx = 0; - for (size_t i = 0; i < packet.size(); i++) { - uint8_t data = packet.data()[i]; - if ((i != 0) && (i == nal_start_idx)) { - if ((data & 0x1F) == 0x05) { - encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameKey; - } - } - if (data == 0x01 && zero_count >= 2) { - nal_start_idx = i + 1; - } - if (data == 0x00) { - zero_count++; - } else { - zero_count = 0; - } - } - - webrtc::CodecSpecificInfo codec_specific; - codec_specific.codecType = webrtc::kVideoCodecH264; - codec_specific.codecSpecific.H264.packetization_mode = - webrtc::H264PacketizationMode::NonInterleaved; - - h264_bitstream_parser_.ParseBitstream(encoded_image_); - encoded_image_.qp_ = h264_bitstream_parser_.GetLastSliceQp().value_or(-1); - - webrtc::EncodedImageCallback::Result result = - callback_->OnEncodedImage(encoded_image_, &codec_specific); - if (result.error != webrtc::EncodedImageCallback::Result::OK) { - RTC_LOG(LS_ERROR) << __FUNCTION__ - << " OnEncodedImage failed error:" << result.error; - return WEBRTC_VIDEO_CODEC_ERROR; - } - bitrate_adjuster_.Update(packet.size()); - } - - return WEBRTC_VIDEO_CODEC_OK; -} - -void NvCodecH264Encoder::SetRates( - const webrtc::VideoEncoder::RateControlParameters& parameters) { - if (!nv_encoder_) { - RTC_LOG(LS_WARNING) << "SetRates() while uninitialized."; - return; - } - - if (parameters.framerate_fps < 1.0) { - RTC_LOG(LS_WARNING) << "Invalid frame rate: " << parameters.framerate_fps; - return; - } - - uint32_t new_framerate = (uint32_t)parameters.framerate_fps; - uint32_t new_bitrate = parameters.bitrate.get_sum_bps(); - RTC_LOG(LS_INFO) << __FUNCTION__ << " framerate_:" << framerate_ - << " new_framerate: " << new_framerate - << " target_bitrate_bps_:" << target_bitrate_bps_ - << " new_bitrate:" << new_bitrate - << " max_bitrate_bps_:" << max_bitrate_bps_; - framerate_ = new_framerate; - target_bitrate_bps_ = new_bitrate; - bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); - reconfigure_needed_ = true; -} - -webrtc::VideoEncoder::EncoderInfo NvCodecH264Encoder::GetEncoderInfo() const { - webrtc::VideoEncoder::EncoderInfo info; - info.supports_native_handle = true; - info.implementation_name = "NvCodec H264"; - info.scaling_settings = webrtc::VideoEncoder::ScalingSettings( - kLowH264QpThreshold, kHighH264QpThreshold); - return info; -} - -int32_t NvCodecH264Encoder::InitNvEnc() { -#ifdef _WIN32 - DXGI_FORMAT dxgi_format = DXGI_FORMAT_NV12; - NV_ENC_BUFFER_FORMAT nvenc_format = NV_ENC_BUFFER_FORMAT_NV12; - if (use_native_) { - dxgi_format = DXGI_FORMAT_B8G8R8A8_UNORM; - nvenc_format = NV_ENC_BUFFER_FORMAT_ARGB; - } - D3D11_TEXTURE2D_DESC desc; - ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC)); - desc.Width = width_; - desc.Height = height_; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = dxgi_format; - desc.SampleDesc.Count = 1; - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - id3d11_device_->CreateTexture2D(&desc, NULL, id3d11_texture_.GetAddressOf()); - - // Driver が古いとかに気づくのはココ - try { - nv_encoder_.reset(new NvEncoderD3D11(id3d11_device_.Get(), width_, height_, - nvenc_format)); - } catch (const NVENCException& e) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); - return WEBRTC_VIDEO_CODEC_ERROR; - } -#endif - -#ifdef __linux__ - try { - nv_encoder_.reset(cuda_->CreateNvEncoder(width_, height_, use_native_)); - } catch (const NVENCException& e) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); - return WEBRTC_VIDEO_CODEC_ERROR; - } -#endif - - initialize_params_ = {NV_ENC_INITIALIZE_PARAMS_VER}; - NV_ENC_CONFIG encode_config = {NV_ENC_CONFIG_VER}; - initialize_params_.encodeConfig = &encode_config; - try { - nv_encoder_->CreateDefaultEncoderParams( - &initialize_params_, NV_ENC_CODEC_H264_GUID, NV_ENC_PRESET_P3_GUID, - NV_ENC_TUNING_INFO_LOW_LATENCY); - - //initialize_params_.enablePTD = 1; - initialize_params_.frameRateDen = 1; - initialize_params_.frameRateNum = framerate_; - initialize_params_.maxEncodeWidth = width_; - initialize_params_.maxEncodeHeight = height_; - - //encode_config.profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID; - //encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ; - encode_config.rcParams.averageBitRate = target_bitrate_bps_; - encode_config.rcParams.maxBitRate = max_bitrate_bps_; - - encode_config.rcParams.disableBadapt = 1; - encode_config.rcParams.vbvBufferSize = - encode_config.rcParams.averageBitRate * - initialize_params_.frameRateDen / initialize_params_.frameRateNum; - encode_config.rcParams.vbvInitialDelay = - encode_config.rcParams.vbvBufferSize; - encode_config.gopLength = NVENC_INFINITE_GOPLENGTH; - encode_config.frameIntervalP = 1; - encode_config.rcParams.enableAQ = 1; - - //encode_config.encodeCodecConfig.h264Config.outputAUD = 1; - //encode_config.encodeCodecConfig.h264Config.level = NV_ENC_LEVEL_H264_31; - //encode_config.encodeCodecConfig.h264Config.entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC; - encode_config.encodeCodecConfig.h264Config.idrPeriod = - NVENC_INFINITE_GOPLENGTH; - encode_config.encodeCodecConfig.h264Config.repeatSPSPPS = 1; - encode_config.encodeCodecConfig.h264Config.sliceMode = 0; - encode_config.encodeCodecConfig.h264Config.sliceModeData = 0; - - nv_encoder_->CreateEncoder(&initialize_params_); - - RTC_LOG(LS_INFO) << __FUNCTION__ << " framerate_:" << framerate_ - << " bitrate_bps_:" << target_bitrate_bps_ - << " maxBitRate:" << encode_config.rcParams.maxBitRate; - } catch (const NVENCException& e) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); - return WEBRTC_VIDEO_CODEC_ERROR; - } - - reconfigure_needed_ = false; - - return WEBRTC_VIDEO_CODEC_OK; -} - -int32_t NvCodecH264Encoder::ReleaseNvEnc() { - if (nv_encoder_) { - try { - nv_encoder_->EndEncode(v_packet_); - nv_encoder_->DestroyEncoder(); - } catch (const NVENCException& e) { - RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); - } - nv_encoder_ = nullptr; -#ifdef _WIN32 - id3d11_texture_.Reset(); -#endif - } - return WEBRTC_VIDEO_CODEC_OK; -} +#include "sora/fix_cuda_noinline_macro_error.h" + +#include "sora/hwenc_nvcodec/nvcodec_video_encoder.h" + +#ifdef _WIN32 +#include +#include +#endif + +#include +#include +#include +#include + +// WebRTC +#include +#include +#include +#include +#include +#include +#include +#include + +// libyuv +#include + +// NvCodec +#ifdef _WIN32 +#include +#endif +#ifdef __linux__ +#include "nvcodec_video_encoder_cuda.h" +#endif + +#ifdef __linux__ +#include "sora/dyn/cuda.h" +#include "sora/dyn/nvcuvid.h" +#endif + +namespace sora { + +const int kLowH264QpThreshold = 34; +const int kHighH264QpThreshold = 40; + +struct nal_entry { + size_t offset; + size_t size; +}; + +#ifdef _WIN32 +using Microsoft::WRL::ComPtr; +#endif + +class NvCodecVideoEncoderImpl : public NvCodecVideoEncoder { + public: + NvCodecVideoEncoderImpl(std::shared_ptr cuda_context, + CudaVideoCodec codec); + ~NvCodecVideoEncoderImpl() override; + + static bool IsSupported(std::shared_ptr cuda_context, + CudaVideoCodec codec); + + int32_t InitEncode(const webrtc::VideoCodec* codec_settings, + int32_t number_of_cores, + size_t max_payload_size) override; + int32_t RegisterEncodeCompleteCallback( + webrtc::EncodedImageCallback* callback) override; + int32_t Release() override; + int32_t Encode( + const webrtc::VideoFrame& frame, + const std::vector* frame_types) override; + void SetRates( + const webrtc::VideoEncoder::RateControlParameters& parameters) override; + webrtc::VideoEncoder::EncoderInfo GetEncoderInfo() const override; + + static std::unique_ptr CreateEncoder( + CudaVideoCodec codec, + int width, + int height, + int framerate, + int target_bitrate_bps, + int max_bitrate_bps +#ifdef _WIN32 + , + ID3D11Device* id3d11_device, + ID3D11Texture2D** out_id3d11_texture +#endif +#ifdef __linux__ + , + NvCodecVideoEncoderCuda* cuda, + bool is_nv12 +#endif + ); + + private: + std::mutex mutex_; + webrtc::EncodedImageCallback* callback_ = nullptr; + webrtc::BitrateAdjuster bitrate_adjuster_; + uint32_t target_bitrate_bps_ = 0; + uint32_t max_bitrate_bps_ = 0; + + int32_t InitNvEnc(); + int32_t ReleaseNvEnc(); + webrtc::H264BitstreamParser h264_bitstream_parser_; + webrtc::H265BitstreamParser h265_bitstream_parser_; + + std::shared_ptr cuda_context_; + CudaVideoCodec codec_; + std::unique_ptr nv_encoder_; +#ifdef _WIN32 + Microsoft::WRL::ComPtr id3d11_device_; + Microsoft::WRL::ComPtr id3d11_context_; + Microsoft::WRL::ComPtr id3d11_texture_; +#endif +#ifdef __linux__ + std::unique_ptr cuda_; + bool is_nv12_ = false; +#endif + bool reconfigure_needed_ = false; + uint32_t width_ = 0; + uint32_t height_ = 0; + uint32_t framerate_ = 0; + webrtc::VideoCodecMode mode_ = webrtc::VideoCodecMode::kRealtimeVideo; + NV_ENC_INITIALIZE_PARAMS initialize_params_; + std::vector> v_packet_; + webrtc::EncodedImage encoded_image_; +}; + +NvCodecVideoEncoderImpl::NvCodecVideoEncoderImpl( + std::shared_ptr cuda_context, + CudaVideoCodec codec) + : cuda_context_(cuda_context), codec_(codec), bitrate_adjuster_(0.5, 0.95) { +#ifdef _WIN32 + ComPtr idxgi_factory; + RTC_CHECK(!FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), + (void**)idxgi_factory.GetAddressOf()))); + ComPtr idxgi_adapter; + RTC_CHECK( + !FAILED(idxgi_factory->EnumAdapters(0, idxgi_adapter.GetAddressOf()))); + RTC_CHECK(!FAILED(D3D11CreateDevice( + idxgi_adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0, + D3D11_SDK_VERSION, id3d11_device_.GetAddressOf(), NULL, + id3d11_context_.GetAddressOf()))); + + // 以下デバイス名を取得するだけの処理 + DXGI_ADAPTER_DESC adapter_desc; + idxgi_adapter->GetDesc(&adapter_desc); + char szDesc[80]; + size_t result = 0; + wcstombs_s(&result, szDesc, adapter_desc.Description, sizeof(szDesc)); + RTC_LOG(LS_INFO) << __FUNCTION__ << "GPU in use: " << szDesc; +#endif +#ifdef __linux__ + cuda_.reset(new NvCodecVideoEncoderCuda(cuda_context_)); +#endif +} + +NvCodecVideoEncoderImpl::~NvCodecVideoEncoderImpl() {} + +int32_t NvCodecVideoEncoderImpl::InitEncode( + const webrtc::VideoCodec* codec_settings, + int32_t number_of_cores, + size_t max_payload_size) { + RTC_DCHECK(codec_settings); + + int32_t release_ret = Release(); + if (release_ret != WEBRTC_VIDEO_CODEC_OK) { + return release_ret; + } + + width_ = codec_settings->width; + height_ = codec_settings->height; + target_bitrate_bps_ = codec_settings->startBitrate * 1000; + max_bitrate_bps_ = codec_settings->maxBitrate * 1000; + bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); + framerate_ = codec_settings->maxFramerate; + mode_ = codec_settings->mode; + + RTC_LOG(LS_INFO) << "InitEncode " << target_bitrate_bps_ << "bit/sec"; + + return InitNvEnc(); +} + +int32_t NvCodecVideoEncoderImpl::RegisterEncodeCompleteCallback( + webrtc::EncodedImageCallback* callback) { + std::lock_guard lock(mutex_); + callback_ = callback; + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t NvCodecVideoEncoderImpl::Release() { + return ReleaseNvEnc(); +} + +int32_t NvCodecVideoEncoderImpl::Encode( + const webrtc::VideoFrame& frame, + const std::vector* frame_types) { + //RTC_LOG(LS_ERROR) << __FUNCTION__ << " Start"; + if (!nv_encoder_) { + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + if (!callback_) { + RTC_LOG(LS_WARNING) + << "InitEncode() has been called, but a callback function " + << "has not been set with RegisterEncodeCompleteCallback()"; + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + +#if defined(__linux__) + if (frame.video_frame_buffer()->type() == + webrtc::VideoFrameBuffer::Type::kNV12) { + if (!is_nv12_) { + ReleaseNvEnc(); + is_nv12_ = true; + InitNvEnc(); + } + } else { + if (is_nv12_) { + ReleaseNvEnc(); + is_nv12_ = false; + InitNvEnc(); + } + } +#endif + + bool send_key_frame = false; + + if (reconfigure_needed_) { + NV_ENC_RECONFIGURE_PARAMS reconfigure_params = { + NV_ENC_RECONFIGURE_PARAMS_VER}; + NV_ENC_CONFIG encode_config = {NV_ENC_CONFIG_VER}; + reconfigure_params.reInitEncodeParams.encodeConfig = &encode_config; + nv_encoder_->GetInitializeParams(&reconfigure_params.reInitEncodeParams); + + reconfigure_params.reInitEncodeParams.frameRateNum = framerate_; + + encode_config.rcParams.averageBitRate = + bitrate_adjuster_.GetAdjustedBitrateBps(); + encode_config.rcParams.maxBitRate = max_bitrate_bps_; + encode_config.rcParams.vbvBufferSize = + encode_config.rcParams.averageBitRate * 1 / framerate_; + encode_config.rcParams.vbvInitialDelay = + encode_config.rcParams.vbvBufferSize; + try { + //RTC_LOG(LS_ERROR) << __FUNCTION__ << " Reconfigure"; + nv_encoder_->Reconfigure(&reconfigure_params); + } catch (const NVENCException& e) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + + reconfigure_needed_ = false; + } + + if (frame_types != nullptr) { + // We only support a single stream. + RTC_DCHECK_EQ(frame_types->size(), static_cast(1)); + // Skip frame? + if ((*frame_types)[0] == webrtc::VideoFrameType::kEmptyFrame) { + return WEBRTC_VIDEO_CODEC_OK; + } + // Force key frame? + send_key_frame = + (*frame_types)[0] == webrtc::VideoFrameType::kVideoFrameKey; + } + + NV_ENC_PIC_PARAMS pic_params = {NV_ENC_PIC_PARAMS_VER}; + pic_params.encodePicFlags = 0; + if (send_key_frame) { + pic_params.encodePicFlags = + NV_ENC_PIC_FLAG_FORCEINTRA | NV_ENC_PIC_FLAG_FORCEIDR; + } + pic_params.inputWidth = width_; + pic_params.inputHeight = height_; + + v_packet_.clear(); + +#ifdef _WIN32 + const NvEncInputFrame* input_frame = nv_encoder_->GetNextInputFrame(); + D3D11_MAPPED_SUBRESOURCE map; + id3d11_context_->Map(id3d11_texture_.Get(), D3D11CalcSubresource(0, 0, 1), + D3D11_MAP_WRITE, 0, &map); + if (frame.video_frame_buffer()->type() == + webrtc::VideoFrameBuffer::Type::kNV12) { + webrtc::NV12BufferInterface* frame_buffer = + static_cast( + frame.video_frame_buffer().get()); + libyuv::NV12Copy( + frame_buffer->DataY(), frame_buffer->StrideY(), frame_buffer->DataUV(), + frame_buffer->StrideUV(), (uint8_t*)map.pData, map.RowPitch, + ((uint8_t*)map.pData + height_ * map.RowPitch), map.RowPitch, + frame_buffer->width(), frame_buffer->height()); + } else { + rtc::scoped_refptr frame_buffer = + frame.video_frame_buffer()->ToI420(); + libyuv::I420ToNV12( + frame_buffer->DataY(), frame_buffer->StrideY(), frame_buffer->DataU(), + frame_buffer->StrideU(), frame_buffer->DataV(), frame_buffer->StrideV(), + (uint8_t*)map.pData, map.RowPitch, + ((uint8_t*)map.pData + height_ * map.RowPitch), map.RowPitch, + frame_buffer->width(), frame_buffer->height()); + } + id3d11_context_->Unmap(id3d11_texture_.Get(), D3D11CalcSubresource(0, 0, 1)); + ID3D11Texture2D* nv11_texture = + reinterpret_cast(input_frame->inputPtr); + id3d11_context_->CopyResource(nv11_texture, id3d11_texture_.Get()); +#endif +#ifdef __linux__ + + //RTC_LOG(LS_INFO) << "type=" + // << VideoFrameBufferTypeToString( + // frame.video_frame_buffer()->type()) + // << " width_=" << width_ << " height_=" << height_ + // << " frame_width=" << frame.video_frame_buffer()->width() + // << " frame_height=" << frame.video_frame_buffer()->height(); + + if (frame.video_frame_buffer()->type() == + webrtc::VideoFrameBuffer::Type::kNV12) { + webrtc::NV12Buffer* buffer = + static_cast(frame.video_frame_buffer().get()); + try { + cuda_->Copy(nv_encoder_.get(), buffer->DataY(), width_, height_); + } catch (const NVENCException& e) { + RTC_LOG(LS_ERROR) << e.what(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + } else { + rtc::scoped_refptr frame_buffer = + frame.video_frame_buffer()->ToI420(); + cuda_->Copy(nv_encoder_.get(), frame_buffer->DataY(), frame_buffer->width(), + frame_buffer->height()); + } +#endif + + try { + nv_encoder_->EncodeFrame(v_packet_, &pic_params); + } catch (const NVENCException& e) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + + for (std::vector& packet : v_packet_) { + auto encoded_image_buffer = + webrtc::EncodedImageBuffer::Create(packet.data(), packet.size()); + encoded_image_.SetEncodedData(encoded_image_buffer); + encoded_image_._encodedWidth = width_; + encoded_image_._encodedHeight = height_; + encoded_image_.content_type_ = + (mode_ == webrtc::VideoCodecMode::kScreensharing) + ? webrtc::VideoContentType::SCREENSHARE + : webrtc::VideoContentType::UNSPECIFIED; + encoded_image_.timing_.flags = webrtc::VideoSendTiming::kInvalid; + encoded_image_.SetRtpTimestamp(frame.timestamp()); + encoded_image_.ntp_time_ms_ = frame.ntp_time_ms(); + encoded_image_.capture_time_ms_ = frame.render_time_ms(); + encoded_image_.rotation_ = frame.rotation(); + encoded_image_.SetColorSpace(frame.color_space()); + encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameDelta; + + uint8_t zero_count = 0; + size_t nal_start_idx = 0; + for (size_t i = 0; i < packet.size(); i++) { + uint8_t data = packet.data()[i]; + if ((i != 0) && (i == nal_start_idx)) { + if ((data & 0x1F) == 0x05) { + encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameKey; + } + } + if (data == 0x01 && zero_count >= 2) { + nal_start_idx = i + 1; + } + if (data == 0x00) { + zero_count++; + } else { + zero_count = 0; + } + } + + webrtc::CodecSpecificInfo codec_specific; + if (codec_ == CudaVideoCodec::H264) { + codec_specific.codecType = webrtc::kVideoCodecH264; + codec_specific.codecSpecific.H264.packetization_mode = + webrtc::H264PacketizationMode::NonInterleaved; + + h264_bitstream_parser_.ParseBitstream(encoded_image_); + encoded_image_.qp_ = h264_bitstream_parser_.GetLastSliceQp().value_or(-1); + } else if (codec_ == CudaVideoCodec::H265) { + codec_specific.codecType = webrtc::kVideoCodecH265; + + h265_bitstream_parser_.ParseBitstream(encoded_image_); + encoded_image_.qp_ = h265_bitstream_parser_.GetLastSliceQp().value_or(-1); + } + + webrtc::EncodedImageCallback::Result result = + callback_->OnEncodedImage(encoded_image_, &codec_specific); + if (result.error != webrtc::EncodedImageCallback::Result::OK) { + RTC_LOG(LS_ERROR) << __FUNCTION__ + << " OnEncodedImage failed error:" << result.error; + return WEBRTC_VIDEO_CODEC_ERROR; + } + bitrate_adjuster_.Update(packet.size()); + } + + return WEBRTC_VIDEO_CODEC_OK; +} + +void NvCodecVideoEncoderImpl::SetRates( + const webrtc::VideoEncoder::RateControlParameters& parameters) { + if (!nv_encoder_) { + RTC_LOG(LS_WARNING) << "SetRates() while uninitialized."; + return; + } + + if (parameters.framerate_fps < 1.0) { + RTC_LOG(LS_WARNING) << "Invalid frame rate: " << parameters.framerate_fps; + return; + } + + uint32_t new_framerate = (uint32_t)parameters.framerate_fps; + uint32_t new_bitrate = parameters.bitrate.get_sum_bps(); + RTC_LOG(LS_INFO) << __FUNCTION__ << " framerate_:" << framerate_ + << " new_framerate: " << new_framerate + << " target_bitrate_bps_:" << target_bitrate_bps_ + << " new_bitrate:" << new_bitrate + << " max_bitrate_bps_:" << max_bitrate_bps_; + framerate_ = new_framerate; + target_bitrate_bps_ = new_bitrate; + bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); + reconfigure_needed_ = true; +} + +webrtc::VideoEncoder::EncoderInfo NvCodecVideoEncoderImpl::GetEncoderInfo() + const { + webrtc::VideoEncoder::EncoderInfo info; + info.supports_native_handle = true; + info.implementation_name = "NvCodec"; + info.scaling_settings = webrtc::VideoEncoder::ScalingSettings( + kLowH264QpThreshold, kHighH264QpThreshold); + return info; +} + +int32_t NvCodecVideoEncoderImpl::InitNvEnc() { +#ifdef _WIN32 + nv_encoder_ = CreateEncoder( + codec_, width_, height_, framerate_, target_bitrate_bps_, + max_bitrate_bps_, id3d11_device_.Get(), id3d11_texture_.GetAddressOf()); +#endif +#ifdef __linux__ + nv_encoder_ = + CreateEncoder(codec_, width_, height_, framerate_, target_bitrate_bps_, + max_bitrate_bps_, cuda_.get(), is_nv12_); +#endif + + if (nv_encoder_ == nullptr) { + return WEBRTC_VIDEO_CODEC_ERROR; + } + + reconfigure_needed_ = false; + + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t NvCodecVideoEncoderImpl::ReleaseNvEnc() { + if (nv_encoder_) { + try { + nv_encoder_->EndEncode(v_packet_); + nv_encoder_->DestroyEncoder(); + } catch (const NVENCException& e) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); + } + nv_encoder_ = nullptr; +#ifdef _WIN32 + id3d11_texture_.Reset(); +#endif + } + return WEBRTC_VIDEO_CODEC_OK; +} + +std::unique_ptr NvCodecVideoEncoderImpl::CreateEncoder( + CudaVideoCodec codec, + int width, + int height, + int framerate, + int target_bitrate_bps, + int max_bitrate_bps +#ifdef _WIN32 + , + ID3D11Device* id3d11_device, + ID3D11Texture2D** out_id3d11_texture +#endif +#ifdef __linux__ + , + NvCodecVideoEncoderCuda* cuda, + bool is_nv12 +#endif +) { + std::unique_ptr encoder; + +#ifdef _WIN32 + DXGI_FORMAT dxgi_format = DXGI_FORMAT_NV12; + NV_ENC_BUFFER_FORMAT nvenc_format = NV_ENC_BUFFER_FORMAT_NV12; + D3D11_TEXTURE2D_DESC desc; + ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC)); + desc.Width = width; + desc.Height = height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = dxgi_format; + desc.SampleDesc.Count = 1; + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + id3d11_device->CreateTexture2D(&desc, NULL, out_id3d11_texture); + + // Driver が古いとかに気づくのはココ + try { + encoder.reset( + new NvEncoderD3D11(id3d11_device, width, height, nvenc_format)); + } catch (const NVENCException& e) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); + return nullptr; + } +#endif + +#ifdef __linux__ + try { + encoder.reset(cuda->CreateNvEncoder(width, height, is_nv12)); + } catch (const NVENCException& e) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << e.what(); + return nullptr; + } +#endif + + NV_ENC_INITIALIZE_PARAMS initialize_params = {NV_ENC_INITIALIZE_PARAMS_VER}; + NV_ENC_CONFIG encode_config = {NV_ENC_CONFIG_VER}; + initialize_params.encodeConfig = &encode_config; + try { + if (codec == CudaVideoCodec::H264) { + encoder->CreateDefaultEncoderParams( + &initialize_params, NV_ENC_CODEC_H264_GUID, NV_ENC_PRESET_P3_GUID, + NV_ENC_TUNING_INFO_LOW_LATENCY); + } else if (codec == CudaVideoCodec::H265) { + encoder->CreateDefaultEncoderParams( + &initialize_params, NV_ENC_CODEC_HEVC_GUID, NV_ENC_PRESET_P2_GUID, + NV_ENC_TUNING_INFO_LOW_LATENCY); + } + + //initialize_params.enablePTD = 1; + initialize_params.frameRateDen = 1; + initialize_params.frameRateNum = framerate; + initialize_params.maxEncodeWidth = width; + initialize_params.maxEncodeHeight = height; + + //encode_config.profileGUID = NV_ENC_H264_PROFILE_BASELINE_GUID; + //encode_config.rcParams.rateControlMode = NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ; + encode_config.rcParams.averageBitRate = target_bitrate_bps; + encode_config.rcParams.maxBitRate = max_bitrate_bps; + + encode_config.rcParams.disableBadapt = 1; + encode_config.rcParams.vbvBufferSize = + encode_config.rcParams.averageBitRate * initialize_params.frameRateDen / + initialize_params.frameRateNum; + encode_config.rcParams.vbvInitialDelay = + encode_config.rcParams.vbvBufferSize; + encode_config.gopLength = NVENC_INFINITE_GOPLENGTH; + encode_config.frameIntervalP = 1; + encode_config.rcParams.enableAQ = 1; + + if (codec == CudaVideoCodec::H264) { + //encode_config.encodeCodecConfig.h264Config.outputAUD = 1; + //encode_config.encodeCodecConfig.h264Config.level = NV_ENC_LEVEL_H264_31; + //encode_config.encodeCodecConfig.h264Config.entropyCodingMode = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC; + encode_config.encodeCodecConfig.h264Config.idrPeriod = + NVENC_INFINITE_GOPLENGTH; + encode_config.encodeCodecConfig.h264Config.repeatSPSPPS = 1; + encode_config.encodeCodecConfig.h264Config.sliceMode = 0; + encode_config.encodeCodecConfig.h264Config.sliceModeData = 0; + } else if (codec == CudaVideoCodec::H265) { + encode_config.encodeCodecConfig.hevcConfig.idrPeriod = + NVENC_INFINITE_GOPLENGTH; + encode_config.encodeCodecConfig.hevcConfig.repeatSPSPPS = 1; + encode_config.encodeCodecConfig.hevcConfig.sliceMode = 0; + encode_config.encodeCodecConfig.hevcConfig.sliceModeData = 0; + } + + encoder->CreateEncoder(&initialize_params); + + RTC_LOG(LS_INFO) << __FUNCTION__ << " framerate:" << framerate + << " bitrate_bps:" << target_bitrate_bps + << " maxBitRate:" << encode_config.rcParams.maxBitRate; + } catch (const NVENCException& e) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << ": " << e.what(); + return nullptr; + } + + return encoder; +} + +bool NvCodecVideoEncoder::IsSupported(std::shared_ptr cuda_context, + CudaVideoCodec codec) { + try { + NvEncoder::TryLoadNvEncApi(); + + // Linux の場合、cuda と nvcuvid のロードも必要なのでチェックする +#ifdef __linux__ + if (cuda_context == nullptr) { + return false; + } + + if (!dyn::DynModule::Instance().IsLoadable(dyn::CUDA_SO)) { + return false; + } + if (!dyn::DynModule::Instance().IsLoadable(dyn::NVCUVID_SO)) { + return false; + } + // 関数が存在するかチェックする + if (dyn::DynModule::Instance().GetFunc(dyn::CUDA_SO, "cuDeviceGetName") == + nullptr) { + return false; + } + if (dyn::DynModule::Instance().GetFunc(dyn::NVCUVID_SO, + "cuvidMapVideoFrame") == nullptr) { + return false; + } +#endif + + // 実際にエンコーダを作れるかを確認する +#ifdef _WIN32 + ComPtr idxgi_factory; + RTC_CHECK(!FAILED(CreateDXGIFactory1( + __uuidof(IDXGIFactory1), (void**)idxgi_factory.GetAddressOf()))); + ComPtr idxgi_adapter; + RTC_CHECK( + !FAILED(idxgi_factory->EnumAdapters(0, idxgi_adapter.GetAddressOf()))); + Microsoft::WRL::ComPtr id3d11_device; + Microsoft::WRL::ComPtr id3d11_context; + Microsoft::WRL::ComPtr id3d11_texture; + RTC_CHECK(!FAILED(D3D11CreateDevice( + idxgi_adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, NULL, 0, + D3D11_SDK_VERSION, id3d11_device.GetAddressOf(), NULL, + id3d11_context.GetAddressOf()))); + + auto encoder = NvCodecVideoEncoderImpl::CreateEncoder( + codec, 640, 480, 30, 100 * 1000, 500 * 1000, id3d11_device.Get(), + id3d11_texture.GetAddressOf()); +#endif +#ifdef __linux__ + auto cuda = std::unique_ptr( + new NvCodecVideoEncoderCuda(cuda_context)); + auto encoder = NvCodecVideoEncoderImpl::CreateEncoder( + codec, 640, 480, 30, 100 * 1000, 500 * 1000, cuda.get(), true); +#endif + if (encoder == nullptr) { + return false; + } + + return true; + } catch (const NVENCException& e) { + RTC_LOG(LS_ERROR) << __FUNCTION__ << ": " << e.what(); + return false; + } +} + +std::unique_ptr NvCodecVideoEncoder::Create( + std::shared_ptr cuda_context, + CudaVideoCodec codec) { + return std::unique_ptr( + new NvCodecVideoEncoderImpl(cuda_context, codec)); +} + +} // namespace sora diff --git a/src/hwenc_nvcodec/nvcodec_h264_encoder_cuda.cpp b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder_cuda.cpp similarity index 66% rename from src/hwenc_nvcodec/nvcodec_h264_encoder_cuda.cpp rename to src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder_cuda.cpp index 662a54f4..a9914d77 100644 --- a/src/hwenc_nvcodec/nvcodec_h264_encoder_cuda.cpp +++ b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder_cuda.cpp @@ -1,4 +1,6 @@ -#include "nvcodec_h264_encoder_cuda.h" +#include "sora/fix_cuda_noinline_macro_error.h" + +#include "nvcodec_video_encoder_cuda.h" #include @@ -6,37 +8,40 @@ #include #include -#include "cuda/cuda_context_cuda.h" -#include "dyn/cuda.h" +#include "../cuda_context_cuda.h" +#include "sora/dyn/cuda.h" + +namespace sora { -class NvCodecH264EncoderCudaImpl { +class NvCodecVideoEncoderCudaImpl { public: - NvCodecH264EncoderCudaImpl(std::shared_ptr ctx); - ~NvCodecH264EncoderCudaImpl(); + NvCodecVideoEncoderCudaImpl(std::shared_ptr ctx); + ~NvCodecVideoEncoderCudaImpl(); void Copy(NvEncoder* nv_encoder, const void* ptr, int width, int height); - NvEncoder* CreateNvEncoder(int width, int height, bool use_native); + NvEncoder* CreateNvEncoder(int width, int height, bool is_nv12); private: std::shared_ptr cuda_context_; }; -NvCodecH264EncoderCuda::NvCodecH264EncoderCuda(std::shared_ptr ctx) - : impl_(new NvCodecH264EncoderCudaImpl(ctx)) {} -NvCodecH264EncoderCuda::~NvCodecH264EncoderCuda() { +NvCodecVideoEncoderCuda::NvCodecVideoEncoderCuda( + std::shared_ptr ctx) + : impl_(new NvCodecVideoEncoderCudaImpl(ctx)) {} +NvCodecVideoEncoderCuda::~NvCodecVideoEncoderCuda() { delete impl_; } -void NvCodecH264EncoderCuda::Copy(NvEncoder* nv_encoder, - const void* ptr, - int width, - int height) { +void NvCodecVideoEncoderCuda::Copy(NvEncoder* nv_encoder, + const void* ptr, + int width, + int height) { impl_->Copy(nv_encoder, ptr, width, height); } -NvEncoder* NvCodecH264EncoderCuda::CreateNvEncoder(int width, - int height, - bool use_native) { - return impl_->CreateNvEncoder(width, height, use_native); +NvEncoder* NvCodecVideoEncoderCuda::CreateNvEncoder(int width, + int height, + bool is_nv12) { + return impl_->CreateNvEncoder(width, height, is_nv12); } void ShowEncoderCapability() { @@ -59,79 +64,68 @@ void ShowEncoderCapability() { std::cout << "GPU " << iGpu << " - " << szDeviceName << std::endl << std::endl; std::cout - << "\tH264:\t\t" - << " " + << "\tH264:\t\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_H264_GUID, NV_ENC_CAPS_SUPPORTED_RATECONTROL_MODES) ? "yes" : "no") << std::endl - << "\tH264_444:\t" - << " " + << "\tH264_444:\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_H264_GUID, NV_ENC_CAPS_SUPPORT_YUV444_ENCODE) ? "yes" : "no") << std::endl - << "\tH264_ME:\t" - << " " + << "\tH264_ME:\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_H264_GUID, NV_ENC_CAPS_SUPPORT_MEONLY_MODE) ? "yes" : "no") << std::endl - << "\tH264_WxH:\t" - << " " + << "\tH264_WxH:\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_H264_GUID, NV_ENC_CAPS_WIDTH_MAX)) << "*" << (enc.GetCapabilityValue(NV_ENC_CODEC_H264_GUID, NV_ENC_CAPS_HEIGHT_MAX)) << std::endl - << "\tHEVC:\t\t" - << " " + << "\tHEVC:\t\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_HEVC_GUID, NV_ENC_CAPS_SUPPORTED_RATECONTROL_MODES) ? "yes" : "no") << std::endl - << "\tHEVC_Main10:\t" - << " " + << "\tHEVC_Main10:\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_HEVC_GUID, NV_ENC_CAPS_SUPPORT_10BIT_ENCODE) ? "yes" : "no") << std::endl - << "\tHEVC_Lossless:\t" - << " " + << "\tHEVC_Lossless:\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_HEVC_GUID, NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE) ? "yes" : "no") << std::endl - << "\tHEVC_SAO:\t" - << " " + << "\tHEVC_SAO:\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_HEVC_GUID, NV_ENC_CAPS_SUPPORT_SAO) ? "yes" : "no") << std::endl - << "\tHEVC_444:\t" - << " " + << "\tHEVC_444:\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_HEVC_GUID, NV_ENC_CAPS_SUPPORT_YUV444_ENCODE) ? "yes" : "no") << std::endl - << "\tHEVC_ME:\t" - << " " + << "\tHEVC_ME:\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_HEVC_GUID, NV_ENC_CAPS_SUPPORT_MEONLY_MODE) ? "yes" : "no") << std::endl - << "\tHEVC_WxH:\t" - << " " + << "\tHEVC_WxH:\t" << " " << (enc.GetCapabilityValue(NV_ENC_CODEC_HEVC_GUID, NV_ENC_CAPS_WIDTH_MAX)) << "*" @@ -146,16 +140,16 @@ void ShowEncoderCapability() { } } -NvCodecH264EncoderCudaImpl::NvCodecH264EncoderCudaImpl( +NvCodecVideoEncoderCudaImpl::NvCodecVideoEncoderCudaImpl( std::shared_ptr ctx) { ShowEncoderCapability(); cuda_context_ = ctx; } -NvCodecH264EncoderCudaImpl::~NvCodecH264EncoderCudaImpl() {} -void NvCodecH264EncoderCudaImpl::Copy(NvEncoder* nv_encoder, - const void* ptr, - int width, - int height) { +NvCodecVideoEncoderCudaImpl::~NvCodecVideoEncoderCudaImpl() {} +void NvCodecVideoEncoderCudaImpl::Copy(NvEncoder* nv_encoder, + const void* ptr, + int width, + int height) { const NvEncInputFrame* input_frame = nv_encoder->GetNextInputFrame(); CUcontext context = GetCudaContext(cuda_context_); NvEncoderCuda::CopyToDeviceFrame( @@ -164,11 +158,13 @@ void NvCodecH264EncoderCudaImpl::Copy(NvEncoder* nv_encoder, input_frame->bufferFormat, input_frame->chromaOffsets, input_frame->numChromaPlanes); } -NvEncoder* NvCodecH264EncoderCudaImpl::CreateNvEncoder(int width, - int height, - bool use_native) { +NvEncoder* NvCodecVideoEncoderCudaImpl::CreateNvEncoder(int width, + int height, + bool is_nv12) { NV_ENC_BUFFER_FORMAT nvenc_format = - use_native ? NV_ENC_BUFFER_FORMAT_NV12 : NV_ENC_BUFFER_FORMAT_IYUV; + is_nv12 ? NV_ENC_BUFFER_FORMAT_NV12 : NV_ENC_BUFFER_FORMAT_IYUV; CUcontext context = GetCudaContext(cuda_context_); return new NvEncoderCuda(context, width, height, nvenc_format); } + +} // namespace sora diff --git a/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder_cuda.h b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder_cuda.h new file mode 100644 index 00000000..1757dd3a --- /dev/null +++ b/src/sora-cpp-sdk/src/hwenc_nvcodec/nvcodec_video_encoder_cuda.h @@ -0,0 +1,32 @@ +#ifndef SORA_HWENC_NVCODEC_NVCODEC_VIDEO_ENCODER_CUDA_H_ +#define SORA_HWENC_NVCODEC_NVCODEC_VIDEO_ENCODER_CUDA_H_ + +// CUDA と WebRTC のヘッダを混ぜてコンパイルすると大量のエラーが発生したので、 +// CUDA の処理だけさせる単純な CUDA ファイルを用意する + +#include + +#include "sora/cuda_context.h" + +class NvEncoder; + +namespace sora { + +class NvCodecVideoEncoderCudaImpl; + +class NvCodecVideoEncoderCuda { + public: + NvCodecVideoEncoderCuda(std::shared_ptr ctx); + ~NvCodecVideoEncoderCuda(); + + void Copy(NvEncoder* nv_encoder, const void* ptr, int width, int height); + // 念のため も include せずポインタを利用する + NvEncoder* CreateNvEncoder(int width, int height, bool is_nv12); + + private: + NvCodecVideoEncoderCudaImpl* impl_; +}; + +} // namespace sora + +#endif diff --git a/src/hwenc_msdk/vaapi_utils.cpp b/src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils.cpp similarity index 98% rename from src/hwenc_msdk/vaapi_utils.cpp rename to src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils.cpp index eca5a637..09c15439 100644 --- a/src/hwenc_msdk/vaapi_utils.cpp +++ b/src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils.cpp @@ -15,6 +15,8 @@ or https://software.intel.com/en-us/media-client-solutions-support. #include "vaapi_utils.h" +namespace sora { + mfxStatus va_to_mfx_status(VAStatus va_res) { mfxStatus mfxRes = MFX_ERR_NONE; @@ -50,4 +52,6 @@ mfxStatus va_to_mfx_status(VAStatus va_res) { break; } return mfxRes; -} \ No newline at end of file +} + +} // namespace sora diff --git a/src/hwenc_msdk/vaapi_utils.h b/src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils.h similarity index 93% rename from src/hwenc_msdk/vaapi_utils.h rename to src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils.h index ad9dd3a6..a17505b2 100644 --- a/src/hwenc_msdk/vaapi_utils.h +++ b/src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils.h @@ -13,15 +13,17 @@ The original version of this sample may be obtained from https://software.intel. or https://software.intel.com/en-us/media-client-solutions-support. \**********************************************************************************/ -#ifndef VAAPI_UTILS_H_ -#define VAAPI_UTILS_H_ - -// msdk -#include +#ifndef SORA_HWENC_VPL_VAAPI_UTILS_H_ +#define SORA_HWENC_VPL_VAAPI_UTILS_H_ // libva #include +// Intel VPL +#include + +namespace sora { + class CLibVA { public: virtual ~CLibVA(void) {} @@ -41,4 +43,6 @@ class CLibVA { mfxStatus va_to_mfx_status(VAStatus va_res); -#endif // VAAPI_UTILS_H_ \ No newline at end of file +} // namespace sora + +#endif diff --git a/src/hwenc_msdk/vaapi_utils_drm.cpp b/src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils_drm.cpp similarity index 99% rename from src/hwenc_msdk/vaapi_utils_drm.cpp rename to src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils_drm.cpp index 016cc25f..5bec4bde 100644 --- a/src/hwenc_msdk/vaapi_utils_drm.cpp +++ b/src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils_drm.cpp @@ -29,6 +29,8 @@ or https://software.intel.com/en-us/media-client-solutions-support. // libva #include +namespace sora { + constexpr mfxU32 MFX_DRI_MAX_NODES_NUM = 16; constexpr mfxU32 MFX_DRI_RENDER_START_INDEX = 128; constexpr mfxU32 MFX_DRI_CARD_START_INDEX = 0; @@ -131,4 +133,6 @@ std::unique_ptr CreateDRMLibVA(const std::string& devicePath) { } catch (std::exception& e) { return nullptr; } -} \ No newline at end of file +} + +} // namespace sora diff --git a/src/hwenc_msdk/vaapi_utils_drm.h b/src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils_drm.h similarity index 95% rename from src/hwenc_msdk/vaapi_utils_drm.h rename to src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils_drm.h index bd64d6a0..b4f1a3f4 100644 --- a/src/hwenc_msdk/vaapi_utils_drm.h +++ b/src/sora-cpp-sdk/src/hwenc_vpl/vaapi_utils_drm.h @@ -13,14 +13,16 @@ The original version of this sample may be obtained from https://software.intel. or https://software.intel.com/en-us/media-client-solutions-support. \**********************************************************************************/ -#ifndef VAAPI_UTILS_DRM_H_ -#define VAAPI_UTILS_DRM_H_ +#ifndef SORA_HWENC_VPL_VAAPI_UTILS_DRM_H_ +#define SORA_HWENC_VPL_VAAPI_UTILS_DRM_H_ #include #include #include "vaapi_utils.h" +namespace sora { + class DRMLibVA : public CLibVA { public: DRMLibVA(const std::string& devicePath); @@ -40,4 +42,6 @@ class DRMLibVA : public CLibVA { std::unique_ptr CreateDRMLibVA(const std::string& devicePath = ""); -#endif // VAAPI_UTILS_DRM_H_ \ No newline at end of file +} // namespace sora + +#endif diff --git a/src/sora-cpp-sdk/src/hwenc_vpl/vpl_session_impl.cpp b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_session_impl.cpp new file mode 100644 index 00000000..839978e9 --- /dev/null +++ b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_session_impl.cpp @@ -0,0 +1,90 @@ +#include "sora/hwenc_vpl/vpl_session.h" + +#include + +// Intel VPL +#include +#include + +#ifdef __linux__ +#include "vaapi_utils_drm.h" +#endif + +namespace sora { + +struct VplSessionImpl : VplSession { + ~VplSessionImpl(); + + mfxLoader loader = nullptr; + mfxSession session = nullptr; + +#ifdef __linux__ + std::unique_ptr libva; +#endif +}; + +VplSessionImpl::~VplSessionImpl() { + MFXClose(session); + MFXUnload(loader); +} + +std::shared_ptr VplSession::Create() { + std::shared_ptr session(new VplSessionImpl()); + + mfxStatus sts = MFX_ERR_NONE; + + session->loader = MFXLoad(); + if (session->loader == nullptr) { + RTC_LOG(LS_VERBOSE) << "Failed to MFXLoad"; + return nullptr; + } + + MFX_ADD_PROPERTY_U32(session->loader, "mfxImplDescription.Impl", + MFX_IMPL_TYPE_HARDWARE); + + sts = MFXCreateSession(session->loader, 0, &session->session); + if (sts != MFX_ERR_NONE) { + RTC_LOG(LS_VERBOSE) << "Failed to MFXCreateSession: sts=" << sts; + return nullptr; + } + +#ifdef __linux__ + session->libva = CreateDRMLibVA(); + if (!session->libva) { + return nullptr; + } + + sts = MFXVideoCORE_SetHandle( + session->session, static_cast(MFX_HANDLE_VA_DISPLAY), + session->libva->GetVADisplay()); + if (sts != MFX_ERR_NONE) { + return nullptr; + } +#endif + + // Query selected implementation and version + mfxIMPL impl; + sts = MFXQueryIMPL(session->session, &impl); + if (sts != MFX_ERR_NONE) { + RTC_LOG(LS_VERBOSE) << "Failed to MFXQueryIMPL: sts=" << sts; + return nullptr; + } + + mfxVersion ver; + sts = MFXQueryVersion(session->session, &ver); + if (sts != MFX_ERR_NONE) { + RTC_LOG(LS_VERBOSE) << "Failed to MFXQueryVersion: sts=" << sts; + return nullptr; + } + + RTC_LOG(LS_VERBOSE) << "Intel VPL Implementation: " + << (impl == MFX_IMPL_SOFTWARE ? "SOFTWARE" : "HARDWARE"); + RTC_LOG(LS_VERBOSE) << "Intel VPL Version: " << ver.Major << "." << ver.Minor; + return session; +} + +mfxSession GetVplSession(std::shared_ptr session) { + return std::static_pointer_cast(session)->session; +} + +} // namespace sora diff --git a/src/sora-cpp-sdk/src/hwenc_vpl/vpl_session_impl.h b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_session_impl.h new file mode 100644 index 00000000..579359ae --- /dev/null +++ b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_session_impl.h @@ -0,0 +1,17 @@ +#ifndef SORA_HWENC_VPL_VPL_SESSION_IMPL_H_ +#define SORA_HWENC_VPL_VPL_SESSION_IMPL_H_ + +#include + +// Intel VPL +#include + +#include "sora/hwenc_vpl/vpl_session.h" + +namespace sora { + +mfxSession GetVplSession(std::shared_ptr session); + +} // namespace sora + +#endif \ No newline at end of file diff --git a/src/sora-cpp-sdk/src/hwenc_vpl/vpl_utils.h b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_utils.h new file mode 100644 index 00000000..bdf8856d --- /dev/null +++ b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_utils.h @@ -0,0 +1,38 @@ +#ifndef SORA_HWENC_VPL_VPL_UTILS_H_ +#define SORA_HWENC_VPL_VPL_UTILS_H_ + +// WebRTC +#include + +// Intel VPL +#include + +#define VPL_CHECK_RESULT(P, X, ERR) \ + { \ + if ((X) > (P)) { \ + RTC_LOG(LS_ERROR) << "Intel VPL Error: " << ERR; \ + throw ERR; \ + } \ + } + +namespace sora { + +static mfxU32 ToMfxCodec(webrtc::VideoCodecType codec) { + return codec == webrtc::kVideoCodecVP8 ? MFX_CODEC_VP8 + : codec == webrtc::kVideoCodecVP9 ? MFX_CODEC_VP9 + : codec == webrtc::kVideoCodecH264 ? MFX_CODEC_AVC + : codec == webrtc::kVideoCodecH265 ? MFX_CODEC_HEVC + : MFX_CODEC_AV1; +} + +static std::string CodecToString(mfxU32 codec) { + return codec == MFX_CODEC_VP8 ? "MFX_CODEC_VP8" + : codec == MFX_CODEC_VP9 ? "MFX_CODEC_VP9" + : codec == MFX_CODEC_AV1 ? "MFX_CODEC_AV1" + : codec == MFX_CODEC_AVC ? "MFX_CODEC_AVC" + : codec == MFX_CODEC_HEVC ? "MFX_CODEC_HEVC" + : "MFX_CODEC_UNKNOWN"; +} + +} // namespace sora +#endif diff --git a/src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_decoder.cpp b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_decoder.cpp new file mode 100644 index 00000000..5b837ba4 --- /dev/null +++ b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_decoder.cpp @@ -0,0 +1,413 @@ +#include "sora/hwenc_vpl/vpl_video_decoder.h" + +#include +#include +#include + +// WebRTC +#include +#include +#include +#include +#include +#include +#include +#include + +// Intel VPL +#include +#include +#include + +#include "vpl_session_impl.h" +#include "vpl_utils.h" + +namespace sora { + +class VplVideoDecoderImpl : public VplVideoDecoder { + public: + VplVideoDecoderImpl(std::shared_ptr session, mfxU32 codec); + ~VplVideoDecoderImpl() override; + + bool Configure(const Settings& settings) override; + + int32_t Decode(const webrtc::EncodedImage& input_image, + bool missing_frames, + int64_t render_time_ms) override; + + int32_t RegisterDecodeCompleteCallback( + webrtc::DecodedImageCallback* callback) override; + + int32_t Release() override; + + const char* ImplementationName() const override; + + static std::unique_ptr CreateDecoder( + std::shared_ptr session, + mfxU32 codec, + std::vector> sizes, + bool init, + mfxFrameAllocRequest* alloc_request); + static std::unique_ptr CreateDecoderInternal( + std::shared_ptr session, + mfxU32 codec, + int width, + int height, + bool init, + mfxFrameAllocRequest* alloc_request); + + private: + bool InitVpl(); + void ReleaseVpl(); + + int width_ = 0; + int height_ = 0; + webrtc::DecodedImageCallback* decode_complete_callback_ = nullptr; + webrtc::VideoFrameBufferPool buffer_pool_; + + mfxU32 codec_; + std::shared_ptr session_; + mfxFrameAllocRequest alloc_request_; + std::unique_ptr decoder_; + std::vector surface_buffer_; + std::vector surfaces_; + std::vector bitstream_buffer_; + mfxBitstream bitstream_; +}; + +VplVideoDecoderImpl::VplVideoDecoderImpl(std::shared_ptr session, + mfxU32 codec) + : session_(session), + codec_(codec), + decoder_(nullptr), + decode_complete_callback_(nullptr), + buffer_pool_(false, 300 /* max_number_of_buffers*/) {} + +VplVideoDecoderImpl::~VplVideoDecoderImpl() { + Release(); +} + +std::unique_ptr VplVideoDecoderImpl::CreateDecoder( + std::shared_ptr session, + mfxU32 codec, + std::vector> sizes, + bool init, + mfxFrameAllocRequest* alloc_request) { + for (auto size : sizes) { + memset(alloc_request, 0, sizeof(*alloc_request)); + auto decoder = CreateDecoderInternal(session, codec, size.first, + size.second, init, alloc_request); + if (decoder != nullptr) { + return decoder; + } + } + return nullptr; +} + +std::unique_ptr VplVideoDecoderImpl::CreateDecoderInternal( + std::shared_ptr session, + mfxU32 codec, + int width, + int height, + bool init, + mfxFrameAllocRequest* alloc_request) { + std::unique_ptr decoder( + new MFXVideoDECODE(GetVplSession(session))); + + mfxStatus sts = MFX_ERR_NONE; + + mfxVideoParam param; + memset(¶m, 0, sizeof(param)); + + param.mfx.CodecId = codec; + + if (codec == MFX_CODEC_HEVC) { + // この設定がないと H.265 デコーダーの Init が sts=-15 で失敗する + param.mfx.CodecProfile = MFX_PROFILE_HEVC_MAIN; + } else if (codec == MFX_CODEC_AV1) { + // param.mfx.CodecProfile = MFX_PROFILE_AV1_MAIN; + // この設定がないと Query しても sts=-3 で失敗する + // MFX_LEVEL_AV1_2 で妥当かどうかはよく分からない + param.mfx.CodecLevel = MFX_LEVEL_AV1_2; + } + + param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; + param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + param.mfx.FrameInfo.CropX = 0; + param.mfx.FrameInfo.CropY = 0; + param.mfx.FrameInfo.CropW = width; + param.mfx.FrameInfo.CropH = height; + param.mfx.FrameInfo.Width = (width + 15) / 16 * 16; + param.mfx.FrameInfo.Height = (height + 15) / 16 * 16; + + param.mfx.GopRefDist = 1; + param.AsyncDepth = 1; + param.IOPattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY; + + //qmfxExtCodingOption ext_coding_option; + //qmemset(&ext_coding_option, 0, sizeof(ext_coding_option)); + //qext_coding_option.Header.BufferId = MFX_EXTBUFF_CODING_OPTION; + //qext_coding_option.Header.BufferSz = sizeof(ext_coding_option); + //qext_coding_option.MaxDecFrameBuffering = 1; + + //qmfxExtBuffer* ext_buffers[1]; + //qext_buffers[0] = (mfxExtBuffer*)&ext_coding_option; + //qparam.ExtParam = ext_buffers; + //qparam.NumExtParam = sizeof(ext_buffers) / sizeof(ext_buffers[0]); + + sts = decoder->Query(¶m, ¶m); + if (sts < 0) { + RTC_LOG(LS_VERBOSE) << "Unsupported decoder codec: resolution=" << width + << "x" << height << " codec=" << CodecToString(codec) + << " sts=" << sts; + return nullptr; + } + + if (sts != MFX_ERR_NONE) { + RTC_LOG(LS_VERBOSE) + << "Supported specified codec but has warning: resolution=" << width + << "x" << height << " sts=" << sts; + } + + // MFX_CODEC_AV1 の時に Init より後に QueryIOSurf すると + // MFX_ERR_UNSUPPORTED になったのでここで QueryIOSurf しておく + // (MFX_CODEC_AVC や MFX_CODEC_HEVC の時には Init 後に QueryIOSurf しても動いた) + memset(alloc_request, 0, sizeof(*alloc_request)); + sts = decoder->QueryIOSurf(¶m, alloc_request); + VPL_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + RTC_LOG(LS_INFO) << "Decoder NumFrameSuggested=" + << alloc_request->NumFrameSuggested; + + // Query した上で Init しても MFX_ERR_UNSUPPORTED になることがあるので + // 本来 Init が不要な時も常に呼ぶようにして確認する + /*if (init)*/ { + // Initialize the Intel VPL encoder + sts = decoder->Init(¶m); + if (sts != MFX_ERR_NONE) { + RTC_LOG(LS_VERBOSE) << "Init failed: resolution=" << width << "x" + << height << " codec=" << CodecToString(codec) + << " sts=" << sts; + return nullptr; + } + } + + return decoder; +} + +bool VplVideoDecoderImpl::Configure( + const webrtc::VideoDecoder::Settings& settings) { + width_ = settings.max_render_resolution().Width(); + height_ = settings.max_render_resolution().Height(); + + return InitVpl(); +} + +int32_t VplVideoDecoderImpl::Decode(const webrtc::EncodedImage& input_image, + bool missing_frames, + int64_t render_time_ms) { + if (decoder_ == nullptr) { + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + if (decode_complete_callback_ == nullptr) { + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + if (input_image.data() == nullptr && input_image.size() > 0) { + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + + if (bitstream_.MaxLength < bitstream_.DataLength + input_image.size()) { + bitstream_buffer_.resize(bitstream_.DataLength + input_image.size()); + bitstream_.MaxLength = bitstream_.DataLength + bitstream_buffer_.size(); + bitstream_.Data = bitstream_buffer_.data(); + } + //printf("size=%zu\n", input_image.size()); + //for (size_t i = 0; i < input_image.size(); i++) { + // const uint8_t* p = input_image.data(); + // if (i < 100) { + // printf(" %02x", p[i]); + // } else { + // printf("\n"); + // break; + // } + //} + + memmove(bitstream_.Data, bitstream_.Data + bitstream_.DataOffset, + bitstream_.DataLength); + bitstream_.DataOffset = 0; + memcpy(bitstream_.Data + bitstream_.DataLength, input_image.data(), + input_image.size()); + bitstream_.DataLength += input_image.size(); + + // 使ってない入力サーフェスを取り出す + auto surface = + std::find_if(surfaces_.begin(), surfaces_.end(), + [](const mfxFrameSurface1& s) { return !s.Data.Locked; }); + if (surface == surfaces_.end()) { + RTC_LOG(LS_ERROR) << "Surface not found"; + return WEBRTC_VIDEO_CODEC_ERROR; + } + + // キューが空になるか、sts == MFX_ERR_MORE_DATA あたりが出るまでループさせる + while (true) { + mfxStatus sts; + mfxSyncPoint syncp; + mfxFrameSurface1* out_surface = nullptr; + + while (true) { + sts = decoder_->DecodeFrameAsync(&bitstream_, &*surface, &out_surface, + &syncp); + if (sts == MFX_WRN_DEVICE_BUSY) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + break; + } + + mfxVideoParam param; + memset(¶m, 0, sizeof(param)); + mfxStatus sts2 = decoder_->GetVideoParam(¶m); + if (sts2 != MFX_ERR_NONE) { + RTC_LOG(LS_ERROR) << "Failed to GetVideoParam: sts=" << sts2; + return WEBRTC_VIDEO_CODEC_ERROR; + } + auto width = param.mfx.FrameInfo.CropW; + auto height = param.mfx.FrameInfo.CropH; + if (width_ != width || height_ != height) { + RTC_LOG(LS_INFO) << "Change Frame Size: " << width_ << "x" << height_ + << " to " << width << "x" << height; + width_ = width; + height_ = height; + } + + if (sts == MFX_ERR_MORE_DATA) { + // もっと入力が必要なので出直す + return WEBRTC_VIDEO_CODEC_OK; + } + if (!syncp) { + RTC_LOG(LS_WARNING) << "Failed to DecodeFrameAsync: syncp is null, sts=" + << (int)sts; + continue; + } + VPL_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + sts = MFXVideoCORE_SyncOperation(GetVplSession(session_), syncp, 600000); + VPL_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + uint64_t pts = input_image.RtpTimestamp(); + // NV12 から I420 に変換 + rtc::scoped_refptr i420_buffer = + buffer_pool_.CreateI420Buffer(width_, height_); + libyuv::NV12ToI420(out_surface->Data.Y, out_surface->Data.Pitch, + out_surface->Data.UV, out_surface->Data.Pitch, + i420_buffer->MutableDataY(), i420_buffer->StrideY(), + i420_buffer->MutableDataU(), i420_buffer->StrideU(), + i420_buffer->MutableDataV(), i420_buffer->StrideV(), + width_, height_); + + webrtc::VideoFrame decoded_image = webrtc::VideoFrame::Builder() + .set_video_frame_buffer(i420_buffer) + .set_timestamp_rtp(pts) + .build(); + decode_complete_callback_->Decoded(decoded_image, absl::nullopt, + absl::nullopt); + } + + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t VplVideoDecoderImpl::RegisterDecodeCompleteCallback( + webrtc::DecodedImageCallback* callback) { + decode_complete_callback_ = callback; + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t VplVideoDecoderImpl::Release() { + ReleaseVpl(); + buffer_pool_.Release(); + return WEBRTC_VIDEO_CODEC_OK; +} + +const char* VplVideoDecoderImpl::ImplementationName() const { + return "libvpl"; +} + +bool VplVideoDecoderImpl::InitVpl() { + decoder_ = CreateDecoder(session_, codec_, {{4096, 4096}, {2048, 2048}}, true, + &alloc_request_); + + mfxStatus sts = MFX_ERR_NONE; + + mfxVideoParam param; + memset(¶m, 0, sizeof(param)); + sts = decoder_->GetVideoParam(¶m); + if (sts != MFX_ERR_NONE) { + return false; + } + + // 入力ビットストリーム + bitstream_buffer_.resize(1024 * 1024); + memset(&bitstream_, 0, sizeof(bitstream_)); + bitstream_.MaxLength = bitstream_buffer_.size(); + bitstream_.Data = bitstream_buffer_.data(); + + // 必要な枚数分の出力サーフェスを作る + { + int width = (alloc_request_.Info.Width + 31) / 32 * 32; + int height = (alloc_request_.Info.Height + 31) / 32 * 32; + // 1枚あたりのバイト数 + // NV12 なので 1 ピクセルあたり 12 ビット + int size = width * height * 12 / 8; + surface_buffer_.resize(alloc_request_.NumFrameSuggested * size); + + surfaces_.clear(); + surfaces_.reserve(alloc_request_.NumFrameSuggested); + for (int i = 0; i < alloc_request_.NumFrameSuggested; i++) { + mfxFrameSurface1 surface; + memset(&surface, 0, sizeof(surface)); + surface.Info = param.mfx.FrameInfo; + surface.Data.Y = surface_buffer_.data() + i * size; + surface.Data.U = surface_buffer_.data() + i * size + width * height; + surface.Data.V = surface_buffer_.data() + i * size + width * height + 1; + surface.Data.Pitch = width; + surfaces_.push_back(surface); + } + } + + return true; +} + +void VplVideoDecoderImpl::ReleaseVpl() { + if (decoder_ != nullptr) { + decoder_->Close(); + } + decoder_.reset(); +} + +//////////////////////// +// VplVideoDecoder +//////////////////////// + +bool VplVideoDecoder::IsSupported(std::shared_ptr session, + webrtc::VideoCodecType codec) { + if (session == nullptr) { + return false; + } + + mfxFrameAllocRequest alloc_request; + auto decoder = VplVideoDecoderImpl::CreateDecoder( + session, ToMfxCodec(codec), {{4096, 4096}, {2048, 2048}}, false, + &alloc_request); + + return decoder != nullptr; +} + +std::unique_ptr VplVideoDecoder::Create( + std::shared_ptr session, + webrtc::VideoCodecType codec) { + return std::unique_ptr( + new VplVideoDecoderImpl(session, ToMfxCodec(codec))); +} + +} // namespace sora diff --git a/src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_encoder.cpp b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_encoder.cpp new file mode 100644 index 00000000..94ea603d --- /dev/null +++ b/src/sora-cpp-sdk/src/hwenc_vpl/vpl_video_encoder.cpp @@ -0,0 +1,730 @@ +#include "sora/hwenc_vpl/vpl_video_encoder.h" + +#include +#include + +// WebRTC +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Intel VPL +#include +#include + +// libyuv +#include + +#include "vpl_session_impl.h" +#include "vpl_utils.h" + +namespace sora { + +class VplVideoEncoderImpl : public VplVideoEncoder { + public: + VplVideoEncoderImpl(std::shared_ptr session, mfxU32 codec); + ~VplVideoEncoderImpl() override; + + int32_t InitEncode(const webrtc::VideoCodec* codec_settings, + int32_t number_of_cores, + size_t max_payload_size) override; + int32_t RegisterEncodeCompleteCallback( + webrtc::EncodedImageCallback* callback) override; + int32_t Release() override; + int32_t Encode( + const webrtc::VideoFrame& frame, + const std::vector* frame_types) override; + void SetRates(const RateControlParameters& parameters) override; + webrtc::VideoEncoder::EncoderInfo GetEncoderInfo() const override; + + static std::unique_ptr CreateEncoder( + std::shared_ptr session, + mfxU32 codec, + int width, + int height, + int framerate, + int target_kbps, + int max_kbps, + bool init); + + private: + struct ExtBuffer { + mfxExtBuffer* ext_buffers[10]; + mfxExtCodingOption ext_coding_option; + mfxExtCodingOption2 ext_coding_option2; + }; + // いろいろなパターンでクエリを投げて、 + // 成功した時の param を返す + static mfxStatus Queries(MFXVideoENCODE* encoder, + mfxU32 codec, + int width, + int height, + int framerate, + int target_kbps, + int max_kbps, + mfxVideoParam& param, + ExtBuffer& ext); + + private: + std::mutex mutex_; + webrtc::EncodedImageCallback* callback_ = nullptr; + webrtc::BitrateAdjuster bitrate_adjuster_; + uint32_t target_bitrate_bps_ = 0; + uint32_t max_bitrate_bps_ = 0; + bool reconfigure_needed_ = false; + bool use_native_ = false; + uint32_t width_ = 0; + uint32_t height_ = 0; + uint32_t framerate_ = 0; + webrtc::VideoCodecMode mode_ = webrtc::VideoCodecMode::kRealtimeVideo; + std::vector> v_packet_; + webrtc::EncodedImage encoded_image_; + webrtc::H264BitstreamParser h264_bitstream_parser_; + webrtc::H265BitstreamParser h265_bitstream_parser_; + webrtc::GofInfoVP9 gof_; + size_t gof_idx_; + + int32_t InitVpl(); + int32_t ReleaseVpl(); + + std::vector surface_buffer_; + std::vector surfaces_; + + std::shared_ptr session_; + mfxU32 codec_; + mfxFrameAllocRequest alloc_request_; + std::unique_ptr encoder_; + std::vector bitstream_buffer_; + mfxBitstream bitstream_; + mfxFrameInfo frame_info_; +}; + +const int kLowH264QpThreshold = 34; +const int kHighH264QpThreshold = 40; + +VplVideoEncoderImpl::VplVideoEncoderImpl(std::shared_ptr session, + mfxU32 codec) + : session_(session), codec_(codec), bitrate_adjuster_(0.5, 0.95) {} + +VplVideoEncoderImpl::~VplVideoEncoderImpl() { + Release(); +} + +std::unique_ptr VplVideoEncoderImpl::CreateEncoder( + std::shared_ptr session, + mfxU32 codec, + int width, + int height, + int framerate, + int target_kbps, + int max_kbps, + bool init) { + std::unique_ptr encoder( + new MFXVideoENCODE(GetVplSession(session))); + + mfxPlatform platform; + memset(&platform, 0, sizeof(platform)); + MFXVideoCORE_QueryPlatform(GetVplSession(session), &platform); + RTC_LOG(LS_VERBOSE) << "--------------- codec=" << CodecToString(codec) + << " CodeName=" << platform.CodeName + << " DeviceId=" << platform.DeviceId + << " MediaAdapterType=" << platform.MediaAdapterType; + + mfxVideoParam param; + ExtBuffer ext; + mfxStatus sts = Queries(encoder.get(), codec, width, height, framerate, + target_kbps, max_kbps, param, ext); + if (sts < MFX_ERR_NONE) { + return nullptr; + } + if (sts > MFX_ERR_NONE) { + RTC_LOG(LS_VERBOSE) << "Supported specified codec but has warning: codec=" + << CodecToString(codec) << " sts=" << sts; + } + + if (init) { + sts = encoder->Init(¶m); + if (sts != MFX_ERR_NONE) { + RTC_LOG(LS_ERROR) << "Failed to Init: sts=" << sts; + return nullptr; + } + } + + return encoder; +} + +mfxStatus VplVideoEncoderImpl::Queries(MFXVideoENCODE* encoder, + mfxU32 codec, + int width, + int height, + int framerate, + int target_kbps, + int max_kbps, + mfxVideoParam& param, + ExtBuffer& ext) { + mfxStatus sts = MFX_ERR_NONE; + + memset(¶m, 0, sizeof(param)); + + param.mfx.CodecId = codec; + if (codec == MFX_CODEC_VP8) { + //param.mfx.CodecProfile = MFX_PROFILE_VP8_0; + } else if (codec == MFX_CODEC_VP9) { + //param.mfx.CodecProfile = MFX_PROFILE_VP9_0; + } else if (codec == MFX_CODEC_AVC) { + //param.mfx.CodecProfile = MFX_PROFILE_AVC_HIGH; + //param.mfx.CodecLevel = MFX_LEVEL_AVC_51; + //param.mfx.CodecProfile = MFX_PROFILE_AVC_MAIN; + //param.mfx.CodecLevel = MFX_LEVEL_AVC_1; + } else if (codec == MFX_CODEC_HEVC) { + // param.mfx.CodecProfile = MFX_PROFILE_HEVC_MAIN; + // param.mfx.CodecLevel = MFX_LEVEL_HEVC_1; + // param.mfx.LowPower = MFX_CODINGOPTION_OFF; + } else if (codec == MFX_CODEC_AV1) { + //param.mfx.CodecProfile = MFX_PROFILE_AV1_MAIN; + } + + param.mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED; + + param.mfx.TargetKbps = target_kbps; + param.mfx.MaxKbps = max_kbps; + param.mfx.RateControlMethod = MFX_RATECONTROL_VBR; + param.mfx.FrameInfo.FrameRateExtN = framerate; + param.mfx.FrameInfo.FrameRateExtD = 1; + param.mfx.FrameInfo.FourCC = MFX_FOURCC_NV12; + param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + param.mfx.FrameInfo.CropX = 0; + param.mfx.FrameInfo.CropY = 0; + param.mfx.FrameInfo.CropW = width; + param.mfx.FrameInfo.CropH = height; + // Width must be a multiple of 16 + // Height must be a multiple of 16 in case of frame picture and a multiple of 32 in case of field picture + param.mfx.FrameInfo.Width = (width + 15) / 16 * 16; + param.mfx.FrameInfo.Height = (height + 15) / 16 * 16; + + param.mfx.GopRefDist = 1; + param.AsyncDepth = 1; + param.IOPattern = + MFX_IOPATTERN_IN_SYSTEM_MEMORY | MFX_IOPATTERN_OUT_SYSTEM_MEMORY; + + mfxExtBuffer** ext_buffers = ext.ext_buffers; + mfxExtCodingOption& ext_coding_option = ext.ext_coding_option; + mfxExtCodingOption2& ext_coding_option2 = ext.ext_coding_option2; + int ext_buffers_size = 0; + if (codec == MFX_CODEC_AVC) { + memset(&ext_coding_option, 0, sizeof(ext_coding_option)); + ext_coding_option.Header.BufferId = MFX_EXTBUFF_CODING_OPTION; + ext_coding_option.Header.BufferSz = sizeof(ext_coding_option); + ext_coding_option.AUDelimiter = MFX_CODINGOPTION_OFF; + ext_coding_option.MaxDecFrameBuffering = 1; + //ext_coding_option.NalHrdConformance = MFX_CODINGOPTION_OFF; + //ext_coding_option.VuiVclHrdParameters = MFX_CODINGOPTION_ON; + //ext_coding_option.SingleSeiNalUnit = MFX_CODINGOPTION_ON; + //ext_coding_option.RefPicMarkRep = MFX_CODINGOPTION_OFF; + //ext_coding_option.PicTimingSEI = MFX_CODINGOPTION_OFF; + //ext_coding_option.RecoveryPointSEI = MFX_CODINGOPTION_OFF; + //ext_coding_option.FramePicture = MFX_CODINGOPTION_OFF; + //ext_coding_option.FieldOutput = MFX_CODINGOPTION_ON; + + memset(&ext_coding_option2, 0, sizeof(ext_coding_option2)); + ext_coding_option2.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; + ext_coding_option2.Header.BufferSz = sizeof(ext_coding_option2); + ext_coding_option2.RepeatPPS = MFX_CODINGOPTION_ON; + //ext_coding_option2.MaxSliceSize = 1; + //ext_coding_option2.AdaptiveI = MFX_CODINGOPTION_ON; + + ext_buffers[0] = (mfxExtBuffer*)&ext_coding_option; + ext_buffers[1] = (mfxExtBuffer*)&ext_coding_option2; + ext_buffers_size = 2; + } else if (codec == MFX_CODEC_HEVC) { + memset(&ext_coding_option2, 0, sizeof(ext_coding_option2)); + ext_coding_option2.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; + ext_coding_option2.Header.BufferSz = sizeof(ext_coding_option2); + ext_coding_option2.RepeatPPS = MFX_CODINGOPTION_ON; + + ext_buffers[0] = (mfxExtBuffer*)&ext_coding_option2; + ext_buffers_size = 1; + } + + if (ext_buffers_size != 0) { + param.ExtParam = ext_buffers; + param.NumExtParam = ext_buffers_size; + } + + // Query 関数を呼び出す。 + // 失敗した場合 param は一切書き換わらない + // 成功した場合 param は書き換わる可能性がある + auto query = [](MFXVideoENCODE* encoder, mfxVideoParam& param) { + mfxVideoParam query_param; + memcpy(&query_param, ¶m, sizeof(param)); + // ドキュメントによると、Query は以下のエラーを返す可能性がある。 + // MFX_ERR_NONE The function completed successfully. + // MFX_ERR_UNSUPPORTED The function failed to identify a specific implementation for the required features. + // MFX_WRN_PARTIAL_ACCELERATION The underlying hardware does not fully support the specified video parameters; The encoding may be partially accelerated. Only SDK HW implementations may return this status code. + // MFX_WRN_INCOMPATIBLE_VIDEO_PARAM The function detected some video parameters were incompatible with others; incompatibility resolved. + mfxStatus sts = encoder->Query(&query_param, &query_param); + if (sts >= 0) { + // デバッグ用。 + // Query によってどのパラメータが変更されたかを表示する + // #define F(NAME) \ + // if (param.NAME != query_param.NAME) \ + // std::cout << "param " << #NAME << " old=" << param.NAME \ + // << " new=" << query_param.NAME << std::endl + // F(mfx.LowPower); + // F(mfx.BRCParamMultiplier); + // F(mfx.FrameInfo.FrameRateExtN); + // F(mfx.FrameInfo.FrameRateExtD); + // F(mfx.FrameInfo.FourCC); + // F(mfx.FrameInfo.ChromaFormat); + // F(mfx.FrameInfo.PicStruct); + // F(mfx.FrameInfo.CropX); + // F(mfx.FrameInfo.CropY); + // F(mfx.FrameInfo.CropW); + // F(mfx.FrameInfo.CropH); + // F(mfx.FrameInfo.Width); + // F(mfx.FrameInfo.Height); + // F(mfx.CodecId); + // F(mfx.CodecProfile); + // F(mfx.CodecLevel); + // F(mfx.GopPicSize); + // F(mfx.GopRefDist); + // F(mfx.GopOptFlag); + // F(mfx.IdrInterval); + // F(mfx.TargetUsage); + // F(mfx.RateControlMethod); + // F(mfx.InitialDelayInKB); + // F(mfx.TargetKbps); + // F(mfx.MaxKbps); + // F(mfx.BufferSizeInKB); + // F(mfx.NumSlice); + // F(mfx.NumRefFrame); + // F(mfx.EncodedOrder); + // F(mfx.DecodedOrder); + // F(mfx.ExtendedPicStruct); + // F(mfx.TimeStampCalc); + // F(mfx.SliceGroupsPresent); + // F(mfx.MaxDecFrameBuffering); + // F(mfx.EnableReallocRequest); + // F(AsyncDepth); + // F(IOPattern); + // #undef F + + memcpy(¶m, &query_param, sizeof(param)); + } + return sts; + }; + + // ここからは、ひたすらパラメータを変えて query を呼び出していく + sts = query(encoder, param); + if (sts >= 0) { + return sts; + } + + // IOPattern を MFX_IOPATTERN_IN_SYSTEM_MEMORY のみにしてみる + // Coffee Lake の H265 はこのパターンでないと通らない + RTC_LOG(LS_VERBOSE) << "Unsupported encoder codec: codec=" + << CodecToString(codec) << " sts=" << sts + << " ... Retry with IOPattern IN_SYSTEM_MEMORY only"; + param.IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY; + sts = query(encoder, param); + if (sts >= 0) { + return sts; + } + + // LowPower ON にして、更に H264/H265 は固定 QP モードにしてみる + RTC_LOG(LS_VERBOSE) << "Unsupported encoder codec: codec=" + << CodecToString(codec) << " sts=" << sts + << " ... Retry with low power mode"; + param.mfx.LowPower = MFX_CODINGOPTION_ON; + if (codec == MFX_CODEC_AVC || codec == MFX_CODEC_HEVC) { + param.mfx.RateControlMethod = MFX_RATECONTROL_CQP; + param.mfx.QPI = 25; + param.mfx.QPP = 33; + param.mfx.QPB = 40; + } + sts = query(encoder, param); + if (sts >= 0) { + return sts; + } + RTC_LOG(LS_VERBOSE) << "Unsupported encoder codec: codec=" + << CodecToString(codec) << " sts=" << sts; + + return sts; +} + +int32_t VplVideoEncoderImpl::InitEncode( + const webrtc::VideoCodec* codec_settings, + int32_t number_of_cores, + size_t max_payload_size) { + RTC_DCHECK(codec_settings); + + int32_t release_ret = Release(); + if (release_ret != WEBRTC_VIDEO_CODEC_OK) { + return release_ret; + } + + width_ = codec_settings->width; + height_ = codec_settings->height; + target_bitrate_bps_ = codec_settings->startBitrate * 1000; + max_bitrate_bps_ = codec_settings->maxBitrate * 1000; + bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); + framerate_ = codec_settings->maxFramerate; + mode_ = codec_settings->mode; + + RTC_LOG(LS_INFO) << "InitEncode " << target_bitrate_bps_ << "bit/sec"; + + // Initialize encoded image. Default buffer size: size of unencoded data. + encoded_image_._encodedWidth = 0; + encoded_image_._encodedHeight = 0; + encoded_image_.set_size(0); + encoded_image_.timing_.flags = + webrtc::VideoSendTiming::TimingFrameFlags::kInvalid; + encoded_image_.content_type_ = + (codec_settings->mode == webrtc::VideoCodecMode::kScreensharing) + ? webrtc::VideoContentType::SCREENSHARE + : webrtc::VideoContentType::UNSPECIFIED; + + if (codec_ == MFX_CODEC_VP9) { + gof_.SetGofInfoVP9(webrtc::TemporalStructureMode::kTemporalStructureMode1); + gof_idx_ = 0; + } + + return InitVpl(); +} +int32_t VplVideoEncoderImpl::RegisterEncodeCompleteCallback( + webrtc::EncodedImageCallback* callback) { + std::lock_guard lock(mutex_); + callback_ = callback; + return WEBRTC_VIDEO_CODEC_OK; +} +int32_t VplVideoEncoderImpl::Release() { + return ReleaseVpl(); +} +int32_t VplVideoEncoderImpl::Encode( + const webrtc::VideoFrame& frame, + const std::vector* frame_types) { + bool send_key_frame = false; + + if (frame_types != nullptr) { + // We only support a single stream. + RTC_DCHECK_EQ(frame_types->size(), static_cast(1)); + // Skip frame? + if ((*frame_types)[0] == webrtc::VideoFrameType::kEmptyFrame) { + return WEBRTC_VIDEO_CODEC_OK; + } + // Force key frame? + send_key_frame = + (*frame_types)[0] == webrtc::VideoFrameType::kVideoFrameKey; + } + + // 使ってない入力サーフェスを取り出す + auto surface = + std::find_if(surfaces_.begin(), surfaces_.end(), + [](const mfxFrameSurface1& s) { return !s.Data.Locked; }); + if (surface == surfaces_.end()) { + RTC_LOG(LS_ERROR) << "Surface not found"; + return WEBRTC_VIDEO_CODEC_ERROR; + } + + // I420 から NV12 に変換 + rtc::scoped_refptr frame_buffer = + frame.video_frame_buffer()->ToI420(); + libyuv::I420ToNV12( + frame_buffer->DataY(), frame_buffer->StrideY(), frame_buffer->DataU(), + frame_buffer->StrideU(), frame_buffer->DataV(), frame_buffer->StrideV(), + surface->Data.Y, surface->Data.Pitch, surface->Data.U, + surface->Data.Pitch, frame_buffer->width(), frame_buffer->height()); + + mfxStatus sts; + + mfxEncodeCtrl ctrl; + memset(&ctrl, 0, sizeof(ctrl)); + //send_key_frame = true; + if (send_key_frame) { + ctrl.FrameType = MFX_FRAMETYPE_I | MFX_FRAMETYPE_IDR | MFX_FRAMETYPE_REF; + } else { + ctrl.FrameType = MFX_FRAMETYPE_UNKNOWN; + } + + if (reconfigure_needed_) { + auto start_time = std::chrono::system_clock::now(); + RTC_LOG(LS_INFO) << "Start reconfigure: bps=" + << (bitrate_adjuster_.GetAdjustedBitrateBps() / 1000) + << " framerate=" << framerate_; + // 今の設定を取得する + mfxVideoParam param; + memset(¶m, 0, sizeof(param)); + + sts = encoder_->GetVideoParam(¶m); + VPL_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + // ビットレートとフレームレートを変更する。 + // なお、encoder_->Reset() はキューイングしているサーフェスを + // 全て処理してから呼び出す必要がある。 + // ここでは encoder_->Init() の時に + // param.mfx.GopRefDist = 1; + // param.AsyncDepth = 1; + // ext_coding_option.MaxDecFrameBuffering = 1; + // を設定して、そもそもキューイングが起きないようにすることで対処している。 + if (param.mfx.RateControlMethod == MFX_RATECONTROL_CQP) { + //param.mfx.QPI = h264_bitstream_parser_.GetLastSliceQp().value_or(30); + } else { + param.mfx.TargetKbps = bitrate_adjuster_.GetAdjustedBitrateBps() / 1000; + } + param.mfx.FrameInfo.FrameRateExtN = framerate_; + param.mfx.FrameInfo.FrameRateExtD = 1; + + sts = encoder_->Reset(¶m); + VPL_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + reconfigure_needed_ = false; + + auto end_time = std::chrono::system_clock::now(); + RTC_LOG(LS_INFO) << "Finish reconfigure: " + << std::chrono::duration_cast( + end_time - start_time) + .count() + << " ms"; + } + + // NV12 をハードウェアエンコード + mfxSyncPoint syncp; + sts = encoder_->EncodeFrameAsync(&ctrl, &*surface, &bitstream_, &syncp); + // alloc_request_.NumFrameSuggested が 1 の場合は MFX_ERR_MORE_DATA は発生しない + if (sts == MFX_ERR_MORE_DATA) { + // もっと入力が必要なので出直す + return WEBRTC_VIDEO_CODEC_OK; + } + VPL_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + sts = MFXVideoCORE_SyncOperation(GetVplSession(session_), syncp, 600000); + VPL_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + //RTC_LOG(LS_ERROR) << "SurfaceSize=" << (surface->Data.U - surface->Data.Y); + //RTC_LOG(LS_ERROR) << "DataLength=" << bitstream_.DataLength; + { + uint8_t* p = bitstream_.Data + bitstream_.DataOffset; + int size = bitstream_.DataLength; + bitstream_.DataLength = 0; + + //FILE* fp = fopen("test.mp4", "a+"); + //fwrite(p, 1, size, fp); + //fclose(fp); + if (codec_ == MFX_CODEC_VP9) { + // VP9 はIVFヘッダーがエンコードフレームについているので取り除く + if ((p[0] == 'D') && (p[1] == 'K') && (p[2] == 'I') && (p[3] == 'F')) { + p += 32; + size -= 32; + } + p += 12; + size -= 12; + } + auto buf = webrtc::EncodedImageBuffer::Create(p, size); + encoded_image_.SetEncodedData(buf); + encoded_image_._encodedWidth = width_; + encoded_image_._encodedHeight = height_; + encoded_image_.content_type_ = + (mode_ == webrtc::VideoCodecMode::kScreensharing) + ? webrtc::VideoContentType::SCREENSHARE + : webrtc::VideoContentType::UNSPECIFIED; + encoded_image_.timing_.flags = webrtc::VideoSendTiming::kInvalid; + encoded_image_.SetRtpTimestamp(frame.timestamp()); + encoded_image_.ntp_time_ms_ = frame.ntp_time_ms(); + encoded_image_.capture_time_ms_ = frame.render_time_ms(); + encoded_image_.rotation_ = frame.rotation(); + encoded_image_.SetColorSpace(frame.color_space()); + if (bitstream_.FrameType & MFX_FRAMETYPE_I || + bitstream_.FrameType & MFX_FRAMETYPE_IDR) { + encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameKey; + } else { + encoded_image_._frameType = webrtc::VideoFrameType::kVideoFrameDelta; + } + + webrtc::CodecSpecificInfo codec_specific; + if (codec_ == MFX_CODEC_VP9) { + codec_specific.codecType = webrtc::kVideoCodecVP9; + bool is_key = + encoded_image_._frameType == webrtc::VideoFrameType::kVideoFrameKey; + if (is_key) { + gof_idx_ = 0; + } + codec_specific.codecSpecific.VP9.inter_pic_predicted = !is_key; + codec_specific.codecSpecific.VP9.flexible_mode = false; + codec_specific.codecSpecific.VP9.ss_data_available = is_key; + codec_specific.codecSpecific.VP9.temporal_idx = webrtc::kNoTemporalIdx; + codec_specific.codecSpecific.VP9.temporal_up_switch = true; + codec_specific.codecSpecific.VP9.inter_layer_predicted = false; + codec_specific.codecSpecific.VP9.gof_idx = + static_cast(gof_idx_++ % gof_.num_frames_in_gof); + codec_specific.codecSpecific.VP9.num_spatial_layers = 1; + codec_specific.codecSpecific.VP9.first_frame_in_picture = true; + codec_specific.codecSpecific.VP9.spatial_layer_resolution_present = false; + if (codec_specific.codecSpecific.VP9.ss_data_available) { + codec_specific.codecSpecific.VP9.spatial_layer_resolution_present = + true; + codec_specific.codecSpecific.VP9.width[0] = + encoded_image_._encodedWidth; + codec_specific.codecSpecific.VP9.height[0] = + encoded_image_._encodedHeight; + codec_specific.codecSpecific.VP9.gof.CopyGofInfoVP9(gof_); + } + webrtc::vp9::GetQp(p, size, &encoded_image_.qp_); + } else if (codec_ == MFX_CODEC_AVC) { + codec_specific.codecType = webrtc::kVideoCodecH264; + codec_specific.codecSpecific.H264.packetization_mode = + webrtc::H264PacketizationMode::NonInterleaved; + + h264_bitstream_parser_.ParseBitstream(encoded_image_); + encoded_image_.qp_ = h264_bitstream_parser_.GetLastSliceQp().value_or(-1); + } else if (codec_ == MFX_CODEC_HEVC) { + codec_specific.codecType = webrtc::kVideoCodecH265; + + h265_bitstream_parser_.ParseBitstream(encoded_image_); + encoded_image_.qp_ = h265_bitstream_parser_.GetLastSliceQp().value_or(-1); + } + + webrtc::EncodedImageCallback::Result result = + callback_->OnEncodedImage(encoded_image_, &codec_specific); + if (result.error != webrtc::EncodedImageCallback::Result::OK) { + RTC_LOG(LS_ERROR) << __FUNCTION__ + << " OnEncodedImage failed error:" << result.error; + return WEBRTC_VIDEO_CODEC_ERROR; + } + bitrate_adjuster_.Update(size); + } + + return WEBRTC_VIDEO_CODEC_OK; +} +void VplVideoEncoderImpl::SetRates(const RateControlParameters& parameters) { + if (parameters.framerate_fps < 1.0) { + RTC_LOG(LS_WARNING) << "Invalid frame rate: " << parameters.framerate_fps; + return; + } + + uint32_t new_framerate = (uint32_t)parameters.framerate_fps; + uint32_t new_bitrate = parameters.bitrate.get_sum_bps(); + RTC_LOG(LS_INFO) << __FUNCTION__ << " framerate_:" << framerate_ + << " new_framerate: " << new_framerate + << " target_bitrate_bps_:" << target_bitrate_bps_ + << " new_bitrate:" << new_bitrate + << " max_bitrate_bps_:" << max_bitrate_bps_; + framerate_ = new_framerate; + target_bitrate_bps_ = new_bitrate; + bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); + reconfigure_needed_ = true; +} +webrtc::VideoEncoder::EncoderInfo VplVideoEncoderImpl::GetEncoderInfo() const { + webrtc::VideoEncoder::EncoderInfo info; + info.supports_native_handle = true; + info.implementation_name = "libvpl"; + info.scaling_settings = webrtc::VideoEncoder::ScalingSettings( + kLowH264QpThreshold, kHighH264QpThreshold); + info.is_hardware_accelerated = true; + return info; +} + +int32_t VplVideoEncoderImpl::InitVpl() { + encoder_ = CreateEncoder(session_, codec_, width_, height_, framerate_, + bitrate_adjuster_.GetAdjustedBitrateBps() / 1000, + max_bitrate_bps_ / 1000, true); + if (encoder_ == nullptr) { + RTC_LOG(LS_ERROR) << "Failed to create encoder"; + return WEBRTC_VIDEO_CODEC_ERROR; + } + + mfxStatus sts = MFX_ERR_NONE; + + mfxVideoParam param; + memset(¶m, 0, sizeof(param)); + + // Retrieve video parameters selected by encoder. + // - BufferSizeInKB parameter is required to set bit stream buffer size + sts = encoder_->GetVideoParam(¶m); + VPL_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + RTC_LOG(LS_INFO) << "BufferSizeInKB=" << param.mfx.BufferSizeInKB; + + // Query number of required surfaces for encoder + memset(&alloc_request_, 0, sizeof(alloc_request_)); + sts = encoder_->QueryIOSurf(¶m, &alloc_request_); + VPL_CHECK_RESULT(sts, MFX_ERR_NONE, sts); + + RTC_LOG(LS_INFO) << "Encoder NumFrameSuggested=" + << alloc_request_.NumFrameSuggested; + + frame_info_ = param.mfx.FrameInfo; + + // 出力ビットストリームの初期化 + bitstream_buffer_.resize(param.mfx.BufferSizeInKB * 1000); + + memset(&bitstream_, 0, sizeof(bitstream_)); + bitstream_.MaxLength = bitstream_buffer_.size(); + bitstream_.Data = bitstream_buffer_.data(); + + // 必要な枚数分の入力サーフェスを作る + { + int width = (alloc_request_.Info.Width + 31) / 32 * 32; + int height = (alloc_request_.Info.Height + 31) / 32 * 32; + // 1枚あたりのバイト数 + // NV12 なので 1 ピクセルあたり 12 ビット + int size = width * height * 12 / 8; + surface_buffer_.resize(alloc_request_.NumFrameSuggested * size); + + surfaces_.clear(); + surfaces_.reserve(alloc_request_.NumFrameSuggested); + for (int i = 0; i < alloc_request_.NumFrameSuggested; i++) { + mfxFrameSurface1 surface; + memset(&surface, 0, sizeof(surface)); + surface.Info = frame_info_; + surface.Data.Y = surface_buffer_.data() + i * size; + surface.Data.U = surface_buffer_.data() + i * size + width * height; + surface.Data.V = surface_buffer_.data() + i * size + width * height + 1; + surface.Data.Pitch = width; + surfaces_.push_back(surface); + } + } + + return WEBRTC_VIDEO_CODEC_OK; +} +int32_t VplVideoEncoderImpl::ReleaseVpl() { + if (encoder_ != nullptr) { + encoder_->Close(); + } + encoder_.reset(); + return WEBRTC_VIDEO_CODEC_OK; +} + +//////////////////////// +// VplVideoEncoder +//////////////////////// + +bool VplVideoEncoder::IsSupported(std::shared_ptr session, + webrtc::VideoCodecType codec) { + if (session == nullptr) { + return false; + } + + auto encoder = VplVideoEncoderImpl::CreateEncoder( + session, ToMfxCodec(codec), 1920, 1080, 30, 10, 20, false); + bool result = encoder != nullptr; + RTC_LOG(LS_VERBOSE) << "IsSupported: codec=" + << CodecToString(ToMfxCodec(codec)) + << " result=" << result; + return result; +} + +std::unique_ptr VplVideoEncoder::Create( + std::shared_ptr session, + webrtc::VideoCodecType codec) { + return std::unique_ptr( + new VplVideoEncoderImpl(session, ToMfxCodec(codec))); +} + +} // namespace sora diff --git a/src/sora-cpp-sdk/src/open_h264_video_encoder.cpp b/src/sora-cpp-sdk/src/open_h264_video_encoder.cpp new file mode 100644 index 00000000..b5ada411 --- /dev/null +++ b/src/sora-cpp-sdk/src/open_h264_video_encoder.cpp @@ -0,0 +1,939 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + */ + +// modules/video_coding/codecs/h264/h264_encoder_impl.{h,cc} の +// OpenH264 の関数を動的に読むようにしただけ + +#include "sora/open_h264_video_encoder.h" + +#include +#include +#include +#include + +#if defined(_WIN32) +// Windows +#include +#else +// Linux +#include +#endif + +// WebRTC +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// OpenH264 +#include +#include +#include +#include + +class ISVCEncoder; + +namespace webrtc { + +class OpenH264VideoEncoder : public VideoEncoder { + public: + struct LayerConfig { + int simulcast_idx = 0; + int width = -1; + int height = -1; + bool sending = true; + bool key_frame_request = false; + float max_frame_rate = 0; + uint32_t target_bps = 0; + uint32_t max_bps = 0; + bool frame_dropping_on = false; + int key_frame_interval = 0; + int num_temporal_layers = 1; + + void SetStreamState(bool send_stream); + }; + + OpenH264VideoEncoder(const Environment& env, + H264EncoderSettings settings, + std::string openh264); + + ~OpenH264VideoEncoder() override; + + // `settings.max_payload_size` is ignored. + // The following members of `codec_settings` are used. The rest are ignored. + // - codecType (must be kVideoCodecH264) + // - targetBitrate + // - maxFramerate + // - width + // - height + int32_t InitEncode(const VideoCodec* codec_settings, + const VideoEncoder::Settings& settings) override; + int32_t Release() override; + + int32_t RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) override; + void SetRates(const RateControlParameters& parameters) override; + + // The result of encoding - an EncodedImage and CodecSpecificInfo - are + // passed to the encode complete callback. + int32_t Encode(const VideoFrame& frame, + const std::vector* frame_types) override; + + EncoderInfo GetEncoderInfo() const override; + + // Exposed for testing. + H264PacketizationMode PacketizationModeForTesting() const { + return packetization_mode_; + } + + private: + SEncParamExt CreateEncoderParams(size_t i) const; + + webrtc::H264BitstreamParser h264_bitstream_parser_; + // Reports statistics with histograms. + void ReportInit(); + void ReportError(); + + std::vector encoders_; + std::vector pictures_; + std::vector> downscaled_buffers_; + std::vector configurations_; + std::vector encoded_images_; + std::vector> svc_controllers_; + absl::InlinedVector, kMaxSimulcastStreams> + scalability_modes_; + + const Environment env_; + VideoCodec codec_; + H264PacketizationMode packetization_mode_; + size_t max_payload_size_; + int32_t number_of_cores_; + absl::optional encoder_thread_limit_; + EncodedImageCallback* encoded_image_callback_; + + bool has_reported_init_; + bool has_reported_error_; + + std::vector tl0sync_limit_; + + private: + bool InitOpenH264(); + void ReleaseOpenH264(); + + std::string openh264_; +#if defined(_WIN32) + HMODULE openh264_handle_ = nullptr; +#else + void* openh264_handle_ = nullptr; +#endif + using CreateEncoderFunc = int (*)(ISVCEncoder**); + using DestroyEncoderFunc = void (*)(ISVCEncoder*); + CreateEncoderFunc create_encoder_ = nullptr; + DestroyEncoderFunc destroy_encoder_ = nullptr; +}; + +} // namespace webrtc + +namespace webrtc { + +namespace { + +const bool kOpenH264EncoderDetailedLogging = false; + +// QP scaling thresholds. +static const int kLowH264QpThreshold = 24; +static const int kHighH264QpThreshold = 37; + +// Used by histograms. Values of entries should not be changed. +enum H264EncoderImplEvent { + kH264EncoderEventInit = 0, + kH264EncoderEventError = 1, + kH264EncoderEventMax = 16, +}; + +int NumberOfThreads(absl::optional encoder_thread_limit, + int width, + int height, + int number_of_cores) { + // TODO(hbos): In Chromium, multiple threads do not work with sandbox on Mac, + // see crbug.com/583348. Until further investigated, only use one thread. + // While this limitation is gone, this changes the bitstream format (see + // bugs.webrtc.org/14368) so still guarded by field trial to allow for + // experimentation using th experimental + // WebRTC-VideoEncoderSettings/encoder_thread_limit trial. + if (encoder_thread_limit.has_value()) { + int limit = encoder_thread_limit.value(); + RTC_DCHECK_GE(limit, 1); + if (width * height >= 1920 * 1080 && number_of_cores > 8) { + return std::min(limit, 8); // 8 threads for 1080p on high perf machines. + } else if (width * height > 1280 * 960 && number_of_cores >= 6) { + return std::min(limit, 3); // 3 threads for 1080p. + } else if (width * height > 640 * 480 && number_of_cores >= 3) { + return std::min(limit, 2); // 2 threads for qHD/HD. + } else { + return 1; // 1 thread for VGA or less. + } + } + // TODO(sprang): Also check sSliceArgument.uiSliceNum on GetEncoderParams(), + // before enabling multithreading here. + return 1; +} + +VideoFrameType ConvertToVideoFrameType(EVideoFrameType type) { + switch (type) { + case videoFrameTypeIDR: + return VideoFrameType::kVideoFrameKey; + case videoFrameTypeSkip: + case videoFrameTypeI: + case videoFrameTypeP: + case videoFrameTypeIPMixed: + return VideoFrameType::kVideoFrameDelta; + case videoFrameTypeInvalid: + break; + } + RTC_DCHECK_NOTREACHED() << "Unexpected/invalid frame type: " << type; + return VideoFrameType::kEmptyFrame; +} + +absl::optional ScalabilityModeFromTemporalLayers( + int num_temporal_layers) { + switch (num_temporal_layers) { + case 0: + break; + case 1: + return ScalabilityMode::kL1T1; + case 2: + return ScalabilityMode::kL1T2; + case 3: + return ScalabilityMode::kL1T3; + default: + RTC_DCHECK_NOTREACHED(); + } + return absl::nullopt; +} + +} // namespace + +// Helper method used by OpenH264VideoEncoder::Encode. +// Copies the encoded bytes from `info` to `encoded_image`. The +// `encoded_image->_buffer` may be deleted and reallocated if a bigger buffer is +// required. +// +// After OpenH264 encoding, the encoded bytes are stored in `info` spread out +// over a number of layers and "NAL units". Each NAL unit is a fragment starting +// with the four-byte start code {0,0,0,1}. All of this data (including the +// start codes) is copied to the `encoded_image->_buffer`. +static void RtpFragmentize(EncodedImage* encoded_image, SFrameBSInfo* info) { + // Calculate minimum buffer size required to hold encoded data. + size_t required_capacity = 0; + size_t fragments_count = 0; + for (int layer = 0; layer < info->iLayerNum; ++layer) { + const SLayerBSInfo& layerInfo = info->sLayerInfo[layer]; + for (int nal = 0; nal < layerInfo.iNalCount; ++nal, ++fragments_count) { + RTC_CHECK_GE(layerInfo.pNalLengthInByte[nal], 0); + // Ensure `required_capacity` will not overflow. + RTC_CHECK_LE(layerInfo.pNalLengthInByte[nal], + std::numeric_limits::max() - required_capacity); + required_capacity += layerInfo.pNalLengthInByte[nal]; + } + } + auto buffer = EncodedImageBuffer::Create(required_capacity); + encoded_image->SetEncodedData(buffer); + + // Iterate layers and NAL units, note each NAL unit as a fragment and copy + // the data to `encoded_image->_buffer`. + const uint8_t start_code[4] = {0, 0, 0, 1}; + size_t frag = 0; + encoded_image->set_size(0); + for (int layer = 0; layer < info->iLayerNum; ++layer) { + const SLayerBSInfo& layerInfo = info->sLayerInfo[layer]; + // Iterate NAL units making up this layer, noting fragments. + size_t layer_len = 0; + for (int nal = 0; nal < layerInfo.iNalCount; ++nal, ++frag) { + // Because the sum of all layer lengths, `required_capacity`, fits in a + // `size_t`, we know that any indices in-between will not overflow. + RTC_DCHECK_GE(layerInfo.pNalLengthInByte[nal], 4); + RTC_DCHECK_EQ(layerInfo.pBsBuf[layer_len + 0], start_code[0]); + RTC_DCHECK_EQ(layerInfo.pBsBuf[layer_len + 1], start_code[1]); + RTC_DCHECK_EQ(layerInfo.pBsBuf[layer_len + 2], start_code[2]); + RTC_DCHECK_EQ(layerInfo.pBsBuf[layer_len + 3], start_code[3]); + layer_len += layerInfo.pNalLengthInByte[nal]; + } + // Copy the entire layer's data (including start codes). + memcpy(buffer->data() + encoded_image->size(), layerInfo.pBsBuf, layer_len); + encoded_image->set_size(encoded_image->size() + layer_len); + } +} + +OpenH264VideoEncoder::OpenH264VideoEncoder(const Environment& env, + H264EncoderSettings settings, + std::string openh264) + : env_(env), + packetization_mode_(settings.packetization_mode), + max_payload_size_(0), + number_of_cores_(0), + encoded_image_callback_(nullptr), + has_reported_init_(false), + has_reported_error_(false), + openh264_(std::move(openh264)) { + downscaled_buffers_.reserve(kMaxSimulcastStreams - 1); + encoded_images_.reserve(kMaxSimulcastStreams); + encoders_.reserve(kMaxSimulcastStreams); + configurations_.reserve(kMaxSimulcastStreams); + tl0sync_limit_.reserve(kMaxSimulcastStreams); + svc_controllers_.reserve(kMaxSimulcastStreams); +} + +OpenH264VideoEncoder::~OpenH264VideoEncoder() { + Release(); + ReleaseOpenH264(); +} + +bool OpenH264VideoEncoder::InitOpenH264() { + if (openh264_handle_ != nullptr) { + return true; + } + +#if defined(_WIN32) + HMODULE handle = LoadLibraryA(openh264_.c_str()); +#else + void* handle = ::dlopen(openh264_.c_str(), RTLD_LAZY); +#endif + if (handle == nullptr) { + return false; + } +#if defined(_WIN32) + create_encoder_ = + (CreateEncoderFunc)::GetProcAddress(handle, "WelsCreateSVCEncoder"); + if (create_encoder_ == nullptr) { + FreeLibrary(handle); + return false; + } + destroy_encoder_ = + (DestroyEncoderFunc)::GetProcAddress(handle, "WelsDestroySVCEncoder"); + if (destroy_encoder_ == nullptr) { + FreeLibrary(handle); + return false; + } +#else + create_encoder_ = (CreateEncoderFunc)::dlsym(handle, "WelsCreateSVCEncoder"); + if (create_encoder_ == nullptr) { + ::dlclose(handle); + return false; + } + destroy_encoder_ = + (DestroyEncoderFunc)::dlsym(handle, "WelsDestroySVCEncoder"); + if (destroy_encoder_ == nullptr) { + ::dlclose(handle); + return false; + } +#endif + openh264_handle_ = handle; + return true; +} + +void OpenH264VideoEncoder::ReleaseOpenH264() { + if (openh264_handle_ != nullptr) { +#if defined(_WIN32) + FreeLibrary(openh264_handle_); +#else + ::dlclose(openh264_handle_); +#endif + openh264_handle_ = nullptr; + } +} + +int32_t OpenH264VideoEncoder::InitEncode( + const VideoCodec* inst, + const VideoEncoder::Settings& settings) { + ReportInit(); + if (!inst || inst->codecType != kVideoCodecH264) { + ReportError(); + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + if (inst->maxFramerate == 0) { + ReportError(); + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + if (inst->width < 1 || inst->height < 1) { + ReportError(); + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + } + + int32_t release_ret = Release(); + if (release_ret != WEBRTC_VIDEO_CODEC_OK) { + ReportError(); + return release_ret; + } + + if (!InitOpenH264()) { + ReportError(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + + int number_of_streams = SimulcastUtility::NumberOfSimulcastStreams(*inst); + bool doing_simulcast = (number_of_streams > 1); + + if (doing_simulcast && + !SimulcastUtility::ValidSimulcastParameters(*inst, number_of_streams)) { + return WEBRTC_VIDEO_CODEC_ERR_SIMULCAST_PARAMETERS_NOT_SUPPORTED; + } + downscaled_buffers_.resize(number_of_streams - 1); + encoded_images_.resize(number_of_streams); + encoders_.resize(number_of_streams); + pictures_.resize(number_of_streams); + svc_controllers_.resize(number_of_streams); + scalability_modes_.resize(number_of_streams); + configurations_.resize(number_of_streams); + tl0sync_limit_.resize(number_of_streams); + + max_payload_size_ = settings.max_payload_size; + number_of_cores_ = settings.number_of_cores; + encoder_thread_limit_ = settings.encoder_thread_limit; + codec_ = *inst; + + // Code expects simulcastStream resolutions to be correct, make sure they are + // filled even when there are no simulcast layers. + if (codec_.numberOfSimulcastStreams == 0) { + codec_.simulcastStream[0].width = codec_.width; + codec_.simulcastStream[0].height = codec_.height; + } + + for (int i = 0, idx = number_of_streams - 1; i < number_of_streams; + ++i, --idx) { + ISVCEncoder* openh264_encoder; + // Create encoder. + if (create_encoder_(&openh264_encoder) != 0) { + // Failed to create encoder. + RTC_LOG(LS_ERROR) << "Failed to create OpenH264 encoder"; + RTC_DCHECK(!openh264_encoder); + Release(); + ReportError(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + RTC_DCHECK(openh264_encoder); + if (kOpenH264EncoderDetailedLogging) { + int trace_level = WELS_LOG_DETAIL; + openh264_encoder->SetOption(ENCODER_OPTION_TRACE_LEVEL, &trace_level); + } + // else WELS_LOG_DEFAULT is used by default. + + // Store h264 encoder. + encoders_[i] = openh264_encoder; + + // Set internal settings from codec_settings + configurations_[i].simulcast_idx = idx; + configurations_[i].sending = false; + configurations_[i].width = codec_.simulcastStream[idx].width; + configurations_[i].height = codec_.simulcastStream[idx].height; + configurations_[i].max_frame_rate = static_cast(codec_.maxFramerate); + configurations_[i].frame_dropping_on = codec_.GetFrameDropEnabled(); + configurations_[i].key_frame_interval = codec_.H264()->keyFrameInterval; + configurations_[i].num_temporal_layers = + std::max(codec_.H264()->numberOfTemporalLayers, + codec_.simulcastStream[idx].numberOfTemporalLayers); + + // Create downscaled image buffers. + if (i > 0) { + downscaled_buffers_[i - 1] = I420Buffer::Create( + configurations_[i].width, configurations_[i].height, + configurations_[i].width, configurations_[i].width / 2, + configurations_[i].width / 2); + } + + // Codec_settings uses kbits/second; encoder uses bits/second. + configurations_[i].max_bps = codec_.maxBitrate * 1000; + configurations_[i].target_bps = codec_.startBitrate * 1000; + + // Create encoder parameters based on the layer configuration. + SEncParamExt encoder_params = CreateEncoderParams(i); + + // Initialize. + if (openh264_encoder->InitializeExt(&encoder_params) != 0) { + RTC_LOG(LS_ERROR) << "Failed to initialize OpenH264 encoder"; + Release(); + ReportError(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + // TODO(pbos): Base init params on these values before submitting. + int video_format = EVideoFormatType::videoFormatI420; + openh264_encoder->SetOption(ENCODER_OPTION_DATAFORMAT, &video_format); + + // Initialize encoded image. Default buffer size: size of unencoded data. + + const size_t new_capacity = + CalcBufferSize(VideoType::kI420, codec_.simulcastStream[idx].width, + codec_.simulcastStream[idx].height); + encoded_images_[i].SetEncodedData(EncodedImageBuffer::Create(new_capacity)); + encoded_images_[i]._encodedWidth = codec_.simulcastStream[idx].width; + encoded_images_[i]._encodedHeight = codec_.simulcastStream[idx].height; + encoded_images_[i].set_size(0); + + tl0sync_limit_[i] = configurations_[i].num_temporal_layers; + scalability_modes_[i] = ScalabilityModeFromTemporalLayers( + configurations_[i].num_temporal_layers); + if (scalability_modes_[i].has_value()) { + svc_controllers_[i] = CreateScalabilityStructure(*scalability_modes_[i]); + if (svc_controllers_[i] == nullptr) { + RTC_LOG(LS_ERROR) << "Failed to create scalability structure"; + Release(); + ReportError(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + } + } + + SimulcastRateAllocator init_allocator(env_, codec_); + VideoBitrateAllocation allocation = + init_allocator.Allocate(VideoBitrateAllocationParameters( + DataRate::KilobitsPerSec(codec_.startBitrate), codec_.maxFramerate)); + SetRates(RateControlParameters(allocation, codec_.maxFramerate)); + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t OpenH264VideoEncoder::Release() { + while (!encoders_.empty()) { + ISVCEncoder* openh264_encoder = encoders_.back(); + if (openh264_encoder) { + RTC_CHECK_EQ(0, openh264_encoder->Uninitialize()); + destroy_encoder_(openh264_encoder); + } + encoders_.pop_back(); + } + downscaled_buffers_.clear(); + configurations_.clear(); + encoded_images_.clear(); + pictures_.clear(); + tl0sync_limit_.clear(); + svc_controllers_.clear(); + scalability_modes_.clear(); + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t OpenH264VideoEncoder::RegisterEncodeCompleteCallback( + EncodedImageCallback* callback) { + encoded_image_callback_ = callback; + return WEBRTC_VIDEO_CODEC_OK; +} + +void OpenH264VideoEncoder::SetRates(const RateControlParameters& parameters) { + if (encoders_.empty()) { + RTC_LOG(LS_WARNING) << "SetRates() while uninitialized."; + return; + } + + if (parameters.framerate_fps < 1.0) { + RTC_LOG(LS_WARNING) << "Invalid frame rate: " << parameters.framerate_fps; + return; + } + + if (parameters.bitrate.get_sum_bps() == 0) { + // Encoder paused, turn off all encoding. + for (size_t i = 0; i < configurations_.size(); ++i) { + configurations_[i].SetStreamState(false); + } + return; + } + + codec_.maxFramerate = static_cast(parameters.framerate_fps); + + size_t stream_idx = encoders_.size() - 1; + for (size_t i = 0; i < encoders_.size(); ++i, --stream_idx) { + // Update layer config. + configurations_[i].target_bps = + parameters.bitrate.GetSpatialLayerSum(stream_idx); + configurations_[i].max_frame_rate = parameters.framerate_fps; + + if (configurations_[i].target_bps) { + configurations_[i].SetStreamState(true); + + // Update h264 encoder. + SBitrateInfo target_bitrate; + memset(&target_bitrate, 0, sizeof(SBitrateInfo)); + target_bitrate.iLayer = SPATIAL_LAYER_ALL, + target_bitrate.iBitrate = configurations_[i].target_bps; + encoders_[i]->SetOption(ENCODER_OPTION_BITRATE, &target_bitrate); + encoders_[i]->SetOption(ENCODER_OPTION_FRAME_RATE, + &configurations_[i].max_frame_rate); + } else { + configurations_[i].SetStreamState(false); + } + } +} + +int32_t OpenH264VideoEncoder::Encode( + const VideoFrame& input_frame, + const std::vector* frame_types) { + if (encoders_.empty()) { + ReportError(); + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + if (!encoded_image_callback_) { + RTC_LOG(LS_WARNING) + << "InitEncode() has been called, but a callback function " + "has not been set with RegisterEncodeCompleteCallback()"; + ReportError(); + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + } + + rtc::scoped_refptr frame_buffer = + input_frame.video_frame_buffer()->ToI420(); + if (!frame_buffer) { + RTC_LOG(LS_ERROR) << "Failed to convert " + << VideoFrameBufferTypeToString( + input_frame.video_frame_buffer()->type()) + << " image to I420. Can't encode frame."; + return WEBRTC_VIDEO_CODEC_ENCODER_FAILURE; + } + RTC_CHECK(frame_buffer->type() == VideoFrameBuffer::Type::kI420 || + frame_buffer->type() == VideoFrameBuffer::Type::kI420A); + + bool is_keyframe_needed = false; + for (size_t i = 0; i < configurations_.size(); ++i) { + if (configurations_[i].key_frame_request && configurations_[i].sending) { + // This is legacy behavior, generating a keyframe on all layers + // when generating one for a layer that became active for the first time + // or after being disabled. + is_keyframe_needed = true; + break; + } + } + + RTC_DCHECK_EQ(configurations_[0].width, frame_buffer->width()); + RTC_DCHECK_EQ(configurations_[0].height, frame_buffer->height()); + + // Encode image for each layer. + for (size_t i = 0; i < encoders_.size(); ++i) { + // EncodeFrame input. + pictures_[i] = {0}; + pictures_[i].iPicWidth = configurations_[i].width; + pictures_[i].iPicHeight = configurations_[i].height; + pictures_[i].iColorFormat = EVideoFormatType::videoFormatI420; + pictures_[i].uiTimeStamp = input_frame.ntp_time_ms(); + // Downscale images on second and ongoing layers. + if (i == 0) { + pictures_[i].iStride[0] = frame_buffer->StrideY(); + pictures_[i].iStride[1] = frame_buffer->StrideU(); + pictures_[i].iStride[2] = frame_buffer->StrideV(); + pictures_[i].pData[0] = const_cast(frame_buffer->DataY()); + pictures_[i].pData[1] = const_cast(frame_buffer->DataU()); + pictures_[i].pData[2] = const_cast(frame_buffer->DataV()); + } else { + pictures_[i].iStride[0] = downscaled_buffers_[i - 1]->StrideY(); + pictures_[i].iStride[1] = downscaled_buffers_[i - 1]->StrideU(); + pictures_[i].iStride[2] = downscaled_buffers_[i - 1]->StrideV(); + pictures_[i].pData[0] = + const_cast(downscaled_buffers_[i - 1]->DataY()); + pictures_[i].pData[1] = + const_cast(downscaled_buffers_[i - 1]->DataU()); + pictures_[i].pData[2] = + const_cast(downscaled_buffers_[i - 1]->DataV()); + // Scale the image down a number of times by downsampling factor. + libyuv::I420Scale(pictures_[i - 1].pData[0], pictures_[i - 1].iStride[0], + pictures_[i - 1].pData[1], pictures_[i - 1].iStride[1], + pictures_[i - 1].pData[2], pictures_[i - 1].iStride[2], + configurations_[i - 1].width, + configurations_[i - 1].height, pictures_[i].pData[0], + pictures_[i].iStride[0], pictures_[i].pData[1], + pictures_[i].iStride[1], pictures_[i].pData[2], + pictures_[i].iStride[2], configurations_[i].width, + configurations_[i].height, libyuv::kFilterBox); + } + + if (!configurations_[i].sending) { + continue; + } + if (frame_types != nullptr && i < frame_types->size()) { + // Skip frame? + if ((*frame_types)[i] == VideoFrameType::kEmptyFrame) { + continue; + } + } + // Send a key frame either when this layer is configured to require one + // or we have explicitly been asked to. + const size_t simulcast_idx = + static_cast(configurations_[i].simulcast_idx); + bool send_key_frame = + is_keyframe_needed || + (frame_types && simulcast_idx < frame_types->size() && + (*frame_types)[simulcast_idx] == VideoFrameType::kVideoFrameKey); + if (send_key_frame) { + // API doc says ForceIntraFrame(false) does nothing, but calling this + // function forces a key frame regardless of the `bIDR` argument's value. + // (If every frame is a key frame we get lag/delays.) + encoders_[i]->ForceIntraFrame(true); + configurations_[i].key_frame_request = false; + } + // EncodeFrame output. + SFrameBSInfo info; + memset(&info, 0, sizeof(SFrameBSInfo)); + + std::vector layer_frames; + if (svc_controllers_[i]) { + layer_frames = svc_controllers_[i]->NextFrameConfig(send_key_frame); + RTC_CHECK_EQ(layer_frames.size(), 1); + } + + // Encode! + int enc_ret = encoders_[i]->EncodeFrame(&pictures_[i], &info); + if (enc_ret != 0) { + RTC_LOG(LS_ERROR) + << "OpenH264 frame encoding failed, EncodeFrame returned " << enc_ret + << "."; + ReportError(); + return WEBRTC_VIDEO_CODEC_ERROR; + } + + encoded_images_[i]._encodedWidth = configurations_[i].width; + encoded_images_[i]._encodedHeight = configurations_[i].height; + encoded_images_[i].SetRtpTimestamp(input_frame.rtp_timestamp()); + encoded_images_[i].SetColorSpace(input_frame.color_space()); + encoded_images_[i]._frameType = ConvertToVideoFrameType(info.eFrameType); + encoded_images_[i].SetSimulcastIndex(configurations_[i].simulcast_idx); + + // Split encoded image up into fragments. This also updates + // `encoded_image_`. + RtpFragmentize(&encoded_images_[i], &info); + + // Encoder can skip frames to save bandwidth in which case + // `encoded_images_[i]._length` == 0. + if (encoded_images_[i].size() > 0) { + // Parse QP. + h264_bitstream_parser_.ParseBitstream(encoded_images_[i]); + encoded_images_[i].qp_ = + h264_bitstream_parser_.GetLastSliceQp().value_or(-1); + + // Deliver encoded image. + CodecSpecificInfo codec_specific; + codec_specific.codecType = kVideoCodecH264; + codec_specific.codecSpecific.H264.packetization_mode = + packetization_mode_; + codec_specific.codecSpecific.H264.temporal_idx = kNoTemporalIdx; + codec_specific.codecSpecific.H264.idr_frame = + info.eFrameType == videoFrameTypeIDR; + codec_specific.codecSpecific.H264.base_layer_sync = false; + if (configurations_[i].num_temporal_layers > 1) { + const uint8_t tid = info.sLayerInfo[0].uiTemporalId; + codec_specific.codecSpecific.H264.temporal_idx = tid; + codec_specific.codecSpecific.H264.base_layer_sync = + tid > 0 && tid < tl0sync_limit_[i]; + if (svc_controllers_[i]) { + if (encoded_images_[i]._frameType == VideoFrameType::kVideoFrameKey) { + // Reset the ScalableVideoController on key frame + // to reset the expected dependency structure. + layer_frames = + svc_controllers_[i]->NextFrameConfig(/* restart= */ true); + RTC_CHECK_EQ(layer_frames.size(), 1); + RTC_DCHECK_EQ(layer_frames[0].TemporalId(), 0); + RTC_DCHECK_EQ(layer_frames[0].IsKeyframe(), true); + } + + if (layer_frames[0].TemporalId() != tid) { + RTC_LOG(LS_WARNING) + << "Encoder produced a frame with temporal id " << tid + << ", expected " << layer_frames[0].TemporalId() << "."; + continue; + } + encoded_images_[i].SetTemporalIndex(tid); + } + if (codec_specific.codecSpecific.H264.base_layer_sync) { + tl0sync_limit_[i] = tid; + } + if (tid == 0) { + tl0sync_limit_[i] = configurations_[i].num_temporal_layers; + } + } + if (svc_controllers_[i]) { + codec_specific.generic_frame_info = + svc_controllers_[i]->OnEncodeDone(layer_frames[0]); + if (send_key_frame && codec_specific.generic_frame_info.has_value()) { + codec_specific.template_structure = + svc_controllers_[i]->DependencyStructure(); + } + codec_specific.scalability_mode = scalability_modes_[i]; + } + encoded_image_callback_->OnEncodedImage(encoded_images_[i], + &codec_specific); + } + } + return WEBRTC_VIDEO_CODEC_OK; +} + +// Initialization parameters. +// There are two ways to initialize. There is SEncParamBase (cleared with +// memset(&p, 0, sizeof(SEncParamBase)) used in Initialize, and SEncParamExt +// which is a superset of SEncParamBase (cleared with GetDefaultParams) used +// in InitializeExt. +SEncParamExt OpenH264VideoEncoder::CreateEncoderParams(size_t i) const { + SEncParamExt encoder_params; + encoders_[i]->GetDefaultParams(&encoder_params); + if (codec_.mode == VideoCodecMode::kRealtimeVideo) { + encoder_params.iUsageType = CAMERA_VIDEO_REAL_TIME; + } else if (codec_.mode == VideoCodecMode::kScreensharing) { + encoder_params.iUsageType = SCREEN_CONTENT_REAL_TIME; + } else { + RTC_DCHECK_NOTREACHED(); + } + encoder_params.iPicWidth = configurations_[i].width; + encoder_params.iPicHeight = configurations_[i].height; + encoder_params.iTargetBitrate = configurations_[i].target_bps; + // Keep unspecified. WebRTC's max codec bitrate is not the same setting + // as OpenH264's iMaxBitrate. More details in https://crbug.com/webrtc/11543 + encoder_params.iMaxBitrate = UNSPECIFIED_BIT_RATE; + // Rate Control mode + encoder_params.iRCMode = RC_BITRATE_MODE; + encoder_params.fMaxFrameRate = configurations_[i].max_frame_rate; + + // The following parameters are extension parameters (they're in SEncParamExt, + // not in SEncParamBase). + encoder_params.bEnableFrameSkip = configurations_[i].frame_dropping_on; + // `uiIntraPeriod` - multiple of GOP size + // `keyFrameInterval` - number of frames + encoder_params.uiIntraPeriod = configurations_[i].key_frame_interval; + // Reuse SPS id if possible. This helps to avoid reset of chromium HW decoder + // on each key-frame. + // Note that WebRTC resets encoder on resolution change which makes all + // EParameterSetStrategy modes except INCREASING_ID (default) essentially + // equivalent to CONSTANT_ID. + encoder_params.eSpsPpsIdStrategy = SPS_LISTING; + encoder_params.uiMaxNalSize = 0; + // Threading model: use auto. + // 0: auto (dynamic imp. internal encoder) + // 1: single thread (default value) + // >1: number of threads + encoder_params.iMultipleThreadIdc = + NumberOfThreads(encoder_thread_limit_, encoder_params.iPicWidth, + encoder_params.iPicHeight, number_of_cores_); + // The base spatial layer 0 is the only one we use. + encoder_params.sSpatialLayers[0].iVideoWidth = encoder_params.iPicWidth; + encoder_params.sSpatialLayers[0].iVideoHeight = encoder_params.iPicHeight; + encoder_params.sSpatialLayers[0].fFrameRate = encoder_params.fMaxFrameRate; + encoder_params.sSpatialLayers[0].iSpatialBitrate = + encoder_params.iTargetBitrate; + encoder_params.sSpatialLayers[0].iMaxSpatialBitrate = + encoder_params.iMaxBitrate; + encoder_params.iTemporalLayerNum = configurations_[i].num_temporal_layers; + if (encoder_params.iTemporalLayerNum > 1) { + // iNumRefFrame specifies total number of reference buffers to allocate. + // For N temporal layers we need at least (N - 1) buffers to store last + // encoded frames of all reference temporal layers. + // Note that there is no API in OpenH264 encoder to specify exact set of + // references to be used to prediction of a given frame. Encoder can + // theoretically use all available reference buffers. + encoder_params.iNumRefFrame = encoder_params.iTemporalLayerNum - 1; + } + RTC_LOG(LS_INFO) << "OpenH264 version is " << OPENH264_MAJOR << "." + << OPENH264_MINOR; + switch (packetization_mode_) { + case H264PacketizationMode::SingleNalUnit: + // Limit the size of the packets produced. + encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceNum = 1; + encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceMode = + SM_SIZELIMITED_SLICE; + encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceSizeConstraint = + static_cast(max_payload_size_); + RTC_LOG(LS_INFO) << "Encoder is configured with NALU constraint: " + << max_payload_size_ << " bytes"; + break; + case H264PacketizationMode::NonInterleaved: + // When uiSliceMode = SM_FIXEDSLCNUM_SLICE, uiSliceNum = 0 means auto + // design it with cpu core number. + // TODO(sprang): Set to 0 when we understand why the rate controller borks + // when uiSliceNum > 1. + encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceNum = 1; + encoder_params.sSpatialLayers[0].sSliceArgument.uiSliceMode = + SM_FIXEDSLCNUM_SLICE; + break; + } + return encoder_params; +} + +void OpenH264VideoEncoder::ReportInit() { + if (has_reported_init_) + return; + RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.OpenH264VideoEncoder.Event", + kH264EncoderEventInit, kH264EncoderEventMax); + has_reported_init_ = true; +} + +void OpenH264VideoEncoder::ReportError() { + if (has_reported_error_) + return; + RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.OpenH264VideoEncoder.Event", + kH264EncoderEventError, kH264EncoderEventMax); + has_reported_error_ = true; +} + +VideoEncoder::EncoderInfo OpenH264VideoEncoder::GetEncoderInfo() const { + EncoderInfo info; + info.supports_native_handle = false; + info.implementation_name = "OpenH264"; + info.scaling_settings = + VideoEncoder::ScalingSettings(kLowH264QpThreshold, kHighH264QpThreshold); + info.is_hardware_accelerated = false; + info.supports_simulcast = true; + info.preferred_pixel_formats = {VideoFrameBuffer::Type::kI420}; + return info; +} + +void OpenH264VideoEncoder::LayerConfig::SetStreamState(bool send_stream) { + if (send_stream && !sending) { + // Need a key frame if we have not sent this stream before. + key_frame_request = true; + } + sending = send_stream; +} + +} // namespace webrtc + +namespace sora { + +std::unique_ptr CreateOpenH264VideoEncoder( + const webrtc::SdpVideoFormat& format, + std::string openh264) { + webrtc::H264EncoderSettings settings; + if (auto it = format.parameters.find(cricket::kH264FmtpPacketizationMode); + it != format.parameters.end()) { + if (it->second == "0") { + settings.packetization_mode = + webrtc::H264PacketizationMode::SingleNalUnit; + } else if (it->second == "1") { + settings.packetization_mode = + webrtc::H264PacketizationMode::NonInterleaved; + } + } + + return absl::make_unique( + webrtc::CreateEnvironment(), settings, std::move(openh264)); +} + +} // namespace sora diff --git a/src/rtc/scalable_track_source.cpp b/src/sora-cpp-sdk/src/scalable_track_source.cpp similarity index 98% rename from src/rtc/scalable_track_source.cpp rename to src/sora-cpp-sdk/src/scalable_track_source.cpp index 043ebe98..f7de5ad7 100644 --- a/src/rtc/scalable_track_source.cpp +++ b/src/sora-cpp-sdk/src/scalable_track_source.cpp @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "scalable_track_source.h" +#include "sora/scalable_track_source.h" #include @@ -22,6 +22,8 @@ // libyuv #include +namespace sora { + ScalableVideoTrackSource::ScalableVideoTrackSource( ScalableVideoTrackSourceConfig config) : AdaptedVideoTrackSource(4), config_(config) {} @@ -132,3 +134,5 @@ bool ScalableVideoTrackSource::OnCapturedFrame( return true; } + +} // namespace sora diff --git a/src/v4l2_video_capturer/v4l2_video_capturer.cpp b/src/sora-cpp-sdk/src/v4l2/v4l2_video_capturer.cpp similarity index 87% rename from src/v4l2_video_capturer/v4l2_video_capturer.cpp rename to src/sora-cpp-sdk/src/v4l2/v4l2_video_capturer.cpp index 190c40f7..85047f0b 100644 --- a/src/v4l2_video_capturer/v4l2_video_capturer.cpp +++ b/src/sora-cpp-sdk/src/v4l2/v4l2_video_capturer.cpp @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "v4l2_video_capturer.h" +#include "sora/v4l2/v4l2_video_capturer.h" // C #include @@ -34,15 +34,16 @@ #include #include #include -#include #include #include #include #define MJPEG_EOS_SEARCH_SIZE 4096 +namespace sora { + rtc::scoped_refptr V4L2VideoCapturer::Create( - V4L2VideoCapturerConfig config) { + const V4L2VideoCapturerConfig& config) { rtc::scoped_refptr capturer; std::unique_ptr device_info( webrtc::VideoCaptureFactory::CreateDeviceInfo()); @@ -83,7 +84,7 @@ void V4L2VideoCapturer::LogDeviceList( rtc::scoped_refptr V4L2VideoCapturer::Create( webrtc::VideoCaptureModule::DeviceInfo* device_info, - V4L2VideoCapturerConfig config, + const V4L2VideoCapturerConfig& config, size_t capture_device_index) { char device_name[256]; char unique_name[256]; @@ -93,9 +94,15 @@ rtc::scoped_refptr V4L2VideoCapturer::Create( RTC_LOG(LS_WARNING) << "Failed to GetDeviceName"; return nullptr; } + // config.video_device が指定されている場合は、デバイス名かユニーク名と一致する必要がある + if (!(config.video_device.empty() || config.video_device == device_name || + config.video_device == unique_name)) { + return nullptr; + } + rtc::scoped_refptr v4l2_capturer = rtc::make_ref_counted(config); - if (v4l2_capturer->Init((const char*)&unique_name, config.video_device) < 0) { + if (v4l2_capturer->Init(unique_name) < 0) { RTC_LOG(LS_WARNING) << "Failed to create V4L2VideoCapturer(" << unique_name << ")"; return nullptr; @@ -109,7 +116,7 @@ rtc::scoped_refptr V4L2VideoCapturer::Create( return v4l2_capturer; } -V4L2VideoCapturer::V4L2VideoCapturer(V4L2VideoCapturerConfig config) +V4L2VideoCapturer::V4L2VideoCapturer(const V4L2VideoCapturerConfig& config) : ScalableVideoTrackSource(config), _deviceFd(-1), _buffersAllocatedByDevice(-1), @@ -143,29 +150,19 @@ bool V4L2VideoCapturer::FindDevice(const char* deviceUniqueIdUTF8, return false; } -int32_t V4L2VideoCapturer::Init(const char* deviceUniqueIdUTF8, - const std::string& specifiedVideoDevice) { +int32_t V4L2VideoCapturer::Init(const char* deviceUniqueIdUTF8) { int fd; bool found = false; - if (!specifiedVideoDevice.empty()) { - // specifiedVideoDevice が指定されてる場合はそれだけ調べる - if (FindDevice(deviceUniqueIdUTF8, specifiedVideoDevice)) { + /* detect /dev/video [0-63] entries */ + char device[32]; + int n; + for (n = 0; n < 64; n++) { + sprintf(device, "/dev/video%d", n); + if (FindDevice(deviceUniqueIdUTF8, device)) { found = true; - _videoDevice = specifiedVideoDevice; - } - } else { - // specifiedVideoDevice が指定されてない場合は頑張って探す - /* detect /dev/video [0-63] entries */ - char device[32]; - int n; - for (n = 0; n < 64; n++) { - sprintf(device, "/dev/video%d", n); - if (FindDevice(deviceUniqueIdUTF8, device)) { - found = true; - _videoDevice = device; // store the video device - break; - } + _videoDevice = device; // store the video device + break; } } @@ -182,7 +179,7 @@ V4L2VideoCapturer::~V4L2VideoCapturer() { close(_deviceFd); } -int32_t V4L2VideoCapturer::StartCapture(V4L2VideoCapturerConfig config) { +int32_t V4L2VideoCapturer::StartCapture(const V4L2VideoCapturerConfig& config) { if (_captureStarted) { if (config.width == _currentWidth && config.height == _currentHeight) { return 0; @@ -365,11 +362,6 @@ int32_t V4L2VideoCapturer::StopCapture() { return 0; } -bool V4L2VideoCapturer::UseNativeBuffer() { - return _useNative && (_captureVideoType == webrtc::VideoType::kMJPEG || - _captureVideoType == webrtc::VideoType::kI420); -} - // critical section protected by the caller bool V4L2VideoCapturer::AllocateVideoBuffers() { @@ -528,27 +520,19 @@ bool V4L2VideoCapturer::CaptureProcess() { void V4L2VideoCapturer::OnCaptured(uint8_t* data, uint32_t bytesused) { rtc::scoped_refptr dst_buffer = nullptr; - if (UseNativeBuffer()) { - rtc::scoped_refptr native_buffer( - NativeBuffer::Create(_captureVideoType, _currentWidth, _currentHeight)); - memcpy(native_buffer->MutableData(), data, bytesused); - native_buffer->SetLength(bytesused); - dst_buffer = native_buffer; + rtc::scoped_refptr i420_buffer( + webrtc::I420Buffer::Create(_currentWidth, _currentHeight)); + i420_buffer->InitializeData(); + if (libyuv::ConvertToI420( + data, bytesused, i420_buffer.get()->MutableDataY(), + i420_buffer.get()->StrideY(), i420_buffer.get()->MutableDataU(), + i420_buffer.get()->StrideU(), i420_buffer.get()->MutableDataV(), + i420_buffer.get()->StrideV(), 0, 0, _currentWidth, _currentHeight, + _currentWidth, _currentHeight, libyuv::kRotate0, + ConvertVideoType(_captureVideoType)) < 0) { + RTC_LOG(LS_ERROR) << "ConvertToI420 Failed"; } else { - rtc::scoped_refptr i420_buffer( - webrtc::I420Buffer::Create(_currentWidth, _currentHeight)); - i420_buffer->InitializeData(); - if (libyuv::ConvertToI420( - data, bytesused, i420_buffer.get()->MutableDataY(), - i420_buffer.get()->StrideY(), i420_buffer.get()->MutableDataU(), - i420_buffer.get()->StrideU(), i420_buffer.get()->MutableDataV(), - i420_buffer.get()->StrideV(), 0, 0, _currentWidth, _currentHeight, - _currentWidth, _currentHeight, libyuv::kRotate0, - ConvertVideoType(_captureVideoType)) < 0) { - RTC_LOG(LS_ERROR) << "ConvertToI420 Failed"; - } else { - dst_buffer = i420_buffer; - } + dst_buffer = i420_buffer; } if (dst_buffer) { @@ -562,3 +546,5 @@ void V4L2VideoCapturer::OnCaptured(uint8_t* data, uint32_t bytesused) { OnCapturedFrame(video_frame); } } + +} // namespace sora \ No newline at end of file diff --git a/src/sora/sora_client.cpp b/src/sora/sora_client.cpp index f3a015dc..2a07c349 100644 --- a/src/sora/sora_client.cpp +++ b/src/sora/sora_client.cpp @@ -73,8 +73,7 @@ SoraClient::~SoraClient() { if (using_datachannel_ && dc_) { webrtc::DataBuffer disconnect = ConvertToDataBuffer("signaling", R"({"type":"disconnect"})"); - dc_->Close( - disconnect, [dc = dc_]() {}, config_.disconnect_wait_timeout); + dc_->Close(disconnect, [dc = dc_]() {}, config_.disconnect_wait_timeout); dc_ = nullptr; std::this_thread::sleep_for(std::chrono::milliseconds(300)); } @@ -671,7 +670,7 @@ void SoraClient::OnMessage( return; } - boost::json::error_code ec; + boost::system::error_code ec; auto json = boost::json::parse(data, ec); if (ec) { RTC_LOG(LS_ERROR) << "JSON Parse Error ec=" << ec.message(); diff --git a/src/sora/sora_session.cpp b/src/sora/sora_session.cpp index 8a343398..054255e4 100644 --- a/src/sora/sora_session.cpp +++ b/src/sora/sora_session.cpp @@ -72,7 +72,7 @@ void SoraSession::OnRead(boost::system::error_code ec, boost::json::value json_message = {{"result", true}}; SendResponse(CreateOKWithJSON(req_, std::move(json_message))); } else if (req_.target() == "/mute") { - boost::json::error_code ec; + boost::system::error_code ec; boost::json::value recv_json = boost::json::parse(req_.body(), ec); if (ec) { SendResponse(Util::BadRequest(req_, "Invalid JSON")); diff --git a/src/util.cpp b/src/util.cpp index 046101cf..200e629b 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -14,7 +14,7 @@ #include // WebRTC -#include +#include #include "momo_version.h" @@ -52,54 +52,6 @@ void Util::ParseArgs(int argc, bool version = false; bool video_codecs = false; - auto is_valid_force_i420 = CLI::Validator( - [](std::string input) -> std::string { -#if USE_MMAL_ENCODER || USE_JETSON_ENCODER || USE_NVCODEC_ENCODER - return std::string(); -#else - return "Not available because your device does not have this feature."; -#endif - }, - ""); - auto is_valid_hw_mjpeg_decoder = CLI::Validator( - [](std::string input) -> std::string { - if (input == "1") { -#if USE_MMAL_ENCODER || USE_JETSON_ENCODER || USE_NVCODEC_ENCODER || USE_V4L2_ENCODER - return std::string(); -#else - return "Not available because your device does not have this " - "feature."; -#endif - } - return std::string(); - }, - ""); - - auto is_valid_h264 = CLI::Validator( - [](std::string input) -> std::string { -#if USE_H264 - return std::string(); -#else - if (input == "H264") { - return "Not available because your device does not have this " - "feature."; - } - return std::string(); -#endif - }, - ""); - - auto is_sdl_available = CLI::Validator( - [](std::string input) -> std::string { -#if USE_SDL2 - return std::string(); -#else - return "Not available because your device does not have this " - "feature."; -#endif - }, - ""); - auto is_valid_resolution = CLI::Validator( [](std::string input) -> std::string { if (input == "QVGA" || input == "VGA" || input == "HD" || @@ -120,7 +72,7 @@ void Util::ParseArgs(int argc, auto is_valid_screen_capture = CLI::Validator( [](std::string input) -> std::string { -#if USE_SCREEN_CAPTURER +#if defined(USE_SCREEN_CAPTURER) return std::string(); #else return "Not available because your device does not have this feature."; @@ -138,14 +90,12 @@ void Util::ParseArgs(int argc, app.add_flag("--no-audio-device", args.no_audio_device, "Do not use audio device"); app.add_flag( - "--force-i420", args.force_i420, - "Prefer I420 format for video capture (only on supported devices)") - ->check(is_valid_force_i420); + "--force-i420", args.force_i420, + "Prefer I420 format for video capture (only on supported devices)"); app.add_option( "--hw-mjpeg-decoder", args.hw_mjpeg_decoder, "Perform MJPEG deoode and video resize by hardware acceleration " "(only on supported devices)") - ->check(is_valid_hw_mjpeg_decoder) ->transform(CLI::CheckedTransformer(bool_map, CLI::ignore_case)); app.add_flag("--use-libcamera", args.use_libcamera, "Use libcamera for video capture (only on supported devices)"); @@ -159,8 +109,7 @@ void Util::ParseArgs(int argc, #elif defined(__linux__) app.add_option("--video-device", args.video_device, "Use the video input device specified by a name " - "(some device will be used if not specified)") - ->check(CLI::ExistingFile); + "(some device will be used if not specified)"); #endif app.add_option("--resolution", args.resolution, "Video resolution (one of QVGA, VGA, HD, FHD, 4K, or " @@ -175,19 +124,15 @@ void Util::ParseArgs(int argc, "Specifies the quality that is maintained against video degradation") ->check(CLI::IsMember({"BALANCE", "FRAMERATE", "RESOLUTION"})); app.add_flag("--use-sdl", args.use_sdl, - "Show video using SDL (if SDL is available)") - ->check(is_sdl_available); + "Show video using SDL (if SDL is available)"); app.add_option("--window-width", args.window_width, "Window width for videos (if SDL is available)") - ->check(is_sdl_available) ->check(CLI::Range(180, 16384)); app.add_option("--window-height", args.window_height, "Window height for videos (if SDL is available)") - ->check(is_sdl_available) ->check(CLI::Range(180, 16384)); app.add_flag("--fullscreen", args.fullscreen, - "Use fullscreen window for videos (if SDL is available)") - ->check(is_sdl_available); + "Use fullscreen window for videos (if SDL is available)"); app.add_flag("--version", version, "Show version information"); app.add_flag("--insecure", args.insecure, "Allow insecure server connections when using SSL"); @@ -235,8 +180,15 @@ void Util::ParseArgs(int argc, ->transform(f(info.h264_encoders)); app.add_option("--h264-decoder", args.h264_decoder, "H.264 Decoder") ->transform(f(info.h264_decoders)); + app.add_option("--h265-encoder", args.h265_encoder, "H.265 Encoder") + ->transform(f(info.h265_encoders)); + app.add_option("--h265-decoder", args.h265_decoder, "H.265 Decoder") + ->transform(f(info.h265_decoders)); } + app.add_option("--openh264", args.openh264, "OpenH264 dynamic library path") + ->check(CLI::ExistingFile); + auto is_serial_setting_format = CLI::Validator( [](std::string input) -> std::string { try { @@ -300,7 +252,7 @@ void Util::ParseArgs(int argc, "Signaling key"); sora_app - ->add_option("--signaling-url", args.sora_signaling_urls, + ->add_option("--signaling-urls", args.sora_signaling_urls, "Signaling URLs") ->take_all() ->required(); @@ -320,8 +272,7 @@ void Util::ParseArgs(int argc, sora_app ->add_option("--video-codec-type", args.sora_video_codec_type, "Video codec for send") - ->check(CLI::IsMember({"", "VP8", "VP9", "AV1", "H264"})) - ->check(is_valid_h264); + ->check(CLI::IsMember({"", "VP8", "VP9", "AV1", "H264", "H265"})); sora_app ->add_option("--audio-codec-type", args.sora_audio_codec_type, "Audio codec for send") @@ -368,7 +319,7 @@ void Util::ParseArgs(int argc, auto is_json = CLI::Validator( [](std::string input) -> std::string { - boost::json::error_code ec; + boost::system::error_code ec; boost::json::parse(input, ec); if (ec) { return "Value " + input + " is not JSON Value"; @@ -411,13 +362,18 @@ void Util::ParseArgs(int argc, std::cout << "Environment: " << MomoVersion::GetEnvironmentName() << std::endl; std::cout << std::endl; - std::cout << "USE_MMAL_ENCODER=" BOOST_PP_STRINGIZE(USE_MMAL_ENCODER) - << std::endl; - std::cout << "USE_JETSON_ENCODER=" BOOST_PP_STRINGIZE(USE_JETSON_ENCODER) - << std::endl; - std::cout << "USE_NVCODEC_ENCODER=" BOOST_PP_STRINGIZE(USE_NVCODEC_ENCODER) - << std::endl; - std::cout << "USE_SDL2=" BOOST_PP_STRINGIZE(USE_SDL2) << std::endl; +#if defined(USE_JETSON_ENCODER) + std::cout << "- USE_JETSON_ENCODER"; +#endif +#if defined(USE_NVCODEC_ENCODER) + std::cout << "- USE_NVCODEC_ENCODER"; +#endif +#if defined(USE_V4L2_ENCODER) + std::cout << "- USE_V4L2_ENCODER"; +#endif +#if defined(USE_VPL_ENCODER) + std::cout << "- USE_VPL_ENCODER"; +#endif exit(0); } @@ -497,6 +453,12 @@ void Util::ShowVideoCodecs(VideoCodecInfo info) { list_codecs(info.h264_encoders); std::cout << " Decoder:" << std::endl; list_codecs(info.h264_decoders); + std::cout << "" << std::endl; + std::cout << "H265:" << std::endl; + std::cout << " Encoder:" << std::endl; + list_codecs(info.h265_encoders); + std::cout << " Decoder:" << std::endl; + list_codecs(info.h265_decoders); } std::string Util::GenerateRandomChars() { diff --git a/src/video_codec_info.h b/src/video_codec_info.h index 66f8c8af..54503860 100644 --- a/src/video_codec_info.h +++ b/src/video_codec_info.h @@ -6,26 +6,25 @@ #include #include -#if USE_NVCODEC_ENCODER -#include "hwenc_nvcodec/nvcodec_h264_encoder.h" -#include "hwenc_nvcodec/nvcodec_video_decoder.h" +#if defined(USE_NVCODEC_ENCODER) +#include "sora/hwenc_nvcodec/nvcodec_video_decoder.h" +#include "sora/hwenc_nvcodec/nvcodec_video_encoder.h" #endif -#if USE_MSDK_ENCODER -#include "hwenc_msdk/msdk_video_decoder.h" -#include "hwenc_msdk/msdk_video_encoder.h" +#if defined(USE_VPL_ENCODER) +#include "sora/hwenc_vpl/vpl_video_decoder.h" +#include "sora/hwenc_vpl/vpl_video_encoder.h" #endif -#if USE_JETSON_ENCODER -#include "hwenc_jetson/jetson_video_decoder.h" -#include "hwenc_jetson/jetson_video_encoder.h" +#if defined(USE_JETSON_ENCODER) +#include "sora/hwenc_jetson/jetson_video_decoder.h" +#include "sora/hwenc_jetson/jetson_video_encoder.h" #endif struct VideoCodecInfo { enum class Type { Default, Jetson, - MMAL, NVIDIA, Intel, VideoToolbox, @@ -46,6 +45,9 @@ struct VideoCodecInfo { std::vector h264_encoders; std::vector h264_decoders; + std::vector h265_encoders; + std::vector h265_decoders; + // Default を解決して、ちゃんとしたエンコーダ名か NotSupported になるようにする static Type Resolve(Type specified, const std::vector& codecs) { if (codecs.empty()) { @@ -77,12 +79,10 @@ struct VideoCodecInfo { switch (type) { case Type::Jetson: return {"Jetson", "jetson"}; - case Type::MMAL: - return {"MMAL", "mmal"}; case Type::NVIDIA: return {"NVIDIA VIDEO CODEC SDK", "nvidia"}; case Type::Intel: - return {"Intel Media SDK", "intel"}; + return {"oneVPL", "vpl"}; case Type::VideoToolbox: return {"VideoToolbox", "videotoolbox"}; case Type::V4L2: @@ -110,46 +110,85 @@ struct VideoCodecInfo { static VideoCodecInfo GetWindows() { VideoCodecInfo info; -#if USE_NVCODEC_ENCODER - if (NvCodecH264Encoder::IsSupported()) { +#if defined(USE_NVCODEC_ENCODER) + auto cuda_context = sora::CudaContext::Create(); + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::VP8)) { + info.vp8_encoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::VP9)) { + info.vp9_encoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::AV1)) { + info.av1_encoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::H264)) { info.h264_encoders.push_back(Type::NVIDIA); } - if (NvCodecVideoDecoder::IsSupported(CudaVideoCodec::VP8)) { + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::H265)) { + info.h265_encoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::VP8)) { info.vp8_decoders.push_back(Type::NVIDIA); } - if (NvCodecVideoDecoder::IsSupported(CudaVideoCodec::VP9)) { + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::VP9)) { info.vp9_decoders.push_back(Type::NVIDIA); } - if (NvCodecVideoDecoder::IsSupported(CudaVideoCodec::H264)) { + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::AV1)) { + info.av1_decoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::H264)) { info.h264_decoders.push_back(Type::NVIDIA); } + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::H265)) { + info.h265_decoders.push_back(Type::NVIDIA); + } #endif -#if USE_MSDK_ENCODER - auto session = MsdkSession::Create(); +#if defined(USE_VPL_ENCODER) + auto session = sora::VplSession::Create(); if (session != nullptr) { - if (MsdkVideoEncoder::IsSupported(session, MFX_CODEC_VP8)) { + if (sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecVP8)) { info.vp8_encoders.push_back(Type::Intel); } - if (MsdkVideoEncoder::IsSupported(session, MFX_CODEC_VP9)) { + if (sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecVP9)) { info.vp9_encoders.push_back(Type::Intel); } - if (MsdkVideoEncoder::IsSupported(session, MFX_CODEC_AVC)) { + if (sora::VplVideoEncoder::IsSupported(session, + webrtc::kVideoCodecH264)) { info.h264_encoders.push_back(Type::Intel); } - if (MsdkVideoEncoder::IsSupported(session, MFX_CODEC_AV1)) { + if (sora::VplVideoEncoder::IsSupported(session, + webrtc::kVideoCodecH265)) { + info.h265_encoders.push_back(Type::Intel); + } + if (sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecAV1)) { info.av1_encoders.push_back(Type::Intel); } - if (MsdkVideoDecoder::IsSupported(session, MFX_CODEC_VP8)) { + if (sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecVP8)) { info.vp8_decoders.push_back(Type::Intel); } - if (MsdkVideoDecoder::IsSupported(session, MFX_CODEC_VP9)) { + if (sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecVP9)) { info.vp9_decoders.push_back(Type::Intel); } - if (MsdkVideoDecoder::IsSupported(session, MFX_CODEC_AVC)) { + if (sora::VplVideoDecoder::IsSupported(session, + webrtc::kVideoCodecH264)) { info.h264_decoders.push_back(Type::Intel); } - if (MsdkVideoDecoder::IsSupported(session, MFX_CODEC_AV1)) { + if (sora::VplVideoDecoder::IsSupported(session, + webrtc::kVideoCodecH265)) { + info.h265_decoders.push_back(Type::Intel); + } + if (sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecAV1)) { info.av1_decoders.push_back(Type::Intel); } } @@ -161,6 +200,7 @@ struct VideoCodecInfo { info.vp9_decoders.push_back(Type::Software); info.av1_encoders.push_back(Type::Software); info.av1_decoders.push_back(Type::Software); + info.h264_encoders.push_back(Type::Software); return info; } @@ -172,12 +212,15 @@ struct VideoCodecInfo { info.h264_encoders.push_back(Type::VideoToolbox); info.h264_decoders.push_back(Type::VideoToolbox); + info.h265_encoders.push_back(Type::VideoToolbox); + info.h265_decoders.push_back(Type::VideoToolbox); info.vp8_encoders.push_back(Type::Software); info.vp9_encoders.push_back(Type::Software); info.vp8_decoders.push_back(Type::Software); info.vp9_decoders.push_back(Type::Software); info.av1_encoders.push_back(Type::Software); info.av1_decoders.push_back(Type::Software); + info.h264_encoders.push_back(Type::Software); return info; } @@ -187,78 +230,124 @@ struct VideoCodecInfo { static VideoCodecInfo GetLinux() { VideoCodecInfo info; -#if USE_NVCODEC_ENCODER - if (NvCodecH264Encoder::IsSupported()) { +#if defined(USE_NVCODEC_ENCODER) + auto cuda_context = sora::CudaContext::Create(); + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::VP8)) { + info.vp8_encoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::VP9)) { + info.vp9_encoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::AV1)) { + info.av1_encoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::H264)) { info.h264_encoders.push_back(Type::NVIDIA); } - if (NvCodecVideoDecoder::IsSupported(CudaVideoCodec::VP8)) { + if (sora::NvCodecVideoEncoder::IsSupported(cuda_context, + sora::CudaVideoCodec::H265)) { + info.h265_encoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::VP8)) { info.vp8_decoders.push_back(Type::NVIDIA); } - if (NvCodecVideoDecoder::IsSupported(CudaVideoCodec::VP9)) { + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::VP9)) { info.vp9_decoders.push_back(Type::NVIDIA); } - if (NvCodecVideoDecoder::IsSupported(CudaVideoCodec::H264)) { + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::AV1)) { + info.av1_decoders.push_back(Type::NVIDIA); + } + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::H264)) { info.h264_decoders.push_back(Type::NVIDIA); } + if (sora::NvCodecVideoDecoder::IsSupported(cuda_context, + sora::CudaVideoCodec::H265)) { + info.h265_decoders.push_back(Type::NVIDIA); + } #endif -#if USE_MSDK_ENCODER - auto session = MsdkSession::Create(); +#if defined(USE_VPL_ENCODER) + auto session = sora::VplSession::Create(); if (session != nullptr) { - if (MsdkVideoEncoder::IsSupported(session, MFX_CODEC_VP8)) { + if (sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecVP8)) { info.vp8_encoders.push_back(Type::Intel); } - if (MsdkVideoEncoder::IsSupported(session, MFX_CODEC_VP9)) { + if (sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecVP9)) { info.vp9_encoders.push_back(Type::Intel); } - if (MsdkVideoEncoder::IsSupported(session, MFX_CODEC_AVC)) { + if (sora::VplVideoEncoder::IsSupported(session, + webrtc::kVideoCodecH264)) { info.h264_encoders.push_back(Type::Intel); } - if (MsdkVideoEncoder::IsSupported(session, MFX_CODEC_AV1)) { + if (sora::VplVideoEncoder::IsSupported(session, + webrtc::kVideoCodecH265)) { + info.h265_encoders.push_back(Type::Intel); + } + if (sora::VplVideoEncoder::IsSupported(session, webrtc::kVideoCodecAV1)) { info.av1_encoders.push_back(Type::Intel); } - if (MsdkVideoDecoder::IsSupported(session, MFX_CODEC_VP8)) { + if (sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecVP8)) { info.vp8_decoders.push_back(Type::Intel); } - if (MsdkVideoDecoder::IsSupported(session, MFX_CODEC_VP9)) { + if (sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecVP9)) { info.vp9_decoders.push_back(Type::Intel); } - if (MsdkVideoDecoder::IsSupported(session, MFX_CODEC_AVC)) { + if (sora::VplVideoDecoder::IsSupported(session, + webrtc::kVideoCodecH264)) { info.h264_decoders.push_back(Type::Intel); } - if (MsdkVideoDecoder::IsSupported(session, MFX_CODEC_AV1)) { + if (sora::VplVideoDecoder::IsSupported(session, + webrtc::kVideoCodecH265)) { + info.h265_decoders.push_back(Type::Intel); + } + if (sora::VplVideoDecoder::IsSupported(session, webrtc::kVideoCodecAV1)) { info.av1_decoders.push_back(Type::Intel); } } #endif -#if USE_MMAL_ENCODER - info.h264_encoders.push_back(Type::MMAL); - info.h264_decoders.push_back(Type::MMAL); -#endif - -#if USE_JETSON_ENCODER - info.h264_encoders.push_back(Type::Jetson); - info.h264_decoders.push_back(Type::Jetson); - if (JetsonVideoEncoder::IsSupportedVP8()) { - info.vp8_encoders.push_back(Type::Jetson); +#if defined(USE_JETSON_ENCODER) + if (sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecH264)) { + info.h264_encoders.push_back(Type::Jetson); } - if (JetsonVideoDecoder::IsSupportedVP8()) { - info.vp8_decoders.push_back(Type::Jetson); + if (sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecH265)) { + info.h265_encoders.push_back(Type::Jetson); + } + if (sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecVP8)) { + info.vp8_encoders.push_back(Type::Jetson); } - if (JetsonVideoEncoder::IsSupportedVP9()) { + if (sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecVP9)) { info.vp9_encoders.push_back(Type::Jetson); } - info.vp9_decoders.push_back(Type::Jetson); - if (JetsonVideoEncoder::IsSupportedAV1()) { + if (sora::JetsonVideoEncoder::IsSupported(webrtc::kVideoCodecAV1)) { info.av1_encoders.push_back(Type::Jetson); } - if (JetsonVideoDecoder::IsSupportedAV1()) { + if (sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecH264)) { + info.h264_decoders.push_back(Type::Jetson); + } + if (sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecH265)) { + info.h265_decoders.push_back(Type::Jetson); + } + if (sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecVP8)) { + info.vp8_decoders.push_back(Type::Jetson); + } + if (sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecVP9)) { + info.vp9_decoders.push_back(Type::Jetson); + } + if (sora::JetsonVideoDecoder::IsSupported(webrtc::kVideoCodecAV1)) { info.av1_decoders.push_back(Type::Jetson); } #endif -#if USE_V4L2_ENCODER +#if defined(USE_V4L2_ENCODER) info.h264_encoders.push_back(Type::V4L2); info.h264_decoders.push_back(Type::V4L2); #endif @@ -267,11 +356,9 @@ struct VideoCodecInfo { info.vp8_decoders.push_back(Type::Software); info.vp9_encoders.push_back(Type::Software); info.vp9_decoders.push_back(Type::Software); - -#if !defined(__arm__) || defined(__aarch64__) || defined(__ARM_NEON__) info.av1_encoders.push_back(Type::Software); info.av1_decoders.push_back(Type::Software); -#endif + info.h264_encoders.push_back(Type::Software); return info; } diff --git a/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp b/third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp similarity index 99% rename from NvCodec/NvCodec/NvDecoder/NvDecoder.cpp rename to third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp index b6d31ddb..d1ce51f1 100644 --- a/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp +++ b/third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.cpp @@ -8,6 +8,7 @@ * is strictly prohibited. * */ +#include "fix_cuda_noinline_macro_error.h" #include #include @@ -15,8 +16,8 @@ #include #include "NvDecoder/NvDecoder.h" -#include "dyn/cuda.h" -#include "dyn/nvcuvid.h" +#include "sora/dyn/cuda.h" +#include "sora/dyn/nvcuvid.h" #define START_TIMER auto start = std::chrono::high_resolution_clock::now(); diff --git a/NvCodec/NvCodec/NvDecoder/NvDecoder.h b/third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.h similarity index 99% rename from NvCodec/NvCodec/NvDecoder/NvDecoder.h rename to third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.h index 19f294b9..f477bcdd 100644 --- a/NvCodec/NvCodec/NvDecoder/NvDecoder.h +++ b/third_party/NvCodec/NvCodec/NvDecoder/NvDecoder.h @@ -21,7 +21,7 @@ #include #include #include "../Utils/NvCodecUtils.h" -#include "dyn/nvcuvid.h" +#include "sora/dyn/nvcuvid.h" #define MAX_FRM_CNT 32 diff --git a/NvCodec/NvCodec/NvEncoder/NvEncoder.cpp b/third_party/NvCodec/NvCodec/NvEncoder/NvEncoder.cpp similarity index 99% rename from NvCodec/NvCodec/NvEncoder/NvEncoder.cpp rename to third_party/NvCodec/NvCodec/NvEncoder/NvEncoder.cpp index 26c490d5..032aee05 100644 --- a/NvCodec/NvCodec/NvEncoder/NvEncoder.cpp +++ b/third_party/NvCodec/NvCodec/NvEncoder/NvEncoder.cpp @@ -8,6 +8,7 @@ * is strictly prohibited. * */ +#include "fix_cuda_noinline_macro_error.h" #include "NvEncoder/NvEncoder.h" @@ -166,13 +167,16 @@ void NvEncoder::LoadNvEncApi() { NV_ENC_ERR_INVALID_VERSION); } - typedef NVENCSTATUS(NVENCAPI *NvEncodeAPICreateInstance_Type)(NV_ENCODE_API_FUNCTION_LIST*); + typedef NVENCSTATUS(NVENCAPI * NvEncodeAPICreateInstance_Type)( + NV_ENCODE_API_FUNCTION_LIST*); #if defined(_WIN32) NvEncodeAPICreateInstance_Type NvEncodeAPICreateInstance = - (NvEncodeAPICreateInstance_Type)GetProcAddress(hModule, "NvEncodeAPICreateInstance"); + (NvEncodeAPICreateInstance_Type)GetProcAddress( + hModule, "NvEncodeAPICreateInstance"); #else NvEncodeAPICreateInstance_Type NvEncodeAPICreateInstance = - (NvEncodeAPICreateInstance_Type)dlsym(hModule, "NvEncodeAPICreateInstance"); + (NvEncodeAPICreateInstance_Type)dlsym(hModule, + "NvEncodeAPICreateInstance"); #endif if (!NvEncodeAPICreateInstance) { diff --git a/NvCodec/NvCodec/NvEncoder/NvEncoder.h b/third_party/NvCodec/NvCodec/NvEncoder/NvEncoder.h similarity index 100% rename from NvCodec/NvCodec/NvEncoder/NvEncoder.h rename to third_party/NvCodec/NvCodec/NvEncoder/NvEncoder.h diff --git a/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp b/third_party/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp similarity index 99% rename from NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp rename to third_party/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp index 5620a51a..f276740c 100644 --- a/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp +++ b/third_party/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.cpp @@ -8,9 +8,10 @@ * is strictly prohibited. * */ +#include "fix_cuda_noinline_macro_error.h" #include "NvEncoder/NvEncoderCuda.h" -#include "dyn/cuda.h" +#include "sora/dyn/cuda.h" NvEncoderCuda::NvEncoderCuda(CUcontext cuContext, uint32_t nWidth, diff --git a/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.h b/third_party/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.h similarity index 100% rename from NvCodec/NvCodec/NvEncoder/NvEncoderCuda.h rename to third_party/NvCodec/NvCodec/NvEncoder/NvEncoderCuda.h diff --git a/NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.cpp b/third_party/NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.cpp similarity index 100% rename from NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.cpp rename to third_party/NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.cpp diff --git a/NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.h b/third_party/NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.h similarity index 100% rename from NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.h rename to third_party/NvCodec/NvCodec/NvEncoder/NvEncoderD3D11.h diff --git a/NvCodec/Utils/Logger.h b/third_party/NvCodec/Utils/Logger.h similarity index 100% rename from NvCodec/Utils/Logger.h rename to third_party/NvCodec/Utils/Logger.h diff --git a/NvCodec/Utils/NvCodecUtils.h b/third_party/NvCodec/Utils/NvCodecUtils.h similarity index 99% rename from NvCodec/Utils/NvCodecUtils.h rename to third_party/NvCodec/Utils/NvCodecUtils.h index fd6d33e0..c9a6e434 100644 --- a/NvCodec/Utils/NvCodecUtils.h +++ b/third_party/NvCodec/Utils/NvCodecUtils.h @@ -30,7 +30,7 @@ #include #include #include "Logger.h" -#include "dyn/cuda.h" +#include "sora/dyn/cuda.h" extern simplelogger::Logger* logger; diff --git a/NvCodec/include/cuviddec.h b/third_party/NvCodec/include/cuviddec.h similarity index 100% rename from NvCodec/include/cuviddec.h rename to third_party/NvCodec/include/cuviddec.h diff --git a/NvCodec/include/nvEncodeAPI.h b/third_party/NvCodec/include/nvEncodeAPI.h similarity index 100% rename from NvCodec/include/nvEncodeAPI.h rename to third_party/NvCodec/include/nvEncodeAPI.h diff --git a/NvCodec/include/nvcuvid.h b/third_party/NvCodec/include/nvcuvid.h similarity index 100% rename from NvCodec/include/nvcuvid.h rename to third_party/NvCodec/include/nvcuvid.h