Skip to content

Commit 1f77300

Browse files
DN6sayakpaul
authored andcommitted
Update Video Loading/Export to use imageio (#9094)
* update * update * update --------- Co-authored-by: Sayak Paul <spsayakpaul@gmail.com>
1 parent 8a79d8e commit 1f77300

File tree

3 files changed

+85
-15
lines changed

3 files changed

+85
-15
lines changed

src/diffusers/utils/export_utils.py

+50-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import PIL.Image
1010
import PIL.ImageOps
1111

12-
from .import_utils import BACKENDS_MAPPING, is_opencv_available
12+
from .import_utils import BACKENDS_MAPPING, is_imageio_available, is_opencv_available
1313
from .logging import get_logger
1414

1515

@@ -112,9 +112,9 @@ def export_to_obj(mesh, output_obj_path: str = None):
112112
f.writelines("\n".join(combined_data))
113113

114114

115-
def export_to_video(
115+
def _legacy_export_to_video(
116116
video_frames: Union[List[np.ndarray], List[PIL.Image.Image]], output_video_path: str = None, fps: int = 10
117-
) -> str:
117+
):
118118
if is_opencv_available():
119119
import cv2
120120
else:
@@ -134,4 +134,51 @@ def export_to_video(
134134
for i in range(len(video_frames)):
135135
img = cv2.cvtColor(video_frames[i], cv2.COLOR_RGB2BGR)
136136
video_writer.write(img)
137+
138+
return output_video_path
139+
140+
141+
def export_to_video(
142+
video_frames: Union[List[np.ndarray], List[PIL.Image.Image]], output_video_path: str = None, fps: int = 10
143+
) -> str:
144+
# TODO: Dhruv. Remove by Diffusers release 0.33.0
145+
# Added to prevent breaking existing code
146+
if not is_imageio_available():
147+
logger.warning(
148+
(
149+
"It is recommended to use `export_to_video` with `imageio` and `imageio-ffmpeg` as a backend. \n"
150+
"These libraries are not present in your environment. Attempting to use legacy OpenCV backend to export video. \n"
151+
"Support for the OpenCV backend will be deprecated in a future Diffusers version"
152+
)
153+
)
154+
return _legacy_export_to_video(video_frames, output_video_path, fps)
155+
156+
if is_imageio_available():
157+
import imageio
158+
else:
159+
raise ImportError(BACKENDS_MAPPING["imageio"][1].format("export_to_video"))
160+
161+
try:
162+
imageio.plugins.ffmpeg.get_exe()
163+
except AttributeError:
164+
raise AttributeError(
165+
(
166+
"Found an existing imageio backend in your environment. Attempting to export video with imageio. \n"
167+
"Unable to find a compatible ffmpeg installation in your environment to use with imageio. Please install via `pip install imageio-ffmpeg"
168+
)
169+
)
170+
171+
if output_video_path is None:
172+
output_video_path = tempfile.NamedTemporaryFile(suffix=".mp4").name
173+
174+
if isinstance(video_frames[0], np.ndarray):
175+
video_frames = [(frame * 255).astype(np.uint8) for frame in video_frames]
176+
177+
elif isinstance(video_frames[0], PIL.Image.Image):
178+
video_frames = [np.array(frame) for frame in video_frames]
179+
180+
with imageio.get_writer(output_video_path, fps=fps) as writer:
181+
for frame in video_frames:
182+
writer.append_data(frame)
183+
137184
return output_video_path

src/diffusers/utils/import_utils.py

+19
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ def is_timm_available():
330330

331331
_is_google_colab = "google.colab" in sys.modules or any(k.startswith("COLAB_") for k in os.environ)
332332

333+
_imageio_available = importlib.util.find_spec("imageio") is not None
334+
if _imageio_available:
335+
try:
336+
_imageio_version = importlib_metadata.version("imageio")
337+
logger.debug(f"Successfully imported imageio version {_imageio_version}")
338+
339+
except importlib_metadata.PackageNotFoundError:
340+
_imageio_available = False
341+
333342

334343
def is_torch_available():
335344
return _torch_available
@@ -447,6 +456,10 @@ def is_sentencepiece_available():
447456
return _sentencepiece_available
448457

449458

459+
def is_imageio_available():
460+
return _imageio_available
461+
462+
450463
# docstyle-ignore
451464
FLAX_IMPORT_ERROR = """
452465
{0} requires the FLAX library but it was not found in your environment. Checkout the instructions on the
@@ -575,6 +588,11 @@ def is_sentencepiece_available():
575588
{0} requires the bitsandbytes library but it was not found in your environment. You can install it with pip: `pip install bitsandbytes`
576589
"""
577590

591+
# docstyle-ignore
592+
IMAGEIO_IMPORT_ERROR = """
593+
{0} requires the imageio library and ffmpeg but it was not found in your environment. You can install it with pip: `pip install imageio imageio-ffmpeg`
594+
"""
595+
578596
BACKENDS_MAPPING = OrderedDict(
579597
[
580598
("bs4", (is_bs4_available, BS4_IMPORT_ERROR)),
@@ -599,6 +617,7 @@ def is_sentencepiece_available():
599617
("safetensors", (is_safetensors_available, SAFETENSORS_IMPORT_ERROR)),
600618
("bitsandbytes", (is_bitsandbytes_available, BITSANDBYTES_IMPORT_ERROR)),
601619
("sentencepiece", (is_sentencepiece_available, SENTENCEPIECE_IMPORT_ERROR)),
620+
("imageio", (is_imageio_available, IMAGEIO_IMPORT_ERROR)),
602621
]
603622
)
604623

src/diffusers/utils/loading_utils.py

+16-12
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import PIL.ImageOps
77
import requests
88

9-
from .import_utils import BACKENDS_MAPPING, is_opencv_available
9+
from .import_utils import BACKENDS_MAPPING, is_imageio_available
1010

1111

1212
def load_image(
@@ -81,7 +81,8 @@ def load_video(
8181

8282
if is_url:
8383
video_data = requests.get(video, stream=True).raw
84-
video_path = tempfile.NamedTemporaryFile(suffix=os.path.splitext(video)[1], delete=False).name
84+
suffix = os.path.splitext(video)[1] or ".mp4"
85+
video_path = tempfile.NamedTemporaryFile(suffix=suffix, delete=False).name
8586
was_tempfile_created = True
8687
with open(video_path, "wb") as f:
8788
f.write(video_data.read())
@@ -99,19 +100,22 @@ def load_video(
99100
pass
100101

101102
else:
102-
if is_opencv_available():
103-
import cv2
103+
if is_imageio_available():
104+
import imageio
104105
else:
105-
raise ImportError(BACKENDS_MAPPING["opencv"][1].format("load_video"))
106+
raise ImportError(BACKENDS_MAPPING["imageio"][1].format("load_video"))
106107

107-
video_capture = cv2.VideoCapture(video)
108-
success, frame = video_capture.read()
109-
while success:
110-
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
111-
pil_images.append(PIL.Image.fromarray(frame))
112-
success, frame = video_capture.read()
108+
try:
109+
imageio.plugins.ffmpeg.get_exe()
110+
except AttributeError:
111+
raise AttributeError(
112+
"`Unable to find an ffmpeg installation on your machine. Please install via `pip install imageio-ffmpeg"
113+
)
113114

114-
video_capture.release()
115+
with imageio.get_reader(video) as reader:
116+
# Read all frames
117+
for frame in reader:
118+
pil_images.append(PIL.Image.fromarray(frame))
115119

116120
if was_tempfile_created:
117121
os.remove(video_path)

0 commit comments

Comments
 (0)