@@ -255,6 +255,79 @@ def _is_ffmpeg4():
255255 return vers ["libavutil" ][0 ] < 57
256256
257257
258+ class TestNvdecStateIsolation (unittest .TestCase ):
259+ def test_decoder_state_isolation_crop_resize (self ) -> None :
260+ """Test that decoder state is properly reset between uses.
261+
262+ This test verifies that crop/resize parameters from one decoding
263+ operation don't leak into subsequent operations when using the
264+ cached thread-local decoder.
265+
266+ Without proper reset(), running a decode with crop+resize followed
267+ by a decode with only crop would incorrectly apply the previous
268+ resize parameters.
269+
270+ See https://github.com/facebookresearch/spdl/issues/1159
271+ """
272+ h264 = _get_h264_sample ()
273+
274+ # First decode: crop + resize
275+ top1 , bottom1 , left1 , right1 = 40 , 80 , 100 , 60
276+ h1 = (240 - top1 - bottom1 ) // 2
277+ w1 = (320 - left1 - right1 ) // 2
278+
279+ array1 = _decode_video (
280+ h264 .path ,
281+ timestamp = (0.0 , 1.0 ),
282+ crop_top = top1 ,
283+ crop_bottom = bottom1 ,
284+ crop_left = left1 ,
285+ crop_right = right1 ,
286+ width = w1 ,
287+ height = h1 ,
288+ )
289+
290+ self .assertEqual (array1 .shape , (25 , 3 , h1 , w1 ))
291+
292+ # Second decode: only crop (no resize)
293+ # This should NOT be affected by the previous resize parameters
294+ top2 , bottom2 , left2 , right2 = 40 , 80 , 100 , 50
295+ h2 = 240 - top2 - bottom2
296+ w2 = 320 - left2 - right2
297+
298+ array2 = _decode_video (
299+ h264 .path ,
300+ timestamp = (0.0 , 1.0 ),
301+ crop_top = top2 ,
302+ crop_bottom = bottom2 ,
303+ crop_left = left2 ,
304+ crop_right = right2 ,
305+ )
306+
307+ # Verify the second decode has the correct dimensions
308+ # (not affected by the first decode's resize)
309+ self .assertEqual (
310+ array2 .shape ,
311+ (25 , 3 , h2 , w2 ),
312+ f"Expected shape (25, 3, { h2 } , { w2 } ) but got { array2 .shape } . "
313+ "This indicates state leakage from previous decode operation." ,
314+ )
315+
316+ # Also verify against a reference decode with the same crop parameters
317+ array_ref = _decode_video (
318+ h264 .path ,
319+ timestamp = (0.0 , 1.0 ),
320+ )
321+
322+ for i in range (3 ):
323+ torch .testing .assert_close (
324+ array2 [:, i ],
325+ array_ref [:, i , top2 : top2 + h2 , left2 : left2 + w2 ],
326+ msg = f"Channel { i } content mismatch. "
327+ "This indicates incorrect crop/resize was applied." ,
328+ )
329+
330+
258331class TestColorConversion (unittest .TestCase ):
259332 @unittest .skipIf (_is_ffmpeg4 (), "FFmpeg4 is known to return a different result." )
260333 def test_color_conversion_rgba (self ) -> None :
0 commit comments