Files
annotations/Azaion.Annotator/MainWindowEventHandler.cs
T
2024-10-25 00:17:24 +03:00

281 lines
10 KiB
C#

using System.IO;
using System.Windows;
using System.Windows.Input;
using Azaion.Annotator.DTO;
using LibVLCSharp.Shared;
using MediatR;
using Microsoft.Extensions.Logging;
namespace Azaion.Annotator;
public class MainWindowEventHandler :
INotificationHandler<KeyEvent>,
INotificationHandler<AnnClassSelectedEvent>,
INotificationHandler<PlaybackControlEvent>,
INotificationHandler<VolumeChangedEvent>
{
private readonly LibVLC _libVLC;
private readonly MediaPlayer _mediaPlayer;
private readonly MainWindow _mainWindow;
private readonly FormState _formState;
private readonly Config _config;
private readonly IMediator _mediator;
private readonly IGalleryManager _galleryManager;
private readonly DatasetExplorer _datasetExplorer;
private readonly ILogger<MainWindowEventHandler> _logger;
private const int STEP = 20;
private const int LARGE_STEP = 5000;
private const int RESULT_WIDTH = 1280;
private readonly Dictionary<Key, PlaybackControlEnum> _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 },
{ Key.PageUp, PlaybackControlEnum.Previous },
{ Key.PageDown, PlaybackControlEnum.Next },
};
public MainWindowEventHandler(LibVLC libVLC,
MediaPlayer mediaPlayer,
MainWindow mainWindow,
FormState formState,
Config config,
IMediator mediator,
IGalleryManager galleryManager,
DatasetExplorer datasetExplorer,
ILogger<MainWindowEventHandler> logger)
{
_libVLC = libVLC;
_mediaPlayer = mediaPlayer;
_mainWindow = mainWindow;
_formState = formState;
_config = config;
_mediator = mediator;
_galleryManager = galleryManager;
_datasetExplorer = datasetExplorer;
_logger = logger;
}
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 (_formState.ActiveWindow != WindowsEnum.Main)
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((AnnotationClass)_mainWindow.LvClasses.Items[keyNumber.Value]);
if (_keysControlEnumDict.TryGetValue(key, out var value))
await ControlPlayback(value);
if (key == Key.A)
await _mediator.Send( new AIDetectEvent(), cancellationToken);
await VolumeControl(key);
}
private async Task VolumeControl(Key key)
{
switch (key)
{
case Key.VolumeMute when _mediaPlayer.Volume == 0:
await ControlPlayback(PlaybackControlEnum.TurnOnVolume);
break;
case Key.VolumeMute:
await ControlPlayback(PlaybackControlEnum.TurnOffVolume);
break;
case Key.Up:
case Key.VolumeUp:
var vUp = Math.Min(100, _mediaPlayer.Volume + 5);
ChangeVolume(vUp);
_mainWindow.Volume.Value = vUp;
break;
case Key.Down:
case Key.VolumeDown:
var vDown = Math.Max(0, _mediaPlayer.Volume - 5);
ChangeVolume(vDown);
_mainWindow.Volume.Value = vDown;
break;
}
}
public async Task Handle(PlaybackControlEvent notification, CancellationToken cancellationToken)
{
await ControlPlayback(notification.PlaybackControl);
_mainWindow.VideoView.Focus();
}
private async Task ControlPlayback(PlaybackControlEnum controlEnum)
{
try
{
var isCtrlPressed = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
var step = isCtrlPressed ? LARGE_STEP : STEP;
switch (controlEnum)
{
case PlaybackControlEnum.Play:
await 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;
_mainWindow.VideoSlider.Value = _mediaPlayer.Position * 100;
break;
case PlaybackControlEnum.NextFrame:
_mediaPlayer.SetPause(true);
_mediaPlayer.Time += step;
_mainWindow.VideoSlider.Value = _mediaPlayer.Position * 100;
break;
case PlaybackControlEnum.SaveAnnotations:
await SaveAnnotations();
break;
case PlaybackControlEnum.RemoveSelectedAnns:
_mainWindow.Editor.RemoveSelectedAnns();
break;
case PlaybackControlEnum.RemoveAllAnns:
_mainWindow.Editor.RemoveAllAnns();
break;
case PlaybackControlEnum.TurnOnVolume:
_mainWindow.TurnOnVolumeBtn.Visibility = Visibility.Collapsed;
_mainWindow.TurnOffVolumeBtn.Visibility = Visibility.Visible;
_mediaPlayer.Volume = _formState.CurrentVolume;
break;
case PlaybackControlEnum.TurnOffVolume:
_mainWindow.TurnOffVolumeBtn.Visibility = Visibility.Collapsed;
_mainWindow.TurnOnVolumeBtn.Visibility = Visibility.Visible;
_formState.CurrentVolume = _mediaPlayer.Volume;
_mediaPlayer.Volume = 0;
break;
case PlaybackControlEnum.Previous:
await NextMedia(isPrevious: true);
break;
case PlaybackControlEnum.Next:
await NextMedia();
break;
case PlaybackControlEnum.None:
break;
default:
throw new ArgumentOutOfRangeException(nameof(controlEnum), controlEnum, null);
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
private async Task NextMedia(bool isPrevious = false)
{
var increment = isPrevious ? -1 : 1;
var check = isPrevious ? -1 : _mainWindow.LvFiles.Items.Count;
if (_mainWindow.LvFiles.SelectedIndex + increment == check)
return;
_mainWindow.LvFiles.SelectedIndex += increment;
await Play();
}
public async Task Handle(VolumeChangedEvent notification, CancellationToken cancellationToken)
{
ChangeVolume(notification.Volume);
await Task.CompletedTask;
}
private void ChangeVolume(int volume)
{
_formState.CurrentVolume = volume;
_mediaPlayer.Volume = volume;
}
private async Task Play()
{
if (_mainWindow.LvFiles.SelectedItem == null)
return;
var mediaInfo = (MediaFileInfo)_mainWindow.LvFiles.SelectedItem;
_formState.CurrentMedia = mediaInfo;
_mediaPlayer.Stop();
_mainWindow.Title = $"Azaion Annotator - {mediaInfo.Name}";
_mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.PauseForAnnotations]);
_mediaPlayer.Play(new Media(_libVLC, mediaInfo.Path));
}
private async Task SaveAnnotations()
{
if (_formState.CurrentMedia == null)
return;
var time = TimeSpan.FromMilliseconds(_mediaPlayer.Time);
var fName = _formState.GetTimeName(time);
var currentAnns = _mainWindow.Editor.CurrentAnns
.Select(x => new YoloLabel(x.Info, _mainWindow.Editor.RenderSize, _formState.CurrentVideoSize))
.ToList();
await YoloLabel.WriteToFile(currentAnns, Path.Combine(_config.LabelsDirectory, $"{fName}.txt"));
var resultHeight = (uint)Math.Round(RESULT_WIDTH / _formState.CurrentVideoSize.Width * _formState.CurrentVideoSize.Height);
await _mainWindow.AddAnnotation(time, currentAnns);
_formState.CurrentMedia.HasAnnotations = _mainWindow.Annotations.Count != 0;
_mainWindow.LvFiles.Items.Refresh();
var isVideo = _formState.CurrentMedia.MediaType == MediaTypes.Video;
var destinationPath = Path.Combine(_config.ImagesDirectory, $"{fName}{(isVideo ? ".jpg" : Path.GetExtension(_formState.CurrentMedia.Path))}");
_mainWindow.Editor.RemoveAllAnns();
if (isVideo)
{
_mediaPlayer.TakeSnapshot(0, destinationPath, RESULT_WIDTH, resultHeight);
_mediaPlayer.Play();
}
else
{
File.Copy(_formState.CurrentMedia.Path, destinationPath, overwrite: true);
await NextMedia();
}
var thumbnailDto = await _galleryManager.CreateThumbnail(destinationPath);
var selectedClass = ((AnnotationClass?)_datasetExplorer.LvClasses.SelectedItem)?.Id;
if (selectedClass != null && (selectedClass == -1 || currentAnns.Any(x => x.ClassNumber == selectedClass)))
_datasetExplorer.ThumbnailsDtos.Insert(0, thumbnailDto);
}
}