mirror of
https://github.com/mifi/lossless-cut.git
synced 2024-11-22 10:22:31 +01:00
fix broken black/silence detection #1705
This commit is contained in:
parent
1acf72fcfd
commit
91ceef3972
@ -277,6 +277,39 @@ async function detectIntervals({ filePath, customArgs, onProgress, from, to, mat
|
|||||||
return adjustSegmentsWithOffset({ segments, from });
|
return adjustSegmentsWithOffset({ segments, from });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mapFilterOptions = (options) => Object.entries(options).map(([key, value]) => `${key}=${value}`).join(':');
|
||||||
|
|
||||||
|
async function blackDetect({ filePath, filterOptions, onProgress, from, to }) {
|
||||||
|
function matchLineTokens(line) {
|
||||||
|
const match = line.match(/^[blackdetect\s*@\s*0x[0-9a-f]+] black_start:([\d\\.]+) black_end:([\d\\.]+) black_duration:[\d\\.]+/);
|
||||||
|
if (!match) return {};
|
||||||
|
return {
|
||||||
|
start: parseFloat(match[1]),
|
||||||
|
end: parseFloat(match[2]),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const customArgs = ['-vf', `blackdetect=${mapFilterOptions(filterOptions)}`, '-an'];
|
||||||
|
return detectIntervals({ filePath, onProgress, from, to, matchLineTokens, customArgs });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function silenceDetect({ filePath, filterOptions, onProgress, from, to }) {
|
||||||
|
function matchLineTokens(line) {
|
||||||
|
const match = line.match(/^[silencedetect\s*@\s*0x[0-9a-f]+] silence_end: ([\d\\.]+)[|\s]+silence_duration: ([\d\\.]+)/);
|
||||||
|
if (!match) return {};
|
||||||
|
const end = parseFloat(match[1]);
|
||||||
|
const silenceDuration = parseFloat(match[2]);
|
||||||
|
if (Number.isNaN(end) || Number.isNaN(silenceDuration)) return {};
|
||||||
|
const start = end - silenceDuration;
|
||||||
|
if (start < 0 || end <= 0 || start >= end) return {};
|
||||||
|
return {
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const customArgs = ['-af', `silencedetect=${mapFilterOptions(filterOptions)}`, '-vn'];
|
||||||
|
return detectIntervals({ filePath, onProgress, from, to, matchLineTokens, customArgs });
|
||||||
|
}
|
||||||
|
|
||||||
function getFffmpegJpegQuality(quality) {
|
function getFffmpegJpegQuality(quality) {
|
||||||
// Normal range for JPEG is 2-31 with 31 being the worst quality.
|
// Normal range for JPEG is 2-31 with 31 being the worst quality.
|
||||||
const qMin = 2;
|
const qMin = 2;
|
||||||
@ -522,7 +555,6 @@ module.exports = {
|
|||||||
renderWaveformPng,
|
renderWaveformPng,
|
||||||
mapTimesToSegments,
|
mapTimesToSegments,
|
||||||
detectSceneChanges,
|
detectSceneChanges,
|
||||||
detectIntervals,
|
|
||||||
captureFrames,
|
captureFrames,
|
||||||
captureFrame,
|
captureFrame,
|
||||||
getFfCommandLine,
|
getFfCommandLine,
|
||||||
@ -530,4 +562,6 @@ module.exports = {
|
|||||||
getDuration,
|
getDuration,
|
||||||
getOneRawFrame,
|
getOneRawFrame,
|
||||||
encodeLiveRawStream,
|
encodeLiveRawStream,
|
||||||
|
blackDetect,
|
||||||
|
silenceDetect,
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,7 @@ const { pathExists } = window.require('fs-extra');
|
|||||||
|
|
||||||
const remote = window.require('@electron/remote');
|
const remote = window.require('@electron/remote');
|
||||||
|
|
||||||
const { renderWaveformPng, mapTimesToSegments, detectSceneChanges, detectIntervals, captureFrames, captureFrame, getFfCommandLine, runFfmpegConcat, runFfmpegWithProgress, html5ify, getDuration, abortFfmpegs, runFfmpeg, runFfprobe, getFfmpegPath, setCustomFfPath } = remote.require('./ffmpeg');
|
const { renderWaveformPng, mapTimesToSegments, detectSceneChanges, captureFrames, captureFrame, getFfCommandLine, runFfmpegConcat, runFfmpegWithProgress, html5ify, getDuration, abortFfmpegs, runFfmpeg, runFfprobe, getFfmpegPath, setCustomFfPath } = remote.require('./ffmpeg');
|
||||||
|
|
||||||
|
|
||||||
export { renderWaveformPng, mapTimesToSegments, detectSceneChanges, captureFrames, captureFrame, getFfCommandLine, runFfmpegConcat, runFfmpegWithProgress, html5ify, getDuration, abortFfmpegs, runFfprobe, getFfmpegPath, setCustomFfPath };
|
export { renderWaveformPng, mapTimesToSegments, detectSceneChanges, captureFrames, captureFrame, getFfCommandLine, runFfmpegConcat, runFfmpegWithProgress, html5ify, getDuration, abortFfmpegs, runFfprobe, getFfmpegPath, setCustomFfPath };
|
||||||
@ -483,40 +483,6 @@ export async function renderThumbnails({ filePath, from, duration, onThumbnail }
|
|||||||
}, { concurrency: 2 });
|
}, { concurrency: 2 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const mapFilterOptions = (options) => Object.entries(options).map(([key, value]) => `${key}=${value}`).join(':');
|
|
||||||
|
|
||||||
export async function blackDetect({ filePath, filterOptions, onProgress, from, to }) {
|
|
||||||
function matchLineTokens(line) {
|
|
||||||
const match = line.match(/^[blackdetect\s*@\s*0x[0-9a-f]+] black_start:([\d\\.]+) black_end:([\d\\.]+) black_duration:[\d\\.]+/);
|
|
||||||
if (!match) return {};
|
|
||||||
return {
|
|
||||||
start: parseFloat(match[1]),
|
|
||||||
end: parseFloat(match[2]),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const customArgs = ['-vf', `blackdetect=${mapFilterOptions(filterOptions)}`, '-an'];
|
|
||||||
return detectIntervals({ filePath, onProgress, from, to, matchLineTokens, customArgs });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function silenceDetect({ filePath, filterOptions, onProgress, from, to }) {
|
|
||||||
function matchLineTokens(line) {
|
|
||||||
const match = line.match(/^[silencedetect\s*@\s*0x[0-9a-f]+] silence_end: ([\d\\.]+)[|\s]+silence_duration: ([\d\\.]+)/);
|
|
||||||
if (!match) return {};
|
|
||||||
const end = parseFloat(match[1]);
|
|
||||||
const silenceDuration = parseFloat(match[2]);
|
|
||||||
if (Number.isNaN(end) || Number.isNaN(silenceDuration)) return {};
|
|
||||||
const start = end - silenceDuration;
|
|
||||||
if (start < 0 || end <= 0 || start >= end) return {};
|
|
||||||
return {
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const customArgs = ['-af', `silencedetect=${mapFilterOptions(filterOptions)}`, '-vn'];
|
|
||||||
return detectIntervals({ filePath, onProgress, from, to, matchLineTokens, customArgs });
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function extractWaveform({ filePath, outPath }) {
|
export async function extractWaveform({ filePath, outPath }) {
|
||||||
const numSegs = 10;
|
const numSegs = 10;
|
||||||
const duration = 60 * 60;
|
const duration = 60 * 60;
|
||||||
|
@ -6,7 +6,7 @@ import pMap from 'p-map';
|
|||||||
|
|
||||||
import sortBy from 'lodash/sortBy';
|
import sortBy from 'lodash/sortBy';
|
||||||
|
|
||||||
import { blackDetect, silenceDetect, detectSceneChanges as ffmpegDetectSceneChanges, readFrames, mapTimesToSegments, findKeyframeNearTime } from '../ffmpeg';
|
import { detectSceneChanges as ffmpegDetectSceneChanges, readFrames, mapTimesToSegments, findKeyframeNearTime } from '../ffmpeg';
|
||||||
import { handleError, shuffleArray } from '../util';
|
import { handleError, shuffleArray } from '../util';
|
||||||
import { errorToast } from '../swal';
|
import { errorToast } from '../swal';
|
||||||
import { showParametersDialog } from '../dialogs/parameters';
|
import { showParametersDialog } from '../dialogs/parameters';
|
||||||
@ -15,6 +15,10 @@ import { createSegment, findSegmentsAtCursor, sortSegments, invertSegments, getS
|
|||||||
import * as ffmpegParameters from '../ffmpeg-parameters';
|
import * as ffmpegParameters from '../ffmpeg-parameters';
|
||||||
import { maxSegmentsAllowed } from '../util/constants';
|
import { maxSegmentsAllowed } from '../util/constants';
|
||||||
|
|
||||||
|
const remote = window.require('@electron/remote');
|
||||||
|
|
||||||
|
const { blackDetect, silenceDetect } = remote.require('./ffmpeg');
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
filePath, workingRef, setWorking, setCutProgress, mainVideoStream,
|
filePath, workingRef, setWorking, setCutProgress, mainVideoStream,
|
||||||
|
Loading…
Reference in New Issue
Block a user