├── version.txt
├── examples
├── decoding
│ ├── README.rst
│ └── audio_decoding.py
├── encoding
│ ├── README.rst
│ └── audio_encoding.py
└── README.rst
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── documentation.yml
│ ├── feature-request.yml
│ └── bug-report.yml
└── workflows
│ ├── lint.yaml
│ ├── reference_resources.yaml
│ ├── cpp_tests.yaml
│ ├── build_ffmpeg.yaml
│ └── macos_wheel.yaml
├── test
├── resources
│ ├── nasa_13013.mp4.stream3.frame000180.pt
│ ├── testsrc2.mp4
│ ├── av1_video.mkv
│ ├── h265_video.mp4
│ ├── nasa_13013.mp4
│ ├── h264_10bits.mp4
│ ├── h265_10bits.mp4
│ ├── sine_mono_s16.wav
│ ├── sine_mono_s32.wav
│ ├── testsrc2_h265.mp4
│ ├── testsrc2_vp8.webm
│ ├── testsrc2_vp9.webm
│ ├── testsrc2_mpeg4.avi
│ ├── bt709_full_range.mp4
│ ├── sine_mono_s32_8000.wav
│ ├── nasa_13013.mp4.audio.mp3
│ ├── sine_mono_s32_44100.wav
│ ├── nasa_13013.mp4.audio_44100.mp3
│ ├── nasa_13013.mp4.time10.000000.pt
│ ├── nasa_13013.mp4.time12.979633.pt
│ ├── nasa_13013.mp4.time6.000000.pt
│ ├── nasa_13013.mp4.time6.100000.pt
│ ├── av1_video.mkv.stream0.frame000010.pt
│ ├── h265_video.mp4.stream0.frame000005.pt
│ ├── nasa_13013.mp4.stream0.frame000000.pt
│ ├── nasa_13013.mp4.stream0.frame000001.pt
│ ├── nasa_13013.mp4.stream0.frame000002.pt
│ ├── nasa_13013.mp4.stream0.frame000003.pt
│ ├── nasa_13013.mp4.stream0.frame000004.pt
│ ├── nasa_13013.mp4.stream0.frame000005.pt
│ ├── nasa_13013.mp4.stream0.frame000006.pt
│ ├── nasa_13013.mp4.stream0.frame000007.pt
│ ├── nasa_13013.mp4.stream0.frame000008.pt
│ ├── nasa_13013.mp4.stream0.frame000009.pt
│ ├── nasa_13013.mp4.stream0.frame000015.pt
│ ├── nasa_13013.mp4.stream0.frame000020.pt
│ ├── nasa_13013.mp4.stream0.frame000025.pt
│ ├── nasa_13013.mp4.stream0.frame000030.pt
│ ├── nasa_13013.mp4.stream0.frame000035.pt
│ ├── nasa_13013.mp4.stream3.frame000000.pt
│ ├── nasa_13013.mp4.stream3.frame000001.pt
│ ├── nasa_13013.mp4.stream3.frame000002.pt
│ ├── nasa_13013.mp4.stream3.frame000003.pt
│ ├── nasa_13013.mp4.stream3.frame000004.pt
│ ├── nasa_13013.mp4.stream3.frame000005.pt
│ ├── nasa_13013.mp4.stream3.frame000006.pt
│ ├── nasa_13013.mp4.stream3.frame000007.pt
│ ├── nasa_13013.mp4.stream3.frame000008.pt
│ ├── nasa_13013.mp4.stream3.frame000009.pt
│ ├── nasa_13013.mp4.stream3.frame000015.pt
│ ├── nasa_13013.mp4.stream3.frame000020.pt
│ ├── nasa_13013.mp4.stream3.frame000025.pt
│ ├── nasa_13013.mp4.stream3.frame000030.pt
│ ├── nasa_13013.mp4.stream3.frame000035.pt
│ ├── nasa_13013.mp4.stream3.frame000386.pt
│ ├── nasa_13013.mp4.stream3.frame000387.pt
│ ├── nasa_13013.mp4.stream3.frame000388.pt
│ ├── nasa_13013.mp4.stream3.frame000389.pt
│ ├── nasa_13013.mp4.stream4.all_frames.pt
│ ├── sine_mono_s16.wav.stream0.all_frames.pt
│ ├── sine_mono_s32.wav.stream0.all_frames.pt
│ ├── nasa_13013.mp4.audio.mp3.stream0.all_frames.pt
│ ├── nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000000.pt
│ ├── nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000015.pt
│ ├── nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000200.pt
│ ├── nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000389.pt
│ ├── nasa_13013.mp4.scale_240_135_flags_bilinear.stream3.frame000017.pt
│ ├── nasa_13013.mp4.scale_240_135_flags_bilinear.stream3.frame000230.pt
│ ├── nasa_13013.mp4.scale_240_135_flags_bilinear.stream3.frame000389.pt
│ ├── sine_mono_s16.wav.stream0.all_frames_info.json
│ └── sine_mono_s32_8000.wav.stream0.all_frames_info.json
├── test_version.py
├── __init__.py
├── test_policy.py
├── CMakeLists.txt
├── test_video_clip_sampler.py
└── conftest.py
├── src
└── torchcodec
│ ├── encoders
│ └── __init__.py
│ ├── samplers
│ ├── __init__.py
│ └── _common.py
│ ├── _samplers
│ └── __init__.py
│ ├── transforms
│ └── __init__.py
│ ├── _core
│ ├── NVCUVIDRuntimeLoader.h
│ ├── ValidationUtils.h
│ ├── ValidationUtils.cpp
│ ├── AVIOTensorContext.h
│ ├── __init__.py
│ ├── NVDECCache.cpp
│ ├── CUDACommon.h
│ ├── AVIOContextHolder.cpp
│ ├── FilterGraph.h
│ ├── Frame.cpp
│ ├── pybind_ops.cpp
│ ├── AVIOFileLikeContext.h
│ ├── Frame.h
│ ├── StreamOptions.h
│ ├── CudaDeviceInterface.h
│ ├── Transform.h
│ ├── AVIOContextHolder.h
│ ├── Metadata.h
│ ├── NVDECCache.h
│ ├── AVIOFileLikeContext.cpp
│ ├── DeviceInterface.cpp
│ ├── Transform.cpp
│ ├── Metadata.cpp
│ ├── Cache.h
│ ├── AVIOTensorContext.cpp
│ ├── fetch_and_expose_non_gpl_ffmpeg_libs.cmake
│ └── CpuDeviceInterface.h
│ ├── decoders
│ ├── __init__.py
│ └── _decoder_utils.py
│ ├── __init__.py
│ ├── _internally_replaced_utils.py
│ └── share
│ └── cmake
│ └── TorchCodec
│ └── TorchCodecConfig.cmake
├── benchmarks
├── decoders
│ ├── benchmark_readme_chart.png
│ ├── generate_readme_chart.py
│ ├── memprofile_decoders.py
│ ├── benchmark_audio_decoders.py
│ └── generate_readme_data.py
└── samplers
│ └── benchmark_samplers.py
├── docs
├── source
│ ├── _static
│ │ ├── img
│ │ │ ├── pytorch-logo-dark.png
│ │ │ ├── pytorch-logo-flame.png
│ │ │ ├── generic-pytorch-logo.png
│ │ │ ├── card-background.svg
│ │ │ ├── pytorch-logo-flame.svg
│ │ │ └── pytorch-logo-dark.svg
│ │ └── css
│ │ │ └── custom_torchcodec.css
│ ├── _templates
│ │ ├── function.rst
│ │ ├── class.rst
│ │ ├── dataclass.rst
│ │ └── layout.html
│ ├── api_ref_torchcodec.rst
│ ├── api_ref_encoders.rst
│ ├── api_ref_transforms.rst
│ ├── api_ref_samplers.rst
│ ├── api_ref_decoders.rst
│ ├── glossary.rst
│ └── index.rst
├── requirements.txt
└── Makefile
├── mypy.ini
├── .flake8
├── MANIFEST.in
├── packaging
├── fake_smoke_test.py
├── pre_build_script.sh
├── build_ffmpeg.bat
├── helpers.sh
├── vc_env_helper.bat
├── post_build_script.sh
└── check_glibcxx.py
├── CMakeLists.txt
├── .gitignore
├── .pre-commit-config.yaml
├── pyproject.toml
├── LICENSE
├── CODE_OF_CONDUCT.md
├── .clang-format
└── CONTRIBUTING.md
/version.txt:
--------------------------------------------------------------------------------
1 | 0.10.0a0
2 |
--------------------------------------------------------------------------------
/examples/decoding/README.rst:
--------------------------------------------------------------------------------
1 | Decoding
2 | --------
3 |
--------------------------------------------------------------------------------
/examples/encoding/README.rst:
--------------------------------------------------------------------------------
1 | Encoding
2 | --------
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 |
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000180.pt:
--------------------------------------------------------------------------------
1 | nasa_13013.mp4.time6.000000.pt
--------------------------------------------------------------------------------
/examples/README.rst:
--------------------------------------------------------------------------------
1 | .. _gallery:
2 |
3 | Interactive examples
4 | ====================
5 |
--------------------------------------------------------------------------------
/test/resources/testsrc2.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/testsrc2.mp4
--------------------------------------------------------------------------------
/test/resources/av1_video.mkv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/av1_video.mkv
--------------------------------------------------------------------------------
/test/resources/h265_video.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/h265_video.mp4
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4
--------------------------------------------------------------------------------
/test/test_version.py:
--------------------------------------------------------------------------------
1 | import torchcodec
2 |
3 |
4 | def test_version():
5 | assert torchcodec.__version__
6 |
--------------------------------------------------------------------------------
/test/resources/h264_10bits.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/h264_10bits.mp4
--------------------------------------------------------------------------------
/test/resources/h265_10bits.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/h265_10bits.mp4
--------------------------------------------------------------------------------
/test/resources/sine_mono_s16.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/sine_mono_s16.wav
--------------------------------------------------------------------------------
/test/resources/sine_mono_s32.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/sine_mono_s32.wav
--------------------------------------------------------------------------------
/test/resources/testsrc2_h265.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/testsrc2_h265.mp4
--------------------------------------------------------------------------------
/test/resources/testsrc2_vp8.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/testsrc2_vp8.webm
--------------------------------------------------------------------------------
/test/resources/testsrc2_vp9.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/testsrc2_vp9.webm
--------------------------------------------------------------------------------
/test/resources/testsrc2_mpeg4.avi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/testsrc2_mpeg4.avi
--------------------------------------------------------------------------------
/test/resources/bt709_full_range.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/bt709_full_range.mp4
--------------------------------------------------------------------------------
/test/resources/sine_mono_s32_8000.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/sine_mono_s32_8000.wav
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.audio.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.audio.mp3
--------------------------------------------------------------------------------
/test/resources/sine_mono_s32_44100.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/sine_mono_s32_44100.wav
--------------------------------------------------------------------------------
/src/torchcodec/encoders/__init__.py:
--------------------------------------------------------------------------------
1 | from ._audio_encoder import AudioEncoder # noqa
2 | from ._video_encoder import VideoEncoder # noqa
3 |
--------------------------------------------------------------------------------
/benchmarks/decoders/benchmark_readme_chart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/benchmarks/decoders/benchmark_readme_chart.png
--------------------------------------------------------------------------------
/docs/source/_static/img/pytorch-logo-dark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/docs/source/_static/img/pytorch-logo-dark.png
--------------------------------------------------------------------------------
/docs/source/_static/img/pytorch-logo-flame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/docs/source/_static/img/pytorch-logo-flame.png
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.audio_44100.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.audio_44100.mp3
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.time10.000000.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.time10.000000.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.time12.979633.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.time12.979633.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.time6.000000.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.time6.000000.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.time6.100000.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.time6.100000.pt
--------------------------------------------------------------------------------
/docs/source/_static/img/generic-pytorch-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/docs/source/_static/img/generic-pytorch-logo.png
--------------------------------------------------------------------------------
/mypy.ini:
--------------------------------------------------------------------------------
1 | [mypy]
2 |
3 | files = src/torchcodec
4 | show_error_codes = True
5 | pretty = True
6 | allow_redefinition = True
7 | follow_untyped_imports = True
8 |
--------------------------------------------------------------------------------
/test/resources/av1_video.mkv.stream0.frame000010.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/av1_video.mkv.stream0.frame000010.pt
--------------------------------------------------------------------------------
/test/resources/h265_video.mp4.stream0.frame000005.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/h265_video.mp4.stream0.frame000005.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000000.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000000.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000001.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000001.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000002.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000002.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000003.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000003.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000004.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000004.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000005.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000005.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000006.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000006.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000007.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000007.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000008.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000008.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000009.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000009.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000015.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000015.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000020.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000020.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000025.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000025.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000030.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000030.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream0.frame000035.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream0.frame000035.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000000.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000000.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000001.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000001.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000002.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000002.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000003.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000003.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000004.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000004.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000005.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000005.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000006.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000006.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000007.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000007.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000008.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000008.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000009.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000009.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000015.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000015.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000020.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000020.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000025.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000025.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000030.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000030.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000035.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000035.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000386.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000386.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000387.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000387.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000388.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000388.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream3.frame000389.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream3.frame000389.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.stream4.all_frames.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.stream4.all_frames.pt
--------------------------------------------------------------------------------
/test/resources/sine_mono_s16.wav.stream0.all_frames.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/sine_mono_s16.wav.stream0.all_frames.pt
--------------------------------------------------------------------------------
/test/resources/sine_mono_s32.wav.stream0.all_frames.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/sine_mono_s32.wav.stream0.all_frames.pt
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 120
3 | ignore = E203, E402, W503, W504, F821, E501, B, C4, EXE, E251, E202
4 | per-file-ignores =
5 | __init__.py: F401, F403, F405
6 |
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.audio.mp3.stream0.all_frames.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.audio.mp3.stream0.all_frames.pt
--------------------------------------------------------------------------------
/docs/source/_templates/function.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 | .. currentmodule:: {{ module }}
4 |
5 |
6 | {{ name | underline}}
7 |
8 | .. autofunction:: {{ name }}
9 |
--------------------------------------------------------------------------------
/src/torchcodec/samplers/__init__.py:
--------------------------------------------------------------------------------
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
3 |
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000000.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000000.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000015.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000015.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000200.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000200.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000389.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.crop_300_200_50_35_exact_1.stream3.frame000389.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.scale_240_135_flags_bilinear.stream3.frame000017.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.scale_240_135_flags_bilinear.stream3.frame000017.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.scale_240_135_flags_bilinear.stream3.frame000230.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.scale_240_135_flags_bilinear.stream3.frame000230.pt
--------------------------------------------------------------------------------
/test/resources/nasa_13013.mp4.scale_240_135_flags_bilinear.stream3.frame000389.pt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/meta-pytorch/torchcodec/HEAD/test/resources/nasa_13013.mp4.scale_240_135_flags_bilinear.stream3.frame000389.pt
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 |
4 | include CMakeLists.txt
5 | recursive-include src *
6 |
7 | recursive-exclude * __pycache__
8 | recursive-exclude src *.py[co]
9 | recursive-exclude src *.so
10 |
--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/docs/source/_templates/class.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 | .. currentmodule:: {{ module }}
4 |
5 |
6 | {{ name | underline}}
7 |
8 | .. autoclass:: {{ name }}
9 | :members:
10 | :special-members: __getitem__
11 |
--------------------------------------------------------------------------------
/docs/source/_templates/dataclass.rst:
--------------------------------------------------------------------------------
1 | .. role:: hidden
2 | :class: hidden-section
3 | .. currentmodule:: {{ module }}
4 |
5 |
6 | {{ name | underline}}
7 |
8 | .. autoclass:: {{ name }}
9 | :members:
10 | :undoc-members: __init__
11 | :inherited-members:
12 |
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | sphinx-gallery>0.11
2 | sphinx==5.0.0
3 | sphinx_design
4 | sphinx_copybutton
5 | sphinx-tabs
6 | sphinx-sitemap
7 | matplotlib
8 | torchvision
9 | ipython
10 | fsspec
11 | aiohttp
12 | joblib
13 | -e git+https://github.com/pytorch/pytorch_sphinx_theme.git#egg=pytorch_sphinx_theme
14 |
--------------------------------------------------------------------------------
/src/torchcodec/_samplers/__init__.py:
--------------------------------------------------------------------------------
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 | from .video_clip_sampler import * # noqa
8 |
--------------------------------------------------------------------------------
/docs/source/api_ref_torchcodec.rst:
--------------------------------------------------------------------------------
1 | .. _torchcodec:
2 |
3 | ===================
4 | torchcodec
5 | ===================
6 |
7 | .. currentmodule:: torchcodec
8 |
9 |
10 | .. autosummary::
11 | :toctree: generated/
12 | :nosignatures:
13 | :template: dataclass.rst
14 |
15 | Frame
16 | FrameBatch
17 | AudioSamples
18 |
--------------------------------------------------------------------------------
/src/torchcodec/transforms/__init__.py:
--------------------------------------------------------------------------------
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 | from ._decoder_transforms import ( # noqa
8 | CenterCrop,
9 | DecoderTransform,
10 | RandomCrop,
11 | Resize,
12 | )
13 |
--------------------------------------------------------------------------------
/packaging/fake_smoke_test.py:
--------------------------------------------------------------------------------
1 | # This is a fake smoke test that runs on the test-infra instances after we build
2 | # a wheel. We cannot run a real smoke test over there, because the machines are
3 | # too old to even install a proper ffmpeg version - and without ffmpeg,
4 | # importing torchcodec just fails. It's OK, we run our *entire* test suite on
5 | # those wheels anyway (on other machines).
6 |
7 | print("Success")
8 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18)
2 | project(TorchCodec)
3 |
4 | # Define LINUX platform variable globally
5 | if (UNIX AND NOT APPLE)
6 | set(LINUX TRUE)
7 | else()
8 | set(LINUX FALSE)
9 | endif()
10 |
11 | add_subdirectory(src/torchcodec/_core)
12 |
13 |
14 | option(BUILD_TESTS "Build tests" OFF)
15 | if(BUILD_TESTS)
16 | enable_testing()
17 | add_subdirectory(test)
18 | endif()
19 |
--------------------------------------------------------------------------------
/docs/source/_static/img/card-background.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/docs/source/api_ref_encoders.rst:
--------------------------------------------------------------------------------
1 | .. _encoders:
2 |
3 | ===================
4 | torchcodec.encoders
5 | ===================
6 |
7 | .. currentmodule:: torchcodec.encoders
8 |
9 |
10 | For an audio decoder tutorial, see: :ref:`sphx_glr_generated_examples_encoding_audio_encoding.py`.
11 |
12 |
13 | .. autosummary::
14 | :toctree: generated/
15 | :nosignatures:
16 | :template: class.rst
17 |
18 | AudioEncoder
19 | VideoEncoder
20 |
--------------------------------------------------------------------------------
/docs/source/api_ref_transforms.rst:
--------------------------------------------------------------------------------
1 | .. _transforms:
2 |
3 | =====================
4 | torchcodec.transforms
5 | =====================
6 |
7 | .. currentmodule:: torchcodec.transforms
8 |
9 | For a tutorial, see: TODO_DECODER_TRANSFORMS_TUTORIAL.
10 |
11 | .. autosummary::
12 | :toctree: generated/
13 | :nosignatures:
14 | :template: dataclass.rst
15 |
16 | DecoderTransform
17 | CenterCrop
18 | RandomCrop
19 | Resize
20 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/NVCUVIDRuntimeLoader.h:
--------------------------------------------------------------------------------
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 | #pragma once
8 |
9 | namespace facebook::torchcodec {
10 |
11 | // See note in corresponding cpp file
12 | bool loadNVCUVIDLibrary();
13 |
14 | } // namespace facebook::torchcodec
15 |
--------------------------------------------------------------------------------
/docs/source/api_ref_samplers.rst:
--------------------------------------------------------------------------------
1 | .. _samplers:
2 |
3 | ===================
4 | torchcodec.samplers
5 | ===================
6 |
7 | .. currentmodule:: torchcodec.samplers
8 |
9 | For a tutorial, see: :ref:`sphx_glr_generated_examples_decoding_sampling.py`.
10 |
11 | .. autosummary::
12 | :toctree: generated/
13 | :nosignatures:
14 | :template: function.rst
15 |
16 | clips_at_regular_indices
17 | clips_at_random_indices
18 | clips_at_regular_timestamps
19 | clips_at_random_timestamps
20 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation.yml:
--------------------------------------------------------------------------------
1 | name: 📚 Documentation
2 | description: Report an issue related to the TorchCodec documentation
3 |
4 | body:
5 | - type: textarea
6 | attributes:
7 | label: 📚 The doc issue
8 | description: >
9 | Is something confusing or wrong? Let us know! Please provide URLs to the content in https://pytorch.org/torchcodec/stable/index.html that you're referring to.
10 | validations:
11 | required: true
12 | - type: markdown
13 | attributes:
14 | value: >
15 | Thanks for contributing 🎉!
16 |
--------------------------------------------------------------------------------
/src/torchcodec/decoders/__init__.py:
--------------------------------------------------------------------------------
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 | from .._core import AudioStreamMetadata, VideoStreamMetadata
8 | from ._audio_decoder import AudioDecoder # noqa
9 | from ._decoder_utils import set_cuda_backend # noqa
10 | from ._video_decoder import CpuFallbackStatus, VideoDecoder # noqa
11 |
12 | SimpleVideoDecoder = VideoDecoder
13 |
--------------------------------------------------------------------------------
/packaging/pre_build_script.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright (c) Meta Platforms, Inc. and affiliates.
3 | # All rights reserved.
4 | #
5 | # This source code is licensed under the BSD-style license found in the
6 | # LICENSE file in the root directory of this source tree.
7 |
8 | set -ex
9 |
10 | # We need to install pybind11 because we need its CMake helpers in order to
11 | # compile correctly on Mac. Pybind11 is actually a C++ header-only library,
12 | # and PyTorch actually has it included. PyTorch, however, does not have the
13 | # CMake helpers.
14 | conda install -y pybind11 -c conda-forge
15 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: 🚀 Feature request
2 | description: Submit a proposal/request for a new TorchCodec feature
3 |
4 | body:
5 | - type: textarea
6 | attributes:
7 | label: 🚀 The feature
8 | description: >
9 | What new functionality do you want?
10 | validations:
11 | required: true
12 | - type: textarea
13 | attributes:
14 | label: Motivation, pitch
15 | description: >
16 | Why do you want it? If this is related to another GitHub issue, please link that here.
17 | validations:
18 | required: false
19 | - type: markdown
20 | attributes:
21 | value: >
22 | Thanks for contributing 🎉!
23 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/ValidationUtils.h:
--------------------------------------------------------------------------------
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 | #pragma once
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | namespace facebook::torchcodec {
14 |
15 | int validateInt64ToInt(int64_t value, const std::string& parameterName);
16 |
17 | std::optional validateOptionalInt64ToInt(
18 | const std::optional& value,
19 | const std::string& parameterName);
20 |
21 | } // namespace facebook::torchcodec
22 |
--------------------------------------------------------------------------------
/packaging/build_ffmpeg.bat:
--------------------------------------------------------------------------------
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 | :: Taken from torchaudio
8 | @echo off
9 |
10 | set PROJ_FOLDER=%cd%
11 |
12 | choco install -y --no-progress msys2 --package-parameters "/NoUpdate"
13 | C:\tools\msys64\usr\bin\env MSYSTEM=MINGW64 /bin/bash -l -c "pacman -S --noconfirm --needed base-devel mingw-w64-x86_64-toolchain diffutils"
14 | C:\tools\msys64\usr\bin\env MSYSTEM=MINGW64 /bin/bash -l -c "cd ${PROJ_FOLDER} && packaging/vc_env_helper.bat bash packaging/build_ffmpeg.sh"
15 |
16 | :end
17 |
--------------------------------------------------------------------------------
/docs/source/_templates/layout.html:
--------------------------------------------------------------------------------
1 | {% extends "!layout.html" %}
2 |
3 | {% block sidebartitle %}
4 |
7 | {% include "searchbox.html" %}
8 | {% endblock %}
9 |
10 |
11 | {% block footer %}
12 |
13 |
17 |
18 |
21 | {% endblock %}
22 |
--------------------------------------------------------------------------------
/benchmarks/decoders/generate_readme_chart.py:
--------------------------------------------------------------------------------
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 | import json
8 |
9 | from pathlib import Path
10 |
11 | from benchmark_decoders_library import plot_data
12 |
13 |
14 | def main() -> None:
15 | data_json = Path(__file__).parent / "benchmark_readme_data.json"
16 | with open(data_json, "r") as read_file:
17 | data_from_file = json.load(read_file)
18 |
19 | output_png = Path(__file__).parent / "benchmark_readme_chart.png"
20 | plot_data(data_from_file, output_png)
21 |
22 |
23 | if __name__ == "__main__":
24 | main()
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | dist/
3 | src/TorchCodec.egg-info/
4 | */**/__pycache__
5 | */__pycache__
6 | */*.pyc
7 | */**/*.pyc
8 | */**/**/*.pyc
9 | */**/*~
10 | *~
11 | frame180.* # output from smoke test
12 |
13 | src/torchcodec/version.py
14 |
15 | docs/build
16 | # sphinx-gallery
17 | docs/source/generated_examples/
18 | docs/source/gen_modules/
19 | docs/source/generated/
20 | docs/source/models/generated/
21 | docs/source/sg_execution_times.rst
22 | # pytorch-sphinx-theme gets installed here
23 | docs/src
24 |
25 | .coverage
26 | htmlcov
27 | .*.swp
28 | *.so*
29 | *.dylib*
30 | */*.so*
31 | */*.dylib*
32 | *.swp
33 | *.swo
34 | gen.yml
35 | .mypy_cache
36 | .vscode/
37 | .idea/
38 | *.orig
39 | *-checkpoint.ipynb
40 | *.venv
41 |
42 | ## Xcode User settings
43 | xcuserdata/
44 |
45 | # direnv
46 | .direnv
47 | .envrc
48 |
--------------------------------------------------------------------------------
/test/test_policy.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from torchcodec.samplers._common import _POLICY_FUNCTIONS
3 |
4 |
5 | @pytest.mark.parametrize(
6 | "policy, frame_indices, expected_frame_indices",
7 | (
8 | ("repeat_last", [1, 2, 3], [1, 2, 3, 3, 3]),
9 | ("repeat_last", [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]),
10 | ("wrap", [1, 2, 3], [1, 2, 3, 1, 2]),
11 | ("wrap", [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]),
12 | ),
13 | )
14 | def test_policy(policy, frame_indices, expected_frame_indices):
15 | policy_fun = _POLICY_FUNCTIONS[policy]
16 | assert policy_fun(frame_indices, desired_len=5) == expected_frame_indices
17 |
18 |
19 | def test_error_policy():
20 | with pytest.raises(ValueError, match="beyond the number of frames"):
21 | _POLICY_FUNCTIONS["error"]([1, 2, 3], desired_len=5)
22 |
--------------------------------------------------------------------------------
/docs/source/api_ref_decoders.rst:
--------------------------------------------------------------------------------
1 | .. _decoders:
2 |
3 | ===================
4 | torchcodec.decoders
5 | ===================
6 |
7 | .. currentmodule:: torchcodec.decoders
8 |
9 |
10 | For a video decoder tutorial, see: :ref:`sphx_glr_generated_examples_decoding_basic_example.py`.
11 | For an audio decoder tutorial, see: :ref:`sphx_glr_generated_examples_decoding_audio_decoding.py`.
12 |
13 |
14 | .. autosummary::
15 | :toctree: generated/
16 | :nosignatures:
17 | :template: class.rst
18 |
19 | VideoDecoder
20 | AudioDecoder
21 |
22 | .. autosummary::
23 | :toctree: generated/
24 | :nosignatures:
25 | :template: function.rst
26 |
27 | set_cuda_backend
28 |
29 | .. autosummary::
30 | :toctree: generated/
31 | :nosignatures:
32 | :template: dataclass.rst
33 |
34 | VideoStreamMetadata
35 | AudioStreamMetadata
36 | CpuFallbackStatus
37 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/ValidationUtils.cpp:
--------------------------------------------------------------------------------
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 | #include "ValidationUtils.h"
8 | #include
9 | #include "c10/util/Exception.h"
10 |
11 | namespace facebook::torchcodec {
12 |
13 | int validateInt64ToInt(int64_t value, const std::string& parameterName) {
14 | TORCH_CHECK(
15 | value >= std::numeric_limits::min() &&
16 | value <= std::numeric_limits::max(),
17 | parameterName,
18 | "=",
19 | value,
20 | " is out of range for int type.");
21 |
22 | return static_cast(value);
23 | }
24 |
25 | std::optional validateOptionalInt64ToInt(
26 | const std::optional& value,
27 | const std::string& parameterName) {
28 | if (value.has_value()) {
29 | return validateInt64ToInt(value.value(), parameterName);
30 | } else {
31 | return std::nullopt;
32 | }
33 | }
34 |
35 | } // namespace facebook::torchcodec
36 |
--------------------------------------------------------------------------------
/packaging/helpers.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | # Copyright (c) Meta Platforms, Inc. and affiliates.
3 | # All rights reserved.
4 | #
5 | # This source code is licensed under the BSD-style license found in the
6 | # LICENSE file in the root directory of this source tree.
7 |
8 | _list_wheel_files() {
9 | unzip -l "$1" | awk '{print $4}'
10 | }
11 |
12 | # $1 = path to wheel
13 | # $2 = pattern to grep for in wheel files
14 | # If files matching $2 are found in the wheel, the function errors.
15 | assert_not_in_wheel() {
16 | wheel_files=$(_list_wheel_files "$1")
17 | if grep -q "$2" <<< "$wheel_files"
18 | then
19 | echo "Found files in $1 that start with $2. Exiting!!"
20 | exit 1
21 | fi
22 | }
23 |
24 | # See assert_not_in_wheel
25 | assert_in_wheel() {
26 | wheel_files=$(_list_wheel_files "$1")
27 | if ! grep -q "$2" <<< "$wheel_files"
28 | then
29 | echo "Did not find files in $1 that start with $2. Exiting!!"
30 | exit 1
31 | fi
32 | }
33 |
34 | assert_ffmpeg_not_installed() {
35 | if command -v "ffmpeg" &> /dev/null
36 | then
37 | echo "ffmpeg is installed, but it shouldn't! Exiting!!"
38 | exit 1
39 | fi
40 | }
41 |
--------------------------------------------------------------------------------
/src/torchcodec/__init__.py:
--------------------------------------------------------------------------------
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 | from pathlib import Path
8 |
9 | # Note: usort wants to put Frame and FrameBatch after decoders and samplers,
10 | # but that results in circular import.
11 | from ._frame import AudioSamples, Frame, FrameBatch # usort:skip # noqa
12 | from . import decoders, encoders, samplers, transforms # noqa
13 |
14 | try:
15 | # Note that version.py is generated during install.
16 | from .version import __version__ # noqa: F401
17 | except Exception:
18 | pass
19 |
20 | # cmake_prefix_path is needed for downstream cmake-based builds that use
21 | # torchcodec as a dependency to tell cmake where torchcodec is installed and where to find its
22 | # CMake configuration files.
23 | # Pytorch itself has a similar mechanism which we use in our setup.py!
24 | cmake_prefix_path = Path(__file__).parent / "share" / "cmake"
25 | # Similarly, these are exposed for downstream builds that use torchcodec as a
26 | # dependency.
27 | from ._core import core_library_path, ffmpeg_major_version # usort:skip
28 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/AVIOTensorContext.h:
--------------------------------------------------------------------------------
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 | #pragma once
8 |
9 | #include
10 | #include "AVIOContextHolder.h"
11 |
12 | namespace facebook::torchcodec {
13 |
14 | namespace detail {
15 |
16 | struct TensorContext {
17 | torch::Tensor data;
18 | int64_t current_pos;
19 | int64_t max_pos;
20 | };
21 |
22 | } // namespace detail
23 |
24 | // For Decoding: enables users to pass in the entire video or audio as bytes.
25 | // Our read and seek functions then traverse the bytes in memory.
26 | class AVIOFromTensorContext : public AVIOContextHolder {
27 | public:
28 | explicit AVIOFromTensorContext(torch::Tensor data);
29 |
30 | private:
31 | detail::TensorContext tensorContext_;
32 | };
33 |
34 | // For Encoding: used to encode into an output uint8 (bytes) tensor.
35 | class AVIOToTensorContext : public AVIOContextHolder {
36 | public:
37 | explicit AVIOToTensorContext();
38 | torch::Tensor getOutputTensor();
39 |
40 | private:
41 | detail::TensorContext tensorContext_;
42 | };
43 |
44 | } // namespace facebook::torchcodec
45 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: v4.6.0
4 | hooks:
5 | - id: check-docstring-first
6 | - id: trailing-whitespace
7 | - id: check-toml
8 | - id: check-yaml
9 | args:
10 | - --allow-multiple-documents
11 | - id: mixed-line-ending
12 | args: [--fix=lf]
13 | - id: end-of-file-fixer
14 | - id: check-added-large-files
15 | args: ['--maxkb=1000']
16 |
17 | - repo: https://github.com/asottile/pyupgrade
18 | rev: v3.21.2
19 | hooks:
20 | - id: pyupgrade
21 | args: [--py310-plus]
22 | files: ^(test|src)/
23 | exclude: ^examples/
24 |
25 | - repo: https://github.com/omnilib/ufmt
26 | rev: v2.6.0
27 | hooks:
28 | - id: ufmt
29 | additional_dependencies:
30 | - black == 24.4.2
31 | - usort == 1.0.5
32 |
33 | - repo: https://github.com/PyCQA/flake8
34 | rev: 7.1.0
35 | hooks:
36 | - id: flake8
37 | args: [--config=.flake8]
38 |
39 | - repo: https://github.com/pre-commit/mirrors-clang-format
40 | rev: v18.1.3
41 | hooks:
42 | - id: clang-format
43 | name: clang-format
44 | files: \.(cpp|hpp|c|h)$
45 | types: [file]
46 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "torchcodec"
3 | description = "A video decoder for PyTorch"
4 | readme = "README.md"
5 | requires-python = ">=3.10"
6 | license-files = ["LICENSE"]
7 | authors = [
8 | { name = "PyTorch Team", email = "packages@pytorch.org" },
9 | ]
10 | dynamic = ["version"]
11 |
12 | [project.urls]
13 | GitHub = "https://github.com/pytorch/torchcodec"
14 | Documentation = "https://pytorch.org/torchcodec/stable/index.html"
15 |
16 | [tool.setuptools.dynamic]
17 | version = {file = "version.txt"}
18 |
19 | [build-system]
20 | requires = ["setuptools>=61.0"]
21 | build-backend = "setuptools.build_meta"
22 |
23 | [project.optional-dependencies]
24 | dev = [
25 | "numpy",
26 | "pytest",
27 | "pillow",
28 | ]
29 |
30 | [tool.usort]
31 | # Needed for compatibility with internal linter
32 | first_party_detection = false
33 |
34 | [tool.black]
35 | target-version = ["py310"]
36 |
37 | [tool.ufmt]
38 |
39 | excludes = [
40 | "examples",
41 | ]
42 |
43 | [tool.pytest.ini_options]
44 | markers = [
45 | # defines a 'slow' mark to mark slow tests with `@pytest.mark.slow`
46 | "slow: mark test as slow"
47 | ]
48 |
49 | # We don't want to run the slow tests by default. These options are ignored in
50 | # the CI, where we definitely want the 'slow' tests to run.
51 | addopts = "-v -m 'not slow'"
52 |
53 | testpaths = ["test"]
54 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/__init__.py:
--------------------------------------------------------------------------------
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 |
8 | from ._metadata import (
9 | AudioStreamMetadata,
10 | ContainerMetadata,
11 | get_container_metadata,
12 | get_container_metadata_from_header,
13 | VideoStreamMetadata,
14 | )
15 | from .ops import (
16 | _add_video_stream,
17 | _get_backend_details,
18 | _get_key_frame_indices,
19 | _test_frame_pts_equality,
20 | add_audio_stream,
21 | add_video_stream,
22 | core_library_path,
23 | create_from_bytes,
24 | create_from_file,
25 | create_from_file_like,
26 | create_from_tensor,
27 | encode_audio_to_file,
28 | encode_audio_to_file_like,
29 | encode_audio_to_tensor,
30 | encode_video_to_file,
31 | encode_video_to_file_like,
32 | encode_video_to_tensor,
33 | ffmpeg_major_version,
34 | get_ffmpeg_library_versions,
35 | get_frame_at_index,
36 | get_frame_at_pts,
37 | get_frames_at_indices,
38 | get_frames_by_pts,
39 | get_frames_by_pts_in_range,
40 | get_frames_by_pts_in_range_audio,
41 | get_frames_in_range,
42 | get_json_metadata,
43 | get_next_frame,
44 | scan_all_streams_to_update_metadata,
45 | seek_to_pts,
46 | )
47 |
--------------------------------------------------------------------------------
/docs/source/glossary.rst:
--------------------------------------------------------------------------------
1 | Glossary
2 | ========
3 |
4 | .. glossary::
5 |
6 | pts
7 | Presentation Time Stamp. The time at which a frame or audio sample should be played.
8 | In TorchCodec, pts are expressed in seconds.
9 |
10 | best stream
11 | The notion of "best" stream is determined by FFmpeg. Quoting the `FFmpeg docs
12 | `_:
13 |
14 | *The best stream is determined according to various heuristics as the most likely to be what the user expects.*
15 |
16 | scan
17 | A scan corresponds to an entire pass over a video file, with the purpose
18 | of retrieving metadata about the different streams and frames. **It does
19 | not involve decoding**, so it is a lot cheaper than decoding the file.
20 | The :class:`~torchcodec.decoders.VideoDecoder` performs a scan when using
21 | ``seek_mode="exact"``, and doesn't scan when using
22 | ``seek_mode="approximate"``.
23 |
24 | clips
25 | A clip is a sequence of frames, usually in :term:`pts` order. The frames
26 | may not necessarily be consecutive. A clip is represented as a 4D
27 | :class:`~torchcodec.FrameBatch`. A group of clips, which is what the
28 | :ref:`samplers ` return, is represented as 5D
29 | :class:`~torchcodec.FrameBatch`.
30 |
--------------------------------------------------------------------------------
/packaging/vc_env_helper.bat:
--------------------------------------------------------------------------------
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 | :: Taken from torchaudio
8 | @echo on
9 |
10 | set VC_VERSION_LOWER=17
11 | set VC_VERSION_UPPER=18
12 |
13 | for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -legacy -products * -version [%VC_VERSION_LOWER%^,%VC_VERSION_UPPER%^) -property installationPath`) do (
14 | if exist "%%i" if exist "%%i\VC\Auxiliary\Build\vcvarsall.bat" (
15 | set "VS15INSTALLDIR=%%i"
16 | set "VS15VCVARSALL=%%i\VC\Auxiliary\Build\vcvarsall.bat"
17 | goto vswhere
18 | )
19 | )
20 |
21 | :vswhere
22 | if "%VSDEVCMD_ARGS%" == "" (
23 | call "%VS15VCVARSALL%" x64 || exit /b 1
24 | ) else (
25 | call "%VS15VCVARSALL%" x64 %VSDEVCMD_ARGS% || exit /b 1
26 | )
27 |
28 | @echo on
29 |
30 | if "%CU_VERSION%" == "xpu" call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat"
31 |
32 | set DISTUTILS_USE_SDK=1
33 | set BUILD_AGAINST_ALL_FFMPEG_FROM_S3=1
34 |
35 | set args=%1
36 | shift
37 | :start
38 | if [%1] == [] goto done
39 | set args=%args% %1
40 | shift
41 | goto start
42 |
43 | :done
44 | if "%args%" == "" (
45 | echo Usage: vc_env_helper.bat [command] [args]
46 | echo e.g. vc_env_helper.bat cl /c test.cpp
47 | )
48 |
49 | %args% || exit /b 1
50 |
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.14)
2 | include(CMakePrintHelpers)
3 | project(TorchCodecTests)
4 | set(CMAKE_CXX_STANDARD 17)
5 | set(CMAKE_CXX_STANDARD_REQUIRED)
6 |
7 | find_package(Torch REQUIRED)
8 |
9 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")
10 |
11 |
12 | include(FetchContent)
13 | FetchContent_Declare(
14 | googletest
15 | URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
16 | )
17 | FetchContent_MakeAvailable(googletest)
18 |
19 | add_executable(
20 | VideoDecoderTest
21 | VideoDecoderTest.cpp
22 | )
23 |
24 | target_include_directories(VideoDecoderTest SYSTEM PRIVATE ${TORCH_INCLUDE_DIRS})
25 | target_include_directories(VideoDecoderTest SYSTEM PRIVATE ${libav_include_dirs})
26 | target_include_directories(VideoDecoderTest PRIVATE ../)
27 |
28 | target_link_libraries(
29 | VideoDecoderTest
30 | ${libtorchcodec_library_name}
31 | ${libtorchcodec_custom_ops_name}
32 | GTest::gtest_main
33 | )
34 |
35 | include(GoogleTest)
36 | gtest_discover_tests(VideoDecoderTest)
37 |
38 |
39 | add_executable(
40 | MetadataTest
41 | MetadataTest.cpp
42 | )
43 |
44 | target_include_directories(MetadataTest SYSTEM PRIVATE ${TORCH_INCLUDE_DIRS})
45 | target_include_directories(MetadataTest SYSTEM PRIVATE ${libav_include_dirs})
46 | target_include_directories(MetadataTest PRIVATE ../)
47 |
48 | target_link_libraries(
49 | MetadataTest
50 | ${libtorchcodec_library_name}
51 | ${libtorchcodec_custom_ops_name}
52 | GTest::gtest_main
53 | )
54 |
55 | gtest_discover_tests(MetadataTest)
56 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright 2024 Meta
4 |
5 | Redistribution and use in source and binary forms, with or without modification,
6 | are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice,this list
9 | of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice, this
12 | list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | 3. Neither the name of the copyright holder nor the names of its contributors may
16 | be used to endorse or promote products derived from this software without specific
17 | prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22 | SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28 | DAMAGE.
29 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/NVDECCache.cpp:
--------------------------------------------------------------------------------
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 | #include
8 | #include
9 |
10 | #include "CUDACommon.h"
11 | #include "FFMPEGCommon.h"
12 | #include "NVDECCache.h"
13 |
14 | #include // For cudaGetDevice
15 |
16 | extern "C" {
17 | #include
18 | #include
19 | }
20 |
21 | namespace facebook::torchcodec {
22 |
23 | NVDECCache& NVDECCache::getCache(const torch::Device& device) {
24 | static NVDECCache cacheInstances[MAX_CUDA_GPUS];
25 | return cacheInstances[getDeviceIndex(device)];
26 | }
27 |
28 | UniqueCUvideodecoder NVDECCache::getDecoder(CUVIDEOFORMAT* videoFormat) {
29 | CacheKey key(videoFormat);
30 | std::lock_guard lock(cacheLock_);
31 |
32 | auto it = cache_.find(key);
33 | if (it != cache_.end()) {
34 | auto decoder = std::move(it->second);
35 | cache_.erase(it);
36 | return decoder;
37 | }
38 |
39 | return nullptr;
40 | }
41 |
42 | bool NVDECCache::returnDecoder(
43 | CUVIDEOFORMAT* videoFormat,
44 | UniqueCUvideodecoder decoder) {
45 | if (!decoder) {
46 | return false;
47 | }
48 |
49 | CacheKey key(videoFormat);
50 | std::lock_guard lock(cacheLock_);
51 |
52 | if (cache_.size() >= MAX_CACHE_SIZE) {
53 | return false;
54 | }
55 |
56 | cache_[key] = std::move(decoder);
57 | return true;
58 | }
59 |
60 | } // namespace facebook::torchcodec
61 |
--------------------------------------------------------------------------------
/docs/source/_static/img/pytorch-logo-flame.svg:
--------------------------------------------------------------------------------
1 |
2 |
34 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/CUDACommon.h:
--------------------------------------------------------------------------------
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 | #pragma once
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "FFMPEGCommon.h"
15 | #include "Frame.h"
16 |
17 | extern "C" {
18 | #include
19 | #include
20 | }
21 |
22 | namespace facebook::torchcodec {
23 |
24 | // Pytorch can only handle up to 128 GPUs.
25 | // https://github.com/pytorch/pytorch/blob/e30c55ee527b40d67555464b9e402b4b7ce03737/c10/cuda/CUDAMacros.h#L44
26 | constexpr int MAX_CUDA_GPUS = 128;
27 |
28 | void initializeCudaContextWithPytorch(const torch::Device& device);
29 |
30 | // Unique pointer type for NPP stream context
31 | using UniqueNppContext = std::unique_ptr;
32 |
33 | torch::Tensor convertNV12FrameToRGB(
34 | UniqueAVFrame& avFrame,
35 | const torch::Device& device,
36 | const UniqueNppContext& nppCtx,
37 | at::cuda::CUDAStream nvdecStream,
38 | std::optional preAllocatedOutputTensor = std::nullopt);
39 |
40 | UniqueNppContext getNppStreamContext(const torch::Device& device);
41 | void returnNppStreamContextToCache(
42 | const torch::Device& device,
43 | UniqueNppContext nppCtx);
44 |
45 | void validatePreAllocatedTensorShape(
46 | const std::optional& preAllocatedOutputTensor,
47 | const UniqueAVFrame& avFrame);
48 |
49 | int getDeviceIndex(const torch::Device& device);
50 |
51 | } // namespace facebook::torchcodec
52 |
--------------------------------------------------------------------------------
/benchmarks/decoders/memprofile_decoders.py:
--------------------------------------------------------------------------------
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 | import argparse
8 | import importlib
9 |
10 | import torch
11 | from memory_profiler import profile
12 | from torchcodec._core import add_video_stream, create_from_file, get_next_frame
13 |
14 | torch._dynamo.config.cache_size_limit = 100
15 | torch._dynamo.config.capture_dynamic_output_shape_ops = True
16 |
17 |
18 | @profile
19 | def torchcodec_create_next(video_file):
20 | video_decoder = create_from_file(video_file)
21 | add_video_stream(video_decoder)
22 | get_next_frame(video_decoder)
23 | return video_decoder
24 |
25 |
26 | def get_video_path_str(filename: str) -> str:
27 | resource = importlib.resources.files(__package__).joinpath(filename)
28 | with importlib.resources.as_file(resource) as path:
29 | return str(path)
30 |
31 |
32 | def main() -> None:
33 | """Memory leak check and profiling for decoders."""
34 | parser = argparse.ArgumentParser()
35 | parser.add_argument(
36 | "--iterations",
37 | help="Number of times to invoke decoder operations.",
38 | type=int,
39 | default=10,
40 | )
41 | args = parser.parse_args()
42 |
43 | large_video_path = get_video_path_str("853.mp4")
44 |
45 | # We call the same function several times, and each call will produce memory stats on
46 | # standard out. We rely on a human looking at the output to see if memory increases
47 | # on each run.
48 | for _ in range(args.iterations):
49 | torchcodec_create_next(large_video_path)
50 |
51 |
52 | if __name__ == "__main__":
53 | main()
54 |
--------------------------------------------------------------------------------
/packaging/post_build_script.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Copyright (c) Meta Platforms, Inc. and affiliates.
3 | # All rights reserved.
4 | #
5 | # This source code is licensed under the BSD-style license found in the
6 | # LICENSE file in the root directory of this source tree.
7 |
8 | set -ex
9 |
10 | source packaging/helpers.sh
11 |
12 | wheel_path=$(pwd)/$(find dist -type f -name "*.whl")
13 | echo "Wheel content:"
14 | unzip -l $wheel_path
15 |
16 | unamestr=$(uname)
17 | if [[ "$unamestr" == 'Linux' ]]; then
18 | ext="so"
19 | elif [[ "$unamestr" == 'Darwin' ]]; then
20 | ext="dylib"
21 | else
22 | echo "Unknown operating system: $unamestr"
23 | exit 1
24 | fi
25 |
26 | # TODO: Make ffmpeg4 work with nvcc.
27 | if [[ "$ENABLE_CUDA" -eq 1 ]]; then
28 | ffmpeg_versions=(5 6 7)
29 | fi
30 |
31 | for ffmpeg_major_version in ${ffmpeg_versions[@]}; do
32 | assert_in_wheel $wheel_path torchcodec/libtorchcodec${ffmpeg_major_version}.${ext}
33 | done
34 | assert_not_in_wheel $wheel_path libtorchcodec.${ext}
35 |
36 | for ffmpeg_ext in libavcodec.${ext} libavfilter.${ext} libavformat.${ext} libavutil.${ext} libavdevice.${ext} ; do
37 | assert_not_in_wheel $wheel_path $ffmpeg_ext
38 | done
39 |
40 | assert_not_in_wheel $wheel_path "^test"
41 | assert_not_in_wheel $wheel_path "^doc"
42 | assert_not_in_wheel $wheel_path "^benchmarks"
43 | assert_not_in_wheel $wheel_path "^packaging"
44 |
45 | if [[ "$unamestr" == 'Linux' ]]; then
46 | # See invoked python script below for details about this check.
47 | extracted_wheel_dir=$(mktemp -d)
48 | unzip -q $wheel_path -d $extracted_wheel_dir
49 | symbols_matches=$(find $extracted_wheel_dir | grep ".so$" | xargs objdump --syms | grep GLIBCXX_3.4.)
50 | python packaging/check_glibcxx.py "$symbols_matches"
51 | fi
52 |
53 | echo "ls dist"
54 | ls dist
55 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/AVIOContextHolder.cpp:
--------------------------------------------------------------------------------
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 | #include "AVIOContextHolder.h"
8 | #include
9 |
10 | namespace facebook::torchcodec {
11 |
12 | void AVIOContextHolder::createAVIOContext(
13 | AVIOReadFunction read,
14 | AVIOWriteFunction write,
15 | AVIOSeekFunction seek,
16 | void* heldData,
17 | bool isForWriting,
18 | int bufferSize) {
19 | TORCH_CHECK(
20 | bufferSize > 0,
21 | "Buffer size must be greater than 0; is " + std::to_string(bufferSize));
22 | auto buffer = static_cast(av_malloc(bufferSize));
23 | TORCH_CHECK(
24 | buffer != nullptr,
25 | "Failed to allocate buffer of size " + std::to_string(bufferSize));
26 |
27 | TORCH_CHECK(seek != nullptr, "seek method must be defined");
28 |
29 | if (isForWriting) {
30 | TORCH_CHECK(write != nullptr, "write method must be defined for writing");
31 | } else {
32 | TORCH_CHECK(read != nullptr, "read method must be defined for reading");
33 | }
34 |
35 | avioContext_.reset(avioAllocContext(
36 | buffer,
37 | bufferSize,
38 | /*write_flag=*/isForWriting,
39 | heldData,
40 | read,
41 | write,
42 | seek));
43 |
44 | if (!avioContext_) {
45 | av_freep(&buffer);
46 | TORCH_CHECK(false, "Failed to allocate AVIOContext");
47 | }
48 | }
49 |
50 | AVIOContextHolder::~AVIOContextHolder() {
51 | if (avioContext_) {
52 | av_freep(&avioContext_->buffer);
53 | }
54 | }
55 |
56 | AVIOContext* AVIOContextHolder::getAVIOContext() {
57 | return avioContext_.get();
58 | }
59 |
60 | } // namespace facebook::torchcodec
61 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | ifneq ($(EXAMPLES_PATTERN),)
5 | EXAMPLES_PATTERN_OPTS := -D sphinx_gallery_conf.filename_pattern="$(EXAMPLES_PATTERN)"
6 | endif
7 |
8 | # You can set these variables from the command line.
9 | SPHINXOPTS = -W -j auto $(EXAMPLES_PATTERN_OPTS)
10 | SPHINXBUILD = sphinx-build
11 | SPHINXPROJ = torchcodec
12 | SOURCEDIR = source
13 | BUILDDIR = build
14 |
15 | # Put it first so that "make" without argument is like "make help".
16 | help:
17 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
18 |
19 | docset: html
20 | doc2dash --name $(SPHINXPROJ) --icon $(SOURCEDIR)/_static/img/pytorch-logo-flame.png --enable-js --online-redirect-url http://pytorch.org/vision/ --force $(BUILDDIR)/html/
21 |
22 | # Manually fix because Zeal doesn't deal well with `icon.png`-only at 2x resolution.
23 | cp $(SPHINXPROJ).docset/icon.png $(SPHINXPROJ).docset/icon@2x.png
24 | convert $(SPHINXPROJ).docset/icon@2x.png -resize 16x16 $(SPHINXPROJ).docset/icon.png
25 |
26 | html-noplot: # Avoids running the gallery examples, which may take time
27 | $(SPHINXBUILD) -D plot_gallery=0 -b html "${SOURCEDIR}" "$(BUILDDIR)"/html
28 | @echo
29 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
30 |
31 | clean:
32 | rm -rf $(BUILDDIR)/*
33 | rm -rf $(SOURCEDIR)/generated_examples/ # sphinx-gallery
34 | rm -rf $(SOURCEDIR)/gen_modules/ # sphinx-gallery
35 | rm -rf $(SOURCEDIR)/sg_execution_times.rst # sphinx-gallery
36 | rm -rf $(SOURCEDIR)/generated/ # autosummary
37 |
38 | .PHONY: help Makefile docset
39 |
40 | # Catch-all target: route all unknown targets to Sphinx using the new
41 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
42 | %: Makefile
43 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
44 |
--------------------------------------------------------------------------------
/docs/source/_static/img/pytorch-logo-dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
25 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/FilterGraph.h:
--------------------------------------------------------------------------------
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 | #pragma once
8 |
9 | #include "FFMPEGCommon.h"
10 | #include "StreamOptions.h"
11 |
12 | namespace facebook::torchcodec {
13 |
14 | struct FiltersContext {
15 | int inputWidth = 0;
16 | int inputHeight = 0;
17 | AVPixelFormat inputFormat = AV_PIX_FMT_NONE;
18 | AVRational inputAspectRatio = {0, 0};
19 | int outputWidth = 0;
20 | int outputHeight = 0;
21 | AVPixelFormat outputFormat = AV_PIX_FMT_NONE;
22 | std::string filtergraphStr;
23 | AVRational timeBase = {0, 0};
24 | UniqueAVBufferRef hwFramesCtx;
25 |
26 | FiltersContext() = default;
27 | FiltersContext(FiltersContext&&) = default;
28 | FiltersContext& operator=(FiltersContext&&) = default;
29 | FiltersContext(
30 | int inputWidth,
31 | int inputHeight,
32 | AVPixelFormat inputFormat,
33 | AVRational inputAspectRatio,
34 | int outputWidth,
35 | int outputHeight,
36 | AVPixelFormat outputFormat,
37 | const std::string& filtergraphStr,
38 | AVRational timeBase,
39 | AVBufferRef* hwFramesCtx = nullptr);
40 |
41 | bool operator==(const FiltersContext&) const;
42 | bool operator!=(const FiltersContext&) const;
43 | };
44 |
45 | class FilterGraph {
46 | public:
47 | FilterGraph(
48 | const FiltersContext& filtersContext,
49 | const VideoStreamOptions& videoStreamOptions);
50 |
51 | UniqueAVFrame convert(const UniqueAVFrame& avFrame);
52 |
53 | private:
54 | UniqueAVFilterGraph filterGraph_;
55 | AVFilterContext* sourceContext_ = nullptr;
56 | AVFilterContext* sinkContext_ = nullptr;
57 | };
58 |
59 | } // namespace facebook::torchcodec
60 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/Frame.cpp:
--------------------------------------------------------------------------------
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 | #include "Frame.h"
8 |
9 | namespace facebook::torchcodec {
10 |
11 | FrameDims::FrameDims(int height, int width) : height(height), width(width) {
12 | TORCH_CHECK(height > 0, "FrameDims.height must be > 0, got: ", height);
13 | TORCH_CHECK(width > 0, "FrameDims.width must be > 0, got: ", width);
14 | }
15 |
16 | FrameBatchOutput::FrameBatchOutput(
17 | int64_t numFrames,
18 | const FrameDims& outputDims,
19 | const torch::Device& device)
20 | : ptsSeconds(torch::empty({numFrames}, {torch::kFloat64})),
21 | durationSeconds(torch::empty({numFrames}, {torch::kFloat64})) {
22 | data = allocateEmptyHWCTensor(outputDims, device, numFrames);
23 | }
24 |
25 | torch::Tensor allocateEmptyHWCTensor(
26 | const FrameDims& frameDims,
27 | const torch::Device& device,
28 | std::optional numFrames) {
29 | auto tensorOptions = torch::TensorOptions()
30 | .dtype(torch::kUInt8)
31 | .layout(torch::kStrided)
32 | .device(device);
33 | TORCH_CHECK(
34 | frameDims.height > 0, "height must be > 0, got: ", frameDims.height);
35 | TORCH_CHECK(frameDims.width > 0, "width must be > 0, got: ", frameDims.width);
36 | if (numFrames.has_value()) {
37 | auto numFramesValue = numFrames.value();
38 | TORCH_CHECK(
39 | numFramesValue >= 0, "numFrames must be >= 0, got: ", numFramesValue);
40 | return torch::empty(
41 | {numFramesValue, frameDims.height, frameDims.width, 3}, tensorOptions);
42 | } else {
43 | return torch::empty({frameDims.height, frameDims.width, 3}, tensorOptions);
44 | }
45 | }
46 |
47 | } // namespace facebook::torchcodec
48 |
--------------------------------------------------------------------------------
/test/test_video_clip_sampler.py:
--------------------------------------------------------------------------------
1 | # (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2 |
3 |
4 | import pytest
5 | import torch
6 | from torchcodec._samplers import (
7 | DEPRECATED_VideoClipSampler,
8 | IndexBasedSamplerArgs,
9 | TimeBasedSamplerArgs,
10 | VideoArgs,
11 | )
12 |
13 | from .utils import NASA_VIDEO
14 |
15 |
16 | @pytest.mark.parametrize(
17 | ("sampler_args"),
18 | [
19 | TimeBasedSamplerArgs(
20 | sampler_type="random", clips_per_video=2, frames_per_clip=4
21 | ),
22 | IndexBasedSamplerArgs(
23 | sampler_type="random", clips_per_video=2, frames_per_clip=4
24 | ),
25 | TimeBasedSamplerArgs(
26 | sampler_type="uniform", clips_per_video=3, frames_per_clip=4
27 | ),
28 | IndexBasedSamplerArgs(
29 | sampler_type="uniform", clips_per_video=3, frames_per_clip=4
30 | ),
31 | ],
32 | )
33 | def test_sampler(sampler_args):
34 | torch.manual_seed(0)
35 | desired_width, desired_height = 320, 240
36 | video_args = VideoArgs(desired_width=desired_width, desired_height=desired_height)
37 | sampler = DEPRECATED_VideoClipSampler(video_args, sampler_args)
38 | clips = sampler(NASA_VIDEO.to_tensor())
39 | assert len(clips) == sampler_args.clips_per_video
40 | clip = clips[0]
41 | if isinstance(sampler_args, TimeBasedSamplerArgs):
42 | # Note: Looks like we have an API inconsistency.
43 | # With time-based sampler, `clip` is a tensor but with index-based
44 | # samplers `clip` is a list.
45 | # Below manually convert that list to a tensor for the `.shape` check to
46 | # be unified, but this block should be removed eventually.
47 | clip = torch.stack(clip)
48 | assert clip.shape == (
49 | sampler_args.frames_per_clip,
50 | 3,
51 | desired_height,
52 | desired_width,
53 | )
54 |
55 |
56 | if __name__ == "__main__":
57 | pytest.main()
58 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: 🐛 Bug Report
2 | description: Create a report to help us reproduce and fix the bug
3 |
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: >
8 | #### Your bug may have already been reported! Please check [the existing and past issues](https://github.com/pytorch/torchcodec/issues?q=sort%3Aupdated-desc+is%3Aissue).
9 | - type: textarea
10 | attributes:
11 | label: 🐛 Describe the bug
12 | description: |
13 | What broke? What behavior did you see versus what did you expect? Please provide any relevant code, error messages and exception tracebacks.
14 |
15 | A minimal code example will help us help you faster! The ideal code example is a small chunk of code that we can copy-paste to see the same error you see. For example:
16 |
17 | ```python
18 | # All necessary imports at the beginning
19 | import torch
20 | import torchcodec
21 | from torchcodec.decoders import VideoDecoder
22 |
23 | # A succinct reproducing example trimmed down to the essential parts:
24 | decoder = VideoDecoder("path/to/video.mp4") # Help! This fails!
25 | # ...
26 | ```
27 |
28 | If the code is long, put it in a public gist and link it in the issue: https://gist.github.com. Please also paste any error messages and full exception tracebacks in ```` ```triple quotes blocks``` ````.
29 | validations:
30 | required: true
31 | - type: textarea
32 | attributes:
33 | label: Versions
34 | description: |
35 | We support a wide variety of platforms and versions, and many bugs are verison-dependent. Knowing your setup will help us help you faster! Please run the following and paste the output below.
36 | ```sh
37 | wget https://raw.githubusercontent.com/pytorch/pytorch/main/torch/utils/collect_env.py
38 | # For security purposes, please check the contents of collect_env.py before running it.
39 | python collect_env.py
40 | ```
41 | validations:
42 | required: true
43 | - type: markdown
44 | attributes:
45 | value: >
46 | Thanks for contributing 🎉!
47 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/pybind_ops.cpp:
--------------------------------------------------------------------------------
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 | #include
8 | #include
9 | #include
10 |
11 | #include "AVIOFileLikeContext.h"
12 |
13 | namespace py = pybind11;
14 |
15 | namespace facebook::torchcodec {
16 |
17 | // Note: It's not immediately obvous why we need both custom_ops.cpp and
18 | // pybind_ops.cpp. We do all other Python to C++ bridging in
19 | // custom_ops.cpp, and that even depends on pybind11, so why have an
20 | // explicit pybind-only file?
21 | //
22 | // The reason is that we want to accept OWNERSHIP of a file-like object
23 | // from the Python side. In order to do that, we need a proper
24 | // py::object. For raw bytes, we can launder that through a tensor on the
25 | // custom_ops.cpp side, but we can't launder a proper Python object
26 | // through a tensor. Custom ops can't accept a proper Python object
27 | // through py::object, so we have to do direct pybind11 here.
28 | //
29 | // TODO: Investigate if we can do something better here. See:
30 | // https://github.com/pytorch/torchcodec/issues/896
31 | // Short version is that we're laundering a pointer through an int, the
32 | // Python side forwards that to decoder creation functions in
33 | // custom_ops.cpp and we do another cast on that side to get a pointer
34 | // again. We want to investigate if we can do something cleaner by
35 | // defining proper pybind objects.
36 | int64_t create_file_like_context(py::object file_like, bool is_for_writing) {
37 | AVIOFileLikeContext* context =
38 | new AVIOFileLikeContext(file_like, is_for_writing);
39 | return reinterpret_cast(context);
40 | }
41 |
42 | #ifndef PYBIND_OPS_MODULE_NAME
43 | #error PYBIND_OPS_MODULE_NAME must be defined!
44 | #endif
45 |
46 | PYBIND11_MODULE(PYBIND_OPS_MODULE_NAME, m) {
47 | m.def("create_file_like_context", &create_file_like_context);
48 | }
49 |
50 | } // namespace facebook::torchcodec
51 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/AVIOFileLikeContext.h:
--------------------------------------------------------------------------------
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 | #pragma once
8 |
9 | #include
10 | #include
11 |
12 | #include "AVIOContextHolder.h"
13 |
14 | namespace py = pybind11;
15 |
16 | namespace facebook::torchcodec {
17 |
18 | // Enables uers to pass in a Python file-like object. We then forward all read
19 | // and seek calls back up to the methods on the Python object.
20 | class AVIOFileLikeContext : public AVIOContextHolder {
21 | public:
22 | explicit AVIOFileLikeContext(const py::object& fileLike, bool isForWriting);
23 |
24 | private:
25 | static int read(void* opaque, uint8_t* buf, int buf_size);
26 | static int64_t seek(void* opaque, int64_t offset, int whence);
27 | static int write(void* opaque, const uint8_t* buf, int buf_size);
28 |
29 | // Note that we dynamically allocate the Python object because we need to
30 | // strictly control when its destructor is called. We must hold the GIL
31 | // when its destructor gets called, as it needs to update the reference
32 | // count. It's easiest to control that when it's dynamic memory. Otherwise,
33 | // we'd have to ensure whatever enclosing scope holds the object has the GIL,
34 | // and that's, at least, hard. For all of the common pitfalls, see:
35 | //
36 | // https://pybind11.readthedocs.io/en/stable/advanced/misc.html#common-sources-of-global-interpreter-lock-errors
37 | //
38 | // We maintain a reference to the file-like object because the file-like
39 | // object that was created on the Python side must live as long as our
40 | // potential use. That is, even if there are no more references to the object
41 | // on the Python side, we require that the object is still live.
42 | struct PyObjectDeleter {
43 | inline void operator()(py::object* obj) const {
44 | if (obj) {
45 | py::gil_scoped_acquire gil;
46 | delete obj;
47 | }
48 | }
49 | };
50 |
51 | using UniquePyObject = std::unique_ptr;
52 | UniquePyObject fileLike_;
53 | };
54 |
55 | } // namespace facebook::torchcodec
56 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/Frame.h:
--------------------------------------------------------------------------------
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 | #pragma once
8 |
9 | #include
10 | #include "FFMPEGCommon.h"
11 | #include "Metadata.h"
12 | #include "StreamOptions.h"
13 |
14 | namespace facebook::torchcodec {
15 |
16 | struct FrameDims {
17 | int height = 0;
18 | int width = 0;
19 |
20 | FrameDims() = default;
21 |
22 | FrameDims(int h, int w);
23 | };
24 |
25 | // All public video decoding entry points return either a FrameOutput or a
26 | // FrameBatchOutput.
27 | // They are the equivalent of the user-facing Frame and FrameBatch classes in
28 | // Python. They contain RGB decoded frames along with some associated data
29 | // like PTS and duration.
30 | // FrameOutput is also relevant for audio decoding, typically as the output of
31 | // getNextFrame(), or as a temporary output variable.
32 | struct FrameOutput {
33 | // data shape is:
34 | // - 3D (C, H, W) or (H, W, C) for videos
35 | // - 2D (numChannels, numSamples) for audio
36 | torch::Tensor data;
37 | double ptsSeconds;
38 | double durationSeconds;
39 | };
40 |
41 | struct FrameBatchOutput {
42 | torch::Tensor data; // 4D: of shape NCHW or NHWC.
43 | torch::Tensor ptsSeconds; // 1D of shape (N,)
44 | torch::Tensor durationSeconds; // 1D of shape (N,)
45 |
46 | FrameBatchOutput(
47 | int64_t numFrames,
48 | const FrameDims& outputDims,
49 | const torch::Device& device);
50 | };
51 |
52 | struct AudioFramesOutput {
53 | torch::Tensor data; // shape is (numChannels, numSamples)
54 | double ptsSeconds;
55 | };
56 |
57 | // --------------------------------------------------------------------------
58 | // FRAME TENSOR ALLOCATION APIs
59 | // --------------------------------------------------------------------------
60 |
61 | // Note [Frame Tensor allocation]
62 | //
63 | // We always allocate [N]HWC tensors. The low-level decoding functions all
64 | // assume HWC tensors, since this is what FFmpeg natively handles. It's up to
65 | // the high-level decoding entry-points to permute that back to CHW, by calling
66 | // maybePermuteHWC2CHW().
67 | torch::Tensor allocateEmptyHWCTensor(
68 | const FrameDims& frameDims,
69 | const torch::Device& device,
70 | std::optional numFrames = std::nullopt);
71 |
72 | } // namespace facebook::torchcodec
73 |
--------------------------------------------------------------------------------
/src/torchcodec/_core/StreamOptions.h:
--------------------------------------------------------------------------------
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 | #pragma once
8 |
9 | #include
10 | #include