diff --git a/apps/api/app/__init__.py b/apps/api/app/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/apps/api/app/api/routes/assets.py b/apps/api/app/api/routes/assets.py old mode 100755 new mode 100644 index 7e2f9b1a0..7d90cf9c7 --- a/apps/api/app/api/routes/assets.py +++ b/apps/api/app/api/routes/assets.py @@ -71,6 +71,7 @@ def _to_asset_response(item, storage_service=None) -> AssetResponse: status=item.status.value, classification_status=item.classification_status.value, quality_score=item.quality_score, + created_at=item.created_at.isoformat() if item.created_at else None, uploaded_by_user_id=item.uploaded_by_user_id, tag_ids=getattr(item, "tag_ids", []), ) diff --git a/apps/api/app/schemas/asset.py b/apps/api/app/schemas/asset.py index afd5f74be..dd6d15c86 100755 --- a/apps/api/app/schemas/asset.py +++ b/apps/api/app/schemas/asset.py @@ -50,6 +50,7 @@ class AssetResponse(BaseModel): status: str classification_status: str quality_score: float | None = None + created_at: str uploaded_by_user_id: str tag_ids: list[str] = Field(default_factory=list) diff --git a/apps/worker/video_processing/render_adapter.py b/apps/worker/video_processing/render_adapter.py index 7c6955a30..59938a596 100755 --- a/apps/worker/video_processing/render_adapter.py +++ b/apps/worker/video_processing/render_adapter.py @@ -258,12 +258,12 @@ class RenderAdapter: plan_id, job_id, exc.returncode, - stderr_text[:3000], + stderr_text[-2000:] if len(stderr_text) > 2000 else stderr_text, ) return RenderAdapterResult( success=False, error_message=f"FFmpeg渲染失败(exit={exc.returncode}): {stderr_text[:200]}", - error_detail=stderr_text[:3000], + error_detail=stderr_text[-2000:] if len(stderr_text) > 2000 else stderr_text, ) except Exception as exc: logger.exception( diff --git a/apps/worker/video_processing/unified_render_service.py b/apps/worker/video_processing/unified_render_service.py index 3e97eeaa3..f97b1aef4 100755 --- a/apps/worker/video_processing/unified_render_service.py +++ b/apps/worker/video_processing/unified_render_service.py @@ -1008,7 +1008,7 @@ class UnifiedRenderService: else: # main / broll: 等比缩放 + 居中留黑边(保持原始比例,不裁剪内容) filters.append(f"scale={self.output_width}:{self.output_height}" ":force_original_aspect_ratio=decrease") - filters.append(f"pad={self.output_width}:{self.output_height}:(ow-iw)/2:(oh-ih)/2:black") + filters.append(f"pad={self.output_width}:{self.output_height}:trunc((ow-iw)/2):trunc((oh-ih)/2):black") # 调色滤镜 color_grade = ColorGradeConfig.from_dict(clip.config.get("color_grade")) @@ -1112,12 +1112,15 @@ class UnifiedRenderService: try: run_ffmpeg(command) except subprocess.CalledProcessError as e: + stderr_text = (e.stderr or "").strip() + stderr_tail = stderr_text[-1500:] if len(stderr_text) > 1500 else stderr_text logger.error( - "直通渲染失败: plan_id=%s clip=%s exit_code=%d\nvf=%s", + "直通渲染失败: plan_id=%s clip=%s exit_code=%d\nvf=%s\nstderr(last 1500):\n%s", self.plan.id, clip.clip_id, e.returncode, vf_str[:2000], + stderr_tail, ) raise @@ -1342,7 +1345,7 @@ class UnifiedRenderService: filters.append( f"scale={self.output_width}:{self.output_height}" ":force_original_aspect_ratio=decrease" ) - filters.append(f"pad={self.output_width}:{self.output_height}:(ow-iw)/2:(oh-ih)/2:black") + filters.append(f"pad={self.output_width}:{self.output_height}:trunc((ow-iw)/2):trunc((oh-ih)/2):black") # 调色滤镜(每个 clip 独立的 color grade 配置) color_grade = ColorGradeConfig.from_dict(clip.config.get("color_grade")) @@ -1576,12 +1579,15 @@ class UnifiedRenderService: try: run_ffmpeg(command) except subprocess.CalledProcessError as e: - # 额外记录 filter_complex,方便排查滤镜链构建问题 + # 额外记录 filter_complex + stderr,方便排查滤镜链构建问题 + stderr_text = (e.stderr or "").strip() + stderr_tail = stderr_text[-1500:] if len(stderr_text) > 1500 else stderr_text logger.error( - "渲染失败: plan_id=%s exit_code=%d\nfilter_complex:\n%s", + "渲染失败: plan_id=%s exit_code=%d\nfilter_complex:\n%s\nstderr(last 1500):\n%s", self.plan.id, e.returncode, filter_complex[:5000], + stderr_tail, ) raise diff --git a/tests/unit/test_unified_render_service.py b/tests/unit/test_unified_render_service.py index a9f025f11..837ff2d0f 100755 --- a/tests/unit/test_unified_render_service.py +++ b/tests/unit/test_unified_render_service.py @@ -1801,7 +1801,7 @@ class TestConcatNormalizeVideoResolution: # 必须用 pad(留黑边),不能用 crop(裁剪) assert "force_original_aspect_ratio=decrease" in fc, "main 层应使用 decrease 模式(等比缩放到画布内)" assert "pad=" in fc, "main 层应有 pad 滤镜(留黑边到目标分辨率)" - assert "(ow-iw)/2:(oh-ih)/2:black" in fc, "pad 应该居中+黑边" + assert "trunc((ow-iw)/2):trunc((oh-ih)/2):black" in fc, "pad 应该居中取整+黑边" # 注意:background 层也用 crop,但 main/broll 应该用 pad # 检查第一个 [0:v] 处理链(第一个 clip 是 main) first_v_chain = fc.split("[v0]")[0]