diff --git a/src/uMainForm.pas b/src/uMainForm.pas index 06a6ab7..2c11e2a 100644 --- a/src/uMainForm.pas +++ b/src/uMainForm.pas @@ -3012,6 +3012,7 @@ var T: TMediaTransform; Key: TColorKey; Applied: Boolean; + At: Double; begin if AClip = nil then Exit; @@ -3041,12 +3042,23 @@ begin end; T := AClip.Transform; + { Кадр окну — из самого клипа, а не из середины исходного файла. + + Клип обычно вырезан из середины долгой съёмки, и кадр «десятая часть + от начала файла» показывал совсем другую сцену: прицелиться + кадрированием было нечем. Берём то место, где стоит курсор, если он + внутри клипа, иначе середину клипа — то, на что человек и смотрит. } + At := FTimeline.Playhead; + if (At < AClip.TlStart) or (At > AClip.TlEnd) then + At := AClip.TlStart + AClip.Duration / 2; + At := AClip.SrcIn + (At - AClip.TlStart); + { Ключ отдаётся окну по ссылке: правку он подтверждает сам, и «Отмена» кадрирования её не отменяет. } Key := AClip.ColorKey; Applied := EditTransform(Self, Item.EffectivePath, Item.Info, FProject.Master.Width, FProject.Master.Height, T, - FProject.CacheDir + 'pancrop.png', @Key); + FProject.CacheDir + 'pancrop.png', @Key, At); if (not Applied) and SameColorKey(Key, AClip.ColorKey) then Exit; diff --git a/src/uPanCropForm.pas b/src/uPanCropForm.pas index dfce88f..f5f961f 100644 --- a/src/uPanCropForm.pas +++ b/src/uPanCropForm.pas @@ -71,6 +71,8 @@ type у заготовки для файла, у которой клипа ещё нет), и кнопки не будет. } FKey: PColorKey; + { Какое место исходника показывать в окне. } + FAtTime: Double; FSourceInfo: TMediaInfo; FDstWidth: Integer; FDstHeight: Integer; @@ -106,11 +108,18 @@ type procedure WriteControls; procedure ScheduleRefresh; procedure RefreshPreview(Sender: TObject); + { Время кадра в исходнике: заданное снаружи или своё. } + function FrameTime: Double; public { Готовит окно. ADstWidth и ADstHeight — кадр проекта. } + { AAtTime — какое место исходника показывать. Меньше нуля — выбрать + самим: десятая часть от начала файла. Для клипа передаётся его + собственное время, иначе прицелиться нечем: клип вырезан из середины + съёмки, а в окне показывалась совсем другая сцена. } procedure Setup(const APath: string; const AInfo: TMediaInfo; ADstWidth, ADstHeight: Integer; const ATransform: TMediaTransform; - const APreviewFile: string; AKey: PColorKey = nil); + const APreviewFile: string; AKey: PColorKey = nil; + AAtTime: Double = -1); property Transform: TMediaTransform read FTransform; end; @@ -124,7 +133,7 @@ type function EditTransform(AOwner: TComponent; const APath: string; const AInfo: TMediaInfo; ADstWidth, ADstHeight: Integer; var ATransform: TMediaTransform; const APreviewFile: string; - AKey: PColorKey = nil): Boolean; + AKey: PColorKey = nil; AAtTime: Double = -1): Boolean; implementation @@ -201,6 +210,21 @@ begin end; +{ Какое место исходника показывать. + + Задано снаружи — берём его: у клипа это его собственное время, и только + по нему можно прицелиться кадрированием. Не задано (кадрирование файла + целиком из списка) — десятая часть от начала, но не дальше пятой + секунды: первые кадры съёмки часто пустые. } +function TPanCropForm.FrameTime: Double; +begin + if FSourceInfo.Kind = mkImage then + Exit(0); + if FAtTime >= 0 then + Exit(Max(0, Min(FAtTime, Max(0, FSourceInfo.Duration - 0.05)))); + Result := Min(5, Max(0, FSourceInfo.Duration * 0.1)); +end; + procedure TPanCropForm.FormDestroy(Sender: TObject); begin FreeAndNil(FSourceBmp); @@ -211,8 +235,9 @@ end; procedure TPanCropForm.Setup(const APath: string; const AInfo: TMediaInfo; ADstWidth, ADstHeight: Integer; const ATransform: TMediaTransform; - const APreviewFile: string; AKey: PColorKey); + const APreviewFile: string; AKey: PColorKey; AAtTime: Double); begin + FAtTime := AAtTime; FKey := AKey; btnKey.Visible := AKey <> nil; FSourcePath := APath; @@ -321,10 +346,7 @@ var begin if FKey = nil then Exit; - if FSourceInfo.Kind = mkImage then - AtTime := 0 - else - AtTime := Min(5, Max(0, FSourceInfo.Duration * 0.1)); + AtTime := FrameTime; EditColorKey(FKey^, FSourcePath, AtTime, FPreviewFile + '.key.png'); end; @@ -515,10 +537,7 @@ begin Exit; Path := FPreviewFile + '.src.png'; - if FSourceInfo.Kind = mkImage then - AtTime := 0 - else - AtTime := Min(5, Max(0, FSourceInfo.Duration * 0.1)); + AtTime := FrameTime; { Пустая цепочка фильтров: нужен именно исходный кадр, без вписывания и полей — иначе рамку не по чему тянуть. } @@ -677,10 +696,7 @@ begin PrevW, PrevH); lblFilter.Caption := Filter; - if FSourceInfo.Kind = mkImage then - AtTime := 0 - else - AtTime := Min(5, Max(0, FSourceInfo.Duration * 0.1)); + AtTime := FrameTime; Res := RunProcess(FfmpegExe, ArgsPreviewFrame(FSourcePath, FPreviewFile, AtTime, Filter), @@ -720,14 +736,14 @@ end; function EditTransform(AOwner: TComponent; const APath: string; const AInfo: TMediaInfo; ADstWidth, ADstHeight: Integer; var ATransform: TMediaTransform; const APreviewFile: string; - AKey: PColorKey): Boolean; + AKey: PColorKey; AAtTime: Double = -1): Boolean; var Form: TPanCropForm; begin Form := TPanCropForm.Create(AOwner); try Form.Setup(APath, AInfo, ADstWidth, ADstHeight, ATransform, APreviewFile, - AKey); + AKey, AAtTime); Result := Form.ShowModal = mrOK; if Result then ATransform := Form.Transform;