Skip to content

Commit d0d23bd

Browse files
youge325SigureMoCopilot
authored
Add ARM wheels build in CI (#4)
Co-authored-by: SigureMo <sigure.qaq@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7f1306e commit d0d23bd

3 files changed

Lines changed: 176 additions & 59 deletions

File tree

.github/workflows/paddle_wheel.yaml

Lines changed: 83 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,61 @@ defaults:
2020
run:
2121
shell: bash -l -eo pipefail {0}
2222

23+
env:
24+
PADDLECODEC_TEST_VIDEO_URL: https://paddlenlp.bj.bcebos.com/datasets/paddlemix/demo_video/example_video.mp4
25+
PADDLECODEC_TEST_VIDEO_CACHE_KEY: paddlecodec-test-video-v1-example-video
26+
PADDLECODEC_TEST_VIDEO_PATH: .github/test-assets/example_video.mp4
27+
2328
jobs:
24-
build-paddlecodec-wheel:
29+
prepare-test-video:
2530
runs-on: ubuntu-latest
31+
name: Prepare cached Paddle test video
32+
steps:
33+
- name: Restore cached test video
34+
id: cache-test-video
35+
uses: actions/cache@v4
36+
with:
37+
path: ${{ env.PADDLECODEC_TEST_VIDEO_PATH }}
38+
key: ${{ env.PADDLECODEC_TEST_VIDEO_CACHE_KEY }}
39+
40+
- name: Download test video
41+
if: steps.cache-test-video.outputs.cache-hit != 'true'
42+
run: |
43+
mkdir -p "$(dirname "${PADDLECODEC_TEST_VIDEO_PATH}")"
44+
curl --fail --location --retry 5 --retry-all-errors \
45+
--output "${PADDLECODEC_TEST_VIDEO_PATH}" \
46+
"${PADDLECODEC_TEST_VIDEO_URL}"
47+
48+
- name: Upload cached test video artifact
49+
uses: actions/upload-artifact@v5
50+
with:
51+
name: paddlecodec-test-video
52+
path: ${{ env.PADDLECODEC_TEST_VIDEO_PATH }}
53+
if-no-files-found: error
54+
55+
build-paddlecodec-wheel:
56+
name: Build and upload Paddle wheel (${{ matrix.arch-name }}, py${{ matrix.python-version }})
57+
runs-on: ${{ matrix.runner }}
2658
container:
27-
image: pytorch/manylinux2_28-builder:cpu
59+
image: ${{ matrix.container-image }}
2860
strategy:
2961
fail-fast: false
3062
matrix:
3163
python-version: ["3.10", "3.11", "3.12", "3.13"]
64+
arch: ["x86_64", "arm64"]
65+
include:
66+
- arch: x86_64
67+
arch-name: x86_64
68+
runner: ubuntu-latest
69+
container-image: pytorch/manylinux2_28-builder:cpu
70+
artifact-prefix: paddlecodec-wheel-linux
71+
wheel-platform: manylinux_2_28_x86_64
72+
- arch: arm64
73+
arch-name: arm64
74+
runner: ubuntu-24.04-arm
75+
container-image: pytorch/manylinux2_28_aarch64-builder:cpu-aarch64
76+
artifact-prefix: paddlecodec-wheel-linux-arm64
77+
wheel-platform: manylinux_2_28_aarch64
3278
permissions:
3379
id-token: write
3480
contents: read
@@ -59,38 +105,27 @@ jobs:
59105
60106
- name: Build wheel
61107
run: |
62-
# Use pre-built FFmpeg from PyTorch S3
63108
export BUILD_AGAINST_ALL_FFMPEG_FROM_S3=1
109+
export I_CONFIRM_THIS_IS_NOT_A_LICENSE_VIOLATION=1
64110
export TORCHCODEC_CMAKE_BUILD_DIR=$(pwd)/build_cmake
65111
python -m build --wheel -vvv --no-isolation
66112
67113
- name: Repair wheel
68114
run: |
69115
pip install auditwheel
70116
71-
# 1. Extract internal libraries from the wheel to a temporary directory
72-
# This allows auditwheel to find them when checking dependencies
73117
mkdir -p temp_libs
74118
unzip -j dist/*.whl "torchcodec/*.so" -d temp_libs || true
75119
76-
# 2. Prepare LD_LIBRARY_PATH
77-
# FFmpeg libraries
78-
FFMPEG_LIB_PATHS=$(find $(pwd)/build_cmake/_deps -type d -name "lib" | tr '\n' ':')
79-
# PaddlePaddle libraries
120+
FFMPEG_LIB_PATHS=$(find "$(pwd)/build_cmake/_deps" -type d -name "lib" -print | paste -sd: -)
80121
PADDLE_PATH=$(python -c "import paddle; print(paddle.__path__[0])")
81122
PADDLE_LIB_PATHS="$PADDLE_PATH/base:$PADDLE_PATH/libs"
82-
# Wheel internal libraries
83123
INTERNAL_LIB_PATH=$(pwd)/temp_libs
84124
85-
export LD_LIBRARY_PATH=${FFMPEG_LIB_PATHS}${PADDLE_LIB_PATHS}:${INTERNAL_LIB_PATH}:${LD_LIBRARY_PATH}
125+
export LD_LIBRARY_PATH=${FFMPEG_LIB_PATHS}:${PADDLE_LIB_PATHS}:${INTERNAL_LIB_PATH}:${LD_LIBRARY_PATH}
86126
87-
# 3. Repair wheel with auditwheel
88-
# We exclude all external libraries because we want to rely on system libraries (like FFmpeg)
89-
# or libraries provided by other packages (like PaddlePaddle).
90-
# auditwheel 6.1.0+ supports wildcards in --exclude.
91-
auditwheel repair dist/*.whl --plat manylinux_2_28_x86_64 -w wheelhouse/ --exclude "*"
127+
auditwheel repair dist/*.whl --plat ${{ matrix.wheel-platform }} -w wheelhouse/ --exclude "*"
92128
93-
# Cleanup
94129
rm -rf temp_libs
95130
rm dist/*.whl
96131
mv wheelhouse/*.whl dist/
@@ -99,7 +134,7 @@ jobs:
99134
- name: Upload wheel artifact
100135
uses: actions/upload-artifact@v5
101136
with:
102-
name: paddlecodec-wheel-linux-py${{ matrix.python-version }}
137+
name: ${{ matrix.artifact-prefix }}-py${{ matrix.python-version }}
103138
path: dist/*.whl
104139

105140
- name: Run post-build script
@@ -113,31 +148,49 @@ jobs:
113148
unzip -l $wheel_path
114149
115150
test-paddlecodec-wheel:
116-
needs: build-paddlecodec-wheel
117-
runs-on: ubuntu-latest
151+
name: Install and test Paddle wheel (${{ matrix.arch-name }}, py${{ matrix.python-version }}, ffmpeg ${{ matrix.ffmpeg-version }})
152+
needs: [prepare-test-video, build-paddlecodec-wheel]
153+
runs-on: ${{ matrix.runner }}
154+
container:
155+
image: ${{ matrix.container-image }}
156+
env:
157+
PADDLECODEC_TEST_VIDEO: .github/test-assets/example_video.mp4
118158
strategy:
119159
fail-fast: false
120160
matrix:
121161
python-version: ["3.10", "3.11", "3.12", "3.13"]
162+
arch: ["x86_64", "arm64"]
122163
# FFmpeg 8.0 depends on libopenvino.so.2520, PaddlePaddle CPU depends on libopenvino.so.2500
123164
# There has some conflict causing test failures, but it works with PaddlePaddle GPU.
124165
# We skip FFmpeg 8.0 tests for PaddlePaddle CPU builds for now.
125166
ffmpeg-version: ["4.4.2", "5.1.2", "6.1.1", "7.0.1"]
167+
include:
168+
- arch: x86_64
169+
arch-name: x86_64
170+
runner: ubuntu-latest
171+
container-image: pytorch/manylinux2_28-builder:cpu
172+
artifact-prefix: paddlecodec-wheel-linux
173+
- arch: arm64
174+
arch-name: arm64
175+
runner: ubuntu-24.04-arm
176+
container-image: pytorch/manylinux2_28_aarch64-builder:cpu-aarch64
177+
artifact-prefix: paddlecodec-wheel-linux-arm64
126178
steps:
127179
- name: Checkout repository
128180
uses: actions/checkout@v6
129181

130-
- name: Set up Python ${{ matrix.python-version }}
131-
uses: actions/setup-python@v5
132-
with:
133-
python-version: ${{ matrix.python-version }}
134-
135182
- name: Download wheel artifact
136183
uses: actions/download-artifact@v4
137184
with:
138-
name: paddlecodec-wheel-linux-py${{ matrix.python-version }}
185+
name: ${{ matrix.artifact-prefix }}-py${{ matrix.python-version }}
139186
path: dist/
140187

188+
- name: Download cached test video artifact
189+
uses: actions/download-artifact@v4
190+
with:
191+
name: paddlecodec-test-video
192+
path: .github/test-assets/
193+
141194
- name: Install FFmpeg via conda
142195
uses: conda-incubator/setup-miniconda@v3
143196
with:
@@ -167,7 +220,6 @@ jobs:
167220
168221
- name: Delete src folder
169222
run: |
170-
# Delete src/ to ensure we're testing the installed wheel, not source code
171223
rm -rf src/
172224
ls -la
173225
@@ -177,18 +229,17 @@ jobs:
177229
178230
publish-pypi:
179231
runs-on: ubuntu-latest
180-
name: Publish to PyPI
232+
name: Publish Paddle wheels to PyPI
181233
if: "startsWith(github.ref, 'refs/tags/')"
182234
needs:
183235
- test-paddlecodec-wheel
184236
permissions:
185237
id-token: write
186-
187238
steps:
188239
- name: Retrieve release distributions
189240
uses: actions/download-artifact@v6
190241
with:
191-
pattern: paddlecodec-wheel-linux-*
242+
pattern: paddlecodec-wheel-linux*
192243
path: dist/
193244
merge-multiple: true
194245

@@ -197,7 +248,7 @@ jobs:
197248

198249
publish-release:
199250
runs-on: ubuntu-latest
200-
name: Publish to GitHub
251+
name: Publish Paddle wheels to GitHub
201252
if: "startsWith(github.ref, 'refs/tags/')"
202253
needs:
203254
- test-paddlecodec-wheel
@@ -206,7 +257,7 @@ jobs:
206257
steps:
207258
- uses: actions/download-artifact@v6
208259
with:
209-
pattern: paddlecodec-wheel-linux-*
260+
pattern: paddlecodec-wheel-linux*
210261
path: dist/
211262
merge-multiple: true
212263
- name: Get tag name

src/torchcodec/_core/fetch_and_expose_non_gpl_ffmpeg_libs.cmake

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,59 @@ set(
2323
if (LINUX)
2424
set(lib_dir "lib")
2525

26-
set(
27-
platform_url
28-
${base_url}/linux_x86_64
29-
)
26+
if (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64")
27+
set(
28+
platform_url
29+
${base_url}/linux_aarch64
30+
)
3031

31-
set(
32-
f4_sha256
33-
1a083f1922443bedb5243d04896383b8c606778a7ddb9d886c8303e55339fe0c
34-
)
35-
set(
36-
f5_sha256
37-
65d6ad54082d94dcb3f801d73df2265e0e1bb303c7afbce7723e3b77ccd0e207
38-
)
39-
set(
40-
f6_sha256
41-
8bd5939c2f4a4b072e837e7870c13fe7d13824e5ff087ab534e4db4e90b7be9c
42-
)
43-
set(
44-
f7_sha256
45-
1cb946d8b7c6393c2c3ebe1f900b8de7a2885fe614c45d4ec32c9833084f2f26
46-
)
47-
set(
48-
f8_sha256
49-
c55b3c1a4b5e4d5fdd7c632bea3ab6f45b4e37cc8e0999dda3f84a8ed8defad8
50-
)
32+
set(
33+
f4_sha256
34+
a310a2ed9ffe555fd3278dae15065541098dd35e124564671dcda6a6620ac842
35+
)
36+
set(
37+
f5_sha256
38+
89ca7996bccbc2db49adaa401d20fdbabffe0e1b4e07a0f81d6b143e858b7c8d
39+
)
40+
set(
41+
f6_sha256
42+
ae44c67b4587d061b8e9cc8990ca891ee013fe52ad79e5016ba29871562621da
43+
)
44+
set(
45+
f7_sha256
46+
948e2cac66ca6f68ff526d5e84138e94bce0f1a7c83f502d15d85d0bd3ddc112
47+
)
48+
set(
49+
f8_sha256
50+
b9cfd99ae75a14e58300854967d4dc49de0b3daa551df51ea1f52a3f08d2c8af
51+
)
52+
else()
53+
set(
54+
platform_url
55+
${base_url}/linux_x86_64
56+
)
57+
58+
set(
59+
f4_sha256
60+
1a083f1922443bedb5243d04896383b8c606778a7ddb9d886c8303e55339fe0c
61+
)
62+
set(
63+
f5_sha256
64+
65d6ad54082d94dcb3f801d73df2265e0e1bb303c7afbce7723e3b77ccd0e207
65+
)
66+
set(
67+
f6_sha256
68+
8bd5939c2f4a4b072e837e7870c13fe7d13824e5ff087ab534e4db4e90b7be9c
69+
)
70+
set(
71+
f7_sha256
72+
1cb946d8b7c6393c2c3ebe1f900b8de7a2885fe614c45d4ec32c9833084f2f26
73+
)
74+
set(
75+
f8_sha256
76+
c55b3c1a4b5e4d5fdd7c632bea3ab6f45b4e37cc8e0999dda3f84a8ed8defad8
77+
)
78+
endif()
5179
set(
5280
f4_library_file_names
5381
libavutil.so.56

test_paddle/test_video_decode.py

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
paddle.enable_compat(scope={"torchcodec"})
33

44
import pytest
5+
import subprocess
56
from dataclasses import dataclass, fields
67
from io import BytesIO
78
from typing import Callable, Mapping, Optional, Union
@@ -11,6 +12,40 @@
1112
import numpy as np
1213

1314

15+
def ffmpeg_rgb_sum(video_path_or_url: str) -> int:
16+
# Use the local FFmpeg build as the oracle because YUV->RGB conversion is
17+
# architecture- and FFmpeg-build-dependent.
18+
proc = subprocess.Popen(
19+
[
20+
"ffmpeg",
21+
"-v",
22+
"error",
23+
"-vsync",
24+
"0",
25+
"-i",
26+
video_path_or_url,
27+
"-f",
28+
"rawvideo",
29+
"-pix_fmt",
30+
"rgb24",
31+
"-",
32+
],
33+
stdout=subprocess.PIPE,
34+
stderr=subprocess.PIPE,
35+
)
36+
assert proc.stdout is not None
37+
assert proc.stderr is not None
38+
39+
total = 0
40+
while chunk := proc.stdout.read(16 * 1024 * 1024):
41+
total += sum(chunk)
42+
43+
stderr = proc.stderr.read().decode("utf-8", "ignore")
44+
if proc.wait() != 0:
45+
raise RuntimeError(f"ffmpeg failed to decode video: {stderr}")
46+
return total
47+
48+
1449
@dataclass
1550
class VideoMetadata(Mapping):
1651
total_num_frames: int
@@ -169,9 +204,12 @@ def sample_indices_fn_func(metadata, **fn_kwargs):
169204

170205

171206
def test_video_decode():
172-
url = "https://paddlenlp.bj.bcebos.com/datasets/paddlemix/demo_video/example_video.mp4"
173-
video, metadata = load_video(url, backend="torchcodec")
174-
assert video.to(paddle.int64).sum().item() == 247759890390
207+
video_path = os.getenv(
208+
"PADDLECODEC_TEST_VIDEO",
209+
"https://paddlenlp.bj.bcebos.com/datasets/paddlemix/demo_video/example_video.mp4",
210+
)
211+
video, metadata = load_video(video_path, backend="torchcodec")
212+
assert video.to(paddle.int64).sum().item() == ffmpeg_rgb_sum(video_path)
175213
assert metadata.total_num_frames == 263
176214
assert metadata.fps == pytest.approx(29.99418249715141)
177215
assert metadata.width == 1920

0 commit comments

Comments
 (0)