Skip to content

Commit 6dc8d12

Browse files
Dan-FloresDaniel Flores
andauthored
Update resource generation script to python (#828)
Co-authored-by: Daniel Flores <[email protected]>
1 parent 1dd1bc7 commit 6dc8d12

File tree

5 files changed

+128
-106
lines changed

5 files changed

+128
-106
lines changed

.github/workflows/reference_resources.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ on:
44
workflow_dispatch:
55
pull_request:
66
paths:
7-
- test/generate_reference_resources.sh
7+
- test/generate_reference_resources.py
88
- .github/workflows/reference_resources.yaml # self reference
99
schedule:
1010
- cron: '0 0 * * 0' # on sunday
@@ -38,7 +38,7 @@ jobs:
3838
- name: Update pip
3939
run: python -m pip install --upgrade pip
4040

41-
- name: Instal generation dependencies
41+
- name: Install generation dependencies
4242
run: |
4343
# Note that we're installing stable - this is for running a script where we're a normal PyTorch
4444
# user, not for building TorhCodec.
@@ -50,4 +50,4 @@ jobs:
5050

5151
- name: Run generation reference resources
5252
run: |
53-
test/generate_reference_resources.sh
53+
python test/generate_reference_resources.py

test/convert_image_to_tensor.py

Lines changed: 0 additions & 24 deletions
This file was deleted.

test/generate_reference_resources.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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 subprocess
8+
from pathlib import Path
9+
10+
import numpy as np
11+
12+
import torch
13+
from PIL import Image
14+
15+
# Run this script to update the resources used in unit tests. The resources are all derived
16+
# from source media already checked into the repo.
17+
18+
19+
def convert_image_to_tensor(image_path):
20+
image_path = Path(image_path)
21+
if not image_path.exists():
22+
return
23+
# Get base filename without extension
24+
base_filename = image_path.with_suffix("")
25+
pil_image = Image.open(image_path)
26+
img_tensor = torch.from_numpy(np.asarray(pil_image))
27+
# Save tensor to disk
28+
torch.save(
29+
img_tensor, str(base_filename) + ".pt", _use_new_zipfile_serialization=True
30+
)
31+
image_path.unlink()
32+
33+
34+
def get_frame_by_index(video_path, frame, output_path, stream):
35+
cmd = [
36+
"ffmpeg",
37+
"-y",
38+
"-i",
39+
video_path,
40+
"-map",
41+
f"0:{stream}",
42+
"-vf",
43+
f"select=eq(n\\,{frame})",
44+
"-vsync",
45+
"vfr",
46+
"-q:v",
47+
"2",
48+
output_path,
49+
]
50+
subprocess.run(cmd, check=True)
51+
52+
53+
def get_frame_by_timestamp(video_path, timestamp, output_path):
54+
cmd = [
55+
"ffmpeg",
56+
"-y",
57+
"-ss",
58+
str(timestamp),
59+
"-i",
60+
video_path,
61+
"-frames:v",
62+
"1",
63+
output_path,
64+
]
65+
subprocess.run(cmd, check=True)
66+
67+
68+
def main():
69+
SCRIPT_DIR = Path(__file__).resolve().parent
70+
TORCHCODEC_PATH = SCRIPT_DIR.parent
71+
RESOURCES_DIR = TORCHCODEC_PATH / "test" / "resources"
72+
VIDEO_PATH = RESOURCES_DIR / "nasa_13013.mp4"
73+
74+
# Last generated with ffmpeg version 4.3
75+
#
76+
# Note: The naming scheme used here must match the naming scheme used to load
77+
# tensors in ./utils.py.
78+
STREAMS = [0, 3]
79+
FRAMES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 20, 25, 30, 35, 386, 387, 388, 389]
80+
for stream in STREAMS:
81+
for frame in FRAMES:
82+
# Note that we are using 0-based index naming. Asking ffmpeg to number output
83+
# frames would result in 1-based index naming. We enforce 0-based index naming
84+
# so that the name of reference frames matches the index when accessing that
85+
# frame in the Python decoder.
86+
output_bmp = f"{VIDEO_PATH}.stream{stream}.frame{frame:06d}.bmp"
87+
get_frame_by_index(VIDEO_PATH, frame, output_bmp, stream=stream)
88+
convert_image_to_tensor(output_bmp)
89+
90+
# Extract individual frames at specific timestamps, including the last frame of the video.
91+
seek_timestamp = [6.0, 6.1, 10.0, 12.979633]
92+
timestamp_name = [f"{seek_timestamp:06f}" for seek_timestamp in seek_timestamp]
93+
for timestamp, name in zip(seek_timestamp, timestamp_name):
94+
output_bmp = f"{VIDEO_PATH}.time{name}.bmp"
95+
get_frame_by_timestamp(VIDEO_PATH, timestamp, output_bmp)
96+
convert_image_to_tensor(output_bmp)
97+
98+
# This video was generated by running the following:
99+
# conda install -c conda-forge x265
100+
# ./configure --enable-nonfree --enable-gpl --prefix=$(readlink -f ../bin) --enable-libx265 --enable-rpath --extra-ldflags=-Wl,-rpath=$CONDA_PREFIX/lib --enable-filter=drawtext --enable-libfontconfig --enable-libfreetype --enable-libharfbuzz
101+
# ffmpeg -f lavfi -i color=size=128x128:duration=1:rate=10:color=blue -vf "drawtext=fontsize=30:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:text='Frame %{frame_num}'" -vcodec libx265 -pix_fmt yuv420p -g 2 -crf 10 h265_video.mp4 -y
102+
# Note that this video only has 1 stream, at index 0.
103+
VIDEO_PATH = RESOURCES_DIR / "h265_video.mp4"
104+
FRAMES = [5]
105+
for frame in FRAMES:
106+
output_bmp = f"{VIDEO_PATH}.stream0.frame{frame:06d}.bmp"
107+
get_frame_by_index(VIDEO_PATH, frame, output_bmp, stream=0)
108+
convert_image_to_tensor(output_bmp)
109+
110+
# This video was generated by running the following:
111+
# ffmpeg -f lavfi -i testsrc=duration=5:size=640x360:rate=25,format=yuv420p -c:v libaom-av1 -crf 30 -colorspace bt709 -color_primaries bt709 -color_trc bt709 av1_video.mkv
112+
# Note that this video only has 1 stream, at index 0.
113+
VIDEO_PATH = RESOURCES_DIR / "av1_video.mkv"
114+
FRAMES = [10]
115+
116+
for frame in FRAMES:
117+
output_bmp = f"{VIDEO_PATH}.stream0.frame{frame:06d}.bmp"
118+
get_frame_by_index(VIDEO_PATH, frame, output_bmp, stream=0)
119+
convert_image_to_tensor(output_bmp)
120+
121+
122+
if __name__ == "__main__":
123+
main()

test/generate_reference_resources.sh

Lines changed: 0 additions & 79 deletions
This file was deleted.

test/utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,8 @@ def sample_format(self) -> str:
510510
return self.stream_infos[self.default_stream_index].sample_format
511511

512512

513+
# This file was generated with:
514+
# ffmpeg -y -i test/resources/nasa_13013.mp4 -b:a 192K -vn test/resources/nasa_13013.mp4.audio.mp3"
513515
NASA_AUDIO_MP3 = TestAudio(
514516
filename="nasa_13013.mp4.audio.mp3",
515517
default_stream_index=0,

0 commit comments

Comments
 (0)