Этапы 3 и 4: звук отдельно от картинки
У дорожки появился вид — картинка или звук, у клипа принадлежность к связке. Проект заводит две дорожки картинки и две звука; при добавлении файла со звуком клип кладётся парой, связанной общим номером. Уплощение теперь делается двумя проходами: отдельно для картинки, отдельно для звука. Одним проходом такое не выразить — в один и тот же момент картинка берётся с одной дорожки, а звук с другой. Сборка соответственно тоже раздваивается. Картинка собирается прежним способом, копированием. Звук собирается в сырой поток и сжимается одним проходом: куски дописываются друг за другом байтами, и длина каждого считается из длительности, а не берётся у ffmpeg. Поэтому стык получается с точностью до отсчёта, а не до звукового кадра, и звук не уезжает от картинки. Тишина в дырах пишется нулями, без запуска ffmpeg вовсе. Готовые потоки сшиваются копированием. Предпросмотр получает второй список кусков как внешнюю звуковую дорожку. Проекты, записанные раньше, переносятся при чтении: звук там шёл вместе с клипом картинки и без пары просто пропал бы. Проверено сборкой: - картинка из молчащего синего файла 0..6 с, звук из другого файла с 2 по 6 с. В результате тишина первые две секунды и тон дальше — звук встал туда, куда положен, а не туда, где картинка; - обычный парный случай: клип с 2 по 6 с, тишина до него и тон в нём; - проверки уплощения пройдены.
This commit is contained in:
parent
b7b41f7cf0
commit
a06ecfd720
7 changed files with 547 additions and 38 deletions
|
|
@ -306,7 +306,8 @@ begin
|
|||
WriteLn('остановка через: ', SecondsToStr(CancelAfter), ' с');
|
||||
WriteLn;
|
||||
|
||||
Thread := TExportThread.Create(Segments, ParamStr(FirstArg - 1), True,
|
||||
{ Проверка вырезания и склейки картинки: звук здесь не собирается. }
|
||||
Thread := TExportThread.Create(Segments, nil, ParamStr(FirstArg - 1), True,
|
||||
Default(TMediaInfo));
|
||||
Watcher := TExportWatcher.Create(Thread);
|
||||
try
|
||||
|
|
@ -563,7 +564,7 @@ begin
|
|||
try
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 10, 5, 0);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 15, 5, 5);
|
||||
FlattenProject(Proj, Segs, Missing);
|
||||
FlattenStream(Proj, tkVideo, Segs, Missing);
|
||||
DumpSegments(Segs);
|
||||
Check(Length(Segs) = 1, 'склеились в один кусок');
|
||||
if Length(Segs) = 1 then
|
||||
|
|
@ -582,7 +583,7 @@ begin
|
|||
try
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 100, 5, 0);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 200, 5, 5);
|
||||
FlattenProject(Proj, Segs, Missing);
|
||||
FlattenStream(Proj, tkVideo, Segs, Missing);
|
||||
DumpSegments(Segs);
|
||||
Check(Length(Segs) = 2, 'остались двумя кусками');
|
||||
finally
|
||||
|
|
@ -597,7 +598,7 @@ begin
|
|||
{ Дорожка 0 — верхняя, она побеждает. }
|
||||
Proj.AddClip(Proj.Tracks[1], Media, 0, 30, 0);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 100, 10, 10);
|
||||
FlattenProject(Proj, Segs, Missing);
|
||||
FlattenStream(Proj, tkVideo, Segs, Missing);
|
||||
DumpSegments(Segs);
|
||||
Check(Length(Segs) = 3, 'получилось три куска');
|
||||
if Length(Segs) = 3 then
|
||||
|
|
@ -621,7 +622,7 @@ begin
|
|||
try
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 0, 5, 3);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 50, 5, 12);
|
||||
FlattenProject(Proj, Segs, Missing);
|
||||
FlattenStream(Proj, tkVideo, Segs, Missing);
|
||||
DumpSegments(Segs);
|
||||
Check(Length(Segs) = 4, 'четыре куска: чёрное, видео, чёрное, видео');
|
||||
if Length(Segs) = 4 then
|
||||
|
|
@ -651,7 +652,7 @@ begin
|
|||
try
|
||||
Proj.AddClip(Proj.Tracks[1], Media, 0, 10, 0);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 200, 10, 0);
|
||||
FlattenProject(Proj, Segs, Missing);
|
||||
FlattenStream(Proj, tkVideo, Segs, Missing);
|
||||
DumpSegments(Segs);
|
||||
Check(Length(Segs) = 1, 'остался один кусок');
|
||||
if Length(Segs) = 1 then
|
||||
|
|
@ -668,7 +669,7 @@ begin
|
|||
Proj.AddClip(Proj.Tracks[1], Media, 0, 10, 0);
|
||||
Proj.AddClip(Proj.Tracks[0], Media, 200, 10, 0);
|
||||
Proj.Tracks[0].Muted := True;
|
||||
FlattenProject(Proj, Segs, Missing);
|
||||
FlattenStream(Proj, tkVideo, Segs, Missing);
|
||||
DumpSegments(Segs);
|
||||
Check(Length(Segs) = 1, 'остался один кусок');
|
||||
if Length(Segs) = 1 then
|
||||
|
|
@ -688,7 +689,7 @@ begin
|
|||
Proj.Tracks[0][0].EdgeIn := edPrecise;
|
||||
Proj.RippleMode := rmAllTracks;
|
||||
Proj.RippleEnabled := True;
|
||||
FlattenProject(Proj, Segs, Missing);
|
||||
FlattenStream(Proj, tkVideo, Segs, Missing);
|
||||
Check(Length(Segs) = 3, 'до записи три куска');
|
||||
Check(Proj.SaveToFile(TempFile, Err), 'записан: ' + Err);
|
||||
finally
|
||||
|
|
@ -698,13 +699,17 @@ begin
|
|||
Proj := TProject.Create;
|
||||
try
|
||||
Check(Proj.LoadFromFile(TempFile, Err), 'прочитан: ' + Err);
|
||||
Check(Proj.TrackCount = 2, 'дорожек снова две');
|
||||
{ Четыре: две картинки и две звука. Звуковые заводятся сразу, чтобы
|
||||
каждому клипу картинки было куда положить парный звук. }
|
||||
Check(Proj.TrackCount = 4, 'дорожек снова четыре');
|
||||
Check(Proj.TrackCountOf(tkVideo) = 2, 'из них две для картинки');
|
||||
Check(Proj.TrackCountOf(tkAudio) = 2, 'и две для звука');
|
||||
Check(Proj.PoolCount = 1, 'файл в списке один');
|
||||
Check(Proj.RippleMode = rmAllTracks, 'режим схлопывания сохранился');
|
||||
Check(Proj.RippleEnabled, 'состояние схлопывания сохранилось');
|
||||
if Proj.TrackCount = 2 then
|
||||
Check(Proj.Tracks[0][0].EdgeIn = edPrecise, 'признак точного реза сохранился');
|
||||
FlattenProject(Proj, Segs, Missing);
|
||||
FlattenStream(Proj, tkVideo, Segs, Missing);
|
||||
DumpSegments(Segs);
|
||||
Check(Length(Segs) = 3, 'после чтения снова три куска');
|
||||
if Length(Segs) = 3 then
|
||||
|
|
@ -739,6 +744,7 @@ begin
|
|||
Proj.Clear;
|
||||
Proj.AddTrack('V1');
|
||||
Proj.AddTrack('V2');
|
||||
Proj.EnsureAudioTracks;
|
||||
|
||||
if not ProbeMedia(ExpandFileName(ParamStr(3)), Info, Err) then
|
||||
begin
|
||||
|
|
@ -750,8 +756,10 @@ begin
|
|||
|
||||
{ Нижняя дорожка: два куска видео из разных мест, между ними дыра
|
||||
в две секунды, и ещё дыра в начале. }
|
||||
Proj.AddClip(Proj.Tracks[1], Video, 100, 6, 1.5);
|
||||
Proj.AddClip(Proj.Tracks[1], Video, 400, 6, 9.5);
|
||||
{ Парой: клип картинки и его звук на соответствующей звуковой
|
||||
дорожке. Так собранный проект похож на настоящий. }
|
||||
Proj.AddClipPair(Proj.Tracks[1], Video, 100, 6, 1.5);
|
||||
Proj.AddClipPair(Proj.Tracks[1], Video, 400, 6, 9.5);
|
||||
|
||||
if ParamCount >= 4 then
|
||||
begin
|
||||
|
|
@ -853,7 +861,7 @@ end;
|
|||
procedure CmdRender;
|
||||
var
|
||||
Proj: TProject;
|
||||
Segs: TFlatSegmentArray;
|
||||
Segs, AudioSegs: TFlatSegmentArray;
|
||||
Missing: TGenRequests;
|
||||
Err: string;
|
||||
Gen: TGenerateThread;
|
||||
|
|
@ -877,7 +885,7 @@ begin
|
|||
WriteLn('длина: ', SecondsToStr(Proj.EndTime), ' с');
|
||||
WriteLn;
|
||||
|
||||
if not FlattenProject(Proj, Segs, Missing) then
|
||||
if not FlattenProject(Proj, Segs, AudioSegs, Missing) then
|
||||
begin
|
||||
WriteLn('Уплотить нечего.');
|
||||
Halt(1);
|
||||
|
|
@ -914,7 +922,7 @@ begin
|
|||
WriteLn;
|
||||
|
||||
{ После создания уплощаем заново: теперь все файлы на месте. }
|
||||
FlattenProject(Proj, Segs, Missing);
|
||||
FlattenProject(Proj, Segs, AudioSegs, Missing);
|
||||
if Length(Missing) > 0 then
|
||||
begin
|
||||
WriteLn('Часть вставок так и не появилась.');
|
||||
|
|
@ -922,8 +930,8 @@ begin
|
|||
end;
|
||||
end;
|
||||
|
||||
Thread := TExportThread.Create(Segs, ExpandFileName(ParamStr(3)), True,
|
||||
Proj.Master);
|
||||
Thread := TExportThread.Create(Segs, AudioSegs,
|
||||
ExpandFileName(ParamStr(3)), True, Proj.Master);
|
||||
Watcher := TExportWatcher.Create(Thread);
|
||||
try
|
||||
Thread.OnProgress := @Watcher.Progress;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue