Skip to content

Conversation

@dvrogozh
Copy link
Contributor

@dvrogozh dvrogozh commented Oct 7, 2025

This commit exposes torchcodec core library to be used by third party modules on the C++ level. The primary purpose is to allow non-CUDA device interfaces out-of-tree implementations. There are the following major changes:

  • Exposed TorchCodecConfig.cmake which defines torchcodec targets to be linked with

  • Provided Python level APIs to faciliate out-of-tree device interfaces work with torchcodec:

    • torchcodec.cmake_prefix_path - path which points to TorchCodecConfig.cmake configuration
    • torchcodec.variant - variant of the torchcodec library which was loaded, i.e. N in libtorchcodec_core{N}.so (currently ffmpeg_major_version)
    • torchcodec.core_library_path - full path of the loaded torchcodec core library
  • src/torchcodec/_core/ dropped from include paths to allow using of the core library out-of-tree

TorchCodecConfig.cmake has 2 working modes:

  • By default config works by checking available version of FFmpeg libraries via pkg-config and configures corresponding (single) version of torchcodec
  • Altenatively, if TORCHCODEC_FFMPEG{N}_INSTALL_PREFIX is set (N=4,5,6,7 - version of FFmpeg), then config defines torchcodec target corresponding to the specified FFmpeg version. Note that multiple prefixes can be specified at the same time allowing to build against few torchcodec versions at once.

Config will define TORCHCODEC_VARIANTS variable with value corresponding to FFmpeg major versions of available torchcodec core libraries. Further, config will also define torchcodec::ffmpeg${N} and torchcodec::core${N} targets where N takes values from TORCHCODEC_VARIANTS.

See the following repository for an actual out-of-tree device interface torchcodec plugin:

I suggest to pay attention on these:

CC: @scotts, @NicolasHug

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 7, 2025
Copy link
Contributor

@NicolasHug NicolasHug left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dvrogozh , I left some questions and some comments below. It looks good overal, but I hope we can simplify and unify the logic with the one that already exists within our own cmake files.

On the #include path changes, I will have to pre-import your PR internall to verify that this isn't breaking our internal build (and to try to find internal workarounds if needed).

except Exception:
pass

cmake_prefix_path = _osp.join(_osp.dirname(__file__), "share", "cmake")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a comment to explain what this is used for, and also let's use the more modern pathlib tools instead of os.path.

Comment on lines +64 to +65
variant = ffmpeg_major_version
core_library_path = decoder_library_path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's return them instead of having them as global.

Also, ffmpeg_major_version is a good name, so we can keep using it for the variable that we expose as torchcodec.ffmpeg_major_version

_pybind_ops: Optional[ModuleType] = None

variant = None
core_library_path = None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you help me understand why in

https://github.com/dvrogozh/torchcodec-xpu/blob/59bfef60e9b41244e804c112729c42d9176ae368/src/torchcodec_xpu/__init__.py#L43

we only need to load the libtorchcodec_core?.so file, and not the other .so like libtorchcodec_pybind_ops?.so and libtorchcodec_custom_ops?.so

Comment on lines +102 to +137
set(f4_library_file_names
libavutil.so.56
libavcodec.so.58
libavformat.so.58
libavdevice.so.58
libavfilter.so.7
libswscale.so.5
libswresample.so.3
)
set(f5_library_file_names
libavutil.so.57
libavcodec.so.59
libavformat.so.59
libavdevice.so.59
libavfilter.so.8
libswscale.so.6
libswresample.so.4
)
set(f6_library_file_names
libavutil.so.58
libavcodec.so.60
libavformat.so.60
libavdevice.so.60
libavfilter.so.9
libswscale.so.7
libswresample.so.4
)
set(f7_library_file_names
libavutil.so.59
libavcodec.so.61
libavformat.so.61
libavdevice.so.61
libavfilter.so.10
libswscale.so.8
libswresample.so.5
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's try to unify that with those that are already in https://github.com/meta-pytorch/torchcodec/blob/main/src/torchcodec/_core/fetch_and_expose_non_gpl_ffmpeg_libs.cmake. We can create a new ffmpeg_versions.cmake file if that helps refactoring.

set(ffmpeg_major_version "6")
elseif (${libavcodec_major_version} STREQUAL "61")
set(ffmpeg_major_version "7")
endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, the logic in this whole branch should ideally be unified with

else()
message(
STATUS
"Building and dynamically linking libtorchcodec against the installed
FFmpeg libraries. This require pkg-config to be installed. If you have
installed FFmpeg from conda, make sure pkg-config is installed from
conda as well."
)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
libavdevice
libavfilter
libavformat
libavcodec
libavutil
libswresample
libswscale
)
# Split libavcodec's version string by '.' and convert it to a list
string(REPLACE "." ";" libavcodec_version_list ${LIBAV_libavcodec_VERSION})
# Get the first element of the list, which is the major version
list(GET libavcodec_version_list 0 libavcodec_major_version)
if (${libavcodec_major_version} STREQUAL "58")
set(ffmpeg_major_version "4")
elseif (${libavcodec_major_version} STREQUAL "59")
set(ffmpeg_major_version "5")
elseif (${libavcodec_major_version} STREQUAL "60")
set(ffmpeg_major_version "6")
elseif (${libavcodec_major_version} STREQUAL "61")
set(ffmpeg_major_version "7")
elseif (${libavcodec_major_version} STREQUAL "62")
set(ffmpeg_major_version "8")
else()
message(
FATAL_ERROR
"Unsupported libavcodec version: ${libavcodec_major_version}"
)
endif()

Comment on lines +38 to +42
if (UNIX AND NOT APPLE)
set(libdir "${prefix}/lib")
else()
message("Skipping ${target} on non-Linux platform")
return()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just assert this is UNIX AND NOT APPLE at the top of this file. It's OK to only support linux for now.

set(target "torchcodec::ffmpeg${ffmpeg_major_version}")
set(prefix "TORCHCODEC_FFMPEG${ffmpeg_major_version}_INSTALL_PREFIX")
if (NOT DEFINED ENV{${prefix}})
message("Skipping ${target} as ${prefix} is not defined")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be an error I think?

foreach(lib IN LISTS libs)
find_library(_LIB_PATH "${lib}" PATHS "${libdir}" NO_DEFAULT_PATH)
if (NOT _LIB_PATH)
message("Skipping ${target} as ${lib} is missing")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well, we'll want to error

# Removing _LIB_PATH from cache otherwise it won't be updated
# on the next call to find_library().
unset(_LIB_PATH CACHE)
endforeach()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I might not completely understand what this branch does, but can we it seems to do very similar logic to what already exists in

make_torchcodec_libraries(8 ffmpeg8)
make_torchcodec_libraries(7 ffmpeg7)
make_torchcodec_libraries(6 ffmpeg6)
make_torchcodec_libraries(4 ffmpeg4)
make_torchcodec_libraries(5 ffmpeg5)

and in

      add_ffmpeg_target(4 "${f4_library_file_names}")
      add_ffmpeg_target(5 "${f5_library_file_names}")
      add_ffmpeg_target(6 "${f6_library_file_names}")
      add_ffmpeg_target(7 "${f7_library_file_names}")

Can we unify these?

This commit exposes torchcodec core library to be used by third
party modules on the C++ level. The primary purpose is to allow
non-CUDA device interfaces out-of-tree implementations. There
are the following major changes:

* Exposed TorchCodecConfig.cmake which defines torchcodec
  targets to be linked with

* Provided Python level APIs to faciliate out-of-tree device
  interfaces work with torchcodec:

  * `torchcodec.cmake_prefix_path` - path which points to
    `TorchCodecConfig.cmake` configuration
  * `torchcodec.variant` - variant of the torchcodec library
    which was loaded, i.e. N in libtorchcodec_core{N}.so
    (currently ffmpeg_major_version)
  * `torchcodec.core_library_path` - full path of the loaded
    torchcodec core library

* `src/torchcodec/_core/` dropped from include paths to allow
  using of the core library out-of-tree

`TorchCodecConfig.cmake` has 2 working modes:

* By default config works by checking available version of
  FFmpeg libraries via `pkg-config` and configures corresponding
  (single) version of torchcodec
* Altenatively, if `TORCHCODEC_FFMPEG{N}_INSTALL_PREFIX` is set
  (`N=4,5,6,7` - version of FFmpeg), then config defines
  torchcodec target corresponding to the specified FFmpeg version.
  Note that multiple prefixes can be specified at the same time
  allowing to build against few torchcodec versions at once.

Config will define `TORCHCODEC_VARIANTS` variable with value
corresponding to FFmpeg major versions of available torchcodec
core libraries. Further, config will also define `torchcodec::ffmpeg${N}`
and `torchcodec::core${N}` targets where `N` takes values from
`TORCHCODEC_VARIANTS`.

Signed-off-by: Dmitry Rogozhkin <[email protected]>
@dvrogozh
Copy link
Contributor Author

On the #include path changes, I will have to pre-import your PR internall to verify that this isn't breaking our internal build (and to try to find internal workarounds if needed).

I've rebased the PR and resolved conflicts, but I will take a look and start address review comments later today or early next week. Please, let me know how #include story goes. If this change is ok (I hope so), then we may consider to make it separately to reduce the scope of this PR and simplify/focus review on the cmake aspects.

@meta-codesync
Copy link

meta-codesync bot commented Oct 24, 2025

@NicolasHug has imported this pull request. If you are a Meta employee, you can view this in D85451979.

@NicolasHug
Copy link
Contributor

Can confirm the header #include changes are OK internally! Yes, happy to consider a separate diff that does just that. Thank you!

@dvrogozh
Copy link
Contributor Author

Can confirm the header #include changes are OK internally! Yes, happy to consider a separate diff that does just that.

Thank you! Here is includes PR: #1002.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants