ffmpeg-skill 3.8.7 → 3.8.9
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/README.md +1 -1
- package/docs/contract.md +15 -4
- package/package.json +1 -1
- package/references/gotchas.md +5 -3
- package/references/scripts.md +69 -17
- package/scripts/_common/asr.py +12 -1
- package/scripts/_common/drawtext.py +11 -0
- package/scripts/_common/emit.py +3 -1
- package/scripts/_common/emoji.py +28 -5
- package/scripts/_common/probe.py +27 -7
- package/scripts/_common/runner.py +146 -5
- package/scripts/_common/timeline.py +45 -12
- package/scripts/_contract.py +19 -11
- package/scripts/batch.py +91 -8
- package/scripts/caption.py +39 -3
- package/scripts/color.py +36 -0
- package/scripts/cropdetect.py +24 -6
- package/scripts/cut.py +13 -5
- package/scripts/export.py +3 -2
- package/scripts/graphics.py +31 -12
- package/scripts/join.py +20 -2
- package/scripts/loudness.py +2 -1
- package/scripts/metadata.py +15 -1
- package/scripts/overlay.py +11 -6
- package/scripts/probe.py +8 -0
- package/scripts/render.py +232 -39
- package/scripts/report.py +27 -1
- package/scripts/sequence.py +5 -1
- package/scripts/silence.py +27 -3
- package/scripts/stabilize.py +6 -2
- package/scripts/sync.py +8 -3
- package/scripts/waveform.py +13 -6
- package/templates/audiogram.json +9 -0
package/scripts/sync.py
CHANGED
|
@@ -33,7 +33,7 @@ import sys
|
|
|
33
33
|
from typing import Dict, List
|
|
34
34
|
|
|
35
35
|
from _common.runner import fail_if_classified
|
|
36
|
-
from _common import video_args, add_common, apply_common, emit, aac_args, audio_codec_for, default_output, die, ffmpeg_base, info, probe, require_tool, run, run_analysis, x264_args, decode_pcm_mono, rms_envelope
|
|
36
|
+
from _common import STATE, video_args, add_common, apply_common, emit, aac_args, audio_codec_for, default_output, die, ffmpeg_base, info, probe, require_tool, run, run_analysis, x264_args, decode_pcm_mono, rms_envelope
|
|
37
37
|
from _common.emit import record_skip, warn
|
|
38
38
|
from _common.decision import SEEK_MARGIN, frame_rate, grid_at_or_after, length_output_t, silence_filter, stream_starts
|
|
39
39
|
from _common.timeline import output_timecode_args
|
|
@@ -259,8 +259,13 @@ def measure_one(reference: str, path: str, args) -> Dict:
|
|
|
259
259
|
offset = offset + (drift_ratio - 1.0) * head_mid
|
|
260
260
|
drift_info = {"residual_at_end_seconds": round(residual, 4), "measured_over_seconds": round(elapsed, 2),
|
|
261
261
|
"drift_ppm": round((drift_ratio - 1) * 1e6, 1),
|
|
262
|
-
|
|
263
|
-
|
|
262
|
+
# a measure-only run writes nothing (#403: it said "will be resampled")
|
|
263
|
+
"meaning": "second file runs %.1f ppm %s (%.3fs over %.0fs); %s" % (
|
|
264
|
+
abs(drift_ratio - 1) * 1e6, "long/slow" if drift_ratio > 1 else "short/fast", abs(residual), elapsed,
|
|
265
|
+
("it would be resampled to match in the file this run plans (--dry-run writes nothing)" if STATE.dry_run
|
|
266
|
+
else "it is resampled to match in the file this run writes")
|
|
267
|
+
if args.replace_audio or args.trim_second else
|
|
268
|
+
"nothing is resampled in this measure-only run (--replace-audio or --trim-second writes the corrected file)"),
|
|
264
269
|
"confidence": round(end_score, 3)}
|
|
265
270
|
else:
|
|
266
271
|
skipped_reason = "low_confidence"
|
package/scripts/waveform.py
CHANGED
|
@@ -36,7 +36,7 @@ import os
|
|
|
36
36
|
import sys
|
|
37
37
|
|
|
38
38
|
from _platforms import PLATFORMS, PLATFORM_CHOICES, resolve as resolve_platform
|
|
39
|
-
from _common.probe import SILENT_PEAK_DBFS, square_pixels, square_pixels_note
|
|
39
|
+
from _common.probe import SILENT_PEAK_DBFS, refuse_not_a_still, square_pixels, square_pixels_note
|
|
40
40
|
from _common import still_input_args # noqa: E402
|
|
41
41
|
from _common import (add_common, apply_common, aac_args, default_output, die, draws_chroma, emit, ffmpeg_base,
|
|
42
42
|
info, load_brand, pad_filters, probe, rgb_chain_to_bt709, run, STATE, validate_color, video_args, X264_PRESETS,
|
|
@@ -119,10 +119,13 @@ def main() -> int:
|
|
|
119
119
|
"the image locally and pass its path", kind="input")
|
|
120
120
|
if not os.path.exists(args.image):
|
|
121
121
|
die(f"--image file not found: {args.image}", kind="input")
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
# read under --dry-run too (the file exists, checked above): a plate the real run refuses
|
|
123
|
+
# is refused by the plan (#404: a dry run completed on a video given as --image)
|
|
124
|
+
plate = probe(args.image, role="input")
|
|
125
|
+
if not (plate.get("video") or {}).get("width"):
|
|
126
|
+
die(f"--image is not an image ffmpeg can decode: {args.image}", kind="input")
|
|
127
|
+
refuse_not_a_still(args.image, plate, "--image",
|
|
128
|
+
"`look.py FILE --at T` writes one frame of a video as a PNG")
|
|
126
129
|
if args.background != "black":
|
|
127
130
|
die("--image and a non-default --background exclude each other: the plate is either "
|
|
128
131
|
"the picture or the colour", kind="input")
|
|
@@ -375,8 +378,12 @@ def _child(script_name: str, argv: "list") -> None:
|
|
|
375
378
|
extra = {"hint": err["hint"]} if err.get("hint") else {}
|
|
376
379
|
if doc.get("encoder"):
|
|
377
380
|
extra["encoder"] = doc["encoder"]
|
|
381
|
+
# the stage's own reason and details ride along (#402: a caller keyed on error.reason saw
|
|
382
|
+
# filter_missing from caption.py and graphics.py run by hand, and nothing from here)
|
|
383
|
+
why = {k: err[k] for k in ("reason", "details") if err.get(k) is not None}
|
|
378
384
|
die(f"{script_name} failed: {err.get('message') or (proc.stderr.strip().splitlines() or ['?'])[-1][:300]}",
|
|
379
|
-
code=int(doc.get("exit_code") or 1), kind=err.get("kind") or "input", stage=script_name,
|
|
385
|
+
code=int(doc.get("exit_code") or 1), kind=err.get("kind") or "input", stage=script_name,
|
|
386
|
+
error_extra=why or None, **extra)
|
|
380
387
|
|
|
381
388
|
if __name__ == "__main__":
|
|
382
389
|
sys.exit(main())
|
package/templates/audiogram.json
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"src": "$INPUT"
|
|
7
7
|
}
|
|
8
8
|
],
|
|
9
|
+
"brand": "$BRAND",
|
|
9
10
|
"audiogram": {
|
|
10
11
|
"image": "$IMAGE",
|
|
11
12
|
"style": "waveform",
|
|
@@ -17,6 +18,14 @@
|
|
|
17
18
|
"position": "bottom",
|
|
18
19
|
"margin": 14
|
|
19
20
|
},
|
|
21
|
+
"graphics": [
|
|
22
|
+
{
|
|
23
|
+
"template": "lower-third",
|
|
24
|
+
"name": "$TITLE",
|
|
25
|
+
"start": 1,
|
|
26
|
+
"end": 6
|
|
27
|
+
}
|
|
28
|
+
],
|
|
20
29
|
"loudness": {
|
|
21
30
|
"lufs": -14,
|
|
22
31
|
"tp": -1
|