patch-torchcodec 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- patch_torchcodec-0.1.0/.gitignore +228 -0
- patch_torchcodec-0.1.0/PKG-INFO +87 -0
- patch_torchcodec-0.1.0/README.md +63 -0
- patch_torchcodec-0.1.0/__init__.py +49 -0
- patch_torchcodec-0.1.0/__main__.py +223 -0
- patch_torchcodec-0.1.0/core.py +361 -0
- patch_torchcodec-0.1.0/pyproject.toml +42 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# Manually added items (project-specific)
|
|
3
|
+
# ============================================================================
|
|
4
|
+
|
|
5
|
+
# Version file (auto-generated by hatch-vcs)
|
|
6
|
+
/src/mediaref/_version.py
|
|
7
|
+
|
|
8
|
+
# ============================================================================
|
|
9
|
+
# Below items are from GitHub's official Python .gitignore template
|
|
10
|
+
# https://github.com/github/gitignore/blob/main/Python.gitignore
|
|
11
|
+
# ============================================================================
|
|
12
|
+
|
|
13
|
+
# Byte-compiled / optimized / DLL files
|
|
14
|
+
__pycache__/
|
|
15
|
+
*.py[codz]
|
|
16
|
+
*$py.class
|
|
17
|
+
|
|
18
|
+
# C extensions
|
|
19
|
+
*.so
|
|
20
|
+
|
|
21
|
+
# Distribution / packaging
|
|
22
|
+
.Python
|
|
23
|
+
build/
|
|
24
|
+
develop-eggs/
|
|
25
|
+
dist/
|
|
26
|
+
downloads/
|
|
27
|
+
eggs/
|
|
28
|
+
.eggs/
|
|
29
|
+
lib/
|
|
30
|
+
lib64/
|
|
31
|
+
parts/
|
|
32
|
+
sdist/
|
|
33
|
+
var/
|
|
34
|
+
wheels/
|
|
35
|
+
share/python-wheels/
|
|
36
|
+
*.egg-info/
|
|
37
|
+
.installed.cfg
|
|
38
|
+
*.egg
|
|
39
|
+
MANIFEST
|
|
40
|
+
|
|
41
|
+
# PyInstaller
|
|
42
|
+
# Usually these files are written by a python script from a template
|
|
43
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
44
|
+
*.manifest
|
|
45
|
+
*.spec
|
|
46
|
+
|
|
47
|
+
# Installer logs
|
|
48
|
+
pip-log.txt
|
|
49
|
+
pip-delete-this-directory.txt
|
|
50
|
+
|
|
51
|
+
# Unit test / coverage reports
|
|
52
|
+
htmlcov/
|
|
53
|
+
.tox/
|
|
54
|
+
.nox/
|
|
55
|
+
.coverage
|
|
56
|
+
.coverage.*
|
|
57
|
+
.cache
|
|
58
|
+
nosetests.xml
|
|
59
|
+
coverage.xml
|
|
60
|
+
*.cover
|
|
61
|
+
*.py.cover
|
|
62
|
+
.hypothesis/
|
|
63
|
+
.pytest_cache/
|
|
64
|
+
cover/
|
|
65
|
+
|
|
66
|
+
# Translations
|
|
67
|
+
*.mo
|
|
68
|
+
*.pot
|
|
69
|
+
|
|
70
|
+
# Django stuff:
|
|
71
|
+
*.log
|
|
72
|
+
local_settings.py
|
|
73
|
+
db.sqlite3
|
|
74
|
+
db.sqlite3-journal
|
|
75
|
+
|
|
76
|
+
# Flask stuff:
|
|
77
|
+
instance/
|
|
78
|
+
.webassets-cache
|
|
79
|
+
|
|
80
|
+
# Scrapy stuff:
|
|
81
|
+
.scrapy
|
|
82
|
+
|
|
83
|
+
# Sphinx documentation
|
|
84
|
+
docs/_build/
|
|
85
|
+
|
|
86
|
+
# PyBuilder
|
|
87
|
+
.pybuilder/
|
|
88
|
+
target/
|
|
89
|
+
|
|
90
|
+
# Jupyter Notebook
|
|
91
|
+
.ipynb_checkpoints
|
|
92
|
+
|
|
93
|
+
# IPython
|
|
94
|
+
profile_default/
|
|
95
|
+
ipython_config.py
|
|
96
|
+
|
|
97
|
+
# pyenv
|
|
98
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
99
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
100
|
+
# .python-version
|
|
101
|
+
|
|
102
|
+
# pipenv
|
|
103
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
104
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
105
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
106
|
+
# install all needed dependencies.
|
|
107
|
+
# Pipfile.lock
|
|
108
|
+
|
|
109
|
+
# UV
|
|
110
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
111
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
112
|
+
# commonly ignored for libraries.
|
|
113
|
+
uv.lock
|
|
114
|
+
|
|
115
|
+
# poetry
|
|
116
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
117
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
118
|
+
# commonly ignored for libraries.
|
|
119
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
120
|
+
# poetry.lock
|
|
121
|
+
# poetry.toml
|
|
122
|
+
|
|
123
|
+
# pdm
|
|
124
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
125
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
126
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
127
|
+
# pdm.lock
|
|
128
|
+
# pdm.toml
|
|
129
|
+
.pdm-python
|
|
130
|
+
.pdm-build/
|
|
131
|
+
|
|
132
|
+
# pixi
|
|
133
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
134
|
+
# pixi.lock
|
|
135
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
136
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
137
|
+
.pixi
|
|
138
|
+
|
|
139
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
140
|
+
__pypackages__/
|
|
141
|
+
|
|
142
|
+
# Celery stuff
|
|
143
|
+
celerybeat-schedule
|
|
144
|
+
celerybeat.pid
|
|
145
|
+
|
|
146
|
+
# Redis
|
|
147
|
+
*.rdb
|
|
148
|
+
*.aof
|
|
149
|
+
*.pid
|
|
150
|
+
|
|
151
|
+
# RabbitMQ
|
|
152
|
+
mnesia/
|
|
153
|
+
rabbitmq/
|
|
154
|
+
rabbitmq-data/
|
|
155
|
+
|
|
156
|
+
# ActiveMQ
|
|
157
|
+
activemq-data/
|
|
158
|
+
|
|
159
|
+
# SageMath parsed files
|
|
160
|
+
*.sage.py
|
|
161
|
+
|
|
162
|
+
# Environments
|
|
163
|
+
.env
|
|
164
|
+
.envrc
|
|
165
|
+
.venv
|
|
166
|
+
env/
|
|
167
|
+
venv/
|
|
168
|
+
ENV/
|
|
169
|
+
env.bak/
|
|
170
|
+
venv.bak/
|
|
171
|
+
|
|
172
|
+
# Spyder project settings
|
|
173
|
+
.spyderproject
|
|
174
|
+
.spyproject
|
|
175
|
+
|
|
176
|
+
# Rope project settings
|
|
177
|
+
.ropeproject
|
|
178
|
+
|
|
179
|
+
# mkdocs documentation
|
|
180
|
+
/site
|
|
181
|
+
|
|
182
|
+
# mypy
|
|
183
|
+
.mypy_cache/
|
|
184
|
+
.dmypy.json
|
|
185
|
+
dmypy.json
|
|
186
|
+
|
|
187
|
+
# Pyre type checker
|
|
188
|
+
.pyre/
|
|
189
|
+
|
|
190
|
+
# pytype static type analyzer
|
|
191
|
+
.pytype/
|
|
192
|
+
|
|
193
|
+
# Cython debug symbols
|
|
194
|
+
cython_debug/
|
|
195
|
+
|
|
196
|
+
# PyCharm
|
|
197
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
198
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
199
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
200
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
201
|
+
# .idea/
|
|
202
|
+
|
|
203
|
+
# Abstra
|
|
204
|
+
# Abstra is an AI-powered process automation framework.
|
|
205
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
206
|
+
# Learn more at https://abstra.io/docs
|
|
207
|
+
.abstra/
|
|
208
|
+
|
|
209
|
+
# Visual Studio Code
|
|
210
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
211
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
212
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
213
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
214
|
+
# .vscode/
|
|
215
|
+
|
|
216
|
+
# Ruff stuff:
|
|
217
|
+
.ruff_cache/
|
|
218
|
+
|
|
219
|
+
# PyPI configuration file
|
|
220
|
+
.pypirc
|
|
221
|
+
|
|
222
|
+
# Marimo
|
|
223
|
+
marimo/_static/
|
|
224
|
+
marimo/_lsp/
|
|
225
|
+
__marimo__/
|
|
226
|
+
|
|
227
|
+
# Streamlit
|
|
228
|
+
.streamlit/secrets.toml
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: patch-torchcodec
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Patch TorchCodec to use PyAV's bundled FFmpeg — one command, no system FFmpeg needed
|
|
5
|
+
Project-URL: Homepage, https://github.com/open-world-agents/MediaRef
|
|
6
|
+
Project-URL: Repository, https://github.com/open-world-agents/MediaRef
|
|
7
|
+
Author: MediaRef Contributors
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: decoder,ffmpeg,patchelf,pyav,torchcodec,video
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Multimedia :: Video
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Requires-Dist: av>=10.0.0
|
|
22
|
+
Requires-Dist: patchelf
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# patch-torchcodec
|
|
26
|
+
|
|
27
|
+
Patch TorchCodec to use PyAV's bundled FFmpeg — **one command, no system FFmpeg needed**.
|
|
28
|
+
|
|
29
|
+
## Problem
|
|
30
|
+
|
|
31
|
+
TorchCodec requires FFmpeg shared libraries (`libavcodec.so.62`, etc.), but installing FFmpeg system-wide can be complex and may cause version conflicts.
|
|
32
|
+
|
|
33
|
+
## Solution
|
|
34
|
+
|
|
35
|
+
PyAV already bundles FFmpeg. `patch-torchcodec` patches TorchCodec's RPATH to find them — no environment variables needed!
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install torchcodec patch-torchcodec # torchcodec + patcher (av & patchelf included)
|
|
41
|
+
patch-torchcodec # patches RPATH — done!
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
That's it. TorchCodec now works:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from torchcodec.decoders import VideoDecoder # ✓ just works
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Command Line Options
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
patch-torchcodec # Patch RPATH (default, recommended)
|
|
54
|
+
patch-torchcodec --env-only # Symlinks only (requires LD_LIBRARY_PATH)
|
|
55
|
+
patch-torchcodec --status # Check current setup status
|
|
56
|
+
patch-torchcodec --verify # Verify TorchCodec works
|
|
57
|
+
patch-torchcodec --quiet # Silent mode
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Python API
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from patch_torchcodec import setup_with_patchelf, verify_torchcodec, is_rpath_patched
|
|
64
|
+
|
|
65
|
+
# Patch RPATH (recommended) — persists across sessions
|
|
66
|
+
setup_with_patchelf(verbose=True)
|
|
67
|
+
|
|
68
|
+
# Verify
|
|
69
|
+
assert verify_torchcodec(require_env=False)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## How It Works
|
|
73
|
+
|
|
74
|
+
1. **Finds PyAV's bundled FFmpeg** in `site-packages/av.libs/`
|
|
75
|
+
2. **Creates symbolic links** with standard names (e.g., `libavcodec.so.62`)
|
|
76
|
+
3. **Patches TorchCodec's `.so` files** with `patchelf` to include PyAV's library path in RPATH
|
|
77
|
+
|
|
78
|
+
## Limitations
|
|
79
|
+
|
|
80
|
+
- **Linux only** (RPATH is Linux-specific)
|
|
81
|
+
- **Same virtualenv**: PyAV and TorchCodec must be in the same environment
|
|
82
|
+
- **Re-run after reinstall**: If you reinstall TorchCodec, run `patch-torchcodec` again
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT
|
|
87
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# patch-torchcodec
|
|
2
|
+
|
|
3
|
+
Patch TorchCodec to use PyAV's bundled FFmpeg — **one command, no system FFmpeg needed**.
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
TorchCodec requires FFmpeg shared libraries (`libavcodec.so.62`, etc.), but installing FFmpeg system-wide can be complex and may cause version conflicts.
|
|
8
|
+
|
|
9
|
+
## Solution
|
|
10
|
+
|
|
11
|
+
PyAV already bundles FFmpeg. `patch-torchcodec` patches TorchCodec's RPATH to find them — no environment variables needed!
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install torchcodec patch-torchcodec # torchcodec + patcher (av & patchelf included)
|
|
17
|
+
patch-torchcodec # patches RPATH — done!
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
That's it. TorchCodec now works:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from torchcodec.decoders import VideoDecoder # ✓ just works
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Command Line Options
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
patch-torchcodec # Patch RPATH (default, recommended)
|
|
30
|
+
patch-torchcodec --env-only # Symlinks only (requires LD_LIBRARY_PATH)
|
|
31
|
+
patch-torchcodec --status # Check current setup status
|
|
32
|
+
patch-torchcodec --verify # Verify TorchCodec works
|
|
33
|
+
patch-torchcodec --quiet # Silent mode
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Python API
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from patch_torchcodec import setup_with_patchelf, verify_torchcodec, is_rpath_patched
|
|
40
|
+
|
|
41
|
+
# Patch RPATH (recommended) — persists across sessions
|
|
42
|
+
setup_with_patchelf(verbose=True)
|
|
43
|
+
|
|
44
|
+
# Verify
|
|
45
|
+
assert verify_torchcodec(require_env=False)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## How It Works
|
|
49
|
+
|
|
50
|
+
1. **Finds PyAV's bundled FFmpeg** in `site-packages/av.libs/`
|
|
51
|
+
2. **Creates symbolic links** with standard names (e.g., `libavcodec.so.62`)
|
|
52
|
+
3. **Patches TorchCodec's `.so` files** with `patchelf` to include PyAV's library path in RPATH
|
|
53
|
+
|
|
54
|
+
## Limitations
|
|
55
|
+
|
|
56
|
+
- **Linux only** (RPATH is Linux-specific)
|
|
57
|
+
- **Same virtualenv**: PyAV and TorchCodec must be in the same environment
|
|
58
|
+
- **Re-run after reinstall**: If you reinstall TorchCodec, run `patch-torchcodec` again
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
MIT
|
|
63
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Patch TorchCodec to use PyAV's bundled FFmpeg — no system FFmpeg needed.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
pip install patch-torchcodec # installs av + patchelf
|
|
5
|
+
patch-torchcodec # patches RPATH — done!
|
|
6
|
+
|
|
7
|
+
Python API:
|
|
8
|
+
from patch_torchcodec import setup_with_patchelf
|
|
9
|
+
setup_with_patchelf() # One-time setup, persists across sessions
|
|
10
|
+
|
|
11
|
+
Alternative (no binary patching):
|
|
12
|
+
patch-torchcodec --env-only
|
|
13
|
+
export LD_LIBRARY_PATH="<shown path>:$LD_LIBRARY_PATH"
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
__version__ = "0.2.0"
|
|
19
|
+
|
|
20
|
+
from .core import (
|
|
21
|
+
create_all_symlinks,
|
|
22
|
+
create_symlinks,
|
|
23
|
+
find_av_libs_dir,
|
|
24
|
+
find_patchelf,
|
|
25
|
+
find_torchcodec_libs,
|
|
26
|
+
get_ld_library_path,
|
|
27
|
+
get_library_mappings,
|
|
28
|
+
is_rpath_patched,
|
|
29
|
+
patch_rpath,
|
|
30
|
+
setup,
|
|
31
|
+
setup_with_patchelf,
|
|
32
|
+
verify_torchcodec,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"create_all_symlinks",
|
|
37
|
+
"create_symlinks",
|
|
38
|
+
"find_av_libs_dir",
|
|
39
|
+
"find_patchelf",
|
|
40
|
+
"find_torchcodec_libs",
|
|
41
|
+
"get_ld_library_path",
|
|
42
|
+
"get_library_mappings",
|
|
43
|
+
"is_rpath_patched",
|
|
44
|
+
"patch_rpath",
|
|
45
|
+
"setup",
|
|
46
|
+
"setup_with_patchelf",
|
|
47
|
+
"verify_torchcodec",
|
|
48
|
+
]
|
|
49
|
+
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Command-line interface for patch-torchcodec."""
|
|
3
|
+
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from .core import (
|
|
11
|
+
create_all_symlinks,
|
|
12
|
+
create_symlinks,
|
|
13
|
+
find_av_libs_dir,
|
|
14
|
+
find_patchelf,
|
|
15
|
+
find_torchcodec_libs,
|
|
16
|
+
get_library_mappings,
|
|
17
|
+
is_rpath_patched,
|
|
18
|
+
setup_with_patchelf,
|
|
19
|
+
verify_torchcodec,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main():
|
|
24
|
+
parser = argparse.ArgumentParser(
|
|
25
|
+
prog="patch-torchcodec",
|
|
26
|
+
description="Patch TorchCodec to use PyAV's bundled FFmpeg libraries via RPATH.",
|
|
27
|
+
epilog="""
|
|
28
|
+
Examples:
|
|
29
|
+
patch-torchcodec # Patch RPATH (recommended, one-time)
|
|
30
|
+
patch-torchcodec --env-only # Symlinks only (requires LD_LIBRARY_PATH)
|
|
31
|
+
patch-torchcodec --verify # Verify TorchCodec works
|
|
32
|
+
patch-torchcodec --status # Check current setup status
|
|
33
|
+
""",
|
|
34
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"--env-only",
|
|
38
|
+
action="store_true",
|
|
39
|
+
help="Only create symlinks, don't patch RPATH (requires LD_LIBRARY_PATH)",
|
|
40
|
+
)
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--print-env",
|
|
43
|
+
action="store_true",
|
|
44
|
+
help="Print shell command to set LD_LIBRARY_PATH",
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"--create-activate",
|
|
48
|
+
action="store_true",
|
|
49
|
+
help="Create an activation script (activate_torchcodec.sh)",
|
|
50
|
+
)
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"--verify", "--verify-only",
|
|
53
|
+
action="store_true",
|
|
54
|
+
dest="verify_only",
|
|
55
|
+
help="Only verify TorchCodec works, don't make changes",
|
|
56
|
+
)
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"--status",
|
|
59
|
+
action="store_true",
|
|
60
|
+
help="Show current setup status",
|
|
61
|
+
)
|
|
62
|
+
parser.add_argument(
|
|
63
|
+
"--quiet", "-q",
|
|
64
|
+
action="store_true",
|
|
65
|
+
help="Suppress verbose output",
|
|
66
|
+
)
|
|
67
|
+
args = parser.parse_args()
|
|
68
|
+
verbose = not args.quiet
|
|
69
|
+
|
|
70
|
+
# Find PyAV libraries
|
|
71
|
+
libs_dir = find_av_libs_dir()
|
|
72
|
+
if libs_dir is None:
|
|
73
|
+
print("Error: Could not find PyAV's av.libs directory.", file=sys.stderr)
|
|
74
|
+
print("Make sure PyAV is installed: pip install av", file=sys.stderr)
|
|
75
|
+
sys.exit(1)
|
|
76
|
+
|
|
77
|
+
# Status mode
|
|
78
|
+
if args.status:
|
|
79
|
+
print("patch-torchcodec: Status")
|
|
80
|
+
print("=" * 40)
|
|
81
|
+
print(f"PyAV av.libs: {libs_dir}")
|
|
82
|
+
|
|
83
|
+
torchcodec_libs = find_torchcodec_libs()
|
|
84
|
+
if torchcodec_libs:
|
|
85
|
+
print(f"TorchCodec libraries: {len(torchcodec_libs)} found")
|
|
86
|
+
else:
|
|
87
|
+
print("TorchCodec: NOT INSTALLED")
|
|
88
|
+
|
|
89
|
+
patchelf = find_patchelf()
|
|
90
|
+
print(f"patchelf: {'found at ' + str(patchelf) if patchelf else 'NOT FOUND'}")
|
|
91
|
+
|
|
92
|
+
rpath_patched = is_rpath_patched()
|
|
93
|
+
print(f"RPATH patched: {'YES' if rpath_patched else 'NO'}")
|
|
94
|
+
|
|
95
|
+
print()
|
|
96
|
+
if verify_torchcodec(libs_dir, require_env=False):
|
|
97
|
+
print("✓ TorchCodec works WITHOUT LD_LIBRARY_PATH")
|
|
98
|
+
elif verify_torchcodec(libs_dir, require_env=True):
|
|
99
|
+
print("⚠ TorchCodec works only WITH LD_LIBRARY_PATH")
|
|
100
|
+
else:
|
|
101
|
+
print("✗ TorchCodec is NOT working")
|
|
102
|
+
sys.exit(0)
|
|
103
|
+
|
|
104
|
+
# Verify only mode
|
|
105
|
+
if args.verify_only:
|
|
106
|
+
if verbose:
|
|
107
|
+
print("Verifying TorchCodec...")
|
|
108
|
+
|
|
109
|
+
# Try without LD_LIBRARY_PATH first
|
|
110
|
+
if verify_torchcodec(libs_dir, require_env=False):
|
|
111
|
+
if verbose:
|
|
112
|
+
print("✓ TorchCodec works without LD_LIBRARY_PATH (RPATH patched)")
|
|
113
|
+
sys.exit(0)
|
|
114
|
+
elif verify_torchcodec(libs_dir, require_env=True):
|
|
115
|
+
if verbose:
|
|
116
|
+
print("✓ TorchCodec works with LD_LIBRARY_PATH")
|
|
117
|
+
print(f" Run: export LD_LIBRARY_PATH=\"{libs_dir}:$LD_LIBRARY_PATH\"")
|
|
118
|
+
sys.exit(0)
|
|
119
|
+
else:
|
|
120
|
+
if verbose:
|
|
121
|
+
print("✗ TorchCodec verification failed.")
|
|
122
|
+
sys.exit(1)
|
|
123
|
+
|
|
124
|
+
if verbose:
|
|
125
|
+
print("patch-torchcodec: Patching")
|
|
126
|
+
print("=" * 40)
|
|
127
|
+
print(f"PyAV av.libs: {libs_dir}")
|
|
128
|
+
|
|
129
|
+
# Decide setup method
|
|
130
|
+
if args.env_only:
|
|
131
|
+
# LD_LIBRARY_PATH only mode
|
|
132
|
+
if verbose:
|
|
133
|
+
print("\nSetup mode: LD_LIBRARY_PATH (symlinks only)")
|
|
134
|
+
print("\nCreating symbolic links...")
|
|
135
|
+
|
|
136
|
+
mappings = get_library_mappings(libs_dir)
|
|
137
|
+
if not mappings:
|
|
138
|
+
print("Error: No FFmpeg libraries found in PyAV bundle.", file=sys.stderr)
|
|
139
|
+
sys.exit(1)
|
|
140
|
+
|
|
141
|
+
created = create_symlinks(libs_dir, mappings)
|
|
142
|
+
# Also create symlinks for all other libraries (libdrm, etc.)
|
|
143
|
+
all_created = create_all_symlinks(libs_dir)
|
|
144
|
+
|
|
145
|
+
if verbose:
|
|
146
|
+
print(f" Created {len(created) + len(all_created)} symbolic links")
|
|
147
|
+
print(f"\n✓ Symlinks created")
|
|
148
|
+
print(f"\nTo use TorchCodec, set LD_LIBRARY_PATH:")
|
|
149
|
+
print(f' export LD_LIBRARY_PATH="{libs_dir}:$LD_LIBRARY_PATH"')
|
|
150
|
+
|
|
151
|
+
if args.print_env:
|
|
152
|
+
print(f'\nexport LD_LIBRARY_PATH="{libs_dir}:$LD_LIBRARY_PATH"')
|
|
153
|
+
else:
|
|
154
|
+
# RPATH patching mode (default)
|
|
155
|
+
if verbose:
|
|
156
|
+
print("\nSetup mode: RPATH patching (recommended)")
|
|
157
|
+
|
|
158
|
+
patchelf = find_patchelf()
|
|
159
|
+
if patchelf is None:
|
|
160
|
+
print("\nError: patchelf not found.", file=sys.stderr)
|
|
161
|
+
print("Install with: pip install patchelf", file=sys.stderr)
|
|
162
|
+
print("\nAlternatively, use --env-only to setup with LD_LIBRARY_PATH.", file=sys.stderr)
|
|
163
|
+
sys.exit(1)
|
|
164
|
+
|
|
165
|
+
torchcodec_libs = find_torchcodec_libs()
|
|
166
|
+
if not torchcodec_libs:
|
|
167
|
+
print("\nError: TorchCodec not found.", file=sys.stderr)
|
|
168
|
+
print("Install with: pip install torchcodec", file=sys.stderr)
|
|
169
|
+
sys.exit(1)
|
|
170
|
+
|
|
171
|
+
if verbose:
|
|
172
|
+
print(f" patchelf: {patchelf}")
|
|
173
|
+
print(f" TorchCodec libraries: {len(torchcodec_libs)}")
|
|
174
|
+
|
|
175
|
+
success = setup_with_patchelf(verbose=verbose)
|
|
176
|
+
|
|
177
|
+
if not success:
|
|
178
|
+
print("\nError: RPATH patching failed.", file=sys.stderr)
|
|
179
|
+
sys.exit(1)
|
|
180
|
+
|
|
181
|
+
if verbose:
|
|
182
|
+
print("\n✓ RPATH patching complete!")
|
|
183
|
+
print(" TorchCodec will now automatically find FFmpeg libraries.")
|
|
184
|
+
print(" No LD_LIBRARY_PATH needed!")
|
|
185
|
+
|
|
186
|
+
# Create activation script if requested
|
|
187
|
+
if args.create_activate:
|
|
188
|
+
script_path = Path("activate_torchcodec.sh")
|
|
189
|
+
script_content = f"""#!/bin/bash
|
|
190
|
+
# Activation script for TorchCodec FFmpeg libraries
|
|
191
|
+
# Source this file: source {script_path}
|
|
192
|
+
|
|
193
|
+
export LD_LIBRARY_PATH="{libs_dir}:$LD_LIBRARY_PATH"
|
|
194
|
+
echo "TorchCodec FFmpeg libraries activated"
|
|
195
|
+
"""
|
|
196
|
+
script_path.write_text(script_content)
|
|
197
|
+
script_path.chmod(0o755)
|
|
198
|
+
if verbose:
|
|
199
|
+
print(f"\n✓ Created activation script: {script_path}")
|
|
200
|
+
print(f" Usage: source {script_path}")
|
|
201
|
+
|
|
202
|
+
# Verify
|
|
203
|
+
if verbose:
|
|
204
|
+
print("\nVerifying TorchCodec...")
|
|
205
|
+
|
|
206
|
+
require_env = args.env_only
|
|
207
|
+
if verify_torchcodec(libs_dir, require_env=require_env):
|
|
208
|
+
if verbose:
|
|
209
|
+
if require_env:
|
|
210
|
+
print("✓ TorchCodec works (with LD_LIBRARY_PATH)")
|
|
211
|
+
else:
|
|
212
|
+
print("✓ TorchCodec works (without LD_LIBRARY_PATH)")
|
|
213
|
+
else:
|
|
214
|
+
if verbose:
|
|
215
|
+
print("⚠ TorchCodec verification failed.")
|
|
216
|
+
if require_env:
|
|
217
|
+
print(" Make sure to set LD_LIBRARY_PATH before running your code.")
|
|
218
|
+
sys.exit(1)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
if __name__ == "__main__":
|
|
222
|
+
main()
|
|
223
|
+
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
"""Core functionality for setting up FFmpeg libraries for TorchCodec."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def find_av_libs_dir() -> Path | None:
|
|
14
|
+
"""Find PyAV's bundled FFmpeg libraries directory.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Path to av.libs directory, or None if not found.
|
|
18
|
+
"""
|
|
19
|
+
try:
|
|
20
|
+
import av
|
|
21
|
+
av_path = Path(av.__file__).parent
|
|
22
|
+
libs_dir = av_path.parent / "av.libs"
|
|
23
|
+
if libs_dir.exists():
|
|
24
|
+
return libs_dir
|
|
25
|
+
except ImportError:
|
|
26
|
+
pass
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_library_mappings(libs_dir: Path) -> dict[str, Path]:
|
|
31
|
+
"""Get mapping from standard library names to actual PyAV library files.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
libs_dir: Path to PyAV's av.libs directory.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Dict mapping standard names (e.g., 'libavcodec.so.62') to actual file paths.
|
|
38
|
+
"""
|
|
39
|
+
required_libs = [
|
|
40
|
+
"libavcodec",
|
|
41
|
+
"libavformat",
|
|
42
|
+
"libavutil",
|
|
43
|
+
"libswscale",
|
|
44
|
+
"libswresample",
|
|
45
|
+
"libavdevice",
|
|
46
|
+
"libavfilter",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
mappings = {}
|
|
50
|
+
|
|
51
|
+
for lib_name in required_libs:
|
|
52
|
+
# Find the actual library file (e.g., libavcodec-e57b519c.so.62.11.100)
|
|
53
|
+
pattern = re.compile(rf"^{lib_name}-[a-f0-9]+\.so\.(\d+)\.\d+\.\d+$")
|
|
54
|
+
|
|
55
|
+
for file in libs_dir.iterdir():
|
|
56
|
+
match = pattern.match(file.name)
|
|
57
|
+
if match:
|
|
58
|
+
major_version = match.group(1)
|
|
59
|
+
standard_name = f"{lib_name}.so.{major_version}"
|
|
60
|
+
mappings[standard_name] = file
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
return mappings
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def create_symlinks(libs_dir: Path, mappings: dict[str, Path] | None = None) -> list[Path]:
|
|
67
|
+
"""Create symbolic links for FFmpeg libraries.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
libs_dir: Path to PyAV's av.libs directory.
|
|
71
|
+
mappings: Optional pre-computed library mappings.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
List of created symlink paths.
|
|
75
|
+
"""
|
|
76
|
+
if mappings is None:
|
|
77
|
+
mappings = get_library_mappings(libs_dir)
|
|
78
|
+
|
|
79
|
+
created = []
|
|
80
|
+
|
|
81
|
+
for standard_name, actual_file in mappings.items():
|
|
82
|
+
symlink_path = libs_dir / standard_name
|
|
83
|
+
|
|
84
|
+
# Remove existing symlink if present
|
|
85
|
+
if symlink_path.is_symlink():
|
|
86
|
+
symlink_path.unlink()
|
|
87
|
+
elif symlink_path.exists():
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
# Create relative symlink
|
|
91
|
+
symlink_path.symlink_to(actual_file.name)
|
|
92
|
+
created.append(symlink_path)
|
|
93
|
+
|
|
94
|
+
return created
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_ld_library_path() -> str | None:
|
|
98
|
+
"""Get the LD_LIBRARY_PATH value needed for TorchCodec.
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Path string to add to LD_LIBRARY_PATH, or None if PyAV not found.
|
|
102
|
+
"""
|
|
103
|
+
libs_dir = find_av_libs_dir()
|
|
104
|
+
if libs_dir is None:
|
|
105
|
+
return None
|
|
106
|
+
return str(libs_dir)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def setup(verbose: bool = False) -> bool:
|
|
110
|
+
"""Setup FFmpeg libraries for TorchCodec.
|
|
111
|
+
|
|
112
|
+
Creates symbolic links from PyAV's bundled FFmpeg libraries to standard
|
|
113
|
+
library names that TorchCodec expects.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
verbose: If True, print progress messages.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
True if setup was successful, False otherwise.
|
|
120
|
+
"""
|
|
121
|
+
libs_dir = find_av_libs_dir()
|
|
122
|
+
if libs_dir is None:
|
|
123
|
+
if verbose:
|
|
124
|
+
print("Error: PyAV not found. Install with: pip install av", file=sys.stderr)
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
mappings = get_library_mappings(libs_dir)
|
|
128
|
+
if not mappings:
|
|
129
|
+
if verbose:
|
|
130
|
+
print("Error: No FFmpeg libraries found in PyAV bundle.", file=sys.stderr)
|
|
131
|
+
return False
|
|
132
|
+
|
|
133
|
+
created = create_symlinks(libs_dir, mappings)
|
|
134
|
+
|
|
135
|
+
if verbose:
|
|
136
|
+
print(f"Created {len(created)} symbolic links in {libs_dir}")
|
|
137
|
+
print(f"\nTo use TorchCodec, set LD_LIBRARY_PATH:")
|
|
138
|
+
print(f' export LD_LIBRARY_PATH="{libs_dir}:$LD_LIBRARY_PATH"')
|
|
139
|
+
|
|
140
|
+
return True
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def find_torchcodec_libs() -> list[Path]:
|
|
144
|
+
"""Find TorchCodec shared libraries.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
List of paths to TorchCodec .so files.
|
|
148
|
+
"""
|
|
149
|
+
try:
|
|
150
|
+
import torchcodec
|
|
151
|
+
torchcodec_dir = Path(torchcodec.__file__).parent
|
|
152
|
+
return list(torchcodec_dir.glob("libtorchcodec_*.so"))
|
|
153
|
+
except ImportError:
|
|
154
|
+
return []
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def find_patchelf() -> Path | None:
|
|
158
|
+
"""Find patchelf executable.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Path to patchelf executable, or None if not found.
|
|
162
|
+
"""
|
|
163
|
+
# Check in current Python environment first
|
|
164
|
+
try:
|
|
165
|
+
import site
|
|
166
|
+
for sp in site.getsitepackages():
|
|
167
|
+
patchelf = Path(sp).parent.parent / "bin" / "patchelf"
|
|
168
|
+
if patchelf.exists():
|
|
169
|
+
return patchelf
|
|
170
|
+
except Exception:
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
# Check system PATH
|
|
174
|
+
patchelf = shutil.which("patchelf")
|
|
175
|
+
if patchelf:
|
|
176
|
+
return Path(patchelf)
|
|
177
|
+
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def patch_rpath(library_path: Path, rpath: str, patchelf: Path | None = None) -> bool:
|
|
182
|
+
"""Set RPATH on a shared library using patchelf.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
library_path: Path to the .so file to patch.
|
|
186
|
+
rpath: RPATH value to set.
|
|
187
|
+
patchelf: Path to patchelf executable. Auto-detected if None.
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
True if successful, False otherwise.
|
|
191
|
+
"""
|
|
192
|
+
if patchelf is None:
|
|
193
|
+
patchelf = find_patchelf()
|
|
194
|
+
if patchelf is None:
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
subprocess.run(
|
|
199
|
+
[str(patchelf), "--force-rpath", "--set-rpath", rpath, str(library_path)],
|
|
200
|
+
check=True,
|
|
201
|
+
capture_output=True,
|
|
202
|
+
)
|
|
203
|
+
return True
|
|
204
|
+
except (subprocess.CalledProcessError, Exception):
|
|
205
|
+
return False
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def setup_with_patchelf(verbose: bool = False) -> bool:
|
|
209
|
+
"""Setup TorchCodec to use PyAV's FFmpeg libraries via RPATH patching.
|
|
210
|
+
|
|
211
|
+
This method patches TorchCodec's shared libraries to include PyAV's av.libs
|
|
212
|
+
directory in their RPATH, eliminating the need for LD_LIBRARY_PATH.
|
|
213
|
+
|
|
214
|
+
Requires: patchelf (install with: pip install patchelf)
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
verbose: If True, print progress messages.
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
True if setup was successful, False otherwise.
|
|
221
|
+
"""
|
|
222
|
+
# Find dependencies
|
|
223
|
+
libs_dir = find_av_libs_dir()
|
|
224
|
+
if libs_dir is None:
|
|
225
|
+
if verbose:
|
|
226
|
+
print("Error: PyAV not found. Install with: pip install av", file=sys.stderr)
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
torchcodec_libs = find_torchcodec_libs()
|
|
230
|
+
if not torchcodec_libs:
|
|
231
|
+
if verbose:
|
|
232
|
+
print("Error: TorchCodec not found. Install with: pip install torchcodec", file=sys.stderr)
|
|
233
|
+
return False
|
|
234
|
+
|
|
235
|
+
patchelf = find_patchelf()
|
|
236
|
+
if patchelf is None:
|
|
237
|
+
if verbose:
|
|
238
|
+
print("Error: patchelf not found. Install with: pip install patchelf", file=sys.stderr)
|
|
239
|
+
return False
|
|
240
|
+
|
|
241
|
+
# Create symlinks for all libraries in av.libs
|
|
242
|
+
if verbose:
|
|
243
|
+
print(f"Creating symbolic links in {libs_dir}...")
|
|
244
|
+
|
|
245
|
+
created_symlinks = create_all_symlinks(libs_dir)
|
|
246
|
+
if verbose:
|
|
247
|
+
print(f" Created {len(created_symlinks)} symbolic links")
|
|
248
|
+
|
|
249
|
+
# Patch TorchCodec libraries
|
|
250
|
+
if verbose:
|
|
251
|
+
print(f"\nPatching TorchCodec libraries with RPATH: {libs_dir}")
|
|
252
|
+
|
|
253
|
+
rpath = str(libs_dir.resolve())
|
|
254
|
+
patched = 0
|
|
255
|
+
for lib in torchcodec_libs:
|
|
256
|
+
if patch_rpath(lib, rpath, patchelf):
|
|
257
|
+
patched += 1
|
|
258
|
+
if verbose:
|
|
259
|
+
print(f" Patched: {lib.name}")
|
|
260
|
+
elif verbose:
|
|
261
|
+
print(f" Failed: {lib.name}", file=sys.stderr)
|
|
262
|
+
|
|
263
|
+
if verbose:
|
|
264
|
+
print(f"\nPatched {patched}/{len(torchcodec_libs)} libraries")
|
|
265
|
+
|
|
266
|
+
return patched == len(torchcodec_libs)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def create_all_symlinks(libs_dir: Path) -> list[Path]:
|
|
270
|
+
"""Create symbolic links for ALL libraries in av.libs.
|
|
271
|
+
|
|
272
|
+
This creates symlinks from hash-included names to standard names,
|
|
273
|
+
e.g., libdrm-b0291a67.so.2.4.0 -> libdrm.so.2
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
libs_dir: Path to PyAV's av.libs directory.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
List of created symlink paths.
|
|
280
|
+
"""
|
|
281
|
+
created = []
|
|
282
|
+
|
|
283
|
+
# Pattern: libname-hash.so.major.minor.patch
|
|
284
|
+
pattern = re.compile(r"^(.+)-[a-f0-9]+\.so\.(\d+)(?:\.\d+)*$")
|
|
285
|
+
|
|
286
|
+
for file in libs_dir.iterdir():
|
|
287
|
+
if file.is_symlink():
|
|
288
|
+
continue
|
|
289
|
+
|
|
290
|
+
match = pattern.match(file.name)
|
|
291
|
+
if match:
|
|
292
|
+
lib_name = match.group(1)
|
|
293
|
+
major_version = match.group(2)
|
|
294
|
+
standard_name = f"{lib_name}.so.{major_version}"
|
|
295
|
+
symlink_path = libs_dir / standard_name
|
|
296
|
+
|
|
297
|
+
if not symlink_path.exists():
|
|
298
|
+
symlink_path.symlink_to(file.name)
|
|
299
|
+
created.append(symlink_path)
|
|
300
|
+
|
|
301
|
+
return created
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def verify_torchcodec(libs_dir: Path | None = None, require_env: bool = True) -> bool:
|
|
305
|
+
"""Verify TorchCodec can load with the configured libraries.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
libs_dir: Path to av.libs directory. If None, will be auto-detected.
|
|
309
|
+
require_env: If True, set LD_LIBRARY_PATH for verification.
|
|
310
|
+
If False, test without setting LD_LIBRARY_PATH (for RPATH-patched installs).
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
True if TorchCodec loads successfully, False otherwise.
|
|
314
|
+
"""
|
|
315
|
+
if libs_dir is None:
|
|
316
|
+
libs_dir = find_av_libs_dir()
|
|
317
|
+
|
|
318
|
+
env = os.environ.copy()
|
|
319
|
+
if require_env and libs_dir is not None:
|
|
320
|
+
env["LD_LIBRARY_PATH"] = f"{libs_dir}:{env.get('LD_LIBRARY_PATH', '')}"
|
|
321
|
+
|
|
322
|
+
try:
|
|
323
|
+
result = subprocess.run(
|
|
324
|
+
[sys.executable, "-c", "from torchcodec.decoders import VideoDecoder; print('OK')"],
|
|
325
|
+
env=env,
|
|
326
|
+
capture_output=True,
|
|
327
|
+
text=True,
|
|
328
|
+
)
|
|
329
|
+
return result.returncode == 0 and "OK" in result.stdout
|
|
330
|
+
except Exception:
|
|
331
|
+
return False
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def is_rpath_patched() -> bool:
|
|
335
|
+
"""Check if TorchCodec libraries have been RPATH-patched.
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
True if RPATH is set to av.libs directory.
|
|
339
|
+
"""
|
|
340
|
+
libs_dir = find_av_libs_dir()
|
|
341
|
+
if libs_dir is None:
|
|
342
|
+
return False
|
|
343
|
+
|
|
344
|
+
torchcodec_libs = find_torchcodec_libs()
|
|
345
|
+
if not torchcodec_libs:
|
|
346
|
+
return False
|
|
347
|
+
|
|
348
|
+
# Check RPATH of one library
|
|
349
|
+
try:
|
|
350
|
+
result = subprocess.run(
|
|
351
|
+
["readelf", "-d", str(torchcodec_libs[0])],
|
|
352
|
+
capture_output=True,
|
|
353
|
+
text=True,
|
|
354
|
+
)
|
|
355
|
+
if result.returncode == 0:
|
|
356
|
+
return str(libs_dir) in result.stdout
|
|
357
|
+
except Exception:
|
|
358
|
+
pass
|
|
359
|
+
|
|
360
|
+
return False
|
|
361
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "patch-torchcodec"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Patch TorchCodec to use PyAV's bundled FFmpeg — one command, no system FFmpeg needed"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "MediaRef Contributors" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["torchcodec", "ffmpeg", "pyav", "video", "decoder", "patchelf"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: POSIX :: Linux",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Multimedia :: Video",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"av>=10.0.0",
|
|
30
|
+
"patchelf",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
patch-torchcodec = "patch_torchcodec.__main__:main"
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/open-world-agents/MediaRef"
|
|
38
|
+
Repository = "https://github.com/open-world-agents/MediaRef"
|
|
39
|
+
|
|
40
|
+
[tool.hatch.build.targets.wheel]
|
|
41
|
+
packages = ["patch_torchcodec"]
|
|
42
|
+
|