We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Video dataset can't instantiate correctly on windows.
When I use the UCF101 class to instantiate the ucf-101 dataset, I get an error, the platform is Windows10,and the code is
 `ucf101_train = UCF101(root="./Datasets/UCF-101", annotation_path="./Datasets/UCF101TrainTestSplits-RecognitionTask/ucfTrainTestlist", frames_per_clip=16, train=True)`
return 
`AttributeError: Can't pickle local object 'VideoClips._compute_frame_pts.<locals>.DS'`
Looking forward to someone who can help solve this problem.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `torchvision/datasets/video_utils.py`
Content:
```
1 import bisect
2 from fractions import Fraction
3 import math
4 import torch
5 from torchvision.io import (
6     _read_video_timestamps_from_file,
7     _read_video_from_file,
8     _probe_video_from_file
9 )
10 from torchvision.io import read_video_timestamps, read_video
11 
12 from .utils import tqdm
13 
14 
15 def pts_convert(pts, timebase_from, timebase_to, round_func=math.floor):
16     """convert pts between different time bases
17     Args:
18         pts: presentation timestamp, float
19         timebase_from: original timebase. Fraction
20         timebase_to: new timebase. Fraction
21         round_func: rounding function.
22     """
23     new_pts = Fraction(pts, 1) * timebase_from / timebase_to
24     return round_func(new_pts)
25 
26 
27 def unfold(tensor, size, step, dilation=1):
28     """
29     similar to tensor.unfold, but with the dilation
30     and specialized for 1d tensors
31 
32     Returns all consecutive windows of `size` elements, with
33     `step` between windows. The distance between each element
34     in a window is given by `dilation`.
35     """
36     assert tensor.dim() == 1
37     o_stride = tensor.stride(0)
38     numel = tensor.numel()
39     new_stride = (step * o_stride, dilation * o_stride)
40     new_size = ((numel - (dilation * (size - 1) + 1)) // step + 1, size)
41     if new_size[0] < 1:
42         new_size = (0, size)
43     return torch.as_strided(tensor, new_size, new_stride)
44 
45 
46 class VideoClips(object):
47     """
48     Given a list of video files, computes all consecutive subvideos of size
49     `clip_length_in_frames`, where the distance between each subvideo in the
50     same video is defined by `frames_between_clips`.
51     If `frame_rate` is specified, it will also resample all the videos to have
52     the same frame rate, and the clips will refer to this frame rate.
53 
54     Creating this instance the first time is time-consuming, as it needs to
55     decode all the videos in `video_paths`. It is recommended that you
56     cache the results after instantiation of the class.
57 
58     Recreating the clips for different clip lengths is fast, and can be done
59     with the `compute_clips` method.
60 
61     Arguments:
62         video_paths (List[str]): paths to the video files
63         clip_length_in_frames (int): size of a clip in number of frames
64         frames_between_clips (int): step (in frames) between each clip
65         frame_rate (int, optional): if specified, it will resample the video
66             so that it has `frame_rate`, and then the clips will be defined
67             on the resampled video
68         num_workers (int): how many subprocesses to use for data loading.
69             0 means that the data will be loaded in the main process. (default: 0)
70     """
71     def __init__(self, video_paths, clip_length_in_frames=16, frames_between_clips=1,
72                  frame_rate=None, _precomputed_metadata=None, num_workers=0,
73                  _video_width=0, _video_height=0, _video_min_dimension=0,
74                  _audio_samples=0, _audio_channels=0):
75 
76         self.video_paths = video_paths
77         self.num_workers = num_workers
78 
79         # these options are not valid for pyav backend
80         self._video_width = _video_width
81         self._video_height = _video_height
82         self._video_min_dimension = _video_min_dimension
83         self._audio_samples = _audio_samples
84         self._audio_channels = _audio_channels
85 
86         if _precomputed_metadata is None:
87             self._compute_frame_pts()
88         else:
89             self._init_from_metadata(_precomputed_metadata)
90         self.compute_clips(clip_length_in_frames, frames_between_clips, frame_rate)
91 
92     def _compute_frame_pts(self):
93         self.video_pts = []
94         self.video_fps = []
95 
96         # strategy: use a DataLoader to parallelize read_video_timestamps
97         # so need to create a dummy dataset first
98         class DS(object):
99             def __init__(self, x):
100                 self.x = x
101 
102             def __len__(self):
103                 return len(self.x)
104 
105             def __getitem__(self, idx):
106                 return read_video_timestamps(self.x[idx])
107 
108         import torch.utils.data
109         dl = torch.utils.data.DataLoader(
110             DS(self.video_paths),
111             batch_size=16,
112             num_workers=self.num_workers,
113             collate_fn=lambda x: x)
114 
115         with tqdm(total=len(dl)) as pbar:
116             for batch in dl:
117                 pbar.update(1)
118                 clips, fps = list(zip(*batch))
119                 clips = [torch.as_tensor(c) for c in clips]
120                 self.video_pts.extend(clips)
121                 self.video_fps.extend(fps)
122 
123     def _init_from_metadata(self, metadata):
124         self.video_paths = metadata["video_paths"]
125         assert len(self.video_paths) == len(metadata["video_pts"])
126         self.video_pts = metadata["video_pts"]
127         assert len(self.video_paths) == len(metadata["video_fps"])
128         self.video_fps = metadata["video_fps"]
129 
130     @property
131     def metadata(self):
132         _metadata = {
133             "video_paths": self.video_paths,
134             "video_pts": self.video_pts,
135             "video_fps": self.video_fps
136         }
137         return _metadata
138 
139     def subset(self, indices):
140         video_paths = [self.video_paths[i] for i in indices]
141         video_pts = [self.video_pts[i] for i in indices]
142         video_fps = [self.video_fps[i] for i in indices]
143         metadata = {
144             "video_paths": video_paths,
145             "video_pts": video_pts,
146             "video_fps": video_fps
147         }
148         return type(self)(video_paths, self.num_frames, self.step, self.frame_rate,
149                           _precomputed_metadata=metadata, num_workers=self.num_workers,
150                           _video_width=self._video_width,
151                           _video_height=self._video_height,
152                           _video_min_dimension=self._video_min_dimension,
153                           _audio_samples=self._audio_samples,
154                           _audio_channels=self._audio_channels)
155 
156     @staticmethod
157     def compute_clips_for_video(video_pts, num_frames, step, fps, frame_rate):
158         if fps is None:
159             # if for some reason the video doesn't have fps (because doesn't have a video stream)
160             # set the fps to 1. The value doesn't matter, because video_pts is empty anyway
161             fps = 1
162         if frame_rate is None:
163             frame_rate = fps
164         total_frames = len(video_pts) * (float(frame_rate) / fps)
165         idxs = VideoClips._resample_video_idx(int(math.floor(total_frames)), fps, frame_rate)
166         video_pts = video_pts[idxs]
167         clips = unfold(video_pts, num_frames, step)
168         if isinstance(idxs, slice):
169             idxs = [idxs] * len(clips)
170         else:
171             idxs = unfold(idxs, num_frames, step)
172         return clips, idxs
173 
174     def compute_clips(self, num_frames, step, frame_rate=None):
175         """
176         Compute all consecutive sequences of clips from video_pts.
177         Always returns clips of size `num_frames`, meaning that the
178         last few frames in a video can potentially be dropped.
179 
180         Arguments:
181             num_frames (int): number of frames for the clip
182             step (int): distance between two clips
183         """
184         self.num_frames = num_frames
185         self.step = step
186         self.frame_rate = frame_rate
187         self.clips = []
188         self.resampling_idxs = []
189         for video_pts, fps in zip(self.video_pts, self.video_fps):
190             clips, idxs = self.compute_clips_for_video(video_pts, num_frames, step, fps, frame_rate)
191             self.clips.append(clips)
192             self.resampling_idxs.append(idxs)
193         clip_lengths = torch.as_tensor([len(v) for v in self.clips])
194         self.cumulative_sizes = clip_lengths.cumsum(0).tolist()
195 
196     def __len__(self):
197         return self.num_clips()
198 
199     def num_videos(self):
200         return len(self.video_paths)
201 
202     def num_clips(self):
203         """
204         Number of subclips that are available in the video list.
205         """
206         return self.cumulative_sizes[-1]
207 
208     def get_clip_location(self, idx):
209         """
210         Converts a flattened representation of the indices into a video_idx, clip_idx
211         representation.
212         """
213         video_idx = bisect.bisect_right(self.cumulative_sizes, idx)
214         if video_idx == 0:
215             clip_idx = idx
216         else:
217             clip_idx = idx - self.cumulative_sizes[video_idx - 1]
218         return video_idx, clip_idx
219 
220     @staticmethod
221     def _resample_video_idx(num_frames, original_fps, new_fps):
222         step = float(original_fps) / new_fps
223         if step.is_integer():
224             # optimization: if step is integer, don't need to perform
225             # advanced indexing
226             step = int(step)
227             return slice(None, None, step)
228         idxs = torch.arange(num_frames, dtype=torch.float32) * step
229         idxs = idxs.floor().to(torch.int64)
230         return idxs
231 
232     def get_clip(self, idx):
233         """
234         Gets a subclip from a list of videos.
235 
236         Arguments:
237             idx (int): index of the subclip. Must be between 0 and num_clips().
238 
239         Returns:
240             video (Tensor)
241             audio (Tensor)
242             info (Dict)
243             video_idx (int): index of the video in `video_paths`
244         """
245         if idx >= self.num_clips():
246             raise IndexError("Index {} out of range "
247                              "({} number of clips)".format(idx, self.num_clips()))
248         video_idx, clip_idx = self.get_clip_location(idx)
249         video_path = self.video_paths[video_idx]
250         clip_pts = self.clips[video_idx][clip_idx]
251 
252         from torchvision import get_video_backend
253         backend = get_video_backend()
254 
255         if backend == "pyav":
256             # check for invalid options
257             if self._video_width != 0:
258                 raise ValueError("pyav backend doesn't support _video_width != 0")
259             if self._video_height != 0:
260                 raise ValueError("pyav backend doesn't support _video_height != 0")
261             if self._video_min_dimension != 0:
262                 raise ValueError("pyav backend doesn't support _video_min_dimension != 0")
263             if self._audio_samples != 0:
264                 raise ValueError("pyav backend doesn't support _audio_samples != 0")
265 
266         if backend == "pyav":
267             start_pts = clip_pts[0].item()
268             end_pts = clip_pts[-1].item()
269             video, audio, info = read_video(video_path, start_pts, end_pts)
270         else:
271             info = _probe_video_from_file(video_path)
272             video_fps = info["video_fps"]
273             audio_fps = None
274 
275             video_start_pts = clip_pts[0].item()
276             video_end_pts = clip_pts[-1].item()
277 
278             audio_start_pts, audio_end_pts = 0, -1
279             audio_timebase = Fraction(0, 1)
280             if "audio_timebase" in info:
281                 audio_timebase = info["audio_timebase"]
282                 audio_start_pts = pts_convert(
283                     video_start_pts,
284                     info["video_timebase"],
285                     info["audio_timebase"],
286                     math.floor,
287                 )
288                 audio_end_pts = pts_convert(
289                     video_end_pts,
290                     info["video_timebase"],
291                     info["audio_timebase"],
292                     math.ceil,
293                 )
294                 audio_fps = info["audio_sample_rate"]
295             video, audio, info = _read_video_from_file(
296                 video_path,
297                 video_width=self._video_width,
298                 video_height=self._video_height,
299                 video_min_dimension=self._video_min_dimension,
300                 video_pts_range=(video_start_pts, video_end_pts),
301                 video_timebase=info["video_timebase"],
302                 audio_samples=self._audio_samples,
303                 audio_channels=self._audio_channels,
304                 audio_pts_range=(audio_start_pts, audio_end_pts),
305                 audio_timebase=audio_timebase,
306             )
307 
308             info = {"video_fps": video_fps}
309             if audio_fps is not None:
310                 info["audio_fps"] = audio_fps
311 
312         if self.frame_rate is not None:
313             resampling_idx = self.resampling_idxs[video_idx][clip_idx]
314             if isinstance(resampling_idx, torch.Tensor):
315                 resampling_idx = resampling_idx - resampling_idx[0]
316             video = video[resampling_idx]
317             info["video_fps"] = self.frame_rate
318         assert len(video) == self.num_frames, "{} x {}".format(video.shape, self.num_frames)
319         return video, audio, info, video_idx
320
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/torchvision/datasets/video_utils.py b/torchvision/datasets/video_utils.py
--- a/torchvision/datasets/video_utils.py
+++ b/torchvision/datasets/video_utils.py
@@ -43,6 +43,21 @@
     return torch.as_strided(tensor, new_size, new_stride)
 
 
+class _DummyDataset(object):
+    """
+    Dummy dataset used for DataLoader in VideoClips.
+    Defined at top level so it can be pickled when forking.
+    """
+    def __init__(self, x):
+        self.x = x
+
+    def __len__(self):
+        return len(self.x)
+
+    def __getitem__(self, idx):
+        return read_video_timestamps(self.x[idx])
+
+
 class VideoClips(object):
     """
     Given a list of video files, computes all consecutive subvideos of size
@@ -95,19 +110,9 @@
 
         # strategy: use a DataLoader to parallelize read_video_timestamps
         # so need to create a dummy dataset first
-        class DS(object):
-            def __init__(self, x):
-                self.x = x
-
-            def __len__(self):
-                return len(self.x)
-
-            def __getitem__(self, idx):
-                return read_video_timestamps(self.x[idx])
-
         import torch.utils.data
         dl = torch.utils.data.DataLoader(
-            DS(self.video_paths),
+            _DummyDataset(self.video_paths),
             batch_size=16,
             num_workers=self.num_workers,
             collate_fn=lambda x: x)

{"golden_diff": "diff --git a/torchvision/datasets/video_utils.py b/torchvision/datasets/video_utils.py\n--- a/torchvision/datasets/video_utils.py\n+++ b/torchvision/datasets/video_utils.py\n@@ -43,6 +43,21 @@\n     return torch.as_strided(tensor, new_size, new_stride)\n \n \n+class _DummyDataset(object):\n+    \"\"\"\n+    Dummy dataset used for DataLoader in VideoClips.\n+    Defined at top level so it can be pickled when forking.\n+    \"\"\"\n+    def __init__(self, x):\n+        self.x = x\n+\n+    def __len__(self):\n+        return len(self.x)\n+\n+    def __getitem__(self, idx):\n+        return read_video_timestamps(self.x[idx])\n+\n+\n class VideoClips(object):\n     \"\"\"\n     Given a list of video files, computes all consecutive subvideos of size\n@@ -95,19 +110,9 @@\n \n         # strategy: use a DataLoader to parallelize read_video_timestamps\n         # so need to create a dummy dataset first\n-        class DS(object):\n-            def __init__(self, x):\n-                self.x = x\n-\n-            def __len__(self):\n-                return len(self.x)\n-\n-            def __getitem__(self, idx):\n-                return read_video_timestamps(self.x[idx])\n-\n         import torch.utils.data\n         dl = torch.utils.data.DataLoader(\n-            DS(self.video_paths),\n+            _DummyDataset(self.video_paths),\n             batch_size=16,\n             num_workers=self.num_workers,\n             collate_fn=lambda x: x)\n", "issue": "Video dataset can't instantiate correctly on windows.\nWhen I use the UCF101 class to instantiate the ucf-101 dataset, I get an error, the platform is Windows10,and the code is\r\n `ucf101_train = UCF101(root=\"./Datasets/UCF-101\", annotation_path=\"./Datasets/UCF101TrainTestSplits-RecognitionTask/ucfTrainTestlist\", frames_per_clip=16, train=True)`\r\nreturn \r\n`AttributeError: Can't pickle local object 'VideoClips._compute_frame_pts.<locals>.DS'`\r\nLooking forward to someone who can help solve this problem.\n", "before_files": [{"content": "import bisect\nfrom fractions import Fraction\nimport math\nimport torch\nfrom torchvision.io import (\n    _read_video_timestamps_from_file,\n    _read_video_from_file,\n    _probe_video_from_file\n)\nfrom torchvision.io import read_video_timestamps, read_video\n\nfrom .utils import tqdm\n\n\ndef pts_convert(pts, timebase_from, timebase_to, round_func=math.floor):\n    \"\"\"convert pts between different time bases\n    Args:\n        pts: presentation timestamp, float\n        timebase_from: original timebase. Fraction\n        timebase_to: new timebase. Fraction\n        round_func: rounding function.\n    \"\"\"\n    new_pts = Fraction(pts, 1) * timebase_from / timebase_to\n    return round_func(new_pts)\n\n\ndef unfold(tensor, size, step, dilation=1):\n    \"\"\"\n    similar to tensor.unfold, but with the dilation\n    and specialized for 1d tensors\n\n    Returns all consecutive windows of `size` elements, with\n    `step` between windows. The distance between each element\n    in a window is given by `dilation`.\n    \"\"\"\n    assert tensor.dim() == 1\n    o_stride = tensor.stride(0)\n    numel = tensor.numel()\n    new_stride = (step * o_stride, dilation * o_stride)\n    new_size = ((numel - (dilation * (size - 1) + 1)) // step + 1, size)\n    if new_size[0] < 1:\n        new_size = (0, size)\n    return torch.as_strided(tensor, new_size, new_stride)\n\n\nclass VideoClips(object):\n    \"\"\"\n    Given a list of video files, computes all consecutive subvideos of size\n    `clip_length_in_frames`, where the distance between each subvideo in the\n    same video is defined by `frames_between_clips`.\n    If `frame_rate` is specified, it will also resample all the videos to have\n    the same frame rate, and the clips will refer to this frame rate.\n\n    Creating this instance the first time is time-consuming, as it needs to\n    decode all the videos in `video_paths`. It is recommended that you\n    cache the results after instantiation of the class.\n\n    Recreating the clips for different clip lengths is fast, and can be done\n    with the `compute_clips` method.\n\n    Arguments:\n        video_paths (List[str]): paths to the video files\n        clip_length_in_frames (int): size of a clip in number of frames\n        frames_between_clips (int): step (in frames) between each clip\n        frame_rate (int, optional): if specified, it will resample the video\n            so that it has `frame_rate`, and then the clips will be defined\n            on the resampled video\n        num_workers (int): how many subprocesses to use for data loading.\n            0 means that the data will be loaded in the main process. (default: 0)\n    \"\"\"\n    def __init__(self, video_paths, clip_length_in_frames=16, frames_between_clips=1,\n                 frame_rate=None, _precomputed_metadata=None, num_workers=0,\n                 _video_width=0, _video_height=0, _video_min_dimension=0,\n                 _audio_samples=0, _audio_channels=0):\n\n        self.video_paths = video_paths\n        self.num_workers = num_workers\n\n        # these options are not valid for pyav backend\n        self._video_width = _video_width\n        self._video_height = _video_height\n        self._video_min_dimension = _video_min_dimension\n        self._audio_samples = _audio_samples\n        self._audio_channels = _audio_channels\n\n        if _precomputed_metadata is None:\n            self._compute_frame_pts()\n        else:\n            self._init_from_metadata(_precomputed_metadata)\n        self.compute_clips(clip_length_in_frames, frames_between_clips, frame_rate)\n\n    def _compute_frame_pts(self):\n        self.video_pts = []\n        self.video_fps = []\n\n        # strategy: use a DataLoader to parallelize read_video_timestamps\n        # so need to create a dummy dataset first\n        class DS(object):\n            def __init__(self, x):\n                self.x = x\n\n            def __len__(self):\n                return len(self.x)\n\n            def __getitem__(self, idx):\n                return read_video_timestamps(self.x[idx])\n\n        import torch.utils.data\n        dl = torch.utils.data.DataLoader(\n            DS(self.video_paths),\n            batch_size=16,\n            num_workers=self.num_workers,\n            collate_fn=lambda x: x)\n\n        with tqdm(total=len(dl)) as pbar:\n            for batch in dl:\n                pbar.update(1)\n                clips, fps = list(zip(*batch))\n                clips = [torch.as_tensor(c) for c in clips]\n                self.video_pts.extend(clips)\n                self.video_fps.extend(fps)\n\n    def _init_from_metadata(self, metadata):\n        self.video_paths = metadata[\"video_paths\"]\n        assert len(self.video_paths) == len(metadata[\"video_pts\"])\n        self.video_pts = metadata[\"video_pts\"]\n        assert len(self.video_paths) == len(metadata[\"video_fps\"])\n        self.video_fps = metadata[\"video_fps\"]\n\n    @property\n    def metadata(self):\n        _metadata = {\n            \"video_paths\": self.video_paths,\n            \"video_pts\": self.video_pts,\n            \"video_fps\": self.video_fps\n        }\n        return _metadata\n\n    def subset(self, indices):\n        video_paths = [self.video_paths[i] for i in indices]\n        video_pts = [self.video_pts[i] for i in indices]\n        video_fps = [self.video_fps[i] for i in indices]\n        metadata = {\n            \"video_paths\": video_paths,\n            \"video_pts\": video_pts,\n            \"video_fps\": video_fps\n        }\n        return type(self)(video_paths, self.num_frames, self.step, self.frame_rate,\n                          _precomputed_metadata=metadata, num_workers=self.num_workers,\n                          _video_width=self._video_width,\n                          _video_height=self._video_height,\n                          _video_min_dimension=self._video_min_dimension,\n                          _audio_samples=self._audio_samples,\n                          _audio_channels=self._audio_channels)\n\n    @staticmethod\n    def compute_clips_for_video(video_pts, num_frames, step, fps, frame_rate):\n        if fps is None:\n            # if for some reason the video doesn't have fps (because doesn't have a video stream)\n            # set the fps to 1. The value doesn't matter, because video_pts is empty anyway\n            fps = 1\n        if frame_rate is None:\n            frame_rate = fps\n        total_frames = len(video_pts) * (float(frame_rate) / fps)\n        idxs = VideoClips._resample_video_idx(int(math.floor(total_frames)), fps, frame_rate)\n        video_pts = video_pts[idxs]\n        clips = unfold(video_pts, num_frames, step)\n        if isinstance(idxs, slice):\n            idxs = [idxs] * len(clips)\n        else:\n            idxs = unfold(idxs, num_frames, step)\n        return clips, idxs\n\n    def compute_clips(self, num_frames, step, frame_rate=None):\n        \"\"\"\n        Compute all consecutive sequences of clips from video_pts.\n        Always returns clips of size `num_frames`, meaning that the\n        last few frames in a video can potentially be dropped.\n\n        Arguments:\n            num_frames (int): number of frames for the clip\n            step (int): distance between two clips\n        \"\"\"\n        self.num_frames = num_frames\n        self.step = step\n        self.frame_rate = frame_rate\n        self.clips = []\n        self.resampling_idxs = []\n        for video_pts, fps in zip(self.video_pts, self.video_fps):\n            clips, idxs = self.compute_clips_for_video(video_pts, num_frames, step, fps, frame_rate)\n            self.clips.append(clips)\n            self.resampling_idxs.append(idxs)\n        clip_lengths = torch.as_tensor([len(v) for v in self.clips])\n        self.cumulative_sizes = clip_lengths.cumsum(0).tolist()\n\n    def __len__(self):\n        return self.num_clips()\n\n    def num_videos(self):\n        return len(self.video_paths)\n\n    def num_clips(self):\n        \"\"\"\n        Number of subclips that are available in the video list.\n        \"\"\"\n        return self.cumulative_sizes[-1]\n\n    def get_clip_location(self, idx):\n        \"\"\"\n        Converts a flattened representation of the indices into a video_idx, clip_idx\n        representation.\n        \"\"\"\n        video_idx = bisect.bisect_right(self.cumulative_sizes, idx)\n        if video_idx == 0:\n            clip_idx = idx\n        else:\n            clip_idx = idx - self.cumulative_sizes[video_idx - 1]\n        return video_idx, clip_idx\n\n    @staticmethod\n    def _resample_video_idx(num_frames, original_fps, new_fps):\n        step = float(original_fps) / new_fps\n        if step.is_integer():\n            # optimization: if step is integer, don't need to perform\n            # advanced indexing\n            step = int(step)\n            return slice(None, None, step)\n        idxs = torch.arange(num_frames, dtype=torch.float32) * step\n        idxs = idxs.floor().to(torch.int64)\n        return idxs\n\n    def get_clip(self, idx):\n        \"\"\"\n        Gets a subclip from a list of videos.\n\n        Arguments:\n            idx (int): index of the subclip. Must be between 0 and num_clips().\n\n        Returns:\n            video (Tensor)\n            audio (Tensor)\n            info (Dict)\n            video_idx (int): index of the video in `video_paths`\n        \"\"\"\n        if idx >= self.num_clips():\n            raise IndexError(\"Index {} out of range \"\n                             \"({} number of clips)\".format(idx, self.num_clips()))\n        video_idx, clip_idx = self.get_clip_location(idx)\n        video_path = self.video_paths[video_idx]\n        clip_pts = self.clips[video_idx][clip_idx]\n\n        from torchvision import get_video_backend\n        backend = get_video_backend()\n\n        if backend == \"pyav\":\n            # check for invalid options\n            if self._video_width != 0:\n                raise ValueError(\"pyav backend doesn't support _video_width != 0\")\n            if self._video_height != 0:\n                raise ValueError(\"pyav backend doesn't support _video_height != 0\")\n            if self._video_min_dimension != 0:\n                raise ValueError(\"pyav backend doesn't support _video_min_dimension != 0\")\n            if self._audio_samples != 0:\n                raise ValueError(\"pyav backend doesn't support _audio_samples != 0\")\n\n        if backend == \"pyav\":\n            start_pts = clip_pts[0].item()\n            end_pts = clip_pts[-1].item()\n            video, audio, info = read_video(video_path, start_pts, end_pts)\n        else:\n            info = _probe_video_from_file(video_path)\n            video_fps = info[\"video_fps\"]\n            audio_fps = None\n\n            video_start_pts = clip_pts[0].item()\n            video_end_pts = clip_pts[-1].item()\n\n            audio_start_pts, audio_end_pts = 0, -1\n            audio_timebase = Fraction(0, 1)\n            if \"audio_timebase\" in info:\n                audio_timebase = info[\"audio_timebase\"]\n                audio_start_pts = pts_convert(\n                    video_start_pts,\n                    info[\"video_timebase\"],\n                    info[\"audio_timebase\"],\n                    math.floor,\n                )\n                audio_end_pts = pts_convert(\n                    video_end_pts,\n                    info[\"video_timebase\"],\n                    info[\"audio_timebase\"],\n                    math.ceil,\n                )\n                audio_fps = info[\"audio_sample_rate\"]\n            video, audio, info = _read_video_from_file(\n                video_path,\n                video_width=self._video_width,\n                video_height=self._video_height,\n                video_min_dimension=self._video_min_dimension,\n                video_pts_range=(video_start_pts, video_end_pts),\n                video_timebase=info[\"video_timebase\"],\n                audio_samples=self._audio_samples,\n                audio_channels=self._audio_channels,\n                audio_pts_range=(audio_start_pts, audio_end_pts),\n                audio_timebase=audio_timebase,\n            )\n\n            info = {\"video_fps\": video_fps}\n            if audio_fps is not None:\n                info[\"audio_fps\"] = audio_fps\n\n        if self.frame_rate is not None:\n            resampling_idx = self.resampling_idxs[video_idx][clip_idx]\n            if isinstance(resampling_idx, torch.Tensor):\n                resampling_idx = resampling_idx - resampling_idx[0]\n            video = video[resampling_idx]\n            info[\"video_fps\"] = self.frame_rate\n        assert len(video) == self.num_frames, \"{} x {}\".format(video.shape, self.num_frames)\n        return video, audio, info, video_idx\n", "path": "torchvision/datasets/video_utils.py"}], "after_files": [{"content": "import bisect\nfrom fractions import Fraction\nimport math\nimport torch\nfrom torchvision.io import (\n    _read_video_timestamps_from_file,\n    _read_video_from_file,\n    _probe_video_from_file\n)\nfrom torchvision.io import read_video_timestamps, read_video\n\nfrom .utils import tqdm\n\n\ndef pts_convert(pts, timebase_from, timebase_to, round_func=math.floor):\n    \"\"\"convert pts between different time bases\n    Args:\n        pts: presentation timestamp, float\n        timebase_from: original timebase. Fraction\n        timebase_to: new timebase. Fraction\n        round_func: rounding function.\n    \"\"\"\n    new_pts = Fraction(pts, 1) * timebase_from / timebase_to\n    return round_func(new_pts)\n\n\ndef unfold(tensor, size, step, dilation=1):\n    \"\"\"\n    similar to tensor.unfold, but with the dilation\n    and specialized for 1d tensors\n\n    Returns all consecutive windows of `size` elements, with\n    `step` between windows. The distance between each element\n    in a window is given by `dilation`.\n    \"\"\"\n    assert tensor.dim() == 1\n    o_stride = tensor.stride(0)\n    numel = tensor.numel()\n    new_stride = (step * o_stride, dilation * o_stride)\n    new_size = ((numel - (dilation * (size - 1) + 1)) // step + 1, size)\n    if new_size[0] < 1:\n        new_size = (0, size)\n    return torch.as_strided(tensor, new_size, new_stride)\n\n\nclass _DummyDataset(object):\n    \"\"\"\n    Dummy dataset used for DataLoader in VideoClips.\n    Defined at top level so it can be pickled when forking.\n    \"\"\"\n    def __init__(self, x):\n        self.x = x\n\n    def __len__(self):\n        return len(self.x)\n\n    def __getitem__(self, idx):\n        return read_video_timestamps(self.x[idx])\n\n\nclass VideoClips(object):\n    \"\"\"\n    Given a list of video files, computes all consecutive subvideos of size\n    `clip_length_in_frames`, where the distance between each subvideo in the\n    same video is defined by `frames_between_clips`.\n    If `frame_rate` is specified, it will also resample all the videos to have\n    the same frame rate, and the clips will refer to this frame rate.\n\n    Creating this instance the first time is time-consuming, as it needs to\n    decode all the videos in `video_paths`. It is recommended that you\n    cache the results after instantiation of the class.\n\n    Recreating the clips for different clip lengths is fast, and can be done\n    with the `compute_clips` method.\n\n    Arguments:\n        video_paths (List[str]): paths to the video files\n        clip_length_in_frames (int): size of a clip in number of frames\n        frames_between_clips (int): step (in frames) between each clip\n        frame_rate (int, optional): if specified, it will resample the video\n            so that it has `frame_rate`, and then the clips will be defined\n            on the resampled video\n        num_workers (int): how many subprocesses to use for data loading.\n            0 means that the data will be loaded in the main process. (default: 0)\n    \"\"\"\n    def __init__(self, video_paths, clip_length_in_frames=16, frames_between_clips=1,\n                 frame_rate=None, _precomputed_metadata=None, num_workers=0,\n                 _video_width=0, _video_height=0, _video_min_dimension=0,\n                 _audio_samples=0, _audio_channels=0):\n\n        self.video_paths = video_paths\n        self.num_workers = num_workers\n\n        # these options are not valid for pyav backend\n        self._video_width = _video_width\n        self._video_height = _video_height\n        self._video_min_dimension = _video_min_dimension\n        self._audio_samples = _audio_samples\n        self._audio_channels = _audio_channels\n\n        if _precomputed_metadata is None:\n            self._compute_frame_pts()\n        else:\n            self._init_from_metadata(_precomputed_metadata)\n        self.compute_clips(clip_length_in_frames, frames_between_clips, frame_rate)\n\n    def _compute_frame_pts(self):\n        self.video_pts = []\n        self.video_fps = []\n\n        # strategy: use a DataLoader to parallelize read_video_timestamps\n        # so need to create a dummy dataset first\n        import torch.utils.data\n        dl = torch.utils.data.DataLoader(\n            _DummyDataset(self.video_paths),\n            batch_size=16,\n            num_workers=self.num_workers,\n            collate_fn=lambda x: x)\n\n        with tqdm(total=len(dl)) as pbar:\n            for batch in dl:\n                pbar.update(1)\n                clips, fps = list(zip(*batch))\n                clips = [torch.as_tensor(c) for c in clips]\n                self.video_pts.extend(clips)\n                self.video_fps.extend(fps)\n\n    def _init_from_metadata(self, metadata):\n        self.video_paths = metadata[\"video_paths\"]\n        assert len(self.video_paths) == len(metadata[\"video_pts\"])\n        self.video_pts = metadata[\"video_pts\"]\n        assert len(self.video_paths) == len(metadata[\"video_fps\"])\n        self.video_fps = metadata[\"video_fps\"]\n\n    @property\n    def metadata(self):\n        _metadata = {\n            \"video_paths\": self.video_paths,\n            \"video_pts\": self.video_pts,\n            \"video_fps\": self.video_fps\n        }\n        return _metadata\n\n    def subset(self, indices):\n        video_paths = [self.video_paths[i] for i in indices]\n        video_pts = [self.video_pts[i] for i in indices]\n        video_fps = [self.video_fps[i] for i in indices]\n        metadata = {\n            \"video_paths\": video_paths,\n            \"video_pts\": video_pts,\n            \"video_fps\": video_fps\n        }\n        return type(self)(video_paths, self.num_frames, self.step, self.frame_rate,\n                          _precomputed_metadata=metadata, num_workers=self.num_workers,\n                          _video_width=self._video_width,\n                          _video_height=self._video_height,\n                          _video_min_dimension=self._video_min_dimension,\n                          _audio_samples=self._audio_samples,\n                          _audio_channels=self._audio_channels)\n\n    @staticmethod\n    def compute_clips_for_video(video_pts, num_frames, step, fps, frame_rate):\n        if fps is None:\n            # if for some reason the video doesn't have fps (because doesn't have a video stream)\n            # set the fps to 1. The value doesn't matter, because video_pts is empty anyway\n            fps = 1\n        if frame_rate is None:\n            frame_rate = fps\n        total_frames = len(video_pts) * (float(frame_rate) / fps)\n        idxs = VideoClips._resample_video_idx(int(math.floor(total_frames)), fps, frame_rate)\n        video_pts = video_pts[idxs]\n        clips = unfold(video_pts, num_frames, step)\n        if isinstance(idxs, slice):\n            idxs = [idxs] * len(clips)\n        else:\n            idxs = unfold(idxs, num_frames, step)\n        return clips, idxs\n\n    def compute_clips(self, num_frames, step, frame_rate=None):\n        \"\"\"\n        Compute all consecutive sequences of clips from video_pts.\n        Always returns clips of size `num_frames`, meaning that the\n        last few frames in a video can potentially be dropped.\n\n        Arguments:\n            num_frames (int): number of frames for the clip\n            step (int): distance between two clips\n        \"\"\"\n        self.num_frames = num_frames\n        self.step = step\n        self.frame_rate = frame_rate\n        self.clips = []\n        self.resampling_idxs = []\n        for video_pts, fps in zip(self.video_pts, self.video_fps):\n            clips, idxs = self.compute_clips_for_video(video_pts, num_frames, step, fps, frame_rate)\n            self.clips.append(clips)\n            self.resampling_idxs.append(idxs)\n        clip_lengths = torch.as_tensor([len(v) for v in self.clips])\n        self.cumulative_sizes = clip_lengths.cumsum(0).tolist()\n\n    def __len__(self):\n        return self.num_clips()\n\n    def num_videos(self):\n        return len(self.video_paths)\n\n    def num_clips(self):\n        \"\"\"\n        Number of subclips that are available in the video list.\n        \"\"\"\n        return self.cumulative_sizes[-1]\n\n    def get_clip_location(self, idx):\n        \"\"\"\n        Converts a flattened representation of the indices into a video_idx, clip_idx\n        representation.\n        \"\"\"\n        video_idx = bisect.bisect_right(self.cumulative_sizes, idx)\n        if video_idx == 0:\n            clip_idx = idx\n        else:\n            clip_idx = idx - self.cumulative_sizes[video_idx - 1]\n        return video_idx, clip_idx\n\n    @staticmethod\n    def _resample_video_idx(num_frames, original_fps, new_fps):\n        step = float(original_fps) / new_fps\n        if step.is_integer():\n            # optimization: if step is integer, don't need to perform\n            # advanced indexing\n            step = int(step)\n            return slice(None, None, step)\n        idxs = torch.arange(num_frames, dtype=torch.float32) * step\n        idxs = idxs.floor().to(torch.int64)\n        return idxs\n\n    def get_clip(self, idx):\n        \"\"\"\n        Gets a subclip from a list of videos.\n\n        Arguments:\n            idx (int): index of the subclip. Must be between 0 and num_clips().\n\n        Returns:\n            video (Tensor)\n            audio (Tensor)\n            info (Dict)\n            video_idx (int): index of the video in `video_paths`\n        \"\"\"\n        if idx >= self.num_clips():\n            raise IndexError(\"Index {} out of range \"\n                             \"({} number of clips)\".format(idx, self.num_clips()))\n        video_idx, clip_idx = self.get_clip_location(idx)\n        video_path = self.video_paths[video_idx]\n        clip_pts = self.clips[video_idx][clip_idx]\n\n        from torchvision import get_video_backend\n        backend = get_video_backend()\n\n        if backend == \"pyav\":\n            # check for invalid options\n            if self._video_width != 0:\n                raise ValueError(\"pyav backend doesn't support _video_width != 0\")\n            if self._video_height != 0:\n                raise ValueError(\"pyav backend doesn't support _video_height != 0\")\n            if self._video_min_dimension != 0:\n                raise ValueError(\"pyav backend doesn't support _video_min_dimension != 0\")\n            if self._audio_samples != 0:\n                raise ValueError(\"pyav backend doesn't support _audio_samples != 0\")\n\n        if backend == \"pyav\":\n            start_pts = clip_pts[0].item()\n            end_pts = clip_pts[-1].item()\n            video, audio, info = read_video(video_path, start_pts, end_pts)\n        else:\n            info = _probe_video_from_file(video_path)\n            video_fps = info[\"video_fps\"]\n            audio_fps = None\n\n            video_start_pts = clip_pts[0].item()\n            video_end_pts = clip_pts[-1].item()\n\n            audio_start_pts, audio_end_pts = 0, -1\n            audio_timebase = Fraction(0, 1)\n            if \"audio_timebase\" in info:\n                audio_timebase = info[\"audio_timebase\"]\n                audio_start_pts = pts_convert(\n                    video_start_pts,\n                    info[\"video_timebase\"],\n                    info[\"audio_timebase\"],\n                    math.floor,\n                )\n                audio_end_pts = pts_convert(\n                    video_end_pts,\n                    info[\"video_timebase\"],\n                    info[\"audio_timebase\"],\n                    math.ceil,\n                )\n                audio_fps = info[\"audio_sample_rate\"]\n            video, audio, info = _read_video_from_file(\n                video_path,\n                video_width=self._video_width,\n                video_height=self._video_height,\n                video_min_dimension=self._video_min_dimension,\n                video_pts_range=(video_start_pts, video_end_pts),\n                video_timebase=info[\"video_timebase\"],\n                audio_samples=self._audio_samples,\n                audio_channels=self._audio_channels,\n                audio_pts_range=(audio_start_pts, audio_end_pts),\n                audio_timebase=audio_timebase,\n            )\n\n            info = {\"video_fps\": video_fps}\n            if audio_fps is not None:\n                info[\"audio_fps\"] = audio_fps\n\n        if self.frame_rate is not None:\n            resampling_idx = self.resampling_idxs[video_idx][clip_idx]\n            if isinstance(resampling_idx, torch.Tensor):\n                resampling_idx = resampling_idx - resampling_idx[0]\n            video = video[resampling_idx]\n            info[\"video_fps\"] = self.frame_rate\n        assert len(video) == self.num_frames, \"{} x {}\".format(video.shape, self.num_frames)\n        return video, audio, info, video_idx\n", "path": "torchvision/datasets/video_utils.py"}]}