This commit is contained in:
yueliang
2024-10-07 10:48:36 +08:00
parent 02e7ef73da
commit 777ca12b3d
21 changed files with 665 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
/fonts
/__pycache__
+91
View File
@@ -0,0 +1,91 @@
<h1 align="center">ComfyUI-FFmpeg</h1>
<p align="center">
<br> <font size=5>中文 | <a href="README_EN.md">English</a></font>
</p>
## 介绍
把FFmpeg常用功能封装成ComfyUI节点,方便用户可以在ComfyUI上也可以进行各种视频处理。<br>
## 安装
#### 方法1:
1. 进入节点目录, `ComfyUI/custom_nodes/`
2. `git clone https://github.com/MoonHugo/ComfyUI-FFmpeg.git`
3. `cd ComfyUI-FFmpeg`
4. `pip install -r requirements.txt`
5. 重启ComfyUI
#### 方法2:
直接下载节点源码包,然后解压到custom_nodes目录下,最后重启ComfyUI
#### 方法3:
通过ComfyUI-Manager安装,搜索“ComfyUI-FFmpeg”进行安装
## 节点介绍
##### Video2Frames节点: 作用是将视频转为一张一张的图片,并保存到指定目录中<br>
![](./assets/1.png)
###### 参数说明
**video_path**: 本地视频路径,比如:`C:\Users\Desktop\222.mp4`
**output_path**: 输出图片保存路径,比如:`C:\Users\Desktop\output`
**frames_max_width**: 这个参数可以用来缩放视频,默认为0,表示不缩放视频,如果frames_max_width大于视频实际宽度,则视频不会被放大,保持原宽度,如果frames_max_width小于视频实际宽度,则视频会被缩小。
___
##### Frames2Video节点: 作用是将图片转为视频,并保存到指定目录中<br>
![](./assets/2.png)
###### 参数说明
**frame_path**: 本地图片路径,比如:`C:\Users\Desktop\output`
**fps**: 视频帧率,默认为`30`
**video_name**: 保存视频名称,比如:`222.mp4`
**output_path**: 视频保存路径,比如:`C:\Users\Desktop\output`
**audio_path**: 视频音频路径,比如:`C:\Users\Desktop\222.mp3`
___
##### AddTextWatermark节点: 作用是在视频上添加文字水印<br>
![](./assets/3.png)
###### 参数说明
**video_path**: 本地视频路径,比如:`C:\Users\Desktop\222.mp4`
**output_path**: 视频保存路径,比如:`C:\Users\Desktop\output`
**font_file**: 字体文件,需要把字体文件放到`custom_nodes\ComfyUI-FFmpeg\fonts`目录下,不仅英文字体,中文字体也可以,比如:`ComfyUI\custom_nodes\ComfyUI-FFmpeg\fonts\Alibaba-PuHuiTi-Heavy.ttf`
**font_size**: 水印文字大小,比如:`40`
**font_color**: 水印文字颜色,比如:`#FFFFFF`或者`white`
**position_x**: 水印文字x坐标,比如:`100`
**position_y**: 水印文字y坐标,比如:`100`
___
##### AddImgWatermark节点: 作用是在视频上添加图片水印<br>
![](./assets/4.png)
###### 参数说明
**video_path**: 本地视频路径,比如:`C:\Users\Desktop\222.mp4`
**output_path**: 视频保存路径,比如:`C:\Users\Desktop\output`
**watermark_image**: 水印图片路径,比如:`C:\Users\Desktop\watermark.png`
**watermark_img_width**: 水印图片宽度,比如:`100`
**position_x**: 水印图片在视频中的x坐标,比如:`100`
**position_y**: 水印图片在视频中的y坐标,比如:`100`
___
## 社交账号
- Bilibili:[我的B站主页](https://space.bilibili.com/1303099255)
## 感谢
感谢FFmpeg仓库的所有作者 [FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg)
部分代码参考了 [Eden-yidun/ComfyUI-EdenVideoTool](https://github.com/Eden-yidun/ComfyUI-EdenVideoTool) 感谢!
## 关注历史
[![Star History Chart](https://api.star-history.com/svg?repos=MoonHugo/ComfyUI-FFmpeg&type=Date)](https://star-history.com/#MoonHugo/ComfyUI-FFmpeg&Date)
+91
View File
@@ -0,0 +1,91 @@
<h1 align="center">ComfyUI-FFmpeg</h1>
<p align="center">
<br> <font size=5>English | <a href="README.md">中文</a></font>
</p>
## Introduction
Encapsulate the commonly used functions of FFmpeg into ComfyUI nodes, making it convenient for users to perform various video processing tasks within ComfyUI.<br>
## Installation
#### Method 1:
1. Go to comfyUI custom_nodes folder, `ComfyUI/custom_nodes/`
2. `git clone https://github.com/MoonHugo/ComfyUI-FFmpeg.git`
3. `cd ComfyUI-FFmpeg`
4. `pip install -r requirements.txt`
5. restart ComfyUI
#### Method 2:
Directly download the node source package, then extract it into the custom_nodes directory, and finally restart ComfyUI.
#### Method 3:
Install through ComfyUI-Manager by searching for 'ComfyUI-BiRefNet-Hugo' and installing it.
## Nodes introduction
##### Video2Frames Node: The function is to convert a video into images and save them to a specified directory.<br>
![](./assets/1.png)
###### Parameter Description
**video_path**: The local video path, e.g:`C:\Users\Desktop\222.mp4`
**output_path**: The path to save the output images, e.g:`C:\Users\Desktop\output`
**frames_max_width**: This parameter can be used to resize the video. The default value is 0, which means the video will not be resized. If frames_max_width is larger than the actual width of the video, the video will not be enlarged and will retain its original width. If frames_max_width is smaller than the actual width of the video, the video will be scaled down.
___
##### Frames2Video Node: The function is to convert images into a video and save it to a specified directory.<br>
![](./assets/2.png)
###### Parameter Description
**frame_path**: local image path, e.g:`C:\Users\Desktop\output`
**fps**: video frame rate, default is`30`
**video_name**: saved video name, e.g:`222.mp4`
**output_path**: video save path,e.g:`C:\Users\Desktop\output`
**audio_path**: video audio path,e.g:`C:\Users\Desktop\222.mp3`
___
##### AddTextWatermark Node: The function is to add a text watermark to the video.<br>
![](./assets/3.png)
###### Parameter Description
**video_path**: local video path,e.g:`C:\Users\Desktop\222.mp4`
**output_path**: video save path,e.g:`C:\Users\Desktop\output`
**font_file**: font file: The font file needs to be placed in the`custom_nodes\ComfyUI-FFmpeg\fonts` directory. Not only English fonts, but Chinese fonts can also be used.,e.g:`ComfyUI\custom_nodes\ComfyUI-FFmpeg\fonts\Alibaba-PuHuiTi-Heavy.ttf`
**font_size**: watermark text size,e.g:`40`
**font_color**: watermark text color,e.g:`#FFFFFF` or `white`
**position_x**: watermark text x-coordinate,e.g:`100`
**position_y**: watermark text y-coordinate,e.g:`100`
___
##### AddImgWatermark Node: The function is to add an image watermark to the video.<br>
![](./assets/4.png)
###### Parameter Description
**video_path**: local video path,e.g:`C:\Users\Desktop\222.mp4`
**output_path**: video save path,e.g:`C:\Users\Desktop\output`
**watermark_image**: watermark image path,e.g:`C:\Users\Desktop\watermark.png`
**watermark_img_width**: watermark image width,e.g:`100`
**position_x**: watermark image x-coordinate in the video,e.g:`100`
**position_y**: watermark image y-coordinate in the video,e.g:`100`
___
## Social Account Homepage
- Bilibili:[My BILIBILI Homepage](https://space.bilibili.com/1303099255)
## Acknowledgments
Thanks to all the contributors of the FFmpeg repository. [FFmpeg/FFmpeg](https://github.com/FFmpeg/FFmpeg)
Some of the code references [Eden-yidun/ComfyUI-EdenVideoTool](https://github.com/Eden-yidun/ComfyUI-EdenVideoTool) Thanks!
## Star history
[![Star History Chart](https://api.star-history.com/svg?repos=MoonHugo/ComfyUI-FFmpeg&type=Date)](https://star-history.com/#MoonHugo/ComfyUI-FFmpeg&Date)
+3
View File
@@ -0,0 +1,3 @@
from .nodes_map import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

+48
View File
@@ -0,0 +1,48 @@
import numpy as np
from PIL import Image
import torch
import subprocess
import json
def tensor2pil(image):
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
def pil2tensor(image):
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
def getVideoInfo(video_path):
command = [
'ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries',
'stream=avg_frame_rate,duration,width,height', '-of', 'json', video_path
]
# 运行ffprobe命令
result = subprocess.run(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
# 将输出转化为字符串
output = result.stdout.decode('utf-8').strip()
print(output)
data = json.loads(output)
# 查找视频流信息
if 'streams' in data and len(data['streams']) > 0:
stream = data['streams'][0] # 获取第一个视频流
fps = stream.get('avg_frame_rate')
if fps is not None:
# 帧率可能是一个分数形式的字符串,例如 "30/1" 或 "20.233000"
if '/' in fps:
num, denom = map(int, fps.split('/'))
fps = num / denom
else:
fps = float(fps) # 直接转换为浮点数
width = int(stream.get('width'))
height = int(stream.get('height'))
duration = float(stream.get('duration'))
return_data = {'fps': fps, 'width': width, 'height': height, 'duration': duration}
else:
return_data = {}
return return_data
def get_image_size(image_path):
# 打开图像文件
with Image.open(image_path) as img:
# 获取图像的宽度和高度
width, height = img.size
return width, height
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+79
View File
@@ -0,0 +1,79 @@
import os
from PIL import Image
import subprocess
import time
from ..func import get_image_size
class AddImgWatermark:
# 初始化方法
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"video_path": ("STRING", {"default":"C:/Users/Desktop/video.mp4",}),
"output_path": ("STRING", {"default":"C:/Users/Desktop/output/",}),
"watermark_image": ("STRING", {"default":"C:/Users/Desktop/logo.png",}),
"watermark_img_width": ("INT", {"default": 100,"min": 1, "step": 1}),
"position_x": ("INT", {"default": 10, "step": 1}),
"position_y": ("INT", {"default": 10, "step": 1}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("video_complete_path",)
FUNCTION = "add_img_watermark"
OUTPUT_NODE = True
CATEGORY = "FFmpeg"
def add_img_watermark(self,video_path,output_path,watermark_image,watermark_img_width,position_x,position_y):
try:
# 视频不存在
if not video_path.lower().endswith(('.mp4', '.avi', '.mov', '.mkv','.rmvb')):
raise ValueError("video_path不是视频文件(video_path is not a video file)")
if not os.path.exists(video_path):
raise ValueError("video_path不存在(video_path does not exist)")
#判断output_path是否是一个目录
if not os.path.isdir(output_path):
raise ValueError("output_path不是目录(output_path is not a directory)")
# 文件不是图片
if not watermark_image.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
raise ValueError("水印文件不是图片文件(watermark file is not a image file)")
if not os.path.exists(watermark_image):
raise ValueError("水印文件不存在(watermark file does not exist)")
file_name = os.path.basename(video_path)
file_extension = os.path.splitext(file_name)[1]
#文件名根据年月日时分秒来命名
file_name = time.strftime("%Y%m%d%H%M%S", time.localtime()) + file_extension
output_path = os.path.join(output_path, file_name)
width,height = get_image_size(watermark_image)
watermark_img_height = int(height * watermark_img_width / width) # 按比例计算新高度
cmd = [
'ffmpeg',
'-i', video_path,
'-i', watermark_image,
'-filter_complex',f"[1:v]scale={watermark_img_width}:{watermark_img_height}[wm];[0:v][wm]overlay=x={position_x}:y={position_y}:format=auto",
output_path,
]
result = subprocess.run(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
#os.remove(image_save_path) # 删除临时水印图片
# 检查返回码
if result.returncode != 0:
# 如果有错误,输出错误信息
print(f"Error: {result.stderr.decode('utf-8')}")
raise ValueError(f"Error: {result.stderr.decode('utf-8')}")
else:
# 输出标准输出信息
print(result.stdout)
except Exception as e:
raise ValueError(e)
return (output_path,)
+85
View File
@@ -0,0 +1,85 @@
import os
import subprocess
import folder_paths
import time
current_path = os.path.abspath(__file__)
font_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.normpath(__file__))), 'fonts')
folder_paths.folder_names_and_paths["fonts"] = ([font_dir], {'.ttf'})
class AddTextWatermark:
# 初始化方法
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"video_path": ("STRING", {"default":"C:/Users/Desktop/video.mp4",}),
"output_path": ("STRING", {"default":"C:/Users/Desktop/output/",}),
'font_file': (["default"] + folder_paths.get_filename_list("fonts"), ),
'font_size': ("INT", {"default": 15, "min": 1, "max": 1000, "step": 1}),
'font_color': ("STRING", {"default": "#FFFFFF"}),
"text": ("STRING", {"default": "Watermark"}),
"position_x": ("INT", {"default": 10, "step": 1}),
"position_y": ("INT", {"default": 10, "step": 1}),
},
}
RETURN_TYPES = ("STRING","STRING",)
RETURN_NAMES = ("video_path","output_path",)
FUNCTION = "add_text_watermark"
OUTPUT_NODE = True
CATEGORY = "FFmpeg"
def add_text_watermark(self,video_path,output_path,font_file,font_size,font_color,text,position_x,position_y):
try:
# 视频不存在
if not video_path.lower().endswith(('.mp4', '.avi', '.mov', '.mkv','.rmvb')):
raise ValueError("video_path不是视频文件(video_path is not a video file)")
if not os.path.exists(video_path):
raise ValueError("video_path不存在(video_path does not exist)")
#判断output_path是否是一个目录
if not os.path.isdir(output_path):
raise ValueError("output_path不是目录(output_path is not a directory)")
file_name = os.path.basename(video_path)
file_extension = os.path.splitext(file_name)[1]
#文件名根据年月日时分秒来命名
file_name = time.strftime("%Y%m%d%H%M%S", time.localtime()) + file_extension
output_path = os.path.join(output_path, file_name)
# 替换为双斜杠
font_path = os.path.join(font_dir, font_file).replace("\\", "/").replace(":", "\\:")
# 构建命令 C\\:/Windows/Fonts/simhei.ttf fontfile='J\\:/Comfyui-for-OOTDiffusion/ComfyUI/custom_nodes/ComfyUI-FFmpeg/fonts/Alibaba-PuHuiTi-Heavy.ttf
if font_file == "default":
cmd = [
'ffmpeg',
'-i', video_path,
'-vf', f"drawtext=text='{text}':x={position_x}:y={position_y}:fontsize={font_size}:fontcolor={font_color}",
output_path,
]
else:
cmd = [
'ffmpeg',
'-i', video_path,
'-vf', f"drawtext=text='{text}':x={position_x}:y={position_y}:fontfile='{font_path}':fontsize={font_size}:fontcolor={font_color}",
output_path,
]
result = subprocess.run(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
# 检查返回码
if result.returncode != 0:
# 如果有错误,输出错误信息
print(f"Error: {result.stderr.decode('utf-8')}")
raise ValueError(f"Error: {result.stderr.decode('utf-8')}")
else:
# 输出标准输出信息
print(result.stdout)
except Exception as e:
raise ValueError(e)
return (video_path,output_path)
+125
View File
@@ -0,0 +1,125 @@
import os
import subprocess
import re
from PIL import Image
from pathlib import Path
class Frames2Video:
# 初始化方法
def __init__(self):
pass
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"frame_path": ("STRING", {"default": "C:/Users/Desktop",}),
"fps": ("FLOAT", {
"default": 30,
"min": 1,
"max": 120,
"step": 1,
"display": "number"
}),
"video_name": ("STRING", {"default": "new_video"}),
"output_path": ("STRING", {"default": "./output"}),
},
"optional":{
"audio_path":("STRING",{"default": "C:/Users/audio.mp3",}),
}
}
RETURN_TYPES = ("STRING","STRING",)
RETURN_NAMES = ("frame_path","output_path",)
FUNCTION = "frames2video"
OUTPUT_NODE = True
CATEGORY = "FFmpeg"
def frames2video(self,frame_path,fps,video_name,output_path,audio_path=None):
try:
if not os.path.exists(frame_path):
raise ValueError("frame_path不存在(frame_path does not exist)")
#判断output_path是否是一个目录
if not os.path.isdir(output_path):
raise ValueError("output_path不是目录(output_path is not a directory)")
output_path = f"{output_path}\{video_name}.mp4" # 将输出目录和输出文件名合并为一个输出路径
# 获取输入目录中的所有图像文件
frame_path = Path(frame_path)
image_files = sorted(frame_path.glob('*.png')) + sorted(frame_path.glob('*.PNG')) + sorted(frame_path.glob('*.Png'))
# 获取第一张图像的文件名,不要路径
image_name = os.path.basename(image_files[0])
print(f"第一张图像文件名: {image_name}")
# 获取图像文件名中的数字个数,包括零
num_digits = sum(c.isdigit() for c in image_name)
print(f"转换后的图像文件名: {num_digits}")
# 将图像文件名中的数字替换为%0{num_digits}d,只影响数字,不影响其他字符
image_name = re.sub(r'\d+', '%0{}d'.format(num_digits), image_name)
print(f"转换后的图像文件名: {image_name}")
# 构建输出目录
if not image_files:
print(f"Files in directory: {os.listdir(frame_path)}")
raise FileNotFoundError(f"No image files found in directory: {frame_path}")
# 获取第一张图像的尺寸
with Image.open(image_files[0]) as img:
width, height = img.size
scale = f'{width}:{height}'
if audio_path:
# 有音频文件,构建ffmpeg命令
ffmpeg_cmd = [
'ffmpeg',
'-framerate', str(fps),
'-i', f'{frame_path}/{image_name}',
'-i', audio_path, # 添加音频文件路径
'-vf', f'scale={scale}',
'-c:v', 'libx264',
'-preset', 'medium',
'-crf', '28',
'-pix_fmt', 'yuv420p',
'-c:a', 'aac', # 指定音频编解码器
'-shortest',
'-y',
str(output_path)
]
# 执行ffmpeg命令
process = subprocess.Popen(ffmpeg_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
if process.returncode != 0:
print(f"ffmpeg 执行失败,错误信息: {stderr.decode('utf-8')}")
else:
print(f"视频合成成功: {output_path}")
else:
# 无音频文件,构建ffmpeg命令
ffmpeg_cmd = [
'ffmpeg',
'-framerate', str(fps),
'-i', f'{frame_path}/{image_name}',
'-vf', f'scale={scale}',
'-c:v', 'libx264',
'-preset', 'medium',
'-crf', '28',
'-pix_fmt', 'yuv420p',
'-y',
str(output_path)
]
# 执行ffmpeg命令
process = subprocess.Popen(ffmpeg_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
if process.returncode != 0:
print(f"ffmpeg 执行失败,错误信息: {stderr.decode('utf-8')}")
else:
print(f"视频合成成功: {output_path}")
frame_path = str(frame_path) # 输出路径为字符串
return (frame_path,output_path)
except Exception as e:
raise ValueError(e)
+121
View File
@@ -0,0 +1,121 @@
import json
import math
import os
import subprocess
class Video2Frames:
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"video_path": ("STRING", {"default":"C:/Users/Desktop/video.mp4",}),
"output_path": ("STRING", {"default":"C:/Users/Desktop/output",}),
"frames_max_width":("INT", {"default": 0, "min": 0, "max": 1920}),
},
}
RETURN_TYPES = ("STRING", "FLOAT", "STRING", "INT","STRING")
RETURN_NAMES = ("frame_path", "fps", "audio_path", "total_frames","output_path")
FUNCTION = "video2frames"
OUTPUT_NODE = True
CATEGORY = "FFmpeg"
def video2frames(self, video_path, output_path, frames_max_width):
try:
# 视频不存在
if not video_path.lower().endswith(('.mp4', '.avi', '.mov', '.mkv','.rmvb')):
raise ValueError("video_path不是视频文件(video_path is not a video file)")
if not os.path.exists(video_path):
raise ValueError("video_path不存在(video_path does not exist)")
#判断output_path是否是一个目录
if not os.path.isdir(output_path):
raise ValueError("output_path不是目录(output_path is not a directory)")
# 判断frames_max_width是否是一个整数
if not isinstance(frames_max_width, int):
raise ValueError("frames_max_width不是整数(frames_max_width is not an integer)")
# 提取音频
audio_path = os.path.join(output_path, 'audio.mp3')
video_path = os.path.abspath(video_path).replace("\ufeff", "").strip()
audio_cmd = [
'ffmpeg', '-i', video_path,
'-q:a', '0', '-map', 'a', '-y', audio_path
]
subprocess.run(audio_cmd)
# 获取视频帧率、时长、宽高信息
command = [
'ffprobe', '-v', 'error', '-select_streams', 'v:0', '-show_entries',
'stream=avg_frame_rate,duration,width,height', '-of', 'json', video_path
]
# 运行ffprobe命令
result = subprocess.run(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
# 将输出转化为字符串
output = result.stdout.decode('utf-8').strip()
print(output)
data = json.loads(output)
# 查找视频流信息
if 'streams' in data and len(data['streams']) > 0:
stream = data['streams'][0] # 获取第一个视频流
fps = stream.get('avg_frame_rate')
if fps is not None:
# 帧率可能是一个分数形式的字符串,例如 "30/1" 或 "20.233000"
if '/' in fps:
num, denom = map(int, fps.split('/'))
fps = num / denom
else:
fps = float(fps) # 直接转换为浮点数
else:
raise ValueError("无法获取视频的帧率")
width = int(stream.get('width'))
height = int(stream.get('height'))
duration = float(stream.get('duration'))
else:
raise ValueError("无法获取视频信息")
# 计算总帧数
total_frames = math.ceil(fps * duration)
print(f"视频的帧率是: {fps}, 宽度是: {width}, 高度是: {height}, 时长是: {duration}, 总帧数是: {total_frames}")
# 提取帧
frame_path = os.path.join(output_path, 'frames')
os.makedirs(frame_path, exist_ok=True) # exist_ok=True表示如果目录已经存在,不会引发异常
# 计算输出宽度和高度以保持比例
if frames_max_width > 0:
if width > frames_max_width:
out_width = frames_max_width
out_height = int(height * frames_max_width / width) # 按比例计算新高度
else:
out_width = width
out_height = height
else:
out_width = width
out_height = height
command = [
'ffmpeg', '-i', video_path, # 输入视频路径
'-vf', f'scale={out_width}:{out_height}', # 使用scale滤镜缩放帧
os.path.join(frame_path, 'frame_%06d.png') # 输出帧路径
]
# 执行命令并检查错误
if subprocess.run(command).returncode != 0:
print("生成序列帧时出错,请检查输入文件和路径。")
# 打印信息
print(f"序列帧图片输出路径: {frame_path}")
print(f"音频输出路径: {audio_path}")
print(f"总帧数: {total_frames}")
print(f"帧率: {fps}")
print(f"输出路径: {output_path}")
return (frame_path, fps, audio_path, total_frames,output_path)
except Exception as e:
raise ValueError(e)
+19
View File
@@ -0,0 +1,19 @@
from .nodes.addTextWatermark import *
from .nodes.frames2video import *
from .nodes.video2frames import *
from .nodes.addImgWatermark import *
NODE_CLASS_MAPPINGS = {
"Video2Frames": Video2Frames,
"Frames2Video": Frames2Video,
"AddTextWatermark": AddTextWatermark,
"AddImgWatermark": AddImgWatermark,
}
# A dictionary that contains the friendly/humanly readable titles for the nodes
NODE_DISPLAY_NAME_MAPPINGS = {
"Video2Frames": "🔥Video2Frames",
"Frames2Video": "🔥Frames2Video",
"AddTextWatermark": "🔥AddTextWatermark",
"AddImgWatermark": "🔥AddImgWatermark",
}
+1
View File
@@ -0,0 +1 @@
pathlib