Skip to content

Commit 43ee807

Browse files
authored
Use more interesting videos for README experiment (#351)
1 parent c7724e2 commit 43ee807

File tree

5 files changed

+265
-147
lines changed

5 files changed

+265
-147
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ The following was generated by running [our benchmark script](./benchmarks/decod
124124

125125
![benchmark_results](./benchmarks/decoders/benchmark_readme_chart.png)
126126

127+
The top row is a [Mandelbrot](https://ffmpeg.org/ffmpeg-filters.html#mandelbrot) video
128+
generated from FFmpeg that has a resolution of 1280x720 at 60 fps and is 120 seconds long.
129+
The bottom row is [promotional video from NASA](https://download.pytorch.org/torchaudio/tutorial-assets/stream-api/NASAs_Most_Scientifically_Complex_Space_Observatory_Requires_Precision-MP4_small.mp4)
130+
that has a resolution of 960x540 at 29.7 fps and is 206 seconds long. Both videos were
131+
encoded with libx264 and yuv420p pixel format.
132+
127133
## Planned future work
128134

129135
We are actively working on the following features:

benchmarks/decoders/benchmark_decoders_library.py

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import abc
22
import json
3-
import os
43
import subprocess
4+
import urllib.request
55
from concurrent.futures import ThreadPoolExecutor, wait
66
from itertools import product
7+
from pathlib import Path
78

89
import matplotlib.pyplot as plt
910
import numpy as np
@@ -341,6 +342,7 @@ def generate_video(command):
341342
def generate_videos(
342343
resolutions,
343344
encodings,
345+
patterns,
344346
fpses,
345347
gop_sizes,
346348
durations,
@@ -352,23 +354,25 @@ def generate_videos(
352354
video_count = 0
353355

354356
futures = []
355-
for resolution, duration, fps, gop_size, encoding, pix_fmt in product(
356-
resolutions, durations, fpses, gop_sizes, encodings, pix_fmts
357+
for resolution, duration, fps, gop_size, encoding, pattern, pix_fmt in product(
358+
resolutions, durations, fpses, gop_sizes, encodings, patterns, pix_fmts
357359
):
358-
outfile = f"{output_dir}/{resolution}_{duration}s_{fps}fps_{gop_size}gop_{encoding}_{pix_fmt}.mp4"
360+
outfile = f"{output_dir}/{pattern}_{resolution}_{duration}s_{fps}fps_{gop_size}gop_{encoding}_{pix_fmt}.mp4"
359361
command = [
360362
ffmpeg_cli,
361363
"-y",
362364
"-f",
363365
"lavfi",
364366
"-i",
365-
f"color=c=blue:s={resolution}:d={duration}",
367+
f"{pattern}=s={resolution}",
368+
"-t",
369+
str(duration),
366370
"-c:v",
367371
encoding,
368372
"-r",
369-
f"{fps}",
373+
str(fps),
370374
"-g",
371-
f"{gop_size}",
375+
str(gop_size),
372376
"-pix_fmt",
373377
pix_fmt,
374378
outfile,
@@ -383,6 +387,11 @@ def generate_videos(
383387
print(f"Generated {video_count} videos")
384388

385389

390+
def retrieve_videos(urls_and_dest_paths):
391+
for url, path in urls_and_dest_paths:
392+
urllib.request.urlretrieve(url, path)
393+
394+
386395
def plot_data(df_data, plot_path):
387396
# Creating the DataFrame
388397
df = pd.DataFrame(df_data)
@@ -411,7 +420,7 @@ def plot_data(df_data, plot_path):
411420
nrows=len(unique_videos),
412421
ncols=max_combinations,
413422
figsize=(max_combinations * 6, len(unique_videos) * 4),
414-
sharex=True,
423+
sharex=False,
415424
sharey=True,
416425
)
417426

@@ -430,16 +439,19 @@ def plot_data(df_data, plot_path):
430439
ax = axes[row, col] # Select the appropriate axis
431440

432441
# Set the title for the subplot
433-
base_video = os.path.basename(video)
442+
base_video = Path(video).name.removesuffix(".mp4")
434443
ax.set_title(
435-
f"video={base_video}\ndecode_pattern={vcount} x {vtype}", fontsize=12
444+
f"video={base_video}\ndecode_pattern={vcount} x {vtype}", fontsize=10
436445
)
437446

438447
# Plot bars with error bars
439448
ax.barh(
440449
group["decoder"],
441-
group["fps"],
442-
xerr=[group["fps"] - group["fps_p75"], group["fps_p25"] - group["fps"]],
450+
group["fps_median"],
451+
xerr=[
452+
group["fps_median"] - group["fps_p75"],
453+
group["fps_p25"] - group["fps_median"],
454+
],
443455
color=[colors(i) for i in range(len(group))],
444456
align="center",
445457
capsize=5,
@@ -449,28 +461,11 @@ def plot_data(df_data, plot_path):
449461
# Set the labels
450462
ax.set_xlabel("FPS")
451463

452-
# No need for y-axis label past the plot on the far left
453-
if col == 0:
454-
ax.set_ylabel("Decoder")
455-
456464
# Remove any empty subplots for videos with fewer combinations
457465
for row in range(len(unique_videos)):
458466
for col in range(video_type_combinations[unique_videos[row]], max_combinations):
459467
fig.delaxes(axes[row, col])
460468

461-
# If we just call fig.legend, we'll get duplicate labels, as each label appears on
462-
# each subplot. We take advantage of dicts having unique keys to de-dupe.
463-
handles, labels = plt.gca().get_legend_handles_labels()
464-
unique_labels = dict(zip(labels, handles))
465-
466-
# Reverse the order of the handles and labels to match the order of the bars
467-
fig.legend(
468-
handles=reversed(unique_labels.values()),
469-
labels=reversed(unique_labels.keys()),
470-
frameon=True,
471-
loc="right",
472-
)
473-
474469
# Adjust layout to avoid overlap
475470
plt.tight_layout()
476471

@@ -486,7 +481,7 @@ def get_metadata(video_file_path: str) -> VideoStreamMetadata:
486481

487482
def run_benchmarks(
488483
decoder_dict: dict[str, AbstractDecoder],
489-
video_files_paths: list[str],
484+
video_files_paths: list[Path],
490485
num_samples: int,
491486
num_sequential_frames_from_start: list[int],
492487
min_runtime_seconds: float,
@@ -526,7 +521,7 @@ def run_benchmarks(
526521
seeked_result = benchmark.Timer(
527522
stmt="decoder.get_frames_from_video(video_file, pts_list)",
528523
globals={
529-
"video_file": video_file_path,
524+
"video_file": str(video_file_path),
530525
"pts_list": pts_list,
531526
"decoder": decoder,
532527
},
@@ -539,22 +534,22 @@ def run_benchmarks(
539534
)
540535
df_item = {}
541536
df_item["decoder"] = decoder_name
542-
df_item["video"] = video_file_path
537+
df_item["video"] = str(video_file_path)
543538
df_item["description"] = results[-1].description
544539
df_item["frame_count"] = num_samples
545540
df_item["median"] = results[-1].median
546541
df_item["iqr"] = results[-1].iqr
547542
df_item["type"] = f"{kind}:seek()+next()"
548-
df_item["fps"] = 1.0 * num_samples / results[-1].median
549-
df_item["fps_p75"] = 1.0 * num_samples / results[-1]._p75
550-
df_item["fps_p25"] = 1.0 * num_samples / results[-1]._p25
543+
df_item["fps_median"] = num_samples / results[-1].median
544+
df_item["fps_p75"] = num_samples / results[-1]._p75
545+
df_item["fps_p25"] = num_samples / results[-1]._p25
551546
df_data.append(df_item)
552547

553548
for num_consecutive_nexts in num_sequential_frames_from_start:
554549
consecutive_frames_result = benchmark.Timer(
555550
stmt="decoder.get_consecutive_frames_from_video(video_file, consecutive_frames_to_extract)",
556551
globals={
557-
"video_file": video_file_path,
552+
"video_file": str(video_file_path),
558553
"consecutive_frames_to_extract": num_consecutive_nexts,
559554
"decoder": decoder,
560555
},
@@ -569,15 +564,15 @@ def run_benchmarks(
569564
)
570565
df_item = {}
571566
df_item["decoder"] = decoder_name
572-
df_item["video"] = video_file_path
567+
df_item["video"] = str(video_file_path)
573568
df_item["description"] = results[-1].description
574569
df_item["frame_count"] = num_consecutive_nexts
575570
df_item["median"] = results[-1].median
576571
df_item["iqr"] = results[-1].iqr
577572
df_item["type"] = "next()"
578-
df_item["fps"] = 1.0 * num_consecutive_nexts / results[-1].median
579-
df_item["fps_p75"] = 1.0 * num_consecutive_nexts / results[-1]._p75
580-
df_item["fps_p25"] = 1.0 * num_consecutive_nexts / results[-1]._p25
573+
df_item["fps_median"] = num_consecutive_nexts / results[-1].median
574+
df_item["fps_p75"] = num_consecutive_nexts / results[-1]._p75
575+
df_item["fps_p25"] = num_consecutive_nexts / results[-1]._p25
581576
df_data.append(df_item)
582577

583578
first_video_file_path = video_files_paths[0]
@@ -587,7 +582,7 @@ def run_benchmarks(
587582
creation_result = benchmark.Timer(
588583
stmt="create_torchcodec_decoder_from_file(video_file)",
589584
globals={
590-
"video_file": first_video_file_path,
585+
"video_file": str(first_video_file_path),
591586
"create_torchcodec_decoder_from_file": create_torchcodec_decoder_from_file,
592587
},
593588
label=f"video={first_video_file_path} {metadata_label}",
13.9 KB
Loading

0 commit comments

Comments
 (0)