From b0e4555c9fe5621a74bfc927c6c3cd3b098cd49d Mon Sep 17 00:00:00 2001 From: winlin Date: Thu, 5 Jun 2025 09:50:35 -0400 Subject: [PATCH 01/12] CICD: Add workflow for WHIP. --- .github/workflows/Dockerfile | 24 ++ .github/workflows/fate-cache.yml | 27 ++ .github/workflows/format-patch.sh | 120 +++++++++ .github/workflows/test.yml | 414 ++++++++++++++++++++++++++++++ .gitignore | 1 + 5 files changed, 586 insertions(+) create mode 100644 .github/workflows/Dockerfile create mode 100644 .github/workflows/fate-cache.yml create mode 100755 .github/workflows/format-patch.sh create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/Dockerfile b/.github/workflows/Dockerfile new file mode 100644 index 0000000000000..78e8d928afe2f --- /dev/null +++ b/.github/workflows/Dockerfile @@ -0,0 +1,24 @@ +# docker build -t ossrs/srs:ffmpeg-fate +# docker push ossrs/srs:ffmpeg-fate +FROM ubuntu:22.04 + +RUN apt-get update && \ + apt-get install -y build-essential git rsync make nasm pkg-config libssl-dev &&\ + rm -rf /var/lib/apt/lists/* + +WORKDIR /opt +RUN git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg + +WORKDIR /opt/ffmpeg +RUN ./configure --enable-openssl --enable-version3 +RUN make -j$(nproc) + +RUN make fate-rsync SAMPLES=/opt/ffmpeg/fate-suite +RUN du -sh /opt/ffmpeg/fate-suite + +# Note that you should use the fate-suite.tar, then extract it out of +# docker, to avoid resync all files. +RUN tar cf fate-suite.tar fate-suite +RUN du -sh /opt/ffmpeg/fate-suite.tar + +ENV FATE_SAMPLES=/opt/ffmpeg/fate-suite diff --git a/.github/workflows/fate-cache.yml b/.github/workflows/fate-cache.yml new file mode 100644 index 0000000000000..f8abc46ccf777 --- /dev/null +++ b/.github/workflows/fate-cache.yml @@ -0,0 +1,27 @@ +name: "FFmpeg FATE Cache" + +on: + workflow_dispatch: + +permissions: read-all + +jobs: + build: + name: "Build FFmpeg Fate Cache" + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Login to docker hub + uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # v2.1.0 + with: + username: "${{ secrets.DOCKER_USERNAME }}" + password: "${{ secrets.DOCKER_PASSWORD }}" + - name: Build FFmpeg Fate Cache + run: | + set -euxo pipefail + docker build -t ossrs/srs:ffmpeg-fate -f .github/workflows/Dockerfile . + - name: Push FFmpeg Fate Cache + run: | + set -euxo pipefail + docker push ossrs/srs:ffmpeg-fate + runs-on: ubuntu-22.04 diff --git a/.github/workflows/format-patch.sh b/.github/workflows/format-patch.sh new file mode 100755 index 0000000000000..cd0ed83ef2c84 --- /dev/null +++ b/.github/workflows/format-patch.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +if [[ $(jq --version 1>/dev/null 2>&1 && echo yes) != "yes" ]]; then + echo "Tool jq is not installed. Please install it to parse JSON data. For example:" + echo " apt install jq" + echo " brew install jq" + echo " yum install jq" + echo "See https://github.com/jqlang/jq" + exit 1 +fi + +if [ -z "$1" ]; then + echo "Please provide a PR link or number. For example: https://github.com/ossrs/ffmpeg-webrtc/pull/20" + exit 1 +fi + +if [[ "$1" =~ ^https://github.com/ossrs/ffmpeg-webrtc/pull/([0-9]+)$ ]]; then + PR_NUMBER="${BASH_REMATCH[1]}" +elif [[ "$1" =~ ^[0-9]+$ ]]; then + PR_NUMBER="$1" +else + echo "Invalid input format. Please provide a PR link or number. For example: https://github.com/ossrs/ffmpeg-webrtc/pull/20" + exit 1 +fi + +PR_URL="https://github.com/ossrs/ffmpeg-webrtc/pull/$PR_NUMBER" +echo "Fetching PR #$PR_NUMBER from $PR_URL" + +PR_DATA=$(curl -s "https://api.github.com/repos/ossrs/ffmpeg-webrtc/pulls/$PR_NUMBER") +REPO_NAME=$(echo "$PR_DATA" | jq -r '.head.repo.full_name') +BRANCH_NAME=$(echo "$PR_DATA" | jq -r '.head.ref') +if [[ -z "$REPO_NAME" || -z "$BRANCH_NAME" ]]; then + echo "Error: REPO_NAME or BRANCH_NAME is empty!" + exit 1 +fi +echo "Repository: $REPO_NAME, Branch: $BRANCH_NAME" + +PR_TITLE=$(echo "$PR_DATA" | jq -r '.title') +PR_DESCRIPTION=$(echo "$PR_DATA" | jq -r '.body // ""') +if [[ -z "$PR_TITLE" ]]; then + echo "Error: PR title is empty!" + exit 1 +fi + +echo "PR information:" +echo "===================================================================" +echo "$PR_TITLE" +echo "$PR_DESCRIPTION" +echo "===================================================================" +echo "" + +set -euxo pipefail + +git checkout workflows +echo "Switched to workflows branch." + +git pull +echo "Pulled latest changes from workflows branch." + +REMOTE_NAME=patch-tmp +if git remote | grep -q "^$REMOTE_NAME$"; then + git remote rm "$REMOTE_NAME" +fi +git remote add $REMOTE_NAME https://github.com/${REPO_NAME}.git +git fetch $REMOTE_NAME $BRANCH_NAME +echo "Fetch remote $REMOTE_NAME at $(git remote get-url $REMOTE_NAME)" + +TMP_BRANCH=tmp-branch-for-patch-$PR_NUMBER +if git branch --list "$TMP_BRANCH" | grep -q "^..$TMP_BRANCH$"; then + git branch -D "$TMP_BRANCH" +fi +git checkout -b $TMP_BRANCH $REMOTE_NAME/$BRANCH_NAME +echo "Checkout branch $TMP_BRANCH from $REMOTE_NAME/$BRANCH_NAME" + +FIRST_AUTHOR_NAME=$(git log workflows..HEAD --reverse --format='%an' | head -n1) +FIRST_AUTHOR_EMAIL=$(git log workflows..HEAD --reverse --format='%ae' | head -n1) +echo "Author: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" + +COAUTHORS=$(git log workflows..HEAD --format='Co-authored-by: %an <%ae>' |grep -v "$FIRST_AUTHOR_NAME" | sort -u) +COAUTHOR_COUNT=$(echo "$COAUTHORS" | wc -l) +if [ "$COAUTHOR_COUNT" -gt 0 ]; then + echo "$COAUTHORS" +fi + +COMMIT_MSG="$PR_TITLE" +if [ -n "$PR_DESCRIPTION" ]; then + COMMIT_MSG="$COMMIT_MSG\n\n$PR_DESCRIPTION" +fi + +if [ "$COAUTHOR_COUNT" -gt 0 ]; then + COMMIT_MSG="$COMMIT_MSG\n" + COMMIT_MSG="$COMMIT_MSG\n$COAUTHORS" +fi + +echo "Commit information:" +echo "Author: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" +echo "===================================================================" +echo -e "$COMMIT_MSG" +echo "===================================================================" +echo "" + +git rebase workflows +git reset --soft workflows +git commit --author "$FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -m "$(echo -e "$COMMIT_MSG")" +echo "Squashed commits into a single commit." +git log -1 --pretty=format:"%an <%ae> %h %s" + +PATCH_FILE="patch-$PR_NUMBER-$(date +%s).patch" +rm -f $PATCH_FILE +git format-patch -1 --stdout > $PATCH_FILE + +git checkout workflows +#git br -D $TMP_BRANCH +#echo "Removed temporary branch $TMP_BRANCH." + +set +e +u +x +o pipefail + +echo "" +echo "Patch file created: $PATCH_FILE" +echo "" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000000..8dae8e9c5c471 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,414 @@ +name: "Test" + +on: + push: + pull_request: + +permissions: read-all + +# Results for commonly used commands: +# $(pwd) is /home/runner/work/ffmpeg-webrtc/ffmpeg-webrtc +# $(nproc) is 4 +# $(whoami) is runner +# $(id -gn) is docker +# $(which docker) is /usr/bin/docker +# $(ifconfig eth0 | grep 'inet ' | awk '{print $2}') is private IP4 address like 10.1.0.76 +jobs: + build: + name: "Build FFmpeg" + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config libssl-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + runs-on: ubuntu-22.04 + + fate: + name: "FFmpeg Fate Test" + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # The cache for FFmpeg FATE samples can help decrease the resync time when executing + # "make fate-resync." The cache is stored in the Docker image "ossrs/srs:ffmpeg-fate," + # which can be refreshed by manually executing the below workflow. + # https://github.com/ossrs/ffmpeg-webrtc/actions/workflows/fate-cache.yml + - name: Download Fate Cache Samples + run: | + set -euxo pipefail + + docker run --rm -v $(pwd):/target ossrs/srs:ffmpeg-fate \ + bash -c "cp /opt/ffmpeg/fate-suite.tar /target/" + tar xf fate-suite.tar + + ls -ldh fate-suite + du -sh fate-suite + - name: Configure FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config libssl-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ + --extra-cflags='-fsanitize=address -g -O0' --extra-cxxflags='-fsanitize=address -g -O0' --extra-ldflags='-fsanitize=address -g -O0' + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: FFmpeg Fate rsync + run: | + set -euxo pipefail + make fate-rsync SAMPLES=$(pwd)/fate-suite + - name: Stat Fate Suite + run: | + set -euxo pipefail + du -sh fate-suite + du -sh * + - name: Run FFmpeg Fate + run: | + set -euxo pipefail + make fate -j$(nproc) SAMPLES=$(pwd)/fate-suite + runs-on: ubuntu-22.04 + + srs: + name: "FFmpeg with SRS" + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config jq libssl-dev libopus-dev libx264-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ + --enable-libx264 --enable-gpl --enable-libopus + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: Start SRS Docker container + run: | + set -euxo pipefail + ip=$(ifconfig eth0 | grep 'inet ' | awk '{print $2}') + docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ + --env CANDIDATE=$ip -p 8000:8000/udp \ + ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf + - name: Test FFmpeg with SRS + run: | + set -euxo pipefail + + # Publish a test stream to SRS using the whip muxer + nohup ./ffmpeg -t 30 -re -f lavfi -i testsrc=size=1280x720 -f lavfi -i sine=frequency=440 -pix_fmt yuv420p \ + -vcodec libx264 -profile:v baseline -r 25 -g 50 -acodec libopus -ar 48000 -ac 2 \ + -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ + >/dev/null 2>&1 & + + # Check streams in SRS. + for ((i=0; i<10; i++)); do + STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') + if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + sleep 3 + done + if [[ "$STREAM" != "livestream" ]]; then + echo "Stream not found: $STREAM" + exit 1 + fi + runs-on: ubuntu-22.04 + + openssl-1-0-1k: + name: "With OpenSSL 1.0.1k" + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build OpenSSL 1.0.1k + run: | + set -euxo pipefail + curl -s -L https://www.openssl.org/source/openssl-1.0.1k.tar.gz | tar xz + cd openssl-1.0.1k && ./config && make -j1 && sudo make install_sw + - name: Download Test File + run: | + set -euxo pipefail + curl -s -L -O https://github.com/ossrs/ffmpeg-webrtc/releases/download/pre-release/bbb-4mbps-baseline-opus.mp4 + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: Start SRS Docker container + run: | + set -euxo pipefail + ip=$(ifconfig eth0 | grep 'inet ' | awk '{print $2}') + docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ + --env CANDIDATE=$ip -p 8000:8000/udp \ + ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf + - name: Test FFmpeg with SRS + run: | + set -euxo pipefail + + # Publish a test stream to SRS using the whip muxer + nohup ./ffmpeg -t 30 -re -i bbb-4mbps-baseline-opus.mp4 -c copy \ + -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ + >/dev/null 2>&1 & + + # Check streams in SRS. + for ((i=0; i<10; i++)); do + STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') + if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + sleep 3 + done + if [[ "$STREAM" != "livestream" ]]; then + echo "Stream not found: $STREAM" + exit 1 + fi + runs-on: ubuntu-22.04 + + openssl-1-0-2: + name: "With OpenSSL 1.0.2" + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build OpenSSL 1.0.2 + run: | + set -euxo pipefail + curl -s -L https://www.openssl.org/source/openssl-1.0.2.tar.gz | tar xz + cd openssl-1.0.2 && ./config && make -j1 && sudo make install_sw + - name: Download Test File + run: | + set -euxo pipefail + curl -s -L -O https://github.com/ossrs/ffmpeg-webrtc/releases/download/pre-release/bbb-4mbps-baseline-opus.mp4 + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: Start SRS Docker container + run: | + set -euxo pipefail + ip=$(ifconfig eth0 | grep 'inet ' | awk '{print $2}') + docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ + --env CANDIDATE=$ip -p 8000:8000/udp \ + ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf + - name: Test FFmpeg with SRS + run: | + set -euxo pipefail + + # Publish a test stream to SRS using the whip muxer + nohup ./ffmpeg -t 30 -re -i bbb-4mbps-baseline-opus.mp4 -c copy \ + -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ + >/dev/null 2>&1 & + + # Check streams in SRS. + for ((i=0; i<10; i++)); do + STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') + if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + sleep 3 + done + if [[ "$STREAM" != "livestream" ]]; then + echo "Stream not found: $STREAM" + exit 1 + fi + runs-on: ubuntu-22.04 + + openssl-1-1-0h: + name: "With OpenSSL 1.1.0h" + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build OpenSSL 1.1.0h + run: | + set -euxo pipefail + curl -s -L https://www.openssl.org/source/openssl-1.1.0h.tar.gz | tar xz + cd openssl-1.1.0h && ./config && make -j$(nproc) && sudo make install_sw + - name: Download Test File + run: | + set -euxo pipefail + curl -s -L -O https://github.com/ossrs/ffmpeg-webrtc/releases/download/pre-release/bbb-4mbps-baseline-opus.mp4 + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: Start SRS Docker container + run: | + set -euxo pipefail + ip=$(ifconfig eth0 | grep 'inet ' | awk '{print $2}') + docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ + --env CANDIDATE=$ip -p 8000:8000/udp \ + ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf + - name: Test FFmpeg with SRS + run: | + set -euxo pipefail + + # Publish a test stream to SRS using the whip muxer + nohup ./ffmpeg -t 30 -re -i bbb-4mbps-baseline-opus.mp4 -c copy \ + -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ + >/dev/null 2>&1 & + + # Check streams in SRS. + for ((i=0; i<10; i++)); do + STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') + if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + sleep 3 + done + if [[ "$STREAM" != "livestream" ]]; then + echo "Stream not found: $STREAM" + exit 1 + fi + runs-on: ubuntu-22.04 + + openssl-3-0: + name: "With OpenSSL 3.0" + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build OpenSSL 3.0 + run: | + set -euxo pipefail + curl -s -L https://www.openssl.org/source/openssl-3.0.0.tar.gz | tar xz + cd openssl-3.0.0 && ./config && make -j$(nproc) && sudo make install_sw + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ + --enable-libx264 --enable-gpl --enable-libopus + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: Start SRS Docker container + run: | + set -euxo pipefail + ip=$(ifconfig eth0 | grep 'inet ' | awk '{print $2}') + docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ + --env CANDIDATE=$ip -p 8000:8000/udp \ + ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf + - name: Test FFmpeg with SRS + run: | + set -euxo pipefail + + # Publish a test stream to SRS using the whip muxer + nohup ./ffmpeg -t 30 -re -f lavfi -i testsrc=size=1280x720 -f lavfi -i sine=frequency=440 -pix_fmt yuv420p \ + -vcodec libx264 -profile:v baseline -r 25 -g 50 -acodec libopus -ar 48000 -ac 2 \ + -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ + >/dev/null 2>&1 & + + # Check streams in SRS. + for ((i=0; i<10; i++)); do + STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') + if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + sleep 3 + done + if [[ "$STREAM" != "livestream" ]]; then + echo "Stream not found: $STREAM" + exit 1 + fi + runs-on: ubuntu-22.04 + + openssl-latest: + name: "With OpenSSL latest" + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build OpenSSL latest + run: | + set -euxo pipefail + curl -s -L https://www.openssl.org/source/openssl-3.5.0.tar.gz | tar xz + cd openssl-3.5.0 && ./config && make -j$(nproc) && sudo make install_sw + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ + --enable-libx264 --enable-gpl --enable-libopus + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: Start SRS Docker container + run: | + set -euxo pipefail + ip=$(ifconfig eth0 | grep 'inet ' | awk '{print $2}') + docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ + --env CANDIDATE=$ip -p 8000:8000/udp \ + ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf + - name: Test FFmpeg with SRS + run: | + set -euxo pipefail + + # Publish a test stream to SRS using the whip muxer + nohup ./ffmpeg -t 30 -re -f lavfi -i testsrc=size=1280x720 -f lavfi -i sine=frequency=440 -pix_fmt yuv420p \ + -vcodec libx264 -profile:v baseline -r 25 -g 50 -acodec libopus -ar 48000 -ac 2 \ + -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ + >/dev/null 2>&1 & + + # Check streams in SRS. + for ((i=0; i<10; i++)); do + STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') + if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + sleep 3 + done + if [[ "$STREAM" != "livestream" ]]; then + echo "Stream not found: $STREAM" + exit 1 + fi + runs-on: ubuntu-22.04 + + test-done: + needs: + - fate + - srs + - openssl-1-0-1k + - openssl-1-0-2 + - openssl-1-1-0h + - openssl-3-0 + - openssl-latest + steps: + - run: echo 'All done' + runs-on: ubuntu-22.04 + diff --git a/.gitignore b/.gitignore index 59c89da5e03b5..da2f89a60dcba 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ *.ptx *.ptx.c *.ptx.gz +*.patch *_g \#* .\#* From cf423801135c17ea499e9e66af897f149284295e Mon Sep 17 00:00:00 2001 From: Winlin Date: Sat, 7 Jun 2025 18:04:37 -0400 Subject: [PATCH 02/12] CICD: Use specified openssl. Add crash case. (#21) --- .github/workflows/format-patch.sh | 8 +- .github/workflows/test.yml | 325 +++++++++++++++++++++++++----- .gitignore | 1 + 3 files changed, 285 insertions(+), 49 deletions(-) diff --git a/.github/workflows/format-patch.sh b/.github/workflows/format-patch.sh index cd0ed83ef2c84..b7fe8c560f8aa 100755 --- a/.github/workflows/format-patch.sh +++ b/.github/workflows/format-patch.sh @@ -27,16 +27,16 @@ PR_URL="https://github.com/ossrs/ffmpeg-webrtc/pull/$PR_NUMBER" echo "Fetching PR #$PR_NUMBER from $PR_URL" PR_DATA=$(curl -s "https://api.github.com/repos/ossrs/ffmpeg-webrtc/pulls/$PR_NUMBER") -REPO_NAME=$(echo "$PR_DATA" | jq -r '.head.repo.full_name') -BRANCH_NAME=$(echo "$PR_DATA" | jq -r '.head.ref') +REPO_NAME=$(printf '%s' "$PR_DATA" | jq -r '.head.repo.full_name') +BRANCH_NAME=$(printf '%s' "$PR_DATA" | jq -r '.head.ref') if [[ -z "$REPO_NAME" || -z "$BRANCH_NAME" ]]; then echo "Error: REPO_NAME or BRANCH_NAME is empty!" exit 1 fi echo "Repository: $REPO_NAME, Branch: $BRANCH_NAME" -PR_TITLE=$(echo "$PR_DATA" | jq -r '.title') -PR_DESCRIPTION=$(echo "$PR_DATA" | jq -r '.body // ""') +PR_TITLE=$(printf '%s' "$PR_DATA" | jq -r '.title') +PR_DESCRIPTION=$(printf '%s' "$PR_DATA" | jq -r '.body // ""') if [[ -z "$PR_TITLE" ]]; then echo "Error: PR title is empty!" exit 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8dae8e9c5c471..cb604c11e9dee 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,6 +7,7 @@ on: permissions: read-all # Results for commonly used commands: +# $HOME is /home/runner # $(pwd) is /home/runner/work/ffmpeg-webrtc/ffmpeg-webrtc # $(nproc) is 4 # $(whoami) is runner @@ -106,26 +107,129 @@ jobs: docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ --env CANDIDATE=$ip -p 8000:8000/udp \ ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf - - name: Test FFmpeg with SRS + - name: Streaming with FFmpeg run: | set -euxo pipefail + nohup ./ffmpeg -t 30 -re -f lavfi -i testsrc=size=1280x720 -f lavfi -i sine=frequency=440 -pix_fmt yuv420p \ + -vcodec libx264 -profile:v baseline -r 25 -g 50 -acodec libopus -ar 48000 -ac 2 \ + -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ + 1>ffstdout.log 2>ffstderr.log & + - name: Check SRS Streaming + id: streaming + run: | + set -euxo pipefail + + # Check streams in SRS. + for ((i=0; i<10; i++)); do + STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') + if [[ "$STREAM" == "livestream" ]]; then + echo 'Test OK'; + echo "has_stream=true" >> $GITHUB_OUTPUT + break; + fi + sleep 3 + done - # Publish a test stream to SRS using the whip muxer + if [[ "$STREAM" != "livestream" ]]; then + echo "Stream not found: $STREAM" + echo "has_stream=false" >> $GITHUB_OUTPUT + fi + - name: Stop FFmpeg normally + run: | + pkill -SIGINT ffmpeg && sleep 3 || + echo "FFmpeg process not found or already stopped." + - name: Show FFmpeg Stdout Log + run: cat ffstdout.log + - name: Show FFmpeg Stderr Log + run: cat ffstderr.log + - name: Check FFmpeg Exit Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'Exiting normally' && exit 0 + echo "Exiting normally not found in ffstderr.log" && exit 1 + - name: Check Stream Existence + if: ${{ steps.streaming.outputs.has_stream == 'false' }} + run: exit 1 + runs-on: ubuntu-22.04 + + asan: + name: "FFmpeg with Asan" + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config jq libssl-dev libopus-dev libx264-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ + --enable-libx264 --enable-gpl --enable-libopus \ + --extra-cflags='-fsanitize=address -g -O0' --extra-cxxflags='-fsanitize=address -g -O0' --extra-ldflags='-fsanitize=address -g -O0' + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: Start SRS Docker container + run: | + set -euxo pipefail + ip=$(ifconfig eth0 | grep 'inet ' | awk '{print $2}') + docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ + --env CANDIDATE=$ip -p 8000:8000/udp \ + ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf + - name: Streaming with FFmpeg + run: | + set -euxo pipefail nohup ./ffmpeg -t 30 -re -f lavfi -i testsrc=size=1280x720 -f lavfi -i sine=frequency=440 -pix_fmt yuv420p \ -vcodec libx264 -profile:v baseline -r 25 -g 50 -acodec libopus -ar 48000 -ac 2 \ -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ - >/dev/null 2>&1 & + 1>ffstdout.log 2>ffstderr.log & + - name: Check SRS Streaming + id: streaming + run: | + set -euxo pipefail # Check streams in SRS. for ((i=0; i<10; i++)); do STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') - if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + if [[ "$STREAM" == "livestream" ]]; then + echo 'Test OK'; + echo "has_stream=true" >> $GITHUB_OUTPUT + break; + fi sleep 3 done + if [[ "$STREAM" != "livestream" ]]; then echo "Stream not found: $STREAM" - exit 1 + echo "has_stream=false" >> $GITHUB_OUTPUT fi + - name: Stop FFmpeg normally + run: | + # TEST: Generate a coredump. + #pkill -SIGSEGV ffmpeg && sleep 3 && exit 0 + pkill -SIGINT ffmpeg && sleep 3 || + echo "FFmpeg process not found or already stopped." + - name: Show FFmpeg Stdout Log + run: cat ffstdout.log + - name: Show FFmpeg Stderr Log + run: cat ffstderr.log + - name: Check Asan Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'ERROR: AddressSanitizer' && + echo "AddressSanitizer error found in ffstderr.log" && exit 1 + echo "AddressSanitizer is ok" + - name: Check FFmpeg Exit Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'Exiting normally' && exit 0 + echo "Exiting normally not found in ffstderr.log" && exit 1 + - name: Check Stream Existence + if: ${{ steps.streaming.outputs.has_stream == 'false' }} + run: exit 1 runs-on: ubuntu-22.04 openssl-1-0-1k: @@ -138,7 +242,9 @@ jobs: run: | set -euxo pipefail curl -s -L https://www.openssl.org/source/openssl-1.0.1k.tar.gz | tar xz - cd openssl-1.0.1k && ./config && make -j1 && sudo make install_sw + cd openssl-1.0.1k + ./config --prefix=$HOME/.release/openssl && make -j1 + sudo make install_sw - name: Download Test File run: | set -euxo pipefail @@ -152,7 +258,8 @@ jobs: sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev # Build FFmpeg with WebRTC support - ./configure --enable-muxer=whip --enable-openssl --enable-version3 + PKG_CONFIG_PATH="$HOME/.release/openssl/lib/pkgconfig" \ + ./configure --enable-muxer=whip --enable-openssl --enable-version3 make -j$(nproc) ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip - name: Start SRS Docker container @@ -162,25 +269,48 @@ jobs: docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ --env CANDIDATE=$ip -p 8000:8000/udp \ ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf - - name: Test FFmpeg with SRS + - name: Streaming with FFmpeg run: | set -euxo pipefail - - # Publish a test stream to SRS using the whip muxer nohup ./ffmpeg -t 30 -re -i bbb-4mbps-baseline-opus.mp4 -c copy \ -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ - >/dev/null 2>&1 & + 1>ffstdout.log 2>ffstderr.log & + - name: Check SRS Streaming + id: streaming + run: | + set -euxo pipefail # Check streams in SRS. for ((i=0; i<10; i++)); do STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') - if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + if [[ "$STREAM" == "livestream" ]]; then + echo 'Test OK'; + echo "has_stream=true" >> $GITHUB_OUTPUT + break; + fi sleep 3 done + if [[ "$STREAM" != "livestream" ]]; then echo "Stream not found: $STREAM" - exit 1 + echo "has_stream=false" >> $GITHUB_OUTPUT fi + - name: Stop FFmpeg normally + run: | + pkill -SIGINT ffmpeg && sleep 3 || + echo "FFmpeg process not found or already stopped." + - name: Show FFmpeg Stdout Log + run: cat ffstdout.log + - name: Show FFmpeg Stderr Log + run: cat ffstderr.log + - name: Check FFmpeg Exit Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'Exiting normally' && exit 0 + echo "Exiting normally not found in ffstderr.log" && exit 1 + - name: Check Stream Existence + if: ${{ steps.streaming.outputs.has_stream == 'false' }} + run: exit 1 runs-on: ubuntu-22.04 openssl-1-0-2: @@ -193,7 +323,9 @@ jobs: run: | set -euxo pipefail curl -s -L https://www.openssl.org/source/openssl-1.0.2.tar.gz | tar xz - cd openssl-1.0.2 && ./config && make -j1 && sudo make install_sw + cd openssl-1.0.2 + ./config --prefix=$HOME/.release/openssl + make -j1 && sudo make install_sw - name: Download Test File run: | set -euxo pipefail @@ -207,7 +339,8 @@ jobs: sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev # Build FFmpeg with WebRTC support - ./configure --enable-muxer=whip --enable-openssl --enable-version3 + PKG_CONFIG_PATH="$HOME/.release/openssl/lib/pkgconfig" \ + ./configure --enable-muxer=whip --enable-openssl --enable-version3 make -j$(nproc) ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip - name: Start SRS Docker container @@ -217,25 +350,48 @@ jobs: docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ --env CANDIDATE=$ip -p 8000:8000/udp \ ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf - - name: Test FFmpeg with SRS + - name: Streaming with FFmpeg run: | set -euxo pipefail - - # Publish a test stream to SRS using the whip muxer nohup ./ffmpeg -t 30 -re -i bbb-4mbps-baseline-opus.mp4 -c copy \ -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ - >/dev/null 2>&1 & + 1>ffstdout.log 2>ffstderr.log & + - name: Check SRS Streaming + id: streaming + run: | + set -euxo pipefail # Check streams in SRS. for ((i=0; i<10; i++)); do STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') - if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + if [[ "$STREAM" == "livestream" ]]; then + echo 'Test OK'; + echo "has_stream=true" >> $GITHUB_OUTPUT + break; + fi sleep 3 done + if [[ "$STREAM" != "livestream" ]]; then echo "Stream not found: $STREAM" - exit 1 + echo "has_stream=false" >> $GITHUB_OUTPUT fi + - name: Stop FFmpeg normally + run: | + pkill -SIGINT ffmpeg && sleep 3 || + echo "FFmpeg process not found or already stopped." + - name: Show FFmpeg Stdout Log + run: cat ffstdout.log + - name: Show FFmpeg Stderr Log + run: cat ffstderr.log + - name: Check FFmpeg Exit Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'Exiting normally' && exit 0 + echo "Exiting normally not found in ffstderr.log" && exit 1 + - name: Check Stream Existence + if: ${{ steps.streaming.outputs.has_stream == 'false' }} + run: exit 1 runs-on: ubuntu-22.04 openssl-1-1-0h: @@ -248,7 +404,9 @@ jobs: run: | set -euxo pipefail curl -s -L https://www.openssl.org/source/openssl-1.1.0h.tar.gz | tar xz - cd openssl-1.1.0h && ./config && make -j$(nproc) && sudo make install_sw + cd openssl-1.1.0h + ./config --prefix=$HOME/.release/openssl + make -j$(nproc) && sudo make install_sw - name: Download Test File run: | set -euxo pipefail @@ -262,7 +420,8 @@ jobs: sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev # Build FFmpeg with WebRTC support - ./configure --enable-muxer=whip --enable-openssl --enable-version3 + PKG_CONFIG_PATH="$HOME/.release/openssl/lib/pkgconfig" \ + ./configure --enable-muxer=whip --enable-openssl --enable-version3 make -j$(nproc) ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip - name: Start SRS Docker container @@ -272,25 +431,48 @@ jobs: docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ --env CANDIDATE=$ip -p 8000:8000/udp \ ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf - - name: Test FFmpeg with SRS + - name: Streaming with FFmpeg run: | set -euxo pipefail - - # Publish a test stream to SRS using the whip muxer nohup ./ffmpeg -t 30 -re -i bbb-4mbps-baseline-opus.mp4 -c copy \ -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ - >/dev/null 2>&1 & + 1>ffstdout.log 2>ffstderr.log & + - name: Check SRS Streaming + id: streaming + run: | + set -euxo pipefail # Check streams in SRS. for ((i=0; i<10; i++)); do STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') - if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + if [[ "$STREAM" == "livestream" ]]; then + echo 'Test OK'; + echo "has_stream=true" >> $GITHUB_OUTPUT + break; + fi sleep 3 done + if [[ "$STREAM" != "livestream" ]]; then echo "Stream not found: $STREAM" - exit 1 + echo "has_stream=false" >> $GITHUB_OUTPUT fi + - name: Stop FFmpeg normally + run: | + pkill -SIGINT ffmpeg && sleep 3 || + echo "FFmpeg process not found or already stopped." + - name: Show FFmpeg Stdout Log + run: cat ffstdout.log + - name: Show FFmpeg Stderr Log + run: cat ffstderr.log + - name: Check FFmpeg Exit Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'Exiting normally' && exit 0 + echo "Exiting normally not found in ffstderr.log" && exit 1 + - name: Check Stream Existence + if: ${{ steps.streaming.outputs.has_stream == 'false' }} + run: exit 1 runs-on: ubuntu-22.04 openssl-3-0: @@ -303,7 +485,9 @@ jobs: run: | set -euxo pipefail curl -s -L https://www.openssl.org/source/openssl-3.0.0.tar.gz | tar xz - cd openssl-3.0.0 && ./config && make -j$(nproc) && sudo make install_sw + cd openssl-3.0.0 + ./config --prefix=$HOME/.release/openssl + make -j$(nproc) && sudo make install_sw - name: Build FFmpeg run: | set -euxo pipefail @@ -313,7 +497,8 @@ jobs: sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev # Build FFmpeg with WebRTC support - ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ + PKG_CONFIG_PATH="$HOME/.release/openssl/lib/pkgconfig" \ + ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ --enable-libx264 --enable-gpl --enable-libopus make -j$(nproc) ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip @@ -324,26 +509,49 @@ jobs: docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ --env CANDIDATE=$ip -p 8000:8000/udp \ ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf - - name: Test FFmpeg with SRS + - name: Streaming with FFmpeg run: | set -euxo pipefail - - # Publish a test stream to SRS using the whip muxer nohup ./ffmpeg -t 30 -re -f lavfi -i testsrc=size=1280x720 -f lavfi -i sine=frequency=440 -pix_fmt yuv420p \ -vcodec libx264 -profile:v baseline -r 25 -g 50 -acodec libopus -ar 48000 -ac 2 \ -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ - >/dev/null 2>&1 & + 1>ffstdout.log 2>ffstderr.log & + - name: Check SRS Streaming + id: streaming + run: | + set -euxo pipefail # Check streams in SRS. for ((i=0; i<10; i++)); do STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') - if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + if [[ "$STREAM" == "livestream" ]]; then + echo 'Test OK'; + echo "has_stream=true" >> $GITHUB_OUTPUT + break; + fi sleep 3 done + if [[ "$STREAM" != "livestream" ]]; then echo "Stream not found: $STREAM" - exit 1 + echo "has_stream=false" >> $GITHUB_OUTPUT fi + - name: Stop FFmpeg normally + run: | + pkill -SIGINT ffmpeg && sleep 3 || + echo "FFmpeg process not found or already stopped." + - name: Show FFmpeg Stdout Log + run: cat ffstdout.log + - name: Show FFmpeg Stderr Log + run: cat ffstderr.log + - name: Check FFmpeg Exit Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'Exiting normally' && exit 0 + echo "Exiting normally not found in ffstderr.log" && exit 1 + - name: Check Stream Existence + if: ${{ steps.streaming.outputs.has_stream == 'false' }} + run: exit 1 runs-on: ubuntu-22.04 openssl-latest: @@ -356,7 +564,9 @@ jobs: run: | set -euxo pipefail curl -s -L https://www.openssl.org/source/openssl-3.5.0.tar.gz | tar xz - cd openssl-3.5.0 && ./config && make -j$(nproc) && sudo make install_sw + cd openssl-3.5.0 + ./config --prefix=$HOME/.release/openssl + make -j$(nproc) && sudo make install_sw - name: Build FFmpeg run: | set -euxo pipefail @@ -366,7 +576,8 @@ jobs: sudo apt-get install -y nasm pkg-config jq libopus-dev libx264-dev # Build FFmpeg with WebRTC support - ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ + PKG_CONFIG_PATH="$HOME/.release/openssl/lib/pkgconfig" \ + ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ --enable-libx264 --enable-gpl --enable-libopus make -j$(nproc) ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip @@ -377,32 +588,56 @@ jobs: docker run --rm -d -p 1935:1935 -p 1985:1985 -p 8080:8080 \ --env CANDIDATE=$ip -p 8000:8000/udp \ ossrs/srs:5 ./objs/srs -c conf/rtc2rtmp.conf - - name: Test FFmpeg with SRS + - name: Streaming with FFmpeg run: | set -euxo pipefail - - # Publish a test stream to SRS using the whip muxer nohup ./ffmpeg -t 30 -re -f lavfi -i testsrc=size=1280x720 -f lavfi -i sine=frequency=440 -pix_fmt yuv420p \ -vcodec libx264 -profile:v baseline -r 25 -g 50 -acodec libopus -ar 48000 -ac 2 \ -f whip "http://localhost:1985/rtc/v1/whip/?app=live&stream=livestream" \ - >/dev/null 2>&1 & + 1>ffstdout.log 2>ffstderr.log & + - name: Check SRS Streaming + id: streaming + run: | + set -euxo pipefail # Check streams in SRS. for ((i=0; i<10; i++)); do STREAM=$(curl -s http://localhost:1985/api/v1/streams/ | jq -r '.streams[].name') - if [[ "$STREAM" == "livestream" ]]; then echo 'Test OK'; break; fi + if [[ "$STREAM" == "livestream" ]]; then + echo 'Test OK'; + echo "has_stream=true" >> $GITHUB_OUTPUT + break; + fi sleep 3 done + if [[ "$STREAM" != "livestream" ]]; then echo "Stream not found: $STREAM" - exit 1 + echo "has_stream=false" >> $GITHUB_OUTPUT fi + - name: Stop FFmpeg normally + run: | + pkill -SIGINT ffmpeg && sleep 3 || + echo "FFmpeg process not found or already stopped." + - name: Show FFmpeg Stdout Log + run: cat ffstdout.log + - name: Show FFmpeg Stderr Log + run: cat ffstderr.log + - name: Check FFmpeg Exit Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'Exiting normally' && exit 0 + echo "Exiting normally not found in ffstderr.log" && exit 1 + - name: Check Stream Existence + if: ${{ steps.streaming.outputs.has_stream == 'false' }} + run: exit 1 runs-on: ubuntu-22.04 test-done: needs: - fate - srs + - asan - openssl-1-0-1k - openssl-1-0-2 - openssl-1-1-0h diff --git a/.gitignore b/.gitignore index da2f89a60dcba..9e56f800f8c67 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ /libavcodec/vulkan/*.c /libavfilter/vulkan/*.c /.*/ +/fate-suite From fdb811a6a643cde67fff190e01c7b8c3c011eb30 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 8 Jun 2025 09:59:52 -0400 Subject: [PATCH 03/12] CICD: Generate Patch for each PR (#22) --- .github/workflows/format-patch.sh | 93 ++++++++++++++++++++----------- .github/workflows/test.yml | 53 ++++++++++++++++++ 2 files changed, 114 insertions(+), 32 deletions(-) diff --git a/.github/workflows/format-patch.sh b/.github/workflows/format-patch.sh index b7fe8c560f8aa..ef67cd50c4cc8 100755 --- a/.github/workflows/format-patch.sh +++ b/.github/workflows/format-patch.sh @@ -9,7 +9,9 @@ if [[ $(jq --version 1>/dev/null 2>&1 && echo yes) != "yes" ]]; then exit 1 fi -if [ -z "$1" ]; then +PR_NUMBER="$1" +PATCH_FILE="$2" +if [ -z "$PR_NUMBER" ]; then echo "Please provide a PR link or number. For example: https://github.com/ossrs/ffmpeg-webrtc/pull/20" exit 1 fi @@ -29,65 +31,77 @@ echo "Fetching PR #$PR_NUMBER from $PR_URL" PR_DATA=$(curl -s "https://api.github.com/repos/ossrs/ffmpeg-webrtc/pulls/$PR_NUMBER") REPO_NAME=$(printf '%s' "$PR_DATA" | jq -r '.head.repo.full_name') BRANCH_NAME=$(printf '%s' "$PR_DATA" | jq -r '.head.ref') +echo "Repository: $REPO_NAME, Branch: $BRANCH_NAME" if [[ -z "$REPO_NAME" || -z "$BRANCH_NAME" ]]; then echo "Error: REPO_NAME or BRANCH_NAME is empty!" exit 1 fi -echo "Repository: $REPO_NAME, Branch: $BRANCH_NAME" PR_TITLE=$(printf '%s' "$PR_DATA" | jq -r '.title') PR_DESCRIPTION=$(printf '%s' "$PR_DATA" | jq -r '.body // ""') -if [[ -z "$PR_TITLE" ]]; then - echo "Error: PR title is empty!" - exit 1 -fi - echo "PR information:" echo "===================================================================" echo "$PR_TITLE" echo "$PR_DESCRIPTION" echo "===================================================================" echo "" +if [[ -z "$PR_TITLE" ]]; then + echo "Error: PR title is empty!" + exit 1 +fi -set -euxo pipefail - -git checkout workflows -echo "Switched to workflows branch." - +git checkout workflows && +echo "Switched to workflows branch." && git pull echo "Pulled latest changes from workflows branch." +if [[ $? -ne 0 ]]; then + echo "Failed to switch to workflows branch or pull latest changes." + exit 1 +fi -REMOTE_NAME=patch-tmp +REMOTE_NAME=patch-tmp && if git remote | grep -q "^$REMOTE_NAME$"; then git remote rm "$REMOTE_NAME" -fi -git remote add $REMOTE_NAME https://github.com/${REPO_NAME}.git -git fetch $REMOTE_NAME $BRANCH_NAME +fi && +git remote add $REMOTE_NAME https://github.com/${REPO_NAME}.git && +git fetch $REMOTE_NAME $BRANCH_NAME && echo "Fetch remote $REMOTE_NAME at $(git remote get-url $REMOTE_NAME)" +if [[ $? -ne 0 ]]; then + echo "Failed to fetch remote branch $BRANCH_NAME from $REMOTE_NAME." + exit 1 +fi -TMP_BRANCH=tmp-branch-for-patch-$PR_NUMBER +TMP_BRANCH=tmp-branch-for-patch-$PR_NUMBER && if git branch --list "$TMP_BRANCH" | grep -q "^..$TMP_BRANCH$"; then git branch -D "$TMP_BRANCH" -fi -git checkout -b $TMP_BRANCH $REMOTE_NAME/$BRANCH_NAME +fi && +git checkout -b $TMP_BRANCH $REMOTE_NAME/$BRANCH_NAME && echo "Checkout branch $TMP_BRANCH from $REMOTE_NAME/$BRANCH_NAME" +if [[ $? -ne 0 ]]; then + echo "Failed to checkout branch $TMP_BRANCH from $REMOTE_NAME/$BRANCH_NAME." + exit 1 +fi FIRST_AUTHOR_NAME=$(git log workflows..HEAD --reverse --format='%an' | head -n1) FIRST_AUTHOR_EMAIL=$(git log workflows..HEAD --reverse --format='%ae' | head -n1) echo "Author: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" +if [[ -z "$FIRST_AUTHOR_NAME" || -z "$FIRST_AUTHOR_EMAIL" ]]; then + echo "Error: Unable to determine the first author of the PR." + exit 1 +fi COAUTHORS=$(git log workflows..HEAD --format='Co-authored-by: %an <%ae>' |grep -v "$FIRST_AUTHOR_NAME" | sort -u) COAUTHOR_COUNT=$(echo "$COAUTHORS" | wc -l) -if [ "$COAUTHOR_COUNT" -gt 0 ]; then +if [[ "$COAUTHOR_COUNT" -gt 0 ]]; then echo "$COAUTHORS" fi COMMIT_MSG="$PR_TITLE" -if [ -n "$PR_DESCRIPTION" ]; then +if [[ -n "$PR_DESCRIPTION" ]]; then COMMIT_MSG="$COMMIT_MSG\n\n$PR_DESCRIPTION" fi -if [ "$COAUTHOR_COUNT" -gt 0 ]; then +if [[ "$COAUTHOR_COUNT" -gt 0 ]]; then COMMIT_MSG="$COMMIT_MSG\n" COMMIT_MSG="$COMMIT_MSG\n$COAUTHORS" fi @@ -95,26 +109,41 @@ fi echo "Commit information:" echo "Author: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" echo "===================================================================" -echo -e "$COMMIT_MSG" +echo -n -e "$COMMIT_MSG" echo "===================================================================" echo "" -git rebase workflows -git reset --soft workflows -git commit --author "$FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -m "$(echo -e "$COMMIT_MSG")" -echo "Squashed commits into a single commit." +git rebase workflows && +git reset --soft workflows && +git commit --author "$FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -m "$(echo -n -e "$COMMIT_MSG")" && +echo "Squashed commits into a single commit." && +if [[ $? -ne 0 ]]; then + echo "Failed to rebase or commit changes." + exit 1 +fi + +git branch -vv && git log -1 --pretty=format:"%an <%ae> %h %s" +if [[ $? -ne 0 ]]; then + echo "Failed to display branch information or last commit." + exit 1 +fi -PATCH_FILE="patch-$PR_NUMBER-$(date +%s).patch" -rm -f $PATCH_FILE -git format-patch -1 --stdout > $PATCH_FILE +if [[ -z "$PATCH_FILE" ]]; then + PATCH_FILE="whip-patch-$PR_NUMBER-$(date +%s).patch" +fi && +rm -f $PATCH_FILE && +git format-patch -1 --stdout > $PATCH_FILE && +echo "Created patch file: $PATCH_FILE" +if [[ $? -ne 0 ]]; then + echo "Failed to create patch file." + exit 1 +fi git checkout workflows #git br -D $TMP_BRANCH #echo "Removed temporary branch $TMP_BRANCH." -set +e +u +x +o pipefail - echo "" echo "Patch file created: $PATCH_FILE" echo "" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cb604c11e9dee..1a3aefe3ab092 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -633,6 +633,58 @@ jobs: run: exit 1 runs-on: ubuntu-22.04 + generate-patch: + name: "Generate Patch" + if: ${{ github.event_name == 'pull_request' }} + steps: + # Checkout to workflows branch, make sure the base branch is available. + - name: Checkout repository with workflows branch + uses: actions/checkout@v4 + with: + ref: workflows + fetch-depth: 0 + - name: Try to checkout to workflows branch + run: | + set -euxo pipefail + git checkout workflows + git branch -vv + # Checkout to PR commit, use the lastest script. + - name: Checkout repository to PR commit + uses: actions/checkout@v4 + - name: Show Git Info + run: | + set -euxo pipefail + git branch -vv + echo "Repository: ${{ github.repository }}" + echo "Ref: ${{ github.ref }}" + echo "Event Name: ${{ github.event_name }}" + echo "Pull Request Number: ${{ github.event.pull_request.number }}" + - name: Install Dependencies + run: | + set -euxo pipefail + sudo apt-get update + sudo apt-get install -y jq + - name: Run Script + id: format_patch + run: | + set -euxo pipefail + + PR_NUMBER=${{ github.event.pull_request.number }} + PATCH_FILENAME="whip-patch-$PR_NUMBER-$(date +%s)" + echo "PR ID is ${{ github.event.pull_request.number }}" + echo "Patch file is $PATCH_FILENAME.patch" + + bash .github/workflows/format-patch.sh $PR_NUMBER "$PATCH_FILENAME.patch" + echo "patch_file=$PATCH_FILENAME" >> $GITHUB_OUTPUT + - name: Upload all patch files + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.format_patch.outputs.patch_file }} + path: | + whip-*.patch + retention-days: 90 + runs-on: ubuntu-22.04 + test-done: needs: - fate @@ -643,6 +695,7 @@ jobs: - openssl-1-1-0h - openssl-3-0 - openssl-latest + - generate-patch steps: - run: echo 'All done' runs-on: ubuntu-22.04 From f25d7d39c187a9809a3a824cfa5a86ab819e9efd Mon Sep 17 00:00:00 2001 From: Winlin Date: Mon, 9 Jun 2025 09:49:55 -0400 Subject: [PATCH 04/12] CICD: Setup the author in git config. (#26) The patch is still generated by git config author. --- .github/workflows/format-patch.sh | 28 ++++++++++++++++++++++------ .github/workflows/test.yml | 7 +++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/.github/workflows/format-patch.sh b/.github/workflows/format-patch.sh index ef67cd50c4cc8..4539d9705f1fa 100755 --- a/.github/workflows/format-patch.sh +++ b/.github/workflows/format-patch.sh @@ -11,6 +11,7 @@ fi PR_NUMBER="$1" PATCH_FILE="$2" +TMP_BRANCH="$3" if [ -z "$PR_NUMBER" ]; then echo "Please provide a PR link or number. For example: https://github.com/ossrs/ffmpeg-webrtc/pull/20" exit 1 @@ -52,7 +53,7 @@ fi git checkout workflows && echo "Switched to workflows branch." && -git pull +git pull && echo "Pulled latest changes from workflows branch." if [[ $? -ne 0 ]]; then echo "Failed to switch to workflows branch or pull latest changes." @@ -71,7 +72,9 @@ if [[ $? -ne 0 ]]; then exit 1 fi -TMP_BRANCH=tmp-branch-for-patch-$PR_NUMBER && +if [[ -z "$TMP_BRANCH" ]]; then + TMP_BRANCH="tmp-branch-for-patch-$PR_NUMBER" +fi && if git branch --list "$TMP_BRANCH" | grep -q "^..$TMP_BRANCH$"; then git branch -D "$TMP_BRANCH" fi && @@ -90,7 +93,7 @@ if [[ -z "$FIRST_AUTHOR_NAME" || -z "$FIRST_AUTHOR_EMAIL" ]]; then exit 1 fi -COAUTHORS=$(git log workflows..HEAD --format='Co-authored-by: %an <%ae>' |grep -v "$FIRST_AUTHOR_NAME" | sort -u) +COAUTHORS=$(git log workflows..HEAD --format='Co-authored-by: %an <%ae>' | sort -u) COAUTHOR_COUNT=$(echo "$COAUTHORS" | wc -l) if [[ "$COAUTHOR_COUNT" -gt 0 ]]; then echo "$COAUTHORS" @@ -109,14 +112,27 @@ fi echo "Commit information:" echo "Author: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" echo "===================================================================" -echo -n -e "$COMMIT_MSG" +echo -e "$COMMIT_MSG" echo "===================================================================" echo "" +if [[ $(git config --list --local |grep 'user.name' >/dev/null 2>&1 && echo yes) != "yes" ]]; then + git config --local user.name "$FIRST_AUTHOR_NAME" +fi && +if [[ $(git config --list --local |grep 'user.email' >/dev/null 2>&1 && echo yes) != "yes" ]]; then + git config --local user.email "$FIRST_AUTHOR_EMAIL" +fi && +git config --list && +echo "Set local git user configuration to: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" +if [[ $? -ne 0 ]]; then + echo "Failed to set local git user configuration." + exit 1 +fi + git rebase workflows && git reset --soft workflows && -git commit --author "$FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -m "$(echo -n -e "$COMMIT_MSG")" && -echo "Squashed commits into a single commit." && +git commit --author "$FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -m "$(echo -e "$COMMIT_MSG")" && +echo "Squashed commits into a single commit." if [[ $? -ne 0 ]]; then echo "Failed to rebase or commit changes." exit 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1a3aefe3ab092..ace9519b88258 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -671,11 +671,18 @@ jobs: PR_NUMBER=${{ github.event.pull_request.number }} PATCH_FILENAME="whip-patch-$PR_NUMBER-$(date +%s)" + TMP_BRANCH="tmp-branch-for-patch-$PR_NUMBER" echo "PR ID is ${{ github.event.pull_request.number }}" echo "Patch file is $PATCH_FILENAME.patch" + echo "Temporary branch is $TMP_BRANCH" bash .github/workflows/format-patch.sh $PR_NUMBER "$PATCH_FILENAME.patch" echo "patch_file=$PATCH_FILENAME" >> $GITHUB_OUTPUT + echo "temporary_branch=$TMP_BRANCH" >> $GITHUB_OUTPUT + - name: Show Branch Info + run: git show ${{ steps.format_patch.outputs.temporary_branch }} + - name: Show Patch File + run: cat ${{ steps.format_patch.outputs.patch_file }}.patch - name: Upload all patch files uses: actions/upload-artifact@v4 with: From 7d8c635c126d3a0c403ae8a4febbf77e85a354dd Mon Sep 17 00:00:00 2001 From: winlin Date: Mon, 9 Jun 2025 10:02:51 -0400 Subject: [PATCH 05/12] CICD: Do not present author as coauthor. --- .github/workflows/format-patch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format-patch.sh b/.github/workflows/format-patch.sh index 4539d9705f1fa..0b712a327a8cd 100755 --- a/.github/workflows/format-patch.sh +++ b/.github/workflows/format-patch.sh @@ -93,7 +93,7 @@ if [[ -z "$FIRST_AUTHOR_NAME" || -z "$FIRST_AUTHOR_EMAIL" ]]; then exit 1 fi -COAUTHORS=$(git log workflows..HEAD --format='Co-authored-by: %an <%ae>' | sort -u) +COAUTHORS=$(git log workflows..HEAD --format='Co-authored-by: %an <%ae>' |grep -v "$FIRST_AUTHOR_NAME" | sort -u) COAUTHOR_COUNT=$(echo "$COAUTHORS" | wc -l) if [[ "$COAUTHOR_COUNT" -gt 0 ]]; then echo "$COAUTHORS" From 87f4731dee5fd2545d40cd64e107fb20f2c247af Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Tue, 10 Jun 2025 09:51:37 +0800 Subject: [PATCH 06/12] workflows/format-patch: fix git format-patch (#27) refer to https://www.ffmpeg.org/developer.html#Submitting-patches-1 add header "X-Unsent: 1" add email recipients Signed-off-by: Jack Lau --- .github/workflows/format-patch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/format-patch.sh b/.github/workflows/format-patch.sh index 0b712a327a8cd..5e80d8c5cc0ea 100755 --- a/.github/workflows/format-patch.sh +++ b/.github/workflows/format-patch.sh @@ -149,7 +149,7 @@ if [[ -z "$PATCH_FILE" ]]; then PATCH_FILE="whip-patch-$PR_NUMBER-$(date +%s).patch" fi && rm -f $PATCH_FILE && -git format-patch -1 --stdout > $PATCH_FILE && +git format-patch --add-header "X-Unsent: 1" --to ffmpeg-devel@ffmpeg.org -1 --stdout > $PATCH_FILE && echo "Created patch file: $PATCH_FILE" if [[ $? -ne 0 ]]; then echo "Failed to create patch file." From 5f2c77c1d7247e4c7626b969c6975feaff1b56df Mon Sep 17 00:00:00 2001 From: Winlin Date: Tue, 10 Jun 2025 10:34:08 -0400 Subject: [PATCH 07/12] CICD: Ignore files in .github for patch (#48) All files in the .github directory pertain to CI/CD and should be ignored; they should not be included in the patch. --- .github/{workflows => docker}/Dockerfile | 0 .github/scripts/format-patch.sh | 189 +++++++++++++++++++++++ .github/workflows/fate-cache.yml | 2 +- .github/workflows/format-patch.sh | 165 -------------------- .github/workflows/test.yml | 11 +- 5 files changed, 200 insertions(+), 167 deletions(-) rename .github/{workflows => docker}/Dockerfile (100%) create mode 100755 .github/scripts/format-patch.sh delete mode 100755 .github/workflows/format-patch.sh diff --git a/.github/workflows/Dockerfile b/.github/docker/Dockerfile similarity index 100% rename from .github/workflows/Dockerfile rename to .github/docker/Dockerfile diff --git a/.github/scripts/format-patch.sh b/.github/scripts/format-patch.sh new file mode 100755 index 0000000000000..3b56e701a652e --- /dev/null +++ b/.github/scripts/format-patch.sh @@ -0,0 +1,189 @@ +#!/bin/bash + +LOGPREFIX=">>" + +if [[ $(jq --version 1>/dev/null 2>&1 && echo yes) != "yes" ]]; then + echo "${LOGPREFIX} Tool jq is not installed. Please install it to parse JSON data. For example:" + echo "${LOGPREFIX} apt install jq" + echo "${LOGPREFIX} brew install jq" + echo "${LOGPREFIX} yum install jq" + echo "${LOGPREFIX} See https://github.com/jqlang/jq" + exit 1 +fi + +PR_NUMBER="$1" +PATCH_FILE="$2" +TMP_BRANCH="$3" +if [ -z "$PR_NUMBER" ]; then + echo "${LOGPREFIX} Please provide a PR link or number. For example: https://github.com/ossrs/ffmpeg-webrtc/pull/20" + exit 1 +fi + +if [[ "$1" =~ ^https://github.com/ossrs/ffmpeg-webrtc/pull/([0-9]+)$ ]]; then + PR_NUMBER="${BASH_REMATCH[1]}" +elif [[ "$1" =~ ^[0-9]+$ ]]; then + PR_NUMBER="$1" +else + echo "${LOGPREFIX} Invalid input format. Please provide a PR link or number. For example: https://github.com/ossrs/ffmpeg-webrtc/pull/20" + exit 1 +fi + +PR_URL="https://github.com/ossrs/ffmpeg-webrtc/pull/$PR_NUMBER" +echo "${LOGPREFIX} Fetching PR #$PR_NUMBER from $PR_URL" + +PR_DATA=$(curl -s "https://api.github.com/repos/ossrs/ffmpeg-webrtc/pulls/$PR_NUMBER") +REPO_NAME=$(printf '%s' "$PR_DATA" | jq -r '.head.repo.full_name') +BRANCH_NAME=$(printf '%s' "$PR_DATA" | jq -r '.head.ref') +echo "${LOGPREFIX} Repository: $REPO_NAME, Branch: $BRANCH_NAME" +if [[ -z "$REPO_NAME" || -z "$BRANCH_NAME" ]]; then + echo "${LOGPREFIX} Error: REPO_NAME or BRANCH_NAME is empty!" + exit 1 +fi + +PR_TITLE=$(printf '%s' "$PR_DATA" | jq -r '.title') +PR_DESCRIPTION=$(printf '%s' "$PR_DATA" | jq -r '.body // ""') +echo "${LOGPREFIX} PR information:" +echo "${LOGPREFIX} ===================================================================" +echo "${LOGPREFIX} $PR_TITLE" +echo "${LOGPREFIX} $PR_DESCRIPTION" +echo "${LOGPREFIX} ===================================================================" +echo "${LOGPREFIX} " +if [[ -z "$PR_TITLE" ]]; then + echo "${LOGPREFIX} Error: PR title is empty!" + exit 1 +fi + +git checkout workflows && +echo "${LOGPREFIX} Switched to workflows branch." && +git pull && +echo "${LOGPREFIX} Pulled latest changes from workflows branch." +if [[ $? -ne 0 ]]; then + echo "${LOGPREFIX} Failed to switch to workflows branch or pull latest changes." + exit 1 +fi + +REMOTE_NAME=patch-tmp && +if git remote | grep -q "^$REMOTE_NAME$"; then + git remote rm "$REMOTE_NAME" +fi && +git remote add $REMOTE_NAME https://github.com/${REPO_NAME}.git && +git fetch $REMOTE_NAME $BRANCH_NAME && +echo "${LOGPREFIX} Fetch remote $REMOTE_NAME at $(git remote get-url $REMOTE_NAME)" +if [[ $? -ne 0 ]]; then + echo "${LOGPREFIX} Failed to fetch remote branch $BRANCH_NAME from $REMOTE_NAME." + exit 1 +fi + +if [[ -z "$TMP_BRANCH" ]]; then + TMP_BRANCH="tmp-branch-for-patch-$PR_NUMBER" +fi && +if git branch --list "$TMP_BRANCH" | grep -q "^..$TMP_BRANCH$"; then + git branch -D "$TMP_BRANCH" +fi && +git checkout -b $TMP_BRANCH $REMOTE_NAME/$BRANCH_NAME && +echo "${LOGPREFIX} Checkout branch $TMP_BRANCH from $REMOTE_NAME/$BRANCH_NAME" +if [[ $? -ne 0 ]]; then + echo "${LOGPREFIX} Failed to checkout branch $TMP_BRANCH from $REMOTE_NAME/$BRANCH_NAME." + exit 1 +fi + +FIRST_AUTHOR_NAME=$(git log workflows..HEAD --reverse --format='%an' | head -n1) +FIRST_AUTHOR_EMAIL=$(git log workflows..HEAD --reverse --format='%ae' | head -n1) +echo "${LOGPREFIX} Author: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" +if [[ -z "$FIRST_AUTHOR_NAME" || -z "$FIRST_AUTHOR_EMAIL" ]]; then + echo "${LOGPREFIX} Error: Unable to determine the first author of the PR." + exit 1 +fi + +COAUTHORS=$(git log workflows..HEAD --format='Co-authored-by: %an <%ae>' |grep -v "$FIRST_AUTHOR_NAME" | sort -u) +COAUTHOR_COUNT=$(echo "$COAUTHORS" | wc -l) +if [[ "$COAUTHOR_COUNT" -gt 0 ]]; then + echo "${LOGPREFIX} $COAUTHORS" +fi + +COMMIT_MSG="$PR_TITLE" +if [[ -n "$PR_DESCRIPTION" ]]; then + COMMIT_MSG="$COMMIT_MSG\n\n$PR_DESCRIPTION" +fi + +if [[ "$COAUTHOR_COUNT" -gt 0 ]]; then + COMMIT_MSG="$COMMIT_MSG\n" + COMMIT_MSG="$COMMIT_MSG\n$COAUTHORS" +fi + +echo "${LOGPREFIX} Commit information:" +echo "${LOGPREFIX} Author: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" +echo "${LOGPREFIX} ===================================================================" +echo -e "$COMMIT_MSG" +echo "${LOGPREFIX} ===================================================================" +echo "${LOGPREFIX} " + +if [[ $(git config --list --local |grep 'user.name' >/dev/null 2>&1 && echo yes) != "yes" ]]; then + git config --local user.name "$FIRST_AUTHOR_NAME" +fi && +if [[ $(git config --list --local |grep 'user.email' >/dev/null 2>&1 && echo yes) != "yes" ]]; then + git config --local user.email "$FIRST_AUTHOR_EMAIL" +fi && +git config --list && +echo "${LOGPREFIX} Set local git user configuration to: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" +if [[ $? -ne 0 ]]; then + echo "${LOGPREFIX} Failed to set local git user configuration." + exit 1 +fi + +git rebase workflows && +git reset --soft workflows && +echo "${LOGPREFIX} Rebased onto workflows branch and reset to soft." +if [[ $? -ne 0 ]]; then + echo "${LOGPREFIX} Failed to rebase or reset changes." + exit 1 +fi + +git status && +git restore --staged .github && +git restore .github && +git status && +echo "${LOGPREFIX} Restored .github directory to the state of workflows branch." +if [[ $? -ne 0 ]]; then + echo "${LOGPREFIX} Failed to restore .github directory." + exit 1 +fi + +if [[ $(git status | grep 'nothing to commit, working tree clean' >/dev/null 2>&1 && echo yes) == "yes" ]]; then + echo "${LOGPREFIX} No changes to commit. Exiting." + git checkout workflows + exit 0 +fi + +git commit --author "$FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -m "$(echo -e "$COMMIT_MSG")" && +echo "${LOGPREFIX} Squashed commits into a single commit." +if [[ $? -ne 0 ]]; then + echo "${LOGPREFIX} Failed to rebase or commit changes." + exit 1 +fi + +git branch -vv && +git log -1 --pretty=format:"%an <%ae> %h %s" +if [[ $? -ne 0 ]]; then + echo "${LOGPREFIX} Failed to display branch information or last commit." + exit 1 +fi + +if [[ -z "$PATCH_FILE" ]]; then + PATCH_FILE="whip-patch-$PR_NUMBER-$(date +%s).patch" +fi && +rm -f $PATCH_FILE && +git format-patch --add-header "X-Unsent: 1" --to ffmpeg-devel@ffmpeg.org -1 --stdout > $PATCH_FILE && +echo "${LOGPREFIX} Created patch file: $PATCH_FILE" +if [[ $? -ne 0 ]]; then + echo "${LOGPREFIX} Failed to create patch file." + exit 1 +fi + +git checkout workflows +#git br -D $TMP_BRANCH +#echo "${LOGPREFIX} Removed temporary branch $TMP_BRANCH." + +echo "${LOGPREFIX} " +echo "${LOGPREFIX} Patch file created: $PATCH_FILE" +echo "${LOGPREFIX} " diff --git a/.github/workflows/fate-cache.yml b/.github/workflows/fate-cache.yml index f8abc46ccf777..77ea32e3f3f4e 100644 --- a/.github/workflows/fate-cache.yml +++ b/.github/workflows/fate-cache.yml @@ -19,7 +19,7 @@ jobs: - name: Build FFmpeg Fate Cache run: | set -euxo pipefail - docker build -t ossrs/srs:ffmpeg-fate -f .github/workflows/Dockerfile . + docker build -t ossrs/srs:ffmpeg-fate -f .github/docker/Dockerfile . - name: Push FFmpeg Fate Cache run: | set -euxo pipefail diff --git a/.github/workflows/format-patch.sh b/.github/workflows/format-patch.sh deleted file mode 100755 index 5e80d8c5cc0ea..0000000000000 --- a/.github/workflows/format-patch.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/bin/bash - -if [[ $(jq --version 1>/dev/null 2>&1 && echo yes) != "yes" ]]; then - echo "Tool jq is not installed. Please install it to parse JSON data. For example:" - echo " apt install jq" - echo " brew install jq" - echo " yum install jq" - echo "See https://github.com/jqlang/jq" - exit 1 -fi - -PR_NUMBER="$1" -PATCH_FILE="$2" -TMP_BRANCH="$3" -if [ -z "$PR_NUMBER" ]; then - echo "Please provide a PR link or number. For example: https://github.com/ossrs/ffmpeg-webrtc/pull/20" - exit 1 -fi - -if [[ "$1" =~ ^https://github.com/ossrs/ffmpeg-webrtc/pull/([0-9]+)$ ]]; then - PR_NUMBER="${BASH_REMATCH[1]}" -elif [[ "$1" =~ ^[0-9]+$ ]]; then - PR_NUMBER="$1" -else - echo "Invalid input format. Please provide a PR link or number. For example: https://github.com/ossrs/ffmpeg-webrtc/pull/20" - exit 1 -fi - -PR_URL="https://github.com/ossrs/ffmpeg-webrtc/pull/$PR_NUMBER" -echo "Fetching PR #$PR_NUMBER from $PR_URL" - -PR_DATA=$(curl -s "https://api.github.com/repos/ossrs/ffmpeg-webrtc/pulls/$PR_NUMBER") -REPO_NAME=$(printf '%s' "$PR_DATA" | jq -r '.head.repo.full_name') -BRANCH_NAME=$(printf '%s' "$PR_DATA" | jq -r '.head.ref') -echo "Repository: $REPO_NAME, Branch: $BRANCH_NAME" -if [[ -z "$REPO_NAME" || -z "$BRANCH_NAME" ]]; then - echo "Error: REPO_NAME or BRANCH_NAME is empty!" - exit 1 -fi - -PR_TITLE=$(printf '%s' "$PR_DATA" | jq -r '.title') -PR_DESCRIPTION=$(printf '%s' "$PR_DATA" | jq -r '.body // ""') -echo "PR information:" -echo "===================================================================" -echo "$PR_TITLE" -echo "$PR_DESCRIPTION" -echo "===================================================================" -echo "" -if [[ -z "$PR_TITLE" ]]; then - echo "Error: PR title is empty!" - exit 1 -fi - -git checkout workflows && -echo "Switched to workflows branch." && -git pull && -echo "Pulled latest changes from workflows branch." -if [[ $? -ne 0 ]]; then - echo "Failed to switch to workflows branch or pull latest changes." - exit 1 -fi - -REMOTE_NAME=patch-tmp && -if git remote | grep -q "^$REMOTE_NAME$"; then - git remote rm "$REMOTE_NAME" -fi && -git remote add $REMOTE_NAME https://github.com/${REPO_NAME}.git && -git fetch $REMOTE_NAME $BRANCH_NAME && -echo "Fetch remote $REMOTE_NAME at $(git remote get-url $REMOTE_NAME)" -if [[ $? -ne 0 ]]; then - echo "Failed to fetch remote branch $BRANCH_NAME from $REMOTE_NAME." - exit 1 -fi - -if [[ -z "$TMP_BRANCH" ]]; then - TMP_BRANCH="tmp-branch-for-patch-$PR_NUMBER" -fi && -if git branch --list "$TMP_BRANCH" | grep -q "^..$TMP_BRANCH$"; then - git branch -D "$TMP_BRANCH" -fi && -git checkout -b $TMP_BRANCH $REMOTE_NAME/$BRANCH_NAME && -echo "Checkout branch $TMP_BRANCH from $REMOTE_NAME/$BRANCH_NAME" -if [[ $? -ne 0 ]]; then - echo "Failed to checkout branch $TMP_BRANCH from $REMOTE_NAME/$BRANCH_NAME." - exit 1 -fi - -FIRST_AUTHOR_NAME=$(git log workflows..HEAD --reverse --format='%an' | head -n1) -FIRST_AUTHOR_EMAIL=$(git log workflows..HEAD --reverse --format='%ae' | head -n1) -echo "Author: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -if [[ -z "$FIRST_AUTHOR_NAME" || -z "$FIRST_AUTHOR_EMAIL" ]]; then - echo "Error: Unable to determine the first author of the PR." - exit 1 -fi - -COAUTHORS=$(git log workflows..HEAD --format='Co-authored-by: %an <%ae>' |grep -v "$FIRST_AUTHOR_NAME" | sort -u) -COAUTHOR_COUNT=$(echo "$COAUTHORS" | wc -l) -if [[ "$COAUTHOR_COUNT" -gt 0 ]]; then - echo "$COAUTHORS" -fi - -COMMIT_MSG="$PR_TITLE" -if [[ -n "$PR_DESCRIPTION" ]]; then - COMMIT_MSG="$COMMIT_MSG\n\n$PR_DESCRIPTION" -fi - -if [[ "$COAUTHOR_COUNT" -gt 0 ]]; then - COMMIT_MSG="$COMMIT_MSG\n" - COMMIT_MSG="$COMMIT_MSG\n$COAUTHORS" -fi - -echo "Commit information:" -echo "Author: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -echo "===================================================================" -echo -e "$COMMIT_MSG" -echo "===================================================================" -echo "" - -if [[ $(git config --list --local |grep 'user.name' >/dev/null 2>&1 && echo yes) != "yes" ]]; then - git config --local user.name "$FIRST_AUTHOR_NAME" -fi && -if [[ $(git config --list --local |grep 'user.email' >/dev/null 2>&1 && echo yes) != "yes" ]]; then - git config --local user.email "$FIRST_AUTHOR_EMAIL" -fi && -git config --list && -echo "Set local git user configuration to: $FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -if [[ $? -ne 0 ]]; then - echo "Failed to set local git user configuration." - exit 1 -fi - -git rebase workflows && -git reset --soft workflows && -git commit --author "$FIRST_AUTHOR_NAME <$FIRST_AUTHOR_EMAIL>" -m "$(echo -e "$COMMIT_MSG")" && -echo "Squashed commits into a single commit." -if [[ $? -ne 0 ]]; then - echo "Failed to rebase or commit changes." - exit 1 -fi - -git branch -vv && -git log -1 --pretty=format:"%an <%ae> %h %s" -if [[ $? -ne 0 ]]; then - echo "Failed to display branch information or last commit." - exit 1 -fi - -if [[ -z "$PATCH_FILE" ]]; then - PATCH_FILE="whip-patch-$PR_NUMBER-$(date +%s).patch" -fi && -rm -f $PATCH_FILE && -git format-patch --add-header "X-Unsent: 1" --to ffmpeg-devel@ffmpeg.org -1 --stdout > $PATCH_FILE && -echo "Created patch file: $PATCH_FILE" -if [[ $? -ne 0 ]]; then - echo "Failed to create patch file." - exit 1 -fi - -git checkout workflows -#git br -D $TMP_BRANCH -#echo "Removed temporary branch $TMP_BRANCH." - -echo "" -echo "Patch file created: $PATCH_FILE" -echo "" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ace9519b88258..397d9c69390a6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -676,14 +676,23 @@ jobs: echo "Patch file is $PATCH_FILENAME.patch" echo "Temporary branch is $TMP_BRANCH" - bash .github/workflows/format-patch.sh $PR_NUMBER "$PATCH_FILENAME.patch" + bash .github/scripts/format-patch.sh $PR_NUMBER "$PATCH_FILENAME.patch" echo "patch_file=$PATCH_FILENAME" >> $GITHUB_OUTPUT echo "temporary_branch=$TMP_BRANCH" >> $GITHUB_OUTPUT + + if [[ -f "$PATCH_FILENAME.patch" ]]; then + echo "has_patch=true" >> $GITHUB_OUTPUT + else + echo "has_patch=false" >> $GITHUB_OUTPUT + fi - name: Show Branch Info + if: ${{ steps.format_patch.outputs.has_patch == 'true' }} run: git show ${{ steps.format_patch.outputs.temporary_branch }} - name: Show Patch File + if: ${{ steps.format_patch.outputs.has_patch == 'true' }} run: cat ${{ steps.format_patch.outputs.patch_file }}.patch - name: Upload all patch files + if: ${{ steps.format_patch.outputs.has_patch == 'true' }} uses: actions/upload-artifact@v4 with: name: ${{ steps.format_patch.outputs.patch_file }} From 688cb249cebe769dc6346718291eacf12ca6f59f Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Sat, 21 Jun 2025 10:19:44 +0800 Subject: [PATCH 08/12] Workflows: add pion and janus test (#53) This PR refer to https://github.com/ossrs/ffmpeg-webrtc/discussions/39 and https://github.com/ossrs/ffmpeg-webrtc/discussions/38 --------- Signed-off-by: Jack Lau --- .github/workflows/test.yml | 129 +++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 397d9c69390a6..1a8ced2650028 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -152,6 +152,133 @@ jobs: run: exit 1 runs-on: ubuntu-22.04 + pion: + name: "FFmpeg with Pion" + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config jq libssl-dev libopus-dev libx264-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ + --enable-libx264 --enable-gpl --enable-libopus + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.22' + - name: Verify Go version + run: go version + - name: Start Pion + run: | + set -euxo pipefail + git clone https://github.com/pion/webrtc.git + cd webrtc/examples/whip-whep + go run *.go & + - name: Streaming with FFmpeg + run: | + set -euxo pipefail + nohup ./ffmpeg -t 30 -re -f lavfi -i testsrc=size=1280x720 -f lavfi -i sine=frequency=440 -pix_fmt yuv420p \ + -vcodec libx264 -profile:v baseline -r 25 -g 50 -acodec libopus -ar 48000 -ac 2 \ + -f whip -authorization "seanTest" "http://localhost:8080/whip" \ + 1>ffstdout.log 2>ffstderr.log & + - name: Stop FFmpeg normally + run: | + pkill -SIGINT ffmpeg && sleep 3 || + echo "FFmpeg process not found or already stopped." + - name: Show FFmpeg Stdout Log + run: cat ffstdout.log + - name: Show FFmpeg Stderr Log + run: cat ffstderr.log + - name: Check FFmpeg Exit Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'Exiting normally' && exit 0 + echo "Exiting normally not found in ffstderr.log" && exit 1 + - name: Check Stream Existence + if: ${{ steps.streaming.outputs.has_stream == 'false' }} + run: exit 1 + runs-on: ubuntu-22.04 + + janus: + name: "FFmpeg with Janus" + needs: build + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Build FFmpeg + run: | + set -euxo pipefail + + # Install dependencies + sudo apt-get update + sudo apt-get install -y nasm pkg-config jq libssl-dev libopus-dev libx264-dev + + # Build FFmpeg with WebRTC support + ./configure --enable-muxer=whip --enable-openssl --enable-version3 \ + --enable-libx264 --enable-gpl --enable-libopus + make -j$(nproc) + ./ffmpeg -version && ./ffmpeg -muxers 2>/dev/null |grep whip + - name: Start Janus + run: | + set -euxo pipefail + git clone https://github.com/winlinvip/janus-docker.git + (cd janus-docker && + ip=$(ifconfig eth0 | grep 'inet ' | awk '{print $2}') && + sed -i "s|\(^[[:blank:]]*nat_1_1_mapping *=\).*|\1\"$ip\"|g" janus.jcfg && + docker run --rm -d -p 8081:8080 -p 8188:8188 -p 8443:8443 -p 20000-20010:20000-20010/udp \ + -v $(pwd)/janus.jcfg:/usr/local/etc/janus/janus.jcfg \ + -v $(pwd)/janus.plugin.videoroom.jcfg:/usr/local/etc/janus/janus.plugin.videoroom.jcfg \ + -v $(pwd)/janus.transport.http.jcfg:/usr/local/etc/janus/janus.transport.http.jcfg \ + -v $(pwd)/janus.transport.websockets.jcfg:/usr/local/etc/janus/janus.transport.websockets.jcfg \ + -v $(pwd)/videoroomtest.js:/usr/local/share/janus/demos/videoroomtest.js \ + ossrs/janus:v1.0.12) + + git clone https://github.com/meetecho/simple-whip-server.git + cd simple-whip-server + git checkout bd2d98898b9842bfc329443b46bcc906aab857aa + npm install + npm run build + npm run start & + + - name: Streaming with FFmpeg + run: | + set -euxo pipefail + curl -H 'Content-Type: application/json' -d '{"id": "abc123", "room": 2345}' \ + http://localhost:7080/whip/create + nohup ./ffmpeg -t 30 -re -f lavfi -i testsrc=size=1280x720 -f lavfi -i sine=frequency=440 -pix_fmt yuv420p \ + -vcodec libx264 -profile:v baseline -r 25 -g 50 -acodec libopus -ar 48000 -ac 2 \ + -f whip 'http://localhost:7080/whip/endpoint/abc123' \ + 1>ffstdout.log 2>ffstderr.log & + - name: Stop FFmpeg normally + run: | + pkill -SIGINT ffmpeg && sleep 3 || + echo "FFmpeg process not found or already stopped." + - name: Show FFmpeg Stdout Log + run: cat ffstdout.log + - name: Show FFmpeg Stderr Log + run: cat ffstderr.log + - name: Check FFmpeg Exit Log + run: | + set -euxo pipefail + cat ffstderr.log |grep 'Exiting normally' && exit 0 + echo "Exiting normally not found in ffstderr.log" && exit 1 + - name: Check Stream Existence + if: ${{ steps.streaming.outputs.has_stream == 'false' }} + run: exit 1 + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + runs-on: ubuntu-22.04 + asan: name: "FFmpeg with Asan" needs: build @@ -705,6 +832,8 @@ jobs: needs: - fate - srs + - pion + - janus - asan - openssl-1-0-1k - openssl-1-0-2 From 95161881a59bc03901e5399ff4c55610f07f84c3 Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 27 Jun 2025 07:10:37 -0400 Subject: [PATCH 09/12] AI: Add ignore for augment code. --- .augmentignore | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .augmentignore diff --git a/.augmentignore b/.augmentignore new file mode 100644 index 0000000000000..0ec86037100e4 --- /dev/null +++ b/.augmentignore @@ -0,0 +1,25 @@ + +# Build artifacts +**/objs/** +**/build/** +**/*.o +**/*.a +**/*.so +**/*.dylib +**/*.d + +# IDE files +**/.idea/** +**/.vscode/** +**/.run/** + +# Generated files +**/.tmp/** +**/fate-suite/** +**/*.flv +**/*.mp4 +**/*.ts + +# Other files. +**/tools/** +**/tests/** From 544578b11dc46d97fdec5e32952702e9736c069f Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 27 Jun 2025 07:59:32 -0400 Subject: [PATCH 10/12] AI: Add guideline for augment code. --- .augment-guidelines | 62 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .augment-guidelines diff --git a/.augment-guidelines b/.augment-guidelines new file mode 100644 index 0000000000000..79e2b5b32f305 --- /dev/null +++ b/.augment-guidelines @@ -0,0 +1,62 @@ +# Augment Guidelines for FFmpeg Repository + +project: + name: "FFmpeg" + description: | + A complete, cross-platform solution to record, convert and stream audio and video. + type: "media" + +architecture: + overview: | + FFmpeg is organized into several core libraries that handle different aspects of + multimedia processing. The codebase follows a modular design where each library + can be used independently or together. FFmpeg also provides command-line tools + built on top of these libraries. + + key_directories: + - path: "libavcodec" + description: | + Implements encoders and decoders for audio/video codecs and bitstream processing + - path: "libavdevice" + description: | + Provides abstraction for accessing capture and playback devices + - path: "libavfilter" + description: | + Implements media filtering framework for processing audio and video + - path: "libavformat" + description: | + Handles container formats, muxing/demuxing, and I/O protocols + - path: "libavutil" + description: | + Contains utility functions, data structures, and common components shared across + libraries + - path: "libswresample" + description: | + Implements audio mixing and resampling routines + - path: "tests" + description: | + Contains test suites and validation tools for FFmpeg functionality + +components: + - name: "WHIP" + description: | + WebRTC-HTTP Ingestion Protocol implementation for low-latency streaming. Handles + SDP exchange, ICE connectivity, DTLS handshake, SRTP encryption, and RTP + packetization for WebRTC streaming. + related_files: + - path: "libavformat/whip.c" + description: | + Core implementation of the WHIP protocol, including SDP offer/answer exchange, + ICE connectivity, DTLS handshake setup, and SRTP encryption for RTP packets + - path: "libavformat/tls.h" + description: | + Header defining the DTLS interface used by WHIP for secure communication, + including functions for certificate handling and DTLS state management + - path: "libavformat/tls.c" + description: | + Common DTLS implementation shared across different SSL backends, providing + UDP socket setup for DTLS connections + - path: "libavformat/tls_openssl.c" + description: | + OpenSSL-specific implementation of DTLS functionality, including handshake + procedures and SRTP key material export From 94675617aa5a552e46e8eba316d0c2bc74838aea Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Thu, 17 Jul 2025 10:03:34 +0800 Subject: [PATCH 11/12] avformat/whip: add support active and passive dtls role Signed-off-by: Jack Lau --- libavformat/whip.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libavformat/whip.c b/libavformat/whip.c index fd6de8503f064..d72703ad9af6f 100644 --- a/libavformat/whip.c +++ b/libavformat/whip.c @@ -201,6 +201,7 @@ typedef struct WHIPContext { /* The callback return value for DTLS. */ int dtls_ret; int dtls_closed; + int is_active; /* Parameters for the input audio and video codecs. */ AVCodecParameters *audio_par; @@ -641,7 +642,7 @@ static int generate_sdp_offer(AVFormatContext *s) "a=ice-ufrag:%s\r\n" "a=ice-pwd:%s\r\n" "a=fingerprint:sha-256 %s\r\n" - "a=setup:passive\r\n" + "a=setup:%s\r\n" "a=mid:0\r\n" "a=sendonly\r\n" "a=msid:FFmpeg audio\r\n" @@ -653,6 +654,7 @@ static int generate_sdp_offer(AVFormatContext *s) whip->ice_ufrag_local, whip->ice_pwd_local, whip->dtls_fingerprint, + whip->is_active ? "active" : "passive", whip->audio_payload_type, acodec_name, whip->audio_par->sample_rate, @@ -676,7 +678,7 @@ static int generate_sdp_offer(AVFormatContext *s) "a=ice-ufrag:%s\r\n" "a=ice-pwd:%s\r\n" "a=fingerprint:sha-256 %s\r\n" - "a=setup:passive\r\n" + "a=setup:%s\r\n" "a=mid:1\r\n" "a=sendonly\r\n" "a=msid:FFmpeg video\r\n" @@ -690,6 +692,7 @@ static int generate_sdp_offer(AVFormatContext *s) whip->ice_ufrag_local, whip->ice_pwd_local, whip->dtls_fingerprint, + whip->is_active ? "active" : "passive", whip->video_payload_type, vcodec_name, whip->video_payload_type, @@ -1266,7 +1269,7 @@ static int ice_dtls_handshake(AVFormatContext *s) } /* Read the STUN or DTLS messages from peer. */ - for (i = 0; i < ICE_DTLS_READ_INTERVAL / 5 && whip->state < WHIP_STATE_DTLS_CONNECTING; i++) { + for (i = 0; i < ICE_DTLS_READ_INTERVAL / 5 && (whip->is_active ? whip->state < WHIP_STATE_ICE_CONNECTED : whip->state < WHIP_STATE_DTLS_CONNECTING); i++) { ret = ffurl_read(whip->udp, whip->buf, sizeof(whip->buf)); if (ret > 0) break; @@ -1279,7 +1282,7 @@ static int ice_dtls_handshake(AVFormatContext *s) } /* Got nothing, continue to process handshake. */ - if (ret <= 0 && whip->state < WHIP_STATE_DTLS_CONNECTING) + if (ret <= 0 && (whip->is_active ? whip->state < WHIP_STATE_ICE_CONNECTED : whip->state < WHIP_STATE_DTLS_CONNECTING)) continue; /* Handle the ICE binding response. */ @@ -1303,7 +1306,7 @@ static int ice_dtls_handshake(AVFormatContext *s) } else av_dict_set(&opts, "key_pem", whip->key_buf, 0); av_dict_set_int(&opts, "external_sock", 1, 0); - av_dict_set_int(&opts, "listen", 1, 0); + av_dict_set_int(&opts, "listen", whip->is_active ? 0 : 1, 0); /* If got the first binding response, start DTLS handshake. */ ret = ffurl_open_whitelist(&whip->dtls_uc, buf, AVIO_FLAG_READ_WRITE, &s->interrupt_callback, &opts, s->protocol_whitelist, s->protocol_blacklist, NULL); @@ -1323,7 +1326,7 @@ static int ice_dtls_handshake(AVFormatContext *s) } /* If got any DTLS messages, handle it. */ - if (is_dtls_packet(whip->buf, ret) && whip->state >= WHIP_STATE_ICE_CONNECTED || whip->state == WHIP_STATE_DTLS_CONNECTING) { + if ((is_dtls_packet(whip->buf, ret) || whip->is_active) && whip->state >= WHIP_STATE_ICE_CONNECTED || whip->state == WHIP_STATE_DTLS_CONNECTING) { whip->state = WHIP_STATE_DTLS_CONNECTING; if ((ret = ffurl_handshake(whip->dtls_uc)) < 0) goto end; @@ -1901,6 +1904,7 @@ static const AVOption options[] = { { "authorization", "The optional Bearer token for WHIP Authorization", OFFSET(authorization), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, ENC }, { "cert_file", "The optional certificate file path for DTLS", OFFSET(cert_file), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, ENC }, { "key_file", "The optional private key file path for DTLS", OFFSET(key_file), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, ENC }, + { "is_active", "Optional dtls role for WHIP, 1 for active, 0 for passive", OFFSET(is_active), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, ENC }, { NULL }, }; From 65780461fd615745915da2d8a72dc09e472006e1 Mon Sep 17 00:00:00 2001 From: Jack Lau Date: Fri, 18 Jul 2025 15:15:24 +0800 Subject: [PATCH 12/12] avformat/whip: properly set the send key and recv key depends on DTLS role As DTLS server, the recv key is client master key plus salt, the send key is server master key plus salt. As DTLS client, the recv key is server master key plus salt, the send key is client master key plus salt. Signed-off-by: Jack Lau --- libavformat/whip.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libavformat/whip.c b/libavformat/whip.c index d72703ad9af6f..5bd8a2be8b65f 100644 --- a/libavformat/whip.c +++ b/libavformat/whip.c @@ -1378,13 +1378,11 @@ static int setup_srtp(AVFormatContext *s) char *client_salt = server_key + DTLS_SRTP_KEY_LEN; char *server_salt = client_salt + DTLS_SRTP_SALT_LEN; - /* As DTLS server, the recv key is client master key plus salt. */ - memcpy(recv_key, client_key, DTLS_SRTP_KEY_LEN); - memcpy(recv_key + DTLS_SRTP_KEY_LEN, client_salt, DTLS_SRTP_SALT_LEN); + memcpy(whip->is_active ? send_key : recv_key, client_key, DTLS_SRTP_KEY_LEN); + memcpy(whip->is_active ? send_key + DTLS_SRTP_KEY_LEN : recv_key + DTLS_SRTP_KEY_LEN, client_salt, DTLS_SRTP_SALT_LEN); - /* As DTLS server, the send key is server master key plus salt. */ - memcpy(send_key, server_key, DTLS_SRTP_KEY_LEN); - memcpy(send_key + DTLS_SRTP_KEY_LEN, server_salt, DTLS_SRTP_SALT_LEN); + memcpy(whip->is_active ? recv_key : send_key, server_key, DTLS_SRTP_KEY_LEN); + memcpy(whip->is_active ? recv_key + DTLS_SRTP_KEY_LEN : send_key + DTLS_SRTP_KEY_LEN, server_salt, DTLS_SRTP_SALT_LEN); /* Setup SRTP context for outgoing packets */ if (!av_base64_encode(buf, sizeof(buf), send_key, sizeof(send_key))) {