torchcodec 0.10.0__cp312-cp312-manylinux_2_28_x86_64.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.
Files changed (88) hide show
  1. torchcodec/__init__.py +27 -0
  2. torchcodec/_core/AVIOContextHolder.cpp +60 -0
  3. torchcodec/_core/AVIOContextHolder.h +64 -0
  4. torchcodec/_core/AVIOFileLikeContext.cpp +98 -0
  5. torchcodec/_core/AVIOFileLikeContext.h +55 -0
  6. torchcodec/_core/AVIOTensorContext.cpp +130 -0
  7. torchcodec/_core/AVIOTensorContext.h +44 -0
  8. torchcodec/_core/BetaCudaDeviceInterface.cpp +849 -0
  9. torchcodec/_core/BetaCudaDeviceInterface.h +196 -0
  10. torchcodec/_core/CMakeLists.txt +295 -0
  11. torchcodec/_core/CUDACommon.cpp +330 -0
  12. torchcodec/_core/CUDACommon.h +51 -0
  13. torchcodec/_core/Cache.h +124 -0
  14. torchcodec/_core/CpuDeviceInterface.cpp +509 -0
  15. torchcodec/_core/CpuDeviceInterface.h +141 -0
  16. torchcodec/_core/CudaDeviceInterface.cpp +602 -0
  17. torchcodec/_core/CudaDeviceInterface.h +79 -0
  18. torchcodec/_core/DeviceInterface.cpp +117 -0
  19. torchcodec/_core/DeviceInterface.h +191 -0
  20. torchcodec/_core/Encoder.cpp +1054 -0
  21. torchcodec/_core/Encoder.h +192 -0
  22. torchcodec/_core/FFMPEGCommon.cpp +684 -0
  23. torchcodec/_core/FFMPEGCommon.h +314 -0
  24. torchcodec/_core/FilterGraph.cpp +159 -0
  25. torchcodec/_core/FilterGraph.h +59 -0
  26. torchcodec/_core/Frame.cpp +47 -0
  27. torchcodec/_core/Frame.h +72 -0
  28. torchcodec/_core/Metadata.cpp +124 -0
  29. torchcodec/_core/Metadata.h +92 -0
  30. torchcodec/_core/NVCUVIDRuntimeLoader.cpp +320 -0
  31. torchcodec/_core/NVCUVIDRuntimeLoader.h +14 -0
  32. torchcodec/_core/NVDECCache.cpp +60 -0
  33. torchcodec/_core/NVDECCache.h +102 -0
  34. torchcodec/_core/SingleStreamDecoder.cpp +1586 -0
  35. torchcodec/_core/SingleStreamDecoder.h +391 -0
  36. torchcodec/_core/StreamOptions.h +70 -0
  37. torchcodec/_core/Transform.cpp +128 -0
  38. torchcodec/_core/Transform.h +86 -0
  39. torchcodec/_core/ValidationUtils.cpp +35 -0
  40. torchcodec/_core/ValidationUtils.h +21 -0
  41. torchcodec/_core/__init__.py +46 -0
  42. torchcodec/_core/_metadata.py +262 -0
  43. torchcodec/_core/custom_ops.cpp +1090 -0
  44. torchcodec/_core/fetch_and_expose_non_gpl_ffmpeg_libs.cmake +169 -0
  45. torchcodec/_core/nvcuvid_include/cuviddec.h +1374 -0
  46. torchcodec/_core/nvcuvid_include/nvcuvid.h +610 -0
  47. torchcodec/_core/ops.py +605 -0
  48. torchcodec/_core/pybind_ops.cpp +50 -0
  49. torchcodec/_frame.py +146 -0
  50. torchcodec/_internally_replaced_utils.py +68 -0
  51. torchcodec/_samplers/__init__.py +7 -0
  52. torchcodec/_samplers/video_clip_sampler.py +419 -0
  53. torchcodec/decoders/__init__.py +12 -0
  54. torchcodec/decoders/_audio_decoder.py +185 -0
  55. torchcodec/decoders/_decoder_utils.py +113 -0
  56. torchcodec/decoders/_video_decoder.py +601 -0
  57. torchcodec/encoders/__init__.py +2 -0
  58. torchcodec/encoders/_audio_encoder.py +149 -0
  59. torchcodec/encoders/_video_encoder.py +196 -0
  60. torchcodec/libtorchcodec_core4.so +0 -0
  61. torchcodec/libtorchcodec_core5.so +0 -0
  62. torchcodec/libtorchcodec_core6.so +0 -0
  63. torchcodec/libtorchcodec_core7.so +0 -0
  64. torchcodec/libtorchcodec_core8.so +0 -0
  65. torchcodec/libtorchcodec_custom_ops4.so +0 -0
  66. torchcodec/libtorchcodec_custom_ops5.so +0 -0
  67. torchcodec/libtorchcodec_custom_ops6.so +0 -0
  68. torchcodec/libtorchcodec_custom_ops7.so +0 -0
  69. torchcodec/libtorchcodec_custom_ops8.so +0 -0
  70. torchcodec/libtorchcodec_pybind_ops4.so +0 -0
  71. torchcodec/libtorchcodec_pybind_ops5.so +0 -0
  72. torchcodec/libtorchcodec_pybind_ops6.so +0 -0
  73. torchcodec/libtorchcodec_pybind_ops7.so +0 -0
  74. torchcodec/libtorchcodec_pybind_ops8.so +0 -0
  75. torchcodec/samplers/__init__.py +2 -0
  76. torchcodec/samplers/_common.py +84 -0
  77. torchcodec/samplers/_index_based.py +287 -0
  78. torchcodec/samplers/_time_based.py +358 -0
  79. torchcodec/share/cmake/TorchCodec/TorchCodecConfig.cmake +76 -0
  80. torchcodec/share/cmake/TorchCodec/ffmpeg_versions.cmake +122 -0
  81. torchcodec/transforms/__init__.py +12 -0
  82. torchcodec/transforms/_decoder_transforms.py +375 -0
  83. torchcodec/version.py +2 -0
  84. torchcodec-0.10.0.dist-info/METADATA +286 -0
  85. torchcodec-0.10.0.dist-info/RECORD +88 -0
  86. torchcodec-0.10.0.dist-info/WHEEL +5 -0
  87. torchcodec-0.10.0.dist-info/licenses/LICENSE +28 -0
  88. torchcodec-0.10.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,149 @@
1
+ from pathlib import Path
2
+
3
+ import torch
4
+ from torch import Tensor
5
+
6
+ from torchcodec import _core
7
+
8
+
9
+ class AudioEncoder:
10
+ """An audio encoder.
11
+
12
+ Args:
13
+ samples (``torch.Tensor``): The samples to encode. This must be a 2D
14
+ tensor of shape ``(num_channels, num_samples)``, or a 1D tensor in
15
+ which case ``num_channels = 1`` is assumed. Values must be float
16
+ values in ``[-1, 1]``.
17
+ sample_rate (int): The sample rate of the **input** ``samples``. The
18
+ sample rate of the encoded output can be specified using the
19
+ encoding methods (``to_file``, etc.).
20
+ """
21
+
22
+ def __init__(self, samples: Tensor, *, sample_rate: int):
23
+ torch._C._log_api_usage_once("torchcodec.encoders.AudioEncoder")
24
+ # Some of these checks are also done in C++: it's OK, they're cheap, and
25
+ # doing them here allows to surface them when the AudioEncoder is
26
+ # instantiated, rather than later when the encoding methods are called.
27
+ if not isinstance(samples, Tensor):
28
+ raise ValueError(
29
+ f"Expected samples to be a Tensor, got {type(samples) = }."
30
+ )
31
+ if samples.ndim == 1:
32
+ # make it 2D and assume 1 channel
33
+ samples = torch.unsqueeze(samples, 0)
34
+ if samples.ndim != 2:
35
+ raise ValueError(f"Expected 1D or 2D samples, got {samples.shape = }.")
36
+ if samples.dtype != torch.float32:
37
+ raise ValueError(f"Expected float32 samples, got {samples.dtype = }.")
38
+ if sample_rate <= 0:
39
+ raise ValueError(f"{sample_rate = } must be > 0.")
40
+
41
+ self._samples = samples
42
+ self._sample_rate = sample_rate
43
+
44
+ def to_file(
45
+ self,
46
+ dest: str | Path,
47
+ *,
48
+ bit_rate: int | None = None,
49
+ num_channels: int | None = None,
50
+ sample_rate: int | None = None,
51
+ ) -> None:
52
+ """Encode samples into a file.
53
+
54
+ Args:
55
+ dest (str or ``pathlib.Path``): The path to the output file, e.g.
56
+ ``audio.mp3``. The extension of the file determines the audio
57
+ format and container.
58
+ bit_rate (int, optional): The output bit rate. Encoders typically
59
+ support a finite set of bit rate values, so ``bit_rate`` will be
60
+ matched to one of those supported values. The default is chosen
61
+ by FFmpeg.
62
+ num_channels (int, optional): The number of channels of the encoded
63
+ output samples. By default, the number of channels of the input
64
+ ``samples`` is used.
65
+ sample_rate (int, optional): The sample rate of the encoded output.
66
+ By default, the sample rate of the input ``samples`` is used.
67
+ """
68
+ _core.encode_audio_to_file(
69
+ samples=self._samples,
70
+ sample_rate=self._sample_rate,
71
+ filename=str(dest),
72
+ bit_rate=bit_rate,
73
+ num_channels=num_channels,
74
+ desired_sample_rate=sample_rate,
75
+ )
76
+
77
+ def to_tensor(
78
+ self,
79
+ format: str,
80
+ *,
81
+ bit_rate: int | None = None,
82
+ num_channels: int | None = None,
83
+ sample_rate: int | None = None,
84
+ ) -> Tensor:
85
+ """Encode samples into raw bytes, as a 1D uint8 Tensor.
86
+
87
+ Args:
88
+ format (str): The format of the encoded samples, e.g. "mp3", "wav"
89
+ or "flac".
90
+ bit_rate (int, optional): The output bit rate. Encoders typically
91
+ support a finite set of bit rate values, so ``bit_rate`` will be
92
+ matched to one of those supported values. The default is chosen
93
+ by FFmpeg.
94
+ num_channels (int, optional): The number of channels of the encoded
95
+ output samples. By default, the number of channels of the input
96
+ ``samples`` is used.
97
+ sample_rate (int, optional): The sample rate of the encoded output.
98
+ By default, the sample rate of the input ``samples`` is used.
99
+
100
+ Returns:
101
+ Tensor: The raw encoded bytes as 1D uint8 Tensor.
102
+ """
103
+ return _core.encode_audio_to_tensor(
104
+ samples=self._samples,
105
+ sample_rate=self._sample_rate,
106
+ format=format,
107
+ bit_rate=bit_rate,
108
+ num_channels=num_channels,
109
+ desired_sample_rate=sample_rate,
110
+ )
111
+
112
+ def to_file_like(
113
+ self,
114
+ file_like,
115
+ format: str,
116
+ *,
117
+ bit_rate: int | None = None,
118
+ num_channels: int | None = None,
119
+ sample_rate: int | None = None,
120
+ ) -> None:
121
+ """Encode samples into a file-like object.
122
+
123
+ Args:
124
+ file_like: A file-like object that supports ``write()`` and
125
+ ``seek()`` methods, such as io.BytesIO(), an open file in binary
126
+ write mode, etc. Methods must have the following signature:
127
+ ``write(data: bytes) -> int`` and ``seek(offset: int, whence:
128
+ int = 0) -> int``.
129
+ format (str): The format of the encoded samples, e.g. "mp3", "wav"
130
+ or "flac".
131
+ bit_rate (int, optional): The output bit rate. Encoders typically
132
+ support a finite set of bit rate values, so ``bit_rate`` will be
133
+ matched to one of those supported values. The default is chosen
134
+ by FFmpeg.
135
+ num_channels (int, optional): The number of channels of the encoded
136
+ output samples. By default, the number of channels of the input
137
+ ``samples`` is used.
138
+ sample_rate (int, optional): The sample rate of the encoded output.
139
+ By default, the sample rate of the input ``samples`` is used.
140
+ """
141
+ _core.encode_audio_to_file_like(
142
+ samples=self._samples,
143
+ sample_rate=self._sample_rate,
144
+ format=format,
145
+ file_like=file_like,
146
+ bit_rate=bit_rate,
147
+ num_channels=num_channels,
148
+ desired_sample_rate=sample_rate,
149
+ )
@@ -0,0 +1,196 @@
1
+ from pathlib import Path
2
+ from typing import Any
3
+
4
+ import torch
5
+ from torch import Tensor
6
+
7
+ from torchcodec import _core
8
+
9
+
10
+ class VideoEncoder:
11
+ """A video encoder on CPU or CUDA..
12
+
13
+ Args:
14
+ frames (``torch.Tensor``): The frames to encode. This must be a 4D
15
+ tensor of shape ``(N, C, H, W)`` where N is the number of frames,
16
+ C is 3 channels (RGB), H is height, and W is width.
17
+ Values must be uint8 in the range ``[0, 255]``.
18
+ The tensor can be on CPU or CUDA. The device of the tensor
19
+ determines which encoder is used (CPU or GPU).
20
+ frame_rate (float): The frame rate of the **input** ``frames``. Also defines the encoded **output** frame rate.
21
+ """
22
+
23
+ def __init__(self, frames: Tensor, *, frame_rate: float):
24
+ torch._C._log_api_usage_once("torchcodec.encoders.VideoEncoder")
25
+ if not isinstance(frames, Tensor):
26
+ raise ValueError(f"Expected frames to be a Tensor, got {type(frames) = }.")
27
+ if frames.ndim != 4:
28
+ raise ValueError(f"Expected 4D frames, got {frames.shape = }.")
29
+ if frames.dtype != torch.uint8:
30
+ raise ValueError(f"Expected uint8 frames, got {frames.dtype = }.")
31
+ if frame_rate <= 0:
32
+ raise ValueError(f"{frame_rate = } must be > 0.")
33
+
34
+ self._frames = frames
35
+ self._frame_rate = frame_rate
36
+
37
+ def to_file(
38
+ self,
39
+ dest: str | Path,
40
+ *,
41
+ codec: str | None = None,
42
+ pixel_format: str | None = None,
43
+ crf: int | float | None = None,
44
+ preset: str | int | None = None,
45
+ extra_options: dict[str, Any] | None = None,
46
+ ) -> None:
47
+ """Encode frames into a file.
48
+
49
+ Args:
50
+ dest (str or ``pathlib.Path``): The path to the output file, e.g.
51
+ ``video.mp4``. The extension of the file determines the video
52
+ container format.
53
+ codec (str, optional): The codec to use for encoding (e.g., "libx264",
54
+ "h264"). If not specified, the default codec
55
+ for the container format will be used.
56
+ See :ref:`codec_selection` for details.
57
+ pixel_format (str, optional): The pixel format for encoding (e.g.,
58
+ "yuv420p", "yuv444p"). If not specified, uses codec's default format.
59
+ Must be left as ``None`` when encoding CUDA tensors.
60
+ See :ref:`pixel_format` for details.
61
+ crf (int or float, optional): Constant Rate Factor for encoding quality. Lower values
62
+ mean better quality. Valid range depends on the encoder (e.g. 0-51 for libx264).
63
+ Defaults to None (which will use encoder's default).
64
+ See :ref:`crf` for details.
65
+ preset (str or int, optional): Encoder option that controls the tradeoff between
66
+ encoding encoding speed and compression (output size). Valid on the encoder (commonly
67
+ a string: "fast", "medium", "slow"). Defaults to None
68
+ (which will use encoder's default).
69
+ See :ref:`preset` for details.
70
+ extra_options (dict[str, Any], optional): A dictionary of additional
71
+ encoder options to pass, e.g. ``{"qp": 5, "tune": "film"}``.
72
+ See :ref:`extra_options` for details.
73
+ """
74
+ preset = str(preset) if isinstance(preset, int) else preset
75
+ _core.encode_video_to_file(
76
+ frames=self._frames,
77
+ frame_rate=self._frame_rate,
78
+ filename=str(dest),
79
+ codec=codec,
80
+ pixel_format=pixel_format,
81
+ crf=crf,
82
+ preset=preset,
83
+ extra_options=[
84
+ str(x) for k, v in (extra_options or {}).items() for x in (k, v)
85
+ ],
86
+ )
87
+
88
+ def to_tensor(
89
+ self,
90
+ format: str,
91
+ *,
92
+ codec: str | None = None,
93
+ pixel_format: str | None = None,
94
+ crf: int | float | None = None,
95
+ preset: str | int | None = None,
96
+ extra_options: dict[str, Any] | None = None,
97
+ ) -> Tensor:
98
+ """Encode frames into raw bytes, as a 1D uint8 Tensor.
99
+
100
+ Args:
101
+ format (str): The container format of the encoded frames, e.g. "mp4", "mov",
102
+ "mkv", "avi", "webm", "flv", etc.
103
+ codec (str, optional): The codec to use for encoding (e.g., "libx264",
104
+ "h264"). If not specified, the default codec
105
+ for the container format will be used.
106
+ See :ref:`codec_selection` for details.
107
+ pixel_format (str, optional): The pixel format to encode frames into (e.g.,
108
+ "yuv420p", "yuv444p"). If not specified, uses codec's default format.
109
+ Must be left as ``None`` when encoding CUDA tensors.
110
+ See :ref:`pixel_format` for details.
111
+ crf (int or float, optional): Constant Rate Factor for encoding quality. Lower values
112
+ mean better quality. Valid range depends on the encoder (e.g. 0-51 for libx264).
113
+ Defaults to None (which will use encoder's default).
114
+ See :ref:`crf` for details.
115
+ preset (str or int, optional): Encoder option that controls the tradeoff between
116
+ encoding encoding speed and compression (output size). Valid on the encoder (commonly
117
+ a string: "fast", "medium", "slow"). Defaults to None
118
+ (which will use encoder's default).
119
+ See :ref:`preset` for details.
120
+ extra_options (dict[str, Any], optional): A dictionary of additional
121
+ encoder options to pass, e.g. ``{"qp": 5, "tune": "film"}``.
122
+ See :ref:`extra_options` for details.
123
+
124
+ Returns:
125
+ Tensor: The raw encoded bytes as 1D uint8 Tensor on CPU regardless of the device of the input frames.
126
+ """
127
+ preset_value = str(preset) if isinstance(preset, int) else preset
128
+ return _core.encode_video_to_tensor(
129
+ frames=self._frames,
130
+ frame_rate=self._frame_rate,
131
+ format=format,
132
+ codec=codec,
133
+ pixel_format=pixel_format,
134
+ crf=crf,
135
+ preset=preset_value,
136
+ extra_options=[
137
+ str(x) for k, v in (extra_options or {}).items() for x in (k, v)
138
+ ],
139
+ )
140
+
141
+ def to_file_like(
142
+ self,
143
+ file_like,
144
+ format: str,
145
+ *,
146
+ codec: str | None = None,
147
+ pixel_format: str | None = None,
148
+ crf: int | float | None = None,
149
+ preset: str | int | None = None,
150
+ extra_options: dict[str, Any] | None = None,
151
+ ) -> None:
152
+ """Encode frames into a file-like object.
153
+
154
+ Args:
155
+ file_like: A file-like object that supports ``write()`` and
156
+ ``seek()`` methods, such as io.BytesIO(), an open file in binary
157
+ write mode, etc. Methods must have the following signature:
158
+ ``write(data: bytes) -> int`` and ``seek(offset: int, whence:
159
+ int = 0) -> int``.
160
+ format (str): The container format of the encoded frames, e.g. "mp4", "mov",
161
+ "mkv", "avi", "webm", "flv", etc.
162
+ codec (str, optional): The codec to use for encoding (e.g., "libx264",
163
+ "h264"). If not specified, the default codec
164
+ for the container format will be used.
165
+ See :ref:`codec_selection` for details.
166
+ pixel_format (str, optional): The pixel format for encoding (e.g.,
167
+ "yuv420p", "yuv444p"). If not specified, uses codec's default format.
168
+ Must be left as ``None`` when encoding CUDA tensors.
169
+ See :ref:`pixel_format` for details.
170
+ crf (int or float, optional): Constant Rate Factor for encoding quality. Lower values
171
+ mean better quality. Valid range depends on the encoder (e.g. 0-51 for libx264).
172
+ Defaults to None (which will use encoder's default).
173
+ See :ref:`crf` for details.
174
+ preset (str or int, optional): Encoder option that controls the tradeoff between
175
+ encoding encoding speed and compression (output size). Valid on the encoder (commonly
176
+ a string: "fast", "medium", "slow"). Defaults to None
177
+ (which will use encoder's default).
178
+ See :ref:`preset` for details.
179
+ extra_options (dict[str, Any], optional): A dictionary of additional
180
+ encoder options to pass, e.g. ``{"qp": 5, "tune": "film"}``.
181
+ See :ref:`extra_options` for details.
182
+ """
183
+ preset = str(preset) if isinstance(preset, int) else preset
184
+ _core.encode_video_to_file_like(
185
+ frames=self._frames,
186
+ frame_rate=self._frame_rate,
187
+ format=format,
188
+ file_like=file_like,
189
+ codec=codec,
190
+ pixel_format=pixel_format,
191
+ crf=crf,
192
+ preset=preset,
193
+ extra_options=[
194
+ str(x) for k, v in (extra_options or {}).items() for x in (k, v)
195
+ ],
196
+ )
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,2 @@
1
+ from ._index_based import clips_at_random_indices, clips_at_regular_indices
2
+ from ._time_based import clips_at_random_timestamps, clips_at_regular_timestamps
@@ -0,0 +1,84 @@
1
+ from collections.abc import Callable
2
+
3
+ from torchcodec import FrameBatch
4
+
5
+ _LIST_OF_INT_OR_FLOAT = list[int] | list[float]
6
+
7
+
8
+ def _repeat_last_policy(
9
+ values: _LIST_OF_INT_OR_FLOAT, desired_len: int
10
+ ) -> _LIST_OF_INT_OR_FLOAT:
11
+ # values = [1, 2, 3], desired_len = 5
12
+ # output = [1, 2, 3, 3, 3]
13
+ values += [values[-1]] * (desired_len - len(values))
14
+ return values
15
+
16
+
17
+ def _wrap_policy(
18
+ values: _LIST_OF_INT_OR_FLOAT, desired_len: int
19
+ ) -> _LIST_OF_INT_OR_FLOAT:
20
+ # values = [1, 2, 3], desired_len = 5
21
+ # output = [1, 2, 3, 1, 2]
22
+ return (values * (desired_len // len(values) + 1))[:desired_len]
23
+
24
+
25
+ def _error_policy(
26
+ frames_indices: _LIST_OF_INT_OR_FLOAT, desired_len: int
27
+ ) -> _LIST_OF_INT_OR_FLOAT:
28
+ raise ValueError(
29
+ "You set the 'error' policy, and the sampler tried to decode a frame "
30
+ "that is beyond the number of frames in the video. "
31
+ "Try to leave sampling_range_end to its default value?"
32
+ )
33
+
34
+
35
+ _POLICY_FUNCTION_TYPE = Callable[[_LIST_OF_INT_OR_FLOAT, int], _LIST_OF_INT_OR_FLOAT]
36
+
37
+ _POLICY_FUNCTIONS: dict[str, _POLICY_FUNCTION_TYPE] = {
38
+ "repeat_last": _repeat_last_policy,
39
+ "wrap": _wrap_policy,
40
+ "error": _error_policy,
41
+ }
42
+
43
+
44
+ def _validate_common_params(*, decoder, num_frames_per_clip, policy):
45
+ if len(decoder) < 1:
46
+ raise ValueError(
47
+ f"Decoder must have at least one frame, found {len(decoder)} frames."
48
+ )
49
+
50
+ if num_frames_per_clip <= 0:
51
+ raise ValueError(
52
+ f"num_frames_per_clip ({num_frames_per_clip}) must be strictly positive"
53
+ )
54
+ if policy not in _POLICY_FUNCTIONS.keys():
55
+ raise ValueError(
56
+ f"Invalid policy ({policy}). Supported values are {_POLICY_FUNCTIONS.keys()}."
57
+ )
58
+
59
+
60
+ def _reshape_4d_framebatch_into_5d(
61
+ *,
62
+ frames: FrameBatch,
63
+ num_clips: int,
64
+ num_frames_per_clip: int,
65
+ ) -> FrameBatch:
66
+ last_3_dims = frames.data.shape[-3:]
67
+ return FrameBatch(
68
+ data=frames.data.view(num_clips, num_frames_per_clip, *last_3_dims),
69
+ pts_seconds=frames.pts_seconds.view(num_clips, num_frames_per_clip),
70
+ duration_seconds=frames.duration_seconds.view(num_clips, num_frames_per_clip),
71
+ )
72
+
73
+
74
+ _FRAMEBATCH_RETURN_DOCS = """
75
+ Returns:
76
+ FrameBatch:
77
+ The sampled :term:`clips`, as a 5D :class:`~torchcodec.FrameBatch`.
78
+ The shape of the ``data`` field is (``num_clips``,
79
+ ``num_frames_per_clips``, ...) where ... is (H, W, C) or (C, H, W)
80
+ depending on the ``dimension_order`` parameter of
81
+ :class:`~torchcodec.decoders.VideoDecoder`. The shape of the
82
+ ``pts_seconds`` and ``duration_seconds`` fields is (``num_clips``,
83
+ ``num_frames_per_clips``).
84
+ """