Skip to content

Commit ab3c741

Browse files
committed
Added benchmark chart to README.md
1 parent 6ecf3a8 commit ab3c741

File tree

4 files changed

+142
-0
lines changed

4 files changed

+142
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ The instructions below assume you're on Linux.
118118
pip install torchcodec
119119
```
120120

121+
## Benchmark Results
122+
123+
The following was generated by running [our benchmark script](./benchmarks/decoders/generate_readme_chart.py) on a lightly loaded 22-core machine.
124+
125+
[benchmark_results](./benchmarks/decoders/benchmark_readme_chart.png)
126+
121127
## Planned future work
122128

123129
We are actively working on the following features:

benchmarks/decoders/benchmark_decoders_library.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import abc
22
import json
33
import os
4+
import subprocess
45
import timeit
6+
from concurrent.futures import ThreadPoolExecutor
57

68
import matplotlib.pyplot as plt
79
import numpy as np
@@ -299,6 +301,55 @@ def create_torchcodec_decoder_from_file(video_file):
299301
return video_decoder
300302

301303

304+
def generate_video(command):
305+
print(command)
306+
print(" ".join(command))
307+
subprocess.check_call(command)
308+
309+
310+
def generate_videos(
311+
resolutions,
312+
encodings,
313+
fpses,
314+
gop_sizes,
315+
durations,
316+
pix_fmts,
317+
ffmpeg_cli,
318+
output_dir,
319+
):
320+
executor = ThreadPoolExecutor(max_workers=20)
321+
video_count = 0
322+
for resolution in resolutions:
323+
for duration in durations:
324+
for fps in fpses:
325+
for gop_size in gop_sizes:
326+
for encoding in encodings:
327+
for pix_fmt in pix_fmts:
328+
outfile = f"{output_dir}/{resolution}_{duration}s_{fps}fps_{gop_size}gop_{encoding}_{pix_fmt}.mp4"
329+
command = [
330+
ffmpeg_cli,
331+
"-y",
332+
"-f",
333+
"lavfi",
334+
"-i",
335+
f"color=c=blue:s={resolution}:d={duration}",
336+
"-c:v",
337+
encoding,
338+
"-r",
339+
f"{fps}",
340+
"-g",
341+
f"{gop_size}",
342+
"-pix_fmt",
343+
pix_fmt,
344+
outfile,
345+
]
346+
executor.submit(generate_video, command)
347+
video_count += 1
348+
349+
executor.shutdown(wait=True)
350+
print(f"Generated {video_count} videos")
351+
352+
302353
def plot_data(df_data, plot_path):
303354
# Creating the DataFrame
304355
df = pd.DataFrame(df_data)
54.3 KB
Loading
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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 glob
8+
import importlib.resources
9+
import os
10+
import shutil
11+
from pathlib import Path
12+
13+
from benchmark_decoders_library import (
14+
generate_videos,
15+
plot_data,
16+
run_benchmarks,
17+
TorchAudioDecoder,
18+
TorchcodecNonCompiledWithOptions,
19+
TVNewAPIDecoderWithBackend,
20+
)
21+
22+
23+
def in_fbcode() -> bool:
24+
return "FB_PAR_RUNTIME_FILES" in os.environ
25+
26+
27+
def get_test_resource_path(filename: str) -> str:
28+
if in_fbcode():
29+
resource = importlib.resources.files(__package__).joinpath(filename)
30+
with importlib.resources.as_file(resource) as path:
31+
return os.fspath(path)
32+
33+
return str(Path(__file__).parent / f"../../test/resources/{filename}")
34+
35+
36+
def main() -> None:
37+
"""Benchmarks the performance of a few video decoders on synthetic videos"""
38+
39+
resolutions = ["640x480"]
40+
encodings = ["libx264"]
41+
fpses = [30]
42+
gop_sizes = [600]
43+
durations = [10]
44+
pix_fmts = ["yuv420p"]
45+
ffmpeg_path = "/usr/local/bin/ffmpeg"
46+
videos_path = "/tmp/videos"
47+
shutil.rmtree(videos_path)
48+
os.makedirs(videos_path)
49+
generate_videos(
50+
resolutions,
51+
encodings,
52+
fpses,
53+
gop_sizes,
54+
durations,
55+
pix_fmts,
56+
ffmpeg_path,
57+
videos_path,
58+
)
59+
video_paths = glob.glob(f"{videos_path}/*.mp4")
60+
61+
decoder_dict = {}
62+
decoder_dict["TorchCodec"] = TorchcodecNonCompiledWithOptions()
63+
decoder_dict["TorchCodec[num_threads=1]"] = TorchcodecNonCompiledWithOptions(
64+
num_threads=1
65+
)
66+
decoder_dict["TorchVision[backend=VideoReader]"] = TVNewAPIDecoderWithBackend(
67+
"video_reader"
68+
)
69+
decoder_dict["TorchAudio"] = TorchAudioDecoder()
70+
71+
output_png = Path(__file__) / "benchmark_readme_chart.png"
72+
# These are the number of uniform seeks we do in the seek+decode benchmark.
73+
num_uniform_samples = 10
74+
df_data = run_benchmarks(
75+
decoder_dict,
76+
video_paths,
77+
num_uniform_samples,
78+
10,
79+
False,
80+
)
81+
plot_data(df_data, output_png)
82+
83+
84+
if __name__ == "__main__":
85+
main()

0 commit comments

Comments
 (0)