public static List <MergePart> GetMergePartsForFilename(string filename, MkvInfo baseInfo) { var result = new List <MergePart>(); var candidates = Directory.GetFiles(Path.GetDirectoryName(filename), "*.mkv"); var loader = new MkvToolNixMkvInfoLoaderStrategy(); foreach (var candidate in candidates) { if (candidate == filename) { continue; } var info = loader.FetchMkvInfo(candidate); var isSafe = false; baseInfo.Chapters.Editions[0].Chapters.ForEach((x => isSafe |= info.SegmentUid.IsSame(x.ReferencedSegmentUid))); if (isSafe) { result.Add(new MergePart(info, candidate)); } } return(result); }
public SelectorDto GetTimecodeAndSegments(MkvInfo info, IList <MergePart> segments, bool forceReorder) { this._segMapping.Clear(); this._timecodes.Clear(); // All chapters var englishChapters = info.Chapters.Editions[0].Chapters.ToList(); englishChapters = englishChapters.Distinct().ToList(); var increasesLinearly = AreChapterStartTimesLinearlyIncreasing(englishChapters); if (!increasesLinearly || forceReorder) { // This means that we'll have to reconstruct the timecodes based on the order in the file // as a best guess.. this would require MkvInfo and can be kind of dangerous as it assumes // all are sequential, but it's the best we can do in many cases. Console.WriteLine("Forced to reorder due to broken file..."); englishChapters = ReOrderChaptersAndTimeCodes(segments, info, englishChapters); } SplitTimecode(info, segments, englishChapters); return(new SelectorDto(this._segMapping, this._timecodes)); }
private List <ChapterAtom> ReOrderChaptersAndTimeCodes(IList <MergePart> segmentParts, MkvInfo baseInfo, List <ChapterAtom> chapters) { var prev = new TimeSpan(); foreach (var chapter in chapters) { // Base info unless we say otherwise... MkvInfo info = null; if (chapter.ReferencedSegmentUid != null) { var segment = segmentParts.First(x => x.Info.SegmentUid.IsSame(chapter.ReferencedSegmentUid)); info = segment.Info; chapter.ChapterTimecodeStart = TimeCodeUtil.TimespanToTimeCode(prev); prev = prev.Add(info.Duration); chapter.ChapterTimecodeEnd = TimeCodeUtil.TimespanToTimeCode(prev); } else { Console.WriteLine("Skipping a chapter from main file; it is presumed to be correct... but it may not be~!"); // Hand over; hopefully it's correct... prev = TimeCodeUtil.TimeCodeToTimespan(chapter.ChapterTimecodeEnd); } } return(chapters); }
public MkvInfo FetchMkvInfo(string file) { var proc = new Process { StartInfo = new ProcessStartInfo("mkvinfo", $"\"{file}\"") { RedirectStandardOutput = true, UseShellExecute = false } }; if (proc == null) { throw new MkvNixException("Failed to find / start mkvinfo"); } proc.Start(); var data = proc.StandardOutput.ReadToEnd(); proc.WaitForExit(); var mapper = new XmlMkvInfoSummaryMapper(); var doc = mapper.DecodeStringIntoDocument(data); // Append some extract MediaInfo data that we might need... :( var mediaInfoProc = new Process { StartInfo = new ProcessStartInfo("mediainfo", $"--Inform=\"Video;%Duration/String3%\" \"{file}\"") { RedirectStandardOutput = true, UseShellExecute = false } }; mediaInfoProc.Start(); var mediaInfoStr = mediaInfoProc.StandardOutput.ReadToEnd(); mediaInfoProc.WaitForExit(); // mediainfo > file > duration... weird format var mkvInfo = new MkvInfo(doc) { Duration = TimeCodeUtil.TimeCodeToTimespan(mediaInfoStr) }; return(mkvInfo); }
public override void PerformExtraction(MkvInfo info, string file) { // Swap to attachments directory CreateAndChangeTo("attachments"); var segment = new MergePart(info, file); var attachmentCount = segment.Info.Attachments.Count; var joinedCounts = ""; for (var i = 0; i < attachmentCount; i++) { joinedCounts += $"{i + 1} "; } var proc = Process.Start("mkvextract", $"attachments \"{segment.Filename}\" {joinedCounts}"); proc.WaitForExit(); }
private void SplitTimecode(MkvInfo info, IList <MergePart> segments, IList <ChapterAtom> chaptersInOrder) { var prev = "00:00:00.000000000"; // This is the index that would have to be "added" onto... we'd always have at least one split var splitIndex = 1; foreach (var chapterAtom in chaptersInOrder) { // A split is required if you're linked; otherwise you can forget it if (chapterAtom.IsLinked()) { if (prev != "00:00:00.000000000") { Console.WriteLine("segment to link!"); this._timecodes.Add(prev); splitIndex++; } var segment = segments.First(x => x.Info.SegmentUid.IsSame(chapterAtom.ReferencedSegmentUid)); this._segMapping.Add(segment.Filename); } else { prev = chapterAtom.ChapterTimecodeEnd; Console.WriteLine("split - original"); // We check the last string to handle the case where the user might have decided // to place chapters next to each other, even if they are adjacenet in the split // which would happen if the episode is split into two parts (Part A + Part B, for example) var filename = $"splits/split-{splitIndex:D3}.mkv"; // for 3 digit splits var lastFilename = this._segMapping.LastOrDefault(); if (filename != lastFilename) { this._segMapping.Add(filename); } } } }
/// <summary> /// Performs the request extract of elements on the given file. /// </summary> public abstract void PerformExtraction(MkvInfo segment, string file);
public MergePart(MkvInfo info, string filename) { Info = info; Filename = filename; }
public void TestStandardMethod() { XmlMkvInfoSummaryMapper mapper = new XmlMkvInfoSummaryMapper(); const string data = @" + EBML head |+ EBML version: 1 |+ EBML read version: 1 |+ EBML maximum ID length: 4 |+ EBML maximum size length: 8 |+ Doc type: matroska |+ Doc type version: 4 |+ Doc type read version: 2 + Segment, size 756458612 |+ Seek head (subentries will be skipped) |+ EbmlVoid (size: 4013) |+ Segment information | + Timecode scale: 1000000 | + Muxing application: libebml v1.3.0 + libmatroska v1.4.0 | + Writing application: mkvmerge v6.0.0 ('Coming Up For Air') built on Jan 20 2013 09:52:00 | + Duration: 1396.360s (00:23:16.360) | + Date: Mon Mar 18 23:40:26 2013 UTC | + Title: Nisemonogatari 01 | + Segment UID: 0xbc 0xfe 0x9f 0x6d 0x5e 0xa3 0xa9 0x70 0x99 0x7c 0x32 0x17 0x3f 0x06 0x60 0x22 |+ Segment tracks | + A track | + Track number: 1 (track ID for mkvmerge & mkvextract: 0) | + Track UID: 3740095644 | + Track type: video | + Lacing flag: 0 | + MinCache: 1 | + Codec ID: V_MPEG4/ISO/AVC | + CodecPrivate, length 47 (h.264 profile: High 10 @L5.0) | + Default duration: 41.708ms (23.976 frames/fields per second for a video track) | + Language: und | + Name: Nisemonogatari 01 | + Video track | + Pixel width: 1920 | + Pixel height: 1080 | + Display width: 1920 | + Display height: 1080 | + A track | + Track number: 2 (track ID for mkvmerge & mkvextract: 1) | + Track UID: 2576664210 | + Track type: audio | + Codec ID: A_FLAC | + CodecPrivate, length 154 | + Default duration: 85.333ms (11.719 frames/fields per second for a video track) | + Language: jpn | + Name: 2.0 FLAC | + Audio track | + Sampling frequency: 48000 | + Channels: 2 | + Bit depth: 16 | + A track | + Track number: 3 (track ID for mkvmerge & mkvextract: 2) | + Track UID: 1317315370984360101 | + Track type: subtitles | + Lacing flag: 0 | + Codec ID: S_TEXT/ASS | + CodecPrivate, length 5185 | + Name: English |+ EbmlVoid (size: 1120) |+ Attachments | + Attached | + File name: Hultog Italic.ttf | + Mime type: application/x-truetype-font | + File data, size: 37372 | + File UID: 2445306772 | + Attached | + File name: Hultog.ttf | + Mime type: application/x-truetype-font | + File data, size: 33296 | + File UID: 2020957090 | + Attached | + File name: AmazGoDa.ttf | + Mime type: application/x-truetype-font | + File data, size: 43044 | + File UID: 3630482355 | + Attached | + File name: AmazGoDaBold.ttf | + Mime type: application/x-truetype-font | + File data, size: 35076 | + File UID: 4075561618 | + Attached | + File name: Andyb.TTF | + Mime type: application/x-truetype-font | + File data, size: 70324 | + File UID: 1824581507 | + Attached | + File name: ANNA.ttf | + Mime type: application/x-truetype-font | + File data, size: 76000 | + File UID: 642960046 | + Attached | + File name: Arena Outline.ttf | + Mime type: application/x-truetype-font | + File data, size: 33233 | + File UID: 186099121 | + Attached | + File name: ariah_.ttf | + Mime type: application/x-truetype-font | + File data, size: 181020 | + File UID: 912525466 | + Attached | + File name: arial.ttf | + Mime type: application/x-truetype-font | + File data, size: 766656 | + File UID: 1718635149 | + Attached | + File name: Arialic Hollow.ttf | + Mime type: application/x-truetype-font | + File data, size: 181020 | + File UID: 1909604002 | + Attached | + File name: ARLRDBD.TTF | + Mime type: application/x-truetype-font | + File data, size: 45260 | + File UID: 64785322 | + Attached | + File name: AUBREY1__.TTF | + Mime type: application/x-truetype-font | + File data, size: 26872 | + File UID: 510261437 | + Attached | + File name: CatShop.ttf | + Mime type: application/x-truetype-font | + File data, size: 79588 | + File UID: 2756332423 | + Attached | + File name: CENTURY.TTF | + Mime type: application/x-truetype-font | + File data, size: 165248 | + File UID: 593692811 | + Attached | + File name: CENTURYO.TTF | + Mime type: application/x-truetype-font | + File data, size: 38128 | + File UID: 3101324205 | + Attached | + File name: Coprgtb.TTF | + Mime type: application/x-truetype-font | + File data, size: 61552 | + File UID: 3011818924 | + Attached | + File name: DanteMTStd-Bold.otf | + Mime type: application/x-truetype-font | + File data, size: 54476 | + File UID: 2857265596 | + Attached | + File name: Disney_Simple.ttf | + Mime type: application/x-truetype-font | + File data, size: 54908 | + File UID: 380671634 | + Attached | + File name: edosz.ttf | + Mime type: application/x-truetype-font | + File data, size: 48820 | + File UID: 1146176129 | + Attached | + File name: Fansub Block-Ozaki.ttf | + Mime type: application/x-truetype-font | + File data, size: 1812 | + File UID: 4251068810 | + Attached | + File name: fansubBlock_0.ttf | + Mime type: application/x-truetype-font | + File data, size: 3364 | + File UID: 3748357566 | + Attached | + File name: FNT_BS.TTF | + Mime type: application/x-truetype-font | + File data, size: 20988 | + File UID: 2420582037 | + Attached | + File name: georgia.ttf | + Mime type: application/x-truetype-font | + File data, size: 157080 | + File UID: 391120276 | + Attached | + File name: GillSansStd.otf | + Mime type: application/x-truetype-font | + File data, size: 28880 | + File UID: 969964701 | + Attached | + File name: GillSansStd-Bold.otf | + Mime type: application/x-truetype-font | + File data, size: 29668 | + File UID: 1400380071 | + Attached | + File name: hongkong.ttf | + Mime type: application/x-truetype-font | + File data, size: 43544 | + File UID: 712839100 | + Attached | + File name: IwaOMinPro-Bd-Fate.ttf | + Mime type: application/x-truetype-font | + File data, size: 700900 | + File UID: 1824292757 | + Attached | + File name: JFRocSol.TTF | + Mime type: application/x-truetype-font | + File data, size: 50284 | + File UID: 1671813507 | + Attached | + File name: jsa_lovechinese.ttf | + Mime type: application/x-truetype-font | + File data, size: 34820 | + File UID: 1847369877 | + Attached | + File name: KGFallForYou.ttf | + Mime type: application/x-truetype-font | + File data, size: 29724 | + File UID: 1050574230 | + Attached | + File name: KIRBY-H.TTF | + Mime type: application/x-truetype-font | + File data, size: 49888 | + File UID: 4280517808 | + Attached | + File name: lightmorning.ttf | + Mime type: application/x-truetype-font | + File data, size: 23516 | + File UID: 2164373178 | + Attached | + File name: mangat.ttf | + Mime type: application/x-truetype-font | + File data, size: 29964 | + File UID: 278465691 | + Attached | + File name: MLSGU.TTF | + Mime type: application/x-truetype-font | + File data, size: 69555 | + File UID: 755965107 | + Attached | + File name: MyriadPro-Bold.otf | + Mime type: application/x-truetype-font | + File data, size: 81436 | + File UID: 616126625 | + Attached | + File name: oakwood.ttf | + Mime type: application/x-truetype-font | + File data, size: 45884 | + File UID: 2952023949 | + Attached | + File name: Old_Rubber_Stamp.ttf | + Mime type: application/x-truetype-font | + File data, size: 42436 | + File UID: 2372587694 | + Attached | + File name: pastel crayon.ttf | + Mime type: application/x-truetype-font | + File data, size: 303164 | + File UID: 741350831 | + Attached | + File name: phillysansps.otf | + Mime type: application/x-truetype-font | + File data, size: 5064 | + File UID: 1617570210 | + Attached | + File name: pixelmix.ttf | + Mime type: application/x-truetype-font | + File data, size: 30232 | + File UID: 872785811 | + Attached | + File name: Plane Crash.ttf | + Mime type: application/x-truetype-font | + File data, size: 286512 | + File UID: 3273697459 | + Attached | + File name: SEVEMFBR.TTF | + Mime type: application/x-truetype-font | + File data, size: 23904 | + File UID: 4132532117 |+ Chapters | + EditionEntry | + EditionFlagOrdered: 1 | + EditionFlagHidden: 0 | + EditionFlagDefault: 1 | + EditionUID: 2906622092 | + ChapterAtom | + ChapterUID: 3143058099 | + ChapterTimeStart: 00:00:00.000000000 | + ChapterTimeEnd: 00:05:56.982000000 | + ChapterFlagHidden: 0 | + ChapterFlagEnabled: 1 | + ChapterDisplay | + ChapterString: Prologue | + ChapterLanguage: eng | + ChapterAtom | + ChapterUID: 3143058098 | + ChapterTimeStart: 00:00:00.000000000 | + ChapterTimeEnd: 00:01:30.048000000 | + ChapterFlagHidden: 0 | + ChapterFlagEnabled: 1 | + ChapterSegmentUID: length 16, data: 0x88 0x79 0x26 0x47 0x4c 0x7d 0x6a 0x4a 0x98 0x4d 0x93 0x8a 0xe8 0xe0 0x11 0x92 | + ChapterDisplay | + ChapterString: Opening | + ChapterLanguage: eng | + ChapterAtom | + ChapterUID: 3143058097 | + ChapterTimeStart: 00:05:57.019000000 | + ChapterTimeEnd: 00:22:40.025000000 | + ChapterFlagHidden: 0 | + ChapterFlagEnabled: 1 | + ChapterDisplay | + ChapterString: Episode | + ChapterLanguage: eng | + ChapterAtom | + ChapterUID: 3143058096 | + ChapterTimeStart: 00:00:00.000000000 | + ChapterTimeEnd: 00:01:30.048000000 | + ChapterFlagHidden: 0 | + ChapterFlagEnabled: 1 | + ChapterSegmentUID: length 16, data: 0xb4 0x6d 0x8b 0x99 0xe1 0x6b 0x17 0x36 0xae 0xe4 0x12 0x1f 0x8a 0x34 0x82 0x79 | + ChapterDisplay | + ChapterString: Ending | + ChapterLanguage: eng | + ChapterAtom | + ChapterUID: 3143058095 | + ChapterTimeStart: 00:22:40.059000000 | + ChapterTimeEnd: 00:23:15.060000000 | + ChapterFlagHidden: 0 | + ChapterFlagEnabled: 1 | + ChapterDisplay | + ChapterString: Preview | + ChapterLanguage: eng |+ EbmlVoid (size: 101) |+ Cluster "; var document = mapper.DecodeStringIntoDocument(data); this._helper.WriteLine(document.ToString()); var info = new MkvInfo(document); // TODO: There's some duplication here as a result of some of the attributes // It won't really affect what I want to do for the application but it might into the future affect // something else as well.. this._helper.WriteLine("!"); }