Use the parent clip last frame and new-segment join for extensions, not the stitched file's first frame. Show this account's library storage in Settings.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+39
-3
@@ -59,6 +59,12 @@ function concatPath(filePath: string) {
|
||||
return filePath.replace(/\\/g, '/').replace(/'/g, "'\\''")
|
||||
}
|
||||
|
||||
function assertFrameFile(path: string, kind: string) {
|
||||
if (!existsSync(path) || statSync(path).size < 64) {
|
||||
throw new Error(`Could not extract the ${kind}`)
|
||||
}
|
||||
}
|
||||
|
||||
export async function extractLastFrame(inputPath: string, outputPath: string) {
|
||||
if (!existsSync(inputPath)) {
|
||||
throw new Error('Source video is missing')
|
||||
@@ -80,7 +86,7 @@ export async function extractLastFrame(inputPath: string, outputPath: string) {
|
||||
for (const args of attempts) {
|
||||
try {
|
||||
await runFfmpeg(args, 60000)
|
||||
if (existsSync(outputPath)) return
|
||||
if (existsSync(outputPath) && statSync(outputPath).size >= 64) return
|
||||
} catch {
|
||||
// Try the next seek strategy.
|
||||
}
|
||||
@@ -102,8 +108,38 @@ export async function extractFirstFrame(inputPath: string, outputPath: string) {
|
||||
'-q:v', '4',
|
||||
outputPath
|
||||
], 20000)
|
||||
if (!existsSync(outputPath)) {
|
||||
throw new Error('Could not extract the first frame')
|
||||
assertFrameFile(outputPath, 'first frame')
|
||||
}
|
||||
|
||||
export async function extractFrameAt(inputPath: string, outputPath: string, seconds: number) {
|
||||
if (!existsSync(inputPath)) {
|
||||
throw new Error('Source video is missing')
|
||||
}
|
||||
const seek = Math.max(0, seconds)
|
||||
await runFfmpeg([
|
||||
'-y',
|
||||
'-ss', seek.toFixed(3),
|
||||
'-i', inputPath,
|
||||
'-frames:v', '1',
|
||||
'-update', '1',
|
||||
'-an',
|
||||
'-q:v', '2',
|
||||
outputPath
|
||||
], 60000)
|
||||
assertFrameFile(outputPath, 'frame')
|
||||
}
|
||||
|
||||
export async function extractFirstFrameFromBuffer(video: Buffer, tmpDir: string) {
|
||||
if (!video.length) throw new Error('Could not extract the first frame')
|
||||
const input = join(tmpDir, `seg_head_${Date.now()}.mp4`)
|
||||
const output = join(tmpDir, `seg_first_${Date.now()}.jpg`)
|
||||
writeFileSync(input, video)
|
||||
try {
|
||||
await extractFirstFrame(input, output)
|
||||
return readFileSync(output)
|
||||
} finally {
|
||||
try { unlinkSync(input) } catch { /* ignore */ }
|
||||
try { unlinkSync(output) } catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user