Save and view video metadata (#227)
* save settings as video metadata * add selector to save metadata * add metadata viewer * save as 'comment' * fixup defaulting * add metadata writing via mutagen * tinytag -> mutagenpull/228/head
parent
d224c227e6
commit
dec26741f9
|
|
@ -2,3 +2,4 @@ imageio_ffmpeg
|
|||
av
|
||||
moviepy
|
||||
numexpr
|
||||
mutagen
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ def process_modelscope(args_dict, extra_args=None):
|
|||
f"{i:06}.png", samples[i])
|
||||
|
||||
# save settings to a file
|
||||
if opts.data.get("modelscope_save_info_to_file") if opts.data is not None and opts.data.get("modelscope_save_info_to_file") is not None else False:
|
||||
if opts.data is not None and opts.data.get("modelscope_save_info_to_file"):
|
||||
|
||||
args_file = os.path.join(outdir_current,'args.txt')
|
||||
with open(args_file, 'w', encoding='utf-8') as f:
|
||||
|
|
@ -242,10 +242,16 @@ def process_modelscope(args_dict, extra_args=None):
|
|||
|
||||
# TODO: add params to the GUI
|
||||
if not video_args.skip_video_creation:
|
||||
metadata = None
|
||||
if opts.data is not None and opts.data.get("modelscope_save_metadata") is not None:
|
||||
if opts.data.get("modelscope_save_metadata"):
|
||||
metadata = infotext
|
||||
else:
|
||||
metadata = infotext
|
||||
ffmpeg_stitch_video(ffmpeg_location=video_args.ffmpeg_location, fps=video_args.fps, outmp4_path=outdir_current + os.path.sep + f"vid.mp4", imgs_path=os.path.join(outdir_current,
|
||||
"%06d.png"),
|
||||
stitch_from_frame=0, stitch_to_frame=-1, add_soundtrack=video_args.add_soundtrack,
|
||||
audio_path=vid2vid_frames_path if video_args.add_soundtrack == 'Init Video' else video_args.soundtrack_path, crf=video_args.ffmpeg_crf, preset=video_args.ffmpeg_preset)
|
||||
audio_path=vid2vid_frames_path if video_args.add_soundtrack == 'Init Video' else video_args.soundtrack_path, crf=video_args.ffmpeg_crf, preset=video_args.ffmpeg_preset, metadata=metadata)
|
||||
print(f't2v complete, result saved at {outdir_current}')
|
||||
|
||||
mp4 = open(outdir_current + os.path.sep + f"vid.mp4", 'rb').read()
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import os
|
|||
import modules.paths as ph
|
||||
from t2v_helpers.general_utils import get_model_location
|
||||
from modules.shared import opts
|
||||
from mutagen.mp4 import MP4
|
||||
|
||||
welcome_text_videocrafter = '''- Download pretrained T2V models via <a style="color:SteelBlue" href="https://drive.google.com/file/d/13ZZTXyAKM3x0tObRQOQWdtnrI2ARWYf_/view?usp=share_link">this link</a>, and put the model.ckpt in models/VideoCrafter/model.ckpt. Then use the same GUI pipeline as ModelScope does.
|
||||
'''
|
||||
|
|
@ -150,6 +151,20 @@ Example: `0:(0), "max_i_f/4":(1), "3*max_i_f/4":(1), "max_i_f-1":(0)` ''')
|
|||
ffmpeg_preset = gr.Dropdown(label="Preset", choices=['veryslow', 'slower', 'slow', 'medium', 'fast', 'faster', 'veryfast', 'superfast', 'ultrafast'], interactive=True, value=dv.ffmpeg_preset, type="value")
|
||||
with gr.Row(equal_height=True, variant='compact', visible=True) as ffmpeg_location_row:
|
||||
ffmpeg_location = gr.Textbox(label="Location", lines=1, interactive=True, value=dv.ffmpeg_location)
|
||||
with gr.Accordion(label='Metadata viewer', open=False, visible=True):
|
||||
with gr.Row(variant='compact'):
|
||||
metadata_file = gr.File(label="Video", interactive=True, file_count="single", file_types=["video"], elem_id="metadata_chosen_file")
|
||||
with gr.Row(variant='compact'):
|
||||
metadata_btn = gr.Button(value='Get metadata')
|
||||
with gr.Row(variant='compact'):
|
||||
metadata_box = gr.HTML()
|
||||
|
||||
def get_metadata(file):
|
||||
print('Reading metadata')
|
||||
video = MP4(file.name)
|
||||
return video["\xa9cmt"]
|
||||
|
||||
metadata_btn.click(get_metadata, inputs=[metadata_file], outputs=[metadata_box])
|
||||
with gr.Tab('How to install? Where to get help, how to help?'):
|
||||
gr.Markdown(welcome_text)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import os, shutil
|
|||
import cv2
|
||||
from modules.shared import state
|
||||
from pkg_resources import resource_filename
|
||||
import requests
|
||||
from mutagen.mp4 import MP4
|
||||
|
||||
def get_frame_name(path):
|
||||
name = os.path.basename(path)
|
||||
|
|
@ -121,7 +123,7 @@ def find_ffmpeg_binary():
|
|||
return 'ffmpeg'
|
||||
|
||||
# Stitch images to a h264 mp4 video using ffmpeg
|
||||
def ffmpeg_stitch_video(ffmpeg_location=None, fps=None, outmp4_path=None, stitch_from_frame=0, stitch_to_frame=None, imgs_path=None, add_soundtrack=None, audio_path=None, crf=17, preset='veryslow'):
|
||||
def ffmpeg_stitch_video(ffmpeg_location=None, fps=None, outmp4_path=None, stitch_from_frame=0, stitch_to_frame=None, imgs_path=None, add_soundtrack=None, audio_path=None, crf=17, preset='veryslow', metadata=None):
|
||||
start_time = time.time()
|
||||
|
||||
print(f"Got a request to stitch frames to video using FFmpeg.\nFrames:\n{imgs_path}\nTo Video:\n{outmp4_path}")
|
||||
|
|
@ -145,8 +147,10 @@ def ffmpeg_stitch_video(ffmpeg_location=None, fps=None, outmp4_path=None, stitch
|
|||
'-crf', str(crf),
|
||||
'-preset', preset,
|
||||
'-pattern_type', 'sequence',
|
||||
outmp4_path
|
||||
]
|
||||
|
||||
cmd.append(outmp4_path)
|
||||
|
||||
process = subprocess.Popen(
|
||||
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = process.communicate()
|
||||
|
|
@ -174,8 +178,10 @@ def ffmpeg_stitch_video(ffmpeg_location=None, fps=None, outmp4_path=None, stitch
|
|||
'-map', '1:a',
|
||||
'-c:v', 'copy',
|
||||
'-shortest',
|
||||
outmp4_path+'.temp.mp4'
|
||||
]
|
||||
|
||||
cmd.append(outmp4_path+'.temp.mp4')
|
||||
|
||||
process = subprocess.Popen(
|
||||
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout, stderr = process.communicate()
|
||||
|
|
@ -195,6 +201,14 @@ def ffmpeg_stitch_video(ffmpeg_location=None, fps=None, outmp4_path=None, stitch
|
|||
else:
|
||||
print("\r" + " " * len(msg_to_print), end="", flush=True)
|
||||
print(f"\r{msg_to_print}", flush=True)
|
||||
|
||||
# adding metadata
|
||||
if metadata is not None:
|
||||
print('Writing metadata')
|
||||
video = MP4(outmp4_path)
|
||||
video["\xa9cmt"] = metadata
|
||||
video.save()
|
||||
|
||||
print(f"\rVideo stitching \033[0;32mdone\033[0m in {time.time() - start_time:.2f} seconds!", flush=True)
|
||||
|
||||
# quick-retreive frame count, FPS and H/W dimensions of a video (local or URL-based)
|
||||
|
|
@ -237,7 +251,7 @@ def duplicate_pngs_from_folder(from_folder, to_folder, img_batch_id, orig_vid_na
|
|||
cv2.imwrite(new_path, image, [cv2.IMWRITE_PNG_COMPRESSION, 0])
|
||||
return frames_handled
|
||||
|
||||
def add_soundtrack(ffmpeg_location=None, fps=None, outmp4_path=None, stitch_from_frame=0, stitch_to_frame=None, imgs_path=None, add_soundtrack=None, audio_path=None, crf=17, preset='veryslow'):
|
||||
def add_soundtrack(ffmpeg_location=None, fps=None, outmp4_path=None, stitch_from_frame=0, stitch_to_frame=None, imgs_path=None, add_soundtrack=None, audio_path=None, crf=17, preset='veryslow', metadata=None):
|
||||
if add_soundtrack is None:
|
||||
return
|
||||
msg_to_print = f"Adding soundtrack to *video*..."
|
||||
|
|
|
|||
|
|
@ -112,6 +112,8 @@ def on_ui_settings():
|
|||
-1, "How many videos to show on the right panel on completion (-1 = show all)", gr.Number, {"interactive": True, "visible": True}, section=section))
|
||||
shared.opts.add_option("modelscope_save_info_to_file", shared.OptionInfo(
|
||||
False, "Save generation params to a text file near the video", gr.Checkbox, {'interactive':True, 'visible':True}, section=section))
|
||||
shared.opts.add_option("modelscope_save_metadata", shared.OptionInfo(
|
||||
True, "Save generation params as video metadata", gr.Checkbox, {'interactive':True, 'visible':True}, section=section))
|
||||
|
||||
script_callbacks.on_ui_tabs(on_ui_tabs)
|
||||
script_callbacks.on_ui_settings(on_ui_settings)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Read LICENSE for usage terms.
|
||||
*/
|
||||
|
||||
#vid_to_vid_chosen_file .w-full, #inpainting_chosen_file .w-full {
|
||||
#vid_to_vid_chosen_file .w-full, #inpainting_chosen_file .w-full, #metadata_chosen_file .w-full {
|
||||
display: flex !important;
|
||||
align-items: flex-start !important;
|
||||
justify-content: center !important;
|
||||
|
|
|
|||
Loading…
Reference in New Issue