mediasnacks 0.18.2 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.zsh/completions/_mediasnacks +3 -2
- package/README.md +2 -1
- package/package.json +1 -1
- package/src/cli.js +1 -0
- package/src/detectdups.js +108 -0
- package/src/dropdups.js +1 -1
- package/src/utils/ffmpeg.js +1 -1
|
@@ -8,7 +8,8 @@ _mediasnacks_commands=(
|
|
|
8
8
|
'edgespic:Extracts first and last frames'
|
|
9
9
|
'gif:Video to GIF'
|
|
10
10
|
|
|
11
|
-
'
|
|
11
|
+
'detectdups:Detects sequentially duplicate frames in a video'
|
|
12
|
+
'dropdups:Removes sequentially duplicate frames in a video'
|
|
12
13
|
'framediff:ffplay with a filter for diffing adjacent frames'
|
|
13
14
|
'hev1tohvc1:Fixes video thumbnails not rendering in macOS Finder'
|
|
14
15
|
'moov2front:Rearranges metadata for fast-start streaming'
|
|
@@ -38,7 +39,7 @@ fi
|
|
|
38
39
|
|
|
39
40
|
local cmd="$words[2]"
|
|
40
41
|
case "$cmd" in
|
|
41
|
-
avif|resize|sqcrop|moov2front|dropdups|edgespic|seqcheck|hev1tohvc1|framediff|vdiff|vconcat|vsplit|vtrim|dlaudio|dlvideo|unemoji|rmcover|curltime|gif|flattendir|prores)
|
|
42
|
+
avif|resize|sqcrop|moov2front|detectdups|dropdups|edgespic|seqcheck|hev1tohvc1|framediff|vdiff|vconcat|vsplit|vtrim|dlaudio|dlvideo|unemoji|rmcover|curltime|gif|flattendir|prores)
|
|
42
43
|
_files
|
|
43
44
|
;;
|
|
44
45
|
qdir)
|
package/README.md
CHANGED
|
@@ -34,7 +34,8 @@ mediasnacks <command> <args>
|
|
|
34
34
|
- `gif`: Video to GIF
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
- `
|
|
37
|
+
- `detectdups` Detects sequentially duplicate frames in a video
|
|
38
|
+
- `dropdups` Removes sequentially duplicate frames in a video
|
|
38
39
|
- `framediff`: Plays a video of adjacent frames diff
|
|
39
40
|
- `hev1tohvc1`: Fixes video thumbnails not rendering in macOS Finder
|
|
40
41
|
- `moov2front` Rearranges .mov and .mp4 metadata for fast-start streaming
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -14,6 +14,7 @@ const COMMANDS = {
|
|
|
14
14
|
edgespic: ['edgespic.js', 'Extracts first and last frames'],
|
|
15
15
|
gif: ['gif.sh', 'Video to GIF\n'],
|
|
16
16
|
|
|
17
|
+
detectdups: ['detectdups.js', 'Detects duplicate frames in a video'],
|
|
17
18
|
dropdups: ['dropdups.js', 'Removes duplicate frames in a video'],
|
|
18
19
|
framediff: ['framediff.sh', 'Plays a video of adjacent frames diff'],
|
|
19
20
|
hev1tohvc1: ['hev1tohvc1.js', 'Fixes video thumbnails not rendering in macOS Finder '],
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { parseOptions } from './utils/parseOptions.js'
|
|
4
|
+
import { ffmpeg, assertUserHasFFmpeg, videoAttrs } from './utils/ffmpeg.js'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const USAGE = `
|
|
8
|
+
Usage: mediasnacks detectdups [options] <video>
|
|
9
|
+
|
|
10
|
+
Detects sequentially duplicate frames in a video and prints their frame numbers.
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
-s, --seek <sec> Video start time for detection
|
|
14
|
+
-d, --duration <sec> Analyze this many seconds of video
|
|
15
|
+
-v, --verbose
|
|
16
|
+
-h, --help
|
|
17
|
+
`.trim()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async function main() {
|
|
21
|
+
await assertUserHasFFmpeg()
|
|
22
|
+
|
|
23
|
+
const { values, files } = await parseOptions({
|
|
24
|
+
seek: { short: 's', type: 'string', },
|
|
25
|
+
duration: { short: 'd', type: 'string' },
|
|
26
|
+
help: { short: 'h', type: 'boolean' }
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
if (values.help) {
|
|
30
|
+
console.log(USAGE)
|
|
31
|
+
process.exit(0)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (files.length !== 1)
|
|
35
|
+
throw new Error('One video file must be specified. See mediasnacks detectdups --help')
|
|
36
|
+
|
|
37
|
+
const v = await videoAttrs(files[0])
|
|
38
|
+
|
|
39
|
+
if (v.codec_type !== 'video')
|
|
40
|
+
throw new Error('Input file must be a video.')
|
|
41
|
+
|
|
42
|
+
const vDur = Number(v.duration)
|
|
43
|
+
const seek = Number(values.seek) || (vDur > 60 ? 20 : 0)
|
|
44
|
+
const duration = Number(values.duration) || (vDur > 60 ? 20 : vDur)
|
|
45
|
+
|
|
46
|
+
if (isNaN(seek) || seek < 0)
|
|
47
|
+
throw new Error(`Invalid --seek value: ${values.seek}`)
|
|
48
|
+
|
|
49
|
+
if (isNaN(duration) || duration < 1)
|
|
50
|
+
throw new Error(`Invalid --duration value: ${values.duration}`)
|
|
51
|
+
|
|
52
|
+
if ((seek + duration) > vDur)
|
|
53
|
+
throw new Error(`Invalid analysis range. Exceeds video duration: ${vDur}`)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
const dupFrames = await detectDuplicateFramesNums(files[0], seek, duration)
|
|
57
|
+
analyze(dupFrames, seek, duration)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function detectDuplicateFramesNums(video, seek, duration) {
|
|
61
|
+
const { stderr } = await ffmpeg([
|
|
62
|
+
'-v', 'info',
|
|
63
|
+
'-stats',
|
|
64
|
+
'-ss', seek,
|
|
65
|
+
'-t', duration,
|
|
66
|
+
'-i', video,
|
|
67
|
+
'-vf', [
|
|
68
|
+
'scale=320:-1',
|
|
69
|
+
'tblend=all_mode=difference',
|
|
70
|
+
'format=gray',
|
|
71
|
+
'showinfo',
|
|
72
|
+
].join(','),
|
|
73
|
+
'-f', 'null', '-',
|
|
74
|
+
])
|
|
75
|
+
|
|
76
|
+
const reBlackFramesNum = /n:\s*(\d+).*?mean:\[0]/
|
|
77
|
+
const dupFrames = []
|
|
78
|
+
for (const line of stderr.split('\n')) {
|
|
79
|
+
const match = line.match(reBlackFramesNum)
|
|
80
|
+
if (match)
|
|
81
|
+
dupFrames.push(Number(match[1]))
|
|
82
|
+
}
|
|
83
|
+
return dupFrames
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function analyze(dup_frames, seek, duration) {
|
|
87
|
+
const dup_distance = []
|
|
88
|
+
const histogram = {}
|
|
89
|
+
for (let i = 1; i < dup_frames.length; i++) {
|
|
90
|
+
const diff = dup_frames[i] - dup_frames[i - 1]
|
|
91
|
+
dup_distance.push(diff)
|
|
92
|
+
histogram[diff] = (histogram[diff] || 0) + 1
|
|
93
|
+
}
|
|
94
|
+
console.log({
|
|
95
|
+
analyzed_region: {
|
|
96
|
+
start: seek + 's',
|
|
97
|
+
end: (seek + duration) + 's',
|
|
98
|
+
},
|
|
99
|
+
dup_frames,
|
|
100
|
+
dup_distance,
|
|
101
|
+
histogram
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
main().catch(err => {
|
|
106
|
+
console.error(err.message || err)
|
|
107
|
+
process.exit(1)
|
|
108
|
+
})
|
package/src/dropdups.js
CHANGED
|
@@ -20,7 +20,7 @@ const PROFILE = PRORES_PROFILES.hq
|
|
|
20
20
|
const USAGE = `
|
|
21
21
|
Usage: mediasnacks dropdups [-n <bad-frame-number>] <video>
|
|
22
22
|
|
|
23
|
-
Removes duplicate frames and outputs ProRes 422 HQ.
|
|
23
|
+
Removes sequentially duplicate frames and outputs ProRes 422 HQ.
|
|
24
24
|
|
|
25
25
|
Options:
|
|
26
26
|
-n, --bad-frame-number <n> Known frame interval to drop.
|