1
0
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:
Mikael Finstad 2023-09-06 19:56:23 +02:00
parent 1acf72fcfd
commit 91ceef3972
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
3 changed files with 41 additions and 37 deletions

View File

@ -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,
}; };

View File

@ -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;

View File

@ -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,