mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 14:26:30 +00:00
move Windows app to Windows folder, create folder for Web, create simplest web api service
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
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<KeyEvent>,
|
||||
INotificationHandler<AnnClassSelectedEvent>,
|
||||
INotificationHandler<PlaybackControlEvent>,
|
||||
INotificationHandler<VolumeChangedEvent>
|
||||
{
|
||||
private const int STEP = 20;
|
||||
private const int LARGE_STEP = 5000;
|
||||
private const int RESULT_WIDTH = 1280;
|
||||
|
||||
private static readonly string[] CatchSenders = ["ForegroundWindow", "ScrollViewer", "VideoView"];
|
||||
|
||||
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 }
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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.None:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(controlEnum), controlEnum, null);
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
|
||||
var resultHeight = (uint)Math.Round(RESULT_WIDTH / formState.CurrentVideoSize.Width * formState.CurrentVideoSize.Height);
|
||||
|
||||
mediaPlayer.TakeSnapshot(0, $"{config.ImagesDirectory}/{fName}.jpg", RESULT_WIDTH, resultHeight);
|
||||
|
||||
mainWindow.Annotations[fName] = currentAnns;
|
||||
mainWindow.Editor.RemoveAllAnns();
|
||||
mediaPlayer.Play();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user