From 484e2c8b3e58d4732489f1d9bbb2ff1d93f3d48d Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Wed, 23 Apr 2025 14:32:20 +0100 Subject: [PATCH 1/2] Final doc touches before release (#650) --- README.md | 8 ++--- docs/source/conf.py | 31 +++++++++++++++++ docs/source/index.rst | 30 +++++++++++++---- examples/basic_example.py | 10 ++++++ src/torchcodec/decoders/_video_decoder.py | 41 +++++++++++++++-------- 5 files changed, 95 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 1fb40a13..0783e513 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ # TorchCodec -TorchCodec is a Python library for decoding videos into PyTorch tensors, on CPU -and CUDA GPU. It aims to be fast, easy to use, and well integrated into the -PyTorch ecosystem. If you want to use PyTorch to train ML models on videos, -TorchCodec is how you turn those videos into data. +TorchCodec is a Python library for decoding video and audio data into PyTorch +tensors, on CPU and CUDA GPU. It aims to be fast, easy to use, and well +integrated into the PyTorch ecosystem. If you want to use PyTorch to train ML +models on videos and audio, TorchCodec is how you turn these into data. We achieve these capabilities through: diff --git a/docs/source/conf.py b/docs/source/conf.py index 39c41ad5..b9d3eb58 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -57,6 +57,36 @@ "sphinx_copybutton", ] + +class CustomGalleryExampleSortKey: + # This class defines the order in which our examples appear in + # https://pytorch.org/torchcodec/stable/generated_examples/index.html + # They would otherwise be sorted alphabetically. + # + # See https://sphinx-gallery.github.io/stable/configuration.html#sorting-gallery-examples + # and https://github.com/sphinx-gallery/sphinx-gallery/blob/master/sphinx_gallery/sorting.py + def __init__(self, src_dir): + self.src_dir = src_dir + + order = [ + "basic_example.py", + "audio_decoding.py", + "basic_cuda_example.py", + "file_like.py", + "approximate_mode.py", + "sampling.py", + ] + + def __call__(self, filename): + try: + return self.order.index(filename) + except ValueError as e: + raise ValueError( + "Looks like you added an example in the examples/ folder?" + "You need to specify its order in docs/source/conf.py. Look for CustomGalleryExampleSortKey." + ) from e + + sphinx_gallery_conf = { "examples_dirs": "../../examples/", # path to your example scripts "gallery_dirs": "generated_examples", # path to where to save gallery generated output @@ -64,6 +94,7 @@ "backreferences_dir": "gen_modules/backreferences", "doc_module": ("torchcodec",), "remove_config_comments": True, + "within_subsection_order": CustomGalleryExampleSortKey, } # We override sphinx-gallery's example header to prevent sphinx-gallery from diff --git a/docs/source/index.rst b/docs/source/index.rst index bbc8bfa7..ed88af40 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,10 +1,10 @@ Welcome to the TorchCodec documentation! ======================================== -TorchCodec is a Python library for decoding videos into PyTorch tensors, on CPU -and CUDA GPU. It aims to be fast, easy to use, and well integrated into the -PyTorch ecosystem. If you want to use PyTorch to train ML models on videos, -TorchCodec is how you turn those videos into data. +TorchCodec is a Python library for decoding video and audio data into PyTorch +tensors, on CPU and CUDA GPU. It aims to be fast, easy to use, and well +integrated into the PyTorch ecosystem. If you want to use PyTorch to train ML +models on videos and audio, TorchCodec is how you turn these into data. We achieve these capabilities through: @@ -36,12 +36,12 @@ We achieve these capabilities through: A simple video decoding example .. grid-item-card:: :octicon:`file-code;1em` - Clip sampling + Audio Decoding :img-top: _static/img/card-background.svg - :link: generated_examples/sampling.html + :link: generated_examples/audio_decoding.html :link-type: url - How to sample regular and random clips from a video + A simple audio decoding example .. grid-item-card:: :octicon:`file-code;1em` GPU decoding @@ -51,6 +51,22 @@ We achieve these capabilities through: A simple example demonstrating CUDA GPU decoding + .. grid-item-card:: :octicon:`file-code;1em` + Streaming video + :img-top: _static/img/card-background.svg + :link: generated_examples/file_like.html + :link-type: url + + How to efficiently decode videos from the cloud + + .. grid-item-card:: :octicon:`file-code;1em` + Clip sampling + :img-top: _static/img/card-background.svg + :link: generated_examples/sampling.html + :link-type: url + + How to sample regular and random clips from a video + .. note:: TorchCodec is still in development stage and we are actively seeking diff --git a/examples/basic_example.py b/examples/basic_example.py index 01c26d44..1b2590c9 100644 --- a/examples/basic_example.py +++ b/examples/basic_example.py @@ -93,6 +93,16 @@ def plot(frames: torch.Tensor, title : Optional[str] = None): # :class:`~torchcodec.decoders.VideoDecoder`. Frames are always of # ``torch.uint8`` dtype. # +# .. note:: +# +# If you need to decode multiple frames, we recommend using the batch +# methods instead, since they are faster: +# :meth:`~torchcodec.decoders.VideoDecoder.get_frames_at`, +# :meth:`~torchcodec.decoders.VideoDecoder.get_frames_in_range`, +# :meth:`~torchcodec.decoders.VideoDecoder.get_frames_played_at`, and +# :meth:`~torchcodec.decoders.VideoDecoder.get_frames_played_in_range`. They +# are described below. + plot(first_frame, "First frame") diff --git a/src/torchcodec/decoders/_video_decoder.py b/src/torchcodec/decoders/_video_decoder.py index b672cc09..fff0fe9f 100644 --- a/src/torchcodec/decoders/_video_decoder.py +++ b/src/torchcodec/decoders/_video_decoder.py @@ -150,6 +150,15 @@ def _getitem_slice(self, key: slice) -> Tensor: def __getitem__(self, key: Union[numbers.Integral, slice]) -> Tensor: """Return frame or frames as tensors, at the given index or range. + .. note:: + + If you need to decode multiple frames, we recommend using the batch + methods instead, since they are faster: + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_at`, + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_in_range`, + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_played_at`, and + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_played_in_range`. + Args: key(int or slice): The index or range of frame(s) to retrieve. @@ -171,6 +180,15 @@ def _get_key_frame_indices(self) -> list[int]: def get_frame_at(self, index: int) -> Frame: """Return a single frame at the given index. + .. note:: + + If you need to decode multiple frames, we recommend using the batch + methods instead, since they are faster: + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_at`, + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_in_range`, + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_played_at`, + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_played_in_range`. + Args: index (int): The index of the frame to retrieve. @@ -194,13 +212,6 @@ def get_frame_at(self, index: int) -> Frame: def get_frames_at(self, indices: list[int]) -> FrameBatch: """Return frames at the given indices. - .. note:: - - Calling this method is more efficient that repeated individual calls - to :meth:`~torchcodec.decoders.VideoDecoder.get_frame_at`. This - method makes sure not to decode the same frame twice, and also - avoids "backwards seek" operations, which are slow. - Args: indices (list of int): The indices of the frames to retrieve. @@ -252,6 +263,15 @@ def get_frames_in_range(self, start: int, stop: int, step: int = 1) -> FrameBatc def get_frame_played_at(self, seconds: float) -> Frame: """Return a single frame played at the given timestamp in seconds. + .. note:: + + If you need to decode multiple frames, we recommend using the batch + methods instead, since they are faster: + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_at`, + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_in_range`, + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_played_at`, + :meth:`~torchcodec.decoders.VideoDecoder.get_frames_played_in_range`. + Args: seconds (float): The time stamp in seconds when the frame is played. @@ -276,13 +296,6 @@ def get_frame_played_at(self, seconds: float) -> Frame: def get_frames_played_at(self, seconds: list[float]) -> FrameBatch: """Return frames played at the given timestamps in seconds. - .. note:: - - Calling this method is more efficient that repeated individual calls - to :meth:`~torchcodec.decoders.VideoDecoder.get_frame_played_at`. - This method makes sure not to decode the same frame twice, and also - avoids "backwards seek" operations, which are slow. - Args: seconds (list of float): The timestamps in seconds when the frames are played. From b3725a7b227ea1769a58c74c92c6c6a571c68b34 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Thu, 24 Apr 2025 09:16:22 +0100 Subject: [PATCH 2/2] Release 0.3.0 (#651) --- .github/workflows/build_ffmpeg.yaml | 4 ++-- .github/workflows/docs.yaml | 12 ++++++------ .github/workflows/linux_cuda_wheel.yaml | 16 ++++++++-------- .github/workflows/linux_wheel.yaml | 12 ++++++------ .github/workflows/macos_wheel.yaml | 12 ++++++------ setup.py | 2 ++ version.txt | 2 +- 7 files changed, 31 insertions(+), 29 deletions(-) diff --git a/.github/workflows/build_ffmpeg.yaml b/.github/workflows/build_ffmpeg.yaml index a2114519..c859d61b 100644 --- a/.github/workflows/build_ffmpeg.yaml +++ b/.github/workflows/build_ffmpeg.yaml @@ -28,7 +28,7 @@ jobs: fail-fast: false matrix: ffmpeg-version: ["4.4.4", "5.1.4", "6.1.1", "7.0.1"] - uses: pytorch/test-infra/.github/workflows/linux_job_v2.yml@main + uses: pytorch/test-infra/.github/workflows/linux_job_v2.yml@release/2.7 permissions: id-token: write contents: read @@ -53,7 +53,7 @@ jobs: fail-fast: false matrix: ffmpeg-version: ["4.4.4", "5.1.4", "6.1.1", "7.0.1"] - uses: pytorch/test-infra/.github/workflows/macos_job.yml@main + uses: pytorch/test-infra/.github/workflows/macos_job.yml@release/2.7 with: job-name: Build upload-artifact: ffmpeg-lgpl-macos-${{ matrix.ffmpeg-version }} diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 60bfbfa2..d938da5a 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -15,12 +15,12 @@ defaults: jobs: generate-matrix: - uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@main + uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@release/2.7 with: package-type: wheel os: linux test-infra-repository: pytorch/test-infra - test-infra-ref: main + test-infra-ref: release/2.7 with-cpu: disable with-xpu: disable with-rocm: disable @@ -31,12 +31,12 @@ jobs: strategy: fail-fast: false name: Build and Upload wheel - uses: pytorch/test-infra/.github/workflows/build_wheels_linux.yml@main + uses: pytorch/test-infra/.github/workflows/build_wheels_linux.yml@release/2.7 with: repository: pytorch/torchcodec ref: "" test-infra-repository: pytorch/test-infra - test-infra-ref: main + test-infra-ref: release/2.7 build-matrix: ${{ needs.generate-matrix.outputs.matrix }} pre-script: packaging/pre_build_script.sh post-script: packaging/post_build_script.sh @@ -73,7 +73,7 @@ jobs: name: pytorch_torchcodec__${{ matrix.python-version }}_cu${{ env.cuda_version_without_periods }}_x86_64 path: pytorch/torchcodec/dist/ - name: Setup miniconda using test-infra - uses: pytorch/test-infra/.github/actions/setup-miniconda@main + uses: pytorch/test-infra/.github/actions/setup-miniconda@release/2.7 with: python-version: ${{ matrix.python-version }} # We install conda packages at the start because otherwise conda may have conflicts with dependencies. @@ -91,7 +91,7 @@ jobs: run: ${CONDA_RUN} python -m pip install --upgrade pip - name: Install PyTorch run: | - ${CONDA_RUN} python -m pip install --pre torch torchvision --index-url https://download.pytorch.org/whl/nightly/cu${{ env.cuda_version_without_periods }} + ${CONDA_RUN} python -m pip install torch torchvision --index-url https://download.pytorch.org/whl/cu${{ env.cuda_version_without_periods }} ${CONDA_RUN} python -c 'import torch; print(f"{torch.__version__}"); print(f"{torch.__file__}"); print(f"{torch.cuda.is_available()=}")' - name: Install torchcodec from the wheel run: | diff --git a/.github/workflows/linux_cuda_wheel.yaml b/.github/workflows/linux_cuda_wheel.yaml index a3abf1c5..94e5e37d 100644 --- a/.github/workflows/linux_cuda_wheel.yaml +++ b/.github/workflows/linux_cuda_wheel.yaml @@ -25,12 +25,12 @@ defaults: jobs: generate-matrix: - uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@main + uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@release/2.7 with: package-type: wheel os: linux test-infra-repository: pytorch/test-infra - test-infra-ref: main + test-infra-ref: release/2.7 with-cpu: disable with-xpu: disable with-rocm: disable @@ -41,12 +41,12 @@ jobs: strategy: fail-fast: false name: Build and Upload wheel - uses: pytorch/test-infra/.github/workflows/build_wheels_linux.yml@main + uses: pytorch/test-infra/.github/workflows/build_wheels_linux.yml@release/2.7 with: repository: pytorch/torchcodec ref: "" test-infra-repository: pytorch/test-infra - test-infra-ref: main + test-infra-ref: release/2.7 build-matrix: ${{ needs.generate-matrix.outputs.matrix }} pre-script: packaging/pre_build_script.sh post-script: packaging/post_build_script.sh @@ -66,10 +66,10 @@ jobs: # PR. # For the actual release we should add that label and change this to # include more python versions. - python-version: ['3.9'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] cuda-version: ['11.8', '12.6', '12.8'] # TODO: put back ffmpeg 5 https://github.com/pytorch/torchcodec/issues/325 - ffmpeg-version-for-tests: ['4.4.2', '6', '7'] + ffmpeg-version-for-tests: ['4.4.2', '5', '6', '7'] container: image: "pytorch/manylinux2_28-builder:cuda${{ matrix.cuda-version }}" @@ -87,7 +87,7 @@ jobs: name: pytorch_torchcodec__${{ matrix.python-version }}_cu${{ env.cuda_version_without_periods }}_x86_64 path: pytorch/torchcodec/dist/ - name: Setup miniconda using test-infra - uses: pytorch/test-infra/.github/actions/setup-miniconda@main + uses: pytorch/test-infra/.github/actions/setup-miniconda@release/2.7 with: python-version: ${{ matrix.python-version }} # We install conda packages at the start because otherwise conda may have conflicts with dependencies. @@ -105,7 +105,7 @@ jobs: run: ${CONDA_RUN} python -m pip install --upgrade pip - name: Install PyTorch run: | - ${CONDA_RUN} python -m pip install --pre torch torchvision --index-url https://download.pytorch.org/whl/nightly/cu${{ env.cuda_version_without_periods }} + ${CONDA_RUN} python -m pip install torch torchvision --index-url https://download.pytorch.org/whl/cu${{ env.cuda_version_without_periods }} ${CONDA_RUN} python -c 'import torch; print(f"{torch.__version__}"); print(f"{torch.__file__}"); print(f"{torch.cuda.is_available()=}")' - name: Install torchcodec from the wheel run: | diff --git a/.github/workflows/linux_wheel.yaml b/.github/workflows/linux_wheel.yaml index 1855e904..051c7c20 100644 --- a/.github/workflows/linux_wheel.yaml +++ b/.github/workflows/linux_wheel.yaml @@ -26,12 +26,12 @@ defaults: jobs: generate-matrix: - uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@main + uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@release/2.7 with: package-type: wheel os: linux test-infra-repository: pytorch/test-infra - test-infra-ref: main + test-infra-ref: release/2.7 with-xpu: disable with-rocm: disable with-cuda: disable @@ -42,12 +42,12 @@ jobs: strategy: fail-fast: false name: Build and Upload Linux wheel - uses: pytorch/test-infra/.github/workflows/build_wheels_linux.yml@main + uses: pytorch/test-infra/.github/workflows/build_wheels_linux.yml@release/2.7 with: repository: pytorch/torchcodec ref: "" test-infra-repository: pytorch/test-infra - test-infra-ref: main + test-infra-ref: release/2.7 build-matrix: ${{ needs.generate-matrix.outputs.matrix }} pre-script: packaging/pre_build_script.sh post-script: packaging/post_build_script.sh @@ -62,7 +62,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] ffmpeg-version-for-tests: ['4.4.2', '5.1.2', '6.1.1', '7.0.1'] needs: build steps: @@ -81,7 +81,7 @@ jobs: run: python -m pip install --upgrade pip - name: Install PyTorch run: | - python -m pip install --pre torch --index-url https://download.pytorch.org/whl/nightly/cpu + python -m pip install torch --index-url https://download.pytorch.org/whl/cpu - name: Install torchcodec from the wheel run: | wheel_path=`find pytorch/torchcodec/dist -type f -name "*.whl"` diff --git a/.github/workflows/macos_wheel.yaml b/.github/workflows/macos_wheel.yaml index ee436b7a..50626067 100644 --- a/.github/workflows/macos_wheel.yaml +++ b/.github/workflows/macos_wheel.yaml @@ -26,12 +26,12 @@ defaults: jobs: generate-matrix: - uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@main + uses: pytorch/test-infra/.github/workflows/generate_binary_build_matrix.yml@release/2.7 with: package-type: wheel os: macos-arm64 test-infra-repository: pytorch/test-infra - test-infra-ref: main + test-infra-ref: release/2.7 with-xpu: disable with-rocm: disable with-cuda: disable @@ -42,12 +42,12 @@ jobs: strategy: fail-fast: false name: Build and Upload Mac wheel - uses: pytorch/test-infra/.github/workflows/build_wheels_macos.yml@main + uses: pytorch/test-infra/.github/workflows/build_wheels_macos.yml@release/2.7 with: repository: pytorch/torchcodec ref: "" test-infra-repository: pytorch/test-infra - test-infra-ref: main + test-infra-ref: release/2.7 build-matrix: ${{ needs.generate-matrix.outputs.matrix }} pre-script: packaging/pre_build_script.sh post-script: packaging/post_build_script.sh @@ -63,7 +63,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.9'] + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] ffmpeg-version-for-tests: ['4.4.2', '5.1.2', '6.1.1', '7.0.1'] needs: build steps: @@ -85,7 +85,7 @@ jobs: - name: Install PyTorch run: | - python -m pip install --pre torch --index-url https://download.pytorch.org/whl/nightly/cpu + python -m pip install torch --index-url https://download.pytorch.org/whl/cpu - name: Install torchcodec from the wheel run: | diff --git a/setup.py b/setup.py index f1652176..a2742510 100644 --- a/setup.py +++ b/setup.py @@ -184,12 +184,14 @@ def _write_version_files(): # the content of `version.txt` plus some suffix like "+cpu" or "+cu112". # See # https://github.com/pytorch/test-infra/blob/61e6da7a6557152eb9879e461a26ad667c15f0fd/tools/pkg-helpers/pytorch_pkg_helpers/version.py#L113 + version = version.replace("+cpu", "") with open(_ROOT_DIR / "version.txt", "w") as f: f.write(f"{version}") else: with open(_ROOT_DIR / "version.txt") as f: version = f.readline().strip() try: + version = version.replace("+cpu", "") sha = ( subprocess.check_output( ["git", "rev-parse", "HEAD"], cwd=str(_ROOT_DIR) diff --git a/version.txt b/version.txt index c181bf59..0d91a54c 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.3.0a0 +0.3.0