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 -> mutagen
pull/228/head
kabachuha 2023-08-31 23:07:33 +03:00 committed by GitHub
parent d224c227e6
commit dec26741f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 7 deletions

View File

@ -2,3 +2,4 @@ imageio_ffmpeg
av
moviepy
numexpr
mutagen

View File

@ -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()

View File

@ -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)

View File

@ -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*..."

View File

@ -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)

View File

@ -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;