1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-22 02:12:30 +01:00

implement DV Analyzer import #1664

This commit is contained in:
Mikael Finstad 2023-07-25 18:55:04 +02:00
parent 5ee1df97fa
commit 2c2fa88dff
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
7 changed files with 231 additions and 6 deletions

View File

@ -100,6 +100,12 @@ module.exports = ({ app, mainWindow, newVersion, isStoreBuild }) => {
mainWindow.webContents.send('importEdlFile', 'pbf');
},
},
{
label: esc(t('DV Analyzer Summary.txt')),
click() {
mainWindow.webContents.send('importEdlFile', 'dv-analyzer-summary-txt');
},
},
],
},
{

View File

@ -103,6 +103,14 @@ let lastOpenedPath;
const hevcPlaybackSupportedPromise = doesPlayerSupportHevcPlayback();
hevcPlaybackSupportedPromise.catch((err) => console.error(err));
function getImportProjectType(filePath) {
if (filePath.endsWith('Summary.txt')) return 'dv-analyzer-summary-txt';
const edlFormatForExtension = { csv: 'csv', pbf: 'pbf', edl: 'mplayer', cue: 'cue', xml: 'xmeml', fcpxml: 'fcpxml' };
const matchingExt = Object.keys(edlFormatForExtension).find((ext) => filePath.toLowerCase().endsWith(`.${ext}`));
if (!matchingExt) return undefined;
return edlFormatForExtension[matchingExt];
}
const App = memo(() => {
// Per project state
const [commandedTime, setCommandedTime] = useState(0);
@ -1712,11 +1720,10 @@ const App = memo(() => {
setWorking(i18n.t('Loading file'));
// Import segments for for already opened file
const edlFormats = { csv: 'csv', pbf: 'pbf', edl: 'mplayer', cue: 'cue', xml: 'xmeml', fcpxml: 'fcpxml' };
const matchingExt = Object.keys(edlFormats).find((ext) => filePathLowerCase.endsWith(`.${ext}`));
if (matchingExt) {
const matchingImportProjectType = getImportProjectType(firstFilePath);
if (matchingImportProjectType) {
if (!checkFileOpened()) return;
await loadEdlFile({ path: firstFilePath, type: edlFormats[matchingExt], append: true });
await loadEdlFile({ path: firstFilePath, type: matchingImportProjectType, append: true });
return;
}

View File

@ -1,5 +1,130 @@
// Vitest Snapshot v1
exports[`parses DV Analyzer Summary.txt 1`] = `
[
{
"end": 60.4,
"name": "XXXX-XX-XX 00:00:00.000 - XXXX-XX-XX XX:XX:XX:XX",
"start": 0,
},
{
"end": 485.08,
"name": "XXXX-XX-XX XX:XX:XX:XX - 2001-12-31 23:22:09",
"start": 60.4,
},
{
"end": 1010.68,
"name": "2001-12-31 23:28:13 - 2002-01-01 19:34:38",
"start": 485.08,
},
{
"end": 1235.32,
"name": "2002-01-01 13:31:24 - 2002-01-01 22:03:01",
"start": 1010.68,
},
{
"end": 1575.04,
"name": "2002-01-02 14:27:10 - 2002-01-02 15:48:55",
"start": 1235.32,
},
{
"end": 1575.08,
"name": "2002-01-02 22:30:22 - 2002-01-02 22:30:22",
"start": 1575.04,
},
{
"end": 1575.16,
"name": "2002-01-02 22:30:22 - 2002-01-02 22:30:22",
"start": 1575.08,
},
{
"end": 1575.24,
"name": "2002-01-02 22:30:22 - 2002-01-05 10:57:51",
"start": 1575.16,
},
{
"end": 1919.44,
"name": "2002-01-05 10:57:51 - 2002-01-05 11:36:20",
"start": 1575.24,
},
{
"end": 2075.88,
"name": "2002-01-05 13:18:43 - 2002-01-05 14:04:19",
"start": 1919.44,
},
{
"end": 2138.2,
"name": "2002-01-05 16:39:22 - 2002-01-05 22:51:40",
"start": 2075.88,
},
{
"end": 2138.76,
"name": "2002-01-05 16:40:24 - 2002-01-05 16:40:25",
"start": 2138.2,
},
{
"end": 2217.32,
"name": "2002-01-05 22:53:17 - 2002-01-05 22:55:08",
"start": 2138.76,
},
{
"end": 2269.96,
"name": "2002-01-16 21:17:04 - 2002-01-16 21:18:01",
"start": 2217.32,
},
{
"end": 2332.64,
"name": "2002-01-20 20:06:37 - 2002-01-20 20:07:48",
"start": 2269.96,
},
{
"end": 3009.12,
"name": "2002-01-30 18:34:52 - 2002-03-12 00:46:51",
"start": 2332.64,
},
{
"end": 3596.48,
"name": "2002-03-14 20:27:57 - 2002-04-12 21:06:54",
"start": 3009.12,
},
{
"end": 3622.08,
"name": "2002-04-12 21:06:56 - 2002-04-12 21:07:22",
"start": 3596.48,
},
{
"end": 4305,
"name": "2002-04-12 21:11:47 - 2002-04-27 00:05:36",
"start": 3622.08,
},
{
"end": 4307.12,
"name": "2002-04-25 22:59:57 - 2002-04-25 22:59:59",
"start": 4305,
},
{
"end": 4357.68,
"name": "2002-04-25 23:00:00 - 2002-05-02 13:33:33",
"start": 4307.12,
},
{
"end": 4359.72,
"name": "2002-04-25 23:00:50 - 2002-04-25 23:00:52",
"start": 4357.68,
},
{
"end": 4660.44,
"name": "2002-05-02 13:40:27 - 2002-05-02 13:53:34",
"start": 4359.72,
},
{
"end": undefined,
"name": "2002-05-02 13:54:14 - 2002-05-02 13:59:29",
"start": 4660.44,
},
]
`;
exports[`parses fcpxml 1.9 1`] = `
[
{

View File

@ -244,3 +244,32 @@ export async function formatCsvHuman(cutSegments) {
export async function formatTsv(cutSegments) {
return csvStringifyAsync(formatSegmentsTimes(cutSegments), { delimiter: '\t' });
}
export function parseDvAnalyzerSummaryTxt(txt) {
const lines = txt.split(/\r?\n/);
let headerFound = false;
const times = [];
// eslint-disable-next-line no-restricted-syntax
for (const line of lines) {
if (headerFound) {
const match = line.match(/^(\d{2}):(\d{2}):(\d{2}).(\d{3})\s+([^\s]+)\s+-\s+([^\s]+)\s+([^\s]+\s+[^\s]+)\s+-\s+([^\s]+\s+[^\s]+)/);
if (!match) break;
const h = parseInt(match[1], 10);
const m = parseInt(match[2], 10);
const s = parseInt(match[3], 10);
const ms = parseInt(match[4], 10);
const total = s + ((m + (h * 60)) * 60) + (ms / 1000);
times.push({ time: total, name: `${match[7]} - ${match[8]}` });
}
if (/^Absolute time\s+DV timecode range\s+Recorded date\/time range\s+Frame range\s*$/.test(line)) headerFound = true;
}
const edl = times.map(({ time, name }, i) => {
const nextTime = times[i + 1];
return { start: time, end: nextTime?.time, name };
});
return edl;
}

View File

@ -4,7 +4,7 @@ import { fileURLToPath } from 'url';
import { it, describe, expect } from 'vitest';
import { parseYouTube, formatYouTube, parseMplayerEdl, parseXmeml, parseFcpXml, parseCsv, getTimeFromFrameNum, formatCsvFrames, getFrameCountRaw, parsePbf } from './edlFormats';
import { parseYouTube, formatYouTube, parseMplayerEdl, parseXmeml, parseFcpXml, parseCsv, getTimeFromFrameNum, formatCsvFrames, getFrameCountRaw, parsePbf, parseDvAnalyzerSummaryTxt } from './edlFormats';
// eslint-disable-next-line no-underscore-dangle
const __dirname = dirname(fileURLToPath(import.meta.url));
@ -217,3 +217,8 @@ it('parses pbf', async () => {
expect(parsePbf(await readFixture('test3.pbf', null))).toMatchSnapshot();
expect(parsePbf(await readFixture('potplayer bookmark format utf16le issue 867.pbf', null))).toMatchSnapshot();
});
// https://github.com/mifi/lossless-cut/issues/1664
it('parses DV Analyzer Summary.txt', async () => {
expect(parseDvAnalyzerSummaryTxt(await readFixture('DV Analyzer Summary.txt', 'utf-8'))).toMatchSnapshot();
});

View File

@ -1,7 +1,7 @@
import JSON5 from 'json5';
import i18n from 'i18next';
import { parseCuesheet, parseXmeml, parseFcpXml, parseCsv, parsePbf, parseMplayerEdl, formatCsvHuman, formatTsv, formatCsvFrames, formatCsvSeconds, getTimeFromFrameNum } from './edlFormats';
import { parseCuesheet, parseXmeml, parseFcpXml, parseCsv, parsePbf, parseMplayerEdl, formatCsvHuman, formatTsv, formatCsvFrames, formatCsvSeconds, getTimeFromFrameNum, parseDvAnalyzerSummaryTxt } from './edlFormats';
import { askForYouTubeInput, showOpenDialog } from './dialogs';
import { getOutPath } from './util';
@ -28,6 +28,10 @@ export async function loadFcpXml(path) {
return parseFcpXml(await fs.readFile(path, 'utf-8'));
}
export async function loadDvAnalyzerSummaryTxt(path) {
return parseDvAnalyzerSummaryTxt(await fs.readFile(path, 'utf-8'));
}
export async function loadPbf(path) {
return parsePbf(await fs.readFile(path));
}
@ -75,6 +79,7 @@ export async function readEdlFile({ type, path, fps }) {
if (type === 'csv-frames') return loadCsvFrames(path, fps);
if (type === 'xmeml') return loadXmeml(path);
if (type === 'fcpxml') return loadFcpXml(path);
if (type === 'dv-analyzer-summary-txt') return loadDvAnalyzerSummaryTxt(path);
if (type === 'cue') return loadCue(path);
if (type === 'pbf') return loadPbf(path);
if (type === 'mplayer') return loadMplayerEdl(path);
@ -95,6 +100,7 @@ export async function askForEdlImport({ type, fps }) {
else if (type === 'cue') filters = [{ name: i18n.t('CUE files'), extensions: ['cue'] }];
else if (type === 'pbf') filters = [{ name: i18n.t('PBF files'), extensions: ['pbf'] }];
else if (type === 'mplayer') filters = [{ name: i18n.t('MPlayer EDL'), extensions: ['*'] }];
else if (type === 'dv-analyzer-summary-txt') filters = [{ name: i18n.t('DV Analyzer Summary.txt'), extensions: ['txt'] }];
else if (type === 'llc') filters = [{ name: i18n.t('LosslessCut project'), extensions: ['llc'] }];
const { canceled, filePaths } = await showOpenDialog({ properties: ['openFile'], filters });

View File

@ -0,0 +1,47 @@
DV Analyzer v.1.4.2 by AudioVisual Preservation Solutions, Inc. http://www.avpreserve.com
L:\To-Re-Encode\31.12.2001 Cats Test Tape (TDK Tape).avi
Frame Count: 116883
Frame count with video error concealment: 2776 frames
Total video error concealment: 319120 errors ( 317500 "A" errors, 1620 "F" errors)
Frame count with CH1 audio error code: 783 frames
Total audio error code for CH1: 16263 errors ( 4005 Dseq=0, 1575 Dseq=1, 3780 Dseq=2, 1611 Dseq=3, 3672 Dseq=4, 1620 Dseq=5)
Frame count with DV timecode incoherency: 2 frames
Frame count with Arbitrary bit inconsistency: 6 frames
Absolute time DV timecode range Recorded date/time range Frame range
00:00:00.000 00:00:00:15 - 00:01:00:16 XXXX-XX-XX 00:00:00.000 - XXXX-XX-XX XX:XX:XX:XX 0 - 1509
00:01:00.400 00:00:00:00 - 00:07:04:08 XXXX-XX-XX XX:XX:XX:XX - 2001-12-31 23:22:09 1510 - 12126
00:08:05.080 00:00:00:00 - 00:08:45:14 2001-12-31 23:28:13 - 2002-01-01 19:34:38 12127 - 25266
00:16:50.680 00:08:45:15 - 00:12:29:22 2002-01-01 13:31:24 - 2002-01-01 22:03:01 25267 - 30882
00:20:35.320 00:00:00:00 - 00:05:39:09 2002-01-02 14:27:10 - 2002-01-02 15:48:55 30883 - 39375
00:26:15.040 00:00:00:00 - 00:00:00:00 2002-01-02 22:30:22 - 2002-01-02 22:30:22 39376 - 39376
00:26:15.080 00:00:00:02 - 00:00:00:03 2002-01-02 22:30:22 - 2002-01-02 22:30:22 39377 - 39378
00:26:15.160 00:00:00:05 - 00:00:00:06 2002-01-02 22:30:22 - 2002-01-05 10:57:51 39379 - 39380
00:26:15.240 00:00:00:08 - 00:05:44:04 2002-01-05 10:57:51 - 2002-01-05 11:36:20 39381 - 47985
00:31:59.440 00:00:00:00 - 00:02:36:02 2002-01-05 13:18:43 - 2002-01-05 14:04:19 47986 - 51896
00:34:35.880 00:00:00:00 - 00:01:02:07 2002-01-05 16:39:22 - 2002-01-05 22:51:40 51897 - 53454
00:35:38.200 00:01:02:08 - 00:01:02:14 2002-01-05 16:40:24 - 2002-01-05 16:40:25 53455 - 53468
00:35:38.760 00:00:00:00 - 00:01:18:05 2002-01-05 22:53:17 - 2002-01-05 22:55:08 53469 - 55432
00:36:57.320 00:00:00:00 - 00:00:52:07 2002-01-16 21:17:04 - 2002-01-16 21:18:01 55433 - 56748
00:37:49.960 00:00:00:00 - 00:01:02:08 2002-01-20 20:06:37 - 2002-01-20 20:07:48 56749 - 58315
00:38:52.640 00:00:00:00 - 00:11:16:02 2002-01-30 18:34:52 - 2002-03-12 00:46:51 58316 - 75227
00:50:09.120 00:00:00:00 - 00:09:47:08 2002-03-14 20:27:57 - 2002-04-12 21:06:54 75228 - 89911
00:59:56.480 00:09:49:07 - 00:10:14:14 2002-04-12 21:06:56 - 2002-04-12 21:07:22 89912 - 90551
01:00:22.080 00:00:00:00 - 00:11:22:21 2002-04-12 21:11:47 - 2002-04-27 00:05:36 90552 - 107624
01:11:45.000 00:11:22:22 - 00:11:25:00 2002-04-25 22:59:57 - 2002-04-25 22:59:59 107625 - 107677
01:11:47.120 00:11:25:01 - 00:12:15:14 2002-04-25 23:00:00 - 2002-05-02 13:33:33 107678 - 108941
01:12:37.680 00:12:15:15 - 00:12:17:07 2002-04-25 23:00:50 - 2002-04-25 23:00:52 108942 - 108992
01:12:39.720 00:00:00:00 - 00:05:00:09 2002-05-02 13:40:27 - 2002-05-02 13:53:34 108993 - 116510
01:17:40.440 00:00:00:00 - 00:00:14:21 2002-05-02 13:54:14 - 2002-05-02 13:59:29 116511 - 116882
Percent of frames with Error: 2.69%
Percent of frames with Error (including Arbitrary bit inconsistency): 2.69%
Percent of frames with Video Error Concealment: 2.38%
Percent of frames with Audio Errors: 0.67%
Percent of frames with Timecode Incoherency: 0.00%
Percent of frames with Arbitrary bit inconsistency: 0.01%
Warning, frame count is maybe incoherant (reported by MediaInfo: 116882)