7
7
import argparse
8
8
import importlib .resources
9
9
import os
10
+ import typing
11
+ from dataclasses import dataclass , field
10
12
from pathlib import Path
11
13
12
14
from benchmark_decoders_library import (
13
- DecordNonBatchDecoderAccurateSeek ,
15
+ AbstractDecoder ,
16
+ DecordAccurate ,
17
+ DecordAccurateBatch ,
14
18
plot_data ,
15
19
run_benchmarks ,
16
20
TorchAudioDecoder ,
17
21
TorchCodecCore ,
18
22
TorchCodecCoreBatch ,
19
23
TorchCodecCoreCompiled ,
24
+ TorchCodecCoreNonBatch ,
20
25
TorchCodecPublic ,
21
26
TorchVision ,
22
27
)
23
28
24
29
30
+ @dataclass
31
+ class DecoderKind :
32
+ display_name : str
33
+ kind : typing .Type [AbstractDecoder ]
34
+ default_options : dict [str , str ] = field (default_factory = dict )
35
+
36
+
37
+ decoder_registry = {
38
+ "decord" : DecoderKind ("DecordAccurate" , DecordAccurate ),
39
+ "decord_batch" : DecoderKind ("DecordAccurateBatch" , DecordAccurateBatch ),
40
+ "torchcodec_core" : DecoderKind ("TorchCodecCore" , TorchCodecCore ),
41
+ "torchcodec_core_batch" : DecoderKind ("TorchCodecCoreBatch" , TorchCodecCoreBatch ),
42
+ "torchcodec_core_nonbatch" : DecoderKind (
43
+ "TorchCodecCoreNonBatch" , TorchCodecCoreNonBatch
44
+ ),
45
+ "torchcodec_core_compiled" : DecoderKind (
46
+ "TorchCodecCoreCompiled" , TorchCodecCoreCompiled
47
+ ),
48
+ "torchcodec_public" : DecoderKind ("TorchCodecPublic" , TorchCodecPublic ),
49
+ "torchvision" : DecoderKind (
50
+ # We don't compare against TorchVision's "pyav" backend because it doesn't support
51
+ # accurate seeks.
52
+ "TorchVision[backend=video_reader]" ,
53
+ TorchVision ,
54
+ {"backend" : "video_reader" },
55
+ ),
56
+ "torchaudio" : DecoderKind ("TorchAudio" , TorchAudioDecoder ),
57
+ }
58
+
59
+
25
60
def in_fbcode () -> bool :
26
61
return "FB_PAR_RUNTIME_FILES" in os .environ
27
62
@@ -35,6 +70,16 @@ def get_test_resource_path(filename: str) -> str:
35
70
return str (Path (__file__ ).parent / f"../../test/resources/{ filename } " )
36
71
37
72
73
+ def parse_options_code (options_code : str ) -> dict [str , str ]:
74
+ options = {}
75
+ for item in options_code .split ("+" ):
76
+ if item .strip () == "" :
77
+ continue
78
+ k , v = item .split ("=" )
79
+ options [k ] = v
80
+ return options
81
+
82
+
38
83
def main () -> None :
39
84
"""Benchmarks the performance of a few video decoders"""
40
85
@@ -67,11 +112,18 @@ def main() -> None:
67
112
"--decoders" ,
68
113
help = (
69
114
"Comma-separated list of decoders to benchmark. "
70
- "Choices are torchcodec, torchaudio, torchvision, decord, tcoptions:num_threads=1+color_conversion_library=filtergraph, torchcodec_compiled"
71
- "For torchcodec, you can specify options with tcoptions:<plus-separated-options>. "
115
+ "Choices are: " + ", " .join (decoder_registry .keys ()) + ". "
116
+ "To specify options, append a ':' and then value pairs seperated by a '+'. "
117
+ "For example, torchcodec_core:num_threads=1+color_conversion_library=filtergraph."
72
118
),
73
119
type = str ,
74
- default = "decord,tcoptions:,torchvision,torchaudio,torchcodec_compiled,torchcodec_public,tcoptions:num_threads=1,tcbatchoptions:" ,
120
+ default = (
121
+ "decord,decord_batch,"
122
+ "torchvision,"
123
+ "torchaudio,"
124
+ "torchcodec_core,torchcodec_core:num_threads=1,torchcodec_core_batch,torchcodec_core_nonbatch,"
125
+ "torchcodec_public"
126
+ ),
75
127
)
76
128
parser .add_argument (
77
129
"--bm_video_dir" ,
@@ -87,51 +139,26 @@ def main() -> None:
87
139
)
88
140
89
141
args = parser .parse_args ()
90
- decoders = set (args .decoders .split ("," ))
142
+ specified_decoders = set (args .decoders .split ("," ))
91
143
92
144
# These are the PTS values we want to extract from the small video.
93
145
num_uniform_samples = 10
94
146
95
- decoder_dict = {}
96
- for decoder in decoders :
97
- if decoder == "decord" :
98
- decoder_dict ["DecordNonBatchDecoderAccurateSeek" ] = (
99
- DecordNonBatchDecoderAccurateSeek ()
100
- )
101
- elif decoder == "torchcodec" :
102
- decoder_dict ["TorchCodecCore:" ] = TorchCodecCore ()
103
- elif decoder == "torchcodec_compiled" :
104
- decoder_dict ["TorchCodecCoreCompiled" ] = TorchCodecCoreCompiled ()
105
- elif decoder == "torchcodec_public" :
106
- decoder_dict ["TorchCodecPublic" ] = TorchCodecPublic ()
107
- elif decoder == "torchvision" :
108
- decoder_dict ["TorchVision[backend=video_reader]" ] = (
109
- # We don't compare TorchVision's "pyav" backend because it doesn't support
110
- # accurate seeks.
111
- TorchVision ("video_reader" )
112
- )
113
- elif decoder == "torchaudio" :
114
- decoder_dict ["TorchAudioDecoder" ] = TorchAudioDecoder ()
115
- elif decoder .startswith ("tcbatchoptions:" ):
116
- options = decoder [len ("tcbatchoptions:" ) :]
117
- kwargs_dict = {}
118
- for item in options .split ("+" ):
119
- if item .strip () == "" :
120
- continue
121
- k , v = item .split ("=" )
122
- kwargs_dict [k ] = v
123
- decoder_dict ["TorchCodecCoreBatch" + options ] = TorchCodecCoreBatch (
124
- ** kwargs_dict
125
- )
126
- elif decoder .startswith ("tcoptions:" ):
127
- options = decoder [len ("tcoptions:" ) :]
128
- kwargs_dict = {}
129
- for item in options .split ("+" ):
130
- if item .strip () == "" :
131
- continue
132
- k , v = item .split ("=" )
133
- kwargs_dict [k ] = v
134
- decoder_dict ["TorchCodecCore:" + options ] = TorchCodecCore (** kwargs_dict )
147
+ decoders_to_run = {}
148
+ for decoder in specified_decoders :
149
+ if ":" in decoder :
150
+ decoder , _ , options_code = decoder .partition (":" )
151
+ assert decoder in decoder_registry , f"Unknown decoder: { decoder } "
152
+ display = decoder_registry [decoder ].display_name + ":" + options_code
153
+ options = parse_options_code (options_code )
154
+ else :
155
+ assert decoder in decoder_registry , f"Unknown decoder: { decoder } "
156
+ display = decoder_registry [decoder ].display_name
157
+ options = decoder_registry [decoder ].default_options
158
+
159
+ kind = decoder_registry [decoder ].kind
160
+ decoders_to_run [display ] = kind (** options )
161
+
135
162
video_paths = args .bm_video_paths .split ("," )
136
163
if args .bm_video_dir :
137
164
video_paths = []
@@ -140,7 +167,7 @@ def main() -> None:
140
167
video_paths .append (entry .path )
141
168
142
169
df_data = run_benchmarks (
143
- decoder_dict ,
170
+ decoders_to_run ,
144
171
video_paths ,
145
172
num_uniform_samples ,
146
173
num_sequential_frames_from_start = [1 , 10 , 100 ],
0 commit comments