Files
clawbot/skills/remotion-prompt-video/node_modules/@remotion/webcodecs/dist/reencode-video-track.js

152 lines
6.9 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.reencodeVideoTrack = void 0;
const arraybuffer_to_uint8_array_1 = require("./arraybuffer-to-uint8-array");
const convert_encoded_chunk_1 = require("./convert-encoded-chunk");
const create_video_decoder_1 = require("./create-video-decoder");
const log_1 = require("./log");
const on_frame_1 = require("./on-frame");
const processing_queue_1 = require("./processing-queue");
const rotation_1 = require("./rotation");
const sort_video_frames_1 = require("./sort-video-frames");
const video_decoder_config_1 = require("./video-decoder-config");
const video_encoder_1 = require("./video-encoder");
const video_encoder_config_1 = require("./video-encoder-config");
const reencodeVideoTrack = async ({ videoOperation, rotate, track, logLevel, abortConversion, onMediaStateUpdate, controller, onVideoFrame, state, progressTracker, }) => {
if (videoOperation.type !== 'reencode') {
throw new Error(`Video track with ID ${track.trackId} could not be resolved with a valid operation. Received ${JSON.stringify(videoOperation)}, but must be either "copy", "reencode", "drop" or "fail"`);
}
const rotation = videoOperation.rotate ?? rotate;
const { height: newHeight, width: newWidth } = (0, rotation_1.calculateNewDimensionsFromRotateAndScale)({
width: track.codedWidth,
height: track.codedHeight,
rotation,
needsToBeMultipleOfTwo: videoOperation.videoCodec === 'h264',
resizeOperation: videoOperation.resize ?? null,
});
const videoEncoderConfig = await (0, video_encoder_config_1.getVideoEncoderConfig)({
codec: videoOperation.videoCodec,
height: newHeight,
width: newWidth,
fps: track.fps,
});
const videoDecoderConfig = await (0, video_decoder_config_1.getVideoDecoderConfigWithHardwareAcceleration)(track);
log_1.Log.verbose(logLevel, 'Video encoder config', videoEncoderConfig);
log_1.Log.verbose(logLevel, 'Video decoder config', videoDecoderConfig ?? track);
if (videoEncoderConfig === null) {
abortConversion(new Error(`Could not configure video encoder of track ${track.trackId}`));
return null;
}
if (videoDecoderConfig === null) {
abortConversion(new Error(`Could not configure video decoder of track ${track.trackId}`));
return null;
}
const { trackNumber } = await state.addTrack({
type: 'video',
color: track.advancedColor,
width: newWidth,
height: newHeight,
codec: videoOperation.videoCodec,
codecPrivate: null,
timescale: track.originalTimescale,
});
log_1.Log.verbose(logLevel, `Created new video track with ID ${trackNumber}, codec ${videoOperation.videoCodec} and timescale ${track.originalTimescale}`);
const videoEncoder = (0, video_encoder_1.createVideoEncoder)({
onChunk: async (chunk, metadata) => {
await state.addSample({
chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk),
trackNumber,
isVideo: true,
codecPrivate: (0, arraybuffer_to_uint8_array_1.arrayBufferToUint8Array)((metadata?.decoderConfig?.description ?? null)),
});
onMediaStateUpdate?.((prevState) => {
return {
...prevState,
encodedVideoFrames: prevState.encodedVideoFrames + 1,
};
});
},
onError: (err) => {
abortConversion(new Error(`Video encoder of track ${track.trackId} failed (see .cause of this error)`, {
cause: err,
}));
},
controller,
config: videoEncoderConfig,
logLevel,
outputCodec: videoOperation.videoCodec,
keyframeInterval: 40,
});
const videoProcessingQueue = (0, processing_queue_1.processingQueue)({
controller,
label: 'VideoFrame processing queue',
logLevel,
onError: (err) => {
abortConversion(new Error(`VideoFrame processing queue of track ${track.trackId} failed (see .cause of this error)`, {
cause: err,
}));
},
onOutput: async (frame) => {
await controller._internals._mediaParserController._internals.checkForAbortAndPause();
const processedFrame = await (0, on_frame_1.processFrame)({
frame,
track,
onVideoFrame,
outputCodec: videoOperation.videoCodec,
rotation,
resizeOperation: videoOperation.resize ?? null,
});
await controller._internals._mediaParserController._internals.checkForAbortAndPause();
await videoEncoder.ioSynchronizer.waitForQueueSize(10);
await controller._internals._mediaParserController._internals.checkForAbortAndPause();
videoEncoder.encode(processedFrame);
processedFrame.close();
},
});
const frameSorter = (0, sort_video_frames_1.videoFrameSorter)({
controller,
onOutput: async (frame) => {
await controller._internals._mediaParserController._internals.checkForAbortAndPause();
await videoProcessingQueue.ioSynchronizer.waitForQueueSize(10);
videoProcessingQueue.input(frame);
},
});
const videoDecoder = await (0, create_video_decoder_1.createVideoDecoder)({
track: videoDecoderConfig,
onFrame: async (frame) => {
await frameSorter.waitUntilProcessed();
frameSorter.inputFrame(frame);
},
onError: (err) => {
abortConversion(new Error(`Video decoder of track ${track.trackId} failed (see .cause of this error)`, {
cause: err,
}));
},
controller,
logLevel,
});
state.addWaitForFinishPromise(async () => {
log_1.Log.verbose(logLevel, 'Waiting for video decoder to finish');
await videoDecoder.flush();
videoDecoder.close();
log_1.Log.verbose(logLevel, 'Video decoder finished. Waiting for encoder to finish');
await frameSorter.flush();
log_1.Log.verbose(logLevel, 'Frame sorter flushed');
await videoProcessingQueue.ioSynchronizer.waitForQueueSize(0);
log_1.Log.verbose(logLevel, 'Video processing queue finished');
await videoEncoder.waitForFinish();
videoEncoder.close();
log_1.Log.verbose(logLevel, 'Video encoder finished');
});
return async (chunk) => {
progressTracker.setPossibleLowestTimestamp(Math.min(chunk.timestamp, chunk.decodingTimestamp ?? Infinity));
await controller._internals._mediaParserController._internals.checkForAbortAndPause();
await videoDecoder.waitForQueueToBeLessThan(15);
if (chunk.type === 'key') {
await videoDecoder.flush();
}
videoDecoder.decode(chunk);
};
};
exports.reencodeVideoTrack = reencodeVideoTrack;