Рез больше не теряет настройки клипа
После разреза хвост оставался без цветового ключа: перенос настроек был написан перечислением полей, а ключ появился позже и в перечень не попал. Хвост переставал быть наложением, становился обычным победителем и закрывал собой всё, что ниже — вместо компаса в углу окно показывало пурпурную плашку во весь кадр. Перечисление заменено на CopySettingsFrom: одно место, где сказано, что переносится при копировании клипа, а что делает клип этим клипом. Иначе та же ловушка досталась бы следующему свойству. Проверка в lfmcheck: рез клипа с ключом, прозрачностью, громкостью и кадрированием — всё остаётся у обеих половин, связки у них разные и непустые. Проекты, разрезанные прежней сборкой, правка задним числом не чинит: у хвоста ключ надо включить заново.
This commit is contained in:
parent
d098f1621e
commit
5bd4e822d9
3 changed files with 130 additions and 9 deletions
|
|
@ -143,6 +143,19 @@ type
|
||||||
FColorKey: TColorKey;
|
FColorKey: TColorKey;
|
||||||
public
|
public
|
||||||
constructor Create;
|
constructor Create;
|
||||||
|
{ Переносит на этот клип всё, что настроено у другого: громкость,
|
||||||
|
кадрирование, прозрачность, ключ, затухания, текст.
|
||||||
|
|
||||||
|
Не переносится то, что делает клип этим клипом: имя, место на
|
||||||
|
монтаже, кусок исходника, связка и выделение.
|
||||||
|
|
||||||
|
Зачем метод, а не переписывание полей на месте: копия клипа нужна в
|
||||||
|
нескольких местах (рез — самое частое), и каждое новое свойство
|
||||||
|
иначе приходится вспоминать в каждом из них. Один раз не вспомнили —
|
||||||
|
и после реза половина клипа теряла цветовой ключ, а вместе с ним и
|
||||||
|
прозрачность: она переставала быть наложением и закрывала собой всё,
|
||||||
|
что ниже. }
|
||||||
|
procedure CopySettingsFrom(ASource: TClip);
|
||||||
function TlEnd: Double;
|
function TlEnd: Double;
|
||||||
function SrcOut: Double;
|
function SrcOut: Double;
|
||||||
{ Попадает ли момент внутрь клипа. Правый край не включается: там уже
|
{ Попадает ли момент внутрь клипа. Правый край не включается: там уже
|
||||||
|
|
@ -402,6 +415,21 @@ end;
|
||||||
|
|
||||||
{ --- TClip --- }
|
{ --- TClip --- }
|
||||||
|
|
||||||
|
procedure TClip.CopySettingsFrom(ASource: TClip);
|
||||||
|
begin
|
||||||
|
if ASource = nil then
|
||||||
|
Exit;
|
||||||
|
FKind := ASource.Kind;
|
||||||
|
FVolume := ASource.Volume;
|
||||||
|
FTransform := ASource.Transform;
|
||||||
|
FOpacity := ASource.Opacity;
|
||||||
|
FColorKey := ASource.ColorKey;
|
||||||
|
FFadeIn := ASource.FadeIn;
|
||||||
|
FFadeOut := ASource.FadeOut;
|
||||||
|
FText := ASource.Text;
|
||||||
|
FTextStyle := ASource.TextStyle;
|
||||||
|
end;
|
||||||
|
|
||||||
constructor TClip.Create;
|
constructor TClip.Create;
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
inherited Create;
|
||||||
|
|
|
||||||
|
|
@ -2232,19 +2232,17 @@ begin
|
||||||
Tail := TClip.Create;
|
Tail := TClip.Create;
|
||||||
Tail.Id := Clip.Id + '_b';
|
Tail.Id := Clip.Id + '_b';
|
||||||
Tail.MediaId := Clip.MediaId;
|
Tail.MediaId := Clip.MediaId;
|
||||||
Tail.Kind := Clip.Kind;
|
|
||||||
Tail.SrcIn := Clip.SrcIn + Offset;
|
Tail.SrcIn := Clip.SrcIn + Offset;
|
||||||
Tail.TlStart := FPlayhead;
|
Tail.TlStart := FPlayhead;
|
||||||
Tail.Duration := Clip.Duration - Offset;
|
Tail.Duration := Clip.Duration - Offset;
|
||||||
Tail.EdgeOut := Clip.EdgeOut;
|
Tail.EdgeOut := Clip.EdgeOut;
|
||||||
{ Хвост — тот же клип, только вторая его половина. Всё, что было
|
{ Хвост — тот же клип, только вторая его половина. Всё настроенное
|
||||||
настроено, должно перейти к нему: иначе после реза половина клипа
|
переходит к нему одним махом: перечислять поля по одному значит
|
||||||
теряет громкость и кадрирование. }
|
однажды забыть новое. }
|
||||||
Tail.Volume := Clip.Volume;
|
Tail.CopySettingsFrom(Clip);
|
||||||
Tail.Opacity := Clip.Opacity;
|
{ Кроме появления: оно относится к началу клипа, а начало осталось у
|
||||||
|
первой половины. }
|
||||||
Tail.FadeIn := 0;
|
Tail.FadeIn := 0;
|
||||||
Tail.FadeOut := Clip.FadeOut;
|
|
||||||
Tail.Transform := Clip.Transform;
|
|
||||||
|
|
||||||
{ Связка хвоста — новая.
|
{ Связка хвоста — новая.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ uses
|
||||||
{ Interfaces нужен, чтобы связалась вся LCL и заработала загрузка
|
{ Interfaces нужен, чтобы связалась вся LCL и заработала загрузка
|
||||||
файлов форм. }
|
файлов форм. }
|
||||||
Interfaces, Forms, Classes, SysUtils, Math, TypInfo, uTheme,
|
Interfaces, Forms, Classes, SysUtils, Math, TypInfo, uTheme,
|
||||||
uMediaProbe, uProject, uTimelineCtrl,
|
uMediaProbe, uProject, uTransform, uTimelineCtrl,
|
||||||
uPanCropForm, uDepsForm, uMismatchForm, uProgressForm, uProjectInfoForm,
|
uPanCropForm, uDepsForm, uMismatchForm, uProgressForm, uProjectInfoForm,
|
||||||
uRemuxForm;
|
uRemuxForm;
|
||||||
|
|
||||||
|
|
@ -153,6 +153,100 @@ begin
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ Рез не должен терять настройки клипа.
|
||||||
|
|
||||||
|
Половина клипа после реза — тот же клип, и цветовой ключ, кадрирование,
|
||||||
|
прозрачность, громкость и текст должны остаться при обеих половинах.
|
||||||
|
Однажды не остались: у хвоста пропадал ключ, клип переставал быть
|
||||||
|
наложением и закрывал собой всё, что под ним. }
|
||||||
|
procedure CheckSplitKeepsSettings;
|
||||||
|
var
|
||||||
|
Proj: TProject;
|
||||||
|
Info: TMediaInfo;
|
||||||
|
Media: TMediaItem;
|
||||||
|
Timeline: TTimelineControl;
|
||||||
|
Head, Tail, Cl: TClip;
|
||||||
|
Key: TColorKey;
|
||||||
|
Tr: TMediaTransform;
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
WriteLn;
|
||||||
|
WriteLn('Рез сохраняет настройки клипа');
|
||||||
|
WriteLn;
|
||||||
|
|
||||||
|
Info := Default(TMediaInfo);
|
||||||
|
Info.Valid := True;
|
||||||
|
Info.Kind := mkVideo;
|
||||||
|
Info.Duration := 600;
|
||||||
|
Info.HasVideo := True;
|
||||||
|
Info.VideoCodec := 'hevc';
|
||||||
|
Info.Width := 1920;
|
||||||
|
Info.Height := 1080;
|
||||||
|
Info.FpsNum := 30;
|
||||||
|
Info.FpsDen := 1;
|
||||||
|
Info.PixFmt := 'yuv420p';
|
||||||
|
|
||||||
|
Proj := TProject.Create;
|
||||||
|
Timeline := TTimelineControl.Create(nil);
|
||||||
|
try
|
||||||
|
Proj.Clear;
|
||||||
|
Proj.AddTrack('V1');
|
||||||
|
Media := Proj.AddMedia('/несуществующий/видео.mp4', Info);
|
||||||
|
Cl := Proj.AddClip(Proj.Tracks[0], Media, 0, 10, 0);
|
||||||
|
|
||||||
|
Key := DefaultColorKey;
|
||||||
|
Key.Enabled := True;
|
||||||
|
Key.Similarity := 22;
|
||||||
|
Cl.ColorKey := Key;
|
||||||
|
Cl.Opacity := 0.5;
|
||||||
|
Cl.Volume := 0.3;
|
||||||
|
Tr := Cl.Transform;
|
||||||
|
Tr.Zoom := 0.4;
|
||||||
|
Tr.OffsetX := 0.7;
|
||||||
|
Cl.Transform := Tr;
|
||||||
|
Cl.GroupId := 'g1';
|
||||||
|
|
||||||
|
Timeline.Project := Proj;
|
||||||
|
Timeline.PixelsPerSecond := 100;
|
||||||
|
Timeline.Playhead := 4;
|
||||||
|
Timeline.SplitAtPlayhead(False, False);
|
||||||
|
|
||||||
|
CheckTrue('клипов стало два', Proj.Tracks[0].Count = 2);
|
||||||
|
if Proj.Tracks[0].Count <> 2 then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
Head := nil;
|
||||||
|
Tail := nil;
|
||||||
|
for I := 0 to Proj.Tracks[0].Count - 1 do
|
||||||
|
if Proj.Tracks[0][I].TlStart < 0.001 then
|
||||||
|
Head := Proj.Tracks[0][I]
|
||||||
|
else
|
||||||
|
Tail := Proj.Tracks[0][I];
|
||||||
|
CheckTrue('обе половины нашлись', (Head <> nil) and (Tail <> nil));
|
||||||
|
if (Head = nil) or (Tail = nil) then
|
||||||
|
Exit;
|
||||||
|
|
||||||
|
CheckTrue('ключ остался у хвоста', Tail.ColorKey.Enabled);
|
||||||
|
CheckTrue('и с тем же цветом', Tail.ColorKey.Color = Key.Color);
|
||||||
|
CheckTrue('и с тем же допуском', Tail.ColorKey.Similarity = 22);
|
||||||
|
CheckTrue('прозрачность осталась', Abs(Tail.Opacity - 0.5) < 0.001);
|
||||||
|
CheckTrue('громкость осталась', Abs(Tail.Volume - 0.3) < 0.001);
|
||||||
|
CheckTrue('кадрирование осталось',
|
||||||
|
(Abs(Tail.Transform.Zoom - 0.4) < 0.001) and
|
||||||
|
(Abs(Tail.Transform.OffsetX - 0.7) < 0.001));
|
||||||
|
CheckTrue('ключ остался и у головы', Head.ColorKey.Enabled);
|
||||||
|
{ Связки разные, и обе не пустые: иначе удаление одной половины
|
||||||
|
уносило бы вторую. }
|
||||||
|
CheckTrue('связка у половин разная и не пустая',
|
||||||
|
(Head.GroupId <> Tail.GroupId) and (Head.GroupId <> '') and
|
||||||
|
(Tail.GroupId <> ''));
|
||||||
|
CheckTrue('появление у хвоста снято', Abs(Tail.FadeIn) < 0.001);
|
||||||
|
finally
|
||||||
|
Timeline.Free;
|
||||||
|
Proj.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
WriteLn('Свойства из файлов форм');
|
WriteLn('Свойства из файлов форм');
|
||||||
WriteLn;
|
WriteLn;
|
||||||
|
|
@ -180,6 +274,7 @@ begin
|
||||||
CheckForm(TRemuxForm);
|
CheckForm(TRemuxForm);
|
||||||
|
|
||||||
CheckPlayheadSnap;
|
CheckPlayheadSnap;
|
||||||
|
CheckSplitKeepsSettings;
|
||||||
|
|
||||||
WriteLn;
|
WriteLn;
|
||||||
if Failed = 0 then
|
if Failed = 0 then
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue