Skip to content

Commit 69c1262

Browse files
committed
Add benchmark to compare multi-stream vs single-stream encoding
1 parent 566c66e commit 69c1262

1 file changed

Lines changed: 136 additions & 0 deletions

File tree

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"""
2+
Basic benchmark aimed at validating that the new Encoder class isn't slower than
3+
the existing VideoEncoder and AudioEncoder.
4+
"""
5+
6+
import os
7+
import tempfile
8+
from time import perf_counter_ns
9+
10+
import torch
11+
12+
from torchcodec.encoders import AudioEncoder, Encoder, VideoEncoder
13+
14+
15+
def bench(f, *args, num_exp=100, warmup=0, **kwargs):
16+
for _ in range(warmup):
17+
f(*args, **kwargs)
18+
19+
times = []
20+
for _ in range(num_exp):
21+
start = perf_counter_ns()
22+
f(*args, **kwargs)
23+
end = perf_counter_ns()
24+
times.append(end - start)
25+
return torch.tensor(times).float()
26+
27+
28+
def report_stats(times, unit="ms"):
29+
mul = {
30+
"ns": 1,
31+
"µs": 1e-3,
32+
"ms": 1e-6,
33+
"s": 1e-9,
34+
}[unit]
35+
times = times * mul
36+
std = times.std().item()
37+
med = times.median().item()
38+
print(f"{med = :.2f}{unit} +- {std:.2f}")
39+
return med
40+
41+
42+
# --- Config ---
43+
height, width = 256, 256
44+
frame_rate = 30
45+
num_channels = 2
46+
sample_rate = 48000
47+
durations_s = [3, 10]
48+
49+
50+
def encode_video_with_video_encoder(frames, dest):
51+
encoder = VideoEncoder(frames, frame_rate=frame_rate)
52+
encoder.to_file(dest)
53+
54+
55+
def encode_video_with_streaming_encoder(frames, dest):
56+
encoder = Encoder()
57+
video_stream = encoder.add_video(
58+
height=frames.shape[2],
59+
width=frames.shape[3],
60+
frame_rate=frame_rate,
61+
device=str(frames.device),
62+
)
63+
with encoder.open_file(dest):
64+
video_stream.add_frames(frames)
65+
66+
67+
def encode_audio_with_audio_encoder(samples, dest):
68+
encoder = AudioEncoder(samples, sample_rate=sample_rate)
69+
encoder.to_file(dest)
70+
71+
72+
def encode_audio_with_streaming_encoder(samples, dest):
73+
encoder = Encoder()
74+
audio_stream = encoder.add_audio(sample_rate=sample_rate, num_channels=num_channels)
75+
with encoder.open_file(dest):
76+
audio_stream.add_samples(samples)
77+
78+
79+
if __name__ == "__main__":
80+
tmpdir = tempfile.mkdtemp()
81+
82+
devices = ["cpu"]
83+
if torch.cuda.is_available():
84+
devices.append("cuda")
85+
86+
for duration_s in durations_s:
87+
print(f"\n{'=' * 50}")
88+
print(f"Duration: {duration_s}s")
89+
print(f"{'=' * 50}")
90+
91+
num_frames = frame_rate * duration_s
92+
video_frames = torch.randint(
93+
0, 256, (num_frames, 3, height, width), dtype=torch.uint8
94+
)
95+
96+
num_samples = sample_rate * duration_s
97+
audio_samples = torch.randn(num_channels, num_samples)
98+
99+
# --- Video benchmarks ---
100+
for device in devices:
101+
frames = video_frames.to(device)
102+
dest = os.path.join(tmpdir, "video.mp4")
103+
104+
print(f"\n--- Video encoding ({device}) ---")
105+
106+
print("VideoEncoder: ", end="")
107+
times = bench(
108+
encode_video_with_video_encoder, frames, dest, num_exp=10, warmup=2
109+
)
110+
report_stats(times)
111+
112+
print("StreamingEncoder:", end="")
113+
times = bench(
114+
encode_video_with_streaming_encoder, frames, dest, num_exp=10, warmup=2
115+
)
116+
report_stats(times)
117+
118+
# --- Audio benchmarks ---
119+
print("\n--- Audio encoding (cpu) ---")
120+
dest = os.path.join(tmpdir, "audio.wav")
121+
122+
print("AudioEncoder: ", end="")
123+
times = bench(
124+
encode_audio_with_audio_encoder, audio_samples, dest, num_exp=10, warmup=2
125+
)
126+
report_stats(times)
127+
128+
print("StreamingEncoder:", end="")
129+
times = bench(
130+
encode_audio_with_streaming_encoder,
131+
audio_samples,
132+
dest,
133+
num_exp=10,
134+
warmup=2,
135+
)
136+
report_stats(times)

0 commit comments

Comments
 (0)