Три жалобы из настоящей работы над фильмом, и все про одно: положить кусок туда, куда нужно, было нельзя. Файл из списка падал в конец дорожки, стоило месту под ним оказаться занятым, — а занято оно почти всегда: клип длиной в целый файл упирается хвостом в то, что правее, даже когда начало легло в пустоту. Теперь монтаж раздвигается: MakeRoomAt режет все дорожки в точке вставки и сдвигает всё, что начинается с неё и правее, на длину нового клипа. Звук и надписи едут вместе с картинкой, иначе синхрон рассыплется. Точка вставки при этом округляется к кадровой сетке. Без этого вставка давала наезд в пять миллисекунд: рез внутри раздвижки округляет время сам, а клип клался на неокруглённый курсор. Отсюда и был «кроссфейд без видимого перекрытия». При перетаскивании у кромки окна монтаж прокручивается сам: иначе при большом увеличении кусок упирается в край, и переносить его приходится в несколько приёмов. Прилипание заодно считается и по концу клипа — иначе клип встаёт началом в дыру, а хвостом на соседа, и это снова наезд. Тяжёлая сборка больше не начинается с первым движением: список кусков пересобирается сразу, а ffmpeg запускается, когда монтаж постоял тихо полторы секунды и клип никто не держит мышью. Сам наезд перестал быть сюрпризом — строка состояния называет дорожку, величину и клипы. Проверки числами: раздвижка монтажа и прилипание хвостом. С окном: insertat.sh, dragscroll.sh, genquiet.sh. Все три прогнаны и на прежней сборке, где падают: клип в конце дорожки вместо курсора, 0.667 с вместо 4.238 с, сборка через 0.20 с вместо 1.62 с.
117 lines
5 KiB
Bash
Executable file
117 lines
5 KiB
Bash
Executable file
#!/bin/sh
|
||
# Тяжёлая сборка начинается не сразу, а когда правка закончилась.
|
||
#
|
||
# Наезд двух клипов на одной дорожке — это заказ на переход, и считается
|
||
# он минутами. Пока человек подбирает место, заказ меняется каждым
|
||
# движением руки, и начатая работа уходит в корзину. Поэтому список
|
||
# кусков пересобирается сразу (монтаж обязан показывать правду), а вот
|
||
# ffmpeg запускается, когда монтаж постоял тихо.
|
||
#
|
||
# Проверяется так: клип тащится на соседа, создавая наезд. С момента,
|
||
# когда кнопку отпустили, считается время до первой команды ffmpeg в
|
||
# журнале. Оно обязано быть близко к заданной тишине, но работа всё-таки
|
||
# обязана начаться — отложить не значит забыть.
|
||
#
|
||
# Журнал только читается: усечь его значит снести запись чужой работы.
|
||
#
|
||
# Запуск (экран :99 поднят):
|
||
# tests/genquiet.sh [<путь к nlve>]
|
||
set -e
|
||
cd "$(dirname "$0")/.."
|
||
BIN=${1:-$PWD/nlve}
|
||
DISP=${NLVE_DISPLAY:-:99}
|
||
SRC=$PWD/test/поток/пара.nlve
|
||
PROJ=$PWD/test/поток/тишина.nlve
|
||
LOG=$(dirname "$BIN")/nlve.log
|
||
|
||
[ -f "$SRC" ] || { echo "нет монтажа $SRC"; exit 2; }
|
||
|
||
export DISPLAY=$DISP
|
||
reachable() { timeout 5 xdotool getdisplaygeometry >/dev/null 2>&1; }
|
||
if ! reachable; then
|
||
for p in $(pgrep -x Xvfb); do
|
||
A=$(tr '\0' '\n' < /proc/$p/cmdline | grep -A1 -x -- -auth | tail -1)
|
||
[ -f "$A" ] || continue
|
||
XAUTHORITY=$A; export XAUTHORITY
|
||
reachable && break
|
||
done
|
||
fi
|
||
reachable ||
|
||
{ echo "нет доступа к экрану $DISP: подними его (xvfb-run) и повтори"; exit 2; }
|
||
|
||
cp "$SRC" "$PROJ"
|
||
for p in $(pgrep -x nlve); do
|
||
tr '\0' '\n' < /proc/$p/environ 2>/dev/null | grep -qx "DISPLAY=$DISP" && kill $p
|
||
done
|
||
sleep 1
|
||
SP=$PWD/test/поток/профиль-тишина
|
||
rm -rf "$SP"; mkdir -p "$SP"
|
||
rm -rf "$PROJ-cache"
|
||
rm -f "$PROJ.autosave"
|
||
XDG_CONFIG_HOME=$SP XDG_CACHE_HOME=$SP XDG_DATA_HOME=$SP \
|
||
setsid "$BIN" "$PROJ" >/dev/null 2>&1 < /dev/null &
|
||
sleep 14
|
||
|
||
X="timeout 8 xdotool"
|
||
WID=
|
||
for w in $($X search --name "тишина.nlve" 2>/dev/null); do
|
||
xwininfo -id "$w" 2>/dev/null | grep -q IsViewable && { WID=$w; break; }
|
||
done
|
||
[ -n "$WID" ] || { echo "живое окно редактора не найдено"; exit 2; }
|
||
$X windowmove "$WID" 0 0 windowsize "$WID" 1270 990
|
||
sleep 3
|
||
|
||
ROW=${NLVE_ROW:-505}
|
||
# Сколько команд ffmpeg в журнале сейчас. Считаем строки, а не чистим
|
||
# файл: журнал общий, и усечение уносит чужую работу.
|
||
runs() { grep -c '^> .*ffmpeg' "$LOG" 2>/dev/null || echo 0; }
|
||
|
||
BEFORE=$(runs)
|
||
echo " команд в журнале до правки: $BEFORE"
|
||
|
||
# Тащим первый клип вправо на соседа: наезд примерно в секунду.
|
||
$X mousemove 650 $ROW mousedown 1
|
||
sleep 0.3
|
||
$X mousemove 670 $ROW
|
||
sleep 0.3
|
||
$X mousemove 683 $ROW
|
||
sleep 0.3
|
||
$X mouseup 1
|
||
|
||
# С этой точки отсчёт. Опрашиваем журнал почаще, чтобы поймать момент
|
||
# запуска, а не ждать наугад.
|
||
T0=$(date +%s.%N)
|
||
WAITED=0
|
||
while [ "$WAITED" -lt 60 ]; do
|
||
N=$(runs)
|
||
[ "$N" -gt "$BEFORE" ] && break
|
||
sleep 0.2
|
||
WAITED=$((WAITED + 1))
|
||
done
|
||
T1=$(date +%s.%N)
|
||
AFTER=$(runs)
|
||
|
||
for p in $(pgrep -x nlve); do
|
||
tr '\0' '\n' < /proc/$p/environ 2>/dev/null | grep -qx "DISPLAY=$DISP" && kill $p
|
||
done
|
||
pkill -f "тишина.nlve-cache" 2>/dev/null || true
|
||
rm -f "$PROJ.autosave"
|
||
|
||
python3 -c "
|
||
задержка = $T1 - $T0
|
||
было, стало = $BEFORE, $AFTER
|
||
print(' команд после правки: %d, пауза до запуска: %.2f с' % (стало, задержка))
|
||
if стало <= было:
|
||
print(' ПЛОХО: сборка не началась вовсе — отложить не значит забыть')
|
||
raise SystemExit(1)
|
||
# Задано полторы секунды тишины. Нижняя граница с запасом на разброс
|
||
# опроса, верхняя — чтобы отложенное не превратилось в забытое.
|
||
if задержка < 1.2:
|
||
print(' ПЛОХО: сборка началась через %.2f с — правку не дождались'
|
||
% задержка)
|
||
raise SystemExit(1)
|
||
if задержка > 6:
|
||
print(' ПЛОХО: сборка началась только через %.2f с' % задержка)
|
||
raise SystemExit(1)
|
||
print(' ok: сборка дождалась конца правки и всё-таки началась')
|
||
"
|