CookiesChartConverter/pv_convert.py
2025-06-24 13:36:55 +08:00

84 lines
2.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)