Skip to content

Commit f551763

Browse files
authored
Remove old TODOs (meta-pytorch#1481)
1 parent dc605e9 commit f551763

3 files changed

Lines changed: 35 additions & 49 deletions

File tree

src/torchcodec/_core/SingleStreamDecoder.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,8 +1329,6 @@ bool SingleStreamDecoder::canWeAvoidSeeking() const {
13291329
if (lastDecodedAvFramePts_ == cursor_) {
13301330
// We are seeking to the exact same frame as we are currently at. Without
13311331
// caching we have to rewind back and decode the frame again.
1332-
// TODO: https://github.com/pytorch/torchcodec/issues/84 we could
1333-
// implement caching.
13341332
return false;
13351333
}
13361334
// We are seeking forwards. We can skip a seek if both the last decoded frame

src/torchcodec/encoders/_multi_stream_encoder.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,18 @@
77
from torchcodec import _core
88

99

10-
# TODO MultiStreamEncoder: the stream_index values here are per media-type,
11-
# while everywhere else in the code base (and particularly in the public decoder
12-
# APIs) they are absolute across all media types. That'll quickly becomes
13-
# confusing, and we should definitely not expose this one as-is. We should either:
14-
# - keep it private but rename it to something that's not stream_index
15-
# - make it absolute per container, if we ever want to expose it.
1610
class VideoStream:
1711
"""A video stream within an :class:`Encoder`.
1812
1913
Returned by :meth:`Encoder.add_video`. Use :meth:`add_frames` to feed
2014
video frames into this stream.
2115
"""
2216

23-
def __init__(self, encoder_tensor: Tensor, stream_index: int):
17+
def __init__(self, encoder_tensor: Tensor, stream_identifier: int):
2418
self._encoder_tensor = encoder_tensor
25-
self._stream_index = stream_index
19+
# This is a per-media-type index, not absolute across all media types,
20+
# hence why we don't call this stream_index
21+
self._stream_identifier = stream_identifier
2622

2723
def add_frames(self, frames: Tensor) -> None:
2824
"""Add video frames to this stream.
@@ -36,7 +32,7 @@ def add_frames(self, frames: Tensor) -> None:
3632
:meth:`Encoder.add_video`.
3733
"""
3834
_core.streaming_encoder_add_frames(
39-
self._encoder_tensor, frames, self._stream_index
35+
self._encoder_tensor, frames, self._stream_identifier
4036
)
4137

4238

@@ -47,9 +43,11 @@ class AudioStream:
4743
audio samples into this stream.
4844
"""
4945

50-
def __init__(self, encoder_tensor: Tensor, stream_index: int):
46+
def __init__(self, encoder_tensor: Tensor, stream_identifier: int):
5147
self._encoder_tensor = encoder_tensor
52-
self._stream_index = stream_index
48+
# This is a per-media-type index, not absolute across all media types,
49+
# hence why we don't call this stream_index
50+
self._stream_identifier = stream_identifier
5351

5452
def add_samples(self, samples: Tensor) -> None:
5553
"""Add audio samples to this stream.
@@ -61,7 +59,7 @@ def add_samples(self, samples: Tensor) -> None:
6159
match the ``num_channels`` passed to :meth:`Encoder.add_audio`.
6260
"""
6361
_core.streaming_encoder_add_samples(
64-
self._encoder_tensor, samples, self._stream_index
62+
self._encoder_tensor, samples, self._stream_identifier
6563
)
6664

6765

@@ -166,7 +164,7 @@ def add_video(
166164
device = torch.get_default_device()
167165
device = str(device)
168166
preset = str(preset) if isinstance(preset, int) else preset
169-
stream_index = _core.streaming_encoder_add_video_stream(
167+
stream_identifier = _core.streaming_encoder_add_video_stream(
170168
self._encoder_tensor,
171169
height=height,
172170
width=width,
@@ -180,7 +178,7 @@ def add_video(
180178
str(x) for k, v in (extra_options or {}).items() for x in (k, v)
181179
],
182180
)
183-
return VideoStream(self._encoder_tensor, stream_index)
181+
return VideoStream(self._encoder_tensor, stream_identifier)
184182

185183
def add_audio(
186184
self,
@@ -211,15 +209,15 @@ def add_audio(
211209
An audio stream object. Use its :meth:`~AudioStream.add_samples`
212210
method to feed samples into the stream.
213211
"""
214-
stream_index = _core.streaming_encoder_add_audio_stream(
212+
stream_identifier = _core.streaming_encoder_add_audio_stream(
215213
self._encoder_tensor,
216214
sample_rate=sample_rate,
217215
num_channels=num_channels,
218216
bit_rate=bit_rate,
219217
output_num_channels=out_num_channels,
220218
output_sample_rate=out_sample_rate,
221219
)
222-
return AudioStream(self._encoder_tensor, stream_index)
220+
return AudioStream(self._encoder_tensor, stream_identifier)
223221

224222
def open_file(self, dest: str | Path) -> "Encoder":
225223
"""Open a file for writing the encoded output.

test/test_decoders.py

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
get_ffmpeg_minor_version,
4040
get_python_version,
4141
H264_10BITS,
42-
H265_10BITS,
4342
H265_VIDEO,
4443
in_fbcode,
4544
make_video_decoder,
@@ -1643,8 +1642,6 @@ def test_10bit_gpu_fallsback_to_cpu(self):
16431642
# do the color conversion on the CPU.
16441643
# Here we just assert that the GPU results are the same as the CPU
16451644
# results.
1646-
# TODO see other TODO below in test_10bit_videos_cpu: we should validate
1647-
# the frames against a reference.
16481645
#
16491646
# This test exercises the FFmpeg CUDA interface specifically: its CPU
16501647
# fallback delegates directly to CpuDeviceInterface, so the output
@@ -1675,15 +1672,6 @@ def test_10bit_gpu_fallsback_to_cpu(self):
16751672
frames_cpu = decoder_cpu.get_frames_at(frame_indices).data
16761673
assert_frames_equal(frames_gpu.cpu(), frames_cpu)
16771674

1678-
@pytest.mark.parametrize("device", all_supported_devices())
1679-
@pytest.mark.parametrize("asset", (H264_10BITS, H265_10BITS))
1680-
def test_10bit_videos(self, device, asset):
1681-
# This just validates that we can decode 10-bit videos.
1682-
# TODO validate against the ref that the decoded frames are correct
1683-
1684-
decoder, _ = make_video_decoder(asset.path, device=device)
1685-
decoder.get_frame_at(10)
1686-
16871675
def setup_frame_mappings(tmp_path, file, stream_index):
16881676
json_path = tmp_path / "custom_frame_mappings.json"
16891677
custom_frame_mappings = NASA_VIDEO.generate_custom_frame_mappings(stream_index)
@@ -1811,20 +1799,21 @@ def test_get_frames_at_tensor_indices(self):
18111799
decoder.get_frames_played_at(torch.tensor([0, 1], dtype=torch.int))
18121800
decoder.get_frames_played_at(torch.tensor([0, 1], dtype=torch.float))
18131801

1814-
# TODONVDEC P1:
1815-
# - unskip equality assertion checks on FFMpeg4. The comparison
1816-
# checks are failing on very few pixels, e.g.:
1802+
# Note [NVDEC vs FFmpeg CUDA pixel mismatches]:
1803+
# These tests compare the NVDEC (beta) CUDA backend against the FFmpeg
1804+
# CUDA backend. There are two known sources of pixel mismatches:
18171805
#
1818-
# E Mismatched elements: 648586 / 82944000 (0.8%)
1819-
# E Greatest absolute difference: 164 at index (20, 2, 27, 96)
1820-
# E Greatest relative difference: inf at index (5, 1, 112, 186)
1806+
# 1. FFmpeg 4: small pixel differences on a few pixels (< 1%), cause
1807+
# unknown. We don't investigate further since FFmpeg 4 is not a
1808+
# priority.
18211809
#
1822-
# So we're skipping them to unblock for now, but we should call
1823-
# assert_tensor_close_on_at_least or something like that.
1824-
# - unskip equality assertion checks for MPEG4 asset. The frames are decoded
1825-
# fine, it's the color conversion that's different. The frame from the
1826-
# NVDEC interface is mapped to 709 by the matrix coefficient
1827-
# using NVCUVID while the one from the FFmpeg CUDA interface is 601.
1810+
# 2. MPEG4 asset: NVCUVID's parser reports matrix_coefficients=1
1811+
# (BT.709) for the MPEG4 asset, even though the bitstream has no
1812+
# color metadata. This is an NVIDIA-internal heuristic. FFmpeg's
1813+
# parser leaves colorspace as UNSPECIFIED, which both swscale (CPU)
1814+
# and our color conversion code treat as BT.601. So the NVDEC
1815+
# backend uses BT.709 while the FFmpeg CUDA backend (and CPU) use
1816+
# BT.601 for this asset, leading to different RGB output.
18281817

18291818
@needs_cuda
18301819
@pytest.mark.parametrize(
@@ -1864,7 +1853,7 @@ def test_nvdec_cuda_interface_get_frame_at(
18641853
for frame_index in indices:
18651854
ref_frame = ref_decoder.get_frame_at(frame_index)
18661855
nvdec_frame = nvdec_decoder.get_frame_at(frame_index)
1867-
# TODONVDEC P1 see above
1856+
# See Note [NVDEC vs FFmpeg CUDA pixel mismatches]
18681857
if ffmpeg_major_version > 5 and asset is not TEST_SRC_2_720P_MPEG4:
18691858
torch.testing.assert_close(
18701859
nvdec_frame.data, ref_frame.data, rtol=0, atol=0
@@ -1911,7 +1900,7 @@ def test_nvdec_cuda_interface_get_frames_at(
19111900

19121901
ref_frames = ref_decoder.get_frames_at(indices)
19131902
nvdec_frames = nvdec_decoder.get_frames_at(indices)
1914-
# TODONVDEC P1 see above
1903+
# See Note [NVDEC vs FFmpeg CUDA pixel mismatches]
19151904
if ffmpeg_major_version > 5 and asset is not TEST_SRC_2_720P_MPEG4:
19161905
torch.testing.assert_close(
19171906
nvdec_frames.data, ref_frames.data, rtol=0, atol=0
@@ -1954,7 +1943,7 @@ def test_nvdec_cuda_interface_get_frame_played_at(self, asset, seek_mode):
19541943
for pts in timestamps:
19551944
ref_frame = ref_decoder.get_frame_played_at(pts)
19561945
nvdec_frame = nvdec_decoder.get_frame_played_at(pts)
1957-
# TODONVDEC P1 see above
1946+
# See Note [NVDEC vs FFmpeg CUDA pixel mismatches]
19581947
if ffmpeg_major_version > 5 and asset is not TEST_SRC_2_720P_MPEG4:
19591948
torch.testing.assert_close(
19601949
nvdec_frame.data, ref_frame.data, rtol=0, atol=0
@@ -1996,7 +1985,7 @@ def test_nvdec_cuda_interface_get_frames_played_at(self, asset, seek_mode):
19961985

19971986
ref_frames = ref_decoder.get_frames_played_at(timestamps)
19981987
nvdec_frames = nvdec_decoder.get_frames_played_at(timestamps)
1999-
# TODONVDEC P1 see above
1988+
# See Note [NVDEC vs FFmpeg CUDA pixel mismatches]
20001989
if ffmpeg_major_version > 5 and asset is not TEST_SRC_2_720P_MPEG4:
20011990
torch.testing.assert_close(
20021991
nvdec_frames.data, ref_frames.data, rtol=0, atol=0
@@ -2043,7 +2032,7 @@ def test_nvdec_cuda_interface_backwards(self, asset, seek_mode):
20432032

20442033
ref_frame = ref_decoder.get_frame_at(frame_index)
20452034
nvdec_frame = nvdec_decoder.get_frame_at(frame_index)
2046-
# TODONVDEC P1 see above
2035+
# See Note [NVDEC vs FFmpeg CUDA pixel mismatches]
20472036
if ffmpeg_major_version > 5 and asset is not TEST_SRC_2_720P_MPEG4:
20482037
torch.testing.assert_close(
20492038
nvdec_frame.data, ref_frame.data, rtol=0, atol=0
@@ -2071,8 +2060,9 @@ def test_cuda_mpeg4_mp4_first_frame(self, seek_mode):
20712060
assert frame0.pts_seconds == expected_frame0.pts_seconds
20722061
assert frame0.duration_seconds == expected_frame0.duration_seconds
20732062
assert frame0.data.shape == expected_frame0.data.shape
2074-
# Strict pixel equality is skipped — TODONVDEC P1 above (BT.601 vs
2075-
# BT.709 color matrix mismatch between the ffmpeg and default cuda).
2063+
# Strict pixel equality is skipped — see Note [NVDEC vs FFmpeg CUDA
2064+
# pixel mismatches] (BT.601 vs BT.709 color matrix mismatch between the
2065+
# ffmpeg and default cuda backend for this MPEG4 asset).
20762066

20772067
@needs_cuda
20782068
def test_nvdec_cuda_interface_cpu_fallback(self):

0 commit comments

Comments
 (0)