Отмена генерации не ошибка, длинная тишина набирается повторами

Отмену вставок просили мы сами, когда правка сделала работу ненужной, а
журнал сообщал «Не удалось подготовить вставки: Отменено» — неправда там,
где всё шло по плану. Теперь отмена докладывается как отмена и сразу
планирует пересборку предпросмотра, а не ждёт таймера.

Вчерашнее дробление дыр не дошло до звуковых дорожек: они уплощаются
отдельной функцией. Кусок тишины в три минуты ссылался на минутный файл, и
плеер жаловался «uses 192.5 seconds, but file has only 60». Теперь длинная
тишина набирается повторами, а одинаковые файлы не заказываются дважды.

Проверено живьём на материале 2688x1512: отмена ловится, обе строки в
журнале верные, предупреждений о коротких файлах ноль. Проверка 15 в
flattest следит за дроблением тишины.
This commit is contained in:
4aiman 2026-09-12 00:51:19 +03:00
commit 00af5e1eec
4 changed files with 88 additions and 26 deletions

View file

@ -119,15 +119,6 @@ NVENC, если он есть). Это разрозненно и не даёт
неподъёмным. Пока цифры замеряны только на одной машине, у человека
должна быть возможность выключить любую из этих трат.
## Отмена ненужной генерации не проверена живьём
Правка монтажа прекращает создание вставок, ставших ненужными, — код на
месте и вызывается на каждой пересборке предпросмотра. Но поймать отмену
глазами не на чем: на мелком проверочном материале минутная чёрная
вставка делается мгновенно. Нужен прогон на настоящем материале в
2688x1512: завести дыру, дождаться начала генерации, закрыть дыру и
убедиться по журналу, что ffmpeg остановлен.
## Мелочи, до которых не дошли руки
**Вид дорожки не виден в её заголовке.** Дорожки картинки, звука и текста

View file

@ -1043,28 +1043,54 @@ var
Req: TGenRequest;
Path: string;
{ Уже заказан ли такой файл. }
function Requested(const APath: string): Boolean;
var
K: Integer;
begin
Result := False;
for K := 0 to High(AMissing) do
if AMissing[K].TargetPath = APath then
Exit(True);
end;
{ Кусок тишины. Длинный набирается повторами минутного файла — как и
чёрные вставки: готовых длин всего две, и просить у минутного файла
три минуты нельзя, плеер на это ругается, а звук обрывается. }
procedure PushSilence(const ALen: Double);
var
Left, Take: Double;
begin
if ALen <= 0.0005 then
Exit;
Seg := Default(TFlatSegment);
Seg.Volume := 1;
Seg.Kind := skBlack;
Seg.Duration := ALen;
{ Тишина без картинки: см. пояснение у gkSilence. }
Req.Kind := gkSilence;
Req.SourcePath := '';
Req.Duration := BucketFor(ALen);
Req.TargetPath := GeneratedPath(AProject.CacheDir, Req);
Seg.FilePath := Req.TargetPath;
if not FileExists(Req.TargetPath) then
Left := ALen;
while Left > 0.0005 do
begin
SetLength(AMissing, Length(AMissing) + 1);
AMissing[High(AMissing)] := Req;
Take := Min(MaxInsertLength, Left);
Seg := Default(TFlatSegment);
Seg.Volume := 1;
Seg.Kind := skBlack;
Seg.Duration := Take;
{ Тишина без картинки: см. пояснение у gkSilence. }
Req.Kind := gkSilence;
Req.SourcePath := '';
Req.Duration := BucketFor(Take);
Req.TargetPath := GeneratedPath(AProject.CacheDir, Req);
Seg.FilePath := Req.TargetPath;
{ Один и тот же файл не заказываем дважды: длинная тишина набирается
повторами, и без этой проверки минутный кусок делался бы столько
раз, сколько его повторов. }
if (not FileExists(Req.TargetPath)) and (not Requested(Req.TargetPath)) then
begin
SetLength(AMissing, Length(AMissing) + 1);
AMissing[High(AMissing)] := Req;
end;
SetLength(ASegments, N + 1);
ASegments[N] := Seg;
Inc(N);
Left := Left - Take;
end;
SetLength(ASegments, N + 1);
ASegments[N] := Seg;
Inc(N);
end;
begin

View file

@ -3098,14 +3098,26 @@ end;
procedure TMainForm.GenerateDone(Sender: TObject);
var
Ok: Boolean;
Ok, WasCancelled: Boolean;
Msg: string;
begin
Ok := FGenerate.Succeeded;
WasCancelled := FGenerate.Cancelled;
Msg := FGenerate.Message;
FGenerate := nil;
FGenerateBusy := False;
{ Отмену просили мы сами, когда правка сделала работу ненужной. Это не
беда, и говорить «не удалось» тут нельзя: в журнале появлялась строка
об ошибке там, где всё шло по плану. Пересобираем предпросмотр по
свежей расстановке. }
if WasCancelled then
begin
Log('Подготовка вставок прекращена: расстановка изменилась.');
SchedulePreview;
Exit;
end;
if not Ok then
begin
Log('Не удалось подготовить вставки: ' + Msg);

View file

@ -971,6 +971,39 @@ begin
end;
WriteLn;
{ --- 15. Длинная тишина тоже набирается повторами --- }
WriteLn(' 15. Дыра на звуковой дорожке');
Proj := MakeProject(1, Media);
try
Proj.Master := Media.Info;
Proj.EnsureAudioTracks;
{ Два звуковых клипа с промежутком в семьдесят секунд: он разложится
на минуту и десять секунд, то есть на два разных файла. }
Clip := Proj.AddClip(Proj.Tracks[1], Media, 0, 5, 0);
Clip.Kind := ckAudio;
Clip := Proj.AddClip(Proj.Tracks[1], Media, 10, 5, 75);
Clip.Kind := ckAudio;
FlattenAudioTrack(Proj, Proj.Tracks[1], 80, Segs, Missing);
DumpSegments(Segs);
N := 0;
for I := 0 to High(Segs) do
if Segs[I].Kind = skBlack then
begin
Inc(N);
Check(Segs[I].Duration <= 60.0005,
'кусок тишины не длиннее минуты: ' + SecondsToStr(Segs[I].Duration));
end;
Check(N = 2, 'тишина разложена на два куска: ' + IntToStr(N));
Check(Length(Missing) = 2,
'заказаны две длины, минутная и пятнадцатисекундная: ' +
IntToStr(Length(Missing)));
finally
Proj.Free;
end;
WriteLn;
WriteLn;
if FailCount = 0 then
begin