refactor(video): 重构视频裁切功能实现

- 将 crop_size 字段替换为 crop_scale 浮点数字段,支持缩放倍率控制
- 将 face_pos 字段重命名为 crop_pos,统一裁切位置控制
- 移除 zoom_cut 和 crop_size 字段,简化裁切参数
- 新增 _build_crop_filter 静态方法,统一构建裁切滤镜逻辑
- 优化裁切算法,支持按目标比例和倍率进行精确裁切
- 统一处理图像和视频的裁切逻辑,消除代码重复
- 添加 cropScale 参数的安全解析,防止非法数值导致错误
- 改进裁切位置解析,支持浮点数坐标并添加异常处理
This commit is contained in:
2026-02-27 13:37:42 +08:00
parent 9dd5b6237d
commit 34e7d84d52
2 changed files with 57 additions and 43 deletions

View File

@@ -325,6 +325,43 @@ class RenderSegmentTsHandler(BaseHandler):
finally:
self.cleanup_work_dir(work_dir)
@staticmethod
def _build_crop_filter(
render_spec: 'RenderSpec',
width: int,
height: int,
task_id: str = ''
) -> Optional[str]:
"""
构建裁切滤镜
crop_enable 时:以目标比例为基准,按 crop_scale 倍率裁切,crop_pos 控制位置(默认居中)。
Returns:
crop 滤镜字符串,无需裁切时返回 None
"""
if render_spec.crop_enable:
scale = render_spec.crop_scale
target_ratio = width / height
# 解析裁切位置,默认居中
fx, fy = 0.5, 0.5
if render_spec.crop_pos:
try:
fx, fy = map(float, render_spec.crop_pos.split(','))
except ValueError:
logger.warning(f"[task:{task_id}] Invalid crop position: {render_spec.crop_pos}, using center")
fx, fy = 0.5, 0.5
# 基准:源中最大的目标比例矩形,再除以倍率
return (
f"crop='min(iw,ih*{target_ratio})/{scale}':'min(ih,iw/{target_ratio})/{scale}':"
f"'(iw-min(iw,ih*{target_ratio})/{scale})*{fx}':"
f"'(ih-min(ih,iw/{target_ratio})/{scale})*{fy}'"
)
return None
def _convert_image_to_video(
self,
image_file: str,
@@ -373,23 +410,10 @@ class RenderSegmentTsHandler(BaseHandler):
# 构建滤镜:缩放填充到目标尺寸
filters = []
# 裁切处理(与视频相同逻辑)
if render_spec.crop_enable and render_spec.face_pos:
try:
fx, fy = map(float, render_spec.face_pos.split(','))
target_ratio = width / height
filters.append(
f"crop='min(iw,ih*{target_ratio})':'min(ih,iw/{target_ratio})':"
f"'(iw-min(iw,ih*{target_ratio}))*{fx}':"
f"'(ih-min(ih,iw/{target_ratio}))*{fy}'"
)
except (ValueError, ZeroDivisionError):
logger.warning(f"[task:{task_id}] Invalid face position: {render_spec.face_pos}")
elif render_spec.zoom_cut:
target_ratio = width / height
filters.append(
f"crop='min(iw,ih*{target_ratio})':'min(ih,iw/{target_ratio})'"
)
# 裁切处理
crop_filter = self._build_crop_filter(render_spec, width, height, task_id)
if crop_filter:
filters.append(crop_filter)
# 缩放填充
filters.append(
@@ -711,26 +735,9 @@ class RenderSegmentTsHandler(BaseHandler):
filters.append(f"lut3d='{lut_path}'")
# 3. 裁切处理
if render_spec.crop_enable and render_spec.face_pos:
# 根据人脸位置进行智能裁切
try:
fx, fy = map(float, render_spec.face_pos.split(','))
# 计算裁切区域(保持输出比例)
target_ratio = width / height
# 假设裁切到目标比例
filters.append(
f"crop='min(iw,ih*{target_ratio})':'min(ih,iw/{target_ratio})':"
f"'(iw-min(iw,ih*{target_ratio}))*{fx}':"
f"'(ih-min(ih,iw/{target_ratio}))*{fy}'"
)
except (ValueError, ZeroDivisionError):
logger.warning(f"Invalid face position: {render_spec.face_pos}")
elif render_spec.zoom_cut:
# 中心缩放裁切
target_ratio = width / height
filters.append(
f"crop='min(iw,ih*{target_ratio})':'min(ih,iw/{target_ratio})'"
)
crop_filter = self._build_crop_filter(render_spec, width, height)
if crop_filter:
filters.append(crop_filter)
# 4. 缩放和填充
scale_filter = (