Починка проекта: клипы на кадровую сетку, пункт в меню

Меню «Проект» → «Проверить и починить проект...». Показывает найденное и
чинит только по согласию, отменяется через Ctrl+Z.

Ищутся клипы мимо кадровой сетки, клипы на дорожках чужого вида и
повторяющиеся имена дорожек. Первое — наследство: в старых проектах
времена записаны как попало (2.457599 с при 59.94 к/с — это 147.31 кадра),
и пока монтаж просит доли кадра, предпросмотр и сборка округляют их
каждый по-своему. Сдвиг при починке не больше полкадра.

Края отмеченного участка при сборке тоже кладутся на сетку: подрезка
возвращала в крайние куски доли кадра, которые уплощение только что
убрало.

Проверено на копии настоящего проекта: 82 клипа, после починки мимо сетки
ни одного, клипы остались встык, общая длина изменилась на 0.028 с за два
часа; Ctrl+Z возвращает как было. Плюс проверка в lfmcheck, включая клип
короче кадра — он не должен схлопнуться в ничто.
This commit is contained in:
4aiman 2026-09-16 20:39:33 +03:00
commit 37787ce96c
4 changed files with 311 additions and 0 deletions

View file

@ -564,6 +564,73 @@ begin
end;
end;
{ Починка проекта: клипы на кадровую сетку.
Между кадрами времени нет, и монтаж не должен хранить доли кадра:
картинка выйдет целым числом кадров, звук наберётся до отсчёта, и
округление разведёт их. Правка двигает клип не больше чем на полкадра,
но сама сетка обязана получиться ровной. }
procedure CheckFrameGridRepair;
var
Proj: TProject;
Info: TMediaInfo;
Media: TMediaItem;
Step: Double;
I: Integer;
Clip: TClip;
OnGrid: Boolean;
begin
WriteLn;
WriteLn('Починка: клипы на кадровую сетку');
WriteLn;
Info := TestInfo;
{ 59.94 к/с — та самая сетка, на которой доли кадра особенно заметны. }
Info.FpsNum := 60000;
Info.FpsDen := 1001;
Proj := TProject.Create;
try
Proj.Clear;
Proj.AddTrack('V1');
Media := Proj.AddMedia('/несуществующий/видео.mp4', Info);
Proj.Master := Info;
Step := Info.FpsDen / Info.FpsNum;
{ Времена как в настоящем проекте: ни одно не попадает на кадр. }
Proj.AddClip(Proj.Tracks[0], Media, 48.558521, 2.457599, 0);
Proj.AddClip(Proj.Tracks[0], Media, 56.054198, 1.469934, 2.457599);
{ И клип короче кадра: его нельзя схлопнуть в ничто. }
Proj.AddClip(Proj.Tracks[0], Media, 62.710196, 0.004, 3.927533);
CheckTrue('все три клипа мимо сетки', Proj.OffGridClipCount = 3);
CheckTrue('починка подвинула три клипа', Proj.SnapClipsToFrameGrid = 3);
CheckTrue('мимо сетки не осталось', Proj.OffGridClipCount = 0);
OnGrid := True;
for I := 0 to Proj.Tracks[0].Count - 1 do
begin
Clip := Proj.Tracks[0][I];
if Abs(Clip.TlStart / Step - Round(Clip.TlStart / Step)) > 0.001 then
OnGrid := False;
if Abs(Clip.Duration / Step - Round(Clip.Duration / Step)) > 0.001 then
OnGrid := False;
if Abs(Clip.SrcIn / Step - Round(Clip.SrcIn / Step)) > 0.001 then
OnGrid := False;
end;
CheckTrue('начала, длины и точки входа — целые кадры', OnGrid);
CheckTrue('короткий клип остался длиной в кадр',
Abs(Proj.Tracks[0][2].Duration - Step) < 0.0001);
CheckTrue('клипы не разъехались больше чем на полкадра',
Abs(Proj.Tracks[0][0].TlStart - 0) < Step);
CheckTrue('повторная починка ничего не двигает',
Proj.SnapClipsToFrameGrid = 0);
finally
Proj.Free;
end;
end;
begin
WriteLn('Свойства из файлов форм');
WriteLn;
@ -595,6 +662,7 @@ begin
CheckRippleWithoutMouse;
CheckClipCopy;
CheckRubberBand;
CheckFrameGridRepair;
CheckSplitAllTracks;
CheckGapTolerance;