using System.IO; using System.Windows.Input; using Azaion.Annotator.DTO; using LibVLCSharp.Shared; using MediatR; namespace Azaion.Annotator; public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWindow mainWindow, FormState formState, Config config) : INotificationHandler, INotificationHandler, INotificationHandler { private const int STEP = 20; private const int LARGE_STEP = 5000; private static readonly string[] CatchSenders = ["ForegroundWindow", "ScrollViewer"]; private readonly Dictionary KeysControlEnumDict = new() { { Key.Space, PlaybackControlEnum.Pause }, { Key.Left, PlaybackControlEnum.PreviousFrame }, { Key.Right, PlaybackControlEnum.NextFrame }, { Key.Enter, PlaybackControlEnum.SaveAnnotations }, { Key.Delete, PlaybackControlEnum.RemoveSelectedAnns }, { Key.X, PlaybackControlEnum.RemoveAllAnns } }; public async Task Handle(AnnClassSelectedEvent notification, CancellationToken cancellationToken) { SelectClass(notification.AnnotationClass); await Task.CompletedTask; } private void SelectClass(AnnotationClass annClass) { mainWindow.Editor.CurrentAnnClass = annClass; foreach (var ann in mainWindow.Editor.CurrentAnns.Where(x => x.IsSelected)) ann.AnnotationClass = annClass; mainWindow.LvClasses.SelectedIndex = annClass.Id; } public async Task Handle(KeyEvent notification, CancellationToken cancellationToken) { if (!CatchSenders.Contains(notification.Sender.GetType().Name)) return; var key = notification.Args.Key; var keyNumber = (int?)null; if ((int)key >= (int)Key.D1 && (int)key <= (int)Key.D9) keyNumber = key - Key.D1; if ((int)key >= (int)Key.NumPad1 && (int)key <= (int)Key.NumPad9) keyNumber = key - Key.NumPad1; if (keyNumber.HasValue) SelectClass(mainWindow.AnnotationClasses[keyNumber.Value]); if (KeysControlEnumDict.TryGetValue(key, out var value)) await ControlPlayback(value); } public async Task Handle(PlaybackControlEvent notification, CancellationToken cancellationToken) { await ControlPlayback(notification.PlaybackControl); } private async Task ControlPlayback(PlaybackControlEnum controlEnum) { var isCtrlPressed = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl); var step = isCtrlPressed ? LARGE_STEP : STEP; switch (controlEnum) { case PlaybackControlEnum.Play: Play(); break; case PlaybackControlEnum.Pause: mediaPlayer.Pause(); if (!mediaPlayer.IsPlaying) mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.AnnotationHelp]); break; case PlaybackControlEnum.Stop: mediaPlayer.Stop(); break; case PlaybackControlEnum.PreviousFrame: mediaPlayer.SetPause(true); mediaPlayer.Time -= step; break; case PlaybackControlEnum.NextFrame: mediaPlayer.SetPause(true); mediaPlayer.Time += step; break; case PlaybackControlEnum.SaveAnnotations: await SaveAnnotations(); break; case PlaybackControlEnum.RemoveSelectedAnns: mainWindow.Editor.RemoveSelectedAnns(); break; case PlaybackControlEnum.RemoveAllAnns: mainWindow.Editor.RemoveAllAnns(); break; case PlaybackControlEnum.None: break; default: throw new ArgumentOutOfRangeException(nameof(controlEnum), controlEnum, null); } } private void Play() { if (mainWindow.LvFiles.SelectedItem == null) return; var fileInfo = (VideoFileInfo)mainWindow.LvFiles.SelectedItem; formState.CurrentFile = fileInfo.Name; mainWindow.LoadExistingAnnotations(); mediaPlayer.Stop(); mediaPlayer.Play(new Media(libVLC, fileInfo.Path)); mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.PauseForAnnotations]); } private async Task SaveAnnotations() { if (string.IsNullOrEmpty(formState.CurrentFile)) return; var fName = formState.GetTimeName(TimeSpan.FromMilliseconds(mediaPlayer.Time)); var currentAnns = mainWindow.Editor.CurrentAnns .Select(x => x.Info.ToLabelCoordinates(mainWindow.Editor.RenderSize, formState.CurrentVideoSize)) .ToList(); var labels = string.Join(Environment.NewLine, currentAnns.Select(x => x.ToString())); if (!Directory.Exists(config.LabelsDirectory)) Directory.CreateDirectory(config.LabelsDirectory); if (!Directory.Exists(config.ImagesDirectory)) Directory.CreateDirectory(config.ImagesDirectory); await File.WriteAllTextAsync($"{config.LabelsDirectory}/{fName}.txt", labels); mediaPlayer.TakeSnapshot(0, $"{config.ImagesDirectory}/{fName}.jpg", 0, 0); mainWindow.Annotations[fName] = currentAnns; mainWindow.Editor.RemoveAllAnns(); mediaPlayer.Play(); } }