video-preview/MainForm.cs

426 lines
13 KiB
C#
Raw Permalink Normal View History

2021-10-03 17:43:59 +00:00
using MediaToolkit;
using MediaToolkit.Model;
using MediaToolkit.Options;
2021-11-03 00:08:07 +00:00
using RyzStudio.IO;
2021-10-03 17:43:59 +00:00
using RyzStudio.Windows.Forms;
using System;
2021-11-07 15:34:55 +00:00
using System.Diagnostics;
2021-10-03 17:43:59 +00:00
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace VideoPreview
{
public partial class MainForm : Form
{
protected readonly Random randy;
protected OptionsForm optionsForm = null;
protected bool isBusy = false;
protected string videoFilename = null;
protected TimeSpan videoDuration = TimeSpan.FromSeconds(0);
public MainForm()
{
InitializeComponent();
textBox1.NormalImage = UIcon.GetIcon("file", 16, UIcon.IconState.Idle);
textBox1.HighlightImage = UIcon.GetIcon("file", 16, UIcon.IconState.Hover);
button2.DefaultImage = button2.DownImage = UIcon.GetIcon("settings", 16, UIcon.IconState.Idle);
button2.OverImage = UIcon.GetIcon("settings", 16, UIcon.IconState.Hover);
button3.DefaultImage = button3.DownImage = UIcon.GetIcon("refresh-cw", 16, UIcon.IconState.Idle);
button3.OverImage = UIcon.GetIcon("refresh-cw", 16, UIcon.IconState.Hover);
button4.DefaultImage = button4.DownImage = UIcon.GetIcon("arrow-right-circle", 16, UIcon.IconState.Idle);
button4.OverImage = UIcon.GetIcon("arrow-right-circle", 16, UIcon.IconState.Hover);
2021-10-03 17:43:59 +00:00
randy = new Random();
textBox1.InnerTextBox.ReadOnly = true;
textBox1.InnerTextBox.BackColor = Color.White;
textBox1.InnerTextBox.TextChanged += textBox1_TextChanged;
}
2021-11-07 15:34:55 +00:00
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
textBox1_TextChanged(null, null);
}
2021-10-03 17:43:59 +00:00
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (this.IsBusy)
{
e.Cancel = true;
return;
}
base.OnFormClosing(e);
}
public bool IsBusy
{
get => isBusy;
set
{
isBusy = value;
ThreadControl.SetValue(pictureBox1, (isBusy ? UIcon.GetImage("loading_block") : null));
2021-10-03 17:43:59 +00:00
ThreadControl.SetEnable(textBox1, !isBusy);
ThreadControl.SetEnable(button1, !isBusy);
ThreadControl.SetEnable(button2, !isBusy);
2021-11-07 15:34:55 +00:00
ThreadControl.SetEnable(button3, !isBusy);
ThreadControl.SetEnable(button4, !isBusy);
2021-10-03 17:43:59 +00:00
}
}
private void Form1_DragOver(object sender, DragEventArgs e)
{
e.Effect = (e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None);
}
private async void Form1_DragDrop(object sender, DragEventArgs e)
{
string[] fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
if (fileList == null)
{
return;
}
if (fileList.Length <= 0)
{
return;
}
await ReadVideoFile(fileList[0]);
}
private async void textBox1_TextChanged(object sender, EventArgs e)
{
2021-11-07 15:34:55 +00:00
bool isValidPath = !string.IsNullOrWhiteSpace(textBox1.Text);
if (!isValidPath)
{
ThreadControl.SetEnable(button3, isValidPath);
ThreadControl.SetEnable(button4, isValidPath);
return;
}
2021-10-03 17:43:59 +00:00
await ReadVideoFile(textBox1.Text);
}
public AppSession CurrentSession { get; set; } = new AppSession();
2021-11-07 15:34:55 +00:00
#region main menu
/// <summary>
/// Refresh
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void refreshToolStripMenuItem_Click(object sender, EventArgs e) => button3_MouseClick(null, null);
/// <summary>
/// Load next file
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void loadNextFileToolStripMenuItem_Click(object sender, EventArgs e) => button4_MouseClick(null, null);
/// <summary>
/// Options
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void optionsToolStripMenuItem_Click(object sender, EventArgs e) => button2_MouseClick(null, null);
/// <summary>
/// View help
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void viewHelpToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
System.Diagnostics.Process.Start(new ProcessStartInfo()
{
FileName = AppResource.AppHelpURL,
UseShellExecute = true
});
}
catch
{
// do nothing
}
}
/// <summary>
/// About
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show(Application.ProductName + " v" + Application.ProductVersion, "About", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
#endregion
2021-11-03 00:08:07 +00:00
/// <summary>
/// Refresh
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void button3_MouseClick(object sender, MouseEventArgs e)
2021-10-03 17:43:59 +00:00
{
2021-11-03 00:31:50 +00:00
if (this.IsBusy) return;
if (string.IsNullOrWhiteSpace(textBox1.Text)) return;
2021-11-03 00:08:07 +00:00
await ReadVideoFile(textBox1.Text);
2021-10-03 17:43:59 +00:00
}
2021-11-03 00:08:07 +00:00
/// <summary>
/// Options
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
2021-10-03 17:43:59 +00:00
private void button2_MouseClick(object sender, MouseEventArgs e)
{
if (this.IsBusy)
{
return;
}
if (optionsForm == null) optionsForm = new OptionsForm(this.CurrentSession);
if (optionsForm.ShowDialog() == DialogResult.OK)
{
this.CurrentSession = optionsForm.Session;
this.TopMost = this.CurrentSession.AlwaysOnTop;
}
}
2021-11-03 00:08:07 +00:00
/// <summary>
/// Next file
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void button4_MouseClick(object sender, MouseEventArgs e)
2021-10-06 11:57:50 +00:00
{
2021-11-03 00:08:07 +00:00
await Task.Run(() =>
{
if (this.IsBusy) return;
if (string.IsNullOrWhiteSpace(textBox1.Text)) return;
string path = AccessibleDirectory.GetNextFile(textBox1.Text, "*.avi;*.mkv;*.mp4;*.ogm;*.mov;*.mpg;*.mpeg");
if (string.IsNullOrWhiteSpace(path)) return;
textBox1.Text = path;
});
}
/// <summary>
/// Close
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_MouseClick(object sender, MouseEventArgs e)
{
this.Close();
2021-10-06 11:57:50 +00:00
}
2021-10-03 17:43:59 +00:00
protected TimeSpan CalcRandomTimeSpan(TimeSpan duration)
{
int mm = randy.Next(0, (int)Math.Floor(duration.TotalMinutes));
int ss = randy.Next(0, duration.Seconds);
return new TimeSpan(0, mm, ss);
}
protected void Clear()
{
videoFilename = null;
videoDuration = TimeSpan.FromSeconds(0);
2021-11-03 00:31:50 +00:00
ThreadControl.SetText(this, AppResource.AppName);
2021-10-06 11:57:50 +00:00
textBox1.Text = string.Empty;
2021-10-03 17:43:59 +00:00
ThreadControl.SetText(label5, "-");
ThreadControl.SetText(label7, "-");
ThreadControl.SetText(label2, "-");
ThreadControl.Clear(flowLayoutPanel1);
}
protected Label CreateLabel(TimeSpan duration)
{
Label label = new Label();
label.Padding = new Padding(0);
label.Margin = new Padding(0, 0, 0, 10);
label.Text = string.Format("{0}h {1}m {2}s", duration.Hours, duration.Minutes, duration.Seconds);
return label;
}
protected PictureBox CreatePictureBox(string filename, int width, int height)
{
PictureBox imageBox = new PictureBox()
{
BackColor = Color.White,
Margin = new Padding(0, 0, 0, 0),
Padding = new Padding(0),
SizeMode = PictureBoxSizeMode.Zoom,
Width = width,
Height = height,
};
imageBox.Load(filename);
return imageBox;
}
protected void DeleteFile(string filename)
{
try
{
File.Delete(filename);
}
catch
{
// do nothing
}
}
protected decimal ParseFrameSizeRatio(string videoSize)
{
if (string.IsNullOrWhiteSpace(videoSize))
{
return 0;
}
string[] parts = videoSize.Trim().Split("x");
if (parts.Length != 2)
{
return 0;
}
int w;
if (!int.TryParse(parts[0], out w))
{
return 0;
}
int h;
if (!int.TryParse(parts[1], out h))
{
return 0;
}
try
{
return decimal.Divide(w, h);
}
catch
{
return 0;
}
}
protected async Task ReadVideoFile(string filename)
{
await Task.Run(() =>
{
2021-11-03 00:08:07 +00:00
if (this.IsBusy) return;
2021-10-03 17:43:59 +00:00
this.IsBusy = true;
Clear();
2021-11-07 14:09:50 +00:00
string ffmpegPath = Path.GetDirectoryName(Application.ExecutablePath) + @"\ffmpeg.exe";
2021-10-03 17:43:59 +00:00
MediaFile inputFile = new MediaFile
{
Filename = filename
};
2021-11-07 14:09:50 +00:00
using (Engine engine = new Engine(ffmpegPath))
2021-10-03 17:43:59 +00:00
{
try
{
engine.GetMetadata(inputFile);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
this.IsBusy = false;
return;
}
}
2021-11-07 15:34:55 +00:00
if (inputFile.Metadata == null)
{
this.IsBusy = false;
return;
}
2021-10-03 17:43:59 +00:00
videoFilename = filename;
videoDuration = inputFile.Metadata.Duration;
2021-11-03 00:31:50 +00:00
ThreadControl.SetText(this, Path.GetFileName(filename) + " - " + AppResource.AppName);
2021-10-06 11:57:50 +00:00
textBox1.Text = videoFilename;
2021-10-03 17:43:59 +00:00
ThreadControl.SetText(label5, inputFile.Metadata.VideoData.Format ?? string.Empty);
ThreadControl.SetText(label7, (inputFile.Metadata.VideoData.FrameSize ?? string.Empty) + " @ " + inputFile.Metadata.VideoData.Fps.ToString() + "FPS");
ThreadControl.SetText(label2, string.Format("{0}h {1}m {2}s", videoDuration.Hours, videoDuration.Minutes, videoDuration.Seconds));
// calculate frame dimensions ratio
decimal frameRatio = ParseFrameSizeRatio(inputFile.Metadata.VideoData.FrameSize);
if (frameRatio <= 0)
{
this.IsBusy = false;
return;
}
int thumbnailWidth = flowLayoutPanel1.ClientSize.Width - flowLayoutPanel1.Padding.Horizontal - SystemInformation.VerticalScrollBarWidth;
int thumbnailHeight = (int)Math.Round(decimal.Divide((decimal)thumbnailWidth, frameRatio));
2021-11-07 14:09:50 +00:00
using (Engine engine = new Engine(ffmpegPath))
2021-10-03 17:43:59 +00:00
{
for (int i = 0; i < this.CurrentSession.NoFrames; i++)
{
TimeSpan ts = CalcRandomTimeSpan(videoDuration);
2021-10-06 11:57:50 +00:00
string thumbnailFilename = Path.ChangeExtension(Path.GetTempFileName(), "jpg");
2021-10-03 17:43:59 +00:00
ConversionOptions options = new ConversionOptions
{
Seek = ts,
CustomWidth = thumbnailWidth,
CustomHeight = thumbnailHeight
};
2021-10-06 11:57:50 +00:00
engine.GetThumbnail(inputFile, new MediaFile { Filename = thumbnailFilename }, options);
2021-10-03 17:43:59 +00:00
2021-10-06 11:57:50 +00:00
PictureBox imageBox = CreatePictureBox(thumbnailFilename, thumbnailWidth, thumbnailHeight);
2021-10-03 17:43:59 +00:00
ThreadControl.Add(flowLayoutPanel1, imageBox);
Label label = CreateLabel(ts);
ThreadControl.Add(flowLayoutPanel1, label);
// clean-up
2021-10-06 11:57:50 +00:00
DeleteFile(thumbnailFilename);
2021-10-03 17:43:59 +00:00
}
}
this.IsBusy = false;
});
}
}
}