diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..4922421b78
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,230 @@
+#################
+## Eclipse
+#################
+
+*.pydevproject
+.project
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+#################
+## Media Browser
+#################
+ProgramData*/
+ProgramData-Server*/
+ProgramData-UI*/
+
+#################
+## Visual Studio
+#################
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+
+[Dd]ebug/
+[Rr]elease/
+x64/
+build/
+[Bb]in/
+[Oo]bj/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.log
+*.scc
+*.scc
+*.psess
+*.vsp
+*.vspx
+*.orig
+*.rej
+*.sdf
+*.opensdf
+*.ipch
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.Publish.xml
+*.pubxml
+
+# NuGet Packages Directory
+## TODO: If you have NuGet Package Restore enabled, uncomment the next line
+#packages/
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.[Pp]ublish.xml
+*.pfx
+*.publishsettings
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+App_Data/*.mdf
+App_Data/*.ldf
+
+#############
+## Windows detritus
+#############
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Mac crap
+.DS_Store
+
+
+#############
+## Python
+#############
+
+*.py[co]
+
+# Packages
+*.egg
+*.egg-info
+dist/
+build/
+eggs/
+parts/
+var/
+sdist/
+develop-eggs/
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
diff --git a/.hgignore b/.hgignore
index c8162e4c87..c5c5c48773 100644
--- a/.hgignore
+++ b/.hgignore
@@ -1,43 +1,49 @@
-# use glob syntax
-syntax: glob
-
-*.obj
-*.pdb
-*.user
-*.aps
-*.pch
-*.vspscc
-*.vssscc
-*_i.c
-*_p.c
-*.ncb
-*.suo
-*.tlb
-*.tlh
-*.bak
-*.cache
-*.ilk
-*.log
-*.lib
-*.sbr
-*.scc
-*.psess
-*.vsp
-*.orig
-[Bb]in
-[Dd]ebug*/
-obj/
-[Rr]elease*/
-ProgramData*/
-ProgramData-Server*/
-ProgramData-UI*/
-_ReSharper*/
-[Tt]humbs.db
-[Tt]est[Rr]esult*
-[Bb]uild[Ll]og.*
-*.[Pp]ublish.xml
-*.resharper
-
-# ncrunch files
-*.ncrunchsolution
-*.ncrunchproject
+# use glob syntax
+syntax: glob
+
+*.obj
+*.pdb
+*.user
+*.aps
+*.pch
+*.vspscc
+*.vssscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.cache
+*.ilk
+*.log
+*.lib
+*.sbr
+*.scc
+*.psess
+*.vsp
+*.vspx
+*.orig
+*.rej
+*.sdf
+*.opensdf
+*.ipch
+[Bb]in
+[Dd]ebug*/
+obj/
+[Rr]elease*/
+ProgramData*/
+ProgramData-Server*/
+ProgramData-UI*/
+_ReSharper*/
+[Tt]humbs.db
+[Tt]est[Rr]esult*
+[Bb]uild[Ll]og.*
+*.[Pp]ublish.xml
+*.resharper
+
+# ncrunch files
+*.ncrunchsolution
+*.ncrunchproject
+Setup/*
diff --git a/.hgtags b/.hgtags
new file mode 100644
index 0000000000..4972205707
--- /dev/null
+++ b/.hgtags
@@ -0,0 +1,5 @@
+811bcaa9490681194bd72a01c4b0f91d78a0ec97 CO Version 0.12.12.25
+811bcaa9490681194bd72a01c4b0f91d78a0ec97 CO Version 0.12.12.25
+0000000000000000000000000000000000000000 CO Version 0.12.12.25
+0000000000000000000000000000000000000000 CO Version 0.12.12.25
+e98137e38224a0d82cd7d98a71264e0cddc91ca4 CO Version 0.12.12.25
diff --git a/BDInfo/BDInfo.csproj b/BDInfo/BDInfo.csproj
new file mode 100644
index 0000000000..4e57d9e08d
--- /dev/null
+++ b/BDInfo/BDInfo.csproj
@@ -0,0 +1,74 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {07B509C0-0C28-4F3F-8963-5263281F7E3D}
+ Library
+ Properties
+ BDInfo
+ BDInfo
+ v4.5
+ 512
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BDInfo/BDInfoSettings.cs b/BDInfo/BDInfoSettings.cs
new file mode 100644
index 0000000000..108e03af1f
--- /dev/null
+++ b/BDInfo/BDInfoSettings.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BDInfo
+{
+ class BDInfoSettings
+ {
+ public static bool GenerateStreamDiagnostics
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public static bool EnableSSIF
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public static bool AutosaveReport
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public static bool GenerateFrameDataFile
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public static bool FilterLoopingPlaylists
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public static bool FilterShortPlaylists
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public static int FilterShortPlaylistsValue
+ {
+ get
+ {
+ return 0;
+ }
+ }
+
+ public static bool UseImagePrefix
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public static string UseImagePrefixValue
+ {
+ get
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// Setting this to false throws an IComparer error on some discs.
+ ///
+ public static bool KeepStreamOrder
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public static bool GenerateTextSummary
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public static string LastPath
+ {
+ get
+ {
+ return string.Empty;
+ }
+ }
+ }
+}
diff --git a/BDInfo/BDROM.cs b/BDInfo/BDROM.cs
new file mode 100644
index 0000000000..299e7aad70
--- /dev/null
+++ b/BDInfo/BDROM.cs
@@ -0,0 +1,482 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace BDInfo
+{
+ public class BDROM
+ {
+ public DirectoryInfo DirectoryRoot = null;
+ public DirectoryInfo DirectoryBDMV = null;
+ public DirectoryInfo DirectoryBDJO = null;
+ public DirectoryInfo DirectoryCLIPINF = null;
+ public DirectoryInfo DirectoryPLAYLIST = null;
+ public DirectoryInfo DirectorySNP = null;
+ public DirectoryInfo DirectorySSIF = null;
+ public DirectoryInfo DirectorySTREAM = null;
+
+ public string VolumeLabel = null;
+ public ulong Size = 0;
+ public bool IsBDPlus = false;
+ public bool IsBDJava = false;
+ public bool IsDBOX = false;
+ public bool IsPSP = false;
+ public bool Is3D = false;
+ public bool Is50Hz = false;
+
+ public Dictionary PlaylistFiles =
+ new Dictionary();
+ public Dictionary StreamClipFiles =
+ new Dictionary();
+ public Dictionary StreamFiles =
+ new Dictionary();
+ public Dictionary InterleavedFiles =
+ new Dictionary();
+
+ private static List ExcludeDirs = new List { "ANY!", "AACS", "BDSVM", "ANYVM", "SLYVM" };
+
+ public delegate bool OnStreamClipFileScanError(
+ TSStreamClipFile streamClipFile, Exception ex);
+
+ public event OnStreamClipFileScanError StreamClipFileScanError;
+
+ public delegate bool OnStreamFileScanError(
+ TSStreamFile streamClipFile, Exception ex);
+
+ public event OnStreamFileScanError StreamFileScanError;
+
+ public delegate bool OnPlaylistFileScanError(
+ TSPlaylistFile playlistFile, Exception ex);
+
+ public event OnPlaylistFileScanError PlaylistFileScanError;
+
+ public BDROM(
+ string path)
+ {
+ //
+ // Locate BDMV directories.
+ //
+
+ DirectoryBDMV =
+ GetDirectoryBDMV(path);
+
+ if (DirectoryBDMV == null)
+ {
+ throw new Exception("Unable to locate BD structure.");
+ }
+
+ DirectoryRoot =
+ DirectoryBDMV.Parent;
+ DirectoryBDJO =
+ GetDirectory("BDJO", DirectoryBDMV, 0);
+ DirectoryCLIPINF =
+ GetDirectory("CLIPINF", DirectoryBDMV, 0);
+ DirectoryPLAYLIST =
+ GetDirectory("PLAYLIST", DirectoryBDMV, 0);
+ DirectorySNP =
+ GetDirectory("SNP", DirectoryRoot, 0);
+ DirectorySTREAM =
+ GetDirectory("STREAM", DirectoryBDMV, 0);
+ DirectorySSIF =
+ GetDirectory("SSIF", DirectorySTREAM, 0);
+
+ if (DirectoryCLIPINF == null
+ || DirectoryPLAYLIST == null)
+ {
+ throw new Exception("Unable to locate BD structure.");
+ }
+
+ //
+ // Initialize basic disc properties.
+ //
+
+ VolumeLabel = GetVolumeLabel(DirectoryRoot);
+ Size = (ulong)GetDirectorySize(DirectoryRoot);
+
+ if (null != GetDirectory("BDSVM", DirectoryRoot, 0))
+ {
+ IsBDPlus = true;
+ }
+ if (null != GetDirectory("SLYVM", DirectoryRoot, 0))
+ {
+ IsBDPlus = true;
+ }
+ if (null != GetDirectory("ANYVM", DirectoryRoot, 0))
+ {
+ IsBDPlus = true;
+ }
+
+ if (DirectoryBDJO != null &&
+ DirectoryBDJO.GetFiles().Length > 0)
+ {
+ IsBDJava = true;
+ }
+
+ if (DirectorySNP != null &&
+ (DirectorySNP.GetFiles("*.mnv").Length > 0 || DirectorySNP.GetFiles("*.MNV").Length > 0))
+ {
+ IsPSP = true;
+ }
+
+ if (DirectorySSIF != null &&
+ DirectorySSIF.GetFiles().Length > 0)
+ {
+ Is3D = true;
+ }
+
+ if (File.Exists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml")))
+ {
+ IsDBOX = true;
+ }
+
+ //
+ // Initialize file lists.
+ //
+
+ if (DirectoryPLAYLIST != null)
+ {
+ FileInfo[] files = DirectoryPLAYLIST.GetFiles("*.mpls");
+ if (files.Length == 0)
+ {
+ files = DirectoryPLAYLIST.GetFiles("*.MPLS");
+ }
+ foreach (FileInfo file in files)
+ {
+ PlaylistFiles.Add(
+ file.Name.ToUpper(), new TSPlaylistFile(this, file));
+ }
+ }
+
+ if (DirectorySTREAM != null)
+ {
+ FileInfo[] files = DirectorySTREAM.GetFiles("*.m2ts");
+ if (files.Length == 0)
+ {
+ files = DirectoryPLAYLIST.GetFiles("*.M2TS");
+ }
+ foreach (FileInfo file in files)
+ {
+ StreamFiles.Add(
+ file.Name.ToUpper(), new TSStreamFile(file));
+ }
+ }
+
+ if (DirectoryCLIPINF != null)
+ {
+ FileInfo[] files = DirectoryCLIPINF.GetFiles("*.clpi");
+ if (files.Length == 0)
+ {
+ files = DirectoryPLAYLIST.GetFiles("*.CLPI");
+ }
+ foreach (FileInfo file in files)
+ {
+ StreamClipFiles.Add(
+ file.Name.ToUpper(), new TSStreamClipFile(file));
+ }
+ }
+
+ if (DirectorySSIF != null)
+ {
+ FileInfo[] files = DirectorySSIF.GetFiles("*.ssif");
+ if (files.Length == 0)
+ {
+ files = DirectorySSIF.GetFiles("*.SSIF");
+ }
+ foreach (FileInfo file in files)
+ {
+ InterleavedFiles.Add(
+ file.Name.ToUpper(), new TSInterleavedFile(file));
+ }
+ }
+ }
+
+ public void Scan()
+ {
+ List errorStreamClipFiles = new List();
+ foreach (TSStreamClipFile streamClipFile in StreamClipFiles.Values)
+ {
+ try
+ {
+ streamClipFile.Scan();
+ }
+ catch (Exception ex)
+ {
+ errorStreamClipFiles.Add(streamClipFile);
+ if (StreamClipFileScanError != null)
+ {
+ if (StreamClipFileScanError(streamClipFile, ex))
+ {
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else throw ex;
+ }
+ }
+
+ foreach (TSStreamFile streamFile in StreamFiles.Values)
+ {
+ string ssifName = Path.GetFileNameWithoutExtension(streamFile.Name) + ".SSIF";
+ if (InterleavedFiles.ContainsKey(ssifName))
+ {
+ streamFile.InterleavedFile = InterleavedFiles[ssifName];
+ }
+ }
+
+ TSStreamFile[] streamFiles = new TSStreamFile[StreamFiles.Count];
+ StreamFiles.Values.CopyTo(streamFiles, 0);
+ Array.Sort(streamFiles, CompareStreamFiles);
+
+ List errorPlaylistFiles = new List();
+ foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
+ {
+ try
+ {
+ playlistFile.Scan(StreamFiles, StreamClipFiles);
+ }
+ catch (Exception ex)
+ {
+ errorPlaylistFiles.Add(playlistFile);
+ if (PlaylistFileScanError != null)
+ {
+ if (PlaylistFileScanError(playlistFile, ex))
+ {
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else throw ex;
+ }
+ }
+
+ List errorStreamFiles = new List();
+ foreach (TSStreamFile streamFile in streamFiles)
+ {
+ try
+ {
+ List playlists = new List();
+ foreach (TSPlaylistFile playlist in PlaylistFiles.Values)
+ {
+ foreach (TSStreamClip streamClip in playlist.StreamClips)
+ {
+ if (streamClip.Name == streamFile.Name)
+ {
+ playlists.Add(playlist);
+ break;
+ }
+ }
+ }
+ streamFile.Scan(playlists, false);
+ }
+ catch (Exception ex)
+ {
+ errorStreamFiles.Add(streamFile);
+ if (StreamFileScanError != null)
+ {
+ if (StreamFileScanError(streamFile, ex))
+ {
+ continue;
+ }
+ else
+ {
+ break;
+ }
+ }
+ else throw ex;
+ }
+ }
+
+ foreach (TSPlaylistFile playlistFile in PlaylistFiles.Values)
+ {
+ playlistFile.Initialize();
+ if (!Is50Hz)
+ {
+ foreach (TSVideoStream videoStream in playlistFile.VideoStreams)
+ {
+ if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 ||
+ videoStream.FrameRate == TSFrameRate.FRAMERATE_50)
+ {
+ Is50Hz = true;
+ }
+ }
+ }
+ }
+ }
+
+ private DirectoryInfo GetDirectoryBDMV(
+ string path)
+ {
+ DirectoryInfo dir = new DirectoryInfo(path);
+
+ while (dir != null)
+ {
+ if (dir.Name == "BDMV")
+ {
+ return dir;
+ }
+ dir = dir.Parent;
+ }
+
+ return GetDirectory("BDMV", new DirectoryInfo(path), 0);
+ }
+
+ private DirectoryInfo GetDirectory(
+ string name,
+ DirectoryInfo dir,
+ int searchDepth)
+ {
+ if (dir != null)
+ {
+ DirectoryInfo[] children = dir.GetDirectories();
+ foreach (DirectoryInfo child in children)
+ {
+ if (child.Name == name)
+ {
+ return child;
+ }
+ }
+ if (searchDepth > 0)
+ {
+ foreach (DirectoryInfo child in children)
+ {
+ GetDirectory(
+ name, child, searchDepth - 1);
+ }
+ }
+ }
+ return null;
+ }
+
+ private long GetDirectorySize(DirectoryInfo directoryInfo)
+ {
+ long size = 0;
+
+ //if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper())) // TODO: Keep?
+ {
+ FileInfo[] pathFiles = directoryInfo.GetFiles();
+ foreach (FileInfo pathFile in pathFiles)
+ {
+ if (pathFile.Extension.ToUpper() == ".SSIF")
+ {
+ continue;
+ }
+ size += pathFile.Length;
+ }
+
+ DirectoryInfo[] pathChildren = directoryInfo.GetDirectories();
+ foreach (DirectoryInfo pathChild in pathChildren)
+ {
+ size += GetDirectorySize(pathChild);
+ }
+ }
+
+ return size;
+ }
+
+ private string GetVolumeLabel(DirectoryInfo dir)
+ {
+ uint serialNumber = 0;
+ uint maxLength = 0;
+ uint volumeFlags = new uint();
+ StringBuilder volumeLabel = new StringBuilder(256);
+ StringBuilder fileSystemName = new StringBuilder(256);
+ string label = "";
+
+ try
+ {
+ long result = GetVolumeInformation(
+ dir.Name,
+ volumeLabel,
+ (uint)volumeLabel.Capacity,
+ ref serialNumber,
+ ref maxLength,
+ ref volumeFlags,
+ fileSystemName,
+ (uint)fileSystemName.Capacity);
+
+ label = volumeLabel.ToString();
+ }
+ catch { }
+
+ if (label.Length == 0)
+ {
+ label = dir.Name;
+ }
+
+ return label;
+ }
+
+ public static int CompareStreamFiles(
+ TSStreamFile x,
+ TSStreamFile y)
+ {
+ // TODO: Use interleaved file sizes
+
+ if ((x == null || x.FileInfo == null) && (y == null || y.FileInfo == null))
+ {
+ return 0;
+ }
+ else if ((x == null || x.FileInfo == null) && (y != null && y.FileInfo != null))
+ {
+ return 1;
+ }
+ else if ((x != null || x.FileInfo != null) && (y == null || y.FileInfo == null))
+ {
+ return -1;
+ }
+ else
+ {
+ if (x.FileInfo.Length > y.FileInfo.Length)
+ {
+ return 1;
+ }
+ else if (y.FileInfo.Length > x.FileInfo.Length)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+
+ [DllImport("kernel32.dll")]
+ private static extern long GetVolumeInformation(
+ string PathName,
+ StringBuilder VolumeNameBuffer,
+ uint VolumeNameSize,
+ ref uint VolumeSerialNumber,
+ ref uint MaximumComponentLength,
+ ref uint FileSystemFlags,
+ StringBuilder FileSystemNameBuffer,
+ uint FileSystemNameSize);
+ }
+}
diff --git a/BDInfo/LanguageCodes.cs b/BDInfo/LanguageCodes.cs
new file mode 100644
index 0000000000..c4f4dc4a6a
--- /dev/null
+++ b/BDInfo/LanguageCodes.cs
@@ -0,0 +1,496 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public abstract class LanguageCodes
+ {
+ public static string GetName(string code)
+ {
+ switch (code)
+ {
+ case "abk": return "Abkhazian";
+ case "ace": return "Achinese";
+ case "ach": return "Acoli";
+ case "ada": return "Adangme";
+ case "aar": return "Afar";
+ case "afh": return "Afrihili";
+ case "afr": return "Afrikaans";
+ case "afa": return "Afro-Asiatic (Other)";
+ case "aka": return "Akan";
+ case "akk": return "Akkadian";
+ case "alb": return "Albanian";
+ case "sqi": return "Albanian";
+ case "ale": return "Aleut";
+ case "alg": return "Algonquian languages";
+ case "tut": return "Altaic (Other)";
+ case "amh": return "Amharic";
+ case "apa": return "Apache languages";
+ case "ara": return "Arabic";
+ case "arc": return "Aramaic";
+ case "arp": return "Arapaho";
+ case "arn": return "Araucanian";
+ case "arw": return "Arawak";
+ case "arm": return "Armenian";
+ case "hye": return "Armenian";
+ case "art": return "Artificial (Other)";
+ case "asm": return "Assamese";
+ case "ath": return "Athapascan languages";
+ case "aus": return "Australian languages";
+ case "map": return "Austronesian (Other)";
+ case "ava": return "Avaric";
+ case "ave": return "Avestan";
+ case "awa": return "Awadhi";
+ case "aym": return "Aymara";
+ case "aze": return "Azerbaijani";
+ case "ban": return "Balinese";
+ case "bat": return "Baltic (Other)";
+ case "bal": return "Baluchi";
+ case "bam": return "Bambara";
+ case "bai": return "Bamileke languages";
+ case "bad": return "Banda";
+ case "bnt": return "Bantu (Other)";
+ case "bas": return "Basa";
+ case "bak": return "Bashkir";
+ case "baq": return "Basque";
+ case "eus": return "Basque";
+ case "btk": return "Batak (Indonesia)";
+ case "bej": return "Beja";
+ case "bel": return "Belarusian";
+ case "bem": return "Bemba";
+ case "ben": return "Bengali";
+ case "ber": return "Berber (Other)";
+ case "bho": return "Bhojpuri";
+ case "bih": return "Bihari";
+ case "bik": return "Bikol";
+ case "bin": return "Bini";
+ case "bis": return "Bislama";
+ case "bos": return "Bosnian";
+ case "bra": return "Braj";
+ case "bre": return "Breton";
+ case "bug": return "Buginese";
+ case "bul": return "Bulgarian";
+ case "bua": return "Buriat";
+ case "bur": return "Burmese";
+ case "mya": return "Burmese";
+ case "cad": return "Caddo";
+ case "car": return "Carib";
+ case "cat": return "Catalan";
+ case "cau": return "Caucasian (Other)";
+ case "ceb": return "Cebuano";
+ case "cel": return "Celtic (Other)";
+ case "cai": return "Central American Indian (Other)";
+ case "chg": return "Chagatai";
+ case "cmc": return "Chamic languages";
+ case "cha": return "Chamorro";
+ case "che": return "Chechen";
+ case "chr": return "Cherokee";
+ case "chy": return "Cheyenne";
+ case "chb": return "Chibcha";
+ case "chi": return "Chinese";
+ case "zho": return "Chinese";
+ case "chn": return "Chinook jargon";
+ case "chp": return "Chipewyan";
+ case "cho": return "Choctaw";
+ case "chu": return "Church Slavic";
+ case "chk": return "Chuukese";
+ case "chv": return "Chuvash";
+ case "cop": return "Coptic";
+ case "cor": return "Cornish";
+ case "cos": return "Corsican";
+ case "cre": return "Cree";
+ case "mus": return "Creek";
+ case "crp": return "Creoles and pidgins (Other)";
+ case "cpe": return "Creoles and pidgins,";
+ case "cpf": return "Creoles and pidgins,";
+ case "cpp": return "Creoles and pidgins,";
+ case "scr": return "Croatian";
+ case "hrv": return "Croatian";
+ case "cus": return "Cushitic (Other)";
+ case "cze": return "Czech";
+ case "ces": return "Czech";
+ case "dak": return "Dakota";
+ case "dan": return "Danish";
+ case "day": return "Dayak";
+ case "del": return "Delaware";
+ case "din": return "Dinka";
+ case "div": return "Divehi";
+ case "doi": return "Dogri";
+ case "dgr": return "Dogrib";
+ case "dra": return "Dravidian (Other)";
+ case "dua": return "Duala";
+ case "dut": return "Dutch";
+ case "nld": return "Dutch";
+ case "dum": return "Dutch, Middle (ca. 1050-1350)";
+ case "dyu": return "Dyula";
+ case "dzo": return "Dzongkha";
+ case "efi": return "Efik";
+ case "egy": return "Egyptian (Ancient)";
+ case "eka": return "Ekajuk";
+ case "elx": return "Elamite";
+ case "eng": return "English";
+ case "enm": return "English, Middle (1100-1500)";
+ case "ang": return "English, Old (ca.450-1100)";
+ case "epo": return "Esperanto";
+ case "est": return "Estonian";
+ case "ewe": return "Ewe";
+ case "ewo": return "Ewondo";
+ case "fan": return "Fang";
+ case "fat": return "Fanti";
+ case "fao": return "Faroese";
+ case "fij": return "Fijian";
+ case "fin": return "Finnish";
+ case "fiu": return "Finno-Ugrian (Other)";
+ case "fon": return "Fon";
+ case "fre": return "French";
+ case "fra": return "French";
+ case "frm": return "French, Middle (ca.1400-1600)";
+ case "fro": return "French, Old (842-ca.1400)";
+ case "fry": return "Frisian";
+ case "fur": return "Friulian";
+ case "ful": return "Fulah";
+ case "gaa": return "Ga";
+ case "glg": return "Gallegan";
+ case "lug": return "Ganda";
+ case "gay": return "Gayo";
+ case "gba": return "Gbaya";
+ case "gez": return "Geez";
+ case "geo": return "Georgian";
+ case "kat": return "Georgian";
+ case "ger": return "German";
+ case "deu": return "German";
+ case "nds": return "Saxon";
+ case "gmh": return "German, Middle High (ca.1050-1500)";
+ case "goh": return "German, Old High (ca.750-1050)";
+ case "gem": return "Germanic (Other)";
+ case "gil": return "Gilbertese";
+ case "gon": return "Gondi";
+ case "gor": return "Gorontalo";
+ case "got": return "Gothic";
+ case "grb": return "Grebo";
+ case "grc": return "Greek, Ancient (to 1453)";
+ case "gre": return "Greek";
+ case "ell": return "Greek";
+ case "grn": return "Guarani";
+ case "guj": return "Gujarati";
+ case "gwi": return "Gwich´in";
+ case "hai": return "Haida";
+ case "hau": return "Hausa";
+ case "haw": return "Hawaiian";
+ case "heb": return "Hebrew";
+ case "her": return "Herero";
+ case "hil": return "Hiligaynon";
+ case "him": return "Himachali";
+ case "hin": return "Hindi";
+ case "hmo": return "Hiri Motu";
+ case "hit": return "Hittite";
+ case "hmn": return "Hmong";
+ case "hun": return "Hungarian";
+ case "hup": return "Hupa";
+ case "iba": return "Iban";
+ case "ice": return "Icelandic";
+ case "isl": return "Icelandic";
+ case "ibo": return "Igbo";
+ case "ijo": return "Ijo";
+ case "ilo": return "Iloko";
+ case "inc": return "Indic (Other)";
+ case "ine": return "Indo-European (Other)";
+ case "ind": return "Indonesian";
+ case "ina": return "Interlingua (International";
+ case "ile": return "Interlingue";
+ case "iku": return "Inuktitut";
+ case "ipk": return "Inupiaq";
+ case "ira": return "Iranian (Other)";
+ case "gle": return "Irish";
+ case "mga": return "Irish, Middle (900-1200)";
+ case "sga": return "Irish, Old (to 900)";
+ case "iro": return "Iroquoian languages";
+ case "ita": return "Italian";
+ case "jpn": return "Japanese";
+ case "jav": return "Javanese";
+ case "jrb": return "Judeo-Arabic";
+ case "jpr": return "Judeo-Persian";
+ case "kab": return "Kabyle";
+ case "kac": return "Kachin";
+ case "kal": return "Kalaallisut";
+ case "kam": return "Kamba";
+ case "kan": return "Kannada";
+ case "kau": return "Kanuri";
+ case "kaa": return "Kara-Kalpak";
+ case "kar": return "Karen";
+ case "kas": return "Kashmiri";
+ case "kaw": return "Kawi";
+ case "kaz": return "Kazakh";
+ case "kha": return "Khasi";
+ case "khm": return "Khmer";
+ case "khi": return "Khoisan (Other)";
+ case "kho": return "Khotanese";
+ case "kik": return "Kikuyu";
+ case "kmb": return "Kimbundu";
+ case "kin": return "Kinyarwanda";
+ case "kir": return "Kirghiz";
+ case "kom": return "Komi";
+ case "kon": return "Kongo";
+ case "kok": return "Konkani";
+ case "kor": return "Korean";
+ case "kos": return "Kosraean";
+ case "kpe": return "Kpelle";
+ case "kro": return "Kru";
+ case "kua": return "Kuanyama";
+ case "kum": return "Kumyk";
+ case "kur": return "Kurdish";
+ case "kru": return "Kurukh";
+ case "kut": return "Kutenai";
+ case "lad": return "Ladino";
+ case "lah": return "Lahnda";
+ case "lam": return "Lamba";
+ case "lao": return "Lao";
+ case "lat": return "Latin";
+ case "lav": return "Latvian";
+ case "ltz": return "Letzeburgesch";
+ case "lez": return "Lezghian";
+ case "lin": return "Lingala";
+ case "lit": return "Lithuanian";
+ case "loz": return "Lozi";
+ case "lub": return "Luba-Katanga";
+ case "lua": return "Luba-Lulua";
+ case "lui": return "Luiseno";
+ case "lun": return "Lunda";
+ case "luo": return "Luo (Kenya and Tanzania)";
+ case "lus": return "Lushai";
+ case "mac": return "Macedonian";
+ case "mkd": return "Macedonian";
+ case "mad": return "Madurese";
+ case "mag": return "Magahi";
+ case "mai": return "Maithili";
+ case "mak": return "Makasar";
+ case "mlg": return "Malagasy";
+ case "may": return "Malay";
+ case "msa": return "Malay";
+ case "mal": return "Malayalam";
+ case "mlt": return "Maltese";
+ case "mnc": return "Manchu";
+ case "mdr": return "Mandar";
+ case "man": return "Mandingo";
+ case "mni": return "Manipuri";
+ case "mno": return "Manobo languages";
+ case "glv": return "Manx";
+ case "mao": return "Maori";
+ case "mri": return "Maori";
+ case "mar": return "Marathi";
+ case "chm": return "Mari";
+ case "mah": return "Marshall";
+ case "mwr": return "Marwari";
+ case "mas": return "Masai";
+ case "myn": return "Mayan languages";
+ case "men": return "Mende";
+ case "mic": return "Micmac";
+ case "min": return "Minangkabau";
+ case "mis": return "Miscellaneous languages";
+ case "moh": return "Mohawk";
+ case "mol": return "Moldavian";
+ case "mkh": return "Mon-Khmer (Other)";
+ case "lol": return "Mongo";
+ case "mon": return "Mongolian";
+ case "mos": return "Mossi";
+ case "mul": return "Multiple languages";
+ case "mun": return "Munda languages";
+ case "nah": return "Nahuatl";
+ case "nau": return "Nauru";
+ case "nav": return "Navajo";
+ case "nde": return "Ndebele, North";
+ case "nbl": return "Ndebele, South";
+ case "ndo": return "Ndonga";
+ case "nep": return "Nepali";
+ case "new": return "Newari";
+ case "nia": return "Nias";
+ case "nic": return "Niger-Kordofanian (Other)";
+ case "ssa": return "Nilo-Saharan (Other)";
+ case "niu": return "Niuean";
+ case "non": return "Norse, Old";
+ case "nai": return "North American Indian (Other)";
+ case "sme": return "Northern Sami";
+ case "nor": return "Norwegian";
+ case "nob": return "Norwegian Bokmål";
+ case "nno": return "Norwegian Nynorsk";
+ case "nub": return "Nubian languages";
+ case "nym": return "Nyamwezi";
+ case "nya": return "Nyanja";
+ case "nyn": return "Nyankole";
+ case "nyo": return "Nyoro";
+ case "nzi": return "Nzima";
+ case "oci": return "Occitan";
+ case "oji": return "Ojibwa";
+ case "ori": return "Oriya";
+ case "orm": return "Oromo";
+ case "osa": return "Osage";
+ case "oss": return "Ossetian";
+ case "oto": return "Otomian languages";
+ case "pal": return "Pahlavi";
+ case "pau": return "Palauan";
+ case "pli": return "Pali";
+ case "pam": return "Pampanga";
+ case "pag": return "Pangasinan";
+ case "pan": return "Panjabi";
+ case "pap": return "Papiamento";
+ case "paa": return "Papuan (Other)";
+ case "per": return "Persian";
+ case "fas": return "Persian";
+ case "peo": return "Persian, Old (ca.600-400 B.C.)";
+ case "phi": return "Philippine (Other)";
+ case "phn": return "Phoenician";
+ case "pon": return "Pohnpeian";
+ case "pol": return "Polish";
+ case "por": return "Portuguese";
+ case "pra": return "Prakrit languages";
+ case "pro": return "Provençal";
+ case "pus": return "Pushto";
+ case "que": return "Quechua";
+ case "roh": return "Raeto-Romance";
+ case "raj": return "Rajasthani";
+ case "rap": return "Rapanui";
+ case "rar": return "Rarotongan";
+ case "roa": return "Romance (Other)";
+ case "rum": return "Romanian";
+ case "ron": return "Romanian";
+ case "rom": return "Romany";
+ case "run": return "Rundi";
+ case "rus": return "Russian";
+ case "sal": return "Salishan languages";
+ case "sam": return "Samaritan Aramaic";
+ case "smi": return "Sami languages (Other)";
+ case "smo": return "Samoan";
+ case "sad": return "Sandawe";
+ case "sag": return "Sango";
+ case "san": return "Sanskrit";
+ case "sat": return "Santali";
+ case "srd": return "Sardinian";
+ case "sas": return "Sasak";
+ case "sco": return "Scots";
+ case "gla": return "Gaelic";
+ case "sel": return "Selkup";
+ case "sem": return "Semitic (Other)";
+ case "scc": return "Serbian";
+ case "srp": return "Serbian";
+ case "srr": return "Serer";
+ case "shn": return "Shan";
+ case "sna": return "Shona";
+ case "sid": return "Sidamo";
+ case "sgn": return "Sign languages";
+ case "bla": return "Siksika";
+ case "snd": return "Sindhi";
+ case "sin": return "Sinhalese";
+ case "sit": return "Sino-Tibetan (Other)";
+ case "sio": return "Siouan languages";
+ case "den": return "Slave (Athapascan)";
+ case "sla": return "Slavic (Other)";
+ case "slo": return "Slovak";
+ case "slk": return "Slovak";
+ case "slv": return "Slovenian";
+ case "sog": return "Sogdian";
+ case "som": return "Somali";
+ case "son": return "Songhai";
+ case "snk": return "Soninke";
+ case "wen": return "Sorbian languages";
+ case "nso": return "Sotho, Northern";
+ case "sot": return "Sotho, Southern";
+ case "sai": return "South American Indian (Other)";
+ case "spa": return "Spanish";
+ case "suk": return "Sukuma";
+ case "sux": return "Sumerian";
+ case "sun": return "Sundanese";
+ case "sus": return "Susu";
+ case "swa": return "Swahili";
+ case "ssw": return "Swati";
+ case "swe": return "Swedish";
+ case "syr": return "Syriac";
+ case "tgl": return "Tagalog";
+ case "tah": return "Tahitian";
+ case "tai": return "Tai (Other)";
+ case "tgk": return "Tajik";
+ case "tmh": return "Tamashek";
+ case "tam": return "Tamil";
+ case "tat": return "Tatar";
+ case "tel": return "Telugu";
+ case "ter": return "Tereno";
+ case "tet": return "Tetum";
+ case "tha": return "Thai";
+ case "tib": return "Tibetan";
+ case "bod": return "Tibetan";
+ case "tig": return "Tigre";
+ case "tir": return "Tigrinya";
+ case "tem": return "Timne";
+ case "tiv": return "Tiv";
+ case "tli": return "Tlingit";
+ case "tpi": return "Tok Pisin";
+ case "tkl": return "Tokelau";
+ case "tog": return "Tonga (Nyasa)";
+ case "ton": return "Tonga (Tonga Islands)";
+ case "tsi": return "Tsimshian";
+ case "tso": return "Tsonga";
+ case "tsn": return "Tswana";
+ case "tum": return "Tumbuka";
+ case "tur": return "Turkish";
+ case "ota": return "Turkish, Ottoman (1500-1928)";
+ case "tuk": return "Turkmen";
+ case "tvl": return "Tuvalu";
+ case "tyv": return "Tuvinian";
+ case "twi": return "Twi";
+ case "uga": return "Ugaritic";
+ case "uig": return "Uighur";
+ case "ukr": return "Ukrainian";
+ case "umb": return "Umbundu";
+ case "und": return "Undetermined";
+ case "urd": return "Urdu";
+ case "uzb": return "Uzbek";
+ case "vai": return "Vai";
+ case "ven": return "Venda";
+ case "vie": return "Vietnamese";
+ case "vol": return "Volapük";
+ case "vot": return "Votic";
+ case "wak": return "Wakashan languages";
+ case "wal": return "Walamo";
+ case "war": return "Waray";
+ case "was": return "Washo";
+ case "wel": return "Welsh";
+ case "cym": return "Welsh";
+ case "wol": return "Wolof";
+ case "xho": return "Xhosa";
+ case "sah": return "Yakut";
+ case "yao": return "Yao";
+ case "yap": return "Yapese";
+ case "yid": return "Yiddish";
+ case "yor": return "Yoruba";
+ case "ypk": return "Yupik languages";
+ case "znd": return "Zande";
+ case "zap": return "Zapotec";
+ case "zen": return "Zenaga";
+ case "zha": return "Zhuang";
+ case "zul": return "Zulu";
+ case "zun": return "Zuni";
+
+ default: return code;
+ }
+ }
+ }
+}
diff --git a/BDInfo/Properties/AssemblyInfo.cs b/BDInfo/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..9ea6496621
--- /dev/null
+++ b/BDInfo/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("BDInfo")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("BDInfo")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("2ecb9fe5-e2da-4b49-880b-d9887a84c311")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/BDInfo/ReadMe.txt b/BDInfo/ReadMe.txt
new file mode 100644
index 0000000000..68326d560a
--- /dev/null
+++ b/BDInfo/ReadMe.txt
@@ -0,0 +1,5 @@
+The source is taken from the BDRom folder of this project:
+
+http://www.cinemasquid.com/blu-ray/tools/bdinfo
+
+BDInfoSettings was taken from the FormSettings class, and changed so that the settings all return defaults.
\ No newline at end of file
diff --git a/BDInfo/TSCodecAC3.cs b/BDInfo/TSCodecAC3.cs
new file mode 100644
index 0000000000..79552df507
--- /dev/null
+++ b/BDInfo/TSCodecAC3.cs
@@ -0,0 +1,312 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+#undef DEBUG
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public abstract class TSCodecAC3
+ {
+ private static byte[] eac3_blocks = new byte[] { 1, 2, 3, 6 };
+
+ public static void Scan(
+ TSAudioStream stream,
+ TSStreamBuffer buffer,
+ ref string tag)
+ {
+ if (stream.IsInitialized) return;
+
+ byte[] sync = buffer.ReadBytes(2);
+ if (sync == null ||
+ sync[0] != 0x0B ||
+ sync[1] != 0x77)
+ {
+ return;
+ }
+
+ int sr_code = 0;
+ int frame_size = 0;
+ int frame_size_code = 0;
+ int channel_mode = 0;
+ int lfe_on = 0;
+ int dial_norm = 0;
+ int num_blocks = 0;
+
+ byte[] hdr = buffer.ReadBytes(4);
+ int bsid = (hdr[3] & 0xF8) >> 3;
+ buffer.Seek(-4, SeekOrigin.Current);
+ if (bsid <= 10)
+ {
+ byte[] crc = buffer.ReadBytes(2);
+ sr_code = buffer.ReadBits(2);
+ frame_size_code = buffer.ReadBits(6);
+ bsid = buffer.ReadBits(5);
+ int bsmod = buffer.ReadBits(3);
+
+ channel_mode = buffer.ReadBits(3);
+ int cmixlev = 0;
+ if (((channel_mode & 0x1) > 0) && (channel_mode != 0x1))
+ {
+ cmixlev = buffer.ReadBits(2);
+ }
+ int surmixlev = 0;
+ if ((channel_mode & 0x4) > 0)
+ {
+ surmixlev = buffer.ReadBits(2);
+ }
+ int dsurmod = 0;
+ if (channel_mode == 0x2)
+ {
+ dsurmod = buffer.ReadBits(2);
+ if (dsurmod == 0x2)
+ {
+ stream.AudioMode = TSAudioMode.Surround;
+ }
+ }
+ lfe_on = buffer.ReadBits(1);
+ dial_norm = buffer.ReadBits(5);
+ int compr = 0;
+ if (1 == buffer.ReadBits(1))
+ {
+ compr = buffer.ReadBits(8);
+ }
+ int langcod = 0;
+ if (1 == buffer.ReadBits(1))
+ {
+ langcod = buffer.ReadBits(8);
+ }
+ int mixlevel = 0;
+ int roomtyp = 0;
+ if (1 == buffer.ReadBits(1))
+ {
+ mixlevel = buffer.ReadBits(5);
+ roomtyp = buffer.ReadBits(2);
+ }
+ if (channel_mode == 0)
+ {
+ int dialnorm2 = buffer.ReadBits(5);
+ int compr2 = 0;
+ if (1 == buffer.ReadBits(1))
+ {
+ compr2 = buffer.ReadBits(8);
+ }
+ int langcod2 = 0;
+ if (1 == buffer.ReadBits(1))
+ {
+ langcod2 = buffer.ReadBits(8);
+ }
+ int mixlevel2 = 0;
+ int roomtyp2 = 0;
+ if (1 == buffer.ReadBits(1))
+ {
+ mixlevel2 = buffer.ReadBits(5);
+ roomtyp2 = buffer.ReadBits(2);
+ }
+ }
+ int copyrightb = buffer.ReadBits(1);
+ int origbs = buffer.ReadBits(1);
+ if (bsid == 6)
+ {
+ if (1 == buffer.ReadBits(1))
+ {
+ int dmixmod = buffer.ReadBits(2);
+ int ltrtcmixlev = buffer.ReadBits(3);
+ int ltrtsurmixlev = buffer.ReadBits(3);
+ int lorocmixlev = buffer.ReadBits(3);
+ int lorosurmixlev = buffer.ReadBits(3);
+ }
+ if (1 == buffer.ReadBits(1))
+ {
+ int dsurexmod = buffer.ReadBits(2);
+ int dheadphonmod = buffer.ReadBits(2);
+ if (dheadphonmod == 0x2)
+ {
+ // TODO
+ }
+ int adconvtyp = buffer.ReadBits(1);
+ int xbsi2 = buffer.ReadBits(8);
+ int encinfo = buffer.ReadBits(1);
+ if (dsurexmod == 2)
+ {
+ stream.AudioMode = TSAudioMode.Extended;
+ }
+ }
+ }
+ }
+ else
+ {
+ int frame_type = buffer.ReadBits(2);
+ int substreamid = buffer.ReadBits(3);
+ frame_size = (buffer.ReadBits(11) + 1) << 1;
+
+ sr_code = buffer.ReadBits(2);
+ if (sr_code == 3)
+ {
+ sr_code = buffer.ReadBits(2);
+ }
+ else
+ {
+ num_blocks = buffer.ReadBits(2);
+ }
+ channel_mode = buffer.ReadBits(3);
+ lfe_on = buffer.ReadBits(1);
+ }
+
+ switch (channel_mode)
+ {
+ case 0: // 1+1
+ stream.ChannelCount = 2;
+ if (stream.AudioMode == TSAudioMode.Unknown)
+ {
+ stream.AudioMode = TSAudioMode.DualMono;
+ }
+ break;
+ case 1: // 1/0
+ stream.ChannelCount = 1;
+ break;
+ case 2: // 2/0
+ stream.ChannelCount = 2;
+ if (stream.AudioMode == TSAudioMode.Unknown)
+ {
+ stream.AudioMode = TSAudioMode.Stereo;
+ }
+ break;
+ case 3: // 3/0
+ stream.ChannelCount = 3;
+ break;
+ case 4: // 2/1
+ stream.ChannelCount = 3;
+ break;
+ case 5: // 3/1
+ stream.ChannelCount = 4;
+ break;
+ case 6: // 2/2
+ stream.ChannelCount = 4;
+ break;
+ case 7: // 3/2
+ stream.ChannelCount = 5;
+ break;
+ default:
+ stream.ChannelCount = 0;
+ break;
+ }
+
+ switch (sr_code)
+ {
+ case 0:
+ stream.SampleRate = 48000;
+ break;
+ case 1:
+ stream.SampleRate = 44100;
+ break;
+ case 2:
+ stream.SampleRate = 32000;
+ break;
+ default:
+ stream.SampleRate = 0;
+ break;
+ }
+
+ if (bsid <= 10)
+ {
+ switch (frame_size_code >> 1)
+ {
+ case 18:
+ stream.BitRate = 640000;
+ break;
+ case 17:
+ stream.BitRate = 576000;
+ break;
+ case 16:
+ stream.BitRate = 512000;
+ break;
+ case 15:
+ stream.BitRate = 448000;
+ break;
+ case 14:
+ stream.BitRate = 384000;
+ break;
+ case 13:
+ stream.BitRate = 320000;
+ break;
+ case 12:
+ stream.BitRate = 256000;
+ break;
+ case 11:
+ stream.BitRate = 224000;
+ break;
+ case 10:
+ stream.BitRate = 192000;
+ break;
+ case 9:
+ stream.BitRate = 160000;
+ break;
+ case 8:
+ stream.BitRate = 128000;
+ break;
+ case 7:
+ stream.BitRate = 112000;
+ break;
+ case 6:
+ stream.BitRate = 96000;
+ break;
+ case 5:
+ stream.BitRate = 80000;
+ break;
+ case 4:
+ stream.BitRate = 64000;
+ break;
+ case 3:
+ stream.BitRate = 56000;
+ break;
+ case 2:
+ stream.BitRate = 48000;
+ break;
+ case 1:
+ stream.BitRate = 40000;
+ break;
+ case 0:
+ stream.BitRate = 32000;
+ break;
+ default:
+ stream.BitRate = 0;
+ break;
+ }
+ }
+ else
+ {
+ stream.BitRate = (long)
+ (4.0 * frame_size * stream.SampleRate / (num_blocks * 256));
+ }
+
+ stream.LFE = lfe_on;
+ if (stream.StreamType != TSStreamType.AC3_PLUS_AUDIO &&
+ stream.StreamType != TSStreamType.AC3_PLUS_SECONDARY_AUDIO)
+ {
+ stream.DialNorm = dial_norm - 31;
+ }
+ stream.IsVBR = false;
+ stream.IsInitialized = true;
+ }
+ }
+}
diff --git a/BDInfo/TSCodecAVC.cs b/BDInfo/TSCodecAVC.cs
new file mode 100644
index 0000000000..0b15f26f3e
--- /dev/null
+++ b/BDInfo/TSCodecAVC.cs
@@ -0,0 +1,151 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public abstract class TSCodecAVC
+ {
+ public static void Scan(
+ TSVideoStream stream,
+ TSStreamBuffer buffer,
+ ref string tag)
+ {
+ uint parse = 0;
+ byte accessUnitDelimiterParse = 0;
+ byte sequenceParameterSetParse = 0;
+ string profile = null;
+ string level = null;
+ byte constraintSet0Flag = 0;
+ byte constraintSet1Flag = 0;
+ byte constraintSet2Flag = 0;
+ byte constraintSet3Flag = 0;
+
+ for (int i = 0; i < buffer.Length; i++)
+ {
+ parse = (parse << 8) + buffer.ReadByte();
+
+ if (parse == 0x00000109)
+ {
+ accessUnitDelimiterParse = 1;
+ }
+ else if (accessUnitDelimiterParse > 0)
+ {
+ --accessUnitDelimiterParse;
+ if (accessUnitDelimiterParse == 0)
+ {
+ switch ((parse & 0xFF) >> 5)
+ {
+ case 0: // I
+ case 3: // SI
+ case 5: // I, SI
+ tag = "I";
+ break;
+
+ case 1: // I, P
+ case 4: // SI, SP
+ case 6: // I, SI, P, SP
+ tag = "P";
+ break;
+
+ case 2: // I, P, B
+ case 7: // I, SI, P, SP, B
+ tag = "B";
+ break;
+ }
+ if (stream.IsInitialized) return;
+ }
+ }
+ else if (parse == 0x00000127 || parse == 0x00000167)
+ {
+ sequenceParameterSetParse = 3;
+ }
+ else if (sequenceParameterSetParse > 0)
+ {
+ --sequenceParameterSetParse;
+ switch (sequenceParameterSetParse)
+ {
+ case 2:
+ switch (parse & 0xFF)
+ {
+ case 66:
+ profile = "Baseline Profile";
+ break;
+ case 77:
+ profile = "Main Profile";
+ break;
+ case 88:
+ profile = "Extended Profile";
+ break;
+ case 100:
+ profile = "High Profile";
+ break;
+ case 110:
+ profile = "High 10 Profile";
+ break;
+ case 122:
+ profile = "High 4:2:2 Profile";
+ break;
+ case 144:
+ profile = "High 4:4:4 Profile";
+ break;
+ default:
+ profile = "Unknown Profile";
+ break;
+ }
+ break;
+
+ case 1:
+ constraintSet0Flag = (byte)
+ ((parse & 0x80) >> 7);
+ constraintSet1Flag = (byte)
+ ((parse & 0x40) >> 6);
+ constraintSet2Flag = (byte)
+ ((parse & 0x20) >> 5);
+ constraintSet3Flag = (byte)
+ ((parse & 0x10) >> 4);
+ break;
+
+ case 0:
+ byte b = (byte)(parse & 0xFF);
+ if (b == 11 && constraintSet3Flag == 1)
+ {
+ level = "1b";
+ }
+ else
+ {
+ level = string.Format(
+ "{0:D}.{1:D}",
+ b / 10, (b - ((b / 10) * 10)));
+ }
+ stream.EncodingProfile = string.Format(
+ "{0} {1}", profile, level);
+ stream.IsVBR = true;
+ stream.IsInitialized = true;
+ break;
+ }
+ }
+ }
+ return;
+ }
+ }
+}
diff --git a/BDInfo/TSCodecDTS.cs b/BDInfo/TSCodecDTS.cs
new file mode 100644
index 0000000000..90af48e934
--- /dev/null
+++ b/BDInfo/TSCodecDTS.cs
@@ -0,0 +1,162 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public abstract class TSCodecDTS
+ {
+ private static int[] dca_sample_rates =
+ {
+ 0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0,
+ 12000, 24000, 48000, 96000, 192000
+ };
+
+ private static int[] dca_bit_rates =
+ {
+ 32000, 56000, 64000, 96000, 112000, 128000,
+ 192000, 224000, 256000, 320000, 384000,
+ 448000, 512000, 576000, 640000, 768000,
+ 896000, 1024000, 1152000, 1280000, 1344000,
+ 1408000, 1411200, 1472000, 1509000, 1920000,
+ 2048000, 3072000, 3840000, 1/*open*/, 2/*variable*/, 3/*lossless*/
+ };
+
+ private static int[] dca_channels =
+ {
+ 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8
+ };
+
+ private static int[] dca_bits_per_sample =
+ {
+ 16, 16, 20, 20, 0, 24, 24
+ };
+
+ public static void Scan(
+ TSAudioStream stream,
+ TSStreamBuffer buffer,
+ long bitrate,
+ ref string tag)
+ {
+ if (stream.IsInitialized) return;
+
+ bool syncFound = false;
+ uint sync = 0;
+ for (int i = 0; i < buffer.Length; i++)
+ {
+ sync = (sync << 8) + buffer.ReadByte();
+ if (sync == 0x7FFE8001)
+ {
+ syncFound = true;
+ break;
+ }
+ }
+ if (!syncFound) return;
+
+ int frame_type = buffer.ReadBits(1);
+ int samples_deficit = buffer.ReadBits(5);
+ int crc_present = buffer.ReadBits(1);
+ int sample_blocks = buffer.ReadBits(7);
+ int frame_size = buffer.ReadBits(14);
+ if (frame_size < 95)
+ {
+ return;
+ }
+ int amode = buffer.ReadBits(6);
+ int sample_rate = buffer.ReadBits(4);
+ if (sample_rate < 0 || sample_rate >= dca_sample_rates.Length)
+ {
+ return;
+ }
+ int bit_rate = buffer.ReadBits(5);
+ if (bit_rate < 0 || bit_rate >= dca_bit_rates.Length)
+ {
+ return;
+ }
+ int downmix = buffer.ReadBits(1);
+ int dynrange = buffer.ReadBits(1);
+ int timestamp = buffer.ReadBits(1);
+ int aux_data = buffer.ReadBits(1);
+ int hdcd = buffer.ReadBits(1);
+ int ext_descr = buffer.ReadBits(3);
+ int ext_coding = buffer.ReadBits(1);
+ int aspf = buffer.ReadBits(1);
+ int lfe = buffer.ReadBits(2);
+ int predictor_history = buffer.ReadBits(1);
+ if (crc_present == 1)
+ {
+ int crc = buffer.ReadBits(16);
+ }
+ int multirate_inter = buffer.ReadBits(1);
+ int version = buffer.ReadBits(4);
+ int copy_history = buffer.ReadBits(2);
+ int source_pcm_res = buffer.ReadBits(3);
+ int front_sum = buffer.ReadBits(1);
+ int surround_sum = buffer.ReadBits(1);
+ int dialog_norm = buffer.ReadBits(4);
+ if (source_pcm_res < 0 || source_pcm_res >= dca_bits_per_sample.Length)
+ {
+ return;
+ }
+ int subframes = buffer.ReadBits(4);
+ int total_channels = buffer.ReadBits(3) + 1 + ext_coding;
+
+ stream.SampleRate = dca_sample_rates[sample_rate];
+ stream.ChannelCount = total_channels;
+ stream.LFE = (lfe > 0 ? 1 : 0);
+ stream.BitDepth = dca_bits_per_sample[source_pcm_res];
+ stream.DialNorm = -dialog_norm;
+ if ((source_pcm_res & 0x1) == 0x1)
+ {
+ stream.AudioMode = TSAudioMode.Extended;
+ }
+
+ stream.BitRate = (uint)dca_bit_rates[bit_rate];
+ switch (stream.BitRate)
+ {
+ case 1:
+ if (bitrate > 0)
+ {
+ stream.BitRate = bitrate;
+ stream.IsVBR = false;
+ stream.IsInitialized = true;
+ }
+ else
+ {
+ stream.BitRate = 0;
+ }
+ break;
+
+ case 2:
+ case 3:
+ stream.IsVBR = true;
+ stream.IsInitialized = true;
+ break;
+
+ default:
+ stream.IsVBR = false;
+ stream.IsInitialized = true;
+ break;
+ }
+ }
+ }
+}
diff --git a/BDInfo/TSCodecDTSHD.cs b/BDInfo/TSCodecDTSHD.cs
new file mode 100644
index 0000000000..83cd724ae9
--- /dev/null
+++ b/BDInfo/TSCodecDTSHD.cs
@@ -0,0 +1,249 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public abstract class TSCodecDTSHD
+ {
+ private static int[] SampleRates = new int[]
+ { 0x1F40, 0x3E80, 0x7D00, 0x0FA00, 0x1F400, 0x5622, 0x0AC44, 0x15888, 0x2B110, 0x56220, 0x2EE0, 0x5DC0, 0x0BB80, 0x17700, 0x2EE00, 0x5DC00 };
+
+ public static void Scan(
+ TSAudioStream stream,
+ TSStreamBuffer buffer,
+ long bitrate,
+ ref string tag)
+ {
+ if (stream.IsInitialized &&
+ (stream.StreamType == TSStreamType.DTS_HD_SECONDARY_AUDIO ||
+ (stream.CoreStream != null &&
+ stream.CoreStream.IsInitialized))) return;
+
+ bool syncFound = false;
+ uint sync = 0;
+ for (int i = 0; i < buffer.Length; i++)
+ {
+ sync = (sync << 8) + buffer.ReadByte();
+ if (sync == 0x64582025)
+ {
+ syncFound = true;
+ break;
+ }
+ }
+
+ if (!syncFound)
+ {
+ tag = "CORE";
+ if (stream.CoreStream == null)
+ {
+ stream.CoreStream = new TSAudioStream();
+ stream.CoreStream.StreamType = TSStreamType.DTS_AUDIO;
+ }
+ if (!stream.CoreStream.IsInitialized)
+ {
+ buffer.BeginRead();
+ TSCodecDTS.Scan(stream.CoreStream, buffer, bitrate, ref tag);
+ }
+ return;
+ }
+
+ tag = "HD";
+ int temp1 = buffer.ReadBits(8);
+ int nuSubStreamIndex = buffer.ReadBits(2);
+ int nuExtSSHeaderSize = 0;
+ int nuExtSSFSize = 0;
+ int bBlownUpHeader = buffer.ReadBits(1);
+ if (1 == bBlownUpHeader)
+ {
+ nuExtSSHeaderSize = buffer.ReadBits(12) + 1;
+ nuExtSSFSize = buffer.ReadBits(20) + 1;
+ }
+ else
+ {
+ nuExtSSHeaderSize = buffer.ReadBits(8) + 1;
+ nuExtSSFSize = buffer.ReadBits(16) + 1;
+ }
+ int nuNumAudioPresent = 1;
+ int nuNumAssets = 1;
+ int bStaticFieldsPresent = buffer.ReadBits(1);
+ if (1 == bStaticFieldsPresent)
+ {
+ int nuRefClockCode = buffer.ReadBits(2);
+ int nuExSSFrameDurationCode = buffer.ReadBits(3) + 1;
+ long nuTimeStamp = 0;
+ if (1 == buffer.ReadBits(1))
+ {
+ nuTimeStamp = (buffer.ReadBits(18) << 18) + buffer.ReadBits(18);
+ }
+ nuNumAudioPresent = buffer.ReadBits(3) + 1;
+ nuNumAssets = buffer.ReadBits(3) + 1;
+ int[] nuActiveExSSMask = new int[nuNumAudioPresent];
+ for (int i = 0; i < nuNumAudioPresent; i++)
+ {
+ nuActiveExSSMask[i] = buffer.ReadBits(nuSubStreamIndex + 1); //?
+ }
+ for (int i = 0; i < nuNumAudioPresent; i++)
+ {
+ for (int j = 0; j < nuSubStreamIndex + 1; j++)
+ {
+ if (((j + 1) % 2) == 1)
+ {
+ int mask = buffer.ReadBits(8);
+ }
+ }
+ }
+ if (1 == buffer.ReadBits(1))
+ {
+ int nuMixMetadataAdjLevel = buffer.ReadBits(2);
+ int nuBits4MixOutMask = buffer.ReadBits(2) * 4 + 4;
+ int nuNumMixOutConfigs = buffer.ReadBits(2) + 1;
+ int[] nuMixOutChMask = new int[nuNumMixOutConfigs];
+ for (int i = 0; i < nuNumMixOutConfigs; i++)
+ {
+ nuMixOutChMask[i] = buffer.ReadBits(nuBits4MixOutMask);
+ }
+ }
+ }
+ int[] AssetSizes = new int[nuNumAssets];
+ for (int i = 0; i < nuNumAssets; i++)
+ {
+ if (1 == bBlownUpHeader)
+ {
+ AssetSizes[i] = buffer.ReadBits(20) + 1;
+ }
+ else
+ {
+ AssetSizes[i] = buffer.ReadBits(16) + 1;
+ }
+ }
+ for (int i = 0; i < nuNumAssets; i++)
+ {
+ long bufferPosition = buffer.Position;
+ int nuAssetDescriptorFSIZE = buffer.ReadBits(9) + 1;
+ int DescriptorDataForAssetIndex = buffer.ReadBits(3);
+ if (1 == bStaticFieldsPresent)
+ {
+ int AssetTypeDescrPresent = buffer.ReadBits(1);
+ if (1 == AssetTypeDescrPresent)
+ {
+ int AssetTypeDescriptor = buffer.ReadBits(4);
+ }
+ int LanguageDescrPresent = buffer.ReadBits(1);
+ if (1 == LanguageDescrPresent)
+ {
+ int LanguageDescriptor = buffer.ReadBits(24);
+ }
+ int bInfoTextPresent = buffer.ReadBits(1);
+ if (1 == bInfoTextPresent)
+ {
+ int nuInfoTextByteSize = buffer.ReadBits(10) + 1;
+ int[] InfoText = new int[nuInfoTextByteSize];
+ for (int j = 0; j < nuInfoTextByteSize; j++)
+ {
+ InfoText[j] = buffer.ReadBits(8);
+ }
+ }
+ int nuBitResolution = buffer.ReadBits(5) + 1;
+ int nuMaxSampleRate = buffer.ReadBits(4);
+ int nuTotalNumChs = buffer.ReadBits(8) + 1;
+ int bOne2OneMapChannels2Speakers = buffer.ReadBits(1);
+ int nuSpkrActivityMask = 0;
+ if (1 == bOne2OneMapChannels2Speakers)
+ {
+ int bEmbeddedStereoFlag = 0;
+ if (nuTotalNumChs > 2)
+ {
+ bEmbeddedStereoFlag = buffer.ReadBits(1);
+ }
+ int bEmbeddedSixChFlag = 0;
+ if (nuTotalNumChs > 6)
+ {
+ bEmbeddedSixChFlag = buffer.ReadBits(1);
+ }
+ int bSpkrMaskEnabled = buffer.ReadBits(1);
+ int nuNumBits4SAMask = 0;
+ if (1 == bSpkrMaskEnabled)
+ {
+ nuNumBits4SAMask = buffer.ReadBits(2);
+ nuNumBits4SAMask = nuNumBits4SAMask * 4 + 4;
+ nuSpkrActivityMask = buffer.ReadBits(nuNumBits4SAMask);
+ }
+ // TODO...
+ }
+ stream.SampleRate = SampleRates[nuMaxSampleRate];
+ stream.BitDepth = nuBitResolution;
+
+ stream.LFE = 0;
+ if ((nuSpkrActivityMask & 0x8) == 0x8)
+ {
+ ++stream.LFE;
+ }
+ if ((nuSpkrActivityMask & 0x1000) == 0x1000)
+ {
+ ++stream.LFE;
+ }
+ stream.ChannelCount = nuTotalNumChs - stream.LFE;
+ }
+ if (nuNumAssets > 1)
+ {
+ // TODO...
+ break;
+ }
+ }
+
+ // TODO
+ if (stream.CoreStream != null)
+ {
+ TSAudioStream coreStream = (TSAudioStream)stream.CoreStream;
+ if (coreStream.AudioMode == TSAudioMode.Extended &&
+ stream.ChannelCount == 5)
+ {
+ stream.AudioMode = TSAudioMode.Extended;
+ }
+ /*
+ if (coreStream.DialNorm != 0)
+ {
+ stream.DialNorm = coreStream.DialNorm;
+ }
+ */
+ }
+
+ if (stream.StreamType == TSStreamType.DTS_HD_MASTER_AUDIO)
+ {
+ stream.IsVBR = true;
+ stream.IsInitialized = true;
+ }
+ else if (bitrate > 0)
+ {
+ stream.IsVBR = false;
+ stream.BitRate = bitrate;
+ if (stream.CoreStream != null)
+ {
+ stream.BitRate += stream.CoreStream.BitRate;
+ stream.IsInitialized = true;
+ }
+ stream.IsInitialized = (stream.BitRate > 0 ? true : false);
+ }
+ }
+ }
+}
diff --git a/BDInfo/TSCodecLPCM.cs b/BDInfo/TSCodecLPCM.cs
new file mode 100644
index 0000000000..b9c8385343
--- /dev/null
+++ b/BDInfo/TSCodecLPCM.cs
@@ -0,0 +1,126 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public abstract class TSCodecLPCM
+ {
+ public static void Scan(
+ TSAudioStream stream,
+ TSStreamBuffer buffer,
+ ref string tag)
+ {
+ if (stream.IsInitialized) return;
+
+ byte[] header = buffer.ReadBytes(4);
+ int flags = (header[2] << 8) + header[3];
+
+ switch ((flags & 0xF000) >> 12)
+ {
+ case 1: // 1/0/0
+ stream.ChannelCount = 1;
+ stream.LFE = 0;
+ break;
+ case 3: // 2/0/0
+ stream.ChannelCount = 2;
+ stream.LFE = 0;
+ break;
+ case 4: // 3/0/0
+ stream.ChannelCount = 3;
+ stream.LFE = 0;
+ break;
+ case 5: // 2/1/0
+ stream.ChannelCount = 3;
+ stream.LFE = 0;
+ break;
+ case 6: // 3/1/0
+ stream.ChannelCount = 4;
+ stream.LFE = 0;
+ break;
+ case 7: // 2/2/0
+ stream.ChannelCount = 4;
+ stream.LFE = 0;
+ break;
+ case 8: // 3/2/0
+ stream.ChannelCount = 5;
+ stream.LFE = 0;
+ break;
+ case 9: // 3/2/1
+ stream.ChannelCount = 5;
+ stream.LFE = 1;
+ break;
+ case 10: // 3/4/0
+ stream.ChannelCount = 7;
+ stream.LFE = 0;
+ break;
+ case 11: // 3/4/1
+ stream.ChannelCount = 7;
+ stream.LFE = 1;
+ break;
+ default:
+ stream.ChannelCount = 0;
+ stream.LFE = 0;
+ break;
+ }
+
+ switch ((flags & 0xC0) >> 6)
+ {
+ case 1:
+ stream.BitDepth = 16;
+ break;
+ case 2:
+ stream.BitDepth = 20;
+ break;
+ case 3:
+ stream.BitDepth = 24;
+ break;
+ default:
+ stream.BitDepth = 0;
+ break;
+ }
+
+ switch ((flags & 0xF00) >> 8)
+ {
+ case 1:
+ stream.SampleRate = 48000;
+ break;
+ case 4:
+ stream.SampleRate = 96000;
+ break;
+ case 5:
+ stream.SampleRate = 192000;
+ break;
+ default:
+ stream.SampleRate = 0;
+ break;
+ }
+
+ stream.BitRate = (uint)
+ (stream.SampleRate * stream.BitDepth *
+ (stream.ChannelCount + stream.LFE));
+
+ stream.IsVBR = false;
+ stream.IsInitialized = true;
+ }
+ }
+}
diff --git a/BDInfo/TSCodecMPEG2.cs b/BDInfo/TSCodecMPEG2.cs
new file mode 100644
index 0000000000..6418a3ad90
--- /dev/null
+++ b/BDInfo/TSCodecMPEG2.cs
@@ -0,0 +1,211 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+#undef DEBUG
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public abstract class TSCodecMPEG2
+ {
+ public static void Scan(
+ TSVideoStream stream,
+ TSStreamBuffer buffer,
+ ref string tag)
+ {
+ int parse = 0;
+ int pictureParse = 0;
+ int sequenceHeaderParse = 0;
+ int extensionParse = 0;
+ int sequenceExtensionParse = 0;
+
+ for (int i = 0; i < buffer.Length; i++)
+ {
+ parse = (parse << 8) + buffer.ReadByte();
+
+ if (parse == 0x00000100)
+ {
+ pictureParse = 2;
+ }
+ else if (parse == 0x000001B3)
+ {
+ sequenceHeaderParse = 7;
+ }
+ else if (sequenceHeaderParse > 0)
+ {
+ --sequenceHeaderParse;
+ switch (sequenceHeaderParse)
+ {
+#if DEBUG
+ case 6:
+ break;
+
+ case 5:
+ break;
+
+ case 4:
+ stream.Width =
+ (int)((parse & 0xFFF000) >> 12);
+ stream.Height =
+ (int)(parse & 0xFFF);
+ break;
+
+ case 3:
+ stream.AspectRatio =
+ (TSAspectRatio)((parse & 0xF0) >> 4);
+
+ switch ((parse & 0xF0) >> 4)
+ {
+ case 0: // Forbidden
+ break;
+ case 1: // Square
+ break;
+ case 2: // 4:3
+ break;
+ case 3: // 16:9
+ break;
+ case 4: // 2.21:1
+ break;
+ default: // Reserved
+ break;
+ }
+
+ switch (parse & 0xF)
+ {
+ case 0: // Forbidden
+ break;
+ case 1: // 23.976
+ stream.FrameRateEnumerator = 24000;
+ stream.FrameRateDenominator = 1001;
+ break;
+ case 2: // 24
+ stream.FrameRateEnumerator = 24000;
+ stream.FrameRateDenominator = 1000;
+ break;
+ case 3: // 25
+ stream.FrameRateEnumerator = 25000;
+ stream.FrameRateDenominator = 1000;
+ break;
+ case 4: // 29.97
+ stream.FrameRateEnumerator = 30000;
+ stream.FrameRateDenominator = 1001;
+ break;
+ case 5: // 30
+ stream.FrameRateEnumerator = 30000;
+ stream.FrameRateDenominator = 1000;
+ break;
+ case 6: // 50
+ stream.FrameRateEnumerator = 50000;
+ stream.FrameRateDenominator = 1000;
+ break;
+ case 7: // 59.94
+ stream.FrameRateEnumerator = 60000;
+ stream.FrameRateDenominator = 1001;
+ break;
+ case 8: // 60
+ stream.FrameRateEnumerator = 60000;
+ stream.FrameRateDenominator = 1000;
+ break;
+ default: // Reserved
+ stream.FrameRateEnumerator = 0;
+ stream.FrameRateDenominator = 0;
+ break;
+ }
+ break;
+
+ case 2:
+ break;
+
+ case 1:
+ break;
+#endif
+
+ case 0:
+#if DEBUG
+ stream.BitRate =
+ (((parse & 0xFFFFC0) >> 6) * 200);
+#endif
+ stream.IsVBR = true;
+ stream.IsInitialized = true;
+ break;
+ }
+ }
+ else if (pictureParse > 0)
+ {
+ --pictureParse;
+ if (pictureParse == 0)
+ {
+ switch ((parse & 0x38) >> 3)
+ {
+ case 1:
+ tag = "I";
+ break;
+ case 2:
+ tag = "P";
+ break;
+ case 3:
+ tag = "B";
+ break;
+ default:
+ break;
+ }
+ if (stream.IsInitialized) return;
+ }
+ }
+ else if (parse == 0x000001B5)
+ {
+ extensionParse = 1;
+ }
+ else if (extensionParse > 0)
+ {
+ --extensionParse;
+ if (extensionParse == 0)
+ {
+ if ((parse & 0xF0) == 0x10)
+ {
+ sequenceExtensionParse = 1;
+ }
+ }
+ }
+ else if (sequenceExtensionParse > 0)
+ {
+ --sequenceExtensionParse;
+#if DEBUG
+ if (sequenceExtensionParse == 0)
+ {
+ uint sequenceExtension =
+ ((parse & 0x8) >> 3);
+ if (sequenceExtension == 0)
+ {
+ stream.IsInterlaced = true;
+ }
+ else
+ {
+ stream.IsInterlaced = false;
+ }
+ }
+#endif
+ }
+ }
+ }
+ }
+}
diff --git a/BDInfo/TSCodecMVC.cs b/BDInfo/TSCodecMVC.cs
new file mode 100644
index 0000000000..0ad16d0811
--- /dev/null
+++ b/BDInfo/TSCodecMVC.cs
@@ -0,0 +1,39 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ // TODO: Do something more interesting here...
+
+ public abstract class TSCodecMVC
+ {
+ public static void Scan(
+ TSVideoStream stream,
+ TSStreamBuffer buffer,
+ ref string tag)
+ {
+ stream.IsVBR = true;
+ stream.IsInitialized = true;
+ }
+ }
+}
diff --git a/BDInfo/TSCodecTrueHD.cs b/BDInfo/TSCodecTrueHD.cs
new file mode 100644
index 0000000000..bfe0d99444
--- /dev/null
+++ b/BDInfo/TSCodecTrueHD.cs
@@ -0,0 +1,189 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public abstract class TSCodecTrueHD
+ {
+ public static void Scan(
+ TSAudioStream stream,
+ TSStreamBuffer buffer,
+ ref string tag)
+ {
+ if (stream.IsInitialized &&
+ stream.CoreStream != null &&
+ stream.CoreStream.IsInitialized) return;
+
+ bool syncFound = false;
+ uint sync = 0;
+ for (int i = 0; i < buffer.Length; i++)
+ {
+ sync = (sync << 8) + buffer.ReadByte();
+ if (sync == 0xF8726FBA)
+ {
+ syncFound = true;
+ break;
+ }
+ }
+
+ if (!syncFound)
+ {
+ tag = "CORE";
+ if (stream.CoreStream == null)
+ {
+ stream.CoreStream = new TSAudioStream();
+ stream.CoreStream.StreamType = TSStreamType.AC3_AUDIO;
+ }
+ if (!stream.CoreStream.IsInitialized)
+ {
+ buffer.BeginRead();
+ TSCodecAC3.Scan(stream.CoreStream, buffer, ref tag);
+ }
+ return;
+ }
+
+ tag = "HD";
+ int ratebits = buffer.ReadBits(4);
+ if (ratebits != 0xF)
+ {
+ stream.SampleRate =
+ (((ratebits & 8) > 0 ? 44100 : 48000) << (ratebits & 7));
+ }
+ int temp1 = buffer.ReadBits(8);
+ int channels_thd_stream1 = buffer.ReadBits(5);
+ int temp2 = buffer.ReadBits(2);
+
+ stream.ChannelCount = 0;
+ stream.LFE = 0;
+ int c_LFE2 = buffer.ReadBits(1);
+ if (c_LFE2 == 1)
+ {
+ stream.LFE += 1;
+ }
+ int c_Cvh = buffer.ReadBits(1);
+ if (c_Cvh == 1)
+ {
+ stream.ChannelCount += 1;
+ }
+ int c_LRw = buffer.ReadBits(1);
+ if (c_LRw == 1)
+ {
+ stream.ChannelCount += 2;
+ }
+ int c_LRsd = buffer.ReadBits(1);
+ if (c_LRsd == 1)
+ {
+ stream.ChannelCount += 2;
+ }
+ int c_Ts = buffer.ReadBits(1);
+ if (c_Ts == 1)
+ {
+ stream.ChannelCount += 1;
+ }
+ int c_Cs = buffer.ReadBits(1);
+ if (c_Cs == 1)
+ {
+ stream.ChannelCount += 1;
+ }
+ int c_LRrs = buffer.ReadBits(1);
+ if (c_LRrs == 1)
+ {
+ stream.ChannelCount += 2;
+ }
+ int c_LRc = buffer.ReadBits(1);
+ if (c_LRc == 1)
+ {
+ stream.ChannelCount += 2;
+ }
+ int c_LRvh = buffer.ReadBits(1);
+ if (c_LRvh == 1)
+ {
+ stream.ChannelCount += 2;
+ }
+ int c_LRs = buffer.ReadBits(1);
+ if (c_LRs == 1)
+ {
+ stream.ChannelCount += 2;
+ }
+ int c_LFE = buffer.ReadBits(1);
+ if (c_LFE == 1)
+ {
+ stream.LFE += 1;
+ }
+ int c_C = buffer.ReadBits(1);
+ if (c_C == 1)
+ {
+ stream.ChannelCount += 1;
+ }
+ int c_LR = buffer.ReadBits(1);
+ if (c_LR == 1)
+ {
+ stream.ChannelCount += 2;
+ }
+
+ int access_unit_size = 40 << (ratebits & 7);
+ int access_unit_size_pow2 = 64 << (ratebits & 7);
+
+ int a1 = buffer.ReadBits(16);
+ int a2 = buffer.ReadBits(16);
+ int a3 = buffer.ReadBits(16);
+
+ int is_vbr = buffer.ReadBits(1);
+ int peak_bitrate = buffer.ReadBits(15);
+ peak_bitrate = (peak_bitrate * stream.SampleRate) >> 4;
+
+ double peak_bitdepth =
+ (double)peak_bitrate /
+ (stream.ChannelCount + stream.LFE) /
+ stream.SampleRate;
+ if (peak_bitdepth > 14)
+ {
+ stream.BitDepth = 24;
+ }
+ else
+ {
+ stream.BitDepth = 16;
+ }
+
+#if DEBUG
+ System.Diagnostics.Debug.WriteLine(string.Format(
+ "{0}\t{1}\t{2:F2}",
+ stream.PID, peak_bitrate, peak_bitdepth));
+#endif
+ /*
+ // TODO: Get THD dialnorm from metadata
+ if (stream.CoreStream != null)
+ {
+ TSAudioStream coreStream = (TSAudioStream)stream.CoreStream;
+ if (coreStream.DialNorm != 0)
+ {
+ stream.DialNorm = coreStream.DialNorm;
+ }
+ }
+ */
+
+ stream.IsVBR = true;
+ stream.IsInitialized = true;
+ }
+ }
+}
diff --git a/BDInfo/TSCodecVC1.cs b/BDInfo/TSCodecVC1.cs
new file mode 100644
index 0000000000..3cfd50cba0
--- /dev/null
+++ b/BDInfo/TSCodecVC1.cs
@@ -0,0 +1,134 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public abstract class TSCodecVC1
+ {
+ public static void Scan(
+ TSVideoStream stream,
+ TSStreamBuffer buffer,
+ ref string tag)
+ {
+ int parse = 0;
+ byte frameHeaderParse = 0;
+ byte sequenceHeaderParse = 0;
+ bool isInterlaced = false;
+
+ for (int i = 0; i < buffer.Length; i++)
+ {
+ parse = (parse << 8) + buffer.ReadByte();
+
+ if (parse == 0x0000010D)
+ {
+ frameHeaderParse = 4;
+ }
+ else if (frameHeaderParse > 0)
+ {
+ --frameHeaderParse;
+ if (frameHeaderParse == 0)
+ {
+ uint pictureType = 0;
+ if (isInterlaced)
+ {
+ if ((parse & 0x80000000) == 0)
+ {
+ pictureType =
+ (uint)((parse & 0x78000000) >> 13);
+ }
+ else
+ {
+ pictureType =
+ (uint)((parse & 0x3c000000) >> 12);
+ }
+ }
+ else
+ {
+ pictureType =
+ (uint)((parse & 0xf0000000) >> 14);
+ }
+
+ if ((pictureType & 0x20000) == 0)
+ {
+ tag = "P";
+ }
+ else if ((pictureType & 0x10000) == 0)
+ {
+ tag = "B";
+ }
+ else if ((pictureType & 0x8000) == 0)
+ {
+ tag = "I";
+ }
+ else if ((pictureType & 0x4000) == 0)
+ {
+ tag = "BI";
+ }
+ else
+ {
+ tag = null;
+ }
+ if (stream.IsInitialized) return;
+ }
+ }
+ else if (parse == 0x0000010F)
+ {
+ sequenceHeaderParse = 6;
+ }
+ else if (sequenceHeaderParse > 0)
+ {
+ --sequenceHeaderParse;
+ switch (sequenceHeaderParse)
+ {
+ case 5:
+ int profileLevel = ((parse & 0x38) >> 3);
+ if (((parse & 0xC0) >> 6) == 3)
+ {
+ stream.EncodingProfile = string.Format(
+ "Advanced Profile {0}", profileLevel);
+ }
+ else
+ {
+ stream.EncodingProfile = string.Format(
+ "Main Profile {0}", profileLevel);
+ }
+ break;
+
+ case 0:
+ if (((parse & 0x40) >> 6) > 0)
+ {
+ isInterlaced = true;
+ }
+ else
+ {
+ isInterlaced = false;
+ }
+ break;
+ }
+ stream.IsVBR = true;
+ stream.IsInitialized = true;
+ }
+ }
+ }
+ }
+}
diff --git a/BDInfo/TSInterleavedFile.cs b/BDInfo/TSInterleavedFile.cs
new file mode 100644
index 0000000000..27049e6602
--- /dev/null
+++ b/BDInfo/TSInterleavedFile.cs
@@ -0,0 +1,40 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+// TODO: Do more interesting things here...
+
+namespace BDInfo
+{
+ public class TSInterleavedFile
+ {
+ public FileInfo FileInfo = null;
+ public string Name = null;
+
+ public TSInterleavedFile(FileInfo fileInfo)
+ {
+ FileInfo = fileInfo;
+ Name = fileInfo.Name.ToUpper();
+ }
+ }
+}
diff --git a/BDInfo/TSPlaylistFile.cs b/BDInfo/TSPlaylistFile.cs
new file mode 100644
index 0000000000..1d00a78450
--- /dev/null
+++ b/BDInfo/TSPlaylistFile.cs
@@ -0,0 +1,1287 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+#undef DEBUG
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+namespace BDInfo
+{
+ public class TSPlaylistFile
+ {
+ private FileInfo FileInfo = null;
+ public string FileType = null;
+ public bool IsInitialized = false;
+ public string Name = null;
+ public BDROM BDROM = null;
+ public bool HasHiddenTracks = false;
+ public bool HasLoops = false;
+ public bool IsCustom = false;
+
+ public List Chapters = new List();
+
+ public Dictionary Streams =
+ new Dictionary();
+ public Dictionary PlaylistStreams =
+ new Dictionary();
+ public List StreamClips =
+ new List();
+ public List> AngleStreams =
+ new List>();
+ public List> AngleClips =
+ new List>();
+ public int AngleCount = 0;
+
+ public List SortedStreams =
+ new List();
+ public List VideoStreams =
+ new List();
+ public List AudioStreams =
+ new List();
+ public List TextStreams =
+ new List();
+ public List GraphicsStreams =
+ new List();
+
+ public TSPlaylistFile(
+ BDROM bdrom,
+ FileInfo fileInfo)
+ {
+ BDROM = bdrom;
+ FileInfo = fileInfo;
+ Name = fileInfo.Name.ToUpper();
+ }
+
+ public TSPlaylistFile(
+ BDROM bdrom,
+ string name,
+ List clips)
+ {
+ BDROM = bdrom;
+ Name = name;
+ IsCustom = true;
+ foreach (TSStreamClip clip in clips)
+ {
+ TSStreamClip newClip = new TSStreamClip(
+ clip.StreamFile, clip.StreamClipFile);
+
+ newClip.Name = clip.Name;
+ newClip.TimeIn = clip.TimeIn;
+ newClip.TimeOut = clip.TimeOut;
+ newClip.Length = newClip.TimeOut - newClip.TimeIn;
+ newClip.RelativeTimeIn = TotalLength;
+ newClip.RelativeTimeOut = newClip.RelativeTimeIn + newClip.Length;
+ newClip.AngleIndex = clip.AngleIndex;
+ newClip.Chapters.Add(clip.TimeIn);
+ StreamClips.Add(newClip);
+
+ if (newClip.AngleIndex > AngleCount)
+ {
+ AngleCount = newClip.AngleIndex;
+ }
+ if (newClip.AngleIndex == 0)
+ {
+ Chapters.Add(newClip.RelativeTimeIn);
+ }
+ }
+ LoadStreamClips();
+ IsInitialized = true;
+ }
+
+ public override string ToString()
+ {
+ return Name;
+ }
+
+ public ulong InterleavedFileSize
+ {
+ get
+ {
+ ulong size = 0;
+ foreach (TSStreamClip clip in StreamClips)
+ {
+ size += clip.InterleavedFileSize;
+ }
+ return size;
+ }
+ }
+ public ulong FileSize
+ {
+ get
+ {
+ ulong size = 0;
+ foreach (TSStreamClip clip in StreamClips)
+ {
+ size += clip.FileSize;
+ }
+ return size;
+ }
+ }
+ public double TotalLength
+ {
+ get
+ {
+ double length = 0;
+ foreach (TSStreamClip clip in StreamClips)
+ {
+ if (clip.AngleIndex == 0)
+ {
+ length += clip.Length;
+ }
+ }
+ return length;
+ }
+ }
+
+ public double TotalAngleLength
+ {
+ get
+ {
+ double length = 0;
+ foreach (TSStreamClip clip in StreamClips)
+ {
+ length += clip.Length;
+ }
+ return length;
+ }
+ }
+
+ public ulong TotalSize
+ {
+ get
+ {
+ ulong size = 0;
+ foreach (TSStreamClip clip in StreamClips)
+ {
+ if (clip.AngleIndex == 0)
+ {
+ size += clip.PacketSize;
+ }
+ }
+ return size;
+ }
+ }
+
+ public ulong TotalAngleSize
+ {
+ get
+ {
+ ulong size = 0;
+ foreach (TSStreamClip clip in StreamClips)
+ {
+ size += clip.PacketSize;
+ }
+ return size;
+ }
+ }
+
+ public ulong TotalBitRate
+ {
+ get
+ {
+ if (TotalLength > 0)
+ {
+ return (ulong)Math.Round(((TotalSize * 8.0) / TotalLength));
+ }
+ return 0;
+ }
+ }
+
+ public ulong TotalAngleBitRate
+ {
+ get
+ {
+ if (TotalAngleLength > 0)
+ {
+ return (ulong)Math.Round(((TotalAngleSize * 8.0) / TotalAngleLength));
+ }
+ return 0;
+ }
+ }
+
+ public void Scan(
+ Dictionary streamFiles,
+ Dictionary streamClipFiles)
+ {
+ FileStream fileStream = null;
+ BinaryReader fileReader = null;
+
+ try
+ {
+ Streams.Clear();
+ StreamClips.Clear();
+
+ fileStream = File.OpenRead(FileInfo.FullName);
+ fileReader = new BinaryReader(fileStream);
+
+ byte[] data = new byte[fileStream.Length];
+ int dataLength = fileReader.Read(data, 0, data.Length);
+
+ int pos = 0;
+
+ FileType = ReadString(data, 8, ref pos);
+ if (FileType != "MPLS0100" && FileType != "MPLS0200")
+ {
+ throw new Exception(string.Format(
+ "Playlist {0} has an unknown file type {1}.",
+ FileInfo.Name, FileType));
+ }
+
+ int playlistOffset = ReadInt32(data, ref pos);
+ int chaptersOffset = ReadInt32(data, ref pos);
+ int extensionsOffset = ReadInt32(data, ref pos);
+
+ pos = playlistOffset;
+
+ int playlistLength = ReadInt32(data, ref pos);
+ int playlistReserved = ReadInt16(data, ref pos);
+ int itemCount = ReadInt16(data, ref pos);
+ int subitemCount = ReadInt16(data, ref pos);
+
+ List chapterClips = new List();
+ for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
+ {
+ int itemStart = pos;
+ int itemLength = ReadInt16(data, ref pos);
+ string itemName = ReadString(data, 5, ref pos);
+ string itemType = ReadString(data, 4, ref pos);
+
+ TSStreamFile streamFile = null;
+ string streamFileName = string.Format(
+ "{0}.M2TS", itemName);
+ if (streamFiles.ContainsKey(streamFileName))
+ {
+ streamFile = streamFiles[streamFileName];
+ }
+ if (streamFile == null)
+ {
+ Debug.WriteLine(string.Format(
+ "Playlist {0} referenced missing file {1}.",
+ FileInfo.Name, streamFileName));
+ }
+
+ TSStreamClipFile streamClipFile = null;
+ string streamClipFileName = string.Format(
+ "{0}.CLPI", itemName);
+ if (streamClipFiles.ContainsKey(streamClipFileName))
+ {
+ streamClipFile = streamClipFiles[streamClipFileName];
+ }
+ if (streamClipFile == null)
+ {
+ throw new Exception(string.Format(
+ "Playlist {0} referenced missing file {1}.",
+ FileInfo.Name, streamFileName));
+ }
+
+ pos += 1;
+ int multiangle = (data[pos] >> 4) & 0x01;
+ int condition = data[pos] & 0x0F;
+ pos += 2;
+
+ int inTime = ReadInt32(data, ref pos);
+ if (inTime < 0) inTime &= 0x7FFFFFFF;
+ double timeIn = (double)inTime / 45000;
+
+ int outTime = ReadInt32(data, ref pos);
+ if (outTime < 0) outTime &= 0x7FFFFFFF;
+ double timeOut = (double)outTime / 45000;
+
+ TSStreamClip streamClip = new TSStreamClip(
+ streamFile, streamClipFile);
+
+ streamClip.Name = streamFileName; //TODO
+ streamClip.TimeIn = timeIn;
+ streamClip.TimeOut = timeOut;
+ streamClip.Length = streamClip.TimeOut - streamClip.TimeIn;
+ streamClip.RelativeTimeIn = TotalLength;
+ streamClip.RelativeTimeOut = streamClip.RelativeTimeIn + streamClip.Length;
+ StreamClips.Add(streamClip);
+ chapterClips.Add(streamClip);
+
+ pos += 12;
+ if (multiangle > 0)
+ {
+ int angles = data[pos];
+ pos += 2;
+ for (int angle = 0; angle < angles - 1; angle++)
+ {
+ string angleName = ReadString(data, 5, ref pos);
+ string angleType = ReadString(data, 4, ref pos);
+ pos += 1;
+
+ TSStreamFile angleFile = null;
+ string angleFileName = string.Format(
+ "{0}.M2TS", angleName);
+ if (streamFiles.ContainsKey(angleFileName))
+ {
+ angleFile = streamFiles[angleFileName];
+ }
+ if (angleFile == null)
+ {
+ throw new Exception(string.Format(
+ "Playlist {0} referenced missing angle file {1}.",
+ FileInfo.Name, angleFileName));
+ }
+
+ TSStreamClipFile angleClipFile = null;
+ string angleClipFileName = string.Format(
+ "{0}.CLPI", angleName);
+ if (streamClipFiles.ContainsKey(angleClipFileName))
+ {
+ angleClipFile = streamClipFiles[angleClipFileName];
+ }
+ if (angleClipFile == null)
+ {
+ throw new Exception(string.Format(
+ "Playlist {0} referenced missing angle file {1}.",
+ FileInfo.Name, angleClipFileName));
+ }
+
+ TSStreamClip angleClip =
+ new TSStreamClip(angleFile, angleClipFile);
+ angleClip.AngleIndex = angle + 1;
+ angleClip.TimeIn = streamClip.TimeIn;
+ angleClip.TimeOut = streamClip.TimeOut;
+ angleClip.RelativeTimeIn = streamClip.RelativeTimeIn;
+ angleClip.RelativeTimeOut = streamClip.RelativeTimeOut;
+ angleClip.Length = streamClip.Length;
+ StreamClips.Add(angleClip);
+ }
+ if (angles - 1 > AngleCount) AngleCount = angles - 1;
+ }
+
+ int streamInfoLength = ReadInt16(data, ref pos);
+ pos += 2;
+ int streamCountVideo = data[pos++];
+ int streamCountAudio = data[pos++];
+ int streamCountPG = data[pos++];
+ int streamCountIG = data[pos++];
+ int streamCountSecondaryAudio = data[pos++];
+ int streamCountSecondaryVideo = data[pos++];
+ int streamCountPIP = data[pos++];
+ pos += 5;
+
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "{0} : {1} -> V:{2} A:{3} PG:{4} IG:{5} 2A:{6} 2V:{7} PIP:{8}",
+ Name, streamFileName, streamCountVideo, streamCountAudio, streamCountPG, streamCountIG,
+ streamCountSecondaryAudio, streamCountSecondaryVideo, streamCountPIP));
+#endif
+
+ for (int i = 0; i < streamCountVideo; i++)
+ {
+ TSStream stream = CreatePlaylistStream(data, ref pos);
+ if (stream != null) PlaylistStreams[stream.PID] = stream;
+ }
+ for (int i = 0; i < streamCountAudio; i++)
+ {
+ TSStream stream = CreatePlaylistStream(data, ref pos);
+ if (stream != null) PlaylistStreams[stream.PID] = stream;
+ }
+ for (int i = 0; i < streamCountPG; i++)
+ {
+ TSStream stream = CreatePlaylistStream(data, ref pos);
+ if (stream != null) PlaylistStreams[stream.PID] = stream;
+ }
+ for (int i = 0; i < streamCountIG; i++)
+ {
+ TSStream stream = CreatePlaylistStream(data, ref pos);
+ if (stream != null) PlaylistStreams[stream.PID] = stream;
+ }
+ for (int i = 0; i < streamCountSecondaryAudio; i++)
+ {
+ TSStream stream = CreatePlaylistStream(data, ref pos);
+ if (stream != null) PlaylistStreams[stream.PID] = stream;
+ pos += 2;
+ }
+ for (int i = 0; i < streamCountSecondaryVideo; i++)
+ {
+ TSStream stream = CreatePlaylistStream(data, ref pos);
+ if (stream != null) PlaylistStreams[stream.PID] = stream;
+ pos += 6;
+ }
+ /*
+ * TODO
+ *
+ for (int i = 0; i < streamCountPIP; i++)
+ {
+ TSStream stream = CreatePlaylistStream(data, ref pos);
+ if (stream != null) PlaylistStreams[stream.PID] = stream;
+ }
+ */
+
+ pos += itemLength - (pos - itemStart) + 2;
+ }
+
+ pos = chaptersOffset + 4;
+
+ int chapterCount = ReadInt16(data, ref pos);
+
+ for (int chapterIndex = 0;
+ chapterIndex < chapterCount;
+ chapterIndex++)
+ {
+ int chapterType = data[pos+1];
+
+ if (chapterType == 1)
+ {
+ int streamFileIndex =
+ ((int)data[pos + 2] << 8) + data[pos + 3];
+
+ long chapterTime =
+ ((long)data[pos + 4] << 24) +
+ ((long)data[pos + 5] << 16) +
+ ((long)data[pos + 6] << 8) +
+ ((long)data[pos + 7]);
+
+ TSStreamClip streamClip = chapterClips[streamFileIndex];
+
+ double chapterSeconds = (double)chapterTime / 45000;
+
+ double relativeSeconds =
+ chapterSeconds -
+ streamClip.TimeIn +
+ streamClip.RelativeTimeIn;
+
+ // TODO: Ignore short last chapter?
+ if (TotalLength - relativeSeconds > 1.0)
+ {
+ streamClip.Chapters.Add(chapterSeconds);
+ this.Chapters.Add(relativeSeconds);
+ }
+ }
+ else
+ {
+ // TODO: Handle other chapter types?
+ }
+ pos += 14;
+ }
+ }
+ finally
+ {
+ if (fileReader != null)
+ {
+ fileReader.Close();
+ }
+ if (fileStream != null)
+ {
+ fileStream.Close();
+ }
+ }
+ }
+
+ public void Initialize()
+ {
+ LoadStreamClips();
+
+ Dictionary> clipTimes = new Dictionary>();
+ foreach (TSStreamClip clip in StreamClips)
+ {
+ if (clip.AngleIndex == 0)
+ {
+ if (clipTimes.ContainsKey(clip.Name))
+ {
+ if (clipTimes[clip.Name].Contains(clip.TimeIn))
+ {
+ HasLoops = true;
+ break;
+ }
+ else
+ {
+ clipTimes[clip.Name].Add(clip.TimeIn);
+ }
+ }
+ else
+ {
+ clipTimes[clip.Name] = new List { clip.TimeIn };
+ }
+ }
+ }
+ ClearBitrates();
+ IsInitialized = true;
+ }
+
+ protected TSStream CreatePlaylistStream(byte[] data, ref int pos)
+ {
+ TSStream stream = null;
+
+ int start = pos;
+
+ int headerLength = data[pos++];
+ int headerPos = pos;
+ int headerType = data[pos++];
+
+ int pid = 0;
+ int subpathid = 0;
+ int subclipid = 0;
+
+ switch (headerType)
+ {
+ case 1:
+ pid = ReadInt16(data, ref pos);
+ break;
+ case 2:
+ subpathid = data[pos++];
+ subclipid = data[pos++];
+ pid = ReadInt16(data, ref pos);
+ break;
+ case 3:
+ subpathid = data[pos++];
+ pid = ReadInt16(data, ref pos);
+ break;
+ case 4:
+ subpathid = data[pos++];
+ subclipid = data[pos++];
+ pid = ReadInt16(data, ref pos);
+ break;
+ default:
+ break;
+ }
+
+ pos = headerPos + headerLength;
+
+ int streamLength = data[pos++];
+ int streamPos = pos;
+
+ TSStreamType streamType = (TSStreamType)data[pos++];
+ switch (streamType)
+ {
+ case TSStreamType.MVC_VIDEO:
+ // TODO
+ break;
+
+ case TSStreamType.AVC_VIDEO:
+ case TSStreamType.MPEG1_VIDEO:
+ case TSStreamType.MPEG2_VIDEO:
+ case TSStreamType.VC1_VIDEO:
+
+ TSVideoFormat videoFormat = (TSVideoFormat)
+ (data[pos] >> 4);
+ TSFrameRate frameRate = (TSFrameRate)
+ (data[pos] & 0xF);
+ TSAspectRatio aspectRatio = (TSAspectRatio)
+ (data[pos + 1] >> 4);
+
+ stream = new TSVideoStream();
+ ((TSVideoStream)stream).VideoFormat = videoFormat;
+ ((TSVideoStream)stream).AspectRatio = aspectRatio;
+ ((TSVideoStream)stream).FrameRate = frameRate;
+
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\t{0} {1} {2} {3} {4}",
+ pid,
+ streamType,
+ videoFormat,
+ frameRate,
+ aspectRatio));
+#endif
+
+ break;
+
+ case TSStreamType.AC3_AUDIO:
+ case TSStreamType.AC3_PLUS_AUDIO:
+ case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
+ case TSStreamType.DTS_AUDIO:
+ case TSStreamType.DTS_HD_AUDIO:
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ case TSStreamType.DTS_HD_SECONDARY_AUDIO:
+ case TSStreamType.LPCM_AUDIO:
+ case TSStreamType.MPEG1_AUDIO:
+ case TSStreamType.MPEG2_AUDIO:
+
+ int audioFormat = ReadByte(data, ref pos);
+
+ TSChannelLayout channelLayout = (TSChannelLayout)
+ (audioFormat >> 4);
+ TSSampleRate sampleRate = (TSSampleRate)
+ (audioFormat & 0xF);
+
+ string audioLanguage = ReadString(data, 3, ref pos);
+
+ stream = new TSAudioStream();
+ ((TSAudioStream)stream).ChannelLayout = channelLayout;
+ ((TSAudioStream)stream).SampleRate = TSAudioStream.ConvertSampleRate(sampleRate);
+ ((TSAudioStream)stream).LanguageCode = audioLanguage;
+
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\t{0} {1} {2} {3} {4}",
+ pid,
+ streamType,
+ audioLanguage,
+ channelLayout,
+ sampleRate));
+#endif
+
+ break;
+
+ case TSStreamType.INTERACTIVE_GRAPHICS:
+ case TSStreamType.PRESENTATION_GRAPHICS:
+
+ string graphicsLanguage = ReadString(data, 3, ref pos);
+
+ stream = new TSGraphicsStream();
+ ((TSGraphicsStream)stream).LanguageCode = graphicsLanguage;
+
+ if (data[pos] != 0)
+ {
+ }
+
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\t{0} {1} {2}",
+ pid,
+ streamType,
+ graphicsLanguage));
+#endif
+
+ break;
+
+ case TSStreamType.SUBTITLE:
+
+ int code = ReadByte(data, ref pos); // TODO
+ string textLanguage = ReadString(data, 3, ref pos);
+
+ stream = new TSTextStream();
+ ((TSTextStream)stream).LanguageCode = textLanguage;
+
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\t{0} {1} {2}",
+ pid,
+ streamType,
+ textLanguage));
+#endif
+
+ break;
+
+ default:
+ break;
+ }
+
+ pos = streamPos + streamLength;
+
+ if (stream != null)
+ {
+ stream.PID = (ushort)pid;
+ stream.StreamType = streamType;
+ }
+
+ return stream;
+ }
+
+ private void LoadStreamClips()
+ {
+ AngleClips.Clear();
+ if (AngleCount > 0)
+ {
+ for (int angleIndex = 0; angleIndex < AngleCount; angleIndex++)
+ {
+ AngleClips.Add(new Dictionary());
+ }
+ }
+
+ TSStreamClip referenceClip = null;
+ if (StreamClips.Count > 0)
+ {
+ referenceClip = StreamClips[0];
+ }
+ foreach (TSStreamClip clip in StreamClips)
+ {
+ if (clip.StreamClipFile.Streams.Count > referenceClip.StreamClipFile.Streams.Count)
+ {
+ referenceClip = clip;
+ }
+ else if (clip.Length > referenceClip.Length)
+ {
+ referenceClip = clip;
+ }
+ if (AngleCount > 0)
+ {
+ if (clip.AngleIndex == 0)
+ {
+ for (int angleIndex = 0; angleIndex < AngleCount; angleIndex++)
+ {
+ AngleClips[angleIndex][clip.RelativeTimeIn] = clip;
+ }
+ }
+ else
+ {
+ AngleClips[clip.AngleIndex - 1][clip.RelativeTimeIn] = clip;
+ }
+ }
+ }
+
+ foreach (TSStream clipStream
+ in referenceClip.StreamClipFile.Streams.Values)
+ {
+ if (!Streams.ContainsKey(clipStream.PID))
+ {
+ TSStream stream = clipStream.Clone();
+ Streams[clipStream.PID] = stream;
+
+ if (!IsCustom && !PlaylistStreams.ContainsKey(stream.PID))
+ {
+ stream.IsHidden = true;
+ HasHiddenTracks = true;
+ }
+
+ if (stream.IsVideoStream)
+ {
+ VideoStreams.Add((TSVideoStream)stream);
+ }
+ else if (stream.IsAudioStream)
+ {
+ AudioStreams.Add((TSAudioStream)stream);
+ }
+ else if (stream.IsGraphicsStream)
+ {
+ GraphicsStreams.Add((TSGraphicsStream)stream);
+ }
+ else if (stream.IsTextStream)
+ {
+ TextStreams.Add((TSTextStream)stream);
+ }
+ }
+ }
+
+ if (referenceClip.StreamFile != null)
+ {
+ // TODO: Better way to add this in?
+ if (BDInfoSettings.EnableSSIF &&
+ referenceClip.StreamFile.InterleavedFile != null &&
+ referenceClip.StreamFile.Streams.ContainsKey(4114) &&
+ !Streams.ContainsKey(4114))
+ {
+ TSStream stream = referenceClip.StreamFile.Streams[4114].Clone();
+ Streams[4114] = stream;
+ if (stream.IsVideoStream)
+ {
+ VideoStreams.Add((TSVideoStream)stream);
+ }
+ }
+
+ foreach (TSStream clipStream
+ in referenceClip.StreamFile.Streams.Values)
+ {
+ if (Streams.ContainsKey(clipStream.PID))
+ {
+ TSStream stream = Streams[clipStream.PID];
+
+ if (stream.StreamType != clipStream.StreamType) continue;
+
+ if (clipStream.BitRate > stream.BitRate)
+ {
+ stream.BitRate = clipStream.BitRate;
+ }
+ stream.IsVBR = clipStream.IsVBR;
+
+ if (stream.IsVideoStream &&
+ clipStream.IsVideoStream)
+ {
+ ((TSVideoStream)stream).EncodingProfile =
+ ((TSVideoStream)clipStream).EncodingProfile;
+ }
+ else if (stream.IsAudioStream &&
+ clipStream.IsAudioStream)
+ {
+ TSAudioStream audioStream = (TSAudioStream)stream;
+ TSAudioStream clipAudioStream = (TSAudioStream)clipStream;
+
+ if (clipAudioStream.ChannelCount > audioStream.ChannelCount)
+ {
+ audioStream.ChannelCount = clipAudioStream.ChannelCount;
+ }
+ if (clipAudioStream.LFE > audioStream.LFE)
+ {
+ audioStream.LFE = clipAudioStream.LFE;
+ }
+ if (clipAudioStream.SampleRate > audioStream.SampleRate)
+ {
+ audioStream.SampleRate = clipAudioStream.SampleRate;
+ }
+ if (clipAudioStream.BitDepth > audioStream.BitDepth)
+ {
+ audioStream.BitDepth = clipAudioStream.BitDepth;
+ }
+ if (clipAudioStream.DialNorm < audioStream.DialNorm)
+ {
+ audioStream.DialNorm = clipAudioStream.DialNorm;
+ }
+ if (clipAudioStream.AudioMode != TSAudioMode.Unknown)
+ {
+ audioStream.AudioMode = clipAudioStream.AudioMode;
+ }
+ if (clipAudioStream.CoreStream != null &&
+ audioStream.CoreStream == null)
+ {
+ audioStream.CoreStream = (TSAudioStream)
+ clipAudioStream.CoreStream.Clone();
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < AngleCount; i++)
+ {
+ AngleStreams.Add(new Dictionary());
+ }
+
+ if (!BDInfoSettings.KeepStreamOrder)
+ {
+ VideoStreams.Sort(CompareVideoStreams);
+ }
+ foreach (TSStream stream in VideoStreams)
+ {
+ SortedStreams.Add(stream);
+ for (int i = 0; i < AngleCount; i++)
+ {
+ TSStream angleStream = stream.Clone();
+ angleStream.AngleIndex = i + 1;
+ AngleStreams[i][angleStream.PID] = angleStream;
+ SortedStreams.Add(angleStream);
+ }
+ }
+
+ if (!BDInfoSettings.KeepStreamOrder)
+ {
+ AudioStreams.Sort(CompareAudioStreams);
+ }
+ foreach (TSStream stream in AudioStreams)
+ {
+ SortedStreams.Add(stream);
+ }
+
+ if (!BDInfoSettings.KeepStreamOrder)
+ {
+ GraphicsStreams.Sort(CompareGraphicsStreams);
+ }
+ foreach (TSStream stream in GraphicsStreams)
+ {
+ SortedStreams.Add(stream);
+ }
+
+ if (!BDInfoSettings.KeepStreamOrder)
+ {
+ TextStreams.Sort(CompareTextStreams);
+ }
+ foreach (TSStream stream in TextStreams)
+ {
+ SortedStreams.Add(stream);
+ }
+ }
+
+ public void ClearBitrates()
+ {
+ foreach (TSStreamClip clip in StreamClips)
+ {
+ clip.PayloadBytes = 0;
+ clip.PacketCount = 0;
+ clip.PacketSeconds = 0;
+
+ if (clip.StreamFile != null)
+ {
+ foreach (TSStream stream in clip.StreamFile.Streams.Values)
+ {
+ stream.PayloadBytes = 0;
+ stream.PacketCount = 0;
+ stream.PacketSeconds = 0;
+ }
+
+ if (clip.StreamFile != null &&
+ clip.StreamFile.StreamDiagnostics != null)
+ {
+ clip.StreamFile.StreamDiagnostics.Clear();
+ }
+ }
+ }
+
+ foreach (TSStream stream in SortedStreams)
+ {
+ stream.PayloadBytes = 0;
+ stream.PacketCount = 0;
+ stream.PacketSeconds = 0;
+ }
+ }
+
+ public bool IsValid
+ {
+ get
+ {
+ if (!IsInitialized) return false;
+
+ if (BDInfoSettings.FilterShortPlaylists &&
+ TotalLength < BDInfoSettings.FilterShortPlaylistsValue)
+ {
+ return false;
+ }
+
+ if (HasLoops &&
+ BDInfoSettings.FilterLoopingPlaylists)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ public static int CompareVideoStreams(
+ TSVideoStream x,
+ TSVideoStream y)
+ {
+ if (x == null && y == null)
+ {
+ return 0;
+ }
+ else if (x == null && y != null)
+ {
+ return 1;
+ }
+ else if (x != null && y == null)
+ {
+ return -1;
+ }
+ else
+ {
+ if (x.Height > y.Height)
+ {
+ return -1;
+ }
+ else if (y.Height > x.Height)
+ {
+ return 1;
+ }
+ else if (x.PID > y.PID)
+ {
+ return 1;
+ }
+ else if (y.PID > x.PID)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+
+ public static int CompareAudioStreams(
+ TSAudioStream x,
+ TSAudioStream y)
+ {
+ if (x == y)
+ {
+ return 0;
+ }
+ else if (x == null && y == null)
+ {
+ return 0;
+ }
+ else if (x == null && y != null)
+ {
+ return -1;
+ }
+ else if (x != null && y == null)
+ {
+ return 1;
+ }
+ else
+ {
+ if (x.ChannelCount > y.ChannelCount)
+ {
+ return -1;
+ }
+ else if (y.ChannelCount > x.ChannelCount)
+ {
+ return 1;
+ }
+ else
+ {
+ int sortX = GetStreamTypeSortIndex(x.StreamType);
+ int sortY = GetStreamTypeSortIndex(y.StreamType);
+
+ if (sortX > sortY)
+ {
+ return -1;
+ }
+ else if (sortY > sortX)
+ {
+ return 1;
+ }
+ else
+ {
+ if (x.LanguageCode == "eng")
+ {
+ return -1;
+ }
+ else if (y.LanguageCode == "eng")
+ {
+ return 1;
+ }
+ else if (x.LanguageCode != y.LanguageCode)
+ {
+ return string.Compare(
+ x.LanguageName, y.LanguageName);
+ }
+ else if (x.PID < y.PID)
+ {
+ return -1;
+ }
+ else if (y.PID < x.PID)
+ {
+ return 1;
+ }
+ return 0;
+ }
+ }
+ }
+ }
+
+ public static int CompareTextStreams(
+ TSTextStream x,
+ TSTextStream y)
+ {
+ if (x == y)
+ {
+ return 0;
+ }
+ else if (x == null && y == null)
+ {
+ return 0;
+ }
+ else if (x == null && y != null)
+ {
+ return -1;
+ }
+ else if (x != null && y == null)
+ {
+ return 1;
+ }
+ else
+ {
+ if (x.LanguageCode == "eng")
+ {
+ return -1;
+ }
+ else if (y.LanguageCode == "eng")
+ {
+ return 1;
+ }
+ else
+ {
+ if (x.LanguageCode == y.LanguageCode)
+ {
+ if (x.PID > y.PID)
+ {
+ return 1;
+ }
+ else if (y.PID > x.PID)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return string.Compare(
+ x.LanguageName, y.LanguageName);
+ }
+ }
+ }
+ }
+
+ private static int CompareGraphicsStreams(
+ TSGraphicsStream x,
+ TSGraphicsStream y)
+ {
+ if (x == y)
+ {
+ return 0;
+ }
+ else if (x == null && y == null)
+ {
+ return 0;
+ }
+ else if (x == null && y != null)
+ {
+ return -1;
+ }
+ else if (x != null && y == null)
+ {
+ return 1;
+ }
+ else
+ {
+ int sortX = GetStreamTypeSortIndex(x.StreamType);
+ int sortY = GetStreamTypeSortIndex(y.StreamType);
+
+ if (sortX > sortY)
+ {
+ return -1;
+ }
+ else if (sortY > sortX)
+ {
+ return 1;
+ }
+ else if (x.LanguageCode == "eng")
+ {
+ return -1;
+ }
+ else if (y.LanguageCode == "eng")
+ {
+ return 1;
+ }
+ else
+ {
+ if (x.LanguageCode == y.LanguageCode)
+ {
+ if (x.PID > y.PID)
+ {
+ return 1;
+ }
+ else if (y.PID > x.PID)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ return string.Compare(x.LanguageName, y.LanguageName);
+ }
+ }
+ }
+ }
+
+ private static int GetStreamTypeSortIndex(TSStreamType streamType)
+ {
+ switch (streamType)
+ {
+ case TSStreamType.Unknown:
+ return 0;
+ case TSStreamType.MPEG1_VIDEO:
+ return 1;
+ case TSStreamType.MPEG2_VIDEO:
+ return 2;
+ case TSStreamType.AVC_VIDEO:
+ return 3;
+ case TSStreamType.VC1_VIDEO:
+ return 4;
+ case TSStreamType.MVC_VIDEO:
+ return 5;
+
+ case TSStreamType.MPEG1_AUDIO:
+ return 1;
+ case TSStreamType.MPEG2_AUDIO:
+ return 2;
+ case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
+ return 3;
+ case TSStreamType.DTS_HD_SECONDARY_AUDIO:
+ return 4;
+ case TSStreamType.AC3_AUDIO:
+ return 5;
+ case TSStreamType.DTS_AUDIO:
+ return 6;
+ case TSStreamType.AC3_PLUS_AUDIO:
+ return 7;
+ case TSStreamType.DTS_HD_AUDIO:
+ return 8;
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
+ return 9;
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ return 10;
+ case TSStreamType.LPCM_AUDIO:
+ return 11;
+
+ case TSStreamType.SUBTITLE:
+ return 1;
+ case TSStreamType.INTERACTIVE_GRAPHICS:
+ return 2;
+ case TSStreamType.PRESENTATION_GRAPHICS:
+ return 3;
+
+ default:
+ return 0;
+ }
+ }
+
+ protected string ReadString(
+ byte[] data,
+ int count,
+ ref int pos)
+ {
+ string val =
+ ASCIIEncoding.ASCII.GetString(data, pos, count);
+
+ pos += count;
+
+ return val;
+ }
+
+ protected int ReadInt32(
+ byte[] data,
+ ref int pos)
+ {
+ int val =
+ ((int)data[pos] << 24) +
+ ((int)data[pos + 1] << 16) +
+ ((int)data[pos + 2] << 8) +
+ ((int)data[pos + 3]);
+
+ pos += 4;
+
+ return val;
+ }
+
+ protected int ReadInt16(
+ byte[] data,
+ ref int pos)
+ {
+ int val =
+ ((int)data[pos] << 8) +
+ ((int)data[pos + 1]);
+
+ pos += 2;
+
+ return val;
+ }
+
+ protected byte ReadByte(
+ byte[] data,
+ ref int pos)
+ {
+ return data[pos++];
+ }
+ }
+}
diff --git a/BDInfo/TSStream.cs b/BDInfo/TSStream.cs
new file mode 100644
index 0000000000..5324acae4c
--- /dev/null
+++ b/BDInfo/TSStream.cs
@@ -0,0 +1,802 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public enum TSStreamType : byte
+ {
+ Unknown = 0,
+ MPEG1_VIDEO = 0x01,
+ MPEG2_VIDEO = 0x02,
+ AVC_VIDEO = 0x1b,
+ MVC_VIDEO = 0x20,
+ VC1_VIDEO = 0xea,
+ MPEG1_AUDIO = 0x03,
+ MPEG2_AUDIO = 0x04,
+ LPCM_AUDIO = 0x80,
+ AC3_AUDIO = 0x81,
+ AC3_PLUS_AUDIO = 0x84,
+ AC3_PLUS_SECONDARY_AUDIO = 0xA1,
+ AC3_TRUE_HD_AUDIO = 0x83,
+ DTS_AUDIO = 0x82,
+ DTS_HD_AUDIO = 0x85,
+ DTS_HD_SECONDARY_AUDIO = 0xA2,
+ DTS_HD_MASTER_AUDIO = 0x86,
+ PRESENTATION_GRAPHICS = 0x90,
+ INTERACTIVE_GRAPHICS = 0x91,
+ SUBTITLE = 0x92
+ }
+
+ public enum TSVideoFormat : byte
+ {
+ Unknown = 0,
+ VIDEOFORMAT_480i = 1,
+ VIDEOFORMAT_576i = 2,
+ VIDEOFORMAT_480p = 3,
+ VIDEOFORMAT_1080i = 4,
+ VIDEOFORMAT_720p = 5,
+ VIDEOFORMAT_1080p = 6,
+ VIDEOFORMAT_576p = 7,
+ }
+
+ public enum TSFrameRate : byte
+ {
+ Unknown = 0,
+ FRAMERATE_23_976 = 1,
+ FRAMERATE_24 = 2,
+ FRAMERATE_25 = 3,
+ FRAMERATE_29_97 = 4,
+ FRAMERATE_50 = 6,
+ FRAMERATE_59_94 = 7
+ }
+
+ public enum TSChannelLayout : byte
+ {
+ Unknown = 0,
+ CHANNELLAYOUT_MONO = 1,
+ CHANNELLAYOUT_STEREO = 3,
+ CHANNELLAYOUT_MULTI = 6,
+ CHANNELLAYOUT_COMBO = 12
+ }
+
+ public enum TSSampleRate : byte
+ {
+ Unknown = 0,
+ SAMPLERATE_48 = 1,
+ SAMPLERATE_96 = 4,
+ SAMPLERATE_192 = 5,
+ SAMPLERATE_48_192 = 12,
+ SAMPLERATE_48_96 = 14
+ }
+
+ public enum TSAspectRatio
+ {
+ Unknown = 0,
+ ASPECT_4_3 = 2,
+ ASPECT_16_9 = 3,
+ ASPECT_2_21 = 4
+ }
+
+ public class TSDescriptor
+ {
+ public byte Name;
+ public byte[] Value;
+
+ public TSDescriptor(byte name, byte length)
+ {
+ Name = name;
+ Value = new byte[length];
+ }
+
+ public TSDescriptor Clone()
+ {
+ TSDescriptor descriptor =
+ new TSDescriptor(Name, (byte)Value.Length);
+ Value.CopyTo(descriptor.Value, 0);
+ return descriptor;
+ }
+ }
+
+ public abstract class TSStream
+ {
+ public TSStream()
+ {
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{0} ({1})", CodecShortName, PID);
+ }
+
+ public ushort PID;
+ public TSStreamType StreamType;
+ public List Descriptors = null;
+ public long BitRate = 0;
+ public long ActiveBitRate = 0;
+ public bool IsVBR = false;
+ public bool IsInitialized = false;
+ public string LanguageName;
+ public bool IsHidden = false;
+
+ public ulong PayloadBytes = 0;
+ public ulong PacketCount = 0;
+ public double PacketSeconds = 0;
+ public int AngleIndex = 0;
+
+ public ulong PacketSize
+ {
+ get
+ {
+ return PacketCount * 192;
+ }
+ }
+
+ private string _LanguageCode;
+ public string LanguageCode
+ {
+ get
+ {
+ return _LanguageCode;
+ }
+ set
+ {
+ _LanguageCode = value;
+ LanguageName = LanguageCodes.GetName(value);
+ }
+ }
+
+ public bool IsVideoStream
+ {
+ get
+ {
+ switch (StreamType)
+ {
+ case TSStreamType.MPEG1_VIDEO:
+ case TSStreamType.MPEG2_VIDEO:
+ case TSStreamType.AVC_VIDEO:
+ case TSStreamType.MVC_VIDEO:
+ case TSStreamType.VC1_VIDEO:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ public bool IsAudioStream
+ {
+ get
+ {
+ switch (StreamType)
+ {
+ case TSStreamType.MPEG1_AUDIO:
+ case TSStreamType.MPEG2_AUDIO:
+ case TSStreamType.LPCM_AUDIO:
+ case TSStreamType.AC3_AUDIO:
+ case TSStreamType.AC3_PLUS_AUDIO:
+ case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
+ case TSStreamType.DTS_AUDIO:
+ case TSStreamType.DTS_HD_AUDIO:
+ case TSStreamType.DTS_HD_SECONDARY_AUDIO:
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ public bool IsGraphicsStream
+ {
+ get
+ {
+ switch (StreamType)
+ {
+ case TSStreamType.PRESENTATION_GRAPHICS:
+ case TSStreamType.INTERACTIVE_GRAPHICS:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ public bool IsTextStream
+ {
+ get
+ {
+ switch (StreamType)
+ {
+ case TSStreamType.SUBTITLE:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ public string CodecName
+ {
+ get
+ {
+ switch (StreamType)
+ {
+ case TSStreamType.MPEG1_VIDEO:
+ return "MPEG-1 Video";
+ case TSStreamType.MPEG2_VIDEO:
+ return "MPEG-2 Video";
+ case TSStreamType.AVC_VIDEO:
+ return "MPEG-4 AVC Video";
+ case TSStreamType.MVC_VIDEO:
+ return "MPEG-4 MVC Video";
+ case TSStreamType.VC1_VIDEO:
+ return "VC-1 Video";
+ case TSStreamType.MPEG1_AUDIO:
+ return "MP1 Audio";
+ case TSStreamType.MPEG2_AUDIO:
+ return "MP2 Audio";
+ case TSStreamType.LPCM_AUDIO:
+ return "LPCM Audio";
+ case TSStreamType.AC3_AUDIO:
+ if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
+ return "Dolby Digital EX Audio";
+ else
+ return "Dolby Digital Audio";
+ case TSStreamType.AC3_PLUS_AUDIO:
+ case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
+ return "Dolby Digital Plus Audio";
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
+ return "Dolby TrueHD Audio";
+ case TSStreamType.DTS_AUDIO:
+ if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
+ return "DTS-ES Audio";
+ else
+ return "DTS Audio";
+ case TSStreamType.DTS_HD_AUDIO:
+ return "DTS-HD High-Res Audio";
+ case TSStreamType.DTS_HD_SECONDARY_AUDIO:
+ return "DTS Express";
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ return "DTS-HD Master Audio";
+ case TSStreamType.PRESENTATION_GRAPHICS:
+ return "Presentation Graphics";
+ case TSStreamType.INTERACTIVE_GRAPHICS:
+ return "Interactive Graphics";
+ case TSStreamType.SUBTITLE:
+ return "Subtitle";
+ default:
+ return "UNKNOWN";
+ }
+ }
+ }
+
+ public string CodecAltName
+ {
+ get
+ {
+ switch (StreamType)
+ {
+ case TSStreamType.MPEG1_VIDEO:
+ return "MPEG-1";
+ case TSStreamType.MPEG2_VIDEO:
+ return "MPEG-2";
+ case TSStreamType.AVC_VIDEO:
+ return "AVC";
+ case TSStreamType.MVC_VIDEO:
+ return "MVC";
+ case TSStreamType.VC1_VIDEO:
+ return "VC-1";
+ case TSStreamType.MPEG1_AUDIO:
+ return "MP1";
+ case TSStreamType.MPEG2_AUDIO:
+ return "MP2";
+ case TSStreamType.LPCM_AUDIO:
+ return "LPCM";
+ case TSStreamType.AC3_AUDIO:
+ return "DD AC3";
+ case TSStreamType.AC3_PLUS_AUDIO:
+ case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
+ return "DD AC3+";
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
+ return "Dolby TrueHD";
+ case TSStreamType.DTS_AUDIO:
+ return "DTS";
+ case TSStreamType.DTS_HD_AUDIO:
+ return "DTS-HD Hi-Res";
+ case TSStreamType.DTS_HD_SECONDARY_AUDIO:
+ return "DTS Express";
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ return "DTS-HD Master";
+ case TSStreamType.PRESENTATION_GRAPHICS:
+ return "PGS";
+ case TSStreamType.INTERACTIVE_GRAPHICS:
+ return "IGS";
+ case TSStreamType.SUBTITLE:
+ return "SUB";
+ default:
+ return "UNKNOWN";
+ }
+ }
+ }
+
+ public string CodecShortName
+ {
+ get
+ {
+ switch (StreamType)
+ {
+ case TSStreamType.MPEG1_VIDEO:
+ return "MPEG-1";
+ case TSStreamType.MPEG2_VIDEO:
+ return "MPEG-2";
+ case TSStreamType.AVC_VIDEO:
+ return "AVC";
+ case TSStreamType.MVC_VIDEO:
+ return "MVC";
+ case TSStreamType.VC1_VIDEO:
+ return "VC-1";
+ case TSStreamType.MPEG1_AUDIO:
+ return "MP1";
+ case TSStreamType.MPEG2_AUDIO:
+ return "MP2";
+ case TSStreamType.LPCM_AUDIO:
+ return "LPCM";
+ case TSStreamType.AC3_AUDIO:
+ if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
+ return "AC3-EX";
+ else
+ return "AC3";
+ case TSStreamType.AC3_PLUS_AUDIO:
+ case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
+ return "AC3+";
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
+ return "TrueHD";
+ case TSStreamType.DTS_AUDIO:
+ if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended)
+ return "DTS-ES";
+ else
+ return "DTS";
+ case TSStreamType.DTS_HD_AUDIO:
+ return "DTS-HD HR";
+ case TSStreamType.DTS_HD_SECONDARY_AUDIO:
+ return "DTS Express";
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ return "DTS-HD MA";
+ case TSStreamType.PRESENTATION_GRAPHICS:
+ return "PGS";
+ case TSStreamType.INTERACTIVE_GRAPHICS:
+ return "IGS";
+ case TSStreamType.SUBTITLE:
+ return "SUB";
+ default:
+ return "UNKNOWN";
+ }
+ }
+ }
+
+ public virtual string Description
+ {
+ get
+ {
+ return "";
+ }
+ }
+
+ public abstract TSStream Clone();
+
+ protected void CopyTo(TSStream stream)
+ {
+ stream.PID = PID;
+ stream.StreamType = StreamType;
+ stream.IsVBR = IsVBR;
+ stream.BitRate = BitRate;
+ stream.IsInitialized = IsInitialized;
+ stream.LanguageCode = _LanguageCode;
+ if (Descriptors != null)
+ {
+ stream.Descriptors = new List();
+ foreach (TSDescriptor descriptor in Descriptors)
+ {
+ stream.Descriptors.Add(descriptor.Clone());
+ }
+ }
+ }
+ }
+
+ public class TSVideoStream : TSStream
+ {
+ public TSVideoStream()
+ {
+ }
+
+ public int Width;
+ public int Height;
+ public bool IsInterlaced;
+ public int FrameRateEnumerator;
+ public int FrameRateDenominator;
+ public TSAspectRatio AspectRatio;
+ public string EncodingProfile;
+
+ private TSVideoFormat _VideoFormat;
+ public TSVideoFormat VideoFormat
+ {
+ get
+ {
+ return _VideoFormat;
+ }
+ set
+ {
+ _VideoFormat = value;
+ switch (value)
+ {
+ case TSVideoFormat.VIDEOFORMAT_480i:
+ Height = 480;
+ IsInterlaced = true;
+ break;
+ case TSVideoFormat.VIDEOFORMAT_480p:
+ Height = 480;
+ IsInterlaced = false;
+ break;
+ case TSVideoFormat.VIDEOFORMAT_576i:
+ Height = 576;
+ IsInterlaced = true;
+ break;
+ case TSVideoFormat.VIDEOFORMAT_576p:
+ Height = 576;
+ IsInterlaced = false;
+ break;
+ case TSVideoFormat.VIDEOFORMAT_720p:
+ Height = 720;
+ IsInterlaced = false;
+ break;
+ case TSVideoFormat.VIDEOFORMAT_1080i:
+ Height = 1080;
+ IsInterlaced = true;
+ break;
+ case TSVideoFormat.VIDEOFORMAT_1080p:
+ Height = 1080;
+ IsInterlaced = false;
+ break;
+ }
+ }
+ }
+
+ private TSFrameRate _FrameRate;
+ public TSFrameRate FrameRate
+ {
+ get
+ {
+ return _FrameRate;
+ }
+ set
+ {
+ _FrameRate = value;
+ switch (value)
+ {
+ case TSFrameRate.FRAMERATE_23_976:
+ FrameRateEnumerator = 24000;
+ FrameRateDenominator = 1001;
+ break;
+ case TSFrameRate.FRAMERATE_24:
+ FrameRateEnumerator = 24000;
+ FrameRateDenominator = 1000;
+ break;
+ case TSFrameRate.FRAMERATE_25:
+ FrameRateEnumerator = 25000;
+ FrameRateDenominator = 1000;
+ break;
+ case TSFrameRate.FRAMERATE_29_97:
+ FrameRateEnumerator = 30000;
+ FrameRateDenominator = 1001;
+ break;
+ case TSFrameRate.FRAMERATE_50:
+ FrameRateEnumerator = 50000;
+ FrameRateDenominator = 1000;
+ break;
+ case TSFrameRate.FRAMERATE_59_94:
+ FrameRateEnumerator = 60000;
+ FrameRateDenominator = 1001;
+ break;
+ }
+ }
+ }
+
+ public override string Description
+ {
+ get
+ {
+ string description = "";
+
+ if (Height > 0)
+ {
+ description += string.Format("{0:D}{1} / ",
+ Height,
+ IsInterlaced ? "i" : "p");
+ }
+ if (FrameRateEnumerator > 0 &&
+ FrameRateDenominator > 0)
+ {
+ if (FrameRateEnumerator % FrameRateDenominator == 0)
+ {
+ description += string.Format("{0:D} fps / ",
+ FrameRateEnumerator / FrameRateDenominator);
+ }
+ else
+ {
+ description += string.Format("{0:F3} fps / ",
+ (double)FrameRateEnumerator / FrameRateDenominator);
+ }
+
+ }
+ if (AspectRatio == TSAspectRatio.ASPECT_4_3)
+ {
+ description += "4:3 / ";
+ }
+ else if (AspectRatio == TSAspectRatio.ASPECT_16_9)
+ {
+ description += "16:9 / ";
+ }
+ if (EncodingProfile != null)
+ {
+ description += EncodingProfile + " / ";
+ }
+ if (description.EndsWith(" / "))
+ {
+ description = description.Substring(0, description.Length - 3);
+ }
+ return description;
+ }
+ }
+
+ public override TSStream Clone()
+ {
+ TSVideoStream stream = new TSVideoStream();
+ CopyTo(stream);
+
+ stream.VideoFormat = _VideoFormat;
+ stream.FrameRate = _FrameRate;
+ stream.Width = Width;
+ stream.Height = Height;
+ stream.IsInterlaced = IsInterlaced;
+ stream.FrameRateEnumerator = FrameRateEnumerator;
+ stream.FrameRateDenominator = FrameRateDenominator;
+ stream.AspectRatio = AspectRatio;
+ stream.EncodingProfile = EncodingProfile;
+
+ return stream;
+ }
+ }
+
+ public enum TSAudioMode
+ {
+ Unknown,
+ DualMono,
+ Stereo,
+ Surround,
+ Extended
+ }
+
+ public class TSAudioStream : TSStream
+ {
+ public TSAudioStream()
+ {
+ }
+
+ public int SampleRate;
+ public int ChannelCount;
+ public int BitDepth;
+ public int LFE;
+ public int DialNorm;
+ public TSAudioMode AudioMode;
+ public TSAudioStream CoreStream;
+ public TSChannelLayout ChannelLayout;
+
+ public static int ConvertSampleRate(
+ TSSampleRate sampleRate)
+ {
+ switch (sampleRate)
+ {
+ case TSSampleRate.SAMPLERATE_48:
+ return 48000;
+
+ case TSSampleRate.SAMPLERATE_96:
+ case TSSampleRate.SAMPLERATE_48_96:
+ return 96000;
+
+ case TSSampleRate.SAMPLERATE_192:
+ case TSSampleRate.SAMPLERATE_48_192:
+ return 192000;
+ }
+ return 0;
+ }
+
+ public string ChannelDescription
+ {
+ get
+ {
+ if (ChannelLayout == TSChannelLayout.CHANNELLAYOUT_MONO &&
+ ChannelCount == 2)
+ {
+ }
+
+ string description = "";
+ if (ChannelCount > 0)
+ {
+ description += string.Format(
+ "{0:D}.{1:D}",
+ ChannelCount, LFE);
+ }
+ else
+ {
+ switch (ChannelLayout)
+ {
+ case TSChannelLayout.CHANNELLAYOUT_MONO:
+ description += "1.0";
+ break;
+ case TSChannelLayout.CHANNELLAYOUT_STEREO:
+ description += "2.0";
+ break;
+ case TSChannelLayout.CHANNELLAYOUT_MULTI:
+ description += "5.1";
+ break;
+ }
+ }
+ if (AudioMode == TSAudioMode.Extended)
+ {
+ if (StreamType == TSStreamType.AC3_AUDIO)
+ {
+ description += "-EX";
+ }
+ if (StreamType == TSStreamType.DTS_AUDIO ||
+ StreamType == TSStreamType.DTS_HD_AUDIO ||
+ StreamType == TSStreamType.DTS_HD_MASTER_AUDIO)
+ {
+ description += "-ES";
+ }
+ }
+ return description;
+ }
+ }
+
+ public override string Description
+ {
+ get
+ {
+ string description = ChannelDescription;
+
+ if (SampleRate > 0)
+ {
+ description += string.Format(
+ " / {0:D} kHz", SampleRate / 1000);
+ }
+ if (BitRate > 0)
+ {
+ description += string.Format(
+ " / {0:D} kbps", (uint)Math.Round((double)BitRate / 1000));
+ }
+ if (BitDepth > 0)
+ {
+ description += string.Format(
+ " / {0:D}-bit", BitDepth);
+ }
+ if (DialNorm != 0)
+ {
+ description += string.Format(
+ " / DN {0}dB", DialNorm);
+ }
+ if (ChannelCount == 2)
+ {
+ switch (AudioMode)
+ {
+ case TSAudioMode.DualMono:
+ description += " / Dual Mono";
+ break;
+
+ case TSAudioMode.Surround:
+ description += " / Dolby Surround";
+ break;
+ }
+ }
+ if (description.EndsWith(" / "))
+ {
+ description = description.Substring(0, description.Length - 3);
+ }
+ if (CoreStream != null)
+ {
+ string codec = "";
+ switch (CoreStream.StreamType)
+ {
+ case TSStreamType.AC3_AUDIO:
+ codec = "AC3 Embedded";
+ break;
+ case TSStreamType.DTS_AUDIO:
+ codec = "DTS Core";
+ break;
+ }
+ description += string.Format(
+ " ({0}: {1})",
+ codec,
+ CoreStream.Description);
+ }
+ return description;
+ }
+ }
+
+ public override TSStream Clone()
+ {
+ TSAudioStream stream = new TSAudioStream();
+ CopyTo(stream);
+
+ stream.SampleRate = SampleRate;
+ stream.ChannelLayout = ChannelLayout;
+ stream.ChannelCount = ChannelCount;
+ stream.BitDepth = BitDepth;
+ stream.LFE = LFE;
+ stream.DialNorm = DialNorm;
+ stream.AudioMode = AudioMode;
+ if (CoreStream != null)
+ {
+ stream.CoreStream = (TSAudioStream)CoreStream.Clone();
+ }
+
+ return stream;
+ }
+ }
+
+ public class TSGraphicsStream : TSStream
+ {
+ public TSGraphicsStream()
+ {
+ IsVBR = true;
+ IsInitialized = true;
+ }
+
+ public override TSStream Clone()
+ {
+ TSGraphicsStream stream = new TSGraphicsStream();
+ CopyTo(stream);
+ return stream;
+ }
+ }
+
+ public class TSTextStream : TSStream
+ {
+ public TSTextStream()
+ {
+ IsVBR = true;
+ IsInitialized = true;
+ }
+
+ public override TSStream Clone()
+ {
+ TSTextStream stream = new TSTextStream();
+ CopyTo(stream);
+ return stream;
+ }
+ }
+}
diff --git a/BDInfo/TSStreamBuffer.cs b/BDInfo/TSStreamBuffer.cs
new file mode 100644
index 0000000000..78967ae34e
--- /dev/null
+++ b/BDInfo/TSStreamBuffer.cs
@@ -0,0 +1,145 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+namespace BDInfo
+{
+ public class TSStreamBuffer
+ {
+ private MemoryStream Stream = new MemoryStream();
+ private int SkipBits = 0;
+ private byte[] Buffer;
+ private int BufferLength = 0;
+ public int TransferLength = 0;
+
+ public TSStreamBuffer()
+ {
+ Buffer = new byte[4096];
+ Stream = new MemoryStream(Buffer);
+ }
+
+ public long Length
+ {
+ get
+ {
+ return (long)BufferLength;
+ }
+ }
+
+ public long Position
+ {
+ get
+ {
+ return Stream.Position;
+ }
+ }
+
+ public void Add(
+ byte[] buffer,
+ int offset,
+ int length)
+ {
+ TransferLength += length;
+
+ if (BufferLength + length >= Buffer.Length)
+ {
+ length = Buffer.Length - BufferLength;
+ }
+ if (length > 0)
+ {
+ Array.Copy(buffer, offset, Buffer, BufferLength, length);
+ BufferLength += length;
+ }
+ }
+
+ public void Seek(
+ long offset,
+ SeekOrigin loc)
+ {
+ Stream.Seek(offset, loc);
+ }
+
+ public void Reset()
+ {
+ BufferLength = 0;
+ TransferLength = 0;
+ }
+
+ public void BeginRead()
+ {
+ SkipBits = 0;
+ Stream.Seek(0, SeekOrigin.Begin);
+ }
+
+ public void EndRead()
+ {
+ }
+
+ public byte[] ReadBytes(int bytes)
+ {
+ if (Stream.Position + bytes >= BufferLength)
+ {
+ return null;
+ }
+
+ byte[] value = new byte[bytes];
+ Stream.Read(value, 0, bytes);
+ return value;
+ }
+
+ public byte ReadByte()
+ {
+ return (byte)Stream.ReadByte();
+ }
+
+ public int ReadBits(int bits)
+ {
+ long pos = Stream.Position;
+
+ int shift = 24;
+ int data = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ if (pos + i >= BufferLength) break;
+ data += (Stream.ReadByte() << shift);
+ shift -= 8;
+ }
+ BitVector32 vector = new BitVector32(data);
+
+ int value = 0;
+ for (int i = SkipBits; i < SkipBits + bits; i++)
+ {
+ value <<= 1;
+ value += (vector[1 << (32 - i - 1)] ? 1 : 0);
+ }
+
+ SkipBits += bits;
+ Stream.Seek(pos + (SkipBits >> 3), SeekOrigin.Begin);
+ SkipBits = SkipBits % 8;
+
+ return value;
+ }
+ }
+}
diff --git a/BDInfo/TSStreamClip.cs b/BDInfo/TSStreamClip.cs
new file mode 100644
index 0000000000..ba3c96e82a
--- /dev/null
+++ b/BDInfo/TSStreamClip.cs
@@ -0,0 +1,114 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace BDInfo
+{
+ public class TSStreamClip
+ {
+ public int AngleIndex = 0;
+ public string Name;
+ public double TimeIn;
+ public double TimeOut;
+ public double RelativeTimeIn;
+ public double RelativeTimeOut;
+ public double Length;
+
+ public ulong FileSize = 0;
+ public ulong InterleavedFileSize = 0;
+ public ulong PayloadBytes = 0;
+ public ulong PacketCount = 0;
+ public double PacketSeconds = 0;
+
+ public List Chapters = new List();
+
+ public TSStreamFile StreamFile = null;
+ public TSStreamClipFile StreamClipFile = null;
+
+ public TSStreamClip(
+ TSStreamFile streamFile,
+ TSStreamClipFile streamClipFile)
+ {
+ if (streamFile != null)
+ {
+ Name = streamFile.Name;
+ StreamFile = streamFile;
+ FileSize = (ulong)StreamFile.FileInfo.Length;
+ if (StreamFile.InterleavedFile != null)
+ {
+ InterleavedFileSize = (ulong)StreamFile.InterleavedFile.FileInfo.Length;
+ }
+ }
+ StreamClipFile = streamClipFile;
+ }
+
+ public string DisplayName
+ {
+ get
+ {
+ if (StreamFile != null &&
+ StreamFile.InterleavedFile != null &&
+ BDInfoSettings.EnableSSIF)
+ {
+ return StreamFile.InterleavedFile.Name;
+ }
+ return Name;
+ }
+ }
+
+ public ulong PacketSize
+ {
+ get
+ {
+ return PacketCount * 192;
+ }
+ }
+
+ public ulong PacketBitRate
+ {
+ get
+ {
+ if (PacketSeconds > 0)
+ {
+ return (ulong)Math.Round(((PacketSize * 8.0) / PacketSeconds));
+ }
+ return 0;
+ }
+ }
+
+ public bool IsCompatible(TSStreamClip clip)
+ {
+ foreach (TSStream stream1 in StreamFile.Streams.Values)
+ {
+ if (clip.StreamFile.Streams.ContainsKey(stream1.PID))
+ {
+ TSStream stream2 = clip.StreamFile.Streams[stream1.PID];
+ if (stream1.StreamType != stream2.StreamType)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/BDInfo/TSStreamClipFile.cs b/BDInfo/TSStreamClipFile.cs
new file mode 100644
index 0000000000..5042dcde1e
--- /dev/null
+++ b/BDInfo/TSStreamClipFile.cs
@@ -0,0 +1,248 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+#undef DEBUG
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+namespace BDInfo
+{
+ public class TSStreamClipFile
+ {
+ public FileInfo FileInfo = null;
+ public string FileType = null;
+ public bool IsValid = false;
+ public string Name = null;
+
+ public Dictionary Streams =
+ new Dictionary();
+
+ public TSStreamClipFile(
+ FileInfo fileInfo)
+ {
+ FileInfo = fileInfo;
+ Name = fileInfo.Name.ToUpper();
+ }
+
+ public void Scan()
+ {
+ FileStream fileStream = null;
+ BinaryReader fileReader = null;
+
+ try
+ {
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "Scanning {0}...", Name));
+#endif
+ Streams.Clear();
+
+ fileStream = File.OpenRead(FileInfo.FullName);
+ fileReader = new BinaryReader(fileStream);
+
+ byte[] data = new byte[fileStream.Length];
+ fileReader.Read(data, 0, data.Length);
+
+ byte[] fileType = new byte[8];
+ Array.Copy(data, 0, fileType, 0, fileType.Length);
+
+ FileType = ASCIIEncoding.ASCII.GetString(fileType);
+ if (FileType != "HDMV0100" &&
+ FileType != "HDMV0200")
+ {
+ throw new Exception(string.Format(
+ "Clip info file {0} has an unknown file type {1}.",
+ FileInfo.Name, FileType));
+ }
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\tFileType: {0}", FileType));
+#endif
+ int clipIndex =
+ ((int)data[12] << 24) +
+ ((int)data[13] << 16) +
+ ((int)data[14] << 8) +
+ ((int)data[15]);
+
+ int clipLength =
+ ((int)data[clipIndex] << 24) +
+ ((int)data[clipIndex + 1] << 16) +
+ ((int)data[clipIndex + 2] << 8) +
+ ((int)data[clipIndex + 3]);
+
+ byte[] clipData = new byte[clipLength];
+ Array.Copy(data, clipIndex + 4, clipData, 0, clipData.Length);
+
+ int streamCount = clipData[8];
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\tStreamCount: {0}", streamCount));
+#endif
+ int streamOffset = 10;
+ for (int streamIndex = 0;
+ streamIndex < streamCount;
+ streamIndex++)
+ {
+ TSStream stream = null;
+
+ ushort PID = (ushort)
+ ((clipData[streamOffset] << 8) +
+ clipData[streamOffset + 1]);
+
+ streamOffset += 2;
+
+ TSStreamType streamType = (TSStreamType)
+ clipData[streamOffset + 1];
+ switch (streamType)
+ {
+ case TSStreamType.MVC_VIDEO:
+ // TODO
+ break;
+
+ case TSStreamType.AVC_VIDEO:
+ case TSStreamType.MPEG1_VIDEO:
+ case TSStreamType.MPEG2_VIDEO:
+ case TSStreamType.VC1_VIDEO:
+ {
+ TSVideoFormat videoFormat = (TSVideoFormat)
+ (clipData[streamOffset + 2] >> 4);
+ TSFrameRate frameRate = (TSFrameRate)
+ (clipData[streamOffset + 2] & 0xF);
+ TSAspectRatio aspectRatio = (TSAspectRatio)
+ (clipData[streamOffset + 3] >> 4);
+
+ stream = new TSVideoStream();
+ ((TSVideoStream)stream).VideoFormat = videoFormat;
+ ((TSVideoStream)stream).AspectRatio = aspectRatio;
+ ((TSVideoStream)stream).FrameRate = frameRate;
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\t{0} {1} {2} {3} {4}",
+ PID,
+ streamType,
+ videoFormat,
+ frameRate,
+ aspectRatio));
+#endif
+ }
+ break;
+
+ case TSStreamType.AC3_AUDIO:
+ case TSStreamType.AC3_PLUS_AUDIO:
+ case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
+ case TSStreamType.DTS_AUDIO:
+ case TSStreamType.DTS_HD_AUDIO:
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ case TSStreamType.DTS_HD_SECONDARY_AUDIO:
+ case TSStreamType.LPCM_AUDIO:
+ case TSStreamType.MPEG1_AUDIO:
+ case TSStreamType.MPEG2_AUDIO:
+ {
+ byte[] languageBytes = new byte[3];
+ Array.Copy(clipData, streamOffset + 3,
+ languageBytes, 0, languageBytes.Length);
+ string languageCode =
+ ASCIIEncoding.ASCII.GetString(languageBytes);
+
+ TSChannelLayout channelLayout = (TSChannelLayout)
+ (clipData[streamOffset + 2] >> 4);
+ TSSampleRate sampleRate = (TSSampleRate)
+ (clipData[streamOffset + 2] & 0xF);
+
+ stream = new TSAudioStream();
+ ((TSAudioStream)stream).LanguageCode = languageCode;
+ ((TSAudioStream)stream).ChannelLayout = channelLayout;
+ ((TSAudioStream)stream).SampleRate = TSAudioStream.ConvertSampleRate(sampleRate);
+ ((TSAudioStream)stream).LanguageCode = languageCode;
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\t{0} {1} {2} {3} {4}",
+ PID,
+ streamType,
+ languageCode,
+ channelLayout,
+ sampleRate));
+#endif
+ }
+ break;
+
+ case TSStreamType.INTERACTIVE_GRAPHICS:
+ case TSStreamType.PRESENTATION_GRAPHICS:
+ {
+ byte[] languageBytes = new byte[3];
+ Array.Copy(clipData, streamOffset + 2,
+ languageBytes, 0, languageBytes.Length);
+ string languageCode =
+ ASCIIEncoding.ASCII.GetString(languageBytes);
+
+ stream = new TSGraphicsStream();
+ stream.LanguageCode = languageCode;
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\t{0} {1} {2}",
+ PID,
+ streamType,
+ languageCode));
+#endif
+ }
+ break;
+
+ case TSStreamType.SUBTITLE:
+ {
+ byte[] languageBytes = new byte[3];
+ Array.Copy(clipData, streamOffset + 3,
+ languageBytes, 0, languageBytes.Length);
+ string languageCode =
+ ASCIIEncoding.ASCII.GetString(languageBytes);
+#if DEBUG
+ Debug.WriteLine(string.Format(
+ "\t{0} {1} {2}",
+ PID,
+ streamType,
+ languageCode));
+#endif
+ stream = new TSTextStream();
+ stream.LanguageCode = languageCode;
+ }
+ break;
+ }
+
+ if (stream != null)
+ {
+ stream.PID = PID;
+ stream.StreamType = streamType;
+ Streams.Add(PID, stream);
+ }
+
+ streamOffset += clipData[streamOffset] + 1;
+ }
+ IsValid = true;
+ }
+ finally
+ {
+ if (fileReader != null) fileReader.Close();
+ if (fileStream != null) fileStream.Close();
+ }
+ }
+ }
+}
diff --git a/BDInfo/TSStreamFile.cs b/BDInfo/TSStreamFile.cs
new file mode 100644
index 0000000000..4b3a759624
--- /dev/null
+++ b/BDInfo/TSStreamFile.cs
@@ -0,0 +1,1551 @@
+//============================================================================
+// BDInfo - Blu-ray Video and Audio Analysis Tool
+// Copyright © 2010 Cinema Squid
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//=============================================================================
+
+#undef DEBUG
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+namespace BDInfo
+{
+ public class TSStreamState
+ {
+ public ulong TransferCount = 0;
+
+ public string StreamTag = null;
+
+ public ulong TotalPackets = 0;
+ public ulong WindowPackets = 0;
+
+ public ulong TotalBytes = 0;
+ public ulong WindowBytes = 0;
+
+ public long PeakTransferLength = 0;
+ public long PeakTransferRate = 0;
+
+ public double TransferMarker = 0;
+ public double TransferInterval = 0;
+
+ public TSStreamBuffer StreamBuffer = new TSStreamBuffer();
+
+ public uint Parse = 0;
+ public bool TransferState = false;
+ public int TransferLength = 0;
+ public int PacketLength = 0;
+ public byte PacketLengthParse = 0;
+ public byte PacketParse = 0;
+
+ public byte PTSParse = 0;
+ public ulong PTS = 0;
+ public ulong PTSTemp = 0;
+ public ulong PTSLast = 0;
+ public ulong PTSPrev = 0;
+ public ulong PTSDiff = 0;
+ public ulong PTSCount = 0;
+ public ulong PTSTransfer = 0;
+
+ public byte DTSParse = 0;
+ public ulong DTSTemp = 0;
+ public ulong DTSPrev = 0;
+
+ public byte PESHeaderLength = 0;
+ public byte PESHeaderFlags = 0;
+#if DEBUG
+ public byte PESHeaderIndex = 0;
+ public byte[] PESHeader = new byte[256 + 9];
+#endif
+ }
+
+ public class TSPacketParser
+ {
+ public bool SyncState = false;
+ public byte TimeCodeParse = 4;
+ public byte PacketLength = 0;
+ public byte HeaderParse = 0;
+
+ public uint TimeCode;
+ public byte TransportErrorIndicator;
+ public byte PayloadUnitStartIndicator;
+ public byte TransportPriority;
+ public ushort PID;
+ public byte TransportScramblingControl;
+ public byte AdaptionFieldControl;
+
+ public bool AdaptionFieldState = false;
+ public byte AdaptionFieldParse = 0;
+ public byte AdaptionFieldLength = 0;
+
+ public ushort PCRPID = 0xFFFF;
+ public byte PCRParse = 0;
+ public ulong PreviousPCR = 0;
+ public ulong PCR = 0;
+ public ulong PCRCount = 0;
+ public ulong PTSFirst = ulong.MaxValue;
+ public ulong PTSLast = ulong.MinValue;
+ public ulong PTSDiff = 0;
+
+ public byte[] PAT = new byte[1024];
+ public bool PATSectionStart = false;
+ public byte PATPointerField = 0;
+ public uint PATOffset = 0;
+ public byte PATSectionLengthParse = 0;
+ public ushort PATSectionLength = 0;
+ public uint PATSectionParse = 0;
+ public bool PATTransferState = false;
+ public byte PATSectionNumber = 0;
+ public byte PATLastSectionNumber = 0;
+
+ public ushort TransportStreamId = 0xFFFF;
+
+ public List PMTProgramDescriptors = new List();
+ public ushort PMTPID = 0xFFFF;
+ public Dictionary PMT = new Dictionary();
+ public bool PMTSectionStart = false;
+ public ushort PMTProgramInfoLength = 0;
+ public byte PMTProgramDescriptor = 0;
+ public byte PMTProgramDescriptorLengthParse = 0;
+ public byte PMTProgramDescriptorLength = 0;
+ public ushort PMTStreamInfoLength = 0;
+ public uint PMTStreamDescriptorLengthParse = 0;
+ public uint PMTStreamDescriptorLength = 0;
+ public byte PMTPointerField = 0;
+ public uint PMTOffset = 0;
+ public uint PMTSectionLengthParse = 0;
+ public ushort PMTSectionLength = 0;
+ public uint PMTSectionParse = 0;
+ public bool PMTTransferState = false;
+ public byte PMTSectionNumber = 0;
+ public byte PMTLastSectionNumber = 0;
+
+ public byte PMTTemp = 0;
+
+ public TSStream Stream = null;
+ public TSStreamState StreamState = null;
+
+ public ulong TotalPackets = 0;
+ }
+
+ public class TSStreamDiagnostics
+ {
+ public ulong Bytes = 0;
+ public ulong Packets = 0;
+ public double Marker = 0;
+ public double Interval = 0;
+ public string Tag = null;
+ }
+
+ public class TSStreamFile
+ {
+ public FileInfo FileInfo = null;
+ public string Name = null;
+ public long Size = 0;
+ public double Length = 0;
+
+ public TSInterleavedFile InterleavedFile = null;
+
+ private Dictionary StreamStates =
+ new Dictionary();
+
+ public Dictionary Streams =
+ new Dictionary();
+
+ public Dictionary> StreamDiagnostics =
+ new Dictionary>();
+
+ private List Playlists = null;
+
+ public TSStreamFile(FileInfo fileInfo)
+ {
+ FileInfo = fileInfo;
+ Name = fileInfo.Name.ToUpper();
+ }
+
+ public string DisplayName
+ {
+ get
+ {
+ if (BDInfoSettings.EnableSSIF &&
+ InterleavedFile != null)
+ {
+ return InterleavedFile.Name;
+ }
+ return Name;
+ }
+ }
+
+ private bool ScanStream(
+ TSStream stream,
+ TSStreamState streamState,
+ TSStreamBuffer buffer)
+ {
+ streamState.StreamTag = null;
+
+ long bitrate = 0;
+ if (stream.IsAudioStream &&
+ streamState.PTSTransfer > 0)
+ {
+ bitrate = (long)Math.Round(
+ (buffer.TransferLength * 8.0) /
+ ((double)streamState.PTSTransfer / 90000));
+
+ if (bitrate > streamState.PeakTransferRate)
+ {
+ streamState.PeakTransferRate = bitrate;
+ }
+ }
+ if (buffer.TransferLength > streamState.PeakTransferLength)
+ {
+ streamState.PeakTransferLength = buffer.TransferLength;
+ }
+
+ buffer.BeginRead();
+ switch (stream.StreamType)
+ {
+ case TSStreamType.MPEG2_VIDEO:
+ TSCodecMPEG2.Scan(
+ (TSVideoStream)stream, buffer, ref streamState.StreamTag);
+ break;
+
+ case TSStreamType.AVC_VIDEO:
+ TSCodecAVC.Scan(
+ (TSVideoStream)stream, buffer, ref streamState.StreamTag);
+ break;
+
+ case TSStreamType.MVC_VIDEO:
+ TSCodecMVC.Scan(
+ (TSVideoStream)stream, buffer, ref streamState.StreamTag);
+ break;
+
+ case TSStreamType.VC1_VIDEO:
+ TSCodecVC1.Scan(
+ (TSVideoStream)stream, buffer, ref streamState.StreamTag);
+ break;
+
+ case TSStreamType.AC3_AUDIO:
+ TSCodecAC3.Scan(
+ (TSAudioStream)stream, buffer, ref streamState.StreamTag);
+ break;
+
+ case TSStreamType.AC3_PLUS_AUDIO:
+ case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
+ TSCodecAC3.Scan(
+ (TSAudioStream)stream, buffer, ref streamState.StreamTag);
+ break;
+
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
+ TSCodecTrueHD.Scan(
+ (TSAudioStream)stream, buffer, ref streamState.StreamTag);
+ break;
+
+ case TSStreamType.LPCM_AUDIO:
+ TSCodecLPCM.Scan(
+ (TSAudioStream)stream, buffer, ref streamState.StreamTag);
+ break;
+
+ case TSStreamType.DTS_AUDIO:
+ TSCodecDTS.Scan(
+ (TSAudioStream)stream, buffer, bitrate, ref streamState.StreamTag);
+ break;
+
+ case TSStreamType.DTS_HD_AUDIO:
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ case TSStreamType.DTS_HD_SECONDARY_AUDIO:
+ TSCodecDTSHD.Scan(
+ (TSAudioStream)stream, buffer, bitrate, ref streamState.StreamTag);
+ break;
+
+ default:
+ stream.IsInitialized = true;
+ break;
+ }
+ buffer.EndRead();
+ streamState.StreamBuffer.Reset();
+
+ bool isAVC = false;
+ bool isMVC = false;
+ foreach (TSStream finishedStream in Streams.Values)
+ {
+ if (!finishedStream.IsInitialized)
+ {
+ return false;
+ }
+ if (finishedStream.StreamType == TSStreamType.AVC_VIDEO)
+ {
+ isAVC = true;
+ }
+ if (finishedStream.StreamType == TSStreamType.MVC_VIDEO)
+ {
+ isMVC = true;
+ }
+ }
+ if (isMVC && !isAVC)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ private void UpdateStreamBitrates(
+ ushort PTSPID,
+ ulong PTS,
+ ulong PTSDiff)
+ {
+ if (Playlists == null) return;
+
+ foreach (ushort PID in StreamStates.Keys)
+ {
+ if (Streams.ContainsKey(PID) &&
+ Streams[PID].IsVideoStream &&
+ PID != PTSPID)
+ {
+ continue;
+ }
+ if (StreamStates[PID].WindowPackets == 0)
+ {
+ continue;
+ }
+ UpdateStreamBitrate(PID, PTSPID, PTS, PTSDiff);
+ }
+
+ foreach (TSPlaylistFile playlist in Playlists)
+ {
+ double packetSeconds = 0;
+ foreach (TSStreamClip clip in playlist.StreamClips)
+ {
+ if (clip.AngleIndex == 0)
+ {
+ packetSeconds += clip.PacketSeconds;
+ }
+ }
+ if (packetSeconds > 0)
+ {
+ foreach (TSStream playlistStream in playlist.SortedStreams)
+ {
+ if (playlistStream.IsVBR)
+ {
+ playlistStream.BitRate = (long)Math.Round(
+ ((playlistStream.PayloadBytes * 8.0) / packetSeconds));
+
+ if (playlistStream.StreamType == TSStreamType.AC3_TRUE_HD_AUDIO &&
+ ((TSAudioStream)playlistStream).CoreStream != null)
+ {
+ playlistStream.BitRate -=
+ ((TSAudioStream)playlistStream).CoreStream.BitRate;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void UpdateStreamBitrate(
+ ushort PID,
+ ushort PTSPID,
+ ulong PTS,
+ ulong PTSDiff)
+ {
+ if (Playlists == null) return;
+
+ TSStreamState streamState = StreamStates[PID];
+ double streamTime = (double)PTS / 90000;
+ double streamInterval = (double)PTSDiff / 90000;
+ double streamOffset = streamTime + streamInterval;
+
+ foreach (TSPlaylistFile playlist in Playlists)
+ {
+ foreach (TSStreamClip clip in playlist.StreamClips)
+ {
+ if (clip.Name != this.Name) continue;
+
+ if (streamTime == 0 ||
+ (streamTime >= clip.TimeIn &&
+ streamTime <= clip.TimeOut))
+ {
+ clip.PayloadBytes += streamState.WindowBytes;
+ clip.PacketCount += streamState.WindowPackets;
+
+ if (streamOffset > clip.TimeIn &&
+ streamOffset - clip.TimeIn > clip.PacketSeconds)
+ {
+ clip.PacketSeconds = streamOffset - clip.TimeIn;
+ }
+
+ Dictionary playlistStreams = playlist.Streams;
+ if (clip.AngleIndex > 0 &&
+ clip.AngleIndex < playlist.AngleStreams.Count + 1)
+ {
+ playlistStreams = playlist.AngleStreams[clip.AngleIndex - 1];
+ }
+ if (playlistStreams.ContainsKey(PID))
+ {
+ TSStream stream = playlistStreams[PID];
+
+ stream.PayloadBytes += streamState.WindowBytes;
+ stream.PacketCount += streamState.WindowPackets;
+
+ if (stream.IsVideoStream)
+ {
+ stream.PacketSeconds += streamInterval;
+
+ stream.ActiveBitRate = (long)Math.Round(
+ ((stream.PayloadBytes * 8.0) /
+ stream.PacketSeconds));
+ }
+
+ if (stream.StreamType == TSStreamType.AC3_TRUE_HD_AUDIO &&
+ ((TSAudioStream)stream).CoreStream != null)
+ {
+ stream.ActiveBitRate -=
+ ((TSAudioStream)stream).CoreStream.BitRate;
+ }
+ }
+ }
+ }
+ }
+
+ if (Streams.ContainsKey(PID))
+ {
+ TSStream stream = Streams[PID];
+ stream.PayloadBytes += streamState.WindowBytes;
+ stream.PacketCount += streamState.WindowPackets;
+
+ if (stream.IsVideoStream)
+ {
+ TSStreamDiagnostics diag = new TSStreamDiagnostics();
+ diag.Marker = (double)PTS / 90000;
+ diag.Interval = (double)PTSDiff / 90000;
+ diag.Bytes = streamState.WindowBytes;
+ diag.Packets = streamState.WindowPackets;
+ diag.Tag = streamState.StreamTag;
+ StreamDiagnostics[PID].Add(diag);
+
+ stream.PacketSeconds += streamInterval;
+ }
+ }
+ streamState.WindowPackets = 0;
+ streamState.WindowBytes = 0;
+ }
+
+ public void Scan(List playlists, bool isFullScan)
+ {
+ if (playlists == null || playlists.Count == 0)
+ {
+ return;
+ }
+
+ Playlists = playlists;
+ int dataSize = 16384;
+ FileStream fileStream = null;
+ try
+ {
+ string fileName;
+ if (BDInfoSettings.EnableSSIF &&
+ InterleavedFile != null)
+ {
+ fileName = InterleavedFile.FileInfo.FullName;
+ }
+ else
+ {
+ fileName = FileInfo.FullName;
+ }
+ fileStream = new FileStream(
+ fileName,
+ FileMode.Open,
+ FileAccess.Read,
+ FileShare.Read,
+ dataSize, false);
+
+ Size = 0;
+ Length = 0;
+
+ Streams.Clear();
+ StreamStates.Clear();
+ StreamDiagnostics.Clear();
+
+ TSPacketParser parser =
+ new TSPacketParser();
+
+ long fileLength = (uint)fileStream.Length;
+ byte[] buffer = new byte[dataSize];
+ int bufferLength = 0;
+ while ((bufferLength =
+ fileStream.Read(buffer, 0, buffer.Length)) > 0)
+ {
+ int offset = 0;
+ for (int i = 0; i < bufferLength; i++)
+ {
+ if (parser.SyncState == false)
+ {
+ if (parser.TimeCodeParse > 0)
+ {
+ parser.TimeCodeParse--;
+ switch (parser.TimeCodeParse)
+ {
+ case 3:
+ parser.TimeCode = 0;
+ parser.TimeCode |=
+ ((uint)buffer[i] & 0x3F) << 24;
+ break;
+ case 2:
+ parser.TimeCode |=
+ ((uint)buffer[i] & 0xFF) << 16;
+ break;
+ case 1:
+ parser.TimeCode |=
+ ((uint)buffer[i] & 0xFF) << 8;
+ break;
+ case 0:
+ parser.TimeCode |=
+ ((uint)buffer[i] & 0xFF);
+ break;
+ }
+ }
+ else if (buffer[i] == 0x47)
+ {
+ parser.SyncState = true;
+ parser.PacketLength = 187;
+ parser.TimeCodeParse = 4;
+ parser.HeaderParse = 3;
+ }
+ }
+ else if (parser.HeaderParse > 0)
+ {
+ parser.PacketLength--;
+ parser.HeaderParse--;
+
+ switch (parser.HeaderParse)
+ {
+ case 2:
+ {
+ parser.TransportErrorIndicator =
+ (byte)((buffer[i] >> 7) & 0x1);
+ parser.PayloadUnitStartIndicator =
+ (byte)((buffer[i] >> 6) & 0x1);
+ parser.TransportPriority =
+ (byte)((buffer[i] >> 5) & 0x1);
+ parser.PID =
+ (ushort)((buffer[i] & 0x1f) << 8);
+ }
+ break;
+
+ case 1:
+ {
+ parser.PID |= (ushort)buffer[i];
+ if (Streams.ContainsKey(parser.PID))
+ {
+ parser.Stream = Streams[parser.PID];
+ }
+ else
+ {
+ parser.Stream = null;
+ }
+ if (!StreamStates.ContainsKey(parser.PID))
+ {
+ StreamStates[parser.PID] = new TSStreamState();
+ }
+ parser.StreamState = StreamStates[parser.PID];
+ parser.StreamState.TotalPackets++;
+ parser.StreamState.WindowPackets++;
+ parser.TotalPackets++;
+ }
+ break;
+
+ case 0:
+ {
+ parser.TransportScramblingControl =
+ (byte)((buffer[i] >> 6) & 0x3);
+ parser.AdaptionFieldControl =
+ (byte)((buffer[i] >> 4) & 0x3);
+
+ if ((parser.AdaptionFieldControl & 0x2) == 0x2)
+ {
+ parser.AdaptionFieldState = true;
+ }
+ if (parser.PayloadUnitStartIndicator == 1)
+ {
+ if (parser.PID == 0)
+ {
+ parser.PATSectionStart = true;
+ }
+ else if (parser.PID == parser.PMTPID)
+ {
+ parser.PMTSectionStart = true;
+ }
+ else if (parser.StreamState != null &&
+ parser.StreamState.TransferState)
+ {
+ parser.StreamState.TransferState = false;
+ parser.StreamState.TransferCount++;
+
+ bool isFinished = ScanStream(
+ parser.Stream,
+ parser.StreamState,
+ parser.StreamState.StreamBuffer);
+
+ if (!isFullScan && isFinished)
+ {
+ return;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ else if (parser.AdaptionFieldState)
+ {
+ parser.PacketLength--;
+ parser.AdaptionFieldParse = buffer[i];
+ parser.AdaptionFieldLength = buffer[i];
+ parser.AdaptionFieldState = false;
+ }
+ else if (parser.AdaptionFieldParse > 0)
+ {
+ parser.PacketLength--;
+ parser.AdaptionFieldParse--;
+ if ((parser.AdaptionFieldLength - parser.AdaptionFieldParse) == 1)
+ {
+ if ((buffer[i] & 0x10) == 0x10)
+ {
+ parser.PCRParse = 6;
+ parser.PCR = 0;
+ }
+ }
+ else if (parser.PCRParse > 0)
+ {
+ parser.PCRParse--;
+ parser.PCR = (parser.PCR << 8) + (ulong)buffer[i];
+ if (parser.PCRParse == 0)
+ {
+ parser.PreviousPCR = parser.PCR;
+ parser.PCR = (parser.PCR & 0x1FF) +
+ ((parser.PCR >> 15) * 300);
+ }
+ parser.PCRCount++;
+ }
+ if (parser.PacketLength == 0)
+ {
+ parser.SyncState = false;
+ }
+ }
+ else if (parser.PID == 0)
+ {
+ if (parser.PATTransferState)
+ {
+ if ((bufferLength - i) > parser.PATSectionLength)
+ {
+ offset = parser.PATSectionLength;
+ }
+ else
+ {
+ offset = (bufferLength - i);
+ }
+ if (parser.PacketLength <= offset)
+ {
+ offset = parser.PacketLength;
+ }
+
+ for (int k = 0; k < offset; k++)
+ {
+ parser.PAT[parser.PATOffset++] = buffer[i++];
+ parser.PATSectionLength--;
+ parser.PacketLength--;
+ } --i;
+
+ if (parser.PATSectionLength == 0)
+ {
+ parser.PATTransferState = false;
+ if (parser.PATSectionNumber == parser.PATLastSectionNumber)
+ {
+ for (int k = 0; k < (parser.PATOffset - 4); k += 4)
+ {
+ uint programNumber = (uint)
+ ((parser.PAT[k] << 8) +
+ parser.PAT[k + 1]);
+
+ ushort programPID = (ushort)
+ (((parser.PAT[k + 2] & 0x1F) << 8) +
+ parser.PAT[k + 3]);
+
+ if (programNumber == 1)
+ {
+ parser.PMTPID = programPID;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ --parser.PacketLength;
+ if (parser.PATSectionStart)
+ {
+ parser.PATPointerField = buffer[i];
+ if (parser.PATPointerField == 0)
+ {
+ parser.PATSectionLengthParse = 3;
+ }
+ parser.PATSectionStart = false;
+ }
+ else if (parser.PATPointerField > 0)
+ {
+ --parser.PATPointerField;
+ if (parser.PATPointerField == 0)
+ {
+ parser.PATSectionLengthParse = 3;
+ }
+ }
+ else if (parser.PATSectionLengthParse > 0)
+ {
+ --parser.PATSectionLengthParse;
+ switch (parser.PATSectionLengthParse)
+ {
+ case 2:
+ break;
+ case 1:
+ parser.PATSectionLength = (ushort)
+ ((buffer[i] & 0xF) << 8);
+ break;
+ case 0:
+ parser.PATSectionLength |= buffer[i];
+ if (parser.PATSectionLength > 1021)
+ {
+ parser.PATSectionLength = 0;
+ }
+ else
+ {
+ parser.PATSectionParse = 5;
+ }
+ break;
+ }
+ }
+ else if (parser.PATSectionParse > 0)
+ {
+ --parser.PATSectionLength;
+ --parser.PATSectionParse;
+
+ switch (parser.PATSectionParse)
+ {
+ case 4:
+ parser.TransportStreamId = (ushort)
+ (buffer[i] << 8);
+ break;
+ case 3:
+ parser.TransportStreamId |= buffer[i];
+ break;
+ case 2:
+ break;
+ case 1:
+ parser.PATSectionNumber = buffer[i];
+ if (parser.PATSectionNumber == 0)
+ {
+ parser.PATOffset = 0;
+ }
+ break;
+ case 0:
+ parser.PATLastSectionNumber = buffer[i];
+ parser.PATTransferState = true;
+ break;
+ }
+ }
+ }
+ if (parser.PacketLength == 0)
+ {
+ parser.SyncState = false;
+ }
+ }
+ else if (parser.PID == parser.PMTPID)
+ {
+ if (parser.PMTTransferState)
+ {
+ if ((bufferLength - i) >= parser.PMTSectionLength)
+ {
+ offset = parser.PMTSectionLength;
+ }
+ else
+ {
+ offset = (bufferLength - i);
+ }
+ if (parser.PacketLength <= offset)
+ {
+ offset = parser.PacketLength;
+ }
+ if (!parser.PMT.ContainsKey(parser.PID))
+ {
+ parser.PMT[parser.PID] = new byte[1024];
+ }
+
+ byte[] PMT = parser.PMT[parser.PID];
+ for (int k = 0; k < offset; k++)
+ {
+ PMT[parser.PMTOffset++] = buffer[i++];
+ --parser.PMTSectionLength;
+ --parser.PacketLength;
+ } --i;
+
+ if (parser.PMTSectionLength == 0)
+ {
+ parser.PMTTransferState = false;
+ if (parser.PMTSectionNumber == parser.PMTLastSectionNumber)
+ {
+ //Console.WriteLine("PMT Start: " + parser.PMTTemp);
+ try
+ {
+ for (int k = 0; k < (parser.PMTOffset - 4); k += 5)
+ {
+ byte streamType = PMT[k];
+
+ ushort streamPID = (ushort)
+ (((PMT[k + 1] & 0x1F) << 8) +
+ PMT[k + 2]);
+
+ ushort streamInfoLength = (ushort)
+ (((PMT[k + 3] & 0xF) << 8) +
+ PMT[k + 4]);
+
+ /*
+ if (streamInfoLength == 2)
+ {
+ // TODO: Cleanup
+ //streamInfoLength = 0;
+ }
+
+ Console.WriteLine(string.Format(
+ "Type: {0} PID: {1} Length: {2}",
+ streamType, streamPID, streamInfoLength));
+ */
+
+ if (!Streams.ContainsKey(streamPID))
+ {
+ List streamDescriptors =
+ new List();
+
+ /*
+ * TODO: Getting bad streamInfoLength
+ if (streamInfoLength > 0)
+ {
+ for (int d = 0; d < streamInfoLength; d++)
+ {
+ byte name = PMT[k + d + 5];
+ byte length = PMT[k + d + 6];
+ TSDescriptor descriptor =
+ new TSDescriptor(name, length);
+ for (int v = 0; v < length; v++)
+ {
+ descriptor.Value[v] =
+ PMT[k + d + v + 7];
+ }
+ streamDescriptors.Add(descriptor);
+ d += (length + 1);
+ }
+ }
+ */
+ CreateStream(streamPID, streamType, streamDescriptors);
+ }
+ k += streamInfoLength;
+ }
+ }
+ catch (Exception ex)
+ {
+ // TODO
+ Console.WriteLine(ex.Message);
+ }
+ }
+ }
+ }
+ else
+ {
+ --parser.PacketLength;
+ if (parser.PMTSectionStart)
+ {
+ parser.PMTPointerField = buffer[i];
+ if (parser.PMTPointerField == 0)
+ {
+ parser.PMTSectionLengthParse = 3;
+ }
+ parser.PMTSectionStart = false;
+ }
+ else if (parser.PMTPointerField > 0)
+ {
+ --parser.PMTPointerField;
+ if (parser.PMTPointerField == 0)
+ {
+ parser.PMTSectionLengthParse = 3;
+ }
+ }
+ else if (parser.PMTSectionLengthParse > 0)
+ {
+ --parser.PMTSectionLengthParse;
+ switch (parser.PMTSectionLengthParse)
+ {
+ case 2:
+ if (buffer[i] != 0x2)
+ {
+ parser.PMTSectionLengthParse = 0;
+ }
+ break;
+ case 1:
+ parser.PMTSectionLength = (ushort)
+ ((buffer[i] & 0xF) << 8);
+ break;
+ case 0:
+ parser.PMTSectionLength |= buffer[i];
+ if (parser.PMTSectionLength > 1021)
+ {
+ parser.PMTSectionLength = 0;
+ }
+ else
+ {
+ parser.PMTSectionParse = 9;
+ }
+ break;
+ }
+ }
+ else if (parser.PMTSectionParse > 0)
+ {
+ --parser.PMTSectionLength;
+ --parser.PMTSectionParse;
+
+ switch (parser.PMTSectionParse)
+ {
+ case 8:
+ case 7:
+ break;
+ case 6:
+ parser.PMTTemp = buffer[i];
+ break;
+ case 5:
+ parser.PMTSectionNumber = buffer[i];
+ if (parser.PMTSectionNumber == 0)
+ {
+ parser.PMTOffset = 0;
+ }
+ break;
+ case 4:
+ parser.PMTLastSectionNumber = buffer[i];
+ break;
+ case 3:
+ parser.PCRPID = (ushort)
+ ((buffer[i] & 0x1F) << 8);
+ break;
+ case 2:
+ parser.PCRPID |= buffer[i];
+ break;
+ case 1:
+ parser.PMTProgramInfoLength = (ushort)
+ ((buffer[i] & 0xF) << 8);
+ break;
+ case 0:
+ parser.PMTProgramInfoLength |= buffer[i];
+ if (parser.PMTProgramInfoLength == 0)
+ {
+ parser.PMTTransferState = true;
+ }
+ else
+ {
+ parser.PMTProgramDescriptorLengthParse = 2;
+ }
+ break;
+ }
+ }
+ else if (parser.PMTProgramInfoLength > 0)
+ {
+ --parser.PMTSectionLength;
+ --parser.PMTProgramInfoLength;
+
+ if (parser.PMTProgramDescriptorLengthParse > 0)
+ {
+ --parser.PMTProgramDescriptorLengthParse;
+ switch (parser.PMTProgramDescriptorLengthParse)
+ {
+ case 1:
+ parser.PMTProgramDescriptor = buffer[i];
+ break;
+ case 0:
+ parser.PMTProgramDescriptorLength = buffer[i];
+ parser.PMTProgramDescriptors.Add(
+ new TSDescriptor(
+ parser.PMTProgramDescriptor,
+ parser.PMTProgramDescriptorLength));
+ break;
+ }
+ }
+ else if (parser.PMTProgramDescriptorLength > 0)
+ {
+ --parser.PMTProgramDescriptorLength;
+
+ TSDescriptor descriptor = parser.PMTProgramDescriptors[
+ parser.PMTProgramDescriptors.Count - 1];
+
+ int valueIndex =
+ descriptor.Value.Length -
+ parser.PMTProgramDescriptorLength - 1;
+
+ descriptor.Value[valueIndex] = buffer[i];
+
+ if (parser.PMTProgramDescriptorLength == 0 &&
+ parser.PMTProgramInfoLength > 0)
+ {
+ parser.PMTProgramDescriptorLengthParse = 2;
+ }
+ }
+ if (parser.PMTProgramInfoLength == 0)
+ {
+ parser.PMTTransferState = true;
+ }
+ }
+ }
+ if (parser.PacketLength == 0)
+ {
+ parser.SyncState = false;
+ }
+ }
+ else if (parser.Stream != null &&
+ parser.StreamState != null &&
+ parser.TransportScramblingControl == 0)
+ {
+ TSStream stream = parser.Stream;
+ TSStreamState streamState = parser.StreamState;
+
+ streamState.Parse =
+ (streamState.Parse << 8) + buffer[i];
+
+ if (streamState.TransferState)
+ {
+ if ((bufferLength - i) >= streamState.PacketLength &&
+ streamState.PacketLength > 0)
+ {
+ offset = streamState.PacketLength;
+ }
+ else
+ {
+ offset = (bufferLength - i);
+ }
+ if (parser.PacketLength <= offset)
+ {
+ offset = parser.PacketLength;
+ }
+ streamState.TransferLength = offset;
+
+ if (!stream.IsInitialized ||
+ stream.IsVideoStream)
+ {
+ streamState.StreamBuffer.Add(
+ buffer, i, offset);
+ }
+ else
+ {
+ streamState.StreamBuffer.TransferLength += offset;
+ }
+
+ i += (int)(streamState.TransferLength - 1);
+ streamState.PacketLength -= streamState.TransferLength;
+ parser.PacketLength -= (byte)streamState.TransferLength;
+
+ streamState.TotalBytes += (ulong)streamState.TransferLength;
+ streamState.WindowBytes += (ulong)streamState.TransferLength;
+
+ if (streamState.PacketLength == 0)
+ {
+ streamState.TransferState = false;
+ streamState.TransferCount++;
+ bool isFinished = ScanStream(
+ stream,
+ streamState,
+ streamState.StreamBuffer);
+
+ if (!isFullScan && isFinished)
+ {
+ return;
+ }
+ }
+ }
+ else
+ {
+ --parser.PacketLength;
+
+ bool headerFound = false;
+ if (stream.IsVideoStream &&
+ streamState.Parse == 0x000001FD)
+ {
+ headerFound = true;
+ }
+ if (stream.IsVideoStream &&
+ streamState.Parse >= 0x000001E0 &&
+ streamState.Parse <= 0x000001EF)
+ {
+ headerFound = true;
+ }
+ if (stream.IsAudioStream &&
+ streamState.Parse == 0x000001BD)
+ {
+ headerFound = true;
+ }
+ if (stream.IsAudioStream &&
+ (streamState.Parse == 0x000001FA ||
+ streamState.Parse == 0x000001FD))
+ {
+ headerFound = true;
+ }
+
+ if (!stream.IsVideoStream &&
+ !stream.IsAudioStream &&
+ (streamState.Parse == 0x000001FA ||
+ streamState.Parse == 0x000001FD ||
+ streamState.Parse == 0x000001BD ||
+ (streamState.Parse >= 0x000001E0 &&
+ streamState.Parse <= 0x000001EF)))
+ {
+ headerFound = true;
+ }
+
+ if (headerFound)
+ {
+ streamState.PacketLengthParse = 2;
+#if DEBUG
+ streamState.PESHeaderIndex = 0;
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)((streamState.Parse >> 24) & 0xFF);
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)((streamState.Parse >> 16) & 0xFF);
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)((streamState.Parse >> 8) & 0xFF);
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ }
+ else if (streamState.PacketLengthParse > 0)
+ {
+ --streamState.PacketLengthParse;
+ switch (streamState.PacketLengthParse)
+ {
+ case 1:
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 0:
+ streamState.PacketLength =
+ (int)(streamState.Parse & 0xFFFF);
+ streamState.PacketParse = 3;
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+ }
+ }
+ else if (streamState.PacketParse > 0)
+ {
+ --streamState.PacketLength;
+ --streamState.PacketParse;
+
+ switch (streamState.PacketParse)
+ {
+ case 2:
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 1:
+ streamState.PESHeaderFlags =
+ (byte)(streamState.Parse & 0xFF);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 0:
+ streamState.PESHeaderLength =
+ (byte)(streamState.Parse & 0xFF);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ if ((streamState.PESHeaderFlags & 0xC0) == 0x80)
+ {
+ streamState.PTSParse = 5;
+ }
+ else if ((streamState.PESHeaderFlags & 0xC0) == 0xC0)
+ {
+ streamState.DTSParse = 10;
+ }
+ if (streamState.PESHeaderLength == 0)
+ {
+ streamState.TransferState = true;
+ }
+ break;
+ }
+ }
+ else if (streamState.PTSParse > 0)
+ {
+ --streamState.PacketLength;
+ --streamState.PESHeaderLength;
+ --streamState.PTSParse;
+
+ switch (streamState.PTSParse)
+ {
+ case 4:
+ streamState.PTSTemp =
+ ((streamState.Parse & 0xE) << 29);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xff);
+#endif
+ break;
+
+ case 3:
+ streamState.PTSTemp |=
+ ((streamState.Parse & 0xFF) << 22);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 2:
+ streamState.PTSTemp |=
+ ((streamState.Parse & 0xFE) << 14);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 1:
+ streamState.PTSTemp |=
+ ((streamState.Parse & 0xFF) << 7);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 0:
+ streamState.PTSTemp |=
+ ((streamState.Parse & 0xFE) >> 1);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xff);
+#endif
+ streamState.PTS = streamState.PTSTemp;
+
+ if (streamState.PTS > streamState.PTSLast)
+ {
+ if (streamState.PTSLast > 0)
+ {
+ streamState.PTSTransfer = (streamState.PTS - streamState.PTSLast);
+ }
+ streamState.PTSLast = streamState.PTS;
+ }
+
+ streamState.PTSDiff = streamState.PTS - streamState.DTSPrev;
+
+ if (streamState.PTSCount > 0 &&
+ stream.IsVideoStream)
+ {
+ UpdateStreamBitrates(stream.PID, streamState.PTS, streamState.PTSDiff);
+ if (streamState.DTSTemp < parser.PTSFirst)
+ {
+ parser.PTSFirst = streamState.DTSTemp;
+ }
+ if (streamState.DTSTemp > parser.PTSLast)
+ {
+ parser.PTSLast = streamState.DTSTemp;
+ }
+ Length = (double)(parser.PTSLast - parser.PTSFirst) / 90000;
+ }
+
+ streamState.DTSPrev = streamState.PTS;
+ streamState.PTSCount++;
+ if (streamState.PESHeaderLength == 0)
+ {
+ streamState.TransferState = true;
+ }
+ break;
+ }
+ }
+ else if (streamState.DTSParse > 0)
+ {
+ --streamState.PacketLength;
+ --streamState.PESHeaderLength;
+ --streamState.DTSParse;
+
+ switch (streamState.DTSParse)
+ {
+ case 9:
+ streamState.PTSTemp =
+ ((streamState.Parse & 0xE) << 29);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 8:
+ streamState.PTSTemp |=
+ ((streamState.Parse & 0xFF) << 22);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 7:
+ streamState.PTSTemp |=
+ ((streamState.Parse & 0xFE) << 14);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xff);
+#endif
+ break;
+
+ case 6:
+ streamState.PTSTemp |=
+ ((streamState.Parse & 0xFF) << 7);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 5:
+ streamState.PTSTemp |=
+ ((streamState.Parse & 0xFE) >> 1);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xff);
+#endif
+ streamState.PTS = streamState.PTSTemp;
+ if (streamState.PTS > streamState.PTSLast)
+ {
+ streamState.PTSLast = streamState.PTS;
+ }
+ break;
+
+ case 4:
+ streamState.DTSTemp =
+ ((streamState.Parse & 0xE) << 29);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xff);
+#endif
+ break;
+
+ case 3:
+ streamState.DTSTemp |=
+ ((streamState.Parse & 0xFF) << 22);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xff);
+#endif
+ break;
+
+ case 2:
+ streamState.DTSTemp |=
+ ((streamState.Parse & 0xFE) << 14);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xff);
+#endif
+ break;
+
+ case 1:
+ streamState.DTSTemp |=
+ ((streamState.Parse & 0xFF) << 7);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ break;
+
+ case 0:
+ streamState.DTSTemp |=
+ ((streamState.Parse & 0xFE) >> 1);
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xff);
+#endif
+ streamState.PTSDiff = streamState.DTSTemp - streamState.DTSPrev;
+
+ if (streamState.PTSCount > 0 &&
+ stream.IsVideoStream)
+ {
+ UpdateStreamBitrates(stream.PID, streamState.DTSTemp, streamState.PTSDiff);
+ if (streamState.DTSTemp < parser.PTSFirst)
+ {
+ parser.PTSFirst = streamState.DTSTemp;
+ }
+ if (streamState.DTSTemp > parser.PTSLast)
+ {
+ parser.PTSLast = streamState.DTSTemp;
+ }
+ Length = (double)(parser.PTSLast - parser.PTSFirst) / 90000;
+ }
+ streamState.DTSPrev = streamState.DTSTemp;
+ streamState.PTSCount++;
+ if (streamState.PESHeaderLength == 0)
+ {
+ streamState.TransferState = true;
+ }
+ break;
+ }
+ }
+ else if (streamState.PESHeaderLength > 0)
+ {
+ --streamState.PacketLength;
+ --streamState.PESHeaderLength;
+#if DEBUG
+ streamState.PESHeader[streamState.PESHeaderIndex++] =
+ (byte)(streamState.Parse & 0xFF);
+#endif
+ if (streamState.PESHeaderLength == 0)
+ {
+ streamState.TransferState = true;
+ }
+ }
+ }
+ if (parser.PacketLength == 0)
+ {
+ parser.SyncState = false;
+ }
+ }
+ else
+ {
+ parser.PacketLength--;
+ if ((bufferLength - i) >= parser.PacketLength)
+ {
+ i = i + parser.PacketLength;
+ parser.PacketLength = 0;
+ }
+ else
+ {
+ parser.PacketLength -= (byte)((bufferLength - i) + 1);
+ i = bufferLength;
+ }
+ if (parser.PacketLength == 0)
+ {
+ parser.SyncState = false;
+ }
+ }
+ }
+ Size += bufferLength;
+ }
+
+ ulong PTSLast = 0;
+ ulong PTSDiff = 0;
+ foreach (TSStream stream in Streams.Values)
+ {
+ if (!stream.IsVideoStream) continue;
+
+ if (StreamStates.ContainsKey(stream.PID) &&
+ StreamStates[stream.PID].PTSLast > PTSLast)
+ {
+ PTSLast = StreamStates[stream.PID].PTSLast;
+ PTSDiff = PTSLast - StreamStates[stream.PID].DTSPrev;
+ }
+ UpdateStreamBitrates(stream.PID, PTSLast, PTSDiff);
+ }
+ }
+ finally
+ {
+ if (fileStream != null)
+ {
+ fileStream.Close();
+ }
+ }
+ }
+
+ private TSStream CreateStream(
+ ushort streamPID,
+ byte streamType,
+ List streamDescriptors)
+ {
+ TSStream stream = null;
+
+ switch ((TSStreamType)streamType)
+ {
+ case TSStreamType.MVC_VIDEO:
+ case TSStreamType.AVC_VIDEO:
+ case TSStreamType.MPEG1_VIDEO:
+ case TSStreamType.MPEG2_VIDEO:
+ case TSStreamType.VC1_VIDEO:
+ {
+ stream = new TSVideoStream();
+ }
+ break;
+
+ case TSStreamType.AC3_AUDIO:
+ case TSStreamType.AC3_PLUS_AUDIO:
+ case TSStreamType.AC3_PLUS_SECONDARY_AUDIO:
+ case TSStreamType.AC3_TRUE_HD_AUDIO:
+ case TSStreamType.DTS_AUDIO:
+ case TSStreamType.DTS_HD_AUDIO:
+ case TSStreamType.DTS_HD_MASTER_AUDIO:
+ case TSStreamType.DTS_HD_SECONDARY_AUDIO:
+ case TSStreamType.LPCM_AUDIO:
+ case TSStreamType.MPEG1_AUDIO:
+ case TSStreamType.MPEG2_AUDIO:
+ {
+ stream = new TSAudioStream();
+ }
+ break;
+
+ case TSStreamType.INTERACTIVE_GRAPHICS:
+ case TSStreamType.PRESENTATION_GRAPHICS:
+ {
+ stream = new TSGraphicsStream();
+ }
+ break;
+
+ case TSStreamType.SUBTITLE:
+ {
+ stream = new TSTextStream();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (stream != null &&
+ !Streams.ContainsKey(streamPID))
+ {
+ stream.PID = streamPID;
+ stream.StreamType = (TSStreamType)streamType;
+ stream.Descriptors = streamDescriptors;
+ Streams[stream.PID] = stream;
+ }
+ if (!StreamDiagnostics.ContainsKey(streamPID))
+ {
+ StreamDiagnostics[streamPID] =
+ new List();
+ }
+
+ return stream;
+ }
+ }
+}
diff --git a/Bootstrapper/readme.txt b/Bootstrapper/readme.txt
new file mode 100644
index 0000000000..0fdcf2aa57
--- /dev/null
+++ b/Bootstrapper/readme.txt
@@ -0,0 +1,3 @@
+If Publishing, the folders in here must be copied to:
+
+C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\Bootstrapper\Packages
\ No newline at end of file
diff --git a/Bootstrapper/vcredist10_x86/en/package.xml b/Bootstrapper/vcredist10_x86/en/package.xml
new file mode 100644
index 0000000000..613fc0b84c
--- /dev/null
+++ b/Bootstrapper/vcredist10_x86/en/package.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ Visual C++ 2010 Runtime Libraries (x86)
+ en
+ You do not have the permissions required to install Visual C++ 2010 Runtime Libraries (x86). Please contact your administrator.
+ Installation of Visual C++ 2010 Runtime Libraries (x86) is not supported on Windows 95. Contact your application vendor.
+ Installation of Visual C++ 2010 Runtime Libraries (x86) is not supported on Windows NT 4.0. Contact your application vendor.
+ A failure occurred attempting to install Visual C++ 2010 Runtime Libraries (x86).
+ http://go.microsoft.com/fwlink/?LinkID=210621
+
+
+
diff --git a/Bootstrapper/vcredist10_x86/product.xml b/Bootstrapper/vcredist10_x86/product.xml
new file mode 100644
index 0000000000..76edde6187
--- /dev/null
+++ b/Bootstrapper/vcredist10_x86/product.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MediaBrowser.Api/ApiService.cs b/MediaBrowser.Api/ApiService.cs
index 0fef1cb574..68ba6d5225 100644
--- a/MediaBrowser.Api/ApiService.cs
+++ b/MediaBrowser.Api/ApiService.cs
@@ -1,438 +1,78 @@
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
-using MediaBrowser.Model.DTO;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Threading.Tasks;
-
-namespace MediaBrowser.Api
-{
- ///
- /// Contains some helpers for the api
- ///
- public static class ApiService
- {
- ///
- /// Gets an Item by Id, or the root item if none is supplied
- ///
- public static BaseItem GetItemById(string id)
- {
- Guid guid = string.IsNullOrEmpty(id) ? Guid.Empty : new Guid(id);
-
- return Kernel.Instance.GetItemById(guid);
- }
-
- ///
- /// Gets a User by Id
- ///
- /// Whether or not to update the user's LastActivityDate
- public static User GetUserById(string id, bool logActivity)
- {
- var guid = new Guid(id);
-
- var user = Kernel.Instance.Users.FirstOrDefault(u => u.Id == guid);
-
- if (logActivity)
- {
- LogUserActivity(user);
- }
-
- return user;
- }
-
- ///
- /// Gets the default User
- ///
- /// Whether or not to update the user's LastActivityDate
- public static User GetDefaultUser(bool logActivity)
- {
- User user = Kernel.Instance.GetDefaultUser();
-
- if (logActivity)
- {
- LogUserActivity(user);
- }
-
- return user;
- }
-
- ///
- /// Updates LastActivityDate for a given User
- ///
- public static void LogUserActivity(User user)
- {
- user.LastActivityDate = DateTime.UtcNow;
- Kernel.Instance.SaveUser(user);
- }
-
- ///
- /// Converts a BaseItem to a DTOBaseItem
- ///
- public async static Task GetDtoBaseItem(BaseItem item, User user,
- bool includeChildren = true,
- bool includePeople = true)
- {
- var dto = new DtoBaseItem();
-
- var tasks = new List();
-
- tasks.Add(AttachStudios(dto, item));
-
- if (includeChildren)
- {
- tasks.Add(AttachChildren(dto, item, user));
- tasks.Add(AttachLocalTrailers(dto, item, user));
- }
-
- if (includePeople)
- {
- tasks.Add(AttachPeople(dto, item));
- }
-
- AttachBasicFields(dto, item, user);
-
- // Make sure all the tasks we kicked off have completed.
- if (tasks.Count > 0)
- {
- await Task.WhenAll(tasks).ConfigureAwait(false);
- }
-
- return dto;
- }
-
- ///
- /// Sets simple property values on a DTOBaseItem
- ///
- private static void AttachBasicFields(DtoBaseItem dto, BaseItem item, User user)
- {
- dto.AspectRatio = item.AspectRatio;
- dto.BackdropCount = item.BackdropImagePaths == null ? 0 : item.BackdropImagePaths.Count();
- dto.DateCreated = item.DateCreated;
- dto.DisplayMediaType = item.DisplayMediaType;
-
- if (item.Genres != null)
- {
- dto.Genres = item.Genres.ToArray();
- }
-
- dto.HasArt = !string.IsNullOrEmpty(item.ArtImagePath);
- dto.HasBanner = !string.IsNullOrEmpty(item.BannerImagePath);
- dto.HasLogo = !string.IsNullOrEmpty(item.LogoImagePath);
- dto.HasPrimaryImage = !string.IsNullOrEmpty(item.PrimaryImagePath);
- dto.HasThumb = !string.IsNullOrEmpty(item.ThumbnailImagePath);
- dto.Id = item.Id;
- dto.IsNew = item.IsRecentlyAdded(user);
- dto.IndexNumber = item.IndexNumber;
- dto.IsFolder = item.IsFolder;
- dto.Language = item.Language;
- dto.LocalTrailerCount = item.LocalTrailers == null ? 0 : item.LocalTrailers.Count();
- dto.Name = item.Name;
- dto.OfficialRating = item.OfficialRating;
- dto.Overview = item.Overview;
-
- // If there are no backdrops, indicate what parent has them in case the Ui wants to allow inheritance
- if (dto.BackdropCount == 0)
- {
- int backdropCount;
- dto.ParentBackdropItemId = GetParentBackdropItemId(item, out backdropCount);
- dto.ParentBackdropCount = backdropCount;
- }
-
- if (item.Parent != null)
- {
- dto.ParentId = item.Parent.Id;
- }
-
- dto.ParentIndexNumber = item.ParentIndexNumber;
-
- // If there is no logo, indicate what parent has one in case the Ui wants to allow inheritance
- if (!dto.HasLogo)
- {
- dto.ParentLogoItemId = GetParentLogoItemId(item);
- }
-
- dto.Path = item.Path;
-
- dto.PremiereDate = item.PremiereDate;
- dto.ProductionYear = item.ProductionYear;
- dto.ProviderIds = item.ProviderIds;
- dto.RunTimeTicks = item.RunTimeTicks;
- dto.SortName = item.SortName;
-
- if (item.Taglines != null)
- {
- dto.Taglines = item.Taglines.ToArray();
- }
-
- dto.TrailerUrl = item.TrailerUrl;
- dto.Type = item.GetType().Name;
- dto.CommunityRating = item.CommunityRating;
-
- dto.UserData = GetDtoUserItemData(item.GetUserData(user, false));
-
- var folder = item as Folder;
-
- if (folder != null)
- {
- dto.SpecialCounts = folder.GetSpecialCounts(user);
-
- dto.IsRoot = folder.IsRoot;
- dto.IsVirtualFolder = folder.IsVirtualFolder;
- }
-
- // Add AudioInfo
- var audio = item as Audio;
-
- if (audio != null)
- {
- dto.AudioInfo = new AudioInfo
- {
- Album = audio.Album,
- AlbumArtist = audio.AlbumArtist,
- Artist = audio.Artist,
- BitRate = audio.BitRate,
- Channels = audio.Channels
- };
- }
-
- // Add VideoInfo
- var video = item as Video;
-
- if (video != null)
- {
- dto.VideoInfo = new VideoInfo
- {
- Height = video.Height,
- Width = video.Width,
- Codec = video.Codec,
- VideoType = video.VideoType,
- ScanType = video.ScanType
- };
-
- if (video.AudioStreams != null)
- {
- dto.VideoInfo.AudioStreams = video.AudioStreams.ToArray();
- }
-
- if (video.Subtitles != null)
- {
- dto.VideoInfo.Subtitles = video.Subtitles.ToArray();
- }
- }
-
- // Add SeriesInfo
- var series = item as Series;
-
- if (series != null)
- {
- DayOfWeek[] airDays = series.AirDays == null ? new DayOfWeek[] { } : series.AirDays.ToArray();
-
- dto.SeriesInfo = new SeriesInfo
- {
- AirDays = airDays,
- AirTime = series.AirTime,
- Status = series.Status
- };
- }
-
- // Add MovieInfo
- var movie = item as Movie;
-
- if (movie != null)
- {
- int specialFeatureCount = movie.SpecialFeatures == null ? 0 : movie.SpecialFeatures.Count();
-
- dto.MovieInfo = new MovieInfo
- {
- SpecialFeatureCount = specialFeatureCount
- };
- }
- }
-
- ///
- /// Attaches Studio DTO's to a DTOBaseItem
- ///
- private static async Task AttachStudios(DtoBaseItem dto, BaseItem item)
- {
- // Attach Studios by transforming them into BaseItemStudio (DTO)
- if (item.Studios != null)
- {
- Studio[] entities = await Task.WhenAll(item.Studios.Select(c => Kernel.Instance.ItemController.GetStudio(c))).ConfigureAwait(false);
-
- dto.Studios = new BaseItemStudio[entities.Length];
-
- for (int i = 0; i < entities.Length; i++)
- {
- Studio entity = entities[i];
- var baseItemStudio = new BaseItemStudio{};
-
- baseItemStudio.Name = entity.Name;
-
- baseItemStudio.HasImage = !string.IsNullOrEmpty(entity.PrimaryImagePath);
-
- dto.Studios[i] = baseItemStudio;
- }
- }
- }
-
- ///
- /// Attaches child DTO's to a DTOBaseItem
- ///
- private static async Task AttachChildren(DtoBaseItem dto, BaseItem item, User user)
- {
- var folder = item as Folder;
-
- if (folder != null)
- {
- IEnumerable children = folder.GetChildren(user);
-
- dto.Children = await Task.WhenAll(children.Select(c => GetDtoBaseItem(c, user, false, false))).ConfigureAwait(false);
- }
- }
-
- ///
- /// Attaches trailer DTO's to a DTOBaseItem
- ///
- private static async Task AttachLocalTrailers(DtoBaseItem dto, BaseItem item, User user)
- {
- if (item.LocalTrailers != null && item.LocalTrailers.Any())
- {
- dto.LocalTrailers = await Task.WhenAll(item.LocalTrailers.Select(c => GetDtoBaseItem(c, user, false, false))).ConfigureAwait(false);
- }
- }
-
- ///
- /// Attaches People DTO's to a DTOBaseItem
- ///
- private static async Task AttachPeople(DtoBaseItem dto, BaseItem item)
- {
- // Attach People by transforming them into BaseItemPerson (DTO)
- if (item.People != null)
- {
- IEnumerable entities = await Task.WhenAll(item.People.Select(c => Kernel.Instance.ItemController.GetPerson(c.Key))).ConfigureAwait(false);
-
- dto.People = item.People.Select(p =>
- {
- var baseItemPerson = new BaseItemPerson{};
-
- baseItemPerson.Name = p.Key;
- baseItemPerson.Overview = p.Value.Overview;
- baseItemPerson.Type = p.Value.Type;
-
- Person ibnObject = entities.First(i => i.Name.Equals(p.Key, StringComparison.OrdinalIgnoreCase));
-
- if (ibnObject != null)
- {
- baseItemPerson.HasImage = !string.IsNullOrEmpty(ibnObject.PrimaryImagePath);
- }
-
- return baseItemPerson;
- }).ToArray();
- }
- }
-
- ///
- /// If an item does not any backdrops, this can be used to find the first parent that does have one
- ///
- private static Guid? GetParentBackdropItemId(BaseItem item, out int backdropCount)
- {
- backdropCount = 0;
-
- var parent = item.Parent;
-
- while (parent != null)
- {
- if (parent.BackdropImagePaths != null && parent.BackdropImagePaths.Any())
- {
- backdropCount = parent.BackdropImagePaths.Count();
- return parent.Id;
- }
-
- parent = parent.Parent;
- }
-
- return null;
- }
-
- ///
- /// If an item does not have a logo, this can be used to find the first parent that does have one
- ///
- private static Guid? GetParentLogoItemId(BaseItem item)
- {
- var parent = item.Parent;
-
- while (parent != null)
- {
- if (!string.IsNullOrEmpty(parent.LogoImagePath))
- {
- return parent.Id;
- }
-
- parent = parent.Parent;
- }
-
- return null;
- }
-
- ///
- /// Gets an ImagesByName entity along with the number of items containing it
- ///
- public static IbnItem GetIbnItem(BaseEntity entity, int itemCount)
- {
- return new IbnItem
- {
- Id = entity.Id,
- BaseItemCount = itemCount,
- HasImage = !string.IsNullOrEmpty(entity.PrimaryImagePath),
- Name = entity.Name
- };
- }
-
- ///
- /// Converts a User to a DTOUser
- ///
- public static DtoUser GetDtoUser(User user)
- {
- return new DtoUser
- {
- Id = user.Id,
- Name = user.Name,
- HasImage = !string.IsNullOrEmpty(user.PrimaryImagePath),
- HasPassword = !string.IsNullOrEmpty(user.Password),
- LastActivityDate = user.LastActivityDate,
- LastLoginDate = user.LastLoginDate
- };
- }
-
- ///
- /// Converts a UserItemData to a DTOUserItemData
- ///
- public static DtoUserItemData GetDtoUserItemData(UserItemData data)
- {
- if (data == null)
- {
- return null;
- }
-
- return new DtoUserItemData
- {
- IsFavorite = data.IsFavorite,
- Likes = data.Likes,
- PlaybackPositionTicks = data.PlaybackPositionTicks,
- PlayCount = data.PlayCount,
- Rating = data.Rating
- };
- }
-
- public static bool IsApiUrlMatch(string url, HttpListenerRequest request)
- {
- url = "/api/" + url;
-
- return request.Url.LocalPath.EndsWith(url, StringComparison.OrdinalIgnoreCase);
- }
- }
-}
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Model.Connectivity;
+using ServiceStack.Common.Web;
+using System;
+using System.Net;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Api
+{
+ ///
+ /// Contains some helpers for the api
+ ///
+ public static class ApiService
+ {
+ ///
+ /// Gets a User by Id
+ ///
+ /// The id of the user
+ /// User.
+ /// id
+ public static User GetUserById(string id)
+ {
+ if (string.IsNullOrEmpty(id))
+ {
+ throw new ArgumentNullException("id");
+ }
+
+ var guid = new Guid(id);
+
+ return Kernel.Instance.GetUserById(guid);
+ }
+
+ ///
+ /// Determines whether [is API URL match] [the specified URL].
+ ///
+ /// The URL.
+ /// The request.
+ /// true if [is API URL match] [the specified URL]; otherwise, false.
+ public static bool IsApiUrlMatch(string url, HttpListenerRequest request)
+ {
+ url = "/api/" + url;
+
+ return request.Url.LocalPath.EndsWith(url, StringComparison.OrdinalIgnoreCase);
+ }
+
+ /////
+ ///// Gets the current user.
+ /////
+ ///// The request.
+ ///// Task{User}.
+ //public static async Task GetCurrentUser(AuthenticatedRequest request)
+ //{
+ // var user = GetUserById(request.UserId);
+
+ // if (user == null)
+ // {
+ // throw HttpError.Unauthorized("Invalid user or password entered.");
+ // }
+
+ // var clientType = ClientType.Other;
+
+ // if (!string.IsNullOrEmpty(request.Client))
+ // {
+ // ClientType type;
+
+ // if (Enum.TryParse(request.Client, true, out type))
+ // {
+ // clientType = type;
+ // }
+ // }
+
+ // await Kernel.Instance.UserManager.LogUserActivity(user, clientType, request.Device).ConfigureAwait(false);
+
+ // return user;
+ //}
+ }
+}
diff --git a/MediaBrowser.Api/Drawing/DrawingUtils.cs b/MediaBrowser.Api/Drawing/DrawingUtils.cs
deleted file mode 100644
index f76a74218f..0000000000
--- a/MediaBrowser.Api/Drawing/DrawingUtils.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-using System.Drawing;
-
-namespace MediaBrowser.Api.Drawing
-{
- public static class DrawingUtils
- {
- ///
- /// Resizes a set of dimensions
- ///
- public static Size Resize(int currentWidth, int currentHeight, int? width, int? height, int? maxWidth, int? maxHeight)
- {
- return Resize(new Size(currentWidth, currentHeight), width, height, maxWidth, maxHeight);
- }
-
- ///
- /// Resizes a set of dimensions
- ///
- /// The original size object
- /// A new fixed width, if desired
- /// A new fixed neight, if desired
- /// A max fixed width, if desired
- /// A max fixed height, if desired
- /// A new size object
- public static Size Resize(Size size, int? width, int? height, int? maxWidth, int? maxHeight)
- {
- decimal newWidth = size.Width;
- decimal newHeight = size.Height;
-
- if (width.HasValue && height.HasValue)
- {
- newWidth = width.Value;
- newHeight = height.Value;
- }
-
- else if (height.HasValue)
- {
- newWidth = GetNewWidth(newHeight, newWidth, height.Value);
- newHeight = height.Value;
- }
-
- else if (width.HasValue)
- {
- newHeight = GetNewHeight(newHeight, newWidth, width.Value);
- newWidth = width.Value;
- }
-
- if (maxHeight.HasValue && maxHeight < newHeight)
- {
- newWidth = GetNewWidth(newHeight, newWidth, maxHeight.Value);
- newHeight = maxHeight.Value;
- }
-
- if (maxWidth.HasValue && maxWidth < newWidth)
- {
- newHeight = GetNewHeight(newHeight, newWidth, maxWidth.Value);
- newWidth = maxWidth.Value;
- }
-
- return new Size(Convert.ToInt32(newWidth), Convert.ToInt32(newHeight));
- }
-
- private static decimal GetNewWidth(decimal currentHeight, decimal currentWidth, int newHeight)
- {
- decimal scaleFactor = newHeight;
- scaleFactor /= currentHeight;
- scaleFactor *= currentWidth;
-
- return scaleFactor;
- }
-
- private static decimal GetNewHeight(decimal currentHeight, decimal currentWidth, int newWidth)
- {
- decimal scaleFactor = newWidth;
- scaleFactor /= currentWidth;
- scaleFactor *= currentHeight;
-
- return scaleFactor;
- }
- }
-}
diff --git a/MediaBrowser.Api/Drawing/ImageProcessor.cs b/MediaBrowser.Api/Drawing/ImageProcessor.cs
deleted file mode 100644
index 1a471acf54..0000000000
--- a/MediaBrowser.Api/Drawing/ImageProcessor.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Entities;
-using System;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Linq;
-
-namespace MediaBrowser.Api.Drawing
-{
- public static class ImageProcessor
- {
- ///
- /// Processes an image by resizing to target dimensions
- ///
- /// The entity that owns the image
- /// The image type
- /// The image index (currently only used with backdrops)
- /// The stream to save the new image to
- /// Use if a fixed width is required. Aspect ratio will be preserved.
- /// Use if a fixed height is required. Aspect ratio will be preserved.
- /// Use if a max width is required. Aspect ratio will be preserved.
- /// Use if a max height is required. Aspect ratio will be preserved.
- /// Quality level, from 0-100. Currently only applies to JPG. The default value should suffice.
- public static void ProcessImage(BaseEntity entity, ImageType imageType, int imageIndex, Stream toStream, int? width, int? height, int? maxWidth, int? maxHeight, int? quality)
- {
- Image originalImage = Image.FromFile(GetImagePath(entity, imageType, imageIndex));
-
- // Determine the output size based on incoming parameters
- Size newSize = DrawingUtils.Resize(originalImage.Size, width, height, maxWidth, maxHeight);
-
- Bitmap thumbnail;
-
- // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
- if (originalImage.PixelFormat.HasFlag(PixelFormat.Indexed))
- {
- thumbnail = new Bitmap(originalImage, newSize.Width, newSize.Height);
- }
- else
- {
- thumbnail = new Bitmap(newSize.Width, newSize.Height, originalImage.PixelFormat);
- }
-
- thumbnail.MakeTransparent();
-
- // Preserve the original resolution
- thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);
-
- Graphics thumbnailGraph = Graphics.FromImage(thumbnail);
-
- thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;
- thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;
- thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
- thumbnailGraph.PixelOffsetMode = PixelOffsetMode.HighQuality;
- thumbnailGraph.CompositingMode = CompositingMode.SourceOver;
-
- thumbnailGraph.DrawImage(originalImage, 0, 0, newSize.Width, newSize.Height);
-
- ImageFormat outputFormat = originalImage.RawFormat;
-
- // Write to the output stream
- SaveImage(outputFormat, thumbnail, toStream, quality);
-
- thumbnailGraph.Dispose();
- thumbnail.Dispose();
- originalImage.Dispose();
- }
-
- public static string GetImagePath(BaseEntity entity, ImageType imageType, int imageIndex)
- {
- var item = entity as BaseItem;
-
- if (item != null)
- {
- if (imageType == ImageType.Logo)
- {
- return item.LogoImagePath;
- }
- if (imageType == ImageType.Backdrop)
- {
- return item.BackdropImagePaths.ElementAt(imageIndex);
- }
- if (imageType == ImageType.Banner)
- {
- return item.BannerImagePath;
- }
- if (imageType == ImageType.Art)
- {
- return item.ArtImagePath;
- }
- if (imageType == ImageType.Thumbnail)
- {
- return item.ThumbnailImagePath;
- }
- }
-
- return entity.PrimaryImagePath;
- }
-
- public static void SaveImage(ImageFormat outputFormat, Image newImage, Stream toStream, int? quality)
- {
- // Use special save methods for jpeg and png that will result in a much higher quality image
- // All other formats use the generic Image.Save
- if (ImageFormat.Jpeg.Equals(outputFormat))
- {
- SaveJpeg(newImage, toStream, quality);
- }
- else if (ImageFormat.Png.Equals(outputFormat))
- {
- newImage.Save(toStream, ImageFormat.Png);
- }
- else
- {
- newImage.Save(toStream, outputFormat);
- }
- }
-
- public static void SaveJpeg(Image image, Stream target, int? quality)
- {
- if (!quality.HasValue)
- {
- quality = 90;
- }
-
- using (var encoderParameters = new EncoderParameters(1))
- {
- encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality.Value);
- image.Save(target, GetImageCodecInfo("image/jpeg"), encoderParameters);
- }
- }
-
- public static ImageCodecInfo GetImageCodecInfo(string mimeType)
- {
- ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
-
- for (int i = 0; i < info.Length; i++)
- {
- ImageCodecInfo ici = info[i];
- if (ici.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase))
- {
- return ici;
- }
- }
- return info[1];
- }
- }
-}
diff --git a/MediaBrowser.Api/EnvironmentService.cs b/MediaBrowser.Api/EnvironmentService.cs
new file mode 100644
index 0000000000..e552c7f1de
--- /dev/null
+++ b/MediaBrowser.Api/EnvironmentService.cs
@@ -0,0 +1,200 @@
+using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Net;
+using MediaBrowser.Model.IO;
+using ServiceStack.ServiceHost;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Api
+{
+ ///
+ /// Class GetDirectoryContents
+ ///
+ [Route("/Environment/DirectoryContents", "GET")]
+ public class GetDirectoryContents : IReturn>
+ {
+ ///
+ /// Gets or sets the path.
+ ///
+ /// The path.
+ public string Path { get; set; }
+ ///
+ /// Gets or sets a value indicating whether [include files].
+ ///
+ /// true if [include files]; otherwise, false.
+ public bool IncludeFiles { get; set; }
+ ///
+ /// Gets or sets a value indicating whether [include directories].
+ ///
+ /// true if [include directories]; otherwise, false.
+ public bool IncludeDirectories { get; set; }
+ ///
+ /// Gets or sets a value indicating whether [include hidden].
+ ///
+ /// true if [include hidden]; otherwise, false.
+ public bool IncludeHidden { get; set; }
+ }
+
+ ///
+ /// Class GetDrives
+ ///
+ [Route("/Environment/Drives", "GET")]
+ public class GetDrives : IReturn>
+ {
+ }
+
+ ///
+ /// Class GetNetworkComputers
+ ///
+ [Route("/Environment/NetworkComputers", "GET")]
+ public class GetNetworkComputers : IReturn>
+ {
+ }
+
+ ///
+ /// Class EnvironmentService
+ ///
+ [Export(typeof(IRestfulService))]
+ public class EnvironmentService : BaseRestService
+ {
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ /// Path
+ ///
+ public object Get(GetDirectoryContents request)
+ {
+ var path = request.Path;
+
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException("Path");
+ }
+
+ // Reject invalid input
+ if (!Path.IsPathRooted(path))
+ {
+ throw new ArgumentException(string.Format("Invalid path: {0}", path));
+ }
+
+ if (path.StartsWith(NetworkPrefix, StringComparison.OrdinalIgnoreCase) && path.LastIndexOf('\\') == 1)
+ {
+ return GetNetworkShares(path).ToList();
+ }
+
+ return GetFileSystemEntries(request).ToList();
+ }
+
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ public object Get(GetDrives request)
+ {
+ return GetDrives().ToList();
+ }
+
+ ///
+ /// Gets the specified request.
+ ///
+ /// The request.
+ /// System.Object.
+ public object Get(GetNetworkComputers request)
+ {
+ return GetNetworkComputers().ToList();
+ }
+
+ ///
+ /// Gets the list that is returned when an empty path is supplied
+ ///
+ /// IEnumerable{FileSystemEntryInfo}.
+ private IEnumerable GetDrives()
+ {
+ // Only include drives in the ready state or this method could end up being very slow, waiting for drives to timeout
+ return DriveInfo.GetDrives().Where(d => d.IsReady).Select(d => new FileSystemEntryInfo
+ {
+ Name = GetName(d),
+ Path = d.RootDirectory.FullName,
+ Type = FileSystemEntryType.Directory
+
+ });
+ }
+
+ ///
+ /// Gets the network computers.
+ ///
+ /// IEnumerable{FileSystemEntryInfo}.
+ private IEnumerable GetNetworkComputers()
+ {
+ return NetUtils.GetNetworkComputers().Select(c => new FileSystemEntryInfo
+ {
+ Name = c,
+ Path = NetworkPrefix + c,
+ Type = FileSystemEntryType.NetworkComputer
+ });
+ }
+
+ ///
+ /// Gets the name.
+ ///
+ /// The drive.
+ /// System.String.
+ private string GetName(DriveInfo drive)
+ {
+ return drive.Name;
+ }
+
+ ///
+ /// Gets the network shares.
+ ///
+ /// The path.
+ /// IEnumerable{FileSystemEntryInfo}.
+ private IEnumerable GetNetworkShares(string path)
+ {
+ return new ShareCollection(path).OfType().Where(s => s.ShareType == ShareType.Disk).Select(c => new FileSystemEntryInfo
+ {
+ Name = c.NetName,
+ Path = Path.Combine(path, c.NetName),
+ Type = FileSystemEntryType.NetworkShare
+ });
+ }
+
+ ///
+ /// Gets the file system entries.
+ ///
+ /// The request.
+ /// IEnumerable{FileSystemEntryInfo}.
+ private IEnumerable GetFileSystemEntries(GetDirectoryContents request)
+ {
+ var fileSystemEntries = FileSystem.GetFileSystemEntries(request.Path, "*", request.IncludeFiles, request.IncludeDirectories).Where(f => !f.IsSystemFile);
+
+ if (!request.IncludeHidden)
+ {
+ fileSystemEntries = fileSystemEntries.Where(f => !f.IsHidden);
+ }
+
+ return fileSystemEntries.Select(f => new FileSystemEntryInfo
+ {
+ Name = f.cFileName,
+ Path = f.Path,
+ Type = f.IsDirectory ? FileSystemEntryType.Directory : FileSystemEntryType.File
+ });
+ }
+
+ ///
+ /// Gets the network prefix.
+ ///
+ /// The network prefix.
+ private string NetworkPrefix
+ {
+ get { return Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture) + Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture); }
+ }
+ }
+}
diff --git a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs
deleted file mode 100644
index 9c16acd2ef..0000000000
--- a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-using MediaBrowser.Common.Net.Handlers;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.DTO;
-using System.Collections.Generic;
-using System.ComponentModel.Composition;
-using System.IO;
-using System.Net;
-
-namespace MediaBrowser.Api.HttpHandlers
-{
- ///
- /// Supported output formats are: mp3,flac,ogg,wav,asf,wma,aac
- ///
- [Export(typeof(BaseHandler))]
- public class AudioHandler : BaseMediaHandler