CQTAI
FFmpeg 媒体处理 · FFmpeg

成片深度质检NEW

📌 这是什么:只读质检:把成片完整解码两遍(视频一遍、音频一遍)跑检测滤镜,产出一份小体积 JSON 报告——黑帧、定格(画面冻结)、静音三类问题区间 + EBU R128 响度指标。不生成任何媒体文件,原片不变。
💡 什么时候用:成片交付前做自动化验收时用:拿报告里的区间和响度值判定 pass / warning / block,替代人工全片过一遍。检测阈值由服务端固定(黑帧 d=0.5、定格 d=2、静音 -45dB/1.5s),不开放调整——阈值可调会让报告「完全合法但结论错误」。除 inputUrl 外不接受其它参数,多传的键被忽略。

接口地址

用途方法路径
提交任务POST/v1/ffmpeg/qc
查询结果GET/v1/ffmpeg/info?id={taskId}
⏱ 建议轮询时间:建议每 3~5 秒轮询一次(响应含 progress 0→100),直到 status = succeeded / failed。status = queued 表示已入队、排队等待执行(尚未扣费),继续轮询即可。单任务超时 300 秒、超时退款。

请求参数

参数类型必填说明
inputUrlstring必填输入媒体 URL,须为受信白名单域名(平台 CDN 或受信来源 CDN);可先用 upload 上传获取,或直接用已在受信 CDN 上的素材 URL
webhookUrlstring—完成回调地址(可选)

请求示例

curl -X POST https://api.cqtai.com/v1/ffmpeg/qc \
  -H 'Authorization: Bearer <API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{ "inputUrl": "https://cdn.novapi.ai/veo31/1788164205419_de868f9d69d445baaf577d42e87a236f.mp4" }'
# -> { "code":200, "data":"<taskId>" }

响应示例

{
  "code": 200,
  "msg": "success",
  "data": {
    "taskId": "<taskId>",
    "operation": "qc",
    "status": "succeeded",
    "progress": 100,
    "resultUrl": "https://cdn.novapi.ai/ffmpeg/qc/1756800000000_0f1e2d3c4b5a.json",
    "costPoints": 10,
    "errorMsg": ""
  }
}

质检报告 JSON

resultUrl 指向报告 JSON(Content-Type application/json,体积 ≤ 1 MiB,公网直链无跳转,长期保留)。顶层 10 个字段一个都不会缺——序列化不省略空值:段落为空是 [](不是 null),响度取不到才是 null。progress 在视频分析结束时到 45、音频结束时到 90、上传落库后 100。

字段类型说明
schemaVersionint恒为 1;阈值 / 字段语义变更时才会升版
analyzedVideobool视频那一路是否跑完(跑完 ≠ 没查出问题)
analyzedAudiobool音频那一路是否跑完;无音轨 / 该路失败为 false
blackSegmentsobject[]黑帧区间(blackdetect d=0.5 pix_th=0.10),空则 []
freezeSegmentsobject[]定格 / 画面冻结区间(freezedetect n=-50dB d=2),空则 []
silenceSegmentsobject[]静音区间(silencedetect n=-45dB d=1.5),空则 []
integratedLufsnumber | null整体响度(LUFS,带符号,通常为负);取不到为 null
loudnessRangeLunumber | null响度范围(LU);取不到为 null
truePeakDbfsnumber | null真峰值(dBFS,带符号,削波时可能 ≥ 0);取不到为 null
errorstring | null降级说明(英文,多条以 "; " 拼接)。⚠ error 非 null 不代表任务失败
段落形状{ startMs, endMs, durationMs }三类段落统一形状,全部为整数毫秒、以成片自身时间轴从 0 起算。⚠ 跨到片尾未闭合的段:endMs 与 durationMs 都是 null(不是 0、不会丢段)——结尾长静音靠这条才不会被当噪声忽略。段落可能相邻或重叠,服务端不做区间归并,是否合并由调用方决定
{
  "schemaVersion": 1,
  "analyzedVideo": true,
  "analyzedAudio": true,
  "blackSegments": [
    { "startMs": 121500, "endMs": 122510, "durationMs": 1010 }
  ],
  "freezeSegments": [],
  "silenceSegments": [
    { "startMs": 121480, "endMs": 124500, "durationMs": 3020 },
    { "startMs": 331000, "endMs": null,   "durationMs": null }
  ],
  "integratedLufs": -18.4,
  "loudnessRangeLu": 7.2,
  "truePeakDbfs": -1.1,
  "error": null
}
部分失败仍算成功:视频、音频两路独立跑、独立成败。只挂一路时任务仍是 succeeded,失败那一路的段落为 []、对应 analyzed* 为 false,error 点名原因(如 input has no audio track / video analysis failed: ...)——半份真报告好过一份编出来的完整报告。两路都失败才是 failed 并退款。
上限与截断:每类段落最多 500 条,超出截断并在 error 注明 <类>Segments truncated to 500;报告超 1 MiB 则丢掉全部段落、保留 analyzed* 与响度值,error 追加 report exceeded 1048576 bytes; all segments dropped。
超时:视频、音频两路各自享有完整超时预算(默认 300 秒,不共享)。单路超时按部分失败处理,两路都超时才失败退款。