feat: 上传时自动检测 HEVC 编码并转码为 1080p H.264
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 55s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 28s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m39s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m52s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m30s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m51s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m44s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 652h34m59s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 652h34m57s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 652h35m48s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 652h35m52s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 652h35m54s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 652h35m55s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 652h35m55s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 653h8m44s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 653h9m35s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 653h9m40s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 55s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 28s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 29s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 1m39s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m52s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m30s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m51s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m44s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 652h34m59s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 652h34m57s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 652h35m48s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 652h35m52s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 652h35m54s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 652h35m55s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 652h35m55s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 653h8m44s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 653h9m35s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 653h9m40s
解决 4K HEVC 素材在浏览器 WebCodecs 硬件解码时输出黑帧的问题。 改动范围:仅 ingest.py(+88 行) - metadata 提取后检测 codec 是否为 hevc/h265/hvh1 - HEVC 素材自动转码:H.264 CRF18 + 1080p + yuv420p + faststart - 转码产物上传 OSS,storage_key 指向 _h264.mp4 - 转码后重新提取 metadata(新 codec/size/分辨率) - 非 HEVC 素材(H.264 等)不做任何处理 - 转码失败降级使用原始文件,不阻塞上传流程 - 超时 300s,临时文件 finally 清理
This commit is contained in:
@@ -233,6 +233,94 @@ def ingest_asset(job_id: str) -> dict:
|
||||
job_id,
|
||||
thumb_err,
|
||||
)
|
||||
|
||||
# ── HEVC 自动转码为 1080p H.264 ──────────────────────────────
|
||||
# 浏览器 WebCodecs 硬件解码 HEVC 输出黑帧,上传时自动转码
|
||||
# 失败时降级使用原始文件,不阻塞上传流程
|
||||
if (
|
||||
media_type == "video"
|
||||
and extract_success
|
||||
and local_file
|
||||
and local_file.exists()
|
||||
):
|
||||
codec = (metadata.get("codec") or "").lower()
|
||||
if codec in ("hevc", "h265", "hvh1"):
|
||||
logger.info(
|
||||
"检测到 HEVC 编码 (codec=%s),启动转码: job_id=%s",
|
||||
codec, job_id,
|
||||
)
|
||||
_tc_tmp = None
|
||||
try:
|
||||
_tc_tmp = Path(tempfile.mktemp(suffix="_h264.mp4"))
|
||||
_cmd = [
|
||||
"ffmpeg", "-y",
|
||||
"-i", str(local_file),
|
||||
"-c:v", "libx264",
|
||||
"-preset", "fast",
|
||||
"-crf", "18",
|
||||
"-vf",
|
||||
"scale='if(gt(ih,1080),-2,iw)':'if(gt(ih,1080),1080,ih)'",
|
||||
"-pix_fmt", "yuv420p",
|
||||
"-c:a", "aac",
|
||||
"-b:a", "128k",
|
||||
"-movflags", "+faststart",
|
||||
str(_tc_tmp),
|
||||
]
|
||||
_proc = subprocess.run(
|
||||
_cmd, capture_output=True, text=True, timeout=300,
|
||||
)
|
||||
if (
|
||||
_proc.returncode == 0
|
||||
and _tc_tmp.exists()
|
||||
and _tc_tmp.stat().st_size > 0
|
||||
):
|
||||
from video_processing.oss_helpers import upload_to_oss
|
||||
|
||||
_p = Path(job.storage_key)
|
||||
_new_key = str(
|
||||
_p.parent / (_p.stem + "_h264" + _p.suffix)
|
||||
)
|
||||
_url = upload_to_oss(_tc_tmp, _new_key)
|
||||
if _url:
|
||||
job.storage_key = _new_key
|
||||
metadata, extract_success = (
|
||||
extract_media_metadata(
|
||||
str(_tc_tmp), media_type,
|
||||
)
|
||||
)
|
||||
logger.info(
|
||||
"HEVC→H.264 转码完成: job_id=%s key=%s",
|
||||
job_id, _new_key[:80],
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
"转码文件上传 OSS 失败,使用原始文件: job_id=%s",
|
||||
job_id,
|
||||
)
|
||||
else:
|
||||
_tail = (
|
||||
_proc.stderr[-300:] if _proc.stderr else ""
|
||||
)
|
||||
logger.warning(
|
||||
"FFmpeg 转码失败 rc=%s,降级原始文件: job_id=%s",
|
||||
_proc.returncode, job_id,
|
||||
)
|
||||
except subprocess.TimeoutExpired:
|
||||
logger.warning(
|
||||
"FFmpeg 转码超时 (300s),降级原始文件: job_id=%s",
|
||||
job_id,
|
||||
)
|
||||
except Exception as _e:
|
||||
logger.warning(
|
||||
"HEVC 转码异常(降级原始文件): job_id=%s err=%s",
|
||||
job_id, _e,
|
||||
)
|
||||
finally:
|
||||
if _tc_tmp and _tc_tmp.exists():
|
||||
try:
|
||||
_tc_tmp.unlink()
|
||||
except OSError:
|
||||
pass
|
||||
finally:
|
||||
if local_file and local_file.exists():
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user