From 4f99968d39a68dd419656136dc9fad2cd5ccaec3 Mon Sep 17 00:00:00 2001 From: moto <855818+mthrok@users.noreply.github.com> Date: Thu, 9 Jan 2025 17:38:59 -0500 Subject: [PATCH] Remove async Io from test --- src/spdl/io/__init__.py | 2 + src/spdl/io/_composite.py | 68 ++---- tests/spdl_unittest/io/async_test.py | 151 ++++++------- .../io/buffer_conversion_refcount_test.py | 15 +- .../io/concurrent_audio_decoding_test.py | 40 +--- .../io/concurrent_image_decoding_test.py | 44 ++-- tests/spdl_unittest/io/configs_test.py | 53 ++--- tests/spdl_unittest/io/encoding_test.py | 32 ++- tests/spdl_unittest/io/frames_clone_test.py | 64 +++--- tests/spdl_unittest/io/frames_test.py | 11 +- tests/spdl_unittest/io/packets_test.py | 212 ++++++++---------- .../io/streaming_video_decoding_test.py | 108 ++++----- .../io/video_frame_slice_test.py | 15 +- .../io/zero_copy_bytes_passing_test.py | 71 +++--- 14 files changed, 361 insertions(+), 525 deletions(-) diff --git a/src/spdl/io/__init__.py b/src/spdl/io/__init__.py index 79a61fcd..f63bce59 100644 --- a/src/spdl/io/__init__.py +++ b/src/spdl/io/__init__.py @@ -33,6 +33,7 @@ from ._composite import ( load_audio, load_image, + load_image_batch, load_image_batch_nvjpeg, load_video, sample_decode_video, @@ -80,6 +81,7 @@ "load_audio", "load_video", "load_image", + "load_image_batch", "load_image_batch_nvjpeg", "sample_decode_video", # DEMUXING diff --git a/src/spdl/io/_composite.py b/src/spdl/io/_composite.py index 45547097..014bf813 100644 --- a/src/spdl/io/_composite.py +++ b/src/spdl/io/_composite.py @@ -19,7 +19,6 @@ CUDAConfig, DecodeConfig, DemuxConfig, - ImageFrames, ImagePackets, VideoPackets, ) @@ -32,6 +31,7 @@ "load_audio", "load_video", "load_image", + "load_image_batch", "load_image_batch_nvjpeg", "sample_decode_video", ] @@ -404,7 +404,7 @@ def _decode(src, demux_config, decode_config, filter_desc): @overload -async def async_load_image_batch( +def load_image_batch( srcs: list[str | bytes], *, width: int | None, @@ -421,7 +421,7 @@ async def async_load_image_batch( @overload -async def async_load_image_batch( +def load_image_batch( srcs: list[str | bytes], *, width: int | None, @@ -437,7 +437,7 @@ async def async_load_image_batch( ) -> CUDABuffer: ... -async def async_load_image_batch( +def load_image_batch( srcs: list[str | bytes], *, width, @@ -458,32 +458,6 @@ async def async_load_image_batch( and optionally, :py:func:`~spdl.io.transfer_buffer`, to produce buffer object from source in one step. - It concurrently demuxes and decodes the input images, using - the :py:class:`~concurrent.futures.ThreadPoolExecutor` attached to - the running async event loop, fetched by :py:func:`~asyncio.get_running_loop`. - - .. mermaid:: - - gantt - title Illustration of asynchronous batch image decoding timeline - dateFormat X - axisFormat %s - section Thread 1 - Demux image 1 :demux1, 0, 3 - Decode/resize image 1 :after demux1, 20 - section Thread 2 - Demux image 2 :demux2, 1, 5 - Decode/resize image 2 :after demux2, 23 - section Thread 3 - Demux image 3 :demux3, 2, 5 - Decode/resize image 3 :after demux3, 24 - section Thread 4 - Demux image 4 :demux4, 3, 8 - Decode/resize image 4 :decode4, after demux4, 25 - section Thread 5 - Batch conversion :batch, after decode4, 30 - Device Transfer :after batch, 33 - Args: srcs: List of source identifiers. @@ -496,25 +470,25 @@ async def async_load_image_batch( demux_config: *Optional:* Demux configuration passed to - :py:func:`~spdl.io.async_demux_image`. + :py:func:`~spdl.io.demux_image`. decode_config: *Optional:* Decode configuration passed to - :py:func:`~spdl.io.async_decode_packets`. + :py:func:`~spdl.io.decode_packets`. filter_desc: *Optional:* Filter description passed to - :py:func:`~spdl.io.async_decode_packets`. + :py:func:`~spdl.io.decode_packets`. device_config: *Optional:* The CUDA device passed to - :py:func:`~spdl.io.async_transfer_buffer`. + :py:func:`~spdl.io.transfer_buffer`. Providing this argument will move the resulting buffer to the CUDA device. storage: *Optional:* The storage object passed to - :py:func:`~spdl.io.async_convert_frames`. + :py:func:`~spdl.io.convert_frames`. strict: *Optional:* If True, raise an error if any of the images failed to load. @@ -528,13 +502,12 @@ async def async_load_image_batch( ... "sample1.jpg", ... "sample2.png", ... ] - >>> coro = async_load_image_batch( + >>> buffer = load_image_batch( ... srcs, ... scale_width=124, ... scale_height=96, ... pix_fmt="rgb24", ... ) - >>> buffer = asyncio.run(coro) >>> array = spdl.io.to_numpy(buffer) >>> # An array with shape HWC==[2, 96, 124, 3] >>> @@ -563,23 +536,14 @@ async def async_load_image_batch( pix_fmt=pix_fmt, ) - tasks = [ - asyncio.create_task( - run_async(_decode, src, demux_config, decode_config, filter_desc) - ) - for src in srcs - ] - - await asyncio.wait(tasks) - - frames: list[ImageFrames] = [] - for src, future in zip(srcs, tasks): + frames = [] + for src in srcs: try: - frms = future.result() + frame = _decode(src, demux_config, decode_config, filter_desc) except Exception as err: _LG.error(_get_err_msg(src, err)) else: - frames.append(frms) + frames.append(frame) if strict and len(frames) != len(srcs): raise RuntimeError("Failed to load some images.") @@ -587,10 +551,10 @@ async def async_load_image_batch( if not frames: raise RuntimeError("Failed to load all the images.") - buffer = await _core.async_convert_frames(frames, storage=storage) + buffer = _core.convert_frames(frames, storage=storage) if device_config is not None: - buffer = await _core.async_transfer_buffer(buffer, device_config=device_config) + buffer = _core.transfer_buffer(buffer, device_config=device_config) return buffer diff --git a/tests/spdl_unittest/io/async_test.py b/tests/spdl_unittest/io/async_test.py index b203c907..96572a1e 100644 --- a/tests/spdl_unittest/io/async_test.py +++ b/tests/spdl_unittest/io/async_test.py @@ -4,7 +4,7 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio +import time import numpy as np import pytest @@ -21,29 +21,30 @@ def test_failure(): spdl.io.Demuxer("dvkgviuerehidguburuekkhgjijfjbkj") -async def _decode_packet(packets): - frames = await spdl.io.async_decode_packets(packets) +def _decode_packet(packets): + frames = spdl.io.decode_packets(packets) print(frames) - buffer = await spdl.io.async_convert_frames(frames) + buffer = spdl.io.convert_frames(frames) print(buffer) array = spdl.io.to_numpy(buffer) print(array.shape, array.dtype) return array -async def _test_async_decode(demux_fn, timestamps): +def _test_decode(demux_fn, timestamps): # There was a case where the underlying file device was delayed, and the # generated sample file is not ready when the test is started, so # sleeping here for 1 second to make sure the file is ready. - await asyncio.sleep(1) + time.sleep(1) - tasks = [] + frames = [] for timestamp in timestamps: packets = demux_fn(timestamp) print(packets) - tasks.append(asyncio.create_task(_decode_packet(packets))) + frames_ = _decode_packet(packets) + frames.append(frames_) - return await asyncio.gather(*tasks) + return frames def test_decode_audio_clips(get_sample): @@ -51,10 +52,10 @@ def test_decode_audio_clips(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i 'sine=frequency=1000:sample_rate=48000:duration=3' -c:a pcm_s16le sample.wav" sample = get_sample(cmd) - async def _test(): + def _test(): timestamps = [(i, i + 1) for i in range(2)] demuxer = spdl.io.Demuxer(sample.path) - arrays = await _test_async_decode(demuxer.demux_audio, timestamps) + arrays = _test_decode(demuxer.demux_audio, timestamps) assert len(arrays) == 2 for i, arr in enumerate(arrays): @@ -62,7 +63,7 @@ async def _test(): assert arr.shape == (1, 48000) assert arr.dtype == np.float32 - asyncio.run(_test()) + _test() def test_decode_audio_clips_num_frames(get_sample): @@ -70,37 +71,35 @@ def test_decode_audio_clips_num_frames(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i 'sine=frequency=1000:sample_rate=16000:duration=1' -c:a pcm_s16le sample.wav" sample = get_sample(cmd) - async def _decode(src, num_frames=None): + def _decode(src, num_frames=None): with spdl.io.Demuxer(src) as demuxer: packets = demuxer.demux_audio(window=(0, 1)) filter_desc = get_audio_filter_desc( timestamp=(0, 1), num_frames=num_frames, sample_fmt="s16" ) - frames = await spdl.io.async_decode_packets( - packets, filter_desc=filter_desc - ) - buffer = await spdl.io.async_convert_frames(frames) + frames = spdl.io.decode_packets(packets, filter_desc=filter_desc) + buffer = spdl.io.convert_frames(frames) return spdl.io.to_numpy(buffer) - async def _test(src): - arr0 = await _decode(src) + def _test(src): + arr0 = _decode(src) assert arr0.dtype == np.int16 assert arr0.shape == (16000, 1) num_frames = 8000 - arr1 = await _decode(src, num_frames=num_frames) + arr1 = _decode(src, num_frames=num_frames) assert arr1.dtype == np.int16 assert arr1.shape == (num_frames, 1) assert np.all(arr1 == arr0[:num_frames]) num_frames = 32000 - arr2 = await _decode(src, num_frames=num_frames) + arr2 = _decode(src, num_frames=num_frames) assert arr2.dtype == np.int16 assert arr2.shape == (num_frames, 1) assert np.all(arr2[:16000] == arr0) assert np.all(arr2[16000:] == 0) - asyncio.run(_test(sample.path)) + _test(sample.path) def test_decode_video_clips(get_sample): @@ -109,17 +108,17 @@ def test_decode_video_clips(get_sample): sample = get_sample(cmd, width=320, height=240) N = 10 - async def _test(): + def _test(): timestamps = [(i, i + 1) for i in range(N)] demuxer = spdl.io.Demuxer(sample.path) - arrays = await _test_async_decode(demuxer.demux_video, timestamps) + arrays = _test_decode(demuxer.demux_video, timestamps) assert len(arrays) == N for i, arr in enumerate(arrays): print(i, arr.shape, arr.dtype) assert arr.shape == (25, 240, 320, 3) assert arr.dtype == np.uint8 - asyncio.run(_test()) + _test() def test_decode_video_clips_num_frames(get_sample): @@ -130,51 +129,49 @@ def test_decode_video_clips_num_frames(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 50 sample.mp4" sample = get_sample(cmd) - async def _decode(src, pix_fmt="rgb24", **kwargs): + def _decode(src, pix_fmt="rgb24", **kwargs): with spdl.io.Demuxer(src) as demuxer: packets = demuxer.demux_video(window=(0, 2)) filter_desc = get_video_filter_desc( timestamp=(0, 2), pix_fmt=pix_fmt, **kwargs ) - frames = await spdl.io.async_decode_packets( - packets, filter_desc=filter_desc - ) - buffer = await spdl.io.async_convert_frames(frames) + frames = spdl.io.decode_packets(packets, filter_desc=filter_desc) + buffer = spdl.io.convert_frames(frames) return spdl.io.to_numpy(buffer) - async def _test(src): - arr0 = await _decode(src) + def _test(src): + arr0 = _decode(src) assert arr0.dtype == np.uint8 assert arr0.shape == (50, 240, 320, 3) num_frames = 25 - arr1 = await _decode(src, num_frames=num_frames) + arr1 = _decode(src, num_frames=num_frames) assert arr1.dtype == np.uint8 assert arr1.shape == (num_frames, 240, 320, 3) assert np.all(arr1 == arr0[:num_frames]) num_frames = 100 - arr2 = await _decode(src, num_frames=num_frames) + arr2 = _decode(src, num_frames=num_frames) assert arr2.dtype == np.uint8 assert arr2.shape == (num_frames, 240, 320, 3) assert np.all(arr2[:50] == arr0) assert np.all(arr2[50:] == arr2[50]) num_frames = 100 - arr2 = await _decode(src, num_frames=num_frames, pad_mode="black") + arr2 = _decode(src, num_frames=num_frames, pad_mode="black") assert arr2.dtype == np.uint8 assert arr2.shape == (num_frames, 240, 320, 3) assert np.all(arr2[:50] == arr0) assert np.all(arr2[50:] == 0) num_frames = 100 - arr2 = await _decode(src, num_frames=num_frames, pad_mode="white") + arr2 = _decode(src, num_frames=num_frames, pad_mode="white") assert arr2.dtype == np.uint8 assert arr2.shape == (num_frames, 240, 320, 3) assert np.all(arr2[:50] == arr0) assert np.all(arr2[50:] == 255) - asyncio.run(_test(sample.path)) + _test(sample.path) def test_decode_video_frame_rate_pts(get_sample): @@ -182,10 +179,10 @@ def test_decode_video_frame_rate_pts(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -r 10 -frames:v 20 sample.mp4" sample = get_sample(cmd) - async def _test(src): - packets = await spdl.io.async_demux_video(src) - frames_ref = await spdl.io.async_decode_packets(packets.clone()) - frames = await spdl.io.async_decode_packets( + def _test(src): + packets = spdl.io.demux_video(src) + frames_ref = spdl.io.decode_packets(packets.clone()) + frames = spdl.io.decode_packets( packets, filter_desc=get_video_filter_desc(frame_rate=(5, 1)) ) @@ -195,20 +192,20 @@ async def _test(src): assert np.all(pts_ref[::2] == pts) - asyncio.run(_test(sample.path)) + _test(sample.path) -async def _decode_image(path): - packets = await spdl.io.async_demux_image(path) +def _decode_image(path): + packets = spdl.io.demux_image(path) print(packets) - frames = await spdl.io.async_decode_packets(packets) + frames = spdl.io.decode_packets(packets) print(frames) assert type(frames) is _libspdl.FFmpegImageFrames return frames -async def _batch_decode_image(paths): - return await asyncio.gather(*[_decode_image(path) for path in paths]) +def _batch_decode_image(paths): + return [_decode_image(path) for path in paths] def test_decode_image(get_sample): @@ -216,14 +213,14 @@ def test_decode_image(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 1 sample.jpg" sample = get_sample(cmd, width=320, height=240) - async def _test(src): - buffer = await spdl.io.async_load_image(src) + def _test(src): + buffer = spdl.io.load_image(src) array = spdl.io.to_numpy(buffer) print(array.shape, array.dtype) assert array.dtype == np.uint8 assert array.shape == (240, 320, 3) - asyncio.run(_test(sample.path)) + _test(sample.path) def test_batch_decode_image(get_samples): @@ -233,74 +230,74 @@ def test_batch_decode_image(get_samples): flist = ["NON_EXISTING_FILE.JPG", *samples] - async def _test(): - buffer = await spdl.io.async_load_image_batch( + def _test(): + buffer = spdl.io.load_image_batch( flist, width=None, height=None, pix_fmt=None, strict=False ) assert buffer.__array_interface__["shape"] == (250, 3, 240, 320) - asyncio.run(_test()) + _test() -def test_async_convert_audio(get_sample): - """async_convert_frames can convert FFmpegAudioFrames to Buffer""" +def test_convert_audio(get_sample): + """convert_frames can convert FFmpegAudioFrames to Buffer""" cmd = "ffmpeg -hide_banner -y -f lavfi -i 'sine=frequency=1000:sample_rate=48000:duration=3' -c:a pcm_s16le sample.wav" sample = get_sample(cmd) - async def _test(src): + def _test(src): ts = [(1, 2)] demuxer = spdl.io.Demuxer(src) - arrays = await _test_async_decode(demuxer.demux_audio, ts) + arrays = _test_decode(demuxer.demux_audio, ts) array = arrays[0] print(array.dtype, array.shape) assert array.shape == (1, 48000) - asyncio.run(_test(sample.path)) + _test(sample.path) -def test_async_convert_video(get_sample): - """async_convert_frames can convert FFmpegVideoFrames to Buffer""" +def test_convert_video(get_sample): + """convert_frames can convert FFmpegVideoFrames to Buffer""" cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 1000 sample.mp4" sample = get_sample(cmd, width=320, height=240) - async def _test(src): - packets = await spdl.io.async_demux_video(src) - frames = await spdl.io.async_decode_packets(packets) - buffer = await spdl.io.async_convert_frames(frames) + def _test(src): + packets = spdl.io.demux_video(src) + frames = spdl.io.decode_packets(packets) + buffer = spdl.io.convert_frames(frames) array = spdl.io.to_numpy(buffer) print(array.dtype, array.shape) assert array.shape == (1000, 240, 320, 3) - asyncio.run(_test(sample.path)) + _test(sample.path) -def test_async_convert_image(get_sample): - """async_convert_frames can convert FFmpegImageFrames to Buffer""" +def test_convert_image(get_sample): + """convert_frames can convert FFmpegImageFrames to Buffer""" cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 1 sample.jpg" sample = get_sample(cmd, width=320, height=240) - async def _test(src): - frames = await _decode_image(src) - buffer = await spdl.io.async_convert_frames(frames) + def _test(src): + frames = _decode_image(src) + buffer = spdl.io.convert_frames(frames) print(buffer) arr = spdl.io.to_numpy(buffer) print(arr.dtype, arr.shape) assert arr.shape == (240, 320, 3) - asyncio.run(_test(sample.path)) + _test(sample.path) -def test_async_convert_batch_image(get_samples): - """async_convert_frames can convert list[FFmpegImageFrames] to Buffer""" +def test_convert_batch_image(get_samples): + """convert_frames can convert list[FFmpegImageFrames] to Buffer""" cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 4 sample_%03d.jpg" flist = get_samples(cmd) - async def _test(flist): - frames = await _batch_decode_image(flist) - buffer = await spdl.io.async_convert_frames(frames) + def _test(flist): + frames = _batch_decode_image(flist) + buffer = spdl.io.convert_frames(frames) print(buffer) arr = spdl.io.to_numpy(buffer) print(arr.dtype, arr.shape) assert arr.shape == (4, 240, 320, 3) - asyncio.run(_test(flist)) + _test(flist) diff --git a/tests/spdl_unittest/io/buffer_conversion_refcount_test.py b/tests/spdl_unittest/io/buffer_conversion_refcount_test.py index 457fc20a..4c497181 100644 --- a/tests/spdl_unittest/io/buffer_conversion_refcount_test.py +++ b/tests/spdl_unittest/io/buffer_conversion_refcount_test.py @@ -4,7 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio import gc import sys @@ -14,15 +13,6 @@ from spdl.io import get_video_filter_desc -def _decode_video(src, pix_fmt=None): - return asyncio.run( - spdl.io.async_load_video( - src, - filter_desc=get_video_filter_desc(pix_fmt=pix_fmt), - ) - ) - - def test_buffer_conversion_refcount(get_sample): """NumPy array created from Buffer should increment a reference to the buffer so that array keeps working after the original Buffer variable is deleted. @@ -30,7 +20,10 @@ def test_buffer_conversion_refcount(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc,format=yuv420p -frames:v 100 sample.mp4" sample = get_sample(cmd, width=320, height=240) - buf = _decode_video(sample.path, pix_fmt="rgb24") + buf = spdl.io.load_video( + sample.path, + filter_desc=get_video_filter_desc(pix_fmt="rgb24"), + ) assert hasattr(buf, "__array_interface__") print(f"{buf.__array_interface__=}") diff --git a/tests/spdl_unittest/io/concurrent_audio_decoding_test.py b/tests/spdl_unittest/io/concurrent_audio_decoding_test.py index 7a83e340..30697721 100644 --- a/tests/spdl_unittest/io/concurrent_audio_decoding_test.py +++ b/tests/spdl_unittest/io/concurrent_audio_decoding_test.py @@ -4,7 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio import numpy as np import pytest @@ -13,15 +12,6 @@ from spdl.io import get_audio_filter_desc, get_filter_desc -def _decode_audio(src, sample_fmt=None): - buffer = asyncio.run( - spdl.io.async_load_audio( - src, filter_desc=get_audio_filter_desc(sample_fmt=sample_fmt) - ) - ) - return spdl.io.to_numpy(buffer) - - @pytest.mark.parametrize( "sample_fmts", [("s16p", "int16"), ("s16", "int16"), ("fltp", "float32"), ("flt", "float32")], @@ -38,7 +28,9 @@ def test_audio_buffer_conversion_s16p(sample_fmts, get_sample): sample = get_sample(cmd) sample_fmt, expected = sample_fmts - array = _decode_audio(src=sample.path, sample_fmt=sample_fmt) + filter_desc = get_audio_filter_desc(sample_fmt=sample_fmt) + buffer = spdl.io.load_audio(src=sample.path, filter_desc=filter_desc) + array = spdl.io.to_numpy(buffer) assert array.ndim == 2 assert array.dtype == np.dtype(expected) @@ -59,22 +51,14 @@ def test_batch_audio_conversion(get_sample): timestamps = [(0, 1), (1, 1.5), (2, 2.7)] - async def _test(): - decoding = [] - - demuxer = spdl.io.Demuxer(sample.path) - for ts in timestamps: - packets = demuxer.demux_audio(ts) - filter_desc = get_filter_desc(packets, num_frames=8_000) - coro = spdl.io.async_decode_packets(packets, filter_desc=filter_desc) - decoding.append(asyncio.create_task(coro)) - - frames = await asyncio.gather(*decoding) - - buffer = await spdl.io.async_convert_frames(frames) - array = spdl.io.to_numpy(buffer) - return array - - array = asyncio.run(_test()) + frames = [] + demuxer = spdl.io.Demuxer(sample.path) + for ts in timestamps: + packets = demuxer.demux_audio(ts) + filter_desc = get_filter_desc(packets, num_frames=8_000) + frames_ = spdl.io.decode_packets(packets, filter_desc=filter_desc) + frames.append(frames_) + buffer = spdl.io.convert_frames(frames) + array = spdl.io.to_numpy(buffer) assert array.shape == (3, 2, 8000) diff --git a/tests/spdl_unittest/io/concurrent_image_decoding_test.py b/tests/spdl_unittest/io/concurrent_image_decoding_test.py index 2a7f78ec..d290f78a 100644 --- a/tests/spdl_unittest/io/concurrent_image_decoding_test.py +++ b/tests/spdl_unittest/io/concurrent_image_decoding_test.py @@ -4,8 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio - import numpy as np import pytest import spdl.io @@ -14,19 +12,15 @@ def _decode_image(src, pix_fmt=None): - buffer = asyncio.run( - spdl.io.async_load_image( - src, - filter_desc=get_video_filter_desc(pix_fmt=pix_fmt), - ) + buffer = spdl.io.load_image( + src, + filter_desc=get_video_filter_desc(pix_fmt=pix_fmt), ) return spdl.io.to_numpy(buffer) def _batch_load_image(srcs, pix_fmt="rgb24"): - buffer = asyncio.run( - spdl.io.async_load_image_batch(srcs, width=None, height=None, pix_fmt=pix_fmt) - ) + buffer = spdl.io.load_image_batch(srcs, width=None, height=None, pix_fmt=pix_fmt) return spdl.io.to_numpy(buffer) @@ -162,7 +156,8 @@ def test_batch_decode_image_slice(get_samples): n, h, w = 32, 240, 320 flist = get_samples(cmd) - array = _batch_load_image(flist, pix_fmt="rgb24") + buffer = spdl.io.load_image_batch(flist, width=None, height=None, pix_fmt="rgb24") + array = spdl.io.to_numpy(buffer) print(array.shape) assert array.shape == (n, h, w, 3) @@ -186,7 +181,8 @@ def test_batch_decode_image_rgb24(get_samples): # fmt: on flist = get_samples(cmd) - arrays = _batch_load_image(flist, pix_fmt="rgb24") + buffer = spdl.io.load_image_batch(flist, width=None, height=None, pix_fmt="rgb24") + arrays = spdl.io.to_numpy(buffer) assert arrays.shape == (32, h, 3 * w, 3) for i in range(32): @@ -221,20 +217,14 @@ def test_batch_video_conversion(get_sample): timestamps = [(0, 1), (1, 1.5), (2, 2.7), (3, 3.6)] - async def _test(): - decoding = [] - async for packets in spdl.io.async_streaming_demux_video( - src=sample.path, timestamps=timestamps - ): - filter_desc = get_filter_desc(packets, num_frames=15) - coro = spdl.io.async_decode_packets(packets, filter_desc=filter_desc) - decoding.append(asyncio.create_task(coro)) - - frames = await asyncio.gather(*decoding) - - buffer = await spdl.io.async_convert_frames(frames) - return spdl.io.to_numpy(buffer) - - array = asyncio.run(_test()) + demuxer = spdl.io.Demuxer(sample.path) + frames = [] + for ts in timestamps: + packets = demuxer.demux_video(timestamp=ts) + filter_desc = get_filter_desc(packets, num_frames=15) + frames_ = spdl.io.decode_packets(packets, filter_desc=filter_desc) + frames.append(frames_) + buffer = spdl.io.convert_frames(frames) + array = spdl.io.to_numpy(buffer) assert array.shape == (4, 15, 3, 240, 320) diff --git a/tests/spdl_unittest/io/configs_test.py b/tests/spdl_unittest/io/configs_test.py index fb9c809e..35a8a865 100644 --- a/tests/spdl_unittest/io/configs_test.py +++ b/tests/spdl_unittest/io/configs_test.py @@ -4,8 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio - import pytest import spdl.io @@ -15,20 +13,17 @@ def test_demux_config_smoketest(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i 'sine=frequency=1000:sample_rate=48000:duration=3' -c:a pcm_s16le sample.wav" sample = get_sample(cmd) - async def _test(src): - demux_config = spdl.io.demux_config() - _ = await spdl.io.async_demux_audio(src, demux_config=demux_config) - - demux_config = spdl.io.demux_config(format="wav") - _ = await spdl.io.async_demux_audio(src, demux_config=demux_config) + demux_config = spdl.io.demux_config() + _ = spdl.io.demux_audio(sample.path, demux_config=demux_config) - demux_config = spdl.io.demux_config(format_options={"ignore_length": "true"}) - _ = await spdl.io.async_demux_audio(src, demux_config=demux_config) + demux_config = spdl.io.demux_config(format="wav") + _ = spdl.io.demux_audio(sample.path, demux_config=demux_config) - demux_config = spdl.io.demux_config(buffer_size=1024) - _ = await spdl.io.async_demux_audio(src, demux_config=demux_config) + demux_config = spdl.io.demux_config(format_options={"ignore_length": "true"}) + _ = spdl.io.demux_audio(sample.path, demux_config=demux_config) - asyncio.run(_test(sample.path)) + demux_config = spdl.io.demux_config(buffer_size=1024) + _ = spdl.io.demux_audio(sample.path, demux_config=demux_config) def test_demux_config_headless(get_sample): @@ -36,14 +31,11 @@ def test_demux_config_headless(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i 'sine=frequency=1000:sample_rate=48000:duration=3' -f s16le -c:a pcm_s16le sample.raw" sample = get_sample(cmd) - async def _test(src): - with pytest.raises(RuntimeError): - await spdl.io.async_demux_audio(src) + with pytest.raises(RuntimeError): + spdl.io.demux_audio(sample.path) - demux_config = spdl.io.demux_config(format="s16le") - _ = await spdl.io.async_demux_audio(src, demux_config=demux_config) - - asyncio.run(_test(sample.path)) + demux_config = spdl.io.demux_config(format="s16le") + _ = spdl.io.demux_audio(sample.path, demux_config=demux_config) def test_decode_config_smoketest(get_sample): @@ -51,18 +43,15 @@ def test_decode_config_smoketest(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 1000 sample.mp4" sample = get_sample(cmd) - async def _test(src): - packets = await spdl.io.async_demux_video(src) - - cfg = spdl.io.decode_config() - _ = await spdl.io.async_decode_packets(packets.clone(), decode_config=cfg) + packets = spdl.io.demux_video(sample.path) - cfg = spdl.io.decode_config(decoder="h264") - _ = await spdl.io.async_decode_packets(packets.clone(), decode_config=cfg) + cfg = spdl.io.decode_config() + _ = spdl.io.decode_packets(packets.clone(), decode_config=cfg) - cfg = spdl.io.decode_config( - decoder="h264", decoder_options={"nal_length_size": "4"} - ) - _ = await spdl.io.async_decode_packets(packets.clone(), decode_config=cfg) + cfg = spdl.io.decode_config(decoder="h264") + _ = spdl.io.decode_packets(packets.clone(), decode_config=cfg) - asyncio.run(_test(sample.path)) + cfg = spdl.io.decode_config( + decoder="h264", decoder_options={"nal_length_size": "4"} + ) + _ = spdl.io.decode_packets(packets.clone(), decode_config=cfg) diff --git a/tests/spdl_unittest/io/encoding_test.py b/tests/spdl_unittest/io/encoding_test.py index 9466e9e3..10a44d76 100644 --- a/tests/spdl_unittest/io/encoding_test.py +++ b/tests/spdl_unittest/io/encoding_test.py @@ -4,7 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio from itertools import product from tempfile import NamedTemporaryFile @@ -29,47 +28,44 @@ def test_encode_smoketest(fmt, enc_cfg): shape, pix_fmt = fmt data = np.random.randint(255, size=shape, dtype=np.uint8) - async def _test(arr): + def _test(arr): with NamedTemporaryFile(suffix=".png") as f: - await spdl.io.async_encode_image( + spdl.io.encode_image( f.name, arr, pix_fmt=pix_fmt, encode_config=enc_cfg, ) - asyncio.run(_test(data)) - asyncio.run(_test(torch.from_numpy(data))) + _test(data) + _test(torch.from_numpy(data)) def test_encode_png_gray16be(): data = np.random.randint(256, size=(32, 64), dtype=np.uint16) enc_cfg = spdl.io.encode_config(format="gray16be") - async def _test(arr): + def _test(arr): with NamedTemporaryFile(suffix=".png") as f: - await spdl.io.async_encode_image( + spdl.io.encode_image( f.name, arr, pix_fmt="gray16", encode_config=enc_cfg, ) - asyncio.run(_test(data)) + _test(data) def _test_rejects(pix_fmt, dtype): - async def _test(arr): - with NamedTemporaryFile(suffix=".png") as f: - with pytest.raises(RuntimeError): - await spdl.io.async_encode_image( - f.name, - arr, - pix_fmt=pix_fmt, - ) - data = np.ones((32, 64), dtype=dtype) - asyncio.run(_test(data)) + with NamedTemporaryFile(suffix=".png") as f: + with pytest.raises(RuntimeError): + spdl.io.encode_image( + f.name, + data, + pix_fmt=pix_fmt, + ) @pytest.mark.parametrize( diff --git a/tests/spdl_unittest/io/frames_clone_test.py b/tests/spdl_unittest/io/frames_clone_test.py index ee72c0f5..f6c2f074 100644 --- a/tests/spdl_unittest/io/frames_clone_test.py +++ b/tests/spdl_unittest/io/frames_clone_test.py @@ -4,8 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio - import numpy as np import pytest import spdl.io @@ -17,8 +15,8 @@ } -async def _load_from_frames(frames): - buffer = await spdl.io.async_convert_frames(frames) +def _load_from_frames(frames): + buffer = spdl.io.convert_frames(frames) return spdl.io.to_numpy(buffer) @@ -29,21 +27,18 @@ def test_clone_frames(media_type, get_sample): sample = get_sample(cmd) demux_func = { - "audio": spdl.io.async_demux_audio, - "video": spdl.io.async_demux_video, - "image": spdl.io.async_demux_image, + "audio": spdl.io.demux_audio, + "video": spdl.io.demux_video, + "image": spdl.io.demux_image, }[media_type] - async def _test(src): - frames1 = await spdl.io.async_decode_packets(await demux_func(src)) - frames2 = frames1.clone() - - array1 = await _load_from_frames(frames1) - array2 = await _load_from_frames(frames2) + frames1 = spdl.io.decode_packets(demux_func(sample.path)) + frames2 = frames1.clone() - assert np.all(array1 == array2) + array1 = _load_from_frames(frames1) + array2 = _load_from_frames(frames2) - asyncio.run(_test(sample.path)) + assert np.all(array1 == array2) @pytest.mark.parametrize("media_type", ["audio", "video", "image"]) @@ -53,18 +48,15 @@ def test_clone_invalid_frames(media_type, get_sample): sample = get_sample(cmd) demux_func = { - "audio": spdl.io.async_demux_audio, - "video": spdl.io.async_demux_video, - "image": spdl.io.async_demux_image, + "audio": spdl.io.demux_audio, + "video": spdl.io.demux_video, + "image": spdl.io.demux_image, }[media_type] - async def _test(src): - frames = await spdl.io.async_decode_packets(await demux_func(src)) - _ = await spdl.io.async_convert_frames(frames) - with pytest.raises(TypeError): - frames.clone() - - asyncio.run(_test(sample.path)) + frames = spdl.io.decode_packets(demux_func(sample.path)) + _ = spdl.io.convert_frames(frames) + with pytest.raises(TypeError): + frames.clone() @pytest.mark.parametrize("media_type", ["audio", "video", "image"]) @@ -72,21 +64,19 @@ def test_clone_frames_multi(media_type, get_sample): """Can clone multiple times""" cmd = CMDS[media_type] sample = get_sample(cmd) + N = 100 demux_func = { - "audio": spdl.io.async_demux_audio, - "video": spdl.io.async_demux_video, - "image": spdl.io.async_demux_image, + "audio": spdl.io.demux_audio, + "video": spdl.io.demux_video, + "image": spdl.io.demux_image, }[media_type] - async def _test(src, N=100): - frames = await spdl.io.async_decode_packets(await demux_func(src)) - clones = [frames.clone() for _ in range(N)] - - array = await _load_from_frames(frames) - arrays = [await _load_from_frames(c) for c in clones] + frames = spdl.io.decode_packets(demux_func(sample.path)) + clones = [frames.clone() for _ in range(N)] - for i in range(N): - assert np.all(array == arrays[i]) + array = _load_from_frames(frames) + arrays = [_load_from_frames(c) for c in clones] - asyncio.run(_test(sample.path)) + for i in range(N): + assert np.all(array == arrays[i]) diff --git a/tests/spdl_unittest/io/frames_test.py b/tests/spdl_unittest/io/frames_test.py index 3e0577cc..44c8b549 100644 --- a/tests/spdl_unittest/io/frames_test.py +++ b/tests/spdl_unittest/io/frames_test.py @@ -4,8 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio - import spdl.io @@ -18,10 +16,7 @@ def test_image_frame_metadata(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 1 sample.jpg" sample = get_sample(cmd) - async def test(src): - packets = await spdl.io.async_demux_image(src) - frames = await spdl.io.async_decode_packets(packets) - - assert frames.metadata == {} + packets = spdl.io.demux_image(sample.path) + frames = spdl.io.decode_packets(packets) - asyncio.run(test(sample.path)) + assert frames.metadata == {} diff --git a/tests/spdl_unittest/io/packets_test.py b/tests/spdl_unittest/io/packets_test.py index 8df7bddd..b1df5a30 100644 --- a/tests/spdl_unittest/io/packets_test.py +++ b/tests/spdl_unittest/io/packets_test.py @@ -4,7 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio import time import numpy as np @@ -18,9 +17,9 @@ } -async def _load_from_packets(packets): - frames = await spdl.io.async_decode_packets(packets) - buffer = await spdl.io.async_convert_frames(frames) +def _load_from_packets(packets): + frames = spdl.io.decode_packets(packets) + buffer = spdl.io.convert_frames(frames) return spdl.io.to_numpy(buffer) @@ -36,12 +35,9 @@ def test_audio_packets_attribtues(get_sample): # fmt: on sample = get_sample(cmd) - async def _test(src): - packets = await spdl.io.async_demux_audio(src) - assert packets.sample_rate == 8000 - assert packets.num_channels == 2 - - asyncio.run(_test(sample.path)) + packets = spdl.io.demux_audio(sample.path) + assert packets.sample_rate == 8000 + assert packets.num_channels == 2 @pytest.mark.parametrize( @@ -58,14 +54,11 @@ def test_video_packets_attribtues(get_sample, rate): cmd = f"ffmpeg -hide_banner -y -f lavfi -r {rate[0]}/{rate[1]} -i testsrc -frames:v 25 sample.mp4" sample = get_sample(cmd) - async def _test(src): - packets = await spdl.io.async_demux_video(src) - assert packets.width == 320 - assert packets.height == 240 - assert packets.pix_fmt == "yuv444p" - assert packets.frame_rate == rate - - asyncio.run(_test(sample.path)) + packets = spdl.io.demux_video(sample.path) + assert packets.width == 320 + assert packets.height == 240 + assert packets.pix_fmt == "yuv444p" + assert packets.frame_rate == rate def test_image_packets_attribtues(get_sample): @@ -73,13 +66,10 @@ def test_image_packets_attribtues(get_sample): cmd = CMDS["image"] sample = get_sample(cmd) - async def _test(src): - packets = await spdl.io.async_demux_image(src) - assert packets.width == 320 - assert packets.height == 240 - assert packets.pix_fmt == "gray" - - asyncio.run(_test(sample.path)) + packets = spdl.io.demux_image(sample.path) + assert packets.width == 320 + assert packets.height == 240 + assert packets.pix_fmt == "gray" @pytest.mark.parametrize("media_type", ["audio", "video", "image"]) @@ -89,21 +79,18 @@ def test_clone_packets(media_type, get_sample): sample = get_sample(cmd) demux_func = { - "audio": spdl.io.async_demux_audio, - "video": spdl.io.async_demux_video, - "image": spdl.io.async_demux_image, + "audio": spdl.io.demux_audio, + "video": spdl.io.demux_video, + "image": spdl.io.demux_image, }[media_type] - async def _test(src): - packets1 = await demux_func(src) - packets2 = packets1.clone() - - array1 = await _load_from_packets(packets1) - array2 = await _load_from_packets(packets2) + packets1 = demux_func(sample.path) + packets2 = packets1.clone() - assert np.all(array1 == array2) + array1 = _load_from_packets(packets1) + array2 = _load_from_packets(packets2) - asyncio.run(_test(sample.path)) + assert np.all(array1 == array2) @pytest.mark.parametrize("media_type", ["audio", "video", "image"]) @@ -113,18 +100,15 @@ def test_clone_invalid_packets(media_type, get_sample): sample = get_sample(cmd) demux_func = { - "audio": spdl.io.async_demux_audio, - "video": spdl.io.async_demux_video, - "image": spdl.io.async_demux_image, + "audio": spdl.io.demux_audio, + "video": spdl.io.demux_video, + "image": spdl.io.demux_image, }[media_type] - async def _test(src): - packets = await demux_func(src) - _ = await spdl.io.async_decode_packets(packets) - with pytest.raises(TypeError): - packets.clone() - - asyncio.run(_test(sample.path)) + packets = demux_func(sample.path) + _ = spdl.io.decode_packets(packets) + with pytest.raises(TypeError): + packets.clone() @pytest.mark.parametrize("media_type", ["audio", "video", "image"]) @@ -132,24 +116,22 @@ def test_clone_packets_multi(media_type, get_sample): """Can clone multiple times""" cmd = CMDS[media_type] sample = get_sample(cmd) + N = 100 demux_func = { - "audio": spdl.io.async_demux_audio, - "video": spdl.io.async_demux_video, - "image": spdl.io.async_demux_image, + "audio": spdl.io.demux_audio, + "video": spdl.io.demux_video, + "image": spdl.io.demux_image, }[media_type] - async def _test(src, N=100): - packets = await demux_func(src) - clones = [packets.clone() for _ in range(N)] + packets = demux_func(sample.path) + clones = [packets.clone() for _ in range(N)] - array = await _load_from_packets(packets) - arrays = [await _load_from_packets(c) for c in clones] + array = _load_from_packets(packets) + arrays = [_load_from_packets(c) for c in clones] - for i in range(N): - assert np.all(array == arrays[i]) - - asyncio.run(_test(sample.path)) + for i in range(N): + assert np.all(array == arrays[i]) def test_sample_decoding_time(get_sample): @@ -166,30 +148,27 @@ def test_sample_decoding_time(get_sample): # Use ffprobe -loglevel error -select_streams v:0 -show_entries packet=pts_time,flags -of csv=print_section=0 sample.mp4 | grep K__ sample = get_sample(cmd) - async def _test(path): - indices = list(range(0, 5000, 100)) - - packets = await spdl.io.async_demux_video(path) - t0 = time.monotonic() - frames = await spdl.io.async_decode_packets(packets.clone()) - frames = frames[indices] - elapsed_ref = time.monotonic() - t0 - buffer = await spdl.io.async_convert_frames(frames) - array_ref = spdl.io.to_numpy(buffer) + indices = list(range(0, 5000, 100)) - t0 = time.monotonic() - frames = await spdl.io.async_sample_decode_video(packets, indices) - elapsed = time.monotonic() - t0 - buffer = await spdl.io.async_convert_frames(frames) - array = spdl.io.to_numpy(buffer) + packets = spdl.io.demux_video(sample.path) + t0 = time.monotonic() + frames = spdl.io.decode_packets(packets.clone()) + frames = frames[indices] + elapsed_ref = time.monotonic() - t0 + buffer = spdl.io.convert_frames(frames) + array_ref = spdl.io.to_numpy(buffer) - print(f"{elapsed_ref=}, {elapsed=}") - assert np.all(array == array_ref) + t0 = time.monotonic() + frames = spdl.io.sample_decode_video(packets, indices) + elapsed = time.monotonic() - t0 + buffer = spdl.io.convert_frames(frames) + array = spdl.io.to_numpy(buffer) - # should be much faster than 2x - assert elapsed_ref / 2 > elapsed + print(f"{elapsed_ref=}, {elapsed=}") + assert np.all(array == array_ref) - asyncio.run(_test(sample.path)) + # should be much faster than 2x + assert elapsed_ref / 2 > elapsed def test_sample_decoding_time_sync(get_sample): @@ -237,59 +216,53 @@ def test_packet_len(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -force_key_frames 'expr:eq(n, 0)' -frames:v 75 sample.mp4" sample = get_sample(cmd) - async def _test(src): - ref_array = spdl.io.to_numpy(await spdl.io.async_load_video(src)) - - packets = await spdl.io.async_demux_video(src, timestamp=(1.0, 2.0)) - num_packets = len(packets) + ref_array = spdl.io.to_numpy(spdl.io.load_video(sample.path)) - frames = await spdl.io.async_decode_packets(packets) - num_frames = len(frames) - print(f"{num_packets=}, {num_frames=}") - assert num_packets == num_frames == 25 + packets = spdl.io.demux_video(sample.path, timestamp=(1.0, 2.0)) + num_packets = len(packets) - array = spdl.io.to_numpy(await spdl.io.async_convert_frames(frames)) - assert np.all(array == ref_array[25:50]) + frames = spdl.io.decode_packets(packets) + num_frames = len(frames) + print(f"{num_packets=}, {num_frames=}") + assert num_packets == num_frames == 25 - asyncio.run(_test(sample.path)) + array = spdl.io.to_numpy(spdl.io.convert_frames(frames)) + assert np.all(array == ref_array[25:50]) def test_sample_decoding_window(get_sample): - """async_sample_decode_video returns the correct frame when timestamps is specified.""" + """sample_decode_video returns the correct frame when timestamps is specified.""" # 10 seconds of video with only one keyframe at the beginning. # Use the following command to check # `ffprobe -loglevel error -select_streams v:0 -show_entries packet=pts_time,flags -of csv=print_section=0 sample.mp4 | grep K__` cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -force_key_frames 'expr:eq(n, 0)' -frames:v 250 sample.mp4" sample = get_sample(cmd) - async def _test(src): - # 250 frames - ref_array = spdl.io.to_numpy(await spdl.io.async_load_video(src)) - assert len(ref_array) == 250 - - # frames from 25 - 50, but internally it holds 0 - 50 - packets = await spdl.io.async_demux_video(src, timestamp=(1.0, 2.0)) - assert len(packets) == 25 + # 250 frames + ref_array = spdl.io.to_numpy(spdl.io.load_video(sample.path)) + assert len(ref_array) == 250 - # decode all to verify the pre-condition - frames = await spdl.io.async_decode_packets(packets.clone()) - assert len(frames) == 25 - array = spdl.io.to_numpy(await spdl.io.async_convert_frames(frames)) - assert np.all(array == ref_array[25:50]) + # frames from 25 - 50, but internally it holds 0 - 50 + packets = spdl.io.demux_video(sample.path, timestamp=(1.0, 2.0)) + assert len(packets) == 25 - # Sample decode should offset the indices - indices = list(range(0, 25, 2)) - frames = await spdl.io.async_sample_decode_video(packets, indices) - assert len(indices) == len(frames) == 13 - array = spdl.io.to_numpy(await spdl.io.async_convert_frames(frames)) - print(f"{array.shape=}, {ref_array[25:50:2].shape=}") - assert np.all(array == ref_array[25:50:2]) + # decode all to verify the pre-condition + frames = spdl.io.decode_packets(packets.clone()) + assert len(frames) == 25 + array = spdl.io.to_numpy(spdl.io.convert_frames(frames)) + assert np.all(array == ref_array[25:50]) - asyncio.run(_test(sample.path)) + # Sample decode should offset the indices + indices = list(range(0, 25, 2)) + frames = spdl.io.sample_decode_video(packets, indices) + assert len(indices) == len(frames) == 13 + array = spdl.io.to_numpy(spdl.io.convert_frames(frames)) + print(f"{array.shape=}, {ref_array[25:50:2].shape=}") + assert np.all(array == ref_array[25:50:2]) def test_sample_decoding_window_sync(get_sample): - """async_sample_decode_video returns the correct frame when timestamps is specified.""" + """sample_decode_video returns the correct frame when timestamps is specified.""" # 10 seconds of video with only one keyframe at the beginning. # Use the following command to check # `ffprobe -loglevel error -select_streams v:0 -show_entries packet=pts_time,flags -of csv=print_section=0 sample.mp4 | grep K__` @@ -324,15 +297,12 @@ def test_sample_decode_video_default_color_space(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 10 sample.mp4" sample = get_sample(cmd) - async def _test(src): - packets = await spdl.io.async_demux_video(src) - assert packets.pix_fmt != "rgb24" # precondition - frames = await spdl.io.async_sample_decode_video(packets, list(range(10))) - - for f in frames: - assert f.pix_fmt == "rgb24" + packets = spdl.io.demux_video(sample.path) + assert packets.pix_fmt != "rgb24" # precondition + frames = spdl.io.sample_decode_video(packets, list(range(10))) - asyncio.run(_test(sample.path)) + for f in frames: + assert f.pix_fmt == "rgb24" def test_sample_decode_video_default_color_space_sync(get_sample): diff --git a/tests/spdl_unittest/io/streaming_video_decoding_test.py b/tests/spdl_unittest/io/streaming_video_decoding_test.py index 859724c0..267459a7 100644 --- a/tests/spdl_unittest/io/streaming_video_decoding_test.py +++ b/tests/spdl_unittest/io/streaming_video_decoding_test.py @@ -4,8 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio - import numpy as np import pytest import spdl.io @@ -16,22 +14,19 @@ def test_streaming_decode(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 50 sample.mp4" sample = get_sample(cmd) - async def test(src): - packets = await spdl.io.async_demux_video(src) - frames = await spdl.io.async_decode_packets(packets.clone()) - buffer = await spdl.io.async_convert_frames(frames) - ref_array = spdl.io.to_numpy(buffer) - - agen = spdl.io.async_streaming_decode_packets(packets, 1) - for i in range(50): - print(i) - frame = await anext(agen) - buffer = await spdl.io.async_convert_frames(frame) - array = spdl.io.to_numpy(buffer) - print(f"{ref_array.shape=}, {array.shape=}") - assert np.array_equal(ref_array[i : i + 1], array) + packets = spdl.io.demux_video(sample.path) + frames = spdl.io.decode_packets(packets.clone()) + buffer = spdl.io.convert_frames(frames) + ref_array = spdl.io.to_numpy(buffer) - asyncio.run(test(sample.path)) + gen = spdl.io.streaming_decode_packets(packets, 1) + for i in range(50): + print(i) + frame = next(gen) + buffer = spdl.io.convert_frames(frame) + array = spdl.io.to_numpy(buffer) + print(f"{ref_array.shape=}, {array.shape=}") + assert np.array_equal(ref_array[i : i + 1], array) def test_streaming_decode_indivisible(get_sample): @@ -39,21 +34,18 @@ def test_streaming_decode_indivisible(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 8 sample.mp4" sample = get_sample(cmd) - async def test(src): - packets = await spdl.io.async_demux_video(src) - agen = spdl.io.async_streaming_decode_packets(packets, 5) + packets = spdl.io.demux_video(sample.path) + gen = spdl.io.streaming_decode_packets(packets, 5) - frame = await anext(agen) - buffer = await spdl.io.async_convert_frames(frame) - array = spdl.io.to_numpy(buffer) - assert array.shape == (5, 240, 320, 3) - - frame = await anext(agen) - buffer = await spdl.io.async_convert_frames(frame) - array = spdl.io.to_numpy(buffer) - assert array.shape == (3, 240, 320, 3) + frame = next(gen) + buffer = spdl.io.convert_frames(frame) + array = spdl.io.to_numpy(buffer) + assert array.shape == (5, 240, 320, 3) - asyncio.run(test(sample.path)) + frame = next(gen) + buffer = spdl.io.convert_frames(frame) + array = spdl.io.to_numpy(buffer) + assert array.shape == (3, 240, 320, 3) def test_streaming_decode_stop_iteration(get_sample): @@ -61,20 +53,17 @@ def test_streaming_decode_stop_iteration(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 1 sample.mp4" sample = get_sample(cmd) - async def test(src): - packets = await spdl.io.async_demux_video(src) - agen = spdl.io.async_streaming_decode_packets(packets, 5) + packets = spdl.io.demux_video(sample.path) + gen = spdl.io.streaming_decode_packets(packets, 5) - frame = await anext(agen) - buffer = await spdl.io.async_convert_frames(frame) - array = spdl.io.to_numpy(buffer) - assert array.shape == (1, 240, 320, 3) - - for _ in range(20): - with pytest.raises(StopAsyncIteration): - await anext(agen) + frame = next(gen) + buffer = spdl.io.convert_frames(frame) + array = spdl.io.to_numpy(buffer) + assert array.shape == (1, 240, 320, 3) - asyncio.run(test(sample.path)) + for _ in range(20): + with pytest.raises(StopIteration): + next(gen) def test_streaming_decode_carryover(get_sample): @@ -86,24 +75,17 @@ def test_streaming_decode_carryover(get_sample): # this will internally cause the filtergraph to duplicate the frames. filter_desc = "fps=1000" - async def test(src): - packets = await spdl.io.async_demux_video(src) - frames = await spdl.io.async_decode_packets( - packets.clone(), filter_desc=filter_desc - ) - buffer = await spdl.io.async_convert_frames(frames) - ref_array = spdl.io.to_numpy(buffer) - print(ref_array.shape) - - agen = spdl.io.async_streaming_decode_packets( - packets, 5, filter_desc=filter_desc - ) - - for i in range(200): - print(i) - frame = await anext(agen) - buffer = await spdl.io.async_convert_frames(frame) - array = spdl.io.to_numpy(buffer) - assert array.shape == (5, 3, 240, 320) - - asyncio.run(test(sample.path)) + packets = spdl.io.demux_video(sample.path) + frames = spdl.io.decode_packets(packets.clone(), filter_desc=filter_desc) + buffer = spdl.io.convert_frames(frames) + ref_array = spdl.io.to_numpy(buffer) + print(ref_array.shape) + + gen = spdl.io.streaming_decode_packets(packets, 5, filter_desc=filter_desc) + + for i in range(200): + print(i) + frame = next(gen) + buffer = spdl.io.convert_frames(frame) + array = spdl.io.to_numpy(buffer) + assert array.shape == (5, 3, 240, 320) diff --git a/tests/spdl_unittest/io/video_frame_slice_test.py b/tests/spdl_unittest/io/video_frame_slice_test.py index 3491b589..716662a9 100644 --- a/tests/spdl_unittest/io/video_frame_slice_test.py +++ b/tests/spdl_unittest/io/video_frame_slice_test.py @@ -4,8 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio - import numpy as np import pytest import spdl.io @@ -14,18 +12,15 @@ def _to_numpy(frames): - buffer = asyncio.run(spdl.io.async_convert_frames(frames)) + buffer = spdl.io.convert_frames(frames) return spdl.io.to_numpy(buffer) def _decode_video(src, pix_fmt=None): - async def _decode(): - return await spdl.io.async_decode_packets( - await spdl.io.async_demux_video(src), - filter_desc=get_video_filter_desc(pix_fmt=pix_fmt), - ) - - return asyncio.run(_decode()) + return spdl.io.decode_packets( + spdl.io.demux_video(src), + filter_desc=get_video_filter_desc(pix_fmt=pix_fmt), + ) def test_video_frames_getitem_slice(get_sample): diff --git a/tests/spdl_unittest/io/zero_copy_bytes_passing_test.py b/tests/spdl_unittest/io/zero_copy_bytes_passing_test.py index e8abf83a..e8f9baa8 100644 --- a/tests/spdl_unittest/io/zero_copy_bytes_passing_test.py +++ b/tests/spdl_unittest/io/zero_copy_bytes_passing_test.py @@ -4,8 +4,6 @@ # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. -import asyncio - import numpy as np import pytest import spdl.io @@ -28,65 +26,59 @@ def test_demux_bytes_without_copy(media_type, get_sample): sample = get_sample(cmd) demux_func = { - "audio": spdl.io.async_demux_audio, - "video": spdl.io.async_demux_video, - "image": spdl.io.async_demux_image, + "audio": spdl.io.demux_audio, + "video": spdl.io.demux_video, + "image": spdl.io.demux_image, }[media_type] - async def _test(src): + def _test(src): assert not _is_all_zero(src) - _ = await demux_func(src, _zero_clear=True) + _ = demux_func(src, _zero_clear=True) assert _is_all_zero(src) with open(sample.path, "rb") as f: data = f.read() - asyncio.run(_test(data)) + _test(data) -async def _decode(media_type, src): +def _decode(media_type, src): demux_func = { - "audio": spdl.io.async_demux_audio, - "video": spdl.io.async_demux_video, - "image": spdl.io.async_demux_image, + "audio": spdl.io.demux_audio, + "video": spdl.io.demux_video, + "image": spdl.io.demux_image, }[media_type] - packets = await demux_func(src) - frames = await spdl.io.async_decode_packets(packets) - buffer = await spdl.io.async_convert_frames(frames) + packets = demux_func(src) + frames = spdl.io.decode_packets(packets) + buffer = spdl.io.convert_frames(frames) return spdl.io.to_numpy(buffer) -def test_async_decode_audio_bytes(get_sample): +def test_decode_audio_bytes(get_sample): """audio can be decoded from bytes.""" cmd = "ffmpeg -hide_banner -y -f lavfi -i 'sine=frequency=1000:sample_rate=16000:duration=3' -c:a pcm_s16le sample.wav" sample = get_sample(cmd) - async def _test(path): - ref = await _decode("audio", path) - with open(path, "rb") as f: - hyp = await _decode("audio", f.read()) - - assert hyp.shape == (1, 48000) - assert np.all(ref == hyp) + ref = _decode("audio", sample.path) + with open(sample.path, "rb") as f: + hyp = _decode("audio", f.read()) - asyncio.run(_test(sample.path)) + assert hyp.shape == (1, 48000) + assert np.all(ref == hyp) -def test_async_decode_video_bytes(get_sample): +def test_decode_video_bytes(get_sample): """video can be decoded from bytes.""" cmd = "ffmpeg -hide_banner -y -f lavfi -i testsrc -frames:v 1000 sample.mp4" sample = get_sample(cmd, width=320, height=240) - async def _test(path): - ref = await _decode("video", path) - with open(path, "rb") as f: - hyp = await _decode("video", f.read()) - - assert hyp.shape == (1000, 240, 320, 3) - assert np.all(ref == hyp) + ref = _decode("video", sample.path) + with open(sample.path, "rb") as f: + hyp = _decode("video", f.read()) - asyncio.run(_test(sample.path)) + assert hyp.shape == (1000, 240, 320, 3) + assert np.all(ref == hyp) def test_demux_image_bytes(get_sample): @@ -94,12 +86,9 @@ def test_demux_image_bytes(get_sample): cmd = "ffmpeg -hide_banner -y -f lavfi -i color=0x000000,format=gray -frames:v 1 sample.png" sample = get_sample(cmd, width=320, height=240) - async def _test(path): - ref = await _decode("image", path) - with open(sample.path, "rb") as f: - hyp = await _decode("image", f.read()) - - assert hyp.shape == (240, 320, 3) - assert np.all(ref == hyp) + ref = _decode("image", sample.path) + with open(sample.path, "rb") as f: + hyp = _decode("image", f.read()) - asyncio.run(_test(sample.path)) + assert hyp.shape == (240, 320, 3) + assert np.all(ref == hyp)