protected virtual void CutAndConcatAndRenderTextAndImageAndTimeWarps(List <FFMpegCutInfo> cutInfos, FFMpeg ffMpeg, TemporaryFilesStorage temporaryFilesStorage) { var textTimeTableForConcatenatedEpisodeGroups = new List <TextTimeRecord>(); var imagesTimeTableForConcatenatedEpisodeGroups = new List <DrawImageTimeRecord>(); var timeWarpForConcatenatedEpisodeGroups = new List <TimeWarpRecord>(); var currentPosition = 0.0; foreach (var videoRenderOption in this.VideoRenderOptions) { if (videoRenderOption.OverlayTextTimeTable != null && videoRenderOption.OverlayTextTimeTable.Any()) { textTimeTableForConcatenatedEpisodeGroups.AddRange( videoRenderOption.OverlayTextTimeTable.Select(v => new TextTimeRecord(v.Lines, v.StartSecond + currentPosition, v.EndSecond + currentPosition))); } if (videoRenderOption.ImagesTimeTable != null && videoRenderOption.ImagesTimeTable.Any()) { imagesTimeTableForConcatenatedEpisodeGroups.AddRange( videoRenderOption.ImagesTimeTable.Select(v => new DrawImageTimeRecord(v.ImageData, v.LeftOffset, v.TopOffset, v.ImageStartSecond + currentPosition, v.ImageEndSecond + currentPosition))); } if (videoRenderOption.TimeWarpSettings != null && videoRenderOption.TimeWarpSettings.Any()) { timeWarpForConcatenatedEpisodeGroups.AddRange( videoRenderOption.TimeWarpSettings.Select(v => new TimeWarpRecord(v.StartSecond + currentPosition, v.EndSecond + currentPosition, v.Coefficient))); } currentPosition += videoRenderOption.DurationSeconds; } var pathForConcatenatedEpisodes = timeWarpForConcatenatedEpisodeGroups.Any() ? temporaryFilesStorage.GetIntermediateFile(Path.GetExtension(this.outputFile)) : this.outputFile; ffMpeg.CutAndConcatAndDrawImagesAndText( cutInfos, imagesTimeTableForConcatenatedEpisodeGroups, textTimeTableForConcatenatedEpisodeGroups, this.OutputSize, pathForConcatenatedEpisodes, this.globalExportProgress); if (timeWarpForConcatenatedEpisodeGroups.Any()) { ffMpeg.ApplyTimeWarp(pathForConcatenatedEpisodes, timeWarpForConcatenatedEpisodeGroups, this.outputFile, this.globalExportProgress); } }