diff --git a/.github/workflows/linux_cuda_wheel.yaml b/.github/workflows/linux_cuda_wheel.yaml index 4e711b8c3..eb2d9bc3b 100644 --- a/.github/workflows/linux_cuda_wheel.yaml +++ b/.github/workflows/linux_cuda_wheel.yaml @@ -94,7 +94,7 @@ jobs: python-version: ${{ matrix.python-version }} # We install conda packages at the start because otherwise conda may have conflicts with dependencies. # Note: xorg-libxau was addded to fix a problem with ffmpeg 4. We should consider removing it. - default-packages: "nvidia/label/cuda-${{ matrix.cuda-version }}.0::libnpp nvidia::cuda-nvrtc=${{ matrix.cuda-version }} nvidia::cuda-toolkit=${{ matrix.cuda-version }} nvidia::cuda-cudart=${{ matrix.cuda-version }} nvidia::cuda-driver-dev=${{ matrix.cuda-version }} conda-forge::ffmpeg=${{ matrix.ffmpeg-version-for-tests }} conda-forge::xorg-libxau" + default-packages: "nvidia/label/cuda-${{ matrix.cuda-version }}.0::libnpp nvidia::cuda-nvrtc=${{ matrix.cuda-version }} nvidia::cuda-toolkit=${{ matrix.cuda-version }} nvidia::cuda-cudart=${{ matrix.cuda-version }} nvidia::cuda-driver-dev=${{ matrix.cuda-version }} conda-forge::ffmpeg=${{ matrix.ffmpeg-version-for-tests }} conda-forge::xorg-libxau conda-forge::pkg-config" - name: Check env, set LD_LIBRARY_PATH run: | ${CONDA_RUN} env @@ -142,6 +142,8 @@ jobs: - name: Run Python tests run: | ${CONDA_RUN} FAIL_WITHOUT_CUDA=1 pytest --override-ini="addopts=-v" test --tb=short + env: + CUDA_HOME: "/usr/local/cuda" - name: Run Python benchmark run: | ${CONDA_RUN} time python benchmarks/decoders/gpu_benchmark.py --devices=cuda:0,cpu --resize_devices=none diff --git a/.github/workflows/linux_wheel.yaml b/.github/workflows/linux_wheel.yaml index cccbedc25..68b5134e1 100644 --- a/.github/workflows/linux_wheel.yaml +++ b/.github/workflows/linux_wheel.yaml @@ -103,7 +103,7 @@ jobs: source packaging/helpers.sh assert_ffmpeg_not_installed - conda install "ffmpeg=${{ matrix.ffmpeg-version-for-tests }}" -c conda-forge + conda install "ffmpeg=${{ matrix.ffmpeg-version-for-tests }}" pkg-config -c conda-forge ffmpeg -version - name: Install test dependencies diff --git a/.github/workflows/macos_wheel.yaml b/.github/workflows/macos_wheel.yaml index ead45784d..002295c06 100644 --- a/.github/workflows/macos_wheel.yaml +++ b/.github/workflows/macos_wheel.yaml @@ -99,7 +99,7 @@ jobs: - name: Install ffmpeg run: | - conda install "ffmpeg=${{ matrix.ffmpeg-version-for-tests }}" -c conda-forge + conda install "ffmpeg=${{ matrix.ffmpeg-version-for-tests }}" pkg-config -c conda-forge ffmpeg -version - name: Install test dependencies diff --git a/.github/workflows/windows_wheel.yaml b/.github/workflows/windows_wheel.yaml index 8a9b5b740..ee56583c6 100644 --- a/.github/workflows/windows_wheel.yaml +++ b/.github/workflows/windows_wheel.yaml @@ -109,7 +109,7 @@ jobs: # side-effect. It's OK. source packaging/helpers.sh assert_ffmpeg_not_installed - conda install "ffmpeg=${{ matrix.ffmpeg-version-for-tests }}" -c conda-forge + conda install "ffmpeg=${{ matrix.ffmpeg-version-for-tests }}" pkg-config -c conda-forge ffmpeg -version - name: Test torchcodec import after FFmpeg installation run: | diff --git a/test/cppapi/CMakeLists.txt b/test/cppapi/CMakeLists.txt new file mode 100644 index 000000000..cc7b5c941 --- /dev/null +++ b/test/cppapi/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.18) +project(CppApiTest) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Torch REQUIRED) +find_package(TorchCodec REQUIRED) + +function(make_torchcodec_targets torchcodec_variant) + set(binname "torchcodec_cppapitest${torchcodec_variant}") + set(sources CppApiTest.cpp) + + # Building executable to check the linkage + add_executable(${binname} ${sources}) + # Avoid adding the "lib" prefix which we already add explicitly. + set_target_properties(${binname} PROPERTIES PREFIX "") + set_target_properties(${binname} PROPERTIES CXX_STANDARD 17) + target_link_libraries(${binname} + ${TORCH_LIBRARIES} + torchcodec::core${torchcodec_variant} + torchcodec::ffmpeg${torchcodec_variant} + ) +endfunction() + +foreach(variant IN LISTS TORCHCODEC_VARIANTS) + make_torchcodec_targets(${variant}) +endforeach() diff --git a/test/cppapi/CppApiTest.cpp b/test/cppapi/CppApiTest.cpp new file mode 100644 index 000000000..00459207d --- /dev/null +++ b/test/cppapi/CppApiTest.cpp @@ -0,0 +1,38 @@ +#include "DeviceInterface.h" +#include "FilterGraph.h" + +namespace facebook::torchcodec { + +class DummyDeviceInterface : public DeviceInterface { + public: + DummyDeviceInterface(const torch::Device& device) : DeviceInterface(device) {} + + virtual ~DummyDeviceInterface() {} + + void initialize( + const AVStream* avStream, + const UniqueDecodingAVFormatContext& avFormatCtx, + const SharedAVCodecContext& codecContext) override {} + + void convertAVFrameToFrameOutput( + UniqueAVFrame& avFrame, + FrameOutput& frameOutput, + std::optional preAllocatedOutputTensor = + std::nullopt) override {} + + private: + std::unique_ptr filterGraphContext_; +}; + +namespace { +static bool g_dummy = registerDeviceInterface( + DeviceInterfaceKey(torch::kPrivateUse1), + [](const torch::Device& device) { + return new DummyDeviceInterface(device); + }); +} // namespace +} // namespace facebook::torchcodec + +int main(int argc, char* argv[]) { + return 0; +} diff --git a/test/test_cppapi.py b/test/test_cppapi.py new file mode 100644 index 000000000..b26799af9 --- /dev/null +++ b/test/test_cppapi.py @@ -0,0 +1,80 @@ +import os +import subprocess + +from pathlib import Path + +import torch +import torchcodec + + +def test_cppapi_pkgconfig(tmp_path): + cmake_args = [ + "cmake", + "-DCMAKE_BUILD_TYPE=Debug", + "-DCMAKE_VERBOSE_MAKEFILE=ON", + f"-DCMAKE_PREFIX_PATH={torchcodec.cmake_prefix_path};{torch.utils.cmake_prefix_path}", + Path(__file__).parent / "cppapi", + ] + result = subprocess.run(cmake_args, cwd=tmp_path) + assert result.returncode == 0 + + result = subprocess.run(["cmake", "--build", "."], cwd=tmp_path) + assert result.returncode == 0 + + ver = f"{torchcodec.ffmpeg_major_version}" + result = subprocess.run([f"./torchcodec_cppapitest{ver}"], cwd=tmp_path) + assert result.returncode == 0 + + +def test_cppapi_no_ffmpeg(tmp_path): + cmake_args = [ + "cmake", + "-DCMAKE_BUILD_TYPE=Debug", + "-DCMAKE_VERBOSE_MAKEFILE=ON", + f"-DCMAKE_PREFIX_PATH={torchcodec.cmake_prefix_path};{torch.utils.cmake_prefix_path}", + Path(__file__).parent / "cppapi", + ] + ver = f"{torchcodec.ffmpeg_major_version}" + my_env = os.environ.copy() + my_env[f"TORCHCODEC_FFMPEG{ver}_INSTALL_PREFIX"] = ( + Path(__file__).parent / "no-such-dir" + ) + + # cmake config should fail as we've set ffmpeg install prefix to the not existing + # directory + result = subprocess.run(cmake_args, cwd=tmp_path, env=my_env) + assert result.returncode != 0 + + +def test_cppapi_with_prefix(tmp_path): + cmake_args = [ + "cmake", + "-DCMAKE_BUILD_TYPE=Debug", + "-DCMAKE_VERBOSE_MAKEFILE=ON", + f"-DCMAKE_PREFIX_PATH={torchcodec.cmake_prefix_path};{torch.utils.cmake_prefix_path}", + Path(__file__).parent / "cppapi", + ] + + # In this test we are calculating the prefix of installed ffmpeg version from the location + # of its libavcodec.pc file. Potentially, on the custom ffmpeg install with custom layout + # our calculation can be wrong and test might fail. + result = subprocess.run( + ["pkg-config", "--path", "libavcodec"], capture_output=True, text=True + ) + assert result.returncode == 0 + + ver = f"{torchcodec.ffmpeg_major_version}" + my_env = os.environ.copy() + my_env[f"TORCHCODEC_FFMPEG{ver}_INSTALL_PREFIX"] = Path( + f"{result.stdout}" + ).parent.parent.parent + + result = subprocess.run(cmake_args, cwd=tmp_path, env=my_env) + assert result.returncode == 0 + + result = subprocess.run(["cmake", "--build", "."], cwd=tmp_path) + assert result.returncode == 0 + + ver = f"{torchcodec.ffmpeg_major_version}" + result = subprocess.run([f"./torchcodec_cppapitest{ver}"], cwd=tmp_path) + assert result.returncode == 0