torchcodec 0.8.0__cp313-cp313-macosx_12_0_arm64.whl

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.

Potentially problematic release.


This version of torchcodec might be problematic. Click here for more details.

Files changed (82) hide show
  1. torchcodec/.dylibs/libc++.1.0.dylib +0 -0
  2. torchcodec/.dylibs/libpython3.13.dylib +0 -0
  3. torchcodec/__init__.py +16 -0
  4. torchcodec/_core/AVIOContextHolder.cpp +60 -0
  5. torchcodec/_core/AVIOContextHolder.h +64 -0
  6. torchcodec/_core/AVIOFileLikeContext.cpp +98 -0
  7. torchcodec/_core/AVIOFileLikeContext.h +55 -0
  8. torchcodec/_core/AVIOTensorContext.cpp +123 -0
  9. torchcodec/_core/AVIOTensorContext.h +43 -0
  10. torchcodec/_core/BetaCudaDeviceInterface.cpp +636 -0
  11. torchcodec/_core/BetaCudaDeviceInterface.h +191 -0
  12. torchcodec/_core/CMakeLists.txt +325 -0
  13. torchcodec/_core/CUDACommon.cpp +315 -0
  14. torchcodec/_core/CUDACommon.h +46 -0
  15. torchcodec/_core/Cache.h +138 -0
  16. torchcodec/_core/CpuDeviceInterface.cpp +347 -0
  17. torchcodec/_core/CpuDeviceInterface.h +132 -0
  18. torchcodec/_core/CudaDeviceInterface.cpp +357 -0
  19. torchcodec/_core/CudaDeviceInterface.h +64 -0
  20. torchcodec/_core/DeviceInterface.cpp +117 -0
  21. torchcodec/_core/DeviceInterface.h +148 -0
  22. torchcodec/_core/Encoder.cpp +807 -0
  23. torchcodec/_core/Encoder.h +173 -0
  24. torchcodec/_core/FFMPEGCommon.cpp +608 -0
  25. torchcodec/_core/FFMPEGCommon.h +245 -0
  26. torchcodec/_core/FilterGraph.cpp +149 -0
  27. torchcodec/_core/FilterGraph.h +59 -0
  28. torchcodec/_core/Frame.cpp +42 -0
  29. torchcodec/_core/Frame.h +72 -0
  30. torchcodec/_core/Metadata.h +72 -0
  31. torchcodec/_core/NVDECCache.cpp +70 -0
  32. torchcodec/_core/NVDECCache.h +104 -0
  33. torchcodec/_core/SingleStreamDecoder.cpp +1719 -0
  34. torchcodec/_core/SingleStreamDecoder.h +405 -0
  35. torchcodec/_core/StreamOptions.h +63 -0
  36. torchcodec/_core/Transform.cpp +60 -0
  37. torchcodec/_core/Transform.h +59 -0
  38. torchcodec/_core/ValidationUtils.cpp +35 -0
  39. torchcodec/_core/ValidationUtils.h +21 -0
  40. torchcodec/_core/__init__.py +41 -0
  41. torchcodec/_core/_metadata.py +317 -0
  42. torchcodec/_core/custom_ops.cpp +875 -0
  43. torchcodec/_core/fetch_and_expose_non_gpl_ffmpeg_libs.cmake +360 -0
  44. torchcodec/_core/nvcuvid_include/cuviddec.h +1374 -0
  45. torchcodec/_core/nvcuvid_include/nvcuvid.h +610 -0
  46. torchcodec/_core/ops.py +498 -0
  47. torchcodec/_core/pybind_ops.cpp +50 -0
  48. torchcodec/_frame.py +145 -0
  49. torchcodec/_internally_replaced_utils.py +67 -0
  50. torchcodec/_samplers/__init__.py +7 -0
  51. torchcodec/_samplers/video_clip_sampler.py +418 -0
  52. torchcodec/decoders/__init__.py +12 -0
  53. torchcodec/decoders/_audio_decoder.py +177 -0
  54. torchcodec/decoders/_decoder_utils.py +112 -0
  55. torchcodec/decoders/_video_decoder.py +500 -0
  56. torchcodec/encoders/__init__.py +1 -0
  57. torchcodec/encoders/_audio_encoder.py +150 -0
  58. torchcodec/libtorchcodec_core4.dylib +0 -0
  59. torchcodec/libtorchcodec_core5.dylib +0 -0
  60. torchcodec/libtorchcodec_core6.dylib +0 -0
  61. torchcodec/libtorchcodec_core7.dylib +0 -0
  62. torchcodec/libtorchcodec_core8.dylib +0 -0
  63. torchcodec/libtorchcodec_custom_ops4.dylib +0 -0
  64. torchcodec/libtorchcodec_custom_ops5.dylib +0 -0
  65. torchcodec/libtorchcodec_custom_ops6.dylib +0 -0
  66. torchcodec/libtorchcodec_custom_ops7.dylib +0 -0
  67. torchcodec/libtorchcodec_custom_ops8.dylib +0 -0
  68. torchcodec/libtorchcodec_pybind_ops4.so +0 -0
  69. torchcodec/libtorchcodec_pybind_ops5.so +0 -0
  70. torchcodec/libtorchcodec_pybind_ops6.so +0 -0
  71. torchcodec/libtorchcodec_pybind_ops7.so +0 -0
  72. torchcodec/libtorchcodec_pybind_ops8.so +0 -0
  73. torchcodec/samplers/__init__.py +2 -0
  74. torchcodec/samplers/_common.py +84 -0
  75. torchcodec/samplers/_index_based.py +287 -0
  76. torchcodec/samplers/_time_based.py +358 -0
  77. torchcodec/version.py +2 -0
  78. torchcodec-0.8.0.dist-info/METADATA +253 -0
  79. torchcodec-0.8.0.dist-info/RECORD +82 -0
  80. torchcodec-0.8.0.dist-info/WHEEL +5 -0
  81. torchcodec-0.8.0.dist-info/licenses/LICENSE +28 -0
  82. torchcodec-0.8.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,191 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+ // All rights reserved.
3
+ //
4
+ // This source code is licensed under the BSD-style license found in the
5
+ // LICENSE file in the root directory of this source tree.
6
+
7
+ // BETA CUDA device interface that provides direct control over NVDEC
8
+ // while keeping FFmpeg for demuxing. A lot of the logic, particularly the use
9
+ // of a cache for the decoders, is inspired by DALI's implementation which is
10
+ // APACHE 2.0:
11
+ // https://github.com/NVIDIA/DALI/blob/c7539676a24a8e9e99a6e8665e277363c5445259/dali/operators/video/frames_decoder_gpu.cc#L1
12
+ //
13
+ // NVDEC / NVCUVID docs:
14
+ // https://docs.nvidia.com/video-technologies/video-codec-sdk/13.0/nvdec-video-decoder-api-prog-guide/index.html#using-nvidia-video-decoder-nvdecode-api
15
+
16
+ #pragma once
17
+
18
+ #include "src/torchcodec/_core/CUDACommon.h"
19
+ #include "src/torchcodec/_core/Cache.h"
20
+ #include "src/torchcodec/_core/DeviceInterface.h"
21
+ #include "src/torchcodec/_core/FFMPEGCommon.h"
22
+ #include "src/torchcodec/_core/NVDECCache.h"
23
+
24
+ #include <map>
25
+ #include <memory>
26
+ #include <mutex>
27
+ #include <queue>
28
+ #include <unordered_map>
29
+ #include <vector>
30
+
31
+ #include "src/torchcodec/_core/nvcuvid_include/cuviddec.h"
32
+ #include "src/torchcodec/_core/nvcuvid_include/nvcuvid.h"
33
+
34
+ namespace facebook::torchcodec {
35
+
36
+ class BetaCudaDeviceInterface : public DeviceInterface {
37
+ public:
38
+ explicit BetaCudaDeviceInterface(const torch::Device& device);
39
+ virtual ~BetaCudaDeviceInterface();
40
+
41
+ void initialize(
42
+ const AVStream* avStream,
43
+ const UniqueDecodingAVFormatContext& avFormatCtx) override;
44
+
45
+ void convertAVFrameToFrameOutput(
46
+ UniqueAVFrame& avFrame,
47
+ FrameOutput& frameOutput,
48
+ std::optional<torch::Tensor> preAllocatedOutputTensor =
49
+ std::nullopt) override;
50
+
51
+ bool canDecodePacketDirectly() const override {
52
+ return true;
53
+ }
54
+
55
+ int sendPacket(ReferenceAVPacket& packet) override;
56
+ int sendEOFPacket() override;
57
+ int receiveFrame(UniqueAVFrame& avFrame) override;
58
+ void flush() override;
59
+
60
+ // NVDEC callback functions (must be public for C callbacks)
61
+ int streamPropertyChange(CUVIDEOFORMAT* videoFormat);
62
+ int frameReadyForDecoding(CUVIDPICPARAMS* picParams);
63
+ int frameReadyInDisplayOrder(CUVIDPARSERDISPINFO* dispInfo);
64
+
65
+ private:
66
+ int sendCuvidPacket(CUVIDSOURCEDATAPACKET& cuvidPacket);
67
+
68
+ void initializeBSF(
69
+ const AVCodecParameters* codecPar,
70
+ const UniqueDecodingAVFormatContext& avFormatCtx);
71
+ // Apply bitstream filter, returns filtered packet or original if no filter
72
+ // needed.
73
+ ReferenceAVPacket& applyBSF(
74
+ ReferenceAVPacket& packet,
75
+ ReferenceAVPacket& filteredPacket);
76
+
77
+ CUdeviceptr previouslyMappedFrame_ = 0;
78
+ void unmapPreviousFrame();
79
+
80
+ UniqueAVFrame convertCudaFrameToAVFrame(
81
+ CUdeviceptr framePtr,
82
+ unsigned int pitch,
83
+ const CUVIDPARSERDISPINFO& dispInfo);
84
+
85
+ CUvideoparser videoParser_ = nullptr;
86
+ UniqueCUvideodecoder decoder_;
87
+ CUVIDEOFORMAT videoFormat_ = {};
88
+
89
+ std::queue<CUVIDPARSERDISPINFO> readyFrames_;
90
+
91
+ bool eofSent_ = false;
92
+
93
+ AVRational timeBase_ = {0, 1};
94
+ AVRational frameRateAvgFromFFmpeg_ = {0, 1};
95
+
96
+ UniqueAVBSFContext bitstreamFilter_;
97
+
98
+ // NPP context for color conversion
99
+ UniqueNppContext nppCtx_;
100
+ };
101
+
102
+ } // namespace facebook::torchcodec
103
+
104
+ /* clang-format off */
105
+ // Note: [General design, sendPacket, receiveFrame, frame ordering and NVCUVID callbacks]
106
+ //
107
+ // At a high level, this decoding interface mimics the FFmpeg send/receive
108
+ // architecture:
109
+ // - sendPacket(AVPacket) sends an AVPacket from the FFmpeg demuxer to the
110
+ // NVCUVID parser.
111
+ // - receiveFrame(AVFrame) is a non-blocking call:
112
+ // - if a frame is ready **in display order**, it must return it. By display
113
+ // order, we mean that receiveFrame() must return frames with increasing pts
114
+ // values when called successively.
115
+ // - if no frame is ready, it must return AVERROR(EAGAIN) to indicate the
116
+ // caller should send more packets.
117
+ //
118
+ // The rest of this note assumes you have a reasonable level of familiarity with
119
+ // the sendPacket/receiveFrame calling pattern. If you don't, look up the core
120
+ // decoding loop in SingleVideoDecoder.
121
+ //
122
+ // The frame re-ordering problem:
123
+ // Depending on the codec and on the encoding parameters, a packet from a video
124
+ // stream may contain exactly one frame, more than one frame, or a fraction of a
125
+ // frame. And, there may be non-linear frame dependencies because of B-frames,
126
+ // which need both past *and* future frames to be decoded. Consider the
127
+ // following stream, with frames presented in display order: I0 B1 P2 B3 P4 ...
128
+ // - I0 is an I-frame (also key frame, can be decoded independently)
129
+ // - B1 is a B-frame (bi-directional) which needs both I0 and P2 to be decoded
130
+ // - P2 is a P-frame (predicted frame) which only needs I0 to be decodec.
131
+ //
132
+ // Because B1 needs both I0 and P2 to be properly decoded, the decode order
133
+ // (packet order), defined by the encoder, must be: I0 P2 B1 P4 B3 ... which is
134
+ // different from the display order.
135
+ //
136
+ // SendPacket(AVPacket)'s job is just to pass down the packet to the NVCUVID
137
+ // parser by calling cuvidParseVideoData(packet). When
138
+ // cuvidParseVideoData(packet) is called, it may trigger callbacks,
139
+ // particularly:
140
+ // - streamPropertyChange(videoFormat): triggered once at the start of the
141
+ // stream, and possibly later if the stream properties change (e.g.
142
+ // resolution).
143
+ // - frameReadyForDecoding(picParams)): triggered **in decode order** when the
144
+ // parser has accumulated enough data to decode a frame. We send that frame to
145
+ // the NVDEC hardware for **async** decoding.
146
+ // - frameReadyInDisplayOrder(dispInfo)): triggered **in display order** when a
147
+ // frame is ready to be "displayed" (returned). At that point, the parser also
148
+ // gives us the pts of that frame. We store (a reference to) that frame in a
149
+ // FIFO queue: readyFrames_.
150
+ //
151
+ // When receiveFrame(AVFrame) is called, if readyFrames_ is not empty, we pop
152
+ // the front of the queue, which is the next frame in display order, and map it
153
+ // to an AVFrame by calling cuvidMapVideoFrame(). If readyFrames_ is empty we
154
+ // return EAGAIN to indicate the caller should send more packets.
155
+ //
156
+ // There is potentially a small inefficiency due to the callback design: in
157
+ // order for us to know that a frame is ready in display order, we need the
158
+ // frameReadyInDisplayOrder callback to be triggered. This can only happen
159
+ // within cuvidParseVideoData(packet) in sendPacket(). This means there may be
160
+ // the following sequence of calls:
161
+ //
162
+ // sendPacket(relevantAVPacket)
163
+ // cuvidParseVideoData(relevantAVPacket)
164
+ // frameReadyForDecoding()
165
+ // cuvidDecodePicture() Send frame to NVDEC for async decoding
166
+ //
167
+ // receiveFrame() -> EAGAIN Frame is potentially already decoded
168
+ // and could be returned, but we don't
169
+ // know because frameReadyInDisplayOrder
170
+ // hasn't been triggered yet. We'll only
171
+ // know after sending another,
172
+ // potentially irrelevant packet.
173
+ //
174
+ // sendPacket(irrelevantAVPacket)
175
+ // cuvidParseVideoData(irrelevantAVPacket)
176
+ // frameReadyInDisplayOrder() Only now do we know that our target
177
+ // frame is ready.
178
+ //
179
+ // receiveFrame() return target frame
180
+ //
181
+ // How much this matters in practice is unclear, but probably negligible in
182
+ // general. Particularly when frames are decoded consecutively anyway, the
183
+ // "irrelevantPacket" is actually relevant for a future target frame.
184
+ //
185
+ // Note that the alternative is to *not* rely on the frameReadyInDisplayOrder
186
+ // callback. It's technically possible, but it would mean we now have to solve
187
+ // two hard, *codec-dependent* problems that the callback was solving for us:
188
+ // - we have to guess the frame's pts ourselves
189
+ // - we have to re-order the frames ourselves to preserve display order.
190
+ //
191
+ /* clang-format on */
@@ -0,0 +1,325 @@
1
+ cmake_minimum_required(VERSION 3.18)
2
+ project(TorchCodec)
3
+ set(CMAKE_CXX_STANDARD 17)
4
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
5
+
6
+ set(PYBIND11_FINDPYTHON ON)
7
+ find_package(pybind11 REQUIRED)
8
+ find_package(Torch REQUIRED)
9
+ find_package(Python3 ${PYTHON_VERSION} EXACT COMPONENTS Development)
10
+
11
+ if(DEFINED TORCHCODEC_DISABLE_COMPILE_WARNING_AS_ERROR AND TORCHCODEC_DISABLE_COMPILE_WARNING_AS_ERROR)
12
+ set(TORCHCODEC_WERROR_OPTION "")
13
+ else()
14
+ if (WIN32)
15
+ # TODO set warnings as errors on Windows as well.
16
+ # set(TORCHCODEC_WERROR_OPTION "/WX")
17
+ else()
18
+ set(TORCHCODEC_WERROR_OPTION "-Werror")
19
+ endif()
20
+ endif()
21
+
22
+ if (WIN32)
23
+ # Avoid warnings about non-ASCII characters in source files.
24
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4819")
25
+ # Important for when we add Windows CUDA: exporting all symbols is limited to
26
+ # 65535 symbols, which (apparently) will not work for CUDA.
27
+ # https://github.com/pytorch/pytorch/pull/3650
28
+ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
29
+ endif()
30
+
31
+ if (WIN32)
32
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 ${TORCHCODEC_WERROR_OPTION} ${TORCH_CXX_FLAGS}")
33
+ else()
34
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic ${TORCHCODEC_WERROR_OPTION} ${TORCH_CXX_FLAGS}")
35
+ endif()
36
+
37
+
38
+ function(make_torchcodec_sublibrary
39
+ library_name
40
+ type
41
+ sources
42
+ library_dependencies)
43
+
44
+ add_library(${library_name} ${type} ${sources})
45
+ set_target_properties(${library_name} PROPERTIES CXX_STANDARD 17)
46
+ target_include_directories(${library_name}
47
+ PRIVATE
48
+ ./../../../
49
+ "${TORCH_INSTALL_PREFIX}/include"
50
+ ${Python3_INCLUDE_DIRS}
51
+ )
52
+
53
+ # Avoid adding the "lib" prefix which we already add explicitly.
54
+ set_target_properties(${library_name} PROPERTIES PREFIX "")
55
+
56
+ target_link_libraries(
57
+ ${library_name}
58
+ PUBLIC
59
+ ${library_dependencies}
60
+ )
61
+
62
+ endfunction()
63
+
64
+ function(make_torchcodec_libraries
65
+ ffmpeg_major_version
66
+ ffmpeg_target)
67
+
68
+ # We create three shared libraries per version of FFmpeg, where the version
69
+ # is denoted by N:
70
+ #
71
+ # 1. libtorchcodec_coreN.{ext}: Base library which contains the
72
+ # implementation of VideoDecoder and everything VideoDecoder needs. On
73
+ # Linux, {ext} is so. On Mac, it is dylib. On Windows it's dll.
74
+ #
75
+ # 2. libtorchcodec_custom_opsN.{ext}: Implementation of the PyTorch custom
76
+ # ops. Depends on libtorchcodec_coreN.{ext}. On Linux, {ext} is so.
77
+ # On Mac, it is dylib. On Windows it's dll.
78
+ #
79
+ # 3. libtorchcodec_pybind_opsN.{ext}: Implementation of the pybind11 ops. We
80
+ # keep these separate from the PyTorch custom ops because we have to
81
+ # load these libraries separately on the Python side. Depends on
82
+ # libtorchcodec_coreN.{ext}. On BOTH Linux and Mac {ext} is so. On
83
+ # Windows, it's pyd.
84
+
85
+ # 1. Create libtorchcodec_coreN.{ext}.
86
+ set(core_library_name "libtorchcodec_core${ffmpeg_major_version}")
87
+ set(core_sources
88
+ AVIOContextHolder.cpp
89
+ AVIOTensorContext.cpp
90
+ FFMPEGCommon.cpp
91
+ FilterGraph.cpp
92
+ Frame.cpp
93
+ DeviceInterface.cpp
94
+ CpuDeviceInterface.cpp
95
+ SingleStreamDecoder.cpp
96
+ Encoder.cpp
97
+ ValidationUtils.cpp
98
+ Transform.cpp
99
+ )
100
+
101
+ if(ENABLE_CUDA)
102
+ list(APPEND core_sources CudaDeviceInterface.cpp BetaCudaDeviceInterface.cpp NVDECCache.cpp CUDACommon.cpp)
103
+ endif()
104
+
105
+ set(core_library_dependencies
106
+ ${ffmpeg_target}
107
+ ${TORCH_LIBRARIES}
108
+ )
109
+
110
+ if(ENABLE_CUDA)
111
+ # Try to find NVCUVID. Try the normal way first. This should work locally.
112
+ find_library(NVCUVID_LIBRARY NAMES nvcuvid)
113
+ # If not found, try with version suffix, or hardcoded path. Appears
114
+ # to be necessary on the CI.
115
+ if(NOT NVCUVID_LIBRARY)
116
+ find_library(NVCUVID_LIBRARY NAMES nvcuvid.1 PATHS /usr/lib64 /usr/lib)
117
+ endif()
118
+ if(NOT NVCUVID_LIBRARY)
119
+ set(NVCUVID_LIBRARY "/usr/lib64/libnvcuvid.so.1")
120
+ endif()
121
+
122
+ if(NVCUVID_LIBRARY)
123
+ message(STATUS "Found NVCUVID: ${NVCUVID_LIBRARY}")
124
+ else()
125
+ message(FATAL_ERROR "Could not find NVCUVID library")
126
+ endif()
127
+
128
+ list(APPEND core_library_dependencies
129
+ ${CUDA_nppi_LIBRARY}
130
+ ${CUDA_nppicc_LIBRARY}
131
+ ${NVCUVID_LIBRARY}
132
+ )
133
+ endif()
134
+
135
+ make_torchcodec_sublibrary(
136
+ "${core_library_name}"
137
+ SHARED
138
+ "${core_sources}"
139
+ "${core_library_dependencies}"
140
+ )
141
+
142
+ # 2. Create libtorchcodec_custom_opsN.{ext}.
143
+ set(custom_ops_library_name "libtorchcodec_custom_ops${ffmpeg_major_version}")
144
+ set(custom_ops_sources
145
+ AVIOTensorContext.cpp
146
+ custom_ops.cpp
147
+ )
148
+ set(custom_ops_dependencies
149
+ ${core_library_name}
150
+ ${Python3_LIBRARIES}
151
+ )
152
+ make_torchcodec_sublibrary(
153
+ "${custom_ops_library_name}"
154
+ SHARED
155
+ "${custom_ops_sources}"
156
+ "${custom_ops_dependencies}"
157
+ )
158
+
159
+ # 3. Create libtorchcodec_pybind_opsN.so.
160
+ set(pybind_ops_library_name "libtorchcodec_pybind_ops${ffmpeg_major_version}")
161
+ set(pybind_ops_sources
162
+ AVIOFileLikeContext.cpp
163
+ pybind_ops.cpp
164
+ )
165
+ set(pybind_ops_dependencies
166
+ ${core_library_name}
167
+ pybind11::module # This library dependency makes sure we have the right
168
+ # Python libraries included as well as all of the right
169
+ # settings so that we can successfully load the shared
170
+ # library as a Python module on Mac. If we instead use
171
+ # ${Python3_LIBRARIES}, it works on Linux but not on
172
+ # Mac.
173
+ )
174
+ make_torchcodec_sublibrary(
175
+ "${pybind_ops_library_name}"
176
+ MODULE # Note that this not SHARED; otherwise we build the wrong kind
177
+ # of library on Mac. On Mac, SHARED becomes .dylib and MODULE becomes
178
+ # a .so. We want pybind11 libraries to become .so. If this is
179
+ # changed to SHARED, we will be able to succesfully compile a
180
+ # .dylib, but we will not be able to succesfully import that as
181
+ # a Python module on Mac.
182
+ "${pybind_ops_sources}"
183
+ "${pybind_ops_dependencies}"
184
+ )
185
+
186
+ if(WIN32)
187
+ # On Windows, we need to set the suffix to .pyd so that Python can
188
+ # import the shared library as a module. Just setting the MODULE type
189
+ # isn't enough.
190
+ set_target_properties(${pybind_ops_library_name} PROPERTIES SUFFIX ".pyd")
191
+ endif()
192
+
193
+ # pybind11 limits the visibility of symbols in the shared library to prevent
194
+ # stray initialization of py::objects. The rest of the object code must
195
+ # match. See:
196
+ # https://pybind11.readthedocs.io/en/stable/faq.html#someclass-declared-with-greater-visibility-than-the-type-of-its-field-someclass-member-wattributes
197
+ # We have to do this for both pybind_ops and custom_ops because they include
198
+ # some of the same headers.
199
+ #
200
+ # Note that this is Linux only. It's not necessary on Windows, and on Mac
201
+ # hiding visibility can actually break dyanmic casts across share libraries
202
+ # because the type infos don't get exported.
203
+ if(LINUX)
204
+ target_compile_options(
205
+ ${pybind_ops_library_name}
206
+ PUBLIC
207
+ "-fvisibility=hidden"
208
+ )
209
+ target_compile_options(
210
+ ${custom_ops_library_name}
211
+ PUBLIC
212
+ "-fvisibility=hidden"
213
+ )
214
+ endif()
215
+
216
+ # The value we use here must match the value we return from
217
+ # _get_pybind_ops_module_name() on the Python side. If the values do not
218
+ # match, then we will be unable to import the C++ shared library as a
219
+ # Python module at runtime.
220
+ target_compile_definitions(
221
+ ${pybind_ops_library_name}
222
+ PRIVATE
223
+ PYBIND_OPS_MODULE_NAME=core_pybind_ops
224
+ )
225
+
226
+ if(APPLE)
227
+ # If we don't make sure this flag is set, we run into segfauls at import
228
+ # time on Mac. See:
229
+ # https://github.com/pybind/pybind11/issues/3907#issuecomment-1170412764
230
+ target_link_options(
231
+ ${pybind_ops_library_name}
232
+ PUBLIC
233
+ "LINKER:-undefined,dynamic_lookup"
234
+ )
235
+ endif()
236
+
237
+ # Install all libraries.
238
+ set(
239
+ all_libraries
240
+ ${core_library_name}
241
+ ${custom_ops_library_name}
242
+ ${pybind_ops_library_name}
243
+ )
244
+
245
+ # The install step is invoked within CMakeBuild.build_library() in
246
+ # setup.py and just copies the built files from the temp
247
+ # cmake/setuptools build folder into the CMAKE_INSTALL_PREFIX folder. We
248
+ # still need to manually pass "DESTINATION ..." for cmake to copy those
249
+ # files in CMAKE_INSTALL_PREFIX instead of CMAKE_INSTALL_PREFIX/lib.
250
+ install(
251
+ TARGETS ${all_libraries}
252
+ LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}
253
+ RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX} # For Windows
254
+ )
255
+
256
+ endfunction()
257
+
258
+ if(DEFINED ENV{BUILD_AGAINST_ALL_FFMPEG_FROM_S3})
259
+ message(
260
+ STATUS
261
+ "Building and dynamically linking libtorchcodec against our pre-built
262
+ non-GPL FFmpeg libraries. These libraries are only used at build time,
263
+ you still need a different FFmpeg to be installed for run time!"
264
+ )
265
+
266
+ # This will expose the ffmpeg4, ffmpeg5, ffmpeg6, ffmpeg7, and ffmpeg8 targets
267
+ include(
268
+ ${CMAKE_CURRENT_SOURCE_DIR}/fetch_and_expose_non_gpl_ffmpeg_libs.cmake
269
+ )
270
+
271
+ make_torchcodec_libraries(8 ffmpeg8)
272
+ make_torchcodec_libraries(7 ffmpeg7)
273
+ make_torchcodec_libraries(6 ffmpeg6)
274
+ make_torchcodec_libraries(4 ffmpeg4)
275
+ make_torchcodec_libraries(5 ffmpeg5)
276
+ else()
277
+ message(
278
+ STATUS
279
+ "Building and dynamically linking libtorchcodec against the installed
280
+ FFmpeg libraries. This require pkg-config to be installed. If you have
281
+ installed FFmpeg from conda, make sure pkg-config is installed from
282
+ conda as well."
283
+ )
284
+ find_package(PkgConfig REQUIRED)
285
+ pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
286
+ libavdevice
287
+ libavfilter
288
+ libavformat
289
+ libavcodec
290
+ libavutil
291
+ libswresample
292
+ libswscale
293
+ )
294
+
295
+ # Split libavcodec's version string by '.' and convert it to a list
296
+ string(REPLACE "." ";" libavcodec_version_list ${LIBAV_libavcodec_VERSION})
297
+ # Get the first element of the list, which is the major version
298
+ list(GET libavcodec_version_list 0 libavcodec_major_version)
299
+
300
+ if (${libavcodec_major_version} STREQUAL "58")
301
+ set(ffmpeg_major_version "4")
302
+ elseif (${libavcodec_major_version} STREQUAL "59")
303
+ set(ffmpeg_major_version "5")
304
+ elseif (${libavcodec_major_version} STREQUAL "60")
305
+ set(ffmpeg_major_version "6")
306
+ elseif (${libavcodec_major_version} STREQUAL "61")
307
+ set(ffmpeg_major_version "7")
308
+ elseif (${libavcodec_major_version} STREQUAL "62")
309
+ set(ffmpeg_major_version "8")
310
+ else()
311
+ message(
312
+ FATAL_ERROR
313
+ "Unsupported libavcodec version: ${libavcodec_major_version}"
314
+ )
315
+ endif()
316
+
317
+ make_torchcodec_libraries(${ffmpeg_major_version} PkgConfig::LIBAV)
318
+
319
+ # Expose these values updwards so that the test compilation does not need
320
+ # to re-figure it out. FIXME: it's not great that we just copy-paste the
321
+ # library names.
322
+ set(libtorchcodec_library_name "libtorchcodec_core${ffmpeg_major_version}" PARENT_SCOPE)
323
+ set(libtorchcodec_custom_ops_name "libtorchcodec_custom_ops${ffmpeg_major_version}" PARENT_SCOPE)
324
+ set(libav_include_dirs ${LIBAV_INCLUDE_DIRS} PARENT_SCOPE)
325
+ endif()