第27章 遮罩添加服务
27.1 概述
遮罩添加服务是剪映小助手的核心功能之一,主要负责为视频片段添加各种类型的遮罩效果。遮罩可以创建特殊的视觉效果,如圆形头像、渐变边缘、形状裁剪等。该服务支持多种遮罩类型,包括线性遮罩、镜面遮罩、圆形遮罩、矩形遮罩、爱心遮罩和星形遮罩等。
27.2 核心实现
27.2.1 服务入口函数
遮罩添加服务的核心实现位于 src/service/add_masks.py 文件中:
async def add_masks(request: AddMasksRequest) -> AddMasksResponse:
"""为视频片段添加遮罩"""
logger.info(f"为草稿添加遮罩: {request.draft_url}")
# 参数验证
if not request.draft_url:
raise ValueError("草稿URL不能为空")
if not request.segment_ids:
raise ValueError("片段ID列表不能为空")
if not request.mask_type:
raise ValueError("遮罩类型不能为空")
# 获取草稿缓存
draft = await get_draft_cache(request.draft_url)
if not draft:
raise INVALID_DRAFT_URL
# 查找遮罩类型
mask_type = find_mask_type(request.mask_type)
if not mask_type:
raise INVALID_MASK_TYPE
# 为每个片段添加遮罩
mask_ids = []
affected_segments = []
for segment_id in request.segment_ids:
try:
# 查找视频片段
video_segment = find_video_segment(draft, segment_id)
if not video_segment:
logger.warning(f"未找到片段: {segment_id}")
continue
# 创建遮罩
mask = create_mask(mask_type, request, segment_id)
# 添加遮罩到片段
video_segment.mask = mask
mask_ids.append(mask.id)
affected_segments.append(segment_id)
logger.info(f"成功为片段 {segment_id} 添加遮罩")
except Exception as e:
logger.error(f"为片段 {segment_id} 添加遮罩失败: {str(e)}")
continue
# 保存草稿
await save_draft_cache(request.draft_url, draft)
return AddMasksResponse(
draft_url=request.draft_url,
added_count=len(mask_ids),
affected_segments=affected_segments,
mask_ids=mask_ids
)
27.2.2 遮罩类型查找
系统支持多种预定义的遮罩类型:
def find_mask_type(mask_type_name: str) -> dict:
"""查找遮罩类型"""
mask_types = {
"linear": {
"name": "线性遮罩",
"type": "linear",
"default_params": {
"angle": 0,
"feather": 0.1
}
},
"mirror": {
"name": "镜面遮罩",
"type": "mirror",
"default_params": {
"axis": "horizontal",
"feather": 0.1
}
},
"circle": {
"name": "圆形遮罩",
"type": "circle",
"default_params": {
"radius": 0.5,
"feather": 0.1,
"inverted": False
}
},
"rectangle": {
"name": "矩形遮罩",
"type": "rectangle",
"default_params": {
"width": 1.0,
"height": 1.0,
"corner_radius": 0,
"feather": 0.1,
"inverted": False
}
},
"heart": {
"name": "爱心遮罩",
"type": "heart",
"default_params": {
"size": 0.5,
"feather": 0.1,
"inverted": False
}
},
"star": {
"name": "星形遮罩",
"type": "star",
"default_params": {
"points": 5,
"outer_radius": 0.5,
"inner_radius": 0.2,
"feather": 0.1,
"inverted": False
}
}
}
return mask_types.get(mask_type_name.lower())
27.2.3 遮罩创建
根据遮罩类型和参数创建遮罩对象:
def create_mask(mask_type: dict, request: AddMasksRequest, segment_id: str) -> Mask:
"""创建遮罩"""
# 基础参数
mask_params = mask_type["default_params"].copy()
# 应用自定义参数
if request.center_x is not None:
mask_params["center_x"] = request.center_x
if request.center_y is not None:
mask_params["center_y"] = request.center_y
if request.width is not None:
mask_params["width"] = request.width
if request.height is not None:
mask_params["height"] = request.height
if request.feather is not None:
mask_params["feather"] = request.feather
if request.rotation is not None:
mask_params["rotation"] = request.rotation
if request.inverted is not None:
mask_params["inverted"] = request.inverted
if request.corner_radius is not None:
mask_params["corner_radius"] = request.corner_radius
# 创建遮罩ID
mask_id = f"mask_{mask_type['type']}_{uuid.uuid4().hex}"
# 创建遮罩对象
mask = Mask(
id=mask_id,
type=mask_type["type"],
name=mask_type["name"],
params=mask_params,
segment_id=segment_id,
enabled=True
)
return mask
27.2.4 视频片段查找
在草稿中查找指定的视频片段:
def find_video_segment(draft, segment_id: str):
"""查找视频片段"""
# 遍历所有轨道
for track in draft.tracks:
# 只查找视频轨道
if track.type != "video":
continue
# 查找片段
for segment in track.segments:
if segment.id == segment_id:
return segment
return None
27.3 遮罩类型与动画效果
27.3.1 线性遮罩
线性遮罩创建线性渐变效果,支持角度调整:
# 线性遮罩参数
linear_mask_params = {
"type": "linear",
"angle": 45, # 渐变角度
"feather": 0.2, # 羽化程度
"center_x": 0.5, # 中心点X坐标
"center_y": 0.5 # 中心点Y坐标
}
27.3.2 镜面遮罩
镜面遮罩创建镜像效果,支持水平或垂直镜像:
# 镜面遮罩参数
mirror_mask_params = {
"type": "mirror",
"axis": "horizontal", # 镜像轴:horizontal/vertical
"feather": 0.1, # 羽化程度
"center_x": 0.5,
"center_y": 0.5
}
27.3.3 圆形遮罩
圆形遮罩创建圆形裁剪效果,支持半径和反转设置:
# 圆形遮罩参数
circle_mask_params = {
"type": "circle",
"radius": 0.4, # 圆形半径
"feather": 0.15, # 羽化程度
"inverted": False, # 是否反转
"center_x": 0.5,
"center_y": 0.5
}
27.3.4 矩形遮罩
矩形遮罩创建矩形裁剪效果,支持圆角设置:
# 矩形遮罩参数
rectangle_mask_params = {
"type": "rectangle",
"width": 0.8, # 矩形宽度
"height": 0.6, # 矩形高度
"corner_radius": 0.1, # 圆角半径
"feather": 0.1,
"inverted": False,
"center_x": 0.5,
"center_y": 0.5
}
27.3.5 爱心遮罩
爱心遮罩创建爱心形状的裁剪效果:
# 爱心遮罩参数
heart_mask_params = {
"type": "heart",
"size": 0.5, # 爱心大小
"feather": 0.2,
"inverted": False,
"center_x": 0.5,
"center_y": 0.5
}
27.3.6 星形遮罩
星形遮罩创建星形裁剪效果,支持角数设置:
# 星形遮罩参数
star_mask_params = {
"type": "star",
"points": 5, # 星形角数
"outer_radius": 0.4, # 外半径
"inner_radius": 0.2, # 内半径
"feather": 0.15,
"inverted": False,
"center_x": 0.5,
"center_y": 0.5
}
27.4 数据结构定义
27.4.1 请求参数模型
遮罩添加服务的请求参数定义在 src/schemas/add_masks.py 中:
class AddMasksRequest(BaseModel):
"""添加遮罩请求参数"""
draft_url: str = Field(..., description="草稿URL")
segment_ids: List[str] = Field(..., description="要添加遮罩的片段ID列表")
mask_type: str = Field(..., description="遮罩类型名称")
center_x: Optional[float] = Field(default=None, description="中心点X坐标(0-1)")
center_y: Optional[float] = Field(default=None, description="中心点Y坐标(0-1)")
width: Optional[float] = Field(default=None, description="宽度(0-1)")
height: Optional[float] = Field(default=None, description="高度(0-1)")
feather: Optional[float] = Field(default=None, description="羽化程度(0-1)")
rotation: Optional[float] = Field(default=None, description="旋转角度(度)")
inverted: Optional[bool] = Field(default=None, description="是否反转遮罩")
corner_radius: Optional[float] = Field(default=None, description="圆角半径(矩形遮罩)")
27.4.2 响应参数模型
class AddMasksResponse(BaseModel):
"""添加遮罩响应参数"""
draft_url: str = Field(..., description="草稿URL")
added_count: int = Field(..., description="成功添加的遮罩数量")
affected_segments: List[str] = Field(..., description="受影响的片段ID列表")
mask_ids: List[str] = Field(..., description="遮罩ID列表")
27.5 异常处理
遮罩添加服务定义了完善的异常处理机制:
# 无效的遮罩类型
INVALID_MASK_TYPE = HTTPException(
status_code=400,
detail="无效的遮罩类型"
)
# 遮罩添加失败
MASK_ADD_FAILED = HTTPException(
status_code=500,
detail="遮罩添加失败"
)
# 未找到视频片段
VIDEO_SEGMENT_NOT_FOUND = HTTPException(
status_code=404,
detail="未找到指定的视频片段"
)
27.6 API接口定义
@router.post("/addMasks", response_model=AddMasksResponse)
async def add_masks_endpoint(request: AddMasksRequest):
"""添加遮罩"""
try:
return await add_masks(request)
except Exception as e:
logger.error(f"添加遮罩失败: {str(e)}")
raise MASK_ADD_FAILED
27.7 使用示例
27.7.1 请求示例
{
"draft_url": "capcut://draft/123456789",
"segment_ids": ["video_segment_001", "video_segment_002"],
"mask_type": "circle",
"center_x": 0.5,
"center_y": 0.5,
"radius": 0.4,
"feather": 0.15,
"inverted": false
}
27.7.2 响应示例
{
"draft_url": "capcut://draft/123456789",
"added_count": 2,
"affected_segments": ["video_segment_001", "video_segment_002"],
"mask_ids": ["mask_circle_abc123", "mask_circle_def456"]
}
27.8 动画效果支持
遮罩服务还支持为遮罩添加动画效果:
27.8.1 遮罩动画类型
# 遮罩动画类型
class MaskAnimationType:
FADE = "fade" # 淡入淡出
SCALE = "scale" # 缩放
ROTATE = "rotate" # 旋转
SLIDE = "slide" # 滑动
MORPH = "morph" # 形变
27.8.2 动画参数配置
# 遮罩动画参数
mask_animation_params = {
"animation_type": "fade",
"start_time": 0, # 动画开始时间
"duration": 1000000, # 动画持续时间(微秒)
"start_value": 0.0, # 动画起始值
"end_value": 1.0, # 动画结束值
"easing": "ease_in_out" # 缓动函数
}
27.9 性能优化
遮罩添加服务采用了多种性能优化策略:
- 批量处理:支持一次为多个片段添加遮罩
- 缓存机制:遮罩类型定义缓存,避免重复查找
- 异步处理:使用异步函数处理遮罩添加
- 错误隔离:单个片段处理失败不影响其他片段
27.10 扩展性设计
遮罩服务具有良好的扩展性:
- 遮罩类型扩展:易于添加新的遮罩类型
- 参数扩展:支持动态添加新的遮罩参数
- 动画扩展:支持自定义遮罩动画效果
- 组合扩展:支持多个遮罩的组合使用
附录
代码仓库地址:
- GitHub:
https://github.com/Hommy-master/capcut-mate - Gitee:
https://gitee.com/taohongmin-gitee/capcut-mate
接口文档地址:
- API文档地址:
https://docs.jcaigc.cn