kevinwang676's picture
Upload folder using huggingface_hub
6755a2d verified
raw
history blame
5.93 kB
import json
from typing import Tuple
import logging
from librosa.core.audio import get_duration
from moviepy.editor import CompositeVideoClip, concatenate_videoclips, TextClip
import moviepy as mvp
ignored_log = logging.getLogger("PIL")
ignored_log.setLevel(level=logging.INFO)
import logging
logger = logging.getLogger(__name__) # pylint: disable=invalid-name
def generate_lyric_video_from_music_map(
music_map: dict,
size=None,
duration: float = None,
fontsize: float = 50,
padding: int = 0,
gap_th: float = 2,
font: str = "STXinwei",
):
"""从音乐谱面生成歌词 videoclip
Args:
music_map (dict): 音乐谱面,meta_info中必须含有歌词clip信息
size (_type_, optional): _description_. Defaults to None.
duration (float, optional): 歌词总时长. Defaults to None.
fontsize (float, optional): 歌词字体大小. Defaults to 50.
padding (int, optional): _description_. Defaults to 0.
gap_th (float, optional): 补全歌词clip中的间隙部分. Defaults to 2.
font (str, optional): 字体. Defaults to "STXinwei",需要安装.
Returns:
moviepy.VideoClip: 生成的歌词视频
"""
if isinstance(music_map, str):
music_map = MusicInfo(music_map)
lyric_clipseq = complete_clipseq(
clipseq=music_map.meta_info.lyric, duration=duration, gap_th=gap_th
)
videoclips = []
if music_map.meta_info.media_name is not None:
media_name = music_map.meta_info.media_name
else:
media_name = ""
if music_map.meta_info.singer is not None:
singer = music_map.meta_info.singer
else:
singer = ""
if music_map.meta_info.album is not None:
album = music_map.meta_info.album
else:
album = ""
title = "{} {} {}".format(album, media_name, singer)
# if size is not None
title_clip = TextClip(
title,
fontsize=int(fontsize * 1.1),
color="white",
font=font,
stroke_width=2,
)
title_clip = title_clip.set_duration(3)
for i, clip in enumerate(lyric_clipseq):
time_start = clip.time_start
duration = clip.duration
if clip.text is not None:
txt = clip.text
else:
txt = " "
logger.debug(
"render lyric, lyric={}, time_start={}, duration={}".format(
txt, time_start, duration
)
)
txt_clip = TextClip(
txt, fontsize=fontsize, color="white", font=font, stroke_width=2
)
txt_clip = txt_clip.set_duration(duration)
videoclips.append(txt_clip)
videoclips = concatenate_videoclips(videoclips, method="compose")
videoclips = CompositeVideoClip([videoclips, title_clip])
videoclips.audio = None
if duration is None:
duration = lyric_clipseq[-1].time_start + lyric_clipseq[-1].duration
# videoclips.set_duration(duration)
return videoclips
def generate_lyric_video_from_lyric(
path: str,
audio_path: str = None,
duration: float = None,
size: Tuple = None,
fontsize: int = None,
padding: int = 0,
font: str = "Courier",
):
"""从歌词文件中生成歌词视频
Args:
path (str): 歌词文件
audio_path (str, optional): 对应的音频文件,主要用于提取音频总时长. Defaults to None.
duration (float, optional): 歌曲总时长. Defaults to None.
size (Tuple, optional): _description_. Defaults to None.
fontsize (int, optional): 渲染的歌词字体大小. Defaults to None.
padding (int, optional): _description_. Defaults to 0.
Returns:
moviepy. VideoClip: 渲染好的歌词视频
"""
if audio_path is not None:
duration = get_duration(audio_path)
music_map = generate_lyric_map(path=path, duration=duration)
clip = generate_lyric_video_from_music_map(
music_map,
size=size,
duration=duration,
padding=padding,
fontsize=fontsize,
font=font,
)
return clip
def render_lyric2video(
videoclip,
lyric: dict,
lyric_info_type: str = "music_map",
fontsize: int = 25,
font: str = "Courier",
audio_path: str = None,
duration: float = None,
padding: int = 0,
):
"""对视频进行歌词渲染
Args:
videoclip (moviepy.VideoClip): 待渲染的视频
lyric (dict): 歌词信息,也可以是歌词路径
lyric_info_type (str, optional): 歌词类型,可以是 qrc, 也可以是谱面. Defaults to "music_map".
fontsize (int, optional): 渲染的歌词大小. Defaults to 25.
audio_path (str, optional): 音频路径,主要提供一些必要信息. Defaults to None.
duration (float, optional): 音频总时长. Defaults to None.
padding (int, optional): _description_. Defaults to 0.
Raises:
ValueError: _description_
Returns:
moviepy.VideoClip: 渲染好歌词的视频文件
"""
size = (videoclip.w, videoclip.h)
if fontsize is None:
fontsize = int(videoclip.w / 1280 * fontsize)
if lyric_info_type == "lyric":
lyric_clip = generate_lyric_video_from_lyric(
lyric,
size=size,
fontsize=fontsize,
font=font,
)
elif lyric_info_type == "music_map":
lyric_clip = generate_lyric_video_from_music_map(
lyric,
size=size,
fontsize=fontsize,
font=font,
)
else:
raise ValueError("not support {}".format(lyric_info_type))
lyric_clip = lyric_clip.set_position(("center", "bottom"))
lyric_video_clip = CompositeVideoClip([videoclip, lyric_clip], size=size)
lyric_video_clip.audio = videoclip.audio
logger.debug("lyric_clip: duration={}".format(lyric_clip.duration))
return lyric_video_clip