Unity启动,录制视频没有文件产出

This commit is contained in:
2026-06-03 00:37:41 +08:00
parent 3e161ff995
commit f742499b33
4 changed files with 142 additions and 7 deletions

View File

@@ -55,7 +55,7 @@ type CompositionInputSets = {
type VideoTimelineSegment = {
startMs: number;
endMs: number;
endMs: number | null;
activeInputs: ServerTrackRecordingFile[];
};
@@ -275,8 +275,10 @@ function getVideoTimelineSegments(
}
const activeInputs = sortActiveVideoInputs(files.filter((file) => {
const inputStartMs = getInputStartMs(file) || timelineOriginMs;
const inputEndMs = getInputEndMs(file) || timelineEndMs;
const fileStartMs = getInputStartMs(file);
const fileEndMs = getInputEndMs(file);
const inputStartMs = fileStartMs === null ? timelineOriginMs : fileStartMs;
const inputEndMs = fileEndMs === null ? timelineEndMs : fileEndMs;
return inputStartMs < endMs && inputEndMs > startMs;
}));
segments.push({ startMs, endMs, activeInputs });
@@ -285,6 +287,17 @@ function getVideoTimelineSegments(
return segments;
}
function getFallbackVideoTimelineSegment(
files: ServerTrackRecordingFile[],
timelineOriginMs: number | null
): VideoTimelineSegment {
return {
startMs: timelineOriginMs === null ? 0 : timelineOriginMs,
endMs: null,
activeInputs: sortActiveVideoInputs(files)
};
}
export function buildFfmpegCompositionArgs(input: {
videoInputs: ServerTrackRecordingFile[];
audioInputs: ServerTrackRecordingFile[];
@@ -299,7 +312,10 @@ export function buildFfmpegCompositionArgs(input: {
const timelineOriginMs = getTimelineOriginMs(videoInputs.concat(input.audioInputs));
const timelineEndMs = getTimelineEndMs(videoInputs.concat(input.audioInputs));
const timelineDurationSeconds = getTimelineDurationSeconds(videoInputs.concat(input.audioInputs), timelineOriginMs);
const videoSegments = getVideoTimelineSegments(videoInputs, timelineOriginMs, timelineEndMs);
const timelineVideoSegments = getVideoTimelineSegments(videoInputs, timelineOriginMs, timelineEndMs);
const videoSegments = timelineVideoSegments.length > 0
? timelineVideoSegments
: [getFallbackVideoTimelineSegment(videoInputs, timelineOriginMs)];
const args = ['-y'];
const orderedInputs = videoInputs.concat(input.audioInputs);
orderedInputs.forEach((file) => {
@@ -322,8 +338,11 @@ export function buildFfmpegCompositionArgs(input: {
});
videoSegments.forEach((segment, segmentIndex) => {
const segmentDurationSeconds = (segment.endMs - segment.startMs) / 1000;
const segmentDurationSeconds = segment.endMs === null ? null : (segment.endMs - segment.startMs) / 1000;
if (segment.activeInputs.length === 0) {
if (segmentDurationSeconds === null) {
return;
}
filters.push(`color=color=black:size=${outputWidth}x${outputHeight}:rate=30:duration=${formatSeconds(segmentDurationSeconds)},format=yuv420p[seg${segmentIndex}]`);
return;
}
@@ -333,7 +352,8 @@ export function buildFfmpegCompositionArgs(input: {
const inputLabel = videoInputUseCounts[inputIndex] > 1
? `vin${inputIndex}_${videoInputUsePositions[inputIndex]++}`
: `${inputIndex}:v`;
const inputStartMs = getInputStartMs(file) || segment.startMs;
const fileStartMs = getInputStartMs(file);
const inputStartMs = fileStartMs === null ? segment.startMs : fileStartMs;
const trimStartSeconds = Math.max(0, (segment.startMs - inputStartMs) / 1000);
const width = segment.activeInputs.length === 1
? outputWidth
@@ -341,7 +361,11 @@ export function buildFfmpegCompositionArgs(input: {
const height = segment.activeInputs.length === 1
? outputHeight
: activeIndex === 0 ? hostHeight : bottomHeight;
filters.push(`[${inputLabel}]trim=start=${formatSeconds(trimStartSeconds)}:duration=${formatSeconds(segmentDurationSeconds)},setpts=PTS-STARTPTS,scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2:black,setsar=1[seg${segmentIndex}v${activeIndex}]`);
const trimOptions = [`start=${formatSeconds(trimStartSeconds)}`];
if (segmentDurationSeconds !== null) {
trimOptions.push(`duration=${formatSeconds(segmentDurationSeconds)}`);
}
filters.push(`[${inputLabel}]trim=${trimOptions.join(':')},setpts=PTS-STARTPTS,scale=${width}:${height}:force_original_aspect_ratio=decrease,pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2:black,setsar=1[seg${segmentIndex}v${activeIndex}]`);
});
if (segment.activeInputs.length === 1) {
@@ -435,6 +459,16 @@ function toOutput(job: RecordingCompositionJob, target: ServerTrackRecordingTarg
};
}
function getActiveCompositionJob(input: StartCompositionInput): RecordingCompositionJob | null {
const recordingId = normalizeOption(input.recordingId, '');
const meetingId = normalizeOption(input.meetingId, '');
return Array.from(jobs.values()).find((job) => {
return job.recordingId === recordingId
&& job.meetingId === meetingId
&& (job.status === 'queued' || job.status === 'running');
}) || null;
}
async function runRecordingCompositionJob(job: RecordingCompositionJob): Promise<RecordingCompositionJob> {
const timestamp = nowIso();
job.status = 'running';
@@ -489,6 +523,11 @@ async function runRecordingCompositionJob(job: RecordingCompositionJob): Promise
}
export function startRecordingCompositionJob(input: StartCompositionInput): RecordingCompositionJob {
const activeJob = getActiveCompositionJob(input);
if (activeJob) {
return activeJob;
}
const timestamp = nowIso();
const inputSets = getInputSets(input);
const job: RecordingCompositionJob = {