fix(worker): conform — write ProRes/DNxHR to MOV, not MP4

The final concat-demux + encode step erred with:
  [mp4] Could not find tag for codec prores in stream #0,
        codec not currently supported in container
  [out#0/mp4] Could not write header (incorrect codec parameters ?)

ProRes and DNxHR live in QuickTime (.mov), not MP4. The output path,
S3 key, and asset-row filename were all hardcoded to .mp4.

Pick the container from the codec:
  prores / prores_hq / prores_4444 / dnxhr_hq → mov
  h264 / h265 / anything else                 → mp4

outputExt is computed once at the top of the worker (before tmpfile
creation) and reused for the temp output, the S3 key
(jobs/<id>/conformed.<ext>), and the assets row's filename column.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Claude 2026-05-28 15:40:53 -04:00
parent 71d8944a01
commit 446a563647

View file

@ -85,7 +85,15 @@ export const conformWorker = async (job) => {
const tmpDir = tmpdir(); const tmpDir = tmpdir();
const segmentsDir = join(tmpDir, `segments-${jobId}`); const segmentsDir = join(tmpDir, `segments-${jobId}`);
const segmentListPath = join(tmpDir, `segments-${jobId}.txt`); const segmentListPath = join(tmpDir, `segments-${jobId}.txt`);
const outputPath = join(tmpDir, `output-${jobId}.mp4`); // Container per codec — ProRes / DNxHR live in QuickTime (MOV); MP4 only
// accepts H.264/H.265 and a handful of others. The earlier .mp4 hard-code
// tripped ffmpeg with:
// [mp4] Could not find tag for codec prores in stream #0,
// codec not currently supported in container
const outputExt =
(codec === 'prores' || codec === 'prores_hq' || codec === 'prores_4444' || codec === 'dnxhr_hq')
? 'mov' : 'mp4';
const outputPath = join(tmpDir, `output-${jobId}.${outputExt}`);
try { try {
let edits = []; let edits = [];
@ -319,7 +327,7 @@ export const conformWorker = async (job) => {
]); ]);
await job.updateProgress(85); await job.updateProgress(85);
const outputKey = `jobs/${jobId}/conformed.mp4`; const outputKey = `jobs/${jobId}/conformed.${outputExt}`;
console.log(`[conform] Uploading output to ${outputKey}`); console.log(`[conform] Uploading output to ${outputKey}`);
await uploadToS3(S3_BUCKET, outputKey, outputPath); await uploadToS3(S3_BUCKET, outputKey, outputPath);
@ -329,7 +337,7 @@ export const conformWorker = async (job) => {
VALUES ($1, $2, $3, 'video', 'ready', $4, $5, $6, $7, $8, $9) RETURNING id`, VALUES ($1, $2, $3, 'video', 'ready', $4, $5, $6, $7, $8, $9) RETURNING id`,
[ [
projectId || null, projectId || null,
`conformed-${seqName.replace(/[^a-z0-9]/gi, '_')}.mp4`, `conformed-${seqName.replace(/[^a-z0-9]/gi, '_')}.${outputExt}`,
`Conformed: ${seqName}`, `Conformed: ${seqName}`,
outputKey, outputKey,
// Normalise the panel's codec id into the canonical name we store on // Normalise the panel's codec id into the canonical name we store on