1
1
import abc
2
2
import json
3
- import os
4
3
import subprocess
4
+ import urllib .request
5
5
from concurrent .futures import ThreadPoolExecutor , wait
6
6
from itertools import product
7
+ from pathlib import Path
7
8
8
9
import matplotlib .pyplot as plt
9
10
import numpy as np
@@ -341,6 +342,7 @@ def generate_video(command):
341
342
def generate_videos (
342
343
resolutions ,
343
344
encodings ,
345
+ patterns ,
344
346
fpses ,
345
347
gop_sizes ,
346
348
durations ,
@@ -352,23 +354,25 @@ def generate_videos(
352
354
video_count = 0
353
355
354
356
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
357
359
):
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"
359
361
command = [
360
362
ffmpeg_cli ,
361
363
"-y" ,
362
364
"-f" ,
363
365
"lavfi" ,
364
366
"-i" ,
365
- f"color=c=blue:s={ resolution } :d={ duration } " ,
367
+ f"{ pattern } =s={ resolution } " ,
368
+ "-t" ,
369
+ str (duration ),
366
370
"-c:v" ,
367
371
encoding ,
368
372
"-r" ,
369
- f" { fps } " ,
373
+ str ( fps ) ,
370
374
"-g" ,
371
- f" { gop_size } " ,
375
+ str ( gop_size ) ,
372
376
"-pix_fmt" ,
373
377
pix_fmt ,
374
378
outfile ,
@@ -383,6 +387,11 @@ def generate_videos(
383
387
print (f"Generated { video_count } videos" )
384
388
385
389
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
+
386
395
def plot_data (df_data , plot_path ):
387
396
# Creating the DataFrame
388
397
df = pd .DataFrame (df_data )
@@ -411,7 +420,7 @@ def plot_data(df_data, plot_path):
411
420
nrows = len (unique_videos ),
412
421
ncols = max_combinations ,
413
422
figsize = (max_combinations * 6 , len (unique_videos ) * 4 ),
414
- sharex = True ,
423
+ sharex = False ,
415
424
sharey = True ,
416
425
)
417
426
@@ -430,16 +439,19 @@ def plot_data(df_data, plot_path):
430
439
ax = axes [row , col ] # Select the appropriate axis
431
440
432
441
# Set the title for the subplot
433
- base_video = os . path . basename ( video )
442
+ base_video = Path ( video ). name . removesuffix ( ".mp4" )
434
443
ax .set_title (
435
- f"video={ base_video } \n decode_pattern={ vcount } x { vtype } " , fontsize = 12
444
+ f"video={ base_video } \n decode_pattern={ vcount } x { vtype } " , fontsize = 10
436
445
)
437
446
438
447
# Plot bars with error bars
439
448
ax .barh (
440
449
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
+ ],
443
455
color = [colors (i ) for i in range (len (group ))],
444
456
align = "center" ,
445
457
capsize = 5 ,
@@ -449,28 +461,11 @@ def plot_data(df_data, plot_path):
449
461
# Set the labels
450
462
ax .set_xlabel ("FPS" )
451
463
452
- # No need for y-axis label past the plot on the far left
453
- if col == 0 :
454
- ax .set_ylabel ("Decoder" )
455
-
456
464
# Remove any empty subplots for videos with fewer combinations
457
465
for row in range (len (unique_videos )):
458
466
for col in range (video_type_combinations [unique_videos [row ]], max_combinations ):
459
467
fig .delaxes (axes [row , col ])
460
468
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
-
474
469
# Adjust layout to avoid overlap
475
470
plt .tight_layout ()
476
471
@@ -486,7 +481,7 @@ def get_metadata(video_file_path: str) -> VideoStreamMetadata:
486
481
487
482
def run_benchmarks (
488
483
decoder_dict : dict [str , AbstractDecoder ],
489
- video_files_paths : list [str ],
484
+ video_files_paths : list [Path ],
490
485
num_samples : int ,
491
486
num_sequential_frames_from_start : list [int ],
492
487
min_runtime_seconds : float ,
@@ -526,7 +521,7 @@ def run_benchmarks(
526
521
seeked_result = benchmark .Timer (
527
522
stmt = "decoder.get_frames_from_video(video_file, pts_list)" ,
528
523
globals = {
529
- "video_file" : video_file_path ,
524
+ "video_file" : str ( video_file_path ) ,
530
525
"pts_list" : pts_list ,
531
526
"decoder" : decoder ,
532
527
},
@@ -539,22 +534,22 @@ def run_benchmarks(
539
534
)
540
535
df_item = {}
541
536
df_item ["decoder" ] = decoder_name
542
- df_item ["video" ] = video_file_path
537
+ df_item ["video" ] = str ( video_file_path )
543
538
df_item ["description" ] = results [- 1 ].description
544
539
df_item ["frame_count" ] = num_samples
545
540
df_item ["median" ] = results [- 1 ].median
546
541
df_item ["iqr" ] = results [- 1 ].iqr
547
542
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
551
546
df_data .append (df_item )
552
547
553
548
for num_consecutive_nexts in num_sequential_frames_from_start :
554
549
consecutive_frames_result = benchmark .Timer (
555
550
stmt = "decoder.get_consecutive_frames_from_video(video_file, consecutive_frames_to_extract)" ,
556
551
globals = {
557
- "video_file" : video_file_path ,
552
+ "video_file" : str ( video_file_path ) ,
558
553
"consecutive_frames_to_extract" : num_consecutive_nexts ,
559
554
"decoder" : decoder ,
560
555
},
@@ -569,15 +564,15 @@ def run_benchmarks(
569
564
)
570
565
df_item = {}
571
566
df_item ["decoder" ] = decoder_name
572
- df_item ["video" ] = video_file_path
567
+ df_item ["video" ] = str ( video_file_path )
573
568
df_item ["description" ] = results [- 1 ].description
574
569
df_item ["frame_count" ] = num_consecutive_nexts
575
570
df_item ["median" ] = results [- 1 ].median
576
571
df_item ["iqr" ] = results [- 1 ].iqr
577
572
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
581
576
df_data .append (df_item )
582
577
583
578
first_video_file_path = video_files_paths [0 ]
@@ -587,7 +582,7 @@ def run_benchmarks(
587
582
creation_result = benchmark .Timer (
588
583
stmt = "create_torchcodec_decoder_from_file(video_file)" ,
589
584
globals = {
590
- "video_file" : first_video_file_path ,
585
+ "video_file" : str ( first_video_file_path ) ,
591
586
"create_torchcodec_decoder_from_file" : create_torchcodec_decoder_from_file ,
592
587
},
593
588
label = f"video={ first_video_file_path } { metadata_label } " ,
0 commit comments