diff --git a/ChapterInfo.cs b/ChapterInfo.cs index 4d58821..00da258 100644 --- a/ChapterInfo.cs +++ b/ChapterInfo.cs @@ -12,6 +12,7 @@ namespace JarrettVance.ChapterTools public class ChapterInfo { public string Title { get; set; } + public int TitleNumber { get; set; } public int? ChapterSetId { get; set; } public String ImdbId { get; set; } public int? MovieDbId { get; set; } @@ -44,7 +45,7 @@ public bool HasNames() public override string ToString() { - return string.Format("{0}, {1}, {2} chapter(s)", SourceName, Duration.ToShortString(), Chapters.Count); + return string.Format("Title {0} {1}, {2}, {3} chapter(s) ", TitleNumber, SourceName, Duration.ToShortString(), Chapters.Count); } public void ChangeFps(double fps) diff --git a/Extractors/DvdExtractor.cs b/Extractors/DvdExtractor.cs index 477baa2..4b7b6e6 100644 --- a/Extractors/DvdExtractor.cs +++ b/Extractors/DvdExtractor.cs @@ -7,68 +7,69 @@ namespace JarrettVance.ChapterTools.Extractors { - public class DvdExtractor : ChapterExtractor - { - public override string[] Extensions + public class DvdExtractor : ChapterExtractor { - get { return new string[] { }; } - } + public override string[] Extensions + { + get { return new string[] { }; } + } - public override List GetStreams(string location) - { - string path = Path.Combine(location, "VIDEO_TS"); + public override List GetStreams(string location) + { + string path = Path.Combine(location, "VIDEO_TS"); - if (!Directory.Exists(path)) - throw new FileNotFoundException("The VIDEO_TS folder was not found on the DVD."); + if (!Directory.Exists(path)) + throw new FileNotFoundException("The VIDEO_TS folder was not found on the DVD."); - List streams = new List(); + List streams = new List(); - Ifo2Extractor ex = new Ifo2Extractor(); - ex.StreamDetected += (sender, args) => OnStreamDetected(args.ProgramChain); - ex.ChaptersLoaded += (sender, args) => OnChaptersLoaded(args.ProgramChain); + Ifo2Extractor ex = new Ifo2Extractor(); + ex.StreamDetected += (sender, args) => OnStreamDetected(args.ProgramChain); + ex.ChaptersLoaded += (sender, args) => OnChaptersLoaded(args.ProgramChain); - string vol = Pathing.VolumeInfo.GetVolumeLabel(new DirectoryInfo(location)); + string vol = Pathing.VolumeInfo.GetVolumeLabel(new DirectoryInfo(location)); - string videoIFO = Path.Combine(path, "VIDEO_TS.IFO"); - if (File.Exists(videoIFO)) - { - byte[] bytRead = new byte[4]; - long VMG_PTT_STPT_Position = IfoUtil.ToFilePosition(IfoUtil.GetFileBlock(videoIFO, 0xC4, 4)); - int titlePlayMaps = IfoUtil.ToInt16(IfoUtil.GetFileBlock(videoIFO, VMG_PTT_STPT_Position, 2)); - //string longestIfo = GetLongestIFO(videoTSDir); - for (int currentTitle = 1; currentTitle <= titlePlayMaps; ++currentTitle) - { - long titleInfoStart = 8 + ((currentTitle - 1) * 12); - int titleSetNumber = IfoUtil.GetFileBlock(videoIFO, (VMG_PTT_STPT_Position + titleInfoStart) + 6L, 1)[0]; - int titleSetTitleNumber = IfoUtil.GetFileBlock(videoIFO, (VMG_PTT_STPT_Position + titleInfoStart) + 7L, 1)[0]; - string vtsIFO = Path.Combine(path, string.Format("VTS_{0:D2}_0.IFO", titleSetNumber)); - if (!File.Exists(vtsIFO)) - { - Trace.WriteLine(string.Format("VTS IFO file missing: {0}", Path.GetFileName(vtsIFO))); - continue; - } - var pgc = ex.GetStreams(vtsIFO)[0]; - if (string.IsNullOrEmpty(vol)) pgc.VolumeName = vol; - streams.Add(pgc); - } - } - else - { - Trace.WriteLine("VIDEO_TS.IFO file is missing missing on the DVD."); - //read all the ifo files - foreach (string file in Directory.GetFiles(path, "VTS_*_0.IFO")) - { - ChapterInfo pgc = ex.GetStreams(file)[0]; - pgc.SourceName = Path.GetFileNameWithoutExtension(file); - if (!string.IsNullOrEmpty(vol)) pgc.VolumeName = vol; - streams.Add(pgc); - } - } + string videoIFO = Path.Combine(path, "VIDEO_TS.IFO"); + if (File.Exists(videoIFO)) + { + byte[] bytRead = new byte[4]; + long VMG_PTT_STPT_Position = IfoUtil.ToFilePosition(IfoUtil.GetFileBlock(videoIFO, 0xC4, 4)); + int titlePlayMaps = IfoUtil.ToInt16(IfoUtil.GetFileBlock(videoIFO, VMG_PTT_STPT_Position, 2)); + //string longestIfo = GetLongestIFO(videoTSDir); + for (int currentTitle = 1; currentTitle <= titlePlayMaps; ++currentTitle) + { + long titleInfoStart = 8 + ((currentTitle - 1) * 12); + int titleSetNumber = IfoUtil.GetFileBlock(videoIFO, (VMG_PTT_STPT_Position + titleInfoStart) + 6L, 1)[0]; + int titleSetTitleNumber = IfoUtil.GetFileBlock(videoIFO, (VMG_PTT_STPT_Position + titleInfoStart) + 7L, 1)[0]; + string vtsIFO = Path.Combine(path, string.Format("VTS_{0:D2}_0.IFO", titleSetNumber)); + if (!File.Exists(vtsIFO)) + { + Trace.WriteLine(string.Format("VTS IFO file missing: {0}", Path.GetFileName(vtsIFO))); + continue; + } + var pgc = ex.GetStreams(vtsIFO, titleSetTitleNumber); + pgc[0].TitleNumber = currentTitle; + if (string.IsNullOrEmpty(vol)) pgc[0].VolumeName = vol; + streams.Add(pgc[0]); + } + } + else + { + Trace.WriteLine("VIDEO_TS.IFO file is missing missing on the DVD."); + //read all the ifo files + foreach (string file in Directory.GetFiles(path, "VTS_*_0.IFO")) + { + ChapterInfo pgc = ex.GetStreams(file)[0]; + pgc.SourceName = Path.GetFileNameWithoutExtension(file); + if (!string.IsNullOrEmpty(vol)) pgc.VolumeName = vol; + streams.Add(pgc); + } + } - streams = streams.OrderByDescending(p => p.Duration).ToList(); + streams = streams.OrderByDescending(p => p.Duration).ToList(); - OnExtractionComplete(); - return streams; + OnExtractionComplete(); + return streams; + } } - } } diff --git a/Extractors/Ifo2Extractor.cs b/Extractors/Ifo2Extractor.cs index 4c63fd8..d090ff9 100644 --- a/Extractors/Ifo2Extractor.cs +++ b/Extractors/Ifo2Extractor.cs @@ -9,121 +9,153 @@ namespace JarrettVance.ChapterTools.Extractors { - public class Ifo2Extractor : ChapterExtractor - { - public override string[] Extensions + public class Ifo2Extractor : ChapterExtractor { - get { return new string[] { "ifo" }; } - } + public override string[] Extensions + { + get { return new string[] { "ifo" }; } + } - public override bool SupportsMultipleStreams - { - get { return false; } - } + public override bool SupportsMultipleStreams + { + get { return false; } + } - public override List GetStreams(string location) - { - int titleSetNum = 1; - - if (location.StartsWith("VTS_")) - { - titleSetNum = int.Parse(Path.GetFileNameWithoutExtension(location) - .ToUpper() - .Replace("VTS_", string.Empty) - .Replace("_0.IFO", string.Empty)); - } - - ChapterInfo pgc = new ChapterInfo(); - pgc.SourceType = "DVD"; - pgc.SourceName = location; - pgc.SourceHash = ChapterExtractor.ComputeMD5Sum(location); - pgc.Extractor = Application.ProductName + " " + Application.ProductVersion; - pgc.Title = Path.GetFileNameWithoutExtension(location); - OnStreamDetected(pgc); - - TimeSpan duration; - double fps; - pgc.Chapters = GetChapters(location, titleSetNum, out duration, out fps); - pgc.Duration = duration; - pgc.FramesPerSecond = fps; - OnChaptersLoaded(pgc); - - OnExtractionComplete(); - return Enumerable.Repeat(pgc, 1).ToList(); - } + public override List GetStreams(string location) + { + int titleSetNum = 1; - List GetChapters(string ifoFile, int programChain, out TimeSpan duration, out double fps) - { - List chapters = new List(); - duration = TimeSpan.Zero; - fps = 0; - - long pcgITPosition = IfoUtil.GetPCGIP_Position(ifoFile); - int programChainPrograms = -1; - TimeSpan programTime = TimeSpan.Zero; - if (programChain >= 0) - { - double FPS; - uint chainOffset = IfoUtil.GetChainOffset(ifoFile, pcgITPosition, programChain); - programTime = IfoUtil.ReadTimeSpan(ifoFile, pcgITPosition, chainOffset, out FPS) ?? TimeSpan.Zero; - programChainPrograms = IfoUtil.GetNumberOfPrograms(ifoFile, pcgITPosition, chainOffset); - } - else - { - int programChains = IfoUtil.GetProgramChains(ifoFile, pcgITPosition); - for (int curChain = 1; curChain <= programChains; curChain++) + if (location.StartsWith("VTS_")) + { + titleSetNum = int.Parse(Path.GetFileNameWithoutExtension(location) + .ToUpper() + .Replace("VTS_", string.Empty) + .Replace("_0.IFO", string.Empty)); + } + + ChapterInfo pgc = new ChapterInfo(); + pgc.SourceType = "DVD"; + pgc.SourceName = location; + pgc.SourceHash = ChapterExtractor.ComputeMD5Sum(location); + pgc.Extractor = Application.ProductName + " " + Application.ProductVersion; + pgc.Title = Path.GetFileNameWithoutExtension(location); + OnStreamDetected(pgc); + + TimeSpan duration; + double fps; + pgc.Chapters = GetChapters(location, titleSetNum, out duration, out fps); + pgc.Duration = duration; + pgc.FramesPerSecond = fps; + OnChaptersLoaded(pgc); + + OnExtractionComplete(); + return Enumerable.Repeat(pgc, 1).ToList(); + } + + + public List GetStreams(string location, int title) { - double FPS; - uint chainOffset = IfoUtil.GetChainOffset(ifoFile, pcgITPosition, curChain); - TimeSpan? time = IfoUtil.ReadTimeSpan(ifoFile, pcgITPosition, chainOffset, out FPS); - if (time == null) - break; - - if (time.Value > programTime) - { - programChain = curChain; - programChainPrograms = IfoUtil.GetNumberOfPrograms(ifoFile, pcgITPosition, chainOffset); - programTime = time.Value; - } + int titleSetNum = title; + + if (location.StartsWith("VTS_")) + { + titleSetNum = int.Parse(Path.GetFileNameWithoutExtension(location) + .ToUpper() + .Replace("VTS_", string.Empty) + .Replace("_0.IFO", string.Empty)); + } + + ChapterInfo pgc = new ChapterInfo(); + pgc.SourceType = "DVD"; + pgc.SourceName = location; + pgc.SourceHash = ChapterExtractor.ComputeMD5Sum(location); + pgc.Extractor = Application.ProductName + " " + Application.ProductVersion; + pgc.Title = Path.GetFileNameWithoutExtension(location); + OnStreamDetected(pgc); + + TimeSpan duration; + double fps; + pgc.Chapters = GetChapters(location, titleSetNum, out duration, out fps); + pgc.Duration = duration; + pgc.FramesPerSecond = fps; + OnChaptersLoaded(pgc); + + OnExtractionComplete(); + return Enumerable.Repeat(pgc, 1).ToList(); } - } - if (programChain < 0) - return null; - - chapters.Add(new ChapterEntry() { Name = "Chapter 1" }); - - uint longestChainOffset = IfoUtil.GetChainOffset(ifoFile, pcgITPosition, programChain); - int programMapOffset = IfoUtil.ToInt16(IfoUtil.GetFileBlock(ifoFile, (pcgITPosition + longestChainOffset) + 230, 2)); - int cellTableOffset = IfoUtil.ToInt16(IfoUtil.GetFileBlock(ifoFile, (pcgITPosition + longestChainOffset) + 0xE8, 2)); - for (int currentProgram = 0; currentProgram < programChainPrograms; ++currentProgram) - { - int entryCell = IfoUtil.GetFileBlock(ifoFile, ((pcgITPosition + longestChainOffset) + programMapOffset) + currentProgram, 1)[0]; - int exitCell = entryCell; - if (currentProgram < (programChainPrograms - 1)) - exitCell = IfoUtil.GetFileBlock(ifoFile, ((pcgITPosition + longestChainOffset) + programMapOffset) + (currentProgram + 1), 1)[0] - 1; - - TimeSpan totalTime = TimeSpan.Zero; - for (int currentCell = entryCell; currentCell <= exitCell; currentCell++) + + List GetChapters(string ifoFile, int programChain, out TimeSpan duration, out double fps) { - int cellStart = cellTableOffset + ((currentCell - 1) * 0x18); - byte[] bytes = IfoUtil.GetFileBlock(ifoFile, (pcgITPosition + longestChainOffset) + cellStart, 4); - int cellType = bytes[0] >> 6; - if (cellType == 0x00 || cellType == 0x01) - { - bytes = IfoUtil.GetFileBlock(ifoFile, ((pcgITPosition + longestChainOffset) + cellStart) + 4, 4); - TimeSpan time = IfoUtil.ReadTimeSpan(bytes, out fps) ?? TimeSpan.Zero; - totalTime += time; - } + List chapters = new List(); + duration = TimeSpan.Zero; + fps = 0; + + long pcgITPosition = IfoUtil.GetPCGIP_Position(ifoFile); + int programChainPrograms = -1; + TimeSpan programTime = TimeSpan.Zero; + if (programChain >= 0) + { + double FPS; + uint chainOffset = IfoUtil.GetChainOffset(ifoFile, pcgITPosition, programChain); + programTime = IfoUtil.ReadTimeSpan(ifoFile, pcgITPosition, chainOffset, out FPS) ?? TimeSpan.Zero; + programChainPrograms = IfoUtil.GetNumberOfPrograms(ifoFile, pcgITPosition, chainOffset); + } + else + { + int programChains = IfoUtil.GetProgramChains(ifoFile, pcgITPosition); + for (int curChain = 1; curChain <= programChains; curChain++) + { + double FPS; + uint chainOffset = IfoUtil.GetChainOffset(ifoFile, pcgITPosition, curChain); + TimeSpan? time = IfoUtil.ReadTimeSpan(ifoFile, pcgITPosition, chainOffset, out FPS); + if (time == null) + break; + + if (time.Value > programTime) + { + programChain = curChain; + programChainPrograms = IfoUtil.GetNumberOfPrograms(ifoFile, pcgITPosition, chainOffset); + programTime = time.Value; + } + } + } + if (programChain < 0) + return null; + + chapters.Add(new ChapterEntry() { Name = "Chapter 1" }); + + uint longestChainOffset = IfoUtil.GetChainOffset(ifoFile, pcgITPosition, programChain); + int programMapOffset = IfoUtil.ToInt16(IfoUtil.GetFileBlock(ifoFile, (pcgITPosition + longestChainOffset) + 230, 2)); + int cellTableOffset = IfoUtil.ToInt16(IfoUtil.GetFileBlock(ifoFile, (pcgITPosition + longestChainOffset) + 0xE8, 2)); + for (int currentProgram = 0; currentProgram < programChainPrograms; ++currentProgram) + { + int entryCell = IfoUtil.GetFileBlock(ifoFile, ((pcgITPosition + longestChainOffset) + programMapOffset) + currentProgram, 1)[0]; + int exitCell = entryCell; + if (currentProgram < (programChainPrograms - 1)) + exitCell = IfoUtil.GetFileBlock(ifoFile, ((pcgITPosition + longestChainOffset) + programMapOffset) + (currentProgram + 1), 1)[0] - 1; + + TimeSpan totalTime = TimeSpan.Zero; + for (int currentCell = entryCell; currentCell <= exitCell; currentCell++) + { + int cellStart = cellTableOffset + ((currentCell - 1) * 0x18); + byte[] bytes = IfoUtil.GetFileBlock(ifoFile, (pcgITPosition + longestChainOffset) + cellStart, 4); + int cellType = bytes[0] >> 6; + if (cellType == 0x00 || cellType == 0x01) + { + bytes = IfoUtil.GetFileBlock(ifoFile, ((pcgITPosition + longestChainOffset) + cellStart) + 4, 4); + TimeSpan time = IfoUtil.ReadTimeSpan(bytes, out fps) ?? TimeSpan.Zero; + totalTime += time; + } + } + + //add a constant amount of time for each chapter? + //totalTime += TimeSpan.FromMilliseconds(fps != 0 ? (double)1000 / fps / 8D : 0); + + duration += totalTime; + if (currentProgram + 1 < programChainPrograms) + chapters.Add(new ChapterEntry() { Name = string.Format("Chapter {0}", currentProgram + 2), Time = duration }); + } + return chapters; } - - //add a constant amount of time for each chapter? - //totalTime += TimeSpan.FromMilliseconds(fps != 0 ? (double)1000 / fps / 8D : 0); - - duration += totalTime; - if (currentProgram + 1 < programChainPrograms) - chapters.Add(new ChapterEntry() { Name = string.Format("Chapter {0}", currentProgram + 2), Time = duration }); - } - return chapters; } - } } diff --git a/Readme.txt b/Readme.txt index 23f9dec..387d689 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,5 +1,8 @@ ChapterGrabber +2020-07-17: +- added title numbers to DVD information + r4dius fork : -------------------- 2019-09-11 : v5.5