mirror of
https://gitea.cookies.4d.ink/Cookies/CookiesChartConverter.git
synced 2025-10-26 03:02:39 +00:00
84 lines
2.9 KiB
Python
84 lines
2.9 KiB
Python
import subprocess
|
||
import sys
|
||
from fractions import Fraction
|
||
|
||
from loguru import logger
|
||
|
||
|
||
def ratio_to_str(width, height, max_denominator=20):
|
||
"""将宽高比转换为 a:b 的形式"""
|
||
# 确保分子 > 分母
|
||
if width >= height:
|
||
ratio = Fraction(width, height).limit_denominator(max_denominator)
|
||
else:
|
||
ratio = Fraction(height, width).limit_denominator(max_denominator)
|
||
|
||
a, b = ratio.numerator, ratio.denominator
|
||
# 由于上面取了 max(width, height),要对应宽:高
|
||
if width >= height:
|
||
return f"{a}:{b}"
|
||
else:
|
||
return f"{b}:{a}"
|
||
|
||
def get_video_resolution(video_path):
|
||
"""获取视频的宽高信息"""
|
||
cmd = [
|
||
"ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
|
||
"stream=width,height", "-of", "csv=p=0", video_path
|
||
]
|
||
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||
width, height = map(int, result.stdout.strip().split(","))
|
||
return width, height
|
||
|
||
def calculate_padding(width, height):
|
||
"""计算填充黑边,使其变成 1:1(正方形)。
|
||
如果接近4:3或1:1比例(90%以内),则直接返回0。
|
||
"""
|
||
aspect_ratio = width / height if width >= height else height / width
|
||
|
||
# 如果接近 4:3 或 1:1,就不填充
|
||
if (0.9 <= aspect_ratio <= 1.1) or (1.3 <= aspect_ratio <= 1.5):
|
||
return max(width, height), 0, 0
|
||
|
||
max_side = max(width, height) # 以最大边长作为正方形边长
|
||
pad_x = (max_side - width) // 2
|
||
pad_y = (max_side - height) // 2
|
||
return max_side, pad_x, pad_y
|
||
|
||
def process_video(input_file, output_file):
|
||
"""填充黑色边框,调整为 1:1,并转换为 H.264"""
|
||
width, height = get_video_resolution(input_file)
|
||
target_size, pad_x, pad_y = calculate_padding(width, height)
|
||
|
||
if pad_x == 0 and pad_y == 0:
|
||
logger.info(f"视频比例是 {ratio_to_str(width, height)},无需填充。")
|
||
ffmpeg_cmd = [
|
||
"ffmpeg", "-y", "-i", input_file,
|
||
"-c:v", "h264_videotoolbox",
|
||
"-b:v", "5000M", "-maxrate", "70M", "-bufsize", "100M",
|
||
"-c:a", "aac", "-b:a", "320k",
|
||
output_file
|
||
]
|
||
else:
|
||
logger.info(f"视频比例是 {ratio_to_str(width, height)},填充黑边,使视频变为 {target_size}x{target_size}")
|
||
ffmpeg_cmd = [
|
||
"ffmpeg", "-y", "-i", input_file,
|
||
"-vf", f"pad={target_size}:{target_size}:{pad_x}:{pad_y}:black",
|
||
"-c:v", "h264_videotoolbox",
|
||
"-b:v", "5000M", "-maxrate", "70M", "-bufsize", "100M",
|
||
"-c:a", "aac", "-b:a", "320k",
|
||
output_file
|
||
]
|
||
|
||
subprocess.run(ffmpeg_cmd)
|
||
|
||
if __name__ == "__main__":
|
||
if len(sys.argv) < 3:
|
||
logger.info("用法: python pv_convert.py 输入文件 输出文件")
|
||
sys.exit(1)
|
||
|
||
input_file = sys.argv[1]
|
||
output_file = sys.argv[2]
|
||
|
||
process_video(input_file, output_file)
|