/// <summary> /// Transcode's all videos of a site /// </summary> /// <param name="configuration">Json configuration of IDBrowserService as IDBrowserConfiguration class</param> /// <param name="cancellationToken">CancellationToken</param> /// <param name="siteName">Site name to transcode</param> /// <param name="videoSize">Video size to transcode. (e.g. Hd480, Hd720, Hd1080)</param> /// <param name="taskCount">FFmpeg task count (Default 2)</param> /// <param name="logLevel">Serilog log level</param> public static void TranscodeAllVideos(IDBrowserConfiguration configuration, CancellationToken cancellationToken, string siteName, string videoSize, Serilog.Events.LogEventLevel logLevel, int taskCount) { LoggingLevelSwitch loggingLevelSwitch = new LoggingLevelSwitch { MinimumLevel = logLevel }; Log.Logger = new LoggerConfiguration() .MinimumLevel.ControlledBy(loggingLevelSwitch) .WriteTo.File(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log", "ConsoleFunctions.log")) .CreateLogger(); SiteSettings siteSettings = configuration.Sites[siteName]; IDImagerDB db = new IDImagerDB(GetIDImagerDBOptionsBuilder <IDImagerDB>(siteSettings.ConnectionStrings.DBType, siteSettings.ConnectionStrings.IDImager).Options); var query = db.idCatalogItem .Include(x => x.idFilePath) .Where(x => configuration.VideoFileExtensions.Contains(x.idFileType)); ProgressTaskFactory progressTaskFactory = new ProgressTaskFactory(taskCount, 100, 60, Log.Logger); Task windowChangeListenerTask = new Task(() => { int width = Console.WindowWidth; int height = Console.WindowHeight; while (!cancellationToken.IsCancellationRequested) { if (width != Console.WindowWidth || height != Console.WindowHeight) { width = Console.WindowWidth; height = Console.WindowHeight; progressTaskFactory.RedrawConsoleWindows(100, 60); } cancellationToken.WaitHandle.WaitOne(100); } }, cancellationToken); windowChangeListenerTask.Start(); if (!IsWindows) { // Log output scrolling not supported at the moment because Console.MoveBufferArea is currently not supported under Linux and MacOs. // But we can write a single infoline. progressTaskFactory.WriteLog("Log output in console not supported under Linux at the moment. Please take a look at the ConsoleFunctions.log in Logs directory.", true, LogEventLevel.Information); } List <TranscodeVideoBatchInfo> listTranscodeVideoBatch = new List <TranscodeVideoBatchInfo>(); foreach (idCatalogItem catalogItem in query) { catalogItem.GetHeightAndWidth(out int originalVideoWidth, out int originalVideoHeight); string strTranscodeFilePath = StaticFunctions.GetTranscodeFilePath(catalogItem.GUID, siteSettings.ServiceSettings.TranscodeDirectory, videoSize); FileInfo transcodeFileInfo = new FileInfo(strTranscodeFilePath); if (!transcodeFileInfo.Exists) { string strOriginalFilePath = StaticFunctions.GetImageFilePath(catalogItem, siteSettings.ServiceSettings.FilePathReplace); TranscodeVideoBatchInfo transcodeVideoBatchInfo = new TranscodeVideoBatchInfo(catalogItem.GUID, originalVideoWidth, originalVideoHeight, strOriginalFilePath, strTranscodeFilePath); listTranscodeVideoBatch.Add(transcodeVideoBatchInfo); } } db.Dispose(); int intTotalCount = listTranscodeVideoBatch.Count(); int intCounter = 1; TranscodeVideoBatchInfo lastTranscodeVideoBatch = listTranscodeVideoBatch.LastOrDefault(); foreach (TranscodeVideoBatchInfo transcodeVideoBatchInfo in listTranscodeVideoBatch) { if (cancellationToken.IsCancellationRequested) { return; } string strTranscodeFilePath = StaticFunctions.GetTranscodeFilePath(transcodeVideoBatchInfo.GUID, siteSettings.ServiceSettings.TranscodeDirectory, videoSize); StaticFunctions.GetTranscodeVideoSize(videoSize, transcodeVideoBatchInfo.VideoWidth, transcodeVideoBatchInfo.VideoHeight, out VideoSize targetVideoSize, out int targetVideoWidth, out int targetVideoHeight); var conversionOptions = StaticFunctions.GetConversionOptions(targetVideoSize, transcodeVideoBatchInfo.VideoWidth, transcodeVideoBatchInfo.VideoHeight); progressTaskFactory.WriteLog(string.Format("Transcoding file {0} of {1} with guid {2} and path \"{3}\" from resolution {4}x{5} to {6}x{7} ", intCounter, intTotalCount, transcodeVideoBatchInfo.GUID, transcodeVideoBatchInfo.VideoFileInfo.FullName, transcodeVideoBatchInfo.VideoWidth, transcodeVideoBatchInfo.VideoHeight, targetVideoWidth, targetVideoHeight), IsWindows, LogEventLevel.Information); ProgressTask progressTask = progressTaskFactory.GetIdleProgressTask(); if (cancellationToken.IsCancellationRequested) { return; } if (progressTask == null) { progressTask = progressTaskFactory .WaitForAnyTask() .Result; } if (cancellationToken.IsCancellationRequested) { return; } string progressBarText = string.Format("{0} ({1} of {2})", transcodeVideoBatchInfo.TranscodeFileInfo.Name, intCounter, intTotalCount); progressTask.Task = new Task(() => { TranscodeVideoProgressTask(transcodeVideoBatchInfo, videoSize, cancellationToken, progressTask, progressBarText); }); progressTask.Task.Start(); // If we are on the last item we have to wait for all tasks to complete if (transcodeVideoBatchInfo == lastTranscodeVideoBatch) { progressTaskFactory.WaitForAllTasks(); } intCounter++; } Log.CloseAndFlush(); }
/// <summary> /// Transcodes single video with console progresbar updates. /// </summary> /// <param name="transcodeVideoBatchInfo">Transcode video batch info</param> /// <param name="videoSize">Video size</param> /// <param name="cancellationToken">CancellationToken</param> /// <param name="progressTask">Progress task</param> /// <param name="progressBarText">Progress bar text</param> public static void TranscodeVideoProgressTask(TranscodeVideoBatchInfo transcodeVideoBatchInfo, string videoSize, CancellationToken cancellationToken, ProgressTask progressTask, string progressBarText) { try { Engine ffmpegEngine = StaticFunctions.GetFFmpegEngine(); ffmpegEngine.Error += (sender, eventArgs) => { progressTask.ProgressTaskFactory.WriteLog(string.Format("FFmpeg error on file \"{0}\" => {1}", transcodeVideoBatchInfo.VideoFileInfo.FullName, eventArgs.Exception.ToString()), IsWindows, LogEventLevel.Error); }; ffmpegEngine.Progress += (sender, eventArgs) => { int intProgress = (int)Math.Round(eventArgs.ProcessedDuration * 100 / eventArgs.TotalDuration); intProgress = Math.Max(0, Math.Min(100, intProgress)); progressTask.RefreshProgressBar(intProgress, progressBarText); }; progressTask.RefreshProgressBar(0, progressBarText); Task task = StaticFunctions.TranscodeVideo(ffmpegEngine, cancellationToken, transcodeVideoBatchInfo.VideoFileInfo.FullName, transcodeVideoBatchInfo.TranscodeFileInfo.FullName, videoSize, transcodeVideoBatchInfo.VideoWidth, transcodeVideoBatchInfo.VideoHeight); task.Wait(); transcodeVideoBatchInfo.TranscodeFileInfo.Refresh(); if (!transcodeVideoBatchInfo.TranscodeFileInfo.Exists) { progressTask.ProgressTaskFactory.WriteLog(string.Format("Transcoding on file \"{0}\" failed, file does not exist.", transcodeVideoBatchInfo.VideoFileInfo.FullName), IsWindows, LogEventLevel.Error); progressTask.RefreshProgressBar(0, progressBarText + " (failed)"); } else if (transcodeVideoBatchInfo.TranscodeFileInfo.Length == 0) { transcodeVideoBatchInfo.TranscodeFileInfo.Delete(); progressTask.ProgressTaskFactory.WriteLog(string.Format("Transcoding failed on file \"{0}\", file size is zero. Unfinished transcoded file \"{1}\" deleted.", transcodeVideoBatchInfo.VideoFileInfo.FullName, transcodeVideoBatchInfo.TranscodeFileInfo.FullName), IsWindows, LogEventLevel.Error); progressTask.RefreshProgressBar(0, progressBarText + " (failed)"); } else { progressTask.RefreshProgressBar(100, progressBarText); } } catch (Exception ex) { // Wait for file to be unlocked Thread.Sleep(2000); transcodeVideoBatchInfo.TranscodeFileInfo.Refresh(); if (transcodeVideoBatchInfo.TranscodeFileInfo != null && transcodeVideoBatchInfo.TranscodeFileInfo.Exists) { transcodeVideoBatchInfo.TranscodeFileInfo.Delete(); progressTask.ProgressTaskFactory.WriteLog(string.Format("Unfinished transcoded file \"{0}\" deleted.", transcodeVideoBatchInfo.TranscodeFileInfo.FullName), IsWindows, LogEventLevel.Error); } if (ex.GetType() == typeof(AggregateException) && ex.InnerException != null && ex.InnerException.GetType() == typeof(TaskCanceledException)) { progressTask.ProgressTaskFactory.WriteLog("Transcoding cancelled", IsWindows, Serilog.Events.LogEventLevel.Information); } else { progressTask.ProgressTaskFactory.WriteLog(ex.ToString(), IsWindows, Serilog.Events.LogEventLevel.Information); } return; } }