public string Save(string videoName, string overlayTextMarking, EHorizontalAlign markingHorizontalAlign, EVerticalAlign markingVerticalAlign, double?durationMini = null) { this.TraceDebug($"Saving video \"{videoName}\" in buffer"); var videoFileName = $"{videoName}.mpeg"; var exeFilePath = Path.Combine( Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"Video\", Environment.Is64BitOperatingSystem ? "videosplitter-64.exe" : "videosplitter-32.exe"); var fontFilePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"Video\", "arial.ttf"); var textFilePath = Path.GetTempFileName(); if (!string.IsNullOrWhiteSpace(overlayTextMarking)) { using (var stream = File.OpenWrite(textFilePath)) using (var writer = new StreamWriter(stream, new UTF8Encoding(false))) { writer.Write(overlayTextMarking.Replace(@"\", @"\\")); } } string markingAlignment = string.Empty; switch (markingHorizontalAlign) { case EHorizontalAlign.Center: markingAlignment = $"x=(w-tw)/2"; break; case EHorizontalAlign.Left: markingAlignment = $"x={_MARKING_PADDING}"; break; case EHorizontalAlign.Right: markingAlignment = $"x=w-tw-{_MARKING_PADDING}"; break; } switch (markingVerticalAlign) { case EVerticalAlign.Bottom: markingAlignment += $":y=h-th-{_MARKING_PADDING}"; break; case EVerticalAlign.Center: markingAlignment += $":y=(h-th)/2"; break; case EVerticalAlign.Top: markingAlignment += $":y={_MARKING_PADDING}"; break; } double speed = 1; bool slowMotion = false; if (durationMini != null && Duration.TotalSeconds < durationMini) { slowMotion = true; speed = Duration.TotalMilliseconds / (durationMini.Value * 1000); } List <string> filters = new List <string>(); if (slowMotion) { filters.Add($"setpts=(1/{speed.ToString().Replace(',', '.')})*PTS"); } if (!string.IsNullOrWhiteSpace(overlayTextMarking)) { string formattedFontFilePath = fontFilePath.Replace(@"\", @"\\").Replace(":", @"\:"); string formattedtextFilePath = textFilePath.Replace(@"\", @"\\").Replace(":", @"\:"); filters.Add($"drawtext=fontfile='{formattedFontFilePath}':textfile='{formattedtextFilePath}':fontcolor=white:fontsize=24:box=1:[email protected]:boxborderw=5:{markingAlignment}"); } var processArgumentsBuilder = new StringBuilder("-y -nostdin"); processArgumentsBuilder.Append($" -ss {From.ToString(@"hh\:mm\:ss")}.{From.Milliseconds}"); processArgumentsBuilder.Append($" -t {Duration.ToString(@"hh\:mm\:ss")}.{Math.Max(Duration.Milliseconds, 200)}"); processArgumentsBuilder.Append($" -i \"{_input}\""); if (filters.Count > 0) { if (slowMotion) { processArgumentsBuilder.Append(" -an"); } processArgumentsBuilder.Append($" -vf \"{string.Join(",", filters)}\""); } processArgumentsBuilder.Append($" -vcodec mpeg1video -b:v 4000k \"{videoFileName}\""); using (var process = new Process()) { process.StartInfo.FileName = exeFilePath; process.StartInfo.Arguments = processArgumentsBuilder.ToString(); process.StartInfo.CreateNoWindow = true; process.StartInfo.UseShellExecute = false; process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardOutput = true; this.TraceDebug($"{exeFilePath} {processArgumentsBuilder}"); try { string errorOutput = null; string standardOutput = null; process.Start(); var outputStreamTasks = new[] { Task.Factory.StartNew(() => errorOutput = process.StandardError.ReadToEnd()), Task.Factory.StartNew(() => standardOutput = process.StandardOutput.ReadToEnd()) }; var timeout = TimeSpan.FromMinutes(3); // TODO add to configuration process.WaitForExit((int)timeout.TotalMilliseconds); Task.WaitAll(outputStreamTasks, (int)timeout.TotalMilliseconds, KprocessExportWindow.CancellationToken); this.TraceDebug(standardOutput); Debug.WriteLine(standardOutput); if (!string.IsNullOrWhiteSpace(errorOutput)) { this.TraceError("Des erreurs ont été levées par le processus permettant de splitter les videos:"); this.TraceError(errorOutput); Debug.WriteLine(errorOutput); } } catch (Win32Exception e) { this.TraceError(e, "Le splitter de video n'a pas été trouvé"); throw new Exception("An issue has occured during video packaging. It seems that some components are missing.", e); } catch (OperationCanceledException e) { this.TraceError(e, "L'export a été annulé lors du split des vidéos"); throw; } catch (Exception e) { this.TraceError(e, "Une erreur non prévue s'est produite lors du split de la video"); throw; } finally { try { File.Delete(textFilePath); } catch { } } } return(videoName); }
/// <summary> /// Стандартный конструктор /// </summary> /// <param name="parDepth">Глубина</param> /// <param name="parX">Координата X</param> /// <param name="parY">Координата Y</param> /// <param name="parStringToRender">Текстовая строка</param> /// <param name="parFont">Шрифт</param> /// <param name="parColor">Цвет</param> /// <param name="parScaleX">Масштабирование по X</param> /// <param name="parScaleY">Масштабирование по Y</param> /// <param name="parHAlign">Горизонтальное выравнивание</param> /// <param name="parVAlign">Вертикальное выравнивание</param> public RenderingString(double parDepth, double parX, double parY, string parStringToRender, SubassetDataFont parFont, Color parColor, double parScaleX = 1.0, double parScaleY = 1.0, EHorizontalAlign parHAlign = EHorizontalAlign.Left, EVerticalAlign parVAlign = EVerticalAlign.Top) { LinkedList <SubassetDataSprite> usedSprites = parFont.GetSymbolsSprites(parStringToRender); SpritesToRender = new LinkedList <RenderingSprite>(); double totalWidth = 0; double totalHeight = 0; foreach (var usedSprite in usedSprites) { totalWidth += usedSprite.Width; if (usedSprite.Height > totalHeight) { totalHeight = usedSprite.Height; } } X = OpenGlUtil.GetLeftXCoordBasedOnHorizontalAlign(parX, totalWidth, parHAlign, parScaleX); Y = OpenGlUtil.GetTopYCoordBasedOnVerticalAlign(parY, totalHeight, parVAlign, parScaleY); totalWidth = 0; //totalHeight = 0; foreach (var usedSprite in usedSprites) { SpritesToRender.AddLast(new RenderingSprite(usedSprite, X + totalWidth, Y, 0, parColor, parDepth, parScaleX, parScaleY, EHorizontalAlign.Left, EVerticalAlign.Top)); totalWidth += usedSprite.Width * parScaleX; } Depth = parDepth; }
/// <summary> /// Получить координату X в пространстве OpenGL с учетом выбранного горизонтального выравнивания /// </summary> /// <param name="parX">X в обычной системе координат</param> /// <param name="parWidth">Ширина</param> /// <param name="parHAlign">Выбранное горизонтальное выравнивание</param> /// <param name="parScale">Величина масштабирования</param> /// <returns></returns> /// <exception cref="ArgumentOutOfRangeException">Неподдерживаемый формат выравнивания</exception> public static double GetLeftXCoordBasedOnHorizontalAlign(double parX, double parWidth, EHorizontalAlign parHAlign, double parScale) { switch (parHAlign) { case EHorizontalAlign.Left: return(parX); break; case EHorizontalAlign.Middle: return(parX - (parWidth * parScale / 2)); break; case EHorizontalAlign.Right: return(parX - (parWidth * parScale)); break; default: throw new ArgumentOutOfRangeException(nameof(parHAlign), parHAlign, null); } }
/// <summary> /// Стандартный конструктор /// </summary> /// <param name="parSprite">Производный ассет спрайта</param> /// <param name="parX">Координата X</param> /// <param name="parY">Координата Y</param> /// <param name="parRotationDegrees">Поворот в градусах</param> /// <param name="parBlendColor">Цвет</param> /// <param name="parDepth">Глубина</param> /// <param name="parScaleX">Масштабирование по X</param> /// <param name="parScaleY">Масштабирование по Y</param> /// <param name="parHAlign">Горизонтальное выравнивание</param> /// <param name="parVAlign">Вертикальное выравнивание</param> /// <param name="parRotationPivotX">Точка опоры для поворота, координата X</param> /// <param name="parRotationPivotY">Точка опоры для поворота, координата Y</param> public RenderingSprite(SubassetDataSprite parSprite, double parX, double parY, double parRotationDegrees, Color parBlendColor, double parDepth, double parScaleX = 1.0, double parScaleY = 1.0, EHorizontalAlign parHAlign = EHorizontalAlign.Left, EVerticalAlign parVAlign = EVerticalAlign.Top, double parRotationPivotX = 0, double parRotationPivotY = 0) { Sprite = parSprite; X = OpenGlUtil.GetLeftXCoordBasedOnHorizontalAlign(parX, parSprite.Width, parHAlign, parScaleX); Y = OpenGlUtil.GetTopYCoordBasedOnVerticalAlign(parY, parSprite.Height, parVAlign, parScaleY); Depth = parDepth; RotationDegrees = parRotationDegrees; BlendColor = parBlendColor; ScaleX = parScaleX; ScaleY = parScaleY; PivotX = parRotationPivotX; PivotY = parRotationPivotY; }