aboutsummaryrefslogtreecommitdiff
path: root/DvdLib/Ifo
diff options
context:
space:
mode:
Diffstat (limited to 'DvdLib/Ifo')
-rw-r--r--DvdLib/Ifo/AudioAttributes.cs41
-rw-r--r--DvdLib/Ifo/Cell.cs24
-rw-r--r--DvdLib/Ifo/CellPlaybackInfo.cs54
-rw-r--r--DvdLib/Ifo/CellPositionInfo.cs21
-rw-r--r--DvdLib/Ifo/Chapter.cs21
-rw-r--r--DvdLib/Ifo/Dvd.cs161
-rw-r--r--DvdLib/Ifo/DvdTime.cs34
-rw-r--r--DvdLib/Ifo/PgcCommandTable.cs20
-rw-r--r--DvdLib/Ifo/Program.cs17
-rw-r--r--DvdLib/Ifo/ProgramChain.cs117
-rw-r--r--DvdLib/Ifo/Title.cs64
-rw-r--r--DvdLib/Ifo/UserOperation.cs38
-rw-r--r--DvdLib/Ifo/VideoAttributes.cs51
13 files changed, 663 insertions, 0 deletions
diff --git a/DvdLib/Ifo/AudioAttributes.cs b/DvdLib/Ifo/AudioAttributes.cs
new file mode 100644
index 000000000..5b3b9fd9a
--- /dev/null
+++ b/DvdLib/Ifo/AudioAttributes.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace DvdLib.Ifo
+{
+ public enum AudioCodec
+ {
+ AC3 = 0,
+ MPEG1 = 2,
+ MPEG2ext = 3,
+ LPCM = 4,
+ DTS = 6,
+ }
+
+ public enum ApplicationMode
+ {
+ Unspecified = 0,
+ Karaoke = 1,
+ Surround = 2,
+ }
+
+ public class AudioAttributes
+ {
+ public readonly AudioCodec Codec;
+ public readonly bool MultichannelExtensionPresent;
+ public readonly ApplicationMode Mode;
+ public readonly byte QuantDRC;
+ public readonly byte SampleRate;
+ public readonly byte Channels;
+ public readonly ushort LanguageCode;
+ public readonly byte LanguageExtension;
+ public readonly byte CodeExtension;
+ }
+
+ public class MultiChannelExtension
+ {
+
+ }
+}
diff --git a/DvdLib/Ifo/Cell.cs b/DvdLib/Ifo/Cell.cs
new file mode 100644
index 000000000..d0f442e36
--- /dev/null
+++ b/DvdLib/Ifo/Cell.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace DvdLib.Ifo
+{
+ public class Cell
+ {
+ public CellPlaybackInfo PlaybackInfo { get; private set; }
+ public CellPositionInfo PositionInfo { get; private set; }
+
+ internal void ParsePlayback(BinaryReader br)
+ {
+ PlaybackInfo = new CellPlaybackInfo(br);
+ }
+
+ internal void ParsePosition(BinaryReader br)
+ {
+ PositionInfo = new CellPositionInfo(br);
+ }
+ }
+}
diff --git a/DvdLib/Ifo/CellPlaybackInfo.cs b/DvdLib/Ifo/CellPlaybackInfo.cs
new file mode 100644
index 000000000..ae3883eaa
--- /dev/null
+++ b/DvdLib/Ifo/CellPlaybackInfo.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace DvdLib.Ifo
+{
+ public enum BlockMode
+ {
+ NotInBlock = 0,
+ FirstCell = 1,
+ InBlock = 2,
+ LastCell = 3,
+ }
+
+ public enum BlockType
+ {
+ Normal = 0,
+ Angle = 1,
+ }
+
+ public enum PlaybackMode
+ {
+ Normal = 0,
+ StillAfterEachVOBU = 1,
+ }
+
+ public class CellPlaybackInfo
+ {
+ public readonly BlockMode Mode;
+ public readonly BlockType Type;
+ public readonly bool SeamlessPlay;
+ public readonly bool Interleaved;
+ public readonly bool STCDiscontinuity;
+ public readonly bool SeamlessAngle;
+ public readonly PlaybackMode PlaybackMode;
+ public readonly bool Restricted;
+ public readonly byte StillTime;
+ public readonly byte CommandNumber;
+ public readonly DvdTime PlaybackTime;
+ public readonly uint FirstSector;
+ public readonly uint FirstILVUEndSector;
+ public readonly uint LastVOBUStartSector;
+ public readonly uint LastSector;
+
+ internal CellPlaybackInfo(BinaryReader br)
+ {
+ br.BaseStream.Seek(0x4, SeekOrigin.Current);
+ PlaybackTime = new DvdTime(br.ReadBytes(4));
+ br.BaseStream.Seek(0x10, SeekOrigin.Current);
+ }
+ }
+}
diff --git a/DvdLib/Ifo/CellPositionInfo.cs b/DvdLib/Ifo/CellPositionInfo.cs
new file mode 100644
index 000000000..2e0715940
--- /dev/null
+++ b/DvdLib/Ifo/CellPositionInfo.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace DvdLib.Ifo
+{
+ public class CellPositionInfo
+ {
+ public readonly ushort VOBId;
+ public readonly byte CellId;
+
+ internal CellPositionInfo(BinaryReader br)
+ {
+ VOBId = br.ReadUInt16();
+ br.ReadByte();
+ CellId = br.ReadByte();
+ }
+ }
+}
diff --git a/DvdLib/Ifo/Chapter.cs b/DvdLib/Ifo/Chapter.cs
new file mode 100644
index 000000000..802c6ce62
--- /dev/null
+++ b/DvdLib/Ifo/Chapter.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace DvdLib.Ifo
+{
+ public class Chapter
+ {
+ public ushort ProgramChainNumber { get; private set; }
+ public ushort ProgramNumber { get; private set; }
+ public uint ChapterNumber { get; private set; }
+
+ public Chapter(ushort pgcNum, ushort programNum, uint chapterNum)
+ {
+ ProgramChainNumber = pgcNum;
+ ProgramNumber = programNum;
+ ChapterNumber = chapterNum;
+ }
+ }
+}
diff --git a/DvdLib/Ifo/Dvd.cs b/DvdLib/Ifo/Dvd.cs
new file mode 100644
index 000000000..508c23db4
--- /dev/null
+++ b/DvdLib/Ifo/Dvd.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Diagnostics;
+using MediaBrowser.Model.IO;
+
+namespace DvdLib.Ifo
+{
+ public class Dvd
+ {
+ private readonly ushort _titleSetCount;
+ public readonly List<Title> Titles;
+
+ private ushort _titleCount;
+ public readonly Dictionary<ushort, string> VTSPaths = new Dictionary<ushort, string>();
+ private readonly IFileSystem _fileSystem;
+
+ public Dvd(string path, IFileSystem fileSystem)
+ {
+ _fileSystem = fileSystem;
+ Titles = new List<Title>();
+ var allFiles = _fileSystem.GetFiles(path, true).ToList();
+
+ var vmgPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.IFO", StringComparison.OrdinalIgnoreCase)) ??
+ allFiles.FirstOrDefault(i => string.Equals(i.Name, "VIDEO_TS.BUP", StringComparison.OrdinalIgnoreCase));
+
+ if (vmgPath == null)
+ {
+ var allIfos = allFiles.Where(i => string.Equals(i.Extension, ".ifo", StringComparison.OrdinalIgnoreCase));
+
+ foreach (var ifo in allIfos)
+ {
+ var num = ifo.Name.Split('_').ElementAtOrDefault(1);
+ ushort ifoNumber;
+ var numbersRead = new List<ushort>();
+
+ if (!string.IsNullOrEmpty(num) && ushort.TryParse(num, out ifoNumber) && !numbersRead.Contains(ifoNumber))
+ {
+ ReadVTS(ifoNumber, ifo.FullName);
+ numbersRead.Add(ifoNumber);
+ }
+ }
+ }
+ else
+ {
+ using (var vmgFs = _fileSystem.GetFileStream(vmgPath.FullName, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
+ {
+ using (BigEndianBinaryReader vmgRead = new BigEndianBinaryReader(vmgFs))
+ {
+ vmgFs.Seek(0x3E, SeekOrigin.Begin);
+ _titleSetCount = vmgRead.ReadUInt16();
+
+ // read address of TT_SRPT
+ vmgFs.Seek(0xC4, SeekOrigin.Begin);
+ uint ttSectorPtr = vmgRead.ReadUInt32();
+ vmgFs.Seek(ttSectorPtr * 2048, SeekOrigin.Begin);
+ ReadTT_SRPT(vmgRead);
+ }
+ }
+
+ for (ushort titleSetNum = 1; titleSetNum <= _titleSetCount; titleSetNum++)
+ {
+ ReadVTS(titleSetNum, allFiles);
+ }
+ }
+ }
+
+ private void ReadTT_SRPT(BinaryReader read)
+ {
+ _titleCount = read.ReadUInt16();
+ read.BaseStream.Seek(6, SeekOrigin.Current);
+ for (uint titleNum = 1; titleNum <= _titleCount; titleNum++)
+ {
+ Title t = new Title(titleNum);
+ t.ParseTT_SRPT(read);
+ Titles.Add(t);
+ }
+ }
+
+ private void ReadVTS(ushort vtsNum, List<FileSystemMetadata> allFiles)
+ {
+ var filename = String.Format("VTS_{0:00}_0.IFO", vtsNum);
+
+ var vtsPath = allFiles.FirstOrDefault(i => string.Equals(i.Name, filename, StringComparison.OrdinalIgnoreCase)) ??
+ allFiles.FirstOrDefault(i => string.Equals(i.Name, Path.ChangeExtension(filename, ".bup"), StringComparison.OrdinalIgnoreCase));
+
+ if (vtsPath == null)
+ {
+ throw new FileNotFoundException("Unable to find VTS IFO file");
+ }
+
+ ReadVTS(vtsNum, vtsPath.FullName);
+ }
+
+ private void ReadVTS(ushort vtsNum, string vtsPath)
+ {
+ VTSPaths[vtsNum] = vtsPath;
+
+ using (var vtsFs = _fileSystem.GetFileStream(vtsPath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read))
+ {
+ using (BigEndianBinaryReader vtsRead = new BigEndianBinaryReader(vtsFs))
+ {
+ // Read VTS_PTT_SRPT
+ vtsFs.Seek(0xC8, SeekOrigin.Begin);
+ uint vtsPttSrptSecPtr = vtsRead.ReadUInt32();
+ uint baseAddr = (vtsPttSrptSecPtr * 2048);
+ vtsFs.Seek(baseAddr, SeekOrigin.Begin);
+
+ ushort numTitles = vtsRead.ReadUInt16();
+ vtsRead.ReadUInt16();
+ uint endaddr = vtsRead.ReadUInt32();
+ uint[] offsets = new uint[numTitles];
+ for (ushort titleNum = 0; titleNum < numTitles; titleNum++)
+ {
+ offsets[titleNum] = vtsRead.ReadUInt32();
+ }
+
+ for (uint titleNum = 0; titleNum < numTitles; titleNum++)
+ {
+ uint chapNum = 1;
+ vtsFs.Seek(baseAddr + offsets[titleNum], SeekOrigin.Begin);
+ Title t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum + 1));
+ if (t == null) continue;
+
+ do
+ {
+ t.Chapters.Add(new Chapter(vtsRead.ReadUInt16(), vtsRead.ReadUInt16(), chapNum));
+ if (titleNum + 1 < numTitles && vtsFs.Position == (baseAddr + offsets[titleNum + 1])) break;
+ chapNum++;
+ }
+ while (vtsFs.Position < (baseAddr + endaddr));
+ }
+
+ // Read VTS_PGCI
+ vtsFs.Seek(0xCC, SeekOrigin.Begin);
+ uint vtsPgciSecPtr = vtsRead.ReadUInt32();
+ vtsFs.Seek(vtsPgciSecPtr * 2048, SeekOrigin.Begin);
+
+ long startByte = vtsFs.Position;
+
+ ushort numPgcs = vtsRead.ReadUInt16();
+ vtsFs.Seek(6, SeekOrigin.Current);
+ for (ushort pgcNum = 1; pgcNum <= numPgcs; pgcNum++)
+ {
+ byte pgcCat = vtsRead.ReadByte();
+ bool entryPgc = (pgcCat & 0x80) != 0;
+ uint titleNum = (uint)(pgcCat & 0x7F);
+
+ vtsFs.Seek(3, SeekOrigin.Current);
+ uint vtsPgcOffset = vtsRead.ReadUInt32();
+
+ Title t = Titles.FirstOrDefault(vtst => vtst.IsVTSTitle(vtsNum, titleNum));
+ if (t != null) t.AddPgc(vtsRead, startByte + vtsPgcOffset, entryPgc, pgcNum);
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/DvdLib/Ifo/DvdTime.cs b/DvdLib/Ifo/DvdTime.cs
new file mode 100644
index 000000000..f565f5fdf
--- /dev/null
+++ b/DvdLib/Ifo/DvdTime.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace DvdLib.Ifo
+{
+ public class DvdTime
+ {
+ public readonly byte Hour, Minute, Second, Frames, FrameRate;
+
+ public DvdTime(byte[] data)
+ {
+ Hour = GetBCDValue(data[0]);
+ Minute = GetBCDValue(data[1]);
+ Second = GetBCDValue(data[2]);
+ Frames = GetBCDValue((byte)(data[3] & 0x3F));
+
+ if ((data[3] & 0x80) != 0) FrameRate = 30;
+ else if ((data[3] & 0x40) != 0) FrameRate = 25;
+ }
+
+ private byte GetBCDValue(byte data)
+ {
+ return (byte)((((data & 0xF0) >> 4) * 10) + (data & 0x0F));
+ }
+
+ public static explicit operator TimeSpan(DvdTime time)
+ {
+ int ms = (int)(((1.0 / (double)time.FrameRate) * time.Frames) * 1000.0);
+ return new TimeSpan(0, time.Hour, time.Minute, time.Second, ms);
+ }
+ }
+}
diff --git a/DvdLib/Ifo/PgcCommandTable.cs b/DvdLib/Ifo/PgcCommandTable.cs
new file mode 100644
index 000000000..2ead78cef
--- /dev/null
+++ b/DvdLib/Ifo/PgcCommandTable.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace DvdLib.Ifo
+{
+ public class ProgramChainCommandTable
+ {
+ public readonly ushort LastByteAddress;
+ public readonly List<VirtualMachineCommand> PreCommands;
+ public readonly List<VirtualMachineCommand> PostCommands;
+ public readonly List<VirtualMachineCommand> CellCommands;
+ }
+
+ public class VirtualMachineCommand
+ {
+ public readonly byte[] Command;
+ }
+}
diff --git a/DvdLib/Ifo/Program.cs b/DvdLib/Ifo/Program.cs
new file mode 100644
index 000000000..48870d9dd
--- /dev/null
+++ b/DvdLib/Ifo/Program.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace DvdLib.Ifo
+{
+ public class Program
+ {
+ public readonly List<Cell> Cells;
+
+ public Program(List<Cell> cells)
+ {
+ Cells = cells;
+ }
+ }
+}
diff --git a/DvdLib/Ifo/ProgramChain.cs b/DvdLib/Ifo/ProgramChain.cs
new file mode 100644
index 000000000..3179f73cd
--- /dev/null
+++ b/DvdLib/Ifo/ProgramChain.cs
@@ -0,0 +1,117 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace DvdLib.Ifo
+{
+ public enum ProgramPlaybackMode
+ {
+ Sequential,
+ Random,
+ Shuffle
+ }
+
+ public class ProgramChain
+ {
+ private ushort _unknown1;
+
+ private byte _programCount;
+ public readonly List<Program> Programs;
+
+ private byte _cellCount;
+ public readonly List<Cell> Cells;
+
+ public DvdTime PlaybackTime { get; private set; }
+ public UserOperation ProhibitedUserOperations { get; private set; }
+ public byte[] AudioStreamControl { get; private set; } // 8*2 entries
+ public byte[] SubpictureStreamControl { get; private set; } // 32*4 entries
+
+ private ushort _nextProgramNumber;
+ public readonly ProgramChain Next;
+
+ private ushort _prevProgramNumber;
+ public readonly ProgramChain Previous;
+
+ private ushort _goupProgramNumber;
+ public readonly ProgramChain Goup; // ?? maybe Group
+
+ private byte _playbackMode;
+ public ProgramPlaybackMode PlaybackMode { get; private set; }
+ public uint ProgramCount { get; private set; }
+
+ public byte StillTime { get; private set; }
+ public byte[] Palette { get; private set; } // 16*4 entries
+
+ private ushort _commandTableOffset;
+ public readonly ProgramChainCommandTable CommandTable;
+
+ private ushort _programMapOffset;
+ private ushort _cellPlaybackOffset;
+ private ushort _cellPositionOffset;
+
+ public readonly uint VideoTitleSetIndex;
+
+ internal ProgramChain(uint vtsPgcNum)
+ {
+ VideoTitleSetIndex = vtsPgcNum;
+ Cells = new List<Cell>();
+ Programs = new List<Program>();
+ }
+
+ internal void ParseHeader(BinaryReader br)
+ {
+ long startPos = br.BaseStream.Position;
+
+ br.ReadUInt16();
+ _programCount = br.ReadByte();
+ _cellCount = br.ReadByte();
+ PlaybackTime = new DvdTime(br.ReadBytes(4));
+ ProhibitedUserOperations = (UserOperation)br.ReadUInt32();
+ AudioStreamControl = br.ReadBytes(16);
+ SubpictureStreamControl = br.ReadBytes(128);
+
+ _nextProgramNumber = br.ReadUInt16();
+ _prevProgramNumber = br.ReadUInt16();
+ _goupProgramNumber = br.ReadUInt16();
+
+ StillTime = br.ReadByte();
+ byte pbMode = br.ReadByte();
+ if (pbMode == 0) PlaybackMode = ProgramPlaybackMode.Sequential;
+ else PlaybackMode = ((pbMode & 0x80) == 0) ? ProgramPlaybackMode.Random : ProgramPlaybackMode.Shuffle;
+ ProgramCount = (uint)(pbMode & 0x7F);
+
+ Palette = br.ReadBytes(64);
+ _commandTableOffset = br.ReadUInt16();
+ _programMapOffset = br.ReadUInt16();
+ _cellPlaybackOffset = br.ReadUInt16();
+ _cellPositionOffset = br.ReadUInt16();
+
+ // read position info
+ br.BaseStream.Seek(startPos + _cellPositionOffset, SeekOrigin.Begin);
+ for (int cellNum = 0; cellNum < _cellCount; cellNum++)
+ {
+ Cell c = new Cell();
+ c.ParsePosition(br);
+ Cells.Add(c);
+ }
+
+ br.BaseStream.Seek(startPos + _cellPlaybackOffset, SeekOrigin.Begin);
+ for (int cellNum = 0; cellNum < _cellCount; cellNum++)
+ {
+ Cells[cellNum].ParsePlayback(br);
+ }
+
+ br.BaseStream.Seek(startPos + _programMapOffset, SeekOrigin.Begin);
+ List<int> cellNumbers = new List<int>();
+ for (int progNum = 0; progNum < _programCount; progNum++) cellNumbers.Add(br.ReadByte() - 1);
+
+ for (int i = 0; i < cellNumbers.Count; i++)
+ {
+ int max = (i + 1 == cellNumbers.Count) ? _cellCount : cellNumbers[i+1];
+ Programs.Add(new Program(Cells.Where((c, idx) => idx >= cellNumbers[i] && idx < max).ToList()));
+ }
+ }
+ }
+}
diff --git a/DvdLib/Ifo/Title.cs b/DvdLib/Ifo/Title.cs
new file mode 100644
index 000000000..70deb45bf
--- /dev/null
+++ b/DvdLib/Ifo/Title.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace DvdLib.Ifo
+{
+ public class Title
+ {
+ public uint TitleNumber { get; private set; }
+ public uint AngleCount { get; private set; }
+ public ushort ChapterCount { get; private set; }
+ public byte VideoTitleSetNumber { get; private set; }
+
+ private ushort _parentalManagementMask;
+ private byte _titleNumberInVTS;
+ private uint _vtsStartSector; // relative to start of entire disk
+
+ public ProgramChain EntryProgramChain { get; private set; }
+ public readonly List<ProgramChain> ProgramChains;
+
+ public readonly List<Chapter> Chapters;
+
+ public Title(uint titleNum)
+ {
+ ProgramChains = new List<ProgramChain>();
+ Chapters = new List<Chapter>();
+ Chapters = new List<Chapter>();
+ TitleNumber = titleNum;
+ }
+
+ public bool IsVTSTitle(uint vtsNum, uint vtsTitleNum)
+ {
+ return (vtsNum == VideoTitleSetNumber && vtsTitleNum == _titleNumberInVTS);
+ }
+
+ internal void ParseTT_SRPT(BinaryReader br)
+ {
+ byte titleType = br.ReadByte();
+ // TODO parse Title Type
+
+ AngleCount = br.ReadByte();
+ ChapterCount = br.ReadUInt16();
+ _parentalManagementMask = br.ReadUInt16();
+ VideoTitleSetNumber = br.ReadByte();
+ _titleNumberInVTS = br.ReadByte();
+ _vtsStartSector = br.ReadUInt32();
+ }
+
+ internal void AddPgc(BinaryReader br, long startByte, bool entryPgc, uint pgcNum)
+ {
+ long curPos = br.BaseStream.Position;
+ br.BaseStream.Seek(startByte, SeekOrigin.Begin);
+
+ ProgramChain pgc = new ProgramChain(pgcNum);
+ pgc.ParseHeader(br);
+ ProgramChains.Add(pgc);
+ if (entryPgc) EntryProgramChain = pgc;
+
+ br.BaseStream.Seek(curPos, SeekOrigin.Begin);
+ }
+ }
+}
diff --git a/DvdLib/Ifo/UserOperation.cs b/DvdLib/Ifo/UserOperation.cs
new file mode 100644
index 000000000..c3cffd487
--- /dev/null
+++ b/DvdLib/Ifo/UserOperation.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace DvdLib.Ifo
+{
+ [Flags]
+ public enum UserOperation
+ {
+ None = 0,
+ TitleOrTimePlay = 1,
+ ChapterSearchOrPlay = 2,
+ TitlePlay = 4,
+ Stop = 8,
+ GoUp = 16,
+ TimeOrChapterSearch = 32,
+ PrevOrTopProgramSearch = 64,
+ NextProgramSearch = 128,
+ ForwardScan = 256,
+ BackwardScan = 512,
+ TitleMenuCall = 1024,
+ RootMenuCall = 2048,
+ SubpictureMenuCall = 4096,
+ AudioMenuCall = 8192,
+ AngleMenuCall = 16384,
+ ChapterMenuCall = 32768,
+ Resume = 65536,
+ ButtonSelectOrActive = 131072,
+ StillOff = 262144,
+ PauseOn = 524288,
+ AudioStreamChange = 1048576,
+ SubpictureStreamChange = 2097152,
+ AngleChange = 4194304,
+ KaraokeAudioPresentationModeChange = 8388608,
+ VideoPresentationModeChange = 16777216,
+ }
+}
diff --git a/DvdLib/Ifo/VideoAttributes.cs b/DvdLib/Ifo/VideoAttributes.cs
new file mode 100644
index 000000000..b2d375942
--- /dev/null
+++ b/DvdLib/Ifo/VideoAttributes.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace DvdLib.Ifo
+{
+ public enum VideoCodec
+ {
+ MPEG1 = 0,
+ MPEG2 = 1,
+ }
+
+ public enum VideoFormat
+ {
+ NTSC = 0,
+ PAL = 1,
+ }
+
+ public enum AspectRatio
+ {
+ ar4to3 = 0,
+ ar16to9 = 3
+ }
+
+ public enum FilmMode
+ {
+ None = -1,
+ Camera = 0,
+ Film = 1,
+ }
+
+ public class VideoAttributes
+ {
+ public readonly VideoCodec Codec;
+ public readonly VideoFormat Format;
+ public readonly AspectRatio Aspect;
+ public readonly bool AutomaticPanScan;
+ public readonly bool AutomaticLetterBox;
+ public readonly bool Line21CCField1;
+ public readonly bool Line21CCField2;
+ public readonly int Width;
+ public readonly int Height;
+ public readonly bool Letterboxed;
+ public readonly FilmMode FilmMode;
+
+ public VideoAttributes()
+ {
+ }
+ }
+}