Added AutoChapters node

This commit is contained in:
John Andrews
2022-02-21 09:22:01 +13:00
parent 8e91a62b9c
commit df56188363
9 changed files with 665 additions and 1 deletions

View File

@@ -1,6 +1,8 @@
namespace FileFlows.VideoNodes
{
using System.Linq;
using System.Text.RegularExpressions;
internal static class ExtensionMethods
{
public static void AddOrUpdate(this Dictionary<string, object> dict, string key, object value) {
@@ -14,6 +16,12 @@
return str == string.Empty ? null : str;
}
public static bool TryMatch(this Regex regex, string input, out Match match)
{
match = regex.Match(input);
return match.Success;
}
public static IEnumerable<string> SplitCommandLine(this string commandLine)
{
bool inQuotes = false;

View File

@@ -0,0 +1,39 @@
#if(DEBUG)
namespace VideoNodes.Tests
{
using FileFlows.VideoNodes;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
[TestClass]
public class AutoChaptersTests
{
[TestMethod]
public void AutoChaptersTests_Test_01()
{
const string file = @"D:\videos\unprocessed\The IT Crowd - 2x04 - The Dinner Party - No English.mkv";
var vi = new VideoInfoHelper(@"C:\utils\ffmpeg\ffmpeg.exe", new TestLogger());
var vii = vi.Read(file);
AutoChapters node = new();
//node.OutputFile = file + ".sup";
var args = new FileFlows.Plugin.NodeParameters(file, new TestLogger(), false, string.Empty);
args.GetToolPathActual = (string tool) => @"C:\utils\ffmpeg\ffmpeg.exe";
args.TempPath = @"D:\videos\temp";
new VideoFile().Execute(args);
int output = node.Execute(args);
Assert.AreEqual(1, output);
}
}
}
#endif

View File

@@ -392,6 +392,429 @@ namespace VideoNodes.Tests
Assert.AreEqual(1920, vi.VideoStreams[0].Width);
Assert.AreEqual(1080, vi.VideoStreams[0].Height);
}
[TestMethod]
public void VideoInfoTest_Chapters()
{
string ffmpegOutput = @"[matroska,webm @ 00000263322abdc0] Could not find codec parameters for stream 3 (Subtitle: hdmv_pgs_subtitle (pgssub)): unspecified size
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
[matroska,webm @ 00000263322abdc0] Could not find codec parameters for stream 4 (Subtitle: hdmv_pgs_subtitle (pgssub)): unspecified size
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
Input #0, matroska,webm, from 'D:\downloads\sabnzbd\complete\movies\Cast.Away.2000.BluRay.1080p.REMUX.AVC.DTS-HD.MA.5.1-LEGi0N\b0e4afee2ced4ae3a3592b82ae335608.mkv':
Metadata:
encoder : libebml v1.4.2 + libmatroska v1.6.4
creation_time : 2022-02-02T22:32:47.000000Z
Duration: 02:23:46.66, start: 0.000000, bitrate: 38174 kb/s
Chapters:
Chapter #0:0: start 0.000000, end 110.819000
Metadata:
title : Chapter 01
Chapter #0:1: start 110.819000, end 517.851000
Metadata:
title : Chapter 02
Chapter #0:2: start 517.851000, end 743.326000
Metadata:
title : Chapter 03
Chapter #0:3: start 743.326000, end 1061.269000
Metadata:
title : Chapter 04
Chapter #0:4: start 1061.269000, end 1243.534000
Metadata:
title : Chapter 05
Chapter #0:5: start 1243.534000, end 1360.234000
Metadata:
title : Chapter 06
Chapter #0:6: start 1360.234000, end 1545.461000
Metadata:
title : Chapter 07
Chapter #0:7: start 1545.461000, end 1871.620000
Metadata:
title : Chapter 08
Chapter #0:8: start 1871.620000, end 2155.320000
Metadata:
title : Chapter 09
Chapter #0:9: start 2155.320000, end 2375.623000
Metadata:
title : Chapter 10
Chapter #0:10: start 2375.623000, end 2543.207000
Metadata:
title : Chapter 11
Chapter #0:11: start 2543.207000, end 2794.208000
Metadata:
title : Chapter 12
Chapter #0:12: start 2794.208000, end 3109.314000
Metadata:
title : Chapter 13
Chapter #0:13: start 3109.314000, end 3389.052000
Metadata:
title : Chapter 14
Chapter #0:14: start 3389.052000, end 3694.357000
Metadata:
title : Chapter 15
Chapter #0:15: start 3694.357000, end 3873.119000
Metadata:
title : Chapter 16
Chapter #0:16: start 3873.119000, end 4391.846000
Metadata:
title : Chapter 17
Chapter #0:17: start 4391.846000, end 4657.736000
Metadata:
title : Chapter 18
Chapter #0:18: start 4657.736000, end 4749.745000
Metadata:
title : Chapter 19
Chapter #0:19: start 4749.745000, end 4842.045000
Metadata:
title : Chapter 20
Chapter #0:20: start 4842.045000, end 5197.901000
Metadata:
title : Chapter 21
Chapter #0:21: start 5197.901000, end 5640.176000
Metadata:
title : Chapter 22
Chapter #0:22: start 5640.176000, end 6037.365000
Metadata:
title : Chapter 23
Chapter #0:23: start 6037.365000, end 6321.398000
Metadata:
title : Chapter 24
Chapter #0:24: start 6321.398000, end 6458.368000
Metadata:
title : Chapter 25
Chapter #0:25: start 6458.368000, end 6810.470000
Metadata:
title : Chapter 26
Chapter #0:26: start 6810.470000, end 6959.953000
Metadata:
title : Chapter 27
Chapter #0:27: start 6959.953000, end 7499.575000
Metadata:
title : Chapter 28
Chapter #0:28: start 7499.575000, end 7707.575000
Metadata:
title : Chapter 29
Chapter #0:29: start 7707.575000, end 7941.725000
Metadata:
title : Chapter 30
Chapter #0:30: start 7941.725000, end 8214.414000
Metadata:
title : Chapter 31
Chapter #0:31: start 8214.414000, end 8626.656000
Metadata:
title : Chapter 32
Stream #0:0(eng): Video: h264 (High), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc (default)
Metadata:
title : English
BPS : 33666894
DURATION : 02:23:46.618000000
NUMBER_OF_FRAMES: 206832
NUMBER_OF_BYTES : 36303929846
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:1(eng): Audio: dts (DTS-HD MA), 48000 Hz, 5.1(side), s32p (24 bit) (default)
Metadata:
title : English
BPS : 4236399
DURATION : 02:23:46.624000000
NUMBER_OF_FRAMES: 808746
NUMBER_OF_BYTES : 4568228448
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:2(eng): Audio: ac3, 48000 Hz, stereo, fltp, 224 kb/s (comment)
Metadata:
title : English commentary
BPS : 224000
DURATION : 02:23:46.656000000
NUMBER_OF_FRAMES: 269583
NUMBER_OF_BYTES : 241546368
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:3(eng): Subtitle: hdmv_pgs_subtitle
Metadata:
title : English (SDH)
BPS : 25275
DURATION : 02:14:32.439000000
NUMBER_OF_FRAMES: 1740
NUMBER_OF_BYTES : 25504616
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:4(spa): Subtitle: hdmv_pgs_subtitle
Metadata:
title : Spanish
BPS : 21585
DURATION : 02:12:54.884000000
NUMBER_OF_FRAMES: 1412
NUMBER_OF_BYTES : 21517695
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES";
var vi = VideoInfoHelper.ParseOutput(null, ffmpegOutput);
Assert.AreEqual(32, vi.Chapters?.Count ?? 0);
Assert.AreEqual("Chapter 32", vi.Chapters[31].Title);
Assert.AreEqual(TimeSpan.FromSeconds(8214.414000), vi.Chapters[31].Start);
Assert.AreEqual(TimeSpan.FromSeconds(8626.656000), vi.Chapters[31].End);
}
[TestMethod]
public void VideoInfoTest_Chapters_NoStart()
{
string ffmpegOutput = @"[matroska,webm @ 00000263322abdc0] Could not find codec parameters for stream 3 (Subtitle: hdmv_pgs_subtitle (pgssub)): unspecified size
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
[matroska,webm @ 00000263322abdc0] Could not find codec parameters for stream 4 (Subtitle: hdmv_pgs_subtitle (pgssub)): unspecified size
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
Input #0, matroska,webm, from 'D:\downloads\sabnzbd\complete\movies\Cast.Away.2000.BluRay.1080p.REMUX.AVC.DTS-HD.MA.5.1-LEGi0N\b0e4afee2ced4ae3a3592b82ae335608.mkv':
Metadata:
encoder : libebml v1.4.2 + libmatroska v1.6.4
creation_time : 2022-02-02T22:32:47.000000Z
Duration: 02:23:46.66, start: 0.000000, bitrate: 38174 kb/s
Chapters:
Chapter #0:0: end 110.819000
Metadata:
title : Chapter 01
Chapter #0:1: start 110.819000, end 517.851000
Metadata:
title : Chapter 02
Chapter #0:2: start 517.851000, end 743.326000
Metadata:
title : Chapter 03
Chapter #0:3: start 743.326000, end 1061.269000
Metadata:
title : Chapter 04
Chapter #0:4: start 1061.269000, end 1243.534000
Metadata:
title : Chapter 05
Chapter #0:5: start 1243.534000, end 1360.234000
Metadata:
title : Chapter 06
Chapter #0:6: start 1360.234000, end 1545.461000
Metadata:
title : Chapter 07
Chapter #0:7: start 1545.461000, end 1871.620000
Metadata:
title : Chapter 08
Chapter #0:8: start 1871.620000, end 2155.320000
Metadata:
title : Chapter 09
Chapter #0:9: start 2155.320000, end 2375.623000
Metadata:
title : Chapter 10
Chapter #0:10: start 2375.623000, end 2543.207000
Metadata:
title : Chapter 11
Chapter #0:11: start 2543.207000, end 2794.208000
Metadata:
title : Chapter 12
Chapter #0:12: start 2794.208000, end 3109.314000
Metadata:
title : Chapter 13
Chapter #0:13: start 3109.314000, end 3389.052000
Metadata:
title : Chapter 14
Chapter #0:14: start 3389.052000, end 3694.357000
Metadata:
title : Chapter 15
Chapter #0:15: start 3694.357000, end 3873.119000
Metadata:
title : Chapter 16
Chapter #0:16: start 3873.119000, end 4391.846000
Metadata:
title : Chapter 17
Chapter #0:17: start 4391.846000, end 4657.736000
Metadata:
title : Chapter 18
Chapter #0:18: start 4657.736000, end 4749.745000
Metadata:
title : Chapter 19
Chapter #0:19: start 4749.745000, end 4842.045000
Metadata:
title : Chapter 20
Chapter #0:20: start 4842.045000, end 5197.901000
Metadata:
title : Chapter 21
Chapter #0:21: start 5197.901000, end 5640.176000
Metadata:
title : Chapter 22
Chapter #0:22: start 5640.176000, end 6037.365000
Metadata:
title : Chapter 23
Chapter #0:23: start 6037.365000, end 6321.398000
Metadata:
title : Chapter 24
Chapter #0:24: start 6321.398000, end 6458.368000
Metadata:
title : Chapter 25
Chapter #0:25: start 6458.368000, end 6810.470000
Metadata:
title : Chapter 26
Chapter #0:26: start 6810.470000, end 6959.953000
Metadata:
title : Chapter 27
Chapter #0:27: start 6959.953000, end 7499.575000
Metadata:
title : Chapter 28
Chapter #0:28: start 7499.575000, end 7707.575000
Metadata:
title : Chapter 29
Chapter #0:29: start 7707.575000, end 7941.725000
Metadata:
title : Chapter 30
Chapter #0:30: start 7941.725000, end 8214.414000
Metadata:
title : Chapter 31
Chapter #0:31: start 8214.414000, end 8626.656000
Metadata:
title : Chapter 32
Stream #0:0(eng): Video: h264 (High), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc (default)
Metadata:
title : English
BPS : 33666894
DURATION : 02:23:46.618000000
NUMBER_OF_FRAMES: 206832
NUMBER_OF_BYTES : 36303929846
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:1(eng): Audio: dts (DTS-HD MA), 48000 Hz, 5.1(side), s32p (24 bit) (default)
Metadata:
title : English
BPS : 4236399
DURATION : 02:23:46.624000000
NUMBER_OF_FRAMES: 808746
NUMBER_OF_BYTES : 4568228448
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:2(eng): Audio: ac3, 48000 Hz, stereo, fltp, 224 kb/s (comment)
Metadata:
title : English commentary
BPS : 224000
DURATION : 02:23:46.656000000
NUMBER_OF_FRAMES: 269583
NUMBER_OF_BYTES : 241546368
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:3(eng): Subtitle: hdmv_pgs_subtitle
Metadata:
title : English (SDH)
BPS : 25275
DURATION : 02:14:32.439000000
NUMBER_OF_FRAMES: 1740
NUMBER_OF_BYTES : 25504616
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:4(spa): Subtitle: hdmv_pgs_subtitle
Metadata:
title : Spanish
BPS : 21585
DURATION : 02:12:54.884000000
NUMBER_OF_FRAMES: 1412
NUMBER_OF_BYTES : 21517695
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES";
var vi = VideoInfoHelper.ParseOutput(null, ffmpegOutput);
Assert.AreEqual(32, vi.Chapters?.Count ?? 0);
Assert.AreEqual(TimeSpan.FromSeconds(0), vi.Chapters[0].Start);
Assert.AreEqual(TimeSpan.FromSeconds(110.819000), vi.Chapters[0].End);
}
[TestMethod]
public void VideoInfoTest_Chapters_Bad()
{
string ffmpegOutput = @"[matroska,webm @ 00000263322abdc0] Could not find codec parameters for stream 3 (Subtitle: hdmv_pgs_subtitle (pgssub)): unspecified size
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
[matroska,webm @ 00000263322abdc0] Could not find codec parameters for stream 4 (Subtitle: hdmv_pgs_subtitle (pgssub)): unspecified size
Consider increasing the value for the 'analyzeduration' (0) and 'probesize' (5000000) options
Input #0, matroska,webm, from 'D:\downloads\sabnzbd\complete\movies\Cast.Away.2000.BluRay.1080p.REMUX.AVC.DTS-HD.MA.5.1-LEGi0N\b0e4afee2ced4ae3a3592b82ae335608.mkv':
Metadata:
encoder : libebml v1.4.2 + libmatroska v1.6.4
creation_time : 2022-02-02T22:32:47.000000Z
Duration: 02:23:46.66, start: 0.000000, bitrate: 38174 kb/s
Chapters:
Chapter #0:0: end 110.819000
Metadata:
title : Chapter 01
Chapter #0:1: start 110.819000, end 517.851000
Metadata:
title : Chapter 0200, end 5640.176000
Metadata:
title : Chapter 2200, end 7499.575000
Metadata:
title : Chapter 28
Chapter #0:28: start 7499.575000, end 7707.575000
Metadata:
title : Chapter 29
Chapter #0:29: start 7707.575000, end 7941.725000
Metadata:
title : Chapter 30
Chapter #0:30: start 7941.725000, end 8214.414000
Metadata:
title : Chapter 31
Chapter #0:31: start 8214.414000, end 8626.656000
Metadata:
title : Chapter 32
Stream #0:0(eng): Video: h264 (High), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc (default)
Metadata:
title : English
BPS : 33666894
DURATION : 02:23:46.618000000
NUMBER_OF_FRAMES: 206832
NUMBER_OF_BYTES : 36303929846
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:1(eng): Audio: dts (DTS-HD MA), 48000 Hz, 5.1(side), s32p (24 bit) (default)
Metadata:
title : English
BPS : 4236399
DURATION : 02:23:46.624000000
NUMBER_OF_FRAMES: 808746
NUMBER_OF_BYTES : 4568228448
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:2(eng): Audio: ac3, 48000 Hz, stereo, fltp, 224 kb/s (comment)
Metadata:
title : English commentary
BPS : 224000
DURATION : 02:23:46.656000000
NUMBER_OF_FRAMES: 269583
NUMBER_OF_BYTES : 241546368
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:3(eng): Subtitle: hdmv_pgs_subtitle
Metadata:
title : English (SDH)
BPS : 25275
DURATION : 02:14:32.439000000
NUMBER_OF_FRAMES: 1740
NUMBER_OF_BYTES : 25504616
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES
Stream #0:4(spa): Subtitle: hdmv_pgs_subtitle
Metadata:
title : Spanish
BPS : 21585
DURATION : 02:12:54.884000000
NUMBER_OF_FRAMES: 1412
NUMBER_OF_BYTES : 21517695
_STATISTICS_WRITING_APP: mkvmerge v64.0.0 ('Willows') 64-bit
_STATISTICS_WRITING_DATE_UTC: 2022-02-02 22:32:47
_STATISTICS_TAGS: BPS DURATION NUMBER_OF_FRAMES NUMBER_OF_BYTES";
var vi = VideoInfoHelper.ParseOutput(null, ffmpegOutput);
Assert.AreEqual(6, vi.Chapters?.Count ?? 0);
Assert.AreEqual("Chapter 29", vi.Chapters[2].Title);
}
}
}

View File

@@ -10,6 +10,8 @@ namespace FileFlows.VideoNodes
public List<VideoStream> VideoStreams { get; set; } = new List<VideoStream>();
public List<AudioStream> AudioStreams { get; set; } = new List<AudioStream>();
public List<SubtitleStream> SubtitleStreams { get; set; } = new List<SubtitleStream>();
public List<Chapter> Chapters { get; set; } = new List<Chapter>();
}
public class VideoFileStream
@@ -96,4 +98,11 @@ namespace FileFlows.VideoNodes
/// </summary>
public bool Forced { get; set; }
}
public class Chapter
{
public string Title { get; set; }
public TimeSpan Start { get; set; }
public TimeSpan End { get; set; }
}
}

View File

@@ -1,5 +1,6 @@
namespace FileFlows.VideoNodes
{
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
@@ -89,6 +90,8 @@ namespace FileFlows.VideoNodes
vi.Bitrate = float.Parse(brMatch.Value) * 1_000; // to convert to b/s
}
vi.Chapters = ParseChapters(output);
int subtitleIndex = 1;
foreach (Match sm in streamMatches)
{
@@ -135,6 +138,54 @@ namespace FileFlows.VideoNodes
return vi;
}
private static List<Chapter> ParseChapters(string output)
{
try
{
var rgxChatpers = new Regex("(?<=(Chapters:))(.*?)(?=(Stream))", RegexOptions.Singleline);
string strChapters;
if (rgxChatpers.TryMatch(output, out Match matchChapters))
strChapters = matchChapters.Value.Trim();
else
return new List<Chapter>();
var rgxChapter = new Regex("Chapter #(.*?)(?=(Chapter #|$))", RegexOptions.Singleline);
var chapters = new List<Chapter>();
var rgxTitle = new Regex(@"title[\s]*:[\s]*(.*?)$");
var rgxStart = new Regex(@"(?<=(start[\s]))[\d]+\.[\d]+");
var rgxEnd = new Regex(@"(?<=(end[\s]))[\d]+\.[\d]+");
foreach (Match match in rgxChapter.Matches(strChapters))
{
try
{
Chapter chapter = new Chapter();
if (rgxTitle.TryMatch(match.Value.Trim(), out Match title))
chapter.Title = title.Groups[1].Value;
if (rgxStart.TryMatch(match.Value, out Match start))
{
double startSeconds = double.Parse(start.Value);
chapter.Start = TimeSpan.FromSeconds(startSeconds);
}
if (rgxEnd.TryMatch(match.Value, out Match end))
{
double endSeconds = double.Parse(end.Value);
chapter.End = TimeSpan.FromSeconds(endSeconds);
}
if (chapter.Start > TimeSpan.Zero || chapter.End > TimeSpan.Zero)
{
chapters.Add(chapter);
}
}
catch (Exception ) { }
}
return chapters;
}catch (Exception) { return new List<Chapter>(); }
}
public static VideoStream ParseVideoStream(ILogger logger, string info, string fullOutput)
{
// Stream #0:0(eng): Video: h264 (High), yuv420p(tv, bt709/unknown/unknown, progressive), 1920x1080 [SAR 1:1 DAR 16:9], 23.98 fps, 23.98 tbr, 1k tbn (default)

Binary file not shown.

View File

@@ -67,6 +67,21 @@
"Language-Help": "The ISO 639-2 language code to use. \nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes"
}
},
"AutoChapters": {
"Description": "Automatically detect scene changes in the video to generate chapters.",
"Outputs": {
"1": "Chapters generated and saved to temporary file",
"2": "No chapters detected or video already had chapters"
},
"Fields": {
"MinimumLength": "Minimum Length",
"MinimumLength-Suffix": "seconds",
"MinimumLength-Help": "The minimum length of a chapter in seconds",
"Percent": "Percent",
"Percent-Suffix": "%",
"Percent-Help": "The threshold percentage value to use for scene detection changes. A good value is 45%"
}
},
"ComskipChapters": {
"Description": "Uses a comskip EDL file and will create chapters given that EDL comskip file.",
"Outputs": {

View File

@@ -0,0 +1,118 @@
namespace FileFlows.VideoNodes
{
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
public class AutoChapters: EncodingNode
{
public override int Outputs => 2;
[NumberInt(1)]
[DefaultValue(60)]
public int MinimumLength { get; set; } = 60;
[NumberInt(2)]
[DefaultValue(45)]
public int Percent { get; set; } = 45;
public override int Execute(NodeParameters args)
{
string ffmpegExe = GetFFMpegExe(args);
if (string.IsNullOrEmpty(ffmpegExe))
return -1;
VideoInfo videoInfo = GetVideoInfo(args);
if (videoInfo == null)
return -1;
if (videoInfo.Chapters?.Count > 3)
{
args.Logger.ILog(videoInfo.Chapters.Count + " chapters already detected in file");
return 2;
}
string output;
var result = Encode(args, ffmpegExe, new List<string>
{
"-hide_banner",
"-i", args.WorkingFile,
"-filter:v", $"select='gt(scene,{Percent / 100f})',showinfo",
"-f", "null",
"-"
}, out output, updateWorkingFile: false, dontAddInputFile: true);
if(result == false)
{
args.Logger?.WLog("Failed to detect scenes");
return 2;
}
if (MinimumLength < 30)
{
args.Logger?.ILog("Mimium length set to invalid number, defaulting to 60 seconds");
MinimumLength = 60;
}
else
{
args.Logger?.ILog($"Minimum length of chapter {MinimumLength} seconds");
}
StringBuilder metadata = new StringBuilder();
metadata.AppendLine(";FFMETADATA1");
metadata.AppendLine("");
int chapter = 0;
TimeSpan previous = TimeSpan.Zero;
foreach (Match match in Regex.Matches(output, @"(?<=(pts_time:))[\d]+\.[\d]+"))
{
TimeSpan time = TimeSpan.FromSeconds(double.Parse(match.Value));
if(Math.Abs((time - previous).TotalSeconds) < MinimumLength)
continue;
AddChapter(previous, time);
previous = time;
}
var totalTime = TimeSpan.FromSeconds(videoInfo.VideoStreams[0].Duration.TotalSeconds);
if (Math.Abs((totalTime - previous).TotalSeconds) > MinimumLength)
AddChapter(previous, totalTime);
if (chapter == 0)
{
args.Logger?.ILog("No ads found in edl file");
return 2;
}
string tempMetaDataFile = Path.Combine(args.TempPath, Guid.NewGuid().ToString() + ".txt");
File.WriteAllText(tempMetaDataFile, metadata.ToString());
string[] ffArgs = new[] { "-i", tempMetaDataFile, "-map_metadata", "1", "-codec", "copy", "-max_muxing_queue_size", "1024" };
if (Encode(args, ffmpegExe, ffArgs.ToList()))
{
args.Logger?.ILog($"Adding {chapter} chapters to file");
return 1;
}
args.Logger?.ELog("Processing failed");
return -1;
void AddChapter(TimeSpan start, TimeSpan end)
{
metadata.AppendLine("[CHAPTER]");
metadata.AppendLine("TIMEBASE=1/1000");
metadata.AppendLine("START=" + ((int)(start.TotalSeconds * 1000)));
metadata.AppendLine("END=" + ((int)(end.TotalSeconds * 1000)));
metadata.AppendLine("title=Chapter " + (++chapter));
metadata.AppendLine();
}
}
}
}

View File

@@ -61,4 +61,5 @@ scriban
github
normalization
doesn''t
*
*
%