mp4ファイルを読み込んでチャプターを作成しテキストファイルとして保存するアプリです。
作成したテキストファイルはフリーウェアソフト「Drax」でmp4ファイルにチャプターをセットします。
作成したテキストファイルはフリーウェアソフト「Drax」でmp4ファイルにチャプターをセットします。
Releases ?? stevie910/drax
Contribute to stevie910/drax development by creating an account on GitHub.
実行環境構築
プロジェクトの作成
mkdir ChapterEditor
cd ChapterEditor
dotnet new winforms
dotnet add package OpenCvSharp4.Windows
dotnet add package OpenCvSharp4.Extensions
dotnet add package OpenCvSharp4.runtime.win
code .
ソースプログラム
namespace ChapterEditor;
using System;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;
public partial class Form1 : Form
{
SplitContainer splitContainer = new SplitContainer
{
Dock = DockStyle.Fill,
Panel1MinSize = 100,
};
PictureBox picbox = new PictureBox
{
Dock = DockStyle.Fill,
AllowDrop = true,
SizeMode = PictureBoxSizeMode.Zoom,
};
FlowLayoutPanel panel = new FlowLayoutPanel
{
Dock = DockStyle.Bottom,
};
TrackBar trackBar = new System.Windows.Forms.TrackBar
{
Value = 1,
Maximum = 1,
Enabled = false,
};
Button addButton = new Button
{
Width = 100,
Height = 40,
Text = "Add",
Enabled = false,
};
Button saveButton = new Button
{
Width = 100,
Height = 40,
Text = "Save",
Enabled = false,
};
ListBox chapterList = new ListBox
{
Dock = DockStyle.Fill,
Sorted = true,
Enabled = false,
};
VideoCapture? vc = null;
string path = "";
string chapter_text_path = "";
string getChapterItem()
{
if (vc == null) return "";
int msec = (int)((1000.0/vc.Fps) * trackBar.Value);
var ts = new TimeSpan(0,0,0,0,msec);
var s = ts.ToString(@"hh\:mm\:ss\.fff") + " " + trackBar.Value;
return s;
}
private void readFrame()
{
if (vc == null) return;
using var mat = new Mat();
if (!vc.Read(mat)) return;
if (!mat.IsContinuous()) return;
picbox.Invoke(new Action(() => {
if (picbox.Image != null) {
picbox.Image.Dispose();
}
picbox.Image = BitmapConverter.ToBitmap(mat);
}));
Text = getChapterItem();
}
public Form1()
{
InitializeComponent();
Controls.Add(splitContainer);
splitContainer.Panel1.Padding = new Padding(10);
splitContainer.Panel2.Padding = new Padding(10);
splitContainer.Panel1.Controls.Add(picbox);
splitContainer.Panel2.Controls.Add(chapterList);
panel.Controls.Add(trackBar);
panel.Controls.Add(addButton);
panel.Controls.Add(saveButton);
Controls.Add(panel);
trackBar.ValueChanged += (s, e) => {
if (vc == null) return;
vc.PosFrames = trackBar.Value;
readFrame();
};
picbox.DragEnter += (o, e) => {
if (e.Data == null) return;
if(!e.Data.GetDataPresent(DataFormats.FileDrop)) return;
e.Effect = DragDropEffects.Copy;
};
picbox.DragDrop += async (sender, e) => {
// ファイルドロップ
if (e.Data == null) return;
if(!e.Data.GetDataPresent(DataFormats.FileDrop)) return;
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
if (files.Length < 1) return;
path = files[0];
// 読み込み
if (picbox.Image != null) picbox.Image.Dispose();
if (vc != null) vc.Dispose();
await Task.Run(()=>{
vc = new VideoCapture(path);
});
if (vc== null || !vc.IsOpened()) return;
trackBar.Maximum = vc.FrameCount;
trackBar.Value = (trackBar.Value > 0) ? 0 : trackBar.Maximum;
var filename = Path.GetFileNameWithoutExtension(path) + ".chapter.txt";
chapter_text_path = Path.GetDirectoryName(path) + "\\" + filename;
chapterList.Items.Clear();
if (File.Exists(chapter_text_path)) {
using var sr = new StreamReader(chapter_text_path);
var line = "";
while ((line = sr.ReadLine()) != null)
chapterList.Items.Add(line);
}
else {
chapterList.Items.Add("00:00:00.000 0");
}
chapterList.Enabled = true;
trackBar.Enabled = true;
addButton.Enabled = true;
saveButton.Enabled = true;
};
addButton.Click += (sender, e) => {
chapterList.Items.Add(getChapterItem());
};
saveButton.Click += (sender, e) => {
using var sw = new StreamWriter(chapter_text_path);
foreach(var line in chapterList.Items)
sw.WriteLine(line);
};
chapterList.SelectedIndexChanged += (sender, e) => {
if (chapterList.SelectedItem == null) return;
var s = chapterList.SelectedItem.ToString();
if (s == null) return;
string[] arr = s.Split(' ');
if (arr.Length < 2) return;
trackBar.Value = int.Parse(arr[1]);
};
chapterList.KeyDown += (sender, e) => {
if (chapterList.Enabled == false || chapterList.SelectedIndex < 1) return;
if (e.KeyCode == Keys.Delete) chapterList.Items.RemoveAt(chapterList.SelectedIndex);
};
this.Load += (sender, e) => {
trackBar.Width = (int)(panel.Width * 0.7);
};
this.Resize += (sender, e) => {
addButton.Width = (int)(panel.Width * 0.1);
saveButton.Width = (int)(panel.Width * 0.1);
trackBar.Width = (int)(panel.Width * 0.7);
};
}// Form1
}// class
実行
dotnet run
使い方
mp4ファイルをドラッグアンドドロップします。
トラックバーを動かすと連動して動画の位置が移動します。
「Add」ボタンを押すと現在位置でチャプターアイテムが追加されます。
チャプターアイテムを選択するとトラックバーが移動します。
チャプターアイテムを選択した状態で「Delete」キーを押すとアイテムが削除されます。
「Save」ボタンを押すとチャプターがテキストファイルとして保存されます。保存場所は動画ファイルと同じ場所に拡張子が.chapter.txtで保存されます。
保存したテキストファイルは「Drax」で動画ファイルにチャプターをセットします。
コメント