Joeythemonster commited on
Commit
8d316a9
1 Parent(s): 4c9a7db

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +435 -0
README.md CHANGED
@@ -12,3 +12,438 @@ Or you can run your new concept via `diffusers` [Colab Notebook for Inference](h
12
 
13
  Sample pictures of this concept:
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  Sample pictures of this concept:
14
 
15
+
16
+ import subprocess, time, gc, os, sys
17
+
18
+ def setup_environment():
19
+ start_time = time.time()
20
+ print_subprocess = False
21
+ use_xformers_for_colab = True
22
+ try:
23
+ ipy = get_ipython()
24
+ except:
25
+ ipy = 'could not get_ipython'
26
+ if 'google.colab' in str(ipy):
27
+ print("..setting up environment")
28
+
29
+ all_process = [
30
+ ['pip', 'install', 'torch==1.12.1+cu113', 'torchvision==0.13.1+cu113', '--extra-index-url', 'https://download.pytorch.org/whl/cu113'],
31
+ ['pip', 'install', 'omegaconf==2.2.3', 'einops==0.4.1', 'pytorch-lightning==1.7.4', 'torchmetrics==0.9.3', 'torchtext==0.13.1', 'transformers==4.21.2', 'safetensors', 'kornia==0.6.7'],
32
+ ['git', 'clone', 'https://github.com/deforum-art/deforum-stable-diffusion'],
33
+ ['pip', 'install', 'accelerate', 'ftfy', 'jsonmerge', 'matplotlib', 'resize-right', 'timm', 'torchdiffeq','scikit-learn','torchsde','open-clip-torch'],
34
+ ]
35
+ for process in all_process:
36
+ running = subprocess.run(process,stdout=subprocess.PIPE).stdout.decode('utf-8')
37
+ if print_subprocess:
38
+ print(running)
39
+ with open('deforum-stable-diffusion/src/k_diffusion/__init__.py', 'w') as f:
40
+ f.write('')
41
+ sys.path.extend([
42
+ 'deforum-stable-diffusion/',
43
+ 'deforum-stable-diffusion/src',
44
+ ])
45
+ if use_xformers_for_colab:
46
+
47
+ print("..installing xformers")
48
+
49
+ all_process = [['pip', 'install', 'triton==2.0.0.dev20220701']]
50
+ for process in all_process:
51
+ running = subprocess.run(process,stdout=subprocess.PIPE).stdout.decode('utf-8')
52
+ if print_subprocess:
53
+ print(running)
54
+
55
+ v_card_name = subprocess.run(['nvidia-smi', '--query-gpu=name', '--format=csv,noheader'], stdout=subprocess.PIPE).stdout.decode('utf-8')
56
+ if 't4' in v_card_name.lower():
57
+ name_to_download = 'T4'
58
+ elif 'v100' in v_card_name.lower():
59
+ name_to_download = 'V100'
60
+ elif 'a100' in v_card_name.lower():
61
+ name_to_download = 'A100'
62
+ elif 'p100' in v_card_name.lower():
63
+ name_to_download = 'P100'
64
+ elif 'a4000' in v_card_name.lower():
65
+ name_to_download = 'Non-Colab/Paperspace/A4000'
66
+ elif 'p5000' in v_card_name.lower():
67
+ name_to_download = 'Non-Colab/Paperspace/P5000'
68
+ elif 'quadro m4000' in v_card_name.lower():
69
+ name_to_download = 'Non-Colab/Paperspace/Quadro M4000'
70
+ elif 'rtx 4000' in v_card_name.lower():
71
+ name_to_download = 'Non-Colab/Paperspace/RTX 4000'
72
+ elif 'rtx 5000' in v_card_name.lower():
73
+ name_to_download = 'Non-Colab/Paperspace/RTX 5000'
74
+ else:
75
+ print(v_card_name + ' is currently not supported with xformers flash attention in deforum!')
76
+
77
+ if 'Non-Colab' in name_to_download:
78
+ x_ver = 'xformers-0.0.14.dev0-cp39-cp39-linux_x86_64.whl'
79
+ else:
80
+ x_ver = 'xformers-0.0.13.dev0-py3-none-any.whl'
81
+
82
+ x_link = 'https://github.com/TheLastBen/fast-stable-diffusion/raw/main/precompiled/' + name_to_download + '/' + x_ver
83
+
84
+ all_process = [
85
+ ['wget', '--no-verbose', '--no-clobber', x_link],
86
+ ['pip', 'install', x_ver],
87
+ ]
88
+
89
+ for process in all_process:
90
+ running = subprocess.run(process,stdout=subprocess.PIPE).stdout.decode('utf-8')
91
+ if print_subprocess:
92
+ print(running)
93
+ else:
94
+ sys.path.extend([
95
+ 'src'
96
+ ])
97
+ end_time = time.time()
98
+ print(f"..environment set up in {end_time-start_time:.0f} seconds")
99
+ return
100
+
101
+ setup_environment()
102
+
103
+ import torch
104
+ import random
105
+ import clip
106
+ from IPython import display
107
+ from types import SimpleNamespace
108
+ from helpers.save_images import get_output_folder
109
+ from helpers.settings import load_args
110
+ from helpers.render import render_animation, render_input_video, render_image_batch, render_interpolation
111
+ from helpers.model_load import make_linear_decode, load_model, get_model_output_paths
112
+ from helpers.aesthetics import load_aesthetics_model
113
+
114
+ #@markdown **Path Setup**
115
+
116
+ def Root():
117
+ models_path = "models" #@param {type:"string"}
118
+ configs_path = "configs" #@param {type:"string"}
119
+ output_path = "output" #@param {type:"string"}
120
+ mount_google_drive = True #@param {type:"boolean"}
121
+ models_path_gdrive = "/content/drive/MyDrive/AI/models" #@param {type:"string"}
122
+ output_path_gdrive = "/content/drive/MyDrive/AI/StableDiffusion" #@param {type:"string"}
123
+
124
+ #@markdown **Model Setup**
125
+ model_config = "v1-inference.yaml" #@param ["custom","v2-inference.yaml","v1-inference.yaml"]
126
+ model_checkpoint = "v1-5-pruned-emaonly.ckpt" #@param ["custom","512-base-ema.ckpt","v1-5-pruned.ckpt","v1-5-pruned-emaonly.ckpt","sd-v1-4-full-ema.ckpt","sd-v1-4.ckpt","sd-v1-3-full-ema.ckpt","sd-v1-3.ckpt","sd-v1-2-full-ema.ckpt","sd-v1-2.ckpt","sd-v1-1-full-ema.ckpt","sd-v1-1.ckpt", "robo-diffusion-v1.ckpt","wd-v1-3-float16.ckpt"]
127
+ custom_config_path = "" #@param {type:"string"}
128
+ custom_checkpoint_path = "" #@param {type:"string"}
129
+ half_precision = True
130
+ return locals()
131
+
132
+ root = Root()
133
+ root = SimpleNamespace(**root)
134
+
135
+ root.models_path, root.output_path = get_model_output_paths(root)
136
+ root.model, root.device = load_model(root,
137
+ load_on_run_all=True
138
+ ,
139
+ check_sha256=True
140
+ )
141
+
142
+
143
+ def DeforumAnimArgs():
144
+
145
+ #@markdown ####**Animation:**
146
+ animation_mode = 'Video Input' #@param ['None', '2D', '3D', 'Video Input', 'Interpolation'] {type:'string'}
147
+ max_frames = 400 #@param {type:"number"}
148
+ border = 'replicate' #@param ['wrap', 'replicate'] {type:'string'}
149
+
150
+ #@markdown ####**Motion Parameters:**
151
+ angle = "0:(0)"#@param {type:"string"}
152
+ zoom = "0:(1.04)"#@param {type:"string"}
153
+ translation_x = "0:(10*sin(2*3.14*t/10))"#@param {type:"string"}
154
+ translation_y = "0:(0)"#@param {type:"string"}
155
+ translation_z = "0:(10)"#@param {type:"string"}
156
+ rotation_3d_x = "0:(0)"#@param {type:"string"}
157
+ rotation_3d_y = "0:(0)"#@param {type:"string"}
158
+ rotation_3d_z = "0:(0)"#@param {type:"string"}
159
+ flip_2d_perspective = False #@param {type:"boolean"}
160
+ perspective_flip_theta = "0:(0)"#@param {type:"string"}
161
+ perspective_flip_phi = "0:(t%15)"#@param {type:"string"}
162
+ perspective_flip_gamma = "0:(0)"#@param {type:"string"}
163
+ perspective_flip_fv = "0:(53)"#@param {type:"string"}
164
+ noise_schedule = "0: (0.02)"#@param {type:"string"}
165
+ strength_schedule = "0: (0.65)"#@param {type:"string"}
166
+ contrast_schedule = "0: (1.0)"#@param {type:"string"}
167
+
168
+ #@markdown ####**Coherence:**
169
+ color_coherence = 'Match Frame 0 LAB' #@param ['None', 'Match Frame 0 HSV', 'Match Frame 0 LAB', 'Match Frame 0 RGB'] {type:'string'}
170
+ diffusion_cadence = '1' #@param ['1','2','3','4','5','6','7','8'] {type:'string'}
171
+
172
+ #@markdown ####**3D Depth Warping:**
173
+ use_depth_warping = True #@param {type:"boolean"}
174
+ midas_weight = 0.3#@param {type:"number"}
175
+ near_plane = 200
176
+ far_plane = 10000
177
+ fov = 40#@param {type:"number"}
178
+ padding_mode = 'border'#@param ['border', 'reflection', 'zeros'] {type:'string'}
179
+ sampling_mode = 'bicubic'#@param ['bicubic', 'bilinear', 'nearest'] {type:'string'}
180
+ save_depth_maps = True #@param {type:"boolean"}
181
+
182
+ #@markdown ####**Video Input:**
183
+ video_init_path ='/content/drive/MyDrive/mp4 for deforum/stan.mp4'#@param {type:"string"}
184
+ extract_nth_frame = 1#@param {type:"number"}
185
+ overwrite_extracted_frames = True #@param {type:"boolean"}
186
+ use_mask_video = False #@param {type:"boolean"}
187
+ video_mask_path ='/content/drive/MyDrive/mp4 for deforum/stan.mp4'#@param {type:"string"}
188
+
189
+ #@markdown ####**Interpolation:**
190
+ interpolate_key_frames = False #@param {type:"boolean"}
191
+ interpolate_x_frames = 4 #@param {type:"number"}
192
+
193
+ #@markdown ####**Resume Animation:**
194
+ resume_from_timestring = False #@param {type:"boolean"}
195
+ resume_timestring = "20220829210106" #@param {type:"string"}
196
+
197
+ return locals()
198
+
199
+ prompts = [
200
+ "a beautiful lake by Asher Brown Durand, trending on Artstation", # the first prompt I want
201
+ "a beautiful portrait of a woman by Artgerm, trending on Artstation", # the second prompt I want
202
+ #"this prompt I don't want it I commented it out",
203
+ #"a nousr robot, trending on Artstation", # use "nousr robot" with the robot diffusion model (see model_checkpoint setting)
204
+ #"touhou 1girl komeiji_koishi portrait, green hair", # waifu diffusion prompts can use danbooru tag groups (see model_checkpoint)
205
+ #"this prompt has weights if prompt weighting enabled:2 can also do negative:-2", # (see prompt_weighting)
206
+ ]
207
+
208
+ animation_prompts = {
209
+ 0: "a beautiful death, trending on Artstation",
210
+ 100: "a beautiful rebirth, trending on Artstation",
211
+ 200: "a beautiful rise to the top, trending on Artstation",
212
+ 300: "a beautiful world, trending on Artstation",
213
+ }
214
+
215
+
216
+ #@markdown **Load Settings**
217
+ override_settings_with_file = False #@param {type:"boolean"}
218
+ settings_file = "custom" #@param ["custom", "512x512_aesthetic_0.json","512x512_aesthetic_1.json","512x512_colormatch_0.json","512x512_colormatch_1.json","512x512_colormatch_2.json","512x512_colormatch_3.json"]
219
+ custom_settings_file = "/content/drive/MyDrive/Settings.txt"#@param {type:"string"}
220
+
221
+ def DeforumArgs():
222
+ #@markdown **Image Settings**
223
+ W = 512 #@param
224
+ H = 512 #@param
225
+ W, H = map(lambda x: x - x % 64, (W, H)) # resize to integer multiple of 64
226
+
227
+ #@markdown **Sampling Settings**
228
+ seed = -1 #@param
229
+ sampler = 'euler_ancestral' #@param ["klms","dpm2","dpm2_ancestral","heun","euler","euler_ancestral","plms", "ddim", "dpm_fast", "dpm_adaptive", "dpmpp_2s_a", "dpmpp_2m"]
230
+ steps = 80 #@param
231
+ scale = 7 #@param
232
+ ddim_eta = 0.0 #@param
233
+ dynamic_threshold = None
234
+ static_threshold = None
235
+
236
+ #@markdown **Save & Display Settings**
237
+ save_samples = True #@param {type:"boolean"}
238
+ save_settings = True #@param {type:"boolean"}
239
+ display_samples = True #@param {type:"boolean"}
240
+ save_sample_per_step = False #@param {type:"boolean"}
241
+ show_sample_per_step = False #@param {type:"boolean"}
242
+
243
+ #@markdown **Prompt Settings**
244
+ prompt_weighting = True #@param {type:"boolean"}
245
+ normalize_prompt_weights = True #@param {type:"boolean"}
246
+ log_weighted_subprompts = False #@param {type:"boolean"}
247
+
248
+ #@markdown **Batch Settings**
249
+ n_batch = 1 #@param
250
+ batch_name = "STAN" #@param {type:"string"}
251
+ filename_format = "{timestring}_{index}_{prompt}.png" #@param ["{timestring}_{index}_{seed}.png","{timestring}_{index}_{prompt}.png"]
252
+ seed_behavior = "iter" #@param ["iter","fixed","random"]
253
+ make_grid = False #@param {type:"boolean"}
254
+ grid_rows = 2 #@param
255
+ outdir = get_output_folder(root.output_path, batch_name)
256
+
257
+ #@markdown **Init Settings**
258
+ use_init = False #@param {type:"boolean"}
259
+ strength = 0.0 #@param {type:"number"}
260
+ strength_0_no_init = True # Set the strength to 0 automatically when no init image is used
261
+ init_image = "https://cdn.pixabay.com/photo/2022/07/30/13/10/green-longhorn-beetle-7353749_1280.jpg" #@param {type:"string"}
262
+ # Whiter areas of the mask are areas that change more
263
+ use_mask = False #@param {type:"boolean"}
264
+ use_alpha_as_mask = False # use the alpha channel of the init image as the mask
265
+ mask_file = "https://www.filterforge.com/wiki/images/archive/b/b7/20080927223728%21Polygonal_gradient_thumb.jpg" #@param {type:"string"}
266
+ invert_mask = False #@param {type:"boolean"}
267
+ # Adjust mask image, 1.0 is no adjustment. Should be positive numbers.
268
+ mask_brightness_adjust = 1.0 #@param {type:"number"}
269
+ mask_contrast_adjust = 1.0 #@param {type:"number"}
270
+ # Overlay the masked image at the end of the generation so it does not get degraded by encoding and decoding
271
+ overlay_mask = True # {type:"boolean"}
272
+ # Blur edges of final overlay mask, if used. Minimum = 0 (no blur)
273
+ mask_overlay_blur = 5 # {type:"number"}
274
+
275
+ #@markdown **Exposure/Contrast Conditional Settings**
276
+ mean_scale = 0 #@param {type:"number"}
277
+ var_scale = 0 #@param {type:"number"}
278
+ exposure_scale = 0 #@param {type:"number"}
279
+ exposure_target = 0.5 #@param {type:"number"}
280
+
281
+ #@markdown **Color Match Conditional Settings**
282
+ colormatch_scale = 0 #@param {type:"number"}
283
+ colormatch_image = "https://www.saasdesign.io/wp-content/uploads/2021/02/palette-3-min-980x588.png" #@param {type:"string"}
284
+ colormatch_n_colors = 4 #@param {type:"number"}
285
+ ignore_sat_weight = 0 #@param {type:"number"}
286
+
287
+ #@markdown **CLIP\Aesthetics Conditional Settings**
288
+ clip_name = 'ViT-L/14' #@param ['ViT-L/14', 'ViT-L/14@336px', 'ViT-B/16', 'ViT-B/32']
289
+ clip_scale = 0 #@param {type:"number"}
290
+ aesthetics_scale = 0 #@param {type:"number"}
291
+ cutn = 1 #@param {type:"number"}
292
+ cut_pow = 0.0001 #@param {type:"number"}
293
+
294
+ #@markdown **Other Conditional Settings**
295
+ init_mse_scale = 0 #@param {type:"number"}
296
+ init_mse_image = "https://cdn.pixabay.com/photo/2022/07/30/13/10/green-longhorn-beetle-7353749_1280.jpg" #@param {type:"string"}
297
+
298
+ blue_scale = 0 #@param {type:"number"}
299
+
300
+ #@markdown **Conditional Gradient Settings**
301
+ gradient_wrt = 'x0_pred' #@param ["x", "x0_pred"]
302
+ gradient_add_to = 'both' #@param ["cond", "uncond", "both"]
303
+ decode_method = 'linear' #@param ["autoencoder","linear"]
304
+ grad_threshold_type = 'dynamic' #@param ["dynamic", "static", "mean", "schedule"]
305
+ clamp_grad_threshold = 0.2 #@param {type:"number"}
306
+ clamp_start = 0.2 #@param
307
+ clamp_stop = 0.01 #@param
308
+ grad_inject_timing = list(range(1,10)) #@param
309
+
310
+ #@markdown **Speed vs VRAM Settings**
311
+ cond_uncond_sync = True #@param {type:"boolean"}
312
+
313
+ n_samples = 1 # doesnt do anything
314
+ precision = 'autocast'
315
+ C = 4
316
+ f = 8
317
+
318
+ prompt = ""
319
+ timestring = ""
320
+ init_latent = None
321
+ init_sample = None
322
+ init_sample_raw = None
323
+ mask_sample = None
324
+ init_c = None
325
+
326
+ return locals()
327
+
328
+ args_dict = DeforumArgs()
329
+ anim_args_dict = DeforumAnimArgs()
330
+
331
+ if override_settings_with_file:
332
+ load_args(args_dict, anim_args_dict, settings_file, custom_settings_file, verbose=False)
333
+
334
+ args = SimpleNamespace(**args_dict)
335
+ anim_args = SimpleNamespace(**anim_args_dict)
336
+
337
+ args.timestring = time.strftime('%Y%m%d%H%M%S')
338
+ args.strength = max(0.0, min(1.0, args.strength))
339
+
340
+ # Load clip model if using clip guidance
341
+ if (args.clip_scale > 0) or (args.aesthetics_scale > 0):
342
+ root.clip_model = clip.load(args.clip_name, jit=False)[0].eval().requires_grad_(False).to(root.device)
343
+ if (args.aesthetics_scale > 0):
344
+ root.aesthetics_model = load_aesthetics_model(args, root)
345
+
346
+ if args.seed == -1:
347
+ args.seed = random.randint(0, 2**32 - 1)
348
+ if not args.use_init:
349
+ args.init_image = None
350
+ if args.sampler == 'plms' and (args.use_init or anim_args.animation_mode != 'None'):
351
+ print(f"Init images aren't supported with PLMS yet, switching to KLMS")
352
+ args.sampler = 'klms'
353
+ if args.sampler != 'ddim':
354
+ args.ddim_eta = 0
355
+
356
+ if anim_args.animation_mode == 'None':
357
+ anim_args.max_frames = 1
358
+ elif anim_args.animation_mode == 'Video Input':
359
+ args.use_init = True
360
+
361
+ # clean up unused memory
362
+ gc.collect()
363
+ torch.cuda.empty_cache()
364
+
365
+ # dispatch to appropriate renderer
366
+ if anim_args.animation_mode == '2D' or anim_args.animation_mode == '3D':
367
+ render_animation(args, anim_args, animation_prompts, root)
368
+ elif anim_args.animation_mode == 'Video Input':
369
+ render_input_video(args, anim_args, animation_prompts, root)
370
+ elif anim_args.animation_mode == 'Interpolation':
371
+ render_interpolation(args, anim_args, animation_prompts, root)
372
+ else:
373
+ render_image_batch(args, prompts, root)
374
+
375
+
376
+
377
+ skip_video_for_run_all = False #@param {type: 'boolean'}
378
+ fps = 12 #@param {type:"number"}
379
+ #@markdown **Manual Settings**
380
+ use_manual_settings = False #@param {type:"boolean"}
381
+ image_path = "/content/drive/MyDrive/AI/StableDiffusion/2022-09/20220903000939_%05d.png" #@param {type:"string"}
382
+ mp4_path = "/content/drive/MyDrive/AI/StableDiffusion/2022-09/20220903000939.mp4" #@param {type:"string"}
383
+ render_steps = False #@param {type: 'boolean'}
384
+ path_name_modifier = "x0_pred" #@param ["x0_pred","x"]
385
+ make_gif = False
386
+
387
+ if skip_video_for_run_all == True:
388
+ print('Skipping video creation, uncheck skip_video_for_run_all if you want to run it')
389
+ else:
390
+ import os
391
+ import subprocess
392
+ from base64 import b64encode
393
+
394
+ print(f"{image_path} -> {mp4_path}")
395
+
396
+ if use_manual_settings:
397
+ max_frames = "200" #@param {type:"string"}
398
+ else:
399
+ if render_steps: # render steps from a single image
400
+ fname = f"{path_name_modifier}_%05d.png"
401
+ all_step_dirs = [os.path.join(args.outdir, d) for d in os.listdir(args.outdir) if os.path.isdir(os.path.join(args.outdir,d))]
402
+ newest_dir = max(all_step_dirs, key=os.path.getmtime)
403
+ image_path = os.path.join(newest_dir, fname)
404
+ print(f"Reading images from {image_path}")
405
+ mp4_path = os.path.join(newest_dir, f"{args.timestring}_{path_name_modifier}.mp4")
406
+ max_frames = str(args.steps)
407
+ else: # render images for a video
408
+ image_path = os.path.join(args.outdir, f"{args.timestring}_%05d.png")
409
+ mp4_path = os.path.join(args.outdir, f"{args.timestring}.mp4")
410
+ max_frames = str(anim_args.max_frames)
411
+
412
+ # make video
413
+ cmd = [
414
+ 'ffmpeg',
415
+ '-y',
416
+ '-vcodec', 'png',
417
+ '-r', str(fps),
418
+ '-start_number', str(0),
419
+ '-i', image_path,
420
+ '-frames:v', max_frames,
421
+ '-c:v', 'libx264',
422
+ '-vf',
423
+ f'fps={fps}',
424
+ '-pix_fmt', 'yuv420p',
425
+ '-crf', '17',
426
+ '-preset', 'veryfast',
427
+ '-pattern_type', 'sequence',
428
+ mp4_path
429
+ ]
430
+ process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
431
+ stdout, stderr = process.communicate()
432
+ if process.returncode != 0:
433
+ print(stderr)
434
+ raise RuntimeError(stderr)
435
+
436
+ mp4 = open(mp4_path,'rb').read()
437
+ data_url = "data:video/mp4;base64," + b64encode(mp4).decode()
438
+ display.display(display.HTML(f'<video controls loop><source src="{data_url}" type="video/mp4"></video>') )
439
+
440
+ if make_gif:
441
+ gif_path = os.path.splitext(mp4_path)[0]+'.gif'
442
+ cmd_gif = [
443
+ 'ffmpeg',
444
+ '-y',
445
+ '-i', mp4_path,
446
+ '-r', str(fps),
447
+ gif_path
448
+ ]
449
+ process_gif = subprocess.Popen(cmd_gif, stdout=subprocess.PIPE, stderr=subprocess.PIPE)