feat: publish av-tools 0.1.0
This commit is contained in:
315
scripts/generate-fixtures.sh
Normal file
315
scripts/generate-fixtures.sh
Normal file
@@ -0,0 +1,315 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
export LC_ALL=C
|
||||
export TZ=UTC
|
||||
|
||||
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)
|
||||
project_root=$(CDPATH= cd -- "$script_dir/.." && pwd -P)
|
||||
output_dir="$project_root/tests/fixtures/generated"
|
||||
force=false
|
||||
|
||||
if [ "${1:-}" = "--force" ]; then
|
||||
force=true
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ "$#" -ne 0 ]; then
|
||||
echo "Usage: scripts/generate-fixtures.sh [--force]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
for command_name in ffmpeg ffprobe head sha256sum mktemp; do
|
||||
if ! command -v "$command_name" >/dev/null 2>&1; then
|
||||
echo "Required development command is unavailable: $command_name" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
fixture_names="
|
||||
pattern-av.mp4
|
||||
compatible-a.mp4
|
||||
compatible-b.mp4
|
||||
different-dimensions.mp4
|
||||
tone.wav
|
||||
tone.mp3
|
||||
tone.flac
|
||||
pattern.webm
|
||||
subtitle.srt
|
||||
subtitle.vtt
|
||||
subtitle.ass
|
||||
metadata.mp4
|
||||
chapters.mp4
|
||||
attached-cover.mp3
|
||||
truncated.mp4
|
||||
SHA256SUMS
|
||||
"
|
||||
|
||||
mkdir -p "$output_dir"
|
||||
if [ -L "$output_dir" ] || [ ! -d "$output_dir" ]; then
|
||||
echo "Fixture output must be a real directory: $output_dir" >&2
|
||||
exit 1
|
||||
fi
|
||||
canonical_output_dir=$(CDPATH= cd -- "$output_dir" && pwd -P)
|
||||
if [ "$canonical_output_dir" != "$project_root/tests/fixtures/generated" ]; then
|
||||
echo "Fixture output resolves outside the expected project path." >&2
|
||||
exit 1
|
||||
fi
|
||||
for fixture_name in $fixture_names; do
|
||||
fixture_path="$output_dir/$fixture_name"
|
||||
if [ -e "$fixture_path" ] && [ "$force" != true ]; then
|
||||
echo "Fixture already exists: $fixture_path" >&2
|
||||
echo "Pass --force to replace only the known generated fixture set." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$force" = true ]; then
|
||||
for fixture_name in $fixture_names; do
|
||||
rm -f -- "$output_dir/$fixture_name"
|
||||
done
|
||||
fi
|
||||
|
||||
temporary_dir=$(mktemp -d "/tmp/av-tools-fixtures.XXXXXX")
|
||||
case "$temporary_dir" in
|
||||
/tmp/av-tools-fixtures.*) ;;
|
||||
*)
|
||||
echo "Refusing unexpected temporary path: $temporary_dir" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
trap 'rm -rf -- "$temporary_dir"' EXIT HUP INT TERM
|
||||
|
||||
run_ffmpeg() {
|
||||
ffmpeg \
|
||||
-hide_banner \
|
||||
-loglevel error \
|
||||
-y \
|
||||
-fflags +bitexact \
|
||||
-filter_threads 1 \
|
||||
-filter_complex_threads 1 \
|
||||
"$@"
|
||||
}
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "testsrc2=size=160x90:rate=12" \
|
||||
-f lavfi -i "sine=frequency=440:sample_rate=16000" \
|
||||
-t 2 -shortest \
|
||||
-map 0:v:0 -map 1:a:0 \
|
||||
-c:v libx264 -preset ultrafast -crf 35 -pix_fmt yuv420p -g 12 -threads 1 \
|
||||
-c:a aac -b:a 32k -ar 16000 -ac 1 \
|
||||
-flags:v +bitexact -flags:a +bitexact \
|
||||
-metadata title="Generated AV fixture" \
|
||||
-metadata creation_time="2020-01-01T00:00:00Z" \
|
||||
-movflags +faststart \
|
||||
"$output_dir/pattern-av.mp4"
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "color=c=red:size=128x72:rate=10" \
|
||||
-f lavfi -i "sine=frequency=330:sample_rate=16000" \
|
||||
-t 1 -shortest \
|
||||
-map 0:v:0 -map 1:a:0 \
|
||||
-c:v libx264 -preset ultrafast -crf 35 -pix_fmt yuv420p -g 10 -threads 1 \
|
||||
-c:a aac -b:a 32k -ar 16000 -ac 1 \
|
||||
-flags:v +bitexact -flags:a +bitexact \
|
||||
-metadata creation_time="2020-01-01T00:00:00Z" \
|
||||
-movflags +faststart \
|
||||
"$output_dir/compatible-a.mp4"
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "color=c=blue:size=128x72:rate=10" \
|
||||
-f lavfi -i "sine=frequency=550:sample_rate=16000" \
|
||||
-t 1 -shortest \
|
||||
-map 0:v:0 -map 1:a:0 \
|
||||
-c:v libx264 -preset ultrafast -crf 35 -pix_fmt yuv420p -g 10 -threads 1 \
|
||||
-c:a aac -b:a 32k -ar 16000 -ac 1 \
|
||||
-flags:v +bitexact -flags:a +bitexact \
|
||||
-metadata creation_time="2020-01-01T00:00:00Z" \
|
||||
-movflags +faststart \
|
||||
"$output_dir/compatible-b.mp4"
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "testsrc2=size=96x96:rate=10" \
|
||||
-f lavfi -i "sine=frequency=660:sample_rate=16000" \
|
||||
-t 1 -shortest \
|
||||
-map 0:v:0 -map 1:a:0 \
|
||||
-c:v libx264 -preset ultrafast -crf 35 -pix_fmt yuv420p -g 10 -threads 1 \
|
||||
-c:a aac -b:a 32k -ar 16000 -ac 1 \
|
||||
-flags:v +bitexact -flags:a +bitexact \
|
||||
-metadata creation_time="2020-01-01T00:00:00Z" \
|
||||
-movflags +faststart \
|
||||
"$output_dir/different-dimensions.mp4"
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "sine=frequency=440:sample_rate=16000:duration=1" \
|
||||
-c:a pcm_s16le -flags:a +bitexact \
|
||||
-metadata title="Generated tone" \
|
||||
"$output_dir/tone.wav"
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "sine=frequency=440:sample_rate=16000:duration=1" \
|
||||
-c:a libmp3lame -b:a 32k -ar 16000 -ac 1 -flags:a +bitexact \
|
||||
-id3v2_version 3 -write_xing 0 \
|
||||
-metadata title="Generated tone" \
|
||||
"$output_dir/tone.mp3"
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "sine=frequency=440:sample_rate=16000:duration=1" \
|
||||
-c:a flac -compression_level 5 -flags:a +bitexact \
|
||||
-metadata title="Generated tone" \
|
||||
"$output_dir/tone.flac"
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "testsrc2=size=128x72:rate=10" \
|
||||
-f lavfi -i "sine=frequency=440:sample_rate=16000" \
|
||||
-t 1 -shortest \
|
||||
-map 0:v:0 -map 1:a:0 \
|
||||
-c:v libvpx -deadline good -cpu-used 8 -crf 50 -b:v 80k -threads 1 \
|
||||
-c:a libvorbis -b:a 32k -ar 16000 -ac 1 \
|
||||
-flags:v +bitexact -flags:a +bitexact \
|
||||
-metadata title="Generated WebM fixture" \
|
||||
-fflags +bitexact \
|
||||
"$output_dir/pattern.webm"
|
||||
|
||||
printf '%s\n' \
|
||||
'1' \
|
||||
'00:00:00,100 --> 00:00:00,700' \
|
||||
'Generated subtitle' \
|
||||
>"$output_dir/subtitle.srt"
|
||||
|
||||
printf '%s\n' \
|
||||
'WEBVTT' \
|
||||
'' \
|
||||
'00:00:00.100 --> 00:00:00.700' \
|
||||
'Generated subtitle' \
|
||||
>"$output_dir/subtitle.vtt"
|
||||
|
||||
printf '%s\n' \
|
||||
'[Script Info]' \
|
||||
'ScriptType: v4.00+' \
|
||||
'PlayResX: 128' \
|
||||
'PlayResY: 72' \
|
||||
'' \
|
||||
'[V4+ Styles]' \
|
||||
'Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding' \
|
||||
'Style: Default,sans-serif,12,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,1,0,2,8,8,8,1' \
|
||||
'' \
|
||||
'[Events]' \
|
||||
'Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text' \
|
||||
'Dialogue: 0,0:00:00.10,0:00:00.70,Default,,0,0,0,,Generated subtitle' \
|
||||
>"$output_dir/subtitle.ass"
|
||||
|
||||
run_ffmpeg \
|
||||
-i "$output_dir/compatible-a.mp4" \
|
||||
-map 0 -c copy \
|
||||
-metadata title="Metadata fixture" \
|
||||
-metadata artist="add ideas test generator" \
|
||||
-metadata comment="Local generated media" \
|
||||
-metadata creation_time="2020-01-01T00:00:00Z" \
|
||||
"$output_dir/metadata.mp4"
|
||||
|
||||
printf '%s\n' \
|
||||
';FFMETADATA1' \
|
||||
'title=Chapter fixture' \
|
||||
'[CHAPTER]' \
|
||||
'TIMEBASE=1/1000' \
|
||||
'START=0' \
|
||||
'END=500' \
|
||||
'title=First' \
|
||||
'[CHAPTER]' \
|
||||
'TIMEBASE=1/1000' \
|
||||
'START=500' \
|
||||
'END=1000' \
|
||||
'title=Second' \
|
||||
>"$temporary_dir/chapters.ffmeta"
|
||||
|
||||
run_ffmpeg \
|
||||
-i "$output_dir/compatible-b.mp4" \
|
||||
-i "$temporary_dir/chapters.ffmeta" \
|
||||
-map 0 -map_metadata 1 -map_chapters 1 -c copy \
|
||||
-metadata creation_time="2020-01-01T00:00:00Z" \
|
||||
"$output_dir/chapters.mp4"
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "color=c=yellow:size=32x32:rate=1" \
|
||||
-frames:v 1 -c:v png -threads 1 -flags:v +bitexact \
|
||||
"$temporary_dir/cover.png"
|
||||
|
||||
run_ffmpeg \
|
||||
-f lavfi -i "sine=frequency=440:sample_rate=16000:duration=1" \
|
||||
-i "$temporary_dir/cover.png" \
|
||||
-map 0:a:0 -map 1:v:0 \
|
||||
-c:a libmp3lame -b:a 32k -ar 16000 -ac 1 \
|
||||
-c:v png -threads 1 -disposition:v:0 attached_pic \
|
||||
-id3v2_version 3 -write_xing 0 \
|
||||
-metadata title="Attached cover fixture" \
|
||||
-metadata:s:v:0 title="Generated cover" \
|
||||
-metadata:s:v:0 comment="Cover (front)" \
|
||||
"$output_dir/attached-cover.mp3"
|
||||
|
||||
head -c 128 "$output_dir/compatible-a.mp4" >"$output_dir/truncated.mp4"
|
||||
|
||||
for media_name in \
|
||||
attached-cover.mp3 \
|
||||
chapters.mp4 \
|
||||
compatible-a.mp4 \
|
||||
compatible-b.mp4 \
|
||||
different-dimensions.mp4 \
|
||||
metadata.mp4 \
|
||||
pattern-av.mp4 \
|
||||
pattern.webm \
|
||||
tone.flac \
|
||||
tone.mp3 \
|
||||
tone.wav
|
||||
do
|
||||
ffprobe \
|
||||
-v error \
|
||||
-show_entries format=format_name,duration:stream=index,codec_name,codec_type \
|
||||
-of json \
|
||||
"$output_dir/$media_name" \
|
||||
>/dev/null
|
||||
done
|
||||
|
||||
truncated_streams=$(
|
||||
ffprobe \
|
||||
-v error \
|
||||
-show_entries stream=index \
|
||||
-of csv=p=0 \
|
||||
"$output_dir/truncated.mp4"
|
||||
)
|
||||
if [ -n "$truncated_streams" ]; then
|
||||
echo "Truncated fixture unexpectedly contains a usable stream." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
(
|
||||
cd "$output_dir"
|
||||
sha256sum \
|
||||
attached-cover.mp3 \
|
||||
chapters.mp4 \
|
||||
compatible-a.mp4 \
|
||||
compatible-b.mp4 \
|
||||
different-dimensions.mp4 \
|
||||
metadata.mp4 \
|
||||
pattern-av.mp4 \
|
||||
pattern.webm \
|
||||
subtitle.ass \
|
||||
subtitle.srt \
|
||||
subtitle.vtt \
|
||||
tone.flac \
|
||||
tone.mp3 \
|
||||
tone.wav \
|
||||
truncated.mp4 \
|
||||
>SHA256SUMS
|
||||
)
|
||||
|
||||
for fixture_name in $fixture_names; do
|
||||
chmod 0644 "$output_dir/$fixture_name"
|
||||
done
|
||||
|
||||
echo "Generated fixtures in $output_dir"
|
||||
ffmpeg -version | sed -n '1p'
|
||||
(
|
||||
cd "$output_dir"
|
||||
sha256sum -c SHA256SUMS
|
||||
)
|
||||
Reference in New Issue
Block a user