pytorch / audio

Data manipulation and transformation for audio signal processing, powered by PyTorch
https://pytorch.org/audio
BSD 2-Clause "Simplified" License
2.55k stars 657 forks source link

Torchaudio is not detecting FFmpeg #3789

Open ruliworst opened 6 months ago

ruliworst commented 6 months ago

🐛 Describe the bug

Hi everyone,

I am trying to use torchaudio with FFmpeg but for some reason it is not being detected.

import torchaudio
print(torchaudio.list_audio_backends())

ffmpeg ffmpeg files

I added the path 'C:\Program Files\ffmpeg\bin' to the PATH environment variable. As you can see I can execute ffmpeg from cmd. However, when I execute torchaudio.list_audio_backends() only 'soundfile' is detected. I tested this in a Python PIP (I can't use conda) virtual environment with version 3.10 and in another one with version 3.12 but, it didn't work in both. Torchaudio and torch versions are 2.2.1. I don't know if it is a problem with version compatibility but in the official documentation I saw ffmpeg 6 is supported and I checked the code which tries to load the libraries.

I checked a lot of related issues but I couldn't find the right solution.

Any suggestions are welcome! Thanks.

Versions

Collecting environment information...

PyTorch version: 2.2.1+cpu
Is debug build: False
CUDA used to build PyTorch: Could not collect
ROCM used to build PyTorch: N/A
OS: Microsoft Windows Server 2022 Standard
GCC version: Could not collect
Clang version: Could not collect
CMake version: Could not collect
Libc version: N/A

Python version: 3.10.7 (tags/v3.10.7:6cc6b13, Sep  5 2022, 14:08:36) [MSC v.1933 64 bit (AMD64)] (64-bit runtime)
Python platform: Windows-10-10.0.20348-SP0
Is CUDA available: False
CUDA runtime version: 12.3.103
CUDA_MODULE_LOADING set to: N/A
GPU models and configuration: GPU 0: NVIDIA A100-PCIE-40GB
Nvidia driver version: 546.12
cuDNN version: Could not collect
HIP runtime version: N/A
MIOpen runtime version: N/A
Is XNNPACK available: True

CPU:
'wmic' is not recognized as an internal or external command,
operable program or batch file.

Versions of relevant libraries:

[pip3] numpy==1.26.4
[pip3] pytorch-lightning==2.2.4
[pip3] pytorch-metric-learning==2.5.0
[pip3] torch==2.2.1
[pip3] torch-audiomentations==0.11.1
[pip3] torch-pitch-shift==1.2.4
[pip3] torchaudio==2.2.1
[pip3] torchmetrics==1.4.0
[conda] Could not collect
ruliworst commented 6 months ago

Loading manullay the binaries is working but, I would like it was automatic.

ctypes.CDLL('C:/Program Files/ffmpeg/bin/avcodec-60.dll')
ctypes.CDLL('C:/Program Files/ffmpeg/bin/avdevice-60.dll')
ctypes.CDLL('C:/Program Files/ffmpeg/bin/avfilter-9.dll')
ctypes.CDLL('C:/Program Files/ffmpeg/bin/avformat-60.dll')
ctypes.CDLL('C:/Program Files/ffmpeg/bin/avutil-58.dll')

I still don't know why it is not working without preloading libraries.

ruliworst commented 6 months ago

If I locate the libraries in the same folder of libtorio_ffmpeg6.pyd , they are detected while importing. That is, in Lib/site-packages/torio/lib

EDIT: I have been checking the internal code and in file torchaudio\_extension\__init__.py line 24 there is a code which is not being executed:

if os.name == "nt" and (3, 8) <= sys.version_info < (3, 9):
    _init_dll_path()

This code adds the paths from PATH environment variable to the DLL search path. However, I would like to know why it is only executed in Python 3.8 version.

Thank you.

chislon commented 3 months ago

Ran into this same unexpected behavior as well.

If _init_dll_path() is allowed to run it works as expected

HarikalarKutusu commented 3 months ago

Same problem here, struggling for hours. Win 11, Python 3.12.4, using pip, ffmpeg 6.1.2 with shared libraries, path OK, can run on CMD, restarted multiple times, etc... Using torchaudio==2.4.0+cu124 thou...

ctypes.CDLL workaround also did not work in my case. Only "soundfile" can be used. Adding this to the code did not help either:

os.add_dll_directory("C:\\Programs\\ffmpeg-6.1\\bin\\")

PS: I'm trying to convert my code to use torch/torchaudio. Before torchaudio I've been using PyAV without any problems - using ffmpeg for a decade. torchaudio's ffmpeg documentation is also very cryptic. As far as I can see, torchaudio moved to ffmpeg as the main cross-platform library, but still too many problems.

chislonchow commented 3 months ago

Hi HarikalarKutusu, do you have all the required ffmpeg DLL files?

In my case I need all of these for ffmpeg to be detected, in addition to executing _init_dll_path from the file modified in torchaudio:

avcodec-60.dll avdevice-60.dll avfilter-9.dll avformat-60.dll avutil-58.dll postproc-57.dll swresample-4.dll swscale-7.dll

Using the dlls from this ffmpeg shared build: https://github.com/GyanD/codexffmpeg/releases/tag/6.1.1

HarikalarKutusu commented 3 months ago

I used [ffmpeg-builds/win64-gpl-shared-6.1](https://github.com/users/BtbN/packages/container/package/ffmpeg-builds%2Fwin64-gpl-shared-6.1), the naming of the .dll files are the same (v6.1.2 but IMO should not effect this).

I did not update the _init_dll_path directly in tourchaudio distribution, but used os.add_dll_directory() in my code before calling any torch code. This is what it does if ran:

def _init_dll_path():
    # On Windows Python-3.8+ has `os.add_dll_directory` call,
    # which is called to configure dll search path.
    # To find cuda related dlls we need to make sure the
    # conda environment/bin path is configured Please take a look:
    # https://stackoverflow.com/questions/59330863/cant-import-dll-module-in-python
    # Please note: if some path can't be added using add_dll_directory we simply ignore this path
    for path in os.environ.get("PATH", "").split(";"):
        if os.path.exists(path):
            try:
                os.add_dll_directory(path)
            except Exception:
                pass

Let me try the one from your link... EDIT: No joy

HarikalarKutusu commented 3 months ago

Joy! I was wrong. I imported the function and called it.

from torchaudio._extension.utils import _init_dll_path
...
def my_transcode_function():
    _init_dll_path()
   ...

Also changed the v3.8 limitation code to be safe.

# if os.name == "nt" and (3, 8) <= sys.version_info < (3, 9):
#     _init_dll_path()
if os.name == "nt" and (3, 8) <= sys.version_info < (3, 99):
    _init_dll_path()

It now works. Thank you for the guidance @chislonchow !