Преглед изворни кода

Merge branch 'master' into namingtests

Bond_009 пре 5 година
родитељ
комит
b50c4938e1
100 измењених фајлова са 982 додато и 7134 уклоњено
  1. 42 89
      .ci/azure-pipelines.yml
  2. 1 1
      .vscode/launch.json
  3. 0 17
      BDInfo/BDInfo.csproj
  4. 0 33
      BDInfo/BDInfoSettings.cs
  5. 0 449
      BDInfo/BDROM.cs
  6. 0 493
      BDInfo/LanguageCodes.cs
  7. 0 21
      BDInfo/Properties/AssemblyInfo.cs
  8. 0 5
      BDInfo/ReadMe.txt
  9. 0 309
      BDInfo/TSCodecAC3.cs
  10. 0 148
      BDInfo/TSCodecAVC.cs
  11. 0 159
      BDInfo/TSCodecDTS.cs
  12. 0 246
      BDInfo/TSCodecDTSHD.cs
  13. 0 123
      BDInfo/TSCodecLPCM.cs
  14. 0 208
      BDInfo/TSCodecMPEG2.cs
  15. 0 36
      BDInfo/TSCodecMVC.cs
  16. 0 186
      BDInfo/TSCodecTrueHD.cs
  17. 0 131
      BDInfo/TSCodecVC1.cs
  18. 0 37
      BDInfo/TSInterleavedFile.cs
  19. 0 1282
      BDInfo/TSPlaylistFile.cs
  20. 0 780
      BDInfo/TSStream.cs
  21. 0 130
      BDInfo/TSStreamBuffer.cs
  22. 0 107
      BDInfo/TSStreamClip.cs
  23. 0 244
      BDInfo/TSStreamClipFile.cs
  24. 0 1555
      BDInfo/TSStreamFile.cs
  25. 1 0
      CONTRIBUTORS.md
  26. 1 1
      Dockerfile
  27. 1 1
      Dockerfile.arm
  28. 1 1
      Dockerfile.arm64
  29. 12 24
      Emby.Dlna/Eventing/EventManager.cs
  30. 3 0
      Emby.Naming/Audio/AlbumParser.cs
  31. 3 0
      Emby.Naming/Audio/AudioFileParser.cs
  32. 3 0
      Emby.Naming/Audio/MultiPartResult.cs
  33. 3 0
      Emby.Naming/AudioBook/AudioBookFilePathParser.cs
  34. 3 0
      Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs
  35. 3 0
      Emby.Naming/AudioBook/AudioBookInfo.cs
  36. 3 0
      Emby.Naming/AudioBook/AudioBookListResolver.cs
  37. 3 0
      Emby.Naming/AudioBook/AudioBookResolver.cs
  38. 3 0
      Emby.Naming/Common/EpisodeExpression.cs
  39. 3 0
      Emby.Naming/Common/MediaType.cs
  40. 3 0
      Emby.Naming/Common/NamingOptions.cs
  41. 5 1
      Emby.Naming/Emby.Naming.csproj
  42. 3 0
      Emby.Naming/Subtitles/SubtitleInfo.cs
  43. 3 0
      Emby.Naming/Subtitles/SubtitleParser.cs
  44. 3 0
      Emby.Naming/TV/EpisodeInfo.cs
  45. 3 0
      Emby.Naming/TV/EpisodePathParser.cs
  46. 3 0
      Emby.Naming/TV/EpisodePathParserResult.cs
  47. 3 0
      Emby.Naming/TV/EpisodeResolver.cs
  48. 3 0
      Emby.Naming/TV/SeasonPathParser.cs
  49. 3 0
      Emby.Naming/TV/SeasonPathParserResult.cs
  50. 3 0
      Emby.Naming/Video/CleanDateTimeParser.cs
  51. 5 0
      Emby.Naming/Video/CleanDateTimeResult.cs
  52. 3 0
      Emby.Naming/Video/CleanStringParser.cs
  53. 4 0
      Emby.Naming/Video/CleanStringResult.cs
  54. 3 0
      Emby.Naming/Video/ExtraResolver.cs
  55. 3 0
      Emby.Naming/Video/ExtraResult.cs
  56. 6 2
      Emby.Naming/Video/ExtraRule.cs
  57. 5 0
      Emby.Naming/Video/ExtraRuleType.cs
  58. 9 4
      Emby.Naming/Video/FileStack.cs
  59. 3 0
      Emby.Naming/Video/FlagParser.cs
  60. 3 0
      Emby.Naming/Video/Format3DParser.cs
  61. 3 0
      Emby.Naming/Video/Format3DResult.cs
  62. 4 0
      Emby.Naming/Video/Format3DRule.cs
  63. 3 0
      Emby.Naming/Video/StackResolver.cs
  64. 3 0
      Emby.Naming/Video/StackResult.cs
  65. 3 0
      Emby.Naming/Video/StubResolver.cs
  66. 3 0
      Emby.Naming/Video/StubResult.cs
  67. 3 0
      Emby.Naming/Video/StubTypeRule.cs
  68. 1 0
      Emby.Naming/Video/VideoFileInfo.cs
  69. 10 7
      Emby.Naming/Video/VideoInfo.cs
  70. 3 0
      Emby.Naming/Video/VideoListResolver.cs
  71. 3 0
      Emby.Naming/Video/VideoResolver.cs
  72. 5 1
      Emby.Photos/Emby.Photos.csproj
  73. 45 23
      Emby.Server.Implementations/ApplicationHost.cs
  74. 10 38
      Emby.Server.Implementations/Collections/CollectionManager.cs
  75. 5 2
      Emby.Server.Implementations/ConfigurationOptions.cs
  76. 215 4
      Emby.Server.Implementations/Data/SqliteItemRepository.cs
  77. 1 2
      Emby.Server.Implementations/Emby.Server.Implementations.csproj
  78. 1 1
      Emby.Server.Implementations/IO/ManagedFileSystem.cs
  79. 2 2
      Emby.Server.Implementations/Library/LibraryManager.cs
  80. 15 0
      Emby.Server.Implementations/Library/MediaSourceManager.cs
  81. 31 57
      Emby.Server.Implementations/Library/UserManager.cs
  82. 2 1
      Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs
  83. 3 3
      Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
  84. 2 1
      Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
  85. 37 37
      Emby.Server.Implementations/Localization/Core/ca.json
  86. 2 2
      Emby.Server.Implementations/Localization/Core/fr.json
  87. 32 0
      Emby.Server.Implementations/Localization/Core/id.json
  88. 75 75
      Emby.Server.Implementations/Localization/Core/lt-LT.json
  89. 27 27
      Emby.Server.Implementations/Localization/Core/nb.json
  90. 96 0
      Emby.Server.Implementations/Localization/Core/pt.json
  91. 96 0
      Emby.Server.Implementations/Localization/Core/ro.json
  92. 3 3
      Emby.Server.Implementations/Localization/Core/zh-CN.json
  93. 24 11
      Emby.Server.Implementations/Playlists/PlaylistManager.cs
  94. 2 2
      Emby.Server.Implementations/Updates/InstallationManager.cs
  95. 0 1
      Jellyfin.Api/Controllers/StartupController.cs
  96. 1 1
      Jellyfin.Api/Jellyfin.Api.csproj
  97. 13 0
      Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj
  98. 9 0
      Jellyfin.Drawing.Skia/PercentPlayedDrawer.cs
  99. 13 2
      Jellyfin.Drawing.Skia/PlayedIndicatorDrawer.cs
  100. 8 8
      Jellyfin.Drawing.Skia/SkiaCodecException.cs

+ 42 - 89
.ci/azure-pipelines.yml

@@ -19,9 +19,9 @@ jobs:
       vmImage: ubuntu-latest
     strategy:
       matrix:
-        release:
+        Release:
           BuildConfiguration: Release
-        debug:
+        Debug:
           BuildConfiguration: Debug
       maxParallel: 2
     steps:
@@ -31,32 +31,32 @@ jobs:
       persistCredentials: true
 
     - task: CmdLine@2
-      displayName: "Check out web"
+      displayName: "Clone Web Client (Master, Release, or Tag)"
       condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
       inputs:
         script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
 
     - task: CmdLine@2
-      displayName: "Check out web (PR)"
+      displayName: "Clone Web Client (PR)"
       condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
       inputs:
         script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
 
     - task: NodeTool@0
-      displayName: 'Install Node.js'
+      displayName: 'Install Node'
       condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
       inputs:
         versionSpec: '10.x'
 
     - task: CmdLine@2
-      displayName: "Build Web UI"
+      displayName: "Build Web Client"
       condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
       inputs:
         script: yarn install
         workingDirectory: $(Agent.TempDirectory)/jellyfin-web
 
     - task: CopyFiles@2
-      displayName: Copy the web UI
+      displayName: 'Copy Web Client'
       condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
       inputs:
         sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional
@@ -66,8 +66,14 @@ jobs:
         overWrite: true # Optional
         flattenFolders: false # Optional
 
+    - task: UseDotNet@2
+      displayName: 'Update DotNet'
+      inputs:
+        packageType: sdk
+        version: 3.1.100
+
     - task: DotNetCoreCLI@2
-      displayName: Publish
+      displayName: 'Publish Server'
       inputs:
         command: publish
         publishWebProjects: false
@@ -135,62 +141,20 @@ jobs:
           !**\obj\**
           !**\xunit.runner.visualstudio.testadapter.dll
           !**\xunit.runner.visualstudio.dotnetcore.testadapter.dll
-        #testPlan: # Required when testSelector == TestPlan
-        #testSuite: # Required when testSelector == TestPlan
-        #testConfiguration: # Required when testSelector == TestPlan
-        #tcmTestRun: '$(test.RunId)' # Optional
         searchFolder: '$(System.DefaultWorkingDirectory)'
-        #testFiltercriteria: # Optional
-        #runOnlyImpactedTests: False # Optional
-        #runAllTestsAfterXBuilds: '50' # Optional
-        #uiTests: false # Optional
-        #vstestLocationMethod: 'version' # Optional. Options: version, location
-        #vsTestVersion: 'latest' # Optional. Options: latest, 16.0, 15.0, 14.0, toolsInstaller
-        #vstestLocation: # Optional
-        #runSettingsFile: # Optional
-        #overrideTestrunParameters: # Optional
-        #pathtoCustomTestAdapters: # Optional
         runInParallel: True # Optional
         runTestsInIsolation: True # Optional
         codeCoverageEnabled: True # Optional
-        #otherConsoleOptions: # Optional
-        #distributionBatchType: 'basedOnTestCases' # Optional. Options: basedOnTestCases, basedOnExecutionTime, basedOnAssembly
-        #batchingBasedOnAgentsOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customBatchSize
-        #customBatchSizeValue: '10' # Required when distributionBatchType == BasedOnTestCases && BatchingBasedOnAgentsOption == CustomBatchSize
-        #batchingBasedOnExecutionTimeOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customTimeBatchSize
-        #customRunTimePerBatchValue: '60' # Required when distributionBatchType == BasedOnExecutionTime && BatchingBasedOnExecutionTimeOption == CustomTimeBatchSize
-        #dontDistribute: False # Optional
-        #testRunTitle: # Optional
-        #platform: # Optional
         configuration: 'Debug' # Optional
         publishRunAttachments: true # Optional
-        #diagnosticsEnabled: false # Optional
-        #collectDumpOn: 'onAbortOnly' # Optional. Options: onAbortOnly, always, never
-        #rerunFailedTests: False # Optional
-        #rerunType: 'basedOnTestFailurePercentage' # Optional. Options: basedOnTestFailurePercentage, basedOnTestFailureCount
-        #rerunFailedThreshold: '30' # Optional
-        #rerunFailedTestCasesMaxLimit: '5' # Optional
-        #rerunMaxAttempts: '3' # Optional
-
-    # - task: PublishTestResults@2
-    #   inputs:
-    #     testResultsFormat: 'VSTest' # Options: JUnit, NUnit, VSTest, xUnit, cTest
-    #     testResultsFiles: '**/*.trx'
-    #     #searchFolder: '$(System.DefaultWorkingDirectory)' # Optional
-    #     mergeTestResults: true # Optional
-    #     #failTaskOnFailedTests: false # Optional
-    #     #testRunTitle: # Optional
-    #     #buildPlatform: # Optional
-    #     #buildConfiguration: # Optional
-    #     #publishRunAttachments: true # Optional
 
   - job: main_build_win
-    displayName: Main Build Windows
+    displayName: Publish Windows
     pool:
       vmImage: windows-latest
     strategy:
       matrix:
-        release:
+        Release:
           BuildConfiguration: Release
       maxParallel: 2
     steps:
@@ -200,32 +164,32 @@ jobs:
       persistCredentials: true
 
     - task: CmdLine@2
-      displayName: "Check out web (master, release or tag)"
+      displayName: "Clone Web Client (Master, Release, or Tag)"
       condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master'), contains(variables['Build.SourceBranch'], 'tag')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
       inputs:
         script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
 
     - task: CmdLine@2
-      displayName: "Check out web (PR)"
+      displayName: "Clone Web Client (PR)"
       condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest'))
       inputs:
         script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web'
 
     - task: NodeTool@0
-      displayName: 'Install Node.js'
+      displayName: 'Install Node'
       condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
       inputs:
         versionSpec: '10.x'
 
     - task: CmdLine@2
-      displayName: "Build Web UI"
+      displayName: "Build Web Client"
       condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
       inputs:
         script: yarn install
         workingDirectory: $(Agent.TempDirectory)/jellyfin-web
 
     - task: CopyFiles@2
-      displayName: Copy the web UI
+      displayName: 'Copy Web Client'
       condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
       inputs:
         sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional
@@ -236,25 +200,21 @@ jobs:
         flattenFolders: false # Optional
 
     - task: CmdLine@2
-      displayName: Clone the UX repository
+      displayName: 'Clone UX Repository'
       inputs:
         script: git clone --depth=1 https://github.com/jellyfin/jellyfin-ux $(Agent.TempDirectory)\jellyfin-ux
 
     - task: PowerShell@2
-      displayName: Build the NSIS Installer
+      displayName: 'Build NSIS Installer'
       inputs:
         targetType: 'filePath' # Optional. Options: filePath, inline
         filePath: ./deployment/windows/build-jellyfin.ps1 # Required when targetType == FilePath
         arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -InstallTrayApp -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory)
-        #script: '# Write your PowerShell commands here.Write-Host Hello World' # Required when targetType == Inline
         errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue
-        #failOnStderr: false # Optional
-        #ignoreLASTEXITCODE: false # Optional
-        #pwsh: false # Optional
         workingDirectory: $(Build.SourcesDirectory) # Optional
 
     - task: CopyFiles@2
-      displayName: Copy the NSIS Installer to the artifact directory
+      displayName: 'Copy NSIS Installer'
       inputs:
         sourceFolder: $(Build.SourcesDirectory)/deployment/windows/ # Optional
         contents: 'jellyfin*.exe'
@@ -264,7 +224,7 @@ jobs:
         flattenFolders: true # Optional
 
     - task: PublishPipelineArtifact@0
-      displayName: 'Publish Setup Artifact'
+      displayName: 'Publish Artifact Setup'
       condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded())
       inputs:
         targetPath: '$(build.artifactstagingdirectory)/setup'
@@ -275,7 +235,8 @@ jobs:
     pool:
       vmImage: ubuntu-latest
     dependsOn: main_build
-    condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber']) # Only execute if the pullrequest numer is defined. (So not for normal CI builds)
+    # only execute for pull requests
+    condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber'])
     strategy:
       matrix:
         Naming:
@@ -293,24 +254,23 @@ jobs:
       maxParallel: 2
     steps:
     - checkout: none
+    
+    - task: UseDotNet@2
+      displayName: 'Update DotNet'
+      inputs:
+        packageType: sdk
+        version: 3.1.100
 
     - task: DownloadPipelineArtifact@2
-      displayName: Download the New Assembly Build Artifact
+      displayName: 'Download New Assembly Build Artifact'
       inputs:
         source: 'current' # Options: current, specific
-        #preferTriggeringPipeline: false # Optional
-        #tags: # Optional
         artifact: '$(NugetPackageName)' # Optional
-        #patterns: '**' # Optional
         path: '$(System.ArtifactsDirectory)/new-artifacts'
-        #project: # Required when source == Specific
-        #pipeline: # Required when source == Specific
         runVersion: 'latest' # Required when source == Specific. Options: latest, latestFromBranch, specific
-        #runBranch: 'refs/heads/master' # Required when source == Specific && runVersion == LatestFromBranch
-        #runId: # Required when source == Specific && runVersion == Specific
 
     - task: CopyFiles@2
-      displayName: Copy New Assembly to new-release folder
+      displayName: 'Copy New Assembly Build Artifact'
       inputs:
         sourceFolder: $(System.ArtifactsDirectory)/new-artifacts # Optional
         contents: '**/*.dll'
@@ -320,22 +280,18 @@ jobs:
         flattenFolders: true # Optional
 
     - task: DownloadPipelineArtifact@2
-      displayName: Download the Reference Assembly Build Artifact
+      displayName: 'Download Reference Assembly Build Artifact'
       inputs:
         source: 'specific' # Options: current, specific
-        #preferTriggeringPipeline: false # Optional
-        #tags: # Optional
         artifact: '$(NugetPackageName)' # Optional
-        #patterns: '**' # Optional
         path: '$(System.ArtifactsDirectory)/current-artifacts'
         project: '$(System.TeamProjectId)' # Required when source == Specific
         pipeline: '$(System.DefinitionId)' # Required when source == Specific
         runVersion: 'latestFromBranch' # Required when source == Specific. Options: latest, latestFromBranch, specific
         runBranch: 'refs/heads/$(System.PullRequest.TargetBranch)' # Required when source == Specific && runVersion == LatestFromBranch
-        #runId: # Required when source == Specific && runVersion == Specific
 
     - task: CopyFiles@2
-      displayName: Copy Reference Assembly to current-release folder
+      displayName: 'Copy Reference Assembly Build Artifact'
       inputs:
         sourceFolder: $(System.ArtifactsDirectory)/current-artifacts # Optional
         contents: '**/*.dll'
@@ -345,27 +301,24 @@ jobs:
         flattenFolders: true # Optional
 
     - task: DownloadGitHubRelease@0
-      displayName: Download ABI compatibility check tool from GitHub
+      displayName: 'Download ABI Compatibility Check Tool'
       inputs:
         connection: Jellyfin Release Download
         userRepository: EraYaN/dotnet-compatibility
         defaultVersionType: 'latest' # Options: latest, specificVersion, specificTag
-        #version: # Required when defaultVersionType != Latest
         itemPattern: '**-ci.zip' # Optional
         downloadPath: '$(System.ArtifactsDirectory)'
 
     - task: ExtractFiles@1
-      displayName: Extract ABI compatibility check tool
+      displayName: 'Extract ABI Compatibility Check Tool'
       inputs:
         archiveFilePatterns: '$(System.ArtifactsDirectory)/*-ci.zip'
         destinationFolder: $(System.ArtifactsDirectory)/tools
         cleanDestinationFolder: true
 
+    # The `--warnings-only` switch will swallow the return code and not emit any errors.
     - task: CmdLine@2
-      displayName: Execute ABI compatibility check tool
+      displayName: 'Execute ABI Compatibility Check Tool'
       inputs:
-        script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines'
+        script: 'dotnet tools/CompatibilityCheckerCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines --warnings-only'
         workingDirectory: $(System.ArtifactsDirectory) # Optional
-        #failOnStderr: false # Optional
-
-

+ 1 - 1
.vscode/launch.json

@@ -10,7 +10,7 @@
             "request": "launch",
             "preLaunchTask": "build",
             // If you have changed target frameworks, make sure to update the program path.
-            "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.0/jellyfin.dll",
+            "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.1/jellyfin.dll",
             "args": [],
             "cwd": "${workspaceFolder}/Jellyfin.Server",
             // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window

+ 0 - 17
BDInfo/BDInfo.csproj

@@ -1,17 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
-  <ItemGroup>
-    <Compile Include="..\SharedVersion.cs" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
-  </ItemGroup>
-
-  <PropertyGroup>
-    <TargetFramework>netstandard2.0</TargetFramework>
-    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
-    <GenerateDocumentationFile>true</GenerateDocumentationFile>
-  </PropertyGroup>
-
-</Project>

+ 0 - 33
BDInfo/BDInfoSettings.cs

@@ -1,33 +0,0 @@
-
-namespace BDInfo
-{
-    class BDInfoSettings
-    {
-        public static bool GenerateStreamDiagnostics => true;
-
-        public static bool EnableSSIF => true;
-
-        public static bool AutosaveReport => false;
-
-        public static bool GenerateFrameDataFile => false;
-
-        public static bool FilterLoopingPlaylists => true;
-
-        public static bool FilterShortPlaylists => false;
-
-        public static int FilterShortPlaylistsValue => 0;
-
-        public static bool UseImagePrefix => false;
-
-        public static string UseImagePrefixValue => null;
-
-        /// <summary>
-        /// Setting this to false throws an IComparer error on some discs.
-        /// </summary>
-        public static bool KeepStreamOrder => true;
-
-        public static bool GenerateTextSummary => false;
-
-        public static string LastPath => string.Empty;
-    }
-}

+ 0 - 449
BDInfo/BDROM.cs

@@ -1,449 +0,0 @@
-//============================================================================
-// 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.Linq;
-using MediaBrowser.Model.IO;
-
-namespace BDInfo
-{
-    public class BDROM
-    {
-        public FileSystemMetadata DirectoryRoot = null;
-        public FileSystemMetadata DirectoryBDMV = null;
-        public FileSystemMetadata DirectoryBDJO = null;
-        public FileSystemMetadata DirectoryCLIPINF = null;
-        public FileSystemMetadata DirectoryPLAYLIST = null;
-        public FileSystemMetadata DirectorySNP = null;
-        public FileSystemMetadata DirectorySSIF = null;
-        public FileSystemMetadata 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;
-
-        private readonly IFileSystem _fileSystem;
-
-        public Dictionary<string, TSPlaylistFile> PlaylistFiles =
-            new Dictionary<string, TSPlaylistFile>();
-        public Dictionary<string, TSStreamClipFile> StreamClipFiles =
-            new Dictionary<string, TSStreamClipFile>();
-        public Dictionary<string, TSStreamFile> StreamFiles =
-            new Dictionary<string, TSStreamFile>();
-        public Dictionary<string, TSInterleavedFile> InterleavedFiles =
-            new Dictionary<string, TSInterleavedFile>();
-
-        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, IFileSystem fileSystem)
-        {
-            if (string.IsNullOrEmpty(path))
-            {
-                throw new ArgumentNullException(nameof(path));
-            }
-
-            _fileSystem = fileSystem;
-            //
-            // Locate BDMV directories.
-            //
-
-            DirectoryBDMV =
-                GetDirectoryBDMV(path);
-
-            if (DirectoryBDMV == null)
-            {
-                throw new Exception("Unable to locate BD structure.");
-            }
-
-            DirectoryRoot =
-                _fileSystem.GetDirectoryInfo(Path.GetDirectoryName(DirectoryBDMV.FullName));
-            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 &&
-                _fileSystem.GetFilePaths(DirectoryBDJO.FullName).Any())
-            {
-                IsBDJava = true;
-            }
-
-            if (DirectorySNP != null &&
-                GetFilePaths(DirectorySNP.FullName, ".mnv").Any())
-            {
-                IsPSP = true;
-            }
-
-            if (DirectorySSIF != null &&
-                _fileSystem.GetFilePaths(DirectorySSIF.FullName).Any())
-            {
-                Is3D = true;
-            }
-
-            if (File.Exists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml")))
-            {
-                IsDBOX = true;
-            }
-
-            //
-            // Initialize file lists.
-            //
-
-            if (DirectoryPLAYLIST != null)
-            {
-                FileSystemMetadata[] files = GetFiles(DirectoryPLAYLIST.FullName, ".mpls").ToArray();
-                foreach (var file in files)
-                {
-                    PlaylistFiles.Add(
-                        file.Name.ToUpper(), new TSPlaylistFile(this, file));
-                }
-            }
-
-            if (DirectorySTREAM != null)
-            {
-                FileSystemMetadata[] files = GetFiles(DirectorySTREAM.FullName, ".m2ts").ToArray();
-                foreach (var file in files)
-                {
-                    StreamFiles.Add(
-                        file.Name.ToUpper(), new TSStreamFile(file, _fileSystem));
-                }
-            }
-
-            if (DirectoryCLIPINF != null)
-            {
-                FileSystemMetadata[] files = GetFiles(DirectoryCLIPINF.FullName, ".clpi").ToArray();
-                foreach (var file in files)
-                {
-                    StreamClipFiles.Add(
-                        file.Name.ToUpper(), new TSStreamClipFile(file));
-                }
-            }
-
-            if (DirectorySSIF != null)
-            {
-                FileSystemMetadata[] files = GetFiles(DirectorySSIF.FullName, ".ssif").ToArray();
-                foreach (var file in files)
-                {
-                    InterleavedFiles.Add(
-                        file.Name.ToUpper(), new TSInterleavedFile(file));
-                }
-            }
-        }
-
-        private IEnumerable<FileSystemMetadata> GetFiles(string path, string extension)
-        {
-            return _fileSystem.GetFiles(path, new[] { extension }, false, false);
-        }
-
-        private IEnumerable<string> GetFilePaths(string path, string extension)
-        {
-            return _fileSystem.GetFilePaths(path, new[] { extension }, false, false);
-        }
-
-        public void Scan()
-        {
-            foreach (var streamClipFile in StreamClipFiles.Values)
-            {
-                try
-                {
-                    streamClipFile.Scan();
-                }
-                catch (Exception ex)
-                {
-                    if (StreamClipFileScanError != null)
-                    {
-                        if (StreamClipFileScanError(streamClipFile, ex))
-                        {
-                            continue;
-                        }
-                        else
-                        {
-                            break;
-                        }
-                    }
-                    else throw;
-                }
-            }
-
-            foreach (var 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);
-
-            foreach (var playlistFile in PlaylistFiles.Values)
-            {
-                try
-                {
-                    playlistFile.Scan(StreamFiles, StreamClipFiles);
-                }
-                catch (Exception ex)
-                {
-                    if (PlaylistFileScanError != null)
-                    {
-                        if (PlaylistFileScanError(playlistFile, ex))
-                        {
-                            continue;
-                        }
-                        else
-                        {
-                            break;
-                        }
-                    }
-                    else throw;
-                }
-            }
-
-            foreach (var streamFile in streamFiles)
-            {
-                try
-                {
-                    var playlists = new List<TSPlaylistFile>();
-                    foreach (var playlist in PlaylistFiles.Values)
-                    {
-                        foreach (var streamClip in playlist.StreamClips)
-                        {
-                            if (streamClip.Name == streamFile.Name)
-                            {
-                                playlists.Add(playlist);
-                                break;
-                            }
-                        }
-                    }
-                    streamFile.Scan(playlists, false);
-                }
-                catch (Exception ex)
-                {
-                    if (StreamFileScanError != null)
-                    {
-                        if (StreamFileScanError(streamFile, ex))
-                        {
-                            continue;
-                        }
-                        else
-                        {
-                            break;
-                        }
-                    }
-                    else throw;
-                }
-            }
-
-            foreach (var playlistFile in PlaylistFiles.Values)
-            {
-                playlistFile.Initialize();
-                if (!Is50Hz)
-                {
-                    foreach (var videoStream in playlistFile.VideoStreams)
-                    {
-                        if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 ||
-                            videoStream.FrameRate == TSFrameRate.FRAMERATE_50)
-                        {
-                            Is50Hz = true;
-                        }
-                    }
-                }
-            }
-        }
-
-        private FileSystemMetadata GetDirectoryBDMV(
-            string path)
-        {
-            if (string.IsNullOrEmpty(path))
-            {
-                throw new ArgumentNullException(nameof(path));
-            }
-
-            FileSystemMetadata dir = _fileSystem.GetDirectoryInfo(path);
-
-            while (dir != null)
-            {
-                if (string.Equals(dir.Name, "BDMV", StringComparison.OrdinalIgnoreCase))
-                {
-                    return dir;
-                }
-                var parentFolder = Path.GetDirectoryName(dir.FullName);
-                if (string.IsNullOrEmpty(parentFolder))
-                {
-                    dir = null;
-                }
-                else
-                {
-                    dir = _fileSystem.GetDirectoryInfo(parentFolder);
-                }
-            }
-
-            return GetDirectory("BDMV", _fileSystem.GetDirectoryInfo(path), 0);
-        }
-
-        private FileSystemMetadata GetDirectory(
-            string name,
-            FileSystemMetadata dir,
-            int searchDepth)
-        {
-            if (dir != null)
-            {
-                FileSystemMetadata[] children = _fileSystem.GetDirectories(dir.FullName).ToArray();
-                foreach (var child in children)
-                {
-                    if (string.Equals(child.Name, name, StringComparison.OrdinalIgnoreCase))
-                    {
-                        return child;
-                    }
-                }
-                if (searchDepth > 0)
-                {
-                    foreach (var child in children)
-                    {
-                        GetDirectory(
-                            name, child, searchDepth - 1);
-                    }
-                }
-            }
-            return null;
-        }
-
-        private long GetDirectorySize(FileSystemMetadata directoryInfo)
-        {
-            long size = 0;
-
-            //if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper()))  // TODO: Keep?
-            {
-                FileSystemMetadata[] pathFiles = _fileSystem.GetFiles(directoryInfo.FullName).ToArray();
-                foreach (var pathFile in pathFiles)
-                {
-                    if (pathFile.Extension.ToUpper() == ".SSIF")
-                    {
-                        continue;
-                    }
-                    size += pathFile.Length;
-                }
-
-                FileSystemMetadata[] pathChildren = _fileSystem.GetDirectories(directoryInfo.FullName).ToArray();
-                foreach (var pathChild in pathChildren)
-                {
-                    size += GetDirectorySize(pathChild);
-                }
-            }
-
-            return size;
-        }
-
-        private string GetVolumeLabel(FileSystemMetadata dir)
-        {
-            return dir.Name;
-        }
-
-        public 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;
-                }
-            }
-        }
-    }
-}

+ 0 - 493
BDInfo/LanguageCodes.cs

@@ -1,493 +0,0 @@
-//============================================================================
-// 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
-//=============================================================================
-
-
-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;
-            }
-        }
-    }
-}

+ 0 - 21
BDInfo/Properties/AssemblyInfo.cs

@@ -1,21 +0,0 @@
-using System.Reflection;
-using System.Resources;
-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("Jellyfin Project")]
-[assembly: AssemblyProduct("Jellyfin Server")]
-[assembly: AssemblyCopyright("Copyright ©  2016 CinemaSquid. Copyright ©  2019 Jellyfin Contributors. Code released under the GNU General Public License")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: NeutralResourcesLanguage("en")]
-
-// 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)]

+ 0 - 5
BDInfo/ReadMe.txt

@@ -1,5 +0,0 @@
-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.

+ 0 - 309
BDInfo/TSCodecAC3.cs

@@ -1,309 +0,0 @@
-//============================================================================
-// 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.IO;
-
-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;
-        }
-    }
-}

+ 0 - 148
BDInfo/TSCodecAVC.cs

@@ -1,148 +0,0 @@
-//============================================================================
-// 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
-//=============================================================================
-
-
-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;
-        }
-    }
-}

+ 0 - 159
BDInfo/TSCodecDTS.cs

@@ -1,159 +0,0 @@
-//============================================================================
-// 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
-//=============================================================================
-
-
-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;
-            }
-        }
-    }
-}

+ 0 - 246
BDInfo/TSCodecDTSHD.cs

@@ -1,246 +0,0 @@
-//============================================================================
-// 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
-//=============================================================================
-
-
-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)
-            {
-                var 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);
-            }
-        }
-    }
-}

+ 0 - 123
BDInfo/TSCodecLPCM.cs

@@ -1,123 +0,0 @@
-//============================================================================
-// 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
-//=============================================================================
-
-
-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;
-        }
-    }
-}

+ 0 - 208
BDInfo/TSCodecMPEG2.cs

@@ -1,208 +0,0 @@
-//============================================================================
-// 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
-
-
-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
-                }
-            }
-        }
-    }
-}

+ 0 - 36
BDInfo/TSCodecMVC.cs

@@ -1,36 +0,0 @@
-//============================================================================
-// 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
-//=============================================================================
-
-
-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;
-        }
-    }
-}

+ 0 - 186
BDInfo/TSCodecTrueHD.cs

@@ -1,186 +0,0 @@
-//============================================================================
-// 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
-//=============================================================================
-
-
-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;
-        }
-    }
-}

+ 0 - 131
BDInfo/TSCodecVC1.cs

@@ -1,131 +0,0 @@
-//============================================================================
-// 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
-//=============================================================================
-
-
-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;
-                }
-            }
-        }
-    }
-}

+ 0 - 37
BDInfo/TSInterleavedFile.cs

@@ -1,37 +0,0 @@
-//============================================================================
-// 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 MediaBrowser.Model.IO;
-
-// TODO: Do more interesting things here...
-
-namespace BDInfo
-{
-    public class TSInterleavedFile
-    {
-        public FileSystemMetadata FileInfo = null;
-        public string Name = null;
-
-        public TSInterleavedFile(FileSystemMetadata fileInfo)
-        {
-            FileInfo = fileInfo;
-            Name = fileInfo.Name.ToUpper();
-        }
-    }
-}

+ 0 - 1282
BDInfo/TSPlaylistFile.cs

@@ -1,1282 +0,0 @@
-//============================================================================
-// 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.IO;
-using System.Text;
-using MediaBrowser.Model.IO;
-
-namespace BDInfo
-{
-    public class TSPlaylistFile
-    {
-        private FileSystemMetadata 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<double> Chapters = new List<double>();
-
-        public Dictionary<ushort, TSStream> Streams =
-            new Dictionary<ushort, TSStream>();
-        public Dictionary<ushort, TSStream> PlaylistStreams =
-            new Dictionary<ushort, TSStream>();
-        public List<TSStreamClip> StreamClips =
-            new List<TSStreamClip>();
-        public List<Dictionary<ushort, TSStream>> AngleStreams =
-            new List<Dictionary<ushort, TSStream>>();
-        public List<Dictionary<double, TSStreamClip>> AngleClips =
-            new List<Dictionary<double, TSStreamClip>>();
-        public int AngleCount = 0;
-
-        public List<TSStream> SortedStreams =
-            new List<TSStream>();
-        public List<TSVideoStream> VideoStreams =
-            new List<TSVideoStream>();
-        public List<TSAudioStream> AudioStreams =
-            new List<TSAudioStream>();
-        public List<TSTextStream> TextStreams =
-            new List<TSTextStream>();
-        public List<TSGraphicsStream> GraphicsStreams =
-            new List<TSGraphicsStream>();
-
-        public TSPlaylistFile(BDROM bdrom,
-            FileSystemMetadata fileInfo)
-        {
-            BDROM = bdrom;
-            FileInfo = fileInfo;
-            Name = fileInfo.Name.ToUpper();
-        }
-
-        public TSPlaylistFile(BDROM bdrom,
-            string name,
-            List<TSStreamClip> clips)
-        {
-            BDROM = bdrom;
-            Name = name;
-            IsCustom = true;
-            foreach (var clip in clips)
-            {
-                var 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 (var clip in StreamClips)
-                {
-                    size += clip.InterleavedFileSize;
-                }
-                return size;
-            }
-        }
-        public ulong FileSize
-        {
-            get
-            {
-                ulong size = 0;
-                foreach (var clip in StreamClips)
-                {
-                    size += clip.FileSize;
-                }
-                return size;
-            }
-        }
-        public double TotalLength
-        {
-            get
-            {
-                double length = 0;
-                foreach (var clip in StreamClips)
-                {
-                    if (clip.AngleIndex == 0)
-                    {
-                        length += clip.Length;
-                    }
-                }
-                return length;
-            }
-        }
-
-        public double TotalAngleLength
-        {
-            get
-            {
-                double length = 0;
-                foreach (var clip in StreamClips)
-                {
-                    length += clip.Length;
-                }
-                return length;
-            }
-        }
-
-        public ulong TotalSize
-        {
-            get
-            {
-                ulong size = 0;
-                foreach (var clip in StreamClips)
-                {
-                    if (clip.AngleIndex == 0)
-                    {
-                        size += clip.PacketSize;
-                    }
-                }
-                return size;
-            }
-        }
-
-        public ulong TotalAngleSize
-        {
-            get
-            {
-                ulong size = 0;
-                foreach (var 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<string, TSStreamFile> streamFiles,
-            Dictionary<string, TSStreamClipFile> streamClipFiles)
-        {
-            Stream 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);
-
-                var chapterClips = new List<TSStreamClip>();
-                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)
-                    {
-                        // Error condition
-                    }
-
-                    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;
-
-                    var 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));
-                            }
-
-                            var 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++)
-                    {
-                        var stream = CreatePlaylistStream(data, ref pos);
-                        if (stream != null) PlaylistStreams[stream.PID] = stream;
-                    }
-                    for (int i = 0; i < streamCountAudio; i++)
-                    {
-                        var stream = CreatePlaylistStream(data, ref pos);
-                        if (stream != null) PlaylistStreams[stream.PID] = stream;
-                    }
-                    for (int i = 0; i < streamCountPG; i++)
-                    {
-                        var stream = CreatePlaylistStream(data, ref pos);
-                        if (stream != null) PlaylistStreams[stream.PID] = stream;
-                    }
-                    for (int i = 0; i < streamCountIG; i++)
-                    {
-                        var stream = CreatePlaylistStream(data, ref pos);
-                        if (stream != null) PlaylistStreams[stream.PID] = stream;
-                    }
-                    for (int i = 0; i < streamCountSecondaryAudio; i++)
-                    {
-                        var stream = CreatePlaylistStream(data, ref pos);
-                        if (stream != null) PlaylistStreams[stream.PID] = stream;
-                        pos += 2;
-                    }
-                    for (int i = 0; i < streamCountSecondaryVideo; i++)
-                    {
-                        var 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]);
-
-                        var 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.Dispose();
-                }
-                if (fileStream != null)
-                {
-                    fileStream.Dispose();
-                }
-            }
-        }
-
-        public void Initialize()
-        {
-            LoadStreamClips();
-
-            var clipTimes = new Dictionary<string, List<double>>();
-            foreach (var 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<double> { 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;
-
-            var 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:
-
-                    var videoFormat = (TSVideoFormat)
-                        (data[pos] >> 4);
-                    var frameRate = (TSFrameRate)
-                        (data[pos] & 0xF);
-                    var 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);
-
-                    var channelLayout = (TSChannelLayout)
-                        (audioFormat >> 4);
-                    var 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<double, TSStreamClip>());
-                }
-            }
-
-            TSStreamClip referenceClip = null;
-            if (StreamClips.Count > 0)
-            {
-                referenceClip = StreamClips[0];
-            }
-            foreach (var 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 (var clipStream
-                in referenceClip.StreamClipFile.Streams.Values)
-            {
-                if (!Streams.ContainsKey(clipStream.PID))
-                {
-                    var 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))
-                {
-                    var stream = referenceClip.StreamFile.Streams[4114].Clone();
-                    Streams[4114] = stream;
-                    if (stream.IsVideoStream)
-                    {
-                        VideoStreams.Add((TSVideoStream)stream);
-                    }
-                }
-
-                foreach (var clipStream
-                    in referenceClip.StreamFile.Streams.Values)
-                {
-                    if (Streams.ContainsKey(clipStream.PID))
-                    {
-                        var 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)
-                        {
-                            var audioStream = (TSAudioStream)stream;
-                            var 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<ushort, TSStream>());
-            }
-
-            if (!BDInfoSettings.KeepStreamOrder)
-            {
-                VideoStreams.Sort(CompareVideoStreams);
-            }
-            foreach (TSStream stream in VideoStreams)
-            {
-                SortedStreams.Add(stream);
-                for (int i = 0; i < AngleCount; i++)
-                {
-                    var 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 (var clip in StreamClips)
-            {
-                clip.PayloadBytes = 0;
-                clip.PacketCount = 0;
-                clip.PacketSeconds = 0;
-
-                if (clip.StreamFile != null)
-                {
-                    foreach (var 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 (var 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 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 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 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 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 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 = Encoding.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++];
-        }
-    }
-}

+ 0 - 780
BDInfo/TSStream.cs

@@ -1,780 +0,0 @@
-//============================================================================
-// 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;
-
-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()
-        {
-            var 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<TSDescriptor> 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 => PacketCount * 192;
-
-        private string _LanguageCode;
-        public string LanguageCode
-        {
-            get => _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 => "";
-
-        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<TSDescriptor>();
-                foreach (var 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 => _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 => _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()
-        {
-            var 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()
-        {
-            var 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()
-        {
-            var stream = new TSGraphicsStream();
-            CopyTo(stream);
-            return stream;
-        }
-    }
-
-    public class TSTextStream : TSStream
-    {
-        public TSTextStream()
-        {
-            IsVBR = true;
-            IsInitialized = true;
-        }
-
-        public override TSStream Clone()
-        {
-            var stream = new TSTextStream();
-            CopyTo(stream);
-            return stream;
-        }
-    }
-}

+ 0 - 130
BDInfo/TSStreamBuffer.cs

@@ -1,130 +0,0 @@
-//============================================================================
-// 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.Specialized;
-using System.IO;
-
-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 => (long)BufferLength;
-
-        public long Position => 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;
-            }
-            var 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;
-        }
-    }
-}

+ 0 - 107
BDInfo/TSStreamClip.cs

@@ -1,107 +0,0 @@
-//============================================================================
-// 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;
-
-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<double> Chapters = new List<double>();
-
-        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 => 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 (var stream1 in StreamFile.Streams.Values)
-            {
-                if (clip.StreamFile.Streams.ContainsKey(stream1.PID))
-                {
-                    var stream2 = clip.StreamFile.Streams[stream1.PID];
-                    if (stream1.StreamType != stream2.StreamType)
-                    {
-                        return false;
-                    }
-                }
-            }
-            return true;
-        }
-    }
-}

+ 0 - 244
BDInfo/TSStreamClipFile.cs

@@ -1,244 +0,0 @@
-//============================================================================
-// 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.IO;
-using System.Text;
-using MediaBrowser.Model.IO;
-
-namespace BDInfo
-{
-    public class TSStreamClipFile
-    {
-        public FileSystemMetadata FileInfo = null;
-        public string FileType = null;
-        public bool IsValid = false;
-        public string Name = null;
-
-        public Dictionary<ushort, TSStream> Streams =
-            new Dictionary<ushort, TSStream>();
-
-        public TSStreamClipFile(FileSystemMetadata fileInfo)
-        {
-            FileInfo = fileInfo;
-            Name = fileInfo.Name.ToUpper();
-        }
-
-        public void Scan()
-        {
-            Stream 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 = Encoding.ASCII.GetString(fileType, 0, fileType.Length);
-                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;
-
-                    var 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:
-                            {
-                                var videoFormat = (TSVideoFormat)
-                                    (clipData[streamOffset + 2] >> 4);
-                                var frameRate = (TSFrameRate)
-                                    (clipData[streamOffset + 2] & 0xF);
-                                var 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 = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
-
-                                var channelLayout = (TSChannelLayout)
-                                    (clipData[streamOffset + 2] >> 4);
-                                var 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 = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
-
-                                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 = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length);
-#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.Dispose();
-                if (fileStream != null) fileStream.Dispose();
-            }
-        }
-    }
-}

+ 0 - 1555
BDInfo/TSStreamFile.cs

@@ -1,1555 +0,0 @@
-//============================================================================
-// 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.IO;
-using MediaBrowser.Model.IO;
-
-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<TSDescriptor> PMTProgramDescriptors = new List<TSDescriptor>();
-        public ushort PMTPID = 0xFFFF;
-        public Dictionary<ushort, byte[]> PMT = new Dictionary<ushort, byte[]>();
-        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 FileSystemMetadata FileInfo = null;
-        public string Name = null;
-        public long Size = 0;
-        public double Length = 0;
-
-        public TSInterleavedFile InterleavedFile = null;
-
-        private Dictionary<ushort, TSStreamState> StreamStates =
-            new Dictionary<ushort, TSStreamState>();
-
-        public Dictionary<ushort, TSStream> Streams =
-            new Dictionary<ushort, TSStream>();
-
-        public Dictionary<ushort, List<TSStreamDiagnostics>> StreamDiagnostics =
-            new Dictionary<ushort, List<TSStreamDiagnostics>>();
-
-        private List<TSPlaylistFile> Playlists = null;
-
-        private readonly IFileSystem _fileSystem;
-
-        public TSStreamFile(FileSystemMetadata fileInfo, IFileSystem fileSystem)
-        {
-            FileInfo = fileInfo;
-            _fileSystem = fileSystem;
-            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 (var 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 (var playlist in Playlists)
-            {
-                double packetSeconds = 0;
-                foreach (var clip in playlist.StreamClips)
-                {
-                    if (clip.AngleIndex == 0)
-                    {
-                        packetSeconds += clip.PacketSeconds;
-                    }
-                }
-                if (packetSeconds > 0)
-                {
-                    foreach (var 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;
-
-            var streamState = StreamStates[PID];
-            double streamTime = (double)PTS / 90000;
-            double streamInterval = (double)PTSDiff / 90000;
-            double streamOffset = streamTime + streamInterval;
-
-            foreach (var playlist in Playlists)
-            {
-                foreach (var 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;
-                        }
-
-                        var playlistStreams = playlist.Streams;
-                        if (clip.AngleIndex > 0 &&
-                            clip.AngleIndex < playlist.AngleStreams.Count + 1)
-                        {
-                            playlistStreams = playlist.AngleStreams[clip.AngleIndex - 1];
-                        }
-                        if (playlistStreams.ContainsKey(PID))
-                        {
-                            var 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))
-            {
-                var stream = Streams[PID];
-                stream.PayloadBytes += streamState.WindowBytes;
-                stream.PacketCount += streamState.WindowPackets;
-
-                if (stream.IsVideoStream)
-                {
-                    var 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<TSPlaylistFile> playlists, bool isFullScan)
-        {
-            if (playlists == null || playlists.Count == 0)
-            {
-                return;
-            }
-
-            Playlists = playlists;
-            int dataSize = 16384;
-            Stream fileStream = null;
-            try
-            {
-                string fileName;
-                if (BDInfoSettings.EnableSSIF &&
-                    InterleavedFile != null)
-                {
-                    fileName = InterleavedFile.FileInfo.FullName;
-                }
-                else
-                {
-                    fileName = FileInfo.FullName;
-                }
-                fileStream = _fileSystem.GetFileStream(
-                    fileName,
-                    FileOpenMode.Open,
-                    FileAccessMode.Read,
-                    FileShareMode.Read,
-                    false);
-
-                Size = 0;
-                Length = 0;
-
-                Streams.Clear();
-                StreamStates.Clear();
-                StreamDiagnostics.Clear();
-
-                var 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))
-                                                {
-                                                    var streamDescriptors =
-                                                        new List<TSDescriptor>();
-
-                                                    /*
-                                                     * 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
-                                        {
-                                            // 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;
-
-                                        var 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)
-                        {
-                            var stream = parser.Stream;
-                            var 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 (var 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.Dispose();
-                }
-            }
-        }
-
-        private TSStream CreateStream(
-            ushort streamPID,
-            byte streamType,
-            List<TSDescriptor> 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<TSStreamDiagnostics>();
-            }
-
-            return stream;
-        }
-    }
-}

+ 1 - 0
CONTRIBUTORS.md

@@ -31,6 +31,7 @@
  - [fhriley](https://github.com/fhriley)
  - [nevado](https://github.com/nevado)
  - [mark-monteiro](https://github.com/mark-monteiro)
+ - [ullmie02](https://github.com/ullmie02)
 
 # Emby Contributors
 

+ 1 - 1
Dockerfile

@@ -1,4 +1,4 @@
-ARG DOTNET_VERSION=3.0
+ARG DOTNET_VERSION=3.1
 ARG FFMPEG_VERSION=latest
 
 FROM node:alpine as web-builder

+ 1 - 1
Dockerfile.arm

@@ -1,6 +1,6 @@
 # Requires binfm_misc registration
 # https://github.com/multiarch/qemu-user-static#binfmt_misc-register
-ARG DOTNET_VERSION=3.0
+ARG DOTNET_VERSION=3.1
 
 
 FROM node:alpine as web-builder

+ 1 - 1
Dockerfile.arm64

@@ -1,6 +1,6 @@
 # Requires binfm_misc registration
 # https://github.com/multiarch/qemu-user-static#binfmt_misc-register
-ARG DOTNET_VERSION=3.0
+ARG DOTNET_VERSION=3.1
 
 
 FROM node:alpine as web-builder

+ 12 - 24
Emby.Dlna/Eventing/EventManager.cs

@@ -29,25 +29,15 @@ namespace Emby.Dlna.Eventing
         {
             var subscription = GetSubscription(subscriptionId, false);
 
-            int timeoutSeconds;
+            subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
+            int timeoutSeconds = subscription.TimeoutSeconds;
+            subscription.SubscriptionTime = DateTime.UtcNow;
 
-            // Remove logging for now because some devices are sending this very frequently
-            // TODO re-enable with dlna debug logging setting
-            //_logger.LogDebug("Renewing event subscription for {0} with timeout of {1} to {2}",
-            //    subscription.NotificationType,
-            //    timeout,
-            //    subscription.CallbackUrl);
-
-            if (subscription != null)
-            {
-                subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
-                timeoutSeconds = subscription.TimeoutSeconds;
-                subscription.SubscriptionTime = DateTime.UtcNow;
-            }
-            else
-            {
-                timeoutSeconds = 300;
-            }
+            _logger.LogDebug(
+                "Renewing event subscription for {0} with timeout of {1} to {2}",
+                subscription.NotificationType,
+                timeoutSeconds,
+                subscription.CallbackUrl);
 
             return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds);
         }
@@ -57,12 +47,10 @@ namespace Emby.Dlna.Eventing
             var timeout = ParseTimeout(requestedTimeoutString) ?? 300;
             var id = "uuid:" + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
 
-            // Remove logging for now because some devices are sending this very frequently
-            // TODO re-enable with dlna debug logging setting
-            //_logger.LogDebug("Creating event subscription for {0} with timeout of {1} to {2}",
-            //    notificationType,
-            //    timeout,
-            //    callbackUrl);
+            _logger.LogDebug("Creating event subscription for {0} with timeout of {1} to {2}",
+                notificationType,
+                timeout,
+                callbackUrl);
 
             _subscriptions.TryAdd(id, new EventSubscription
             {

+ 3 - 0
Emby.Naming/Audio/AlbumParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Globalization;
 using System.IO;

+ 3 - 0
Emby.Naming/Audio/AudioFileParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.IO;
 using System.Linq;

+ 3 - 0
Emby.Naming/Audio/MultiPartResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.Audio
 {
     public class MultiPartResult

+ 3 - 0
Emby.Naming/AudioBook/AudioBookFilePathParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Globalization;
 using System.IO;

+ 3 - 0
Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.AudioBook
 {
     public class AudioBookFilePathParserResult

+ 3 - 0
Emby.Naming/AudioBook/AudioBookInfo.cs

@@ -7,6 +7,9 @@ namespace Emby.Naming.AudioBook
     /// </summary>
     public class AudioBookInfo
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="AudioBookInfo" /> class.
+        /// </summary>
         public AudioBookInfo()
         {
             Files = new List<AudioBookFileInfo>();

+ 3 - 0
Emby.Naming/AudioBook/AudioBookListResolver.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System.Collections.Generic;
 using System.Linq;
 using Emby.Naming.Common;

+ 3 - 0
Emby.Naming/AudioBook/AudioBookResolver.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.IO;
 using System.Linq;

+ 3 - 0
Emby.Naming/Common/EpisodeExpression.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Text.RegularExpressions;
 

+ 3 - 0
Emby.Naming/Common/MediaType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.Common
 {
     public enum MediaType

+ 3 - 0
Emby.Naming/Common/NamingOptions.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Linq;
 using System.Text.RegularExpressions;

+ 5 - 1
Emby.Naming/Emby.Naming.csproj

@@ -6,6 +6,10 @@
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
 
+  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+  </PropertyGroup>
+
   <ItemGroup>
     <Compile Include="..\SharedVersion.cs" />
   </ItemGroup>
@@ -21,7 +25,7 @@
     <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
   </PropertyGroup>
 
-  <!-- Code analysers-->
+  <!-- Code Analyzers-->
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
     <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7" PrivateAssets="All" />
     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />

+ 3 - 0
Emby.Naming/Subtitles/SubtitleInfo.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.Subtitles
 {
     public class SubtitleInfo

+ 3 - 0
Emby.Naming/Subtitles/SubtitleParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.IO;
 using System.Linq;

+ 3 - 0
Emby.Naming/TV/EpisodeInfo.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.TV
 {
     public class EpisodeInfo

+ 3 - 0
Emby.Naming/TV/EpisodePathParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Collections.Generic;
 using System.Globalization;

+ 3 - 0
Emby.Naming/TV/EpisodePathParserResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.TV
 {
     public class EpisodePathParserResult

+ 3 - 0
Emby.Naming/TV/EpisodeResolver.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.IO;
 using System.Linq;

+ 3 - 0
Emby.Naming/TV/SeasonPathParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Globalization;
 using System.IO;

+ 3 - 0
Emby.Naming/TV/SeasonPathParserResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.TV
 {
     public class SeasonPathParserResult

+ 3 - 0
Emby.Naming/Video/CleanDateTimeParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Globalization;
 using System.IO;

+ 5 - 0
Emby.Naming/Video/CleanDateTimeResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.Video
 {
     public class CleanDateTimeResult
@@ -7,11 +10,13 @@ namespace Emby.Naming.Video
         /// </summary>
         /// <value>The name.</value>
         public string Name { get; set; }
+
         /// <summary>
         /// Gets or sets the year.
         /// </summary>
         /// <value>The year.</value>
         public int? Year { get; set; }
+
         /// <summary>
         /// Gets or sets a value indicating whether this instance has changed.
         /// </summary>

+ 3 - 0
Emby.Naming/Video/CleanStringParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System.Collections.Generic;
 using System.Text.RegularExpressions;
 

+ 4 - 0
Emby.Naming/Video/CleanStringResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.Video
 {
     public class CleanStringResult
@@ -7,6 +10,7 @@ namespace Emby.Naming.Video
         /// </summary>
         /// <value>The name.</value>
         public string Name { get; set; }
+
         /// <summary>
         /// Gets or sets a value indicating whether this instance has changed.
         /// </summary>

+ 3 - 0
Emby.Naming/Video/ExtraResolver.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.IO;
 using System.Linq;

+ 3 - 0
Emby.Naming/Video/ExtraResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using MediaBrowser.Model.Entities;
 
 namespace Emby.Naming.Video

+ 6 - 2
Emby.Naming/Video/ExtraRule.cs

@@ -1,4 +1,8 @@
-using Emby.Naming.Common;
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
+using MediaBrowser.Model.Entities;
+using MediaType = Emby.Naming.Common.MediaType;
 
 namespace Emby.Naming.Video
 {
@@ -14,7 +18,7 @@ namespace Emby.Naming.Video
         /// Gets or sets the type of the extra.
         /// </summary>
         /// <value>The type of the extra.</value>
-        public MediaBrowser.Model.Entities.ExtraType ExtraType { get; set; }
+        public ExtraType ExtraType { get; set; }
 
         /// <summary>
         /// Gets or sets the type of the rule.

+ 5 - 0
Emby.Naming/Video/ExtraRuleType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.Video
 {
     public enum ExtraRuleType
@@ -6,10 +9,12 @@ namespace Emby.Naming.Video
         /// The suffix
         /// </summary>
         Suffix = 0,
+
         /// <summary>
         /// The filename
         /// </summary>
         Filename = 1,
+
         /// <summary>
         /// The regex
         /// </summary>

+ 9 - 4
Emby.Naming/Video/FileStack.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -6,15 +9,17 @@ namespace Emby.Naming.Video
 {
     public class FileStack
     {
-        public string Name { get; set; }
-        public List<string> Files { get; set; }
-        public bool IsDirectoryStack { get; set; }
-
         public FileStack()
         {
             Files = new List<string>();
         }
 
+        public string Name { get; set; }
+
+        public List<string> Files { get; set; }
+
+        public bool IsDirectoryStack { get; set; }
+
         public bool ContainsFile(string file, bool isDirectory)
         {
             if (IsDirectoryStack == isDirectory)

+ 3 - 0
Emby.Naming/Video/FlagParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.IO;
 using Emby.Naming.Common;

+ 3 - 0
Emby.Naming/Video/Format3DParser.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Linq;
 using Emby.Naming.Common;

+ 3 - 0
Emby.Naming/Video/Format3DResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System.Collections.Generic;
 
 namespace Emby.Naming.Video

+ 4 - 0
Emby.Naming/Video/Format3DRule.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.Video
 {
     public class Format3DRule
@@ -7,6 +10,7 @@ namespace Emby.Naming.Video
         /// </summary>
         /// <value>The token.</value>
         public string Token { get; set; }
+
         /// <summary>
         /// Gets or sets the preceeding token.
         /// </summary>

+ 3 - 0
Emby.Naming/Video/StackResolver.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Collections.Generic;
 using System.IO;

+ 3 - 0
Emby.Naming/Video/StackResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System.Collections.Generic;
 
 namespace Emby.Naming.Video

+ 3 - 0
Emby.Naming/Video/StubResolver.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.IO;
 using System.Linq;

+ 3 - 0
Emby.Naming/Video/StubResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.Video
 {
     public struct StubResult

+ 3 - 0
Emby.Naming/Video/StubTypeRule.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace Emby.Naming.Video
 {
     public class StubTypeRule

+ 1 - 0
Emby.Naming/Video/VideoFileInfo.cs

@@ -79,6 +79,7 @@ namespace Emby.Naming.Video
         /// <value>The file name without extension.</value>
         public string FileNameWithoutExtension => !IsDirectory ? System.IO.Path.GetFileNameWithoutExtension(Path) : System.IO.Path.GetFileName(Path);
 
+        /// <inheritdoc />
         public override string ToString()
         {
             // Makes debugging easier

+ 10 - 7
Emby.Naming/Video/VideoInfo.cs

@@ -7,6 +7,16 @@ namespace Emby.Naming.Video
     /// </summary>
     public class VideoInfo
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="VideoInfo" /> class.
+        /// </summary>
+        public VideoInfo()
+        {
+            Files = new List<VideoFileInfo>();
+            Extras = new List<VideoFileInfo>();
+            AlternateVersions = new List<VideoFileInfo>();
+        }
+
         /// <summary>
         /// Gets or sets the name.
         /// </summary>
@@ -36,12 +46,5 @@ namespace Emby.Naming.Video
         /// </summary>
         /// <value>The alternate versions.</value>
         public List<VideoFileInfo> AlternateVersions { get; set; }
-
-        public VideoInfo()
-        {
-            Files = new List<VideoFileInfo>();
-            Extras = new List<VideoFileInfo>();
-            AlternateVersions = new List<VideoFileInfo>();
-        }
     }
 }

+ 3 - 0
Emby.Naming/Video/VideoListResolver.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Collections.Generic;
 using System.IO;

+ 3 - 0
Emby.Naming/Video/VideoResolver.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.IO;
 using System.Linq;

+ 5 - 1
Emby.Photos/Emby.Photos.csproj

@@ -1,5 +1,9 @@
 <Project Sdk="Microsoft.NET.Sdk">
 
+  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+  </PropertyGroup>
+
   <ItemGroup>
     <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
     <ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
@@ -20,7 +24,7 @@
     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
 
-  <!-- Code analysers-->
+  <!-- Code Analyzers-->
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
     <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7" />
     <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />

+ 45 - 23
Emby.Server.Implementations/ApplicationHost.cs

@@ -103,14 +103,11 @@ using MediaBrowser.Providers.Subtitles;
 using MediaBrowser.Providers.TV.TheTVDB;
 using MediaBrowser.WebDashboard.Api;
 using MediaBrowser.XbmcMetadata.Providers;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http.Extensions;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
-using Microsoft.OpenApi.Models;
 using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
 
 namespace Emby.Server.Implementations
@@ -764,9 +761,8 @@ namespace Emby.Server.Implementations
             LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
             serviceCollection.AddSingleton(LibraryManager);
 
-            // TODO wtaylor: investigate use of second music manager
             var musicManager = new MusicManager(LibraryManager);
-            serviceCollection.AddSingleton<IMusicManager>(new MusicManager(LibraryManager));
+            serviceCollection.AddSingleton<IMusicManager>(musicManager);
 
             LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager);
             serviceCollection.AddSingleton(LibraryMonitor);
@@ -841,16 +837,14 @@ namespace Emby.Server.Implementations
             serviceCollection.AddSingleton(ChapterManager);
 
             MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
-                LoggerFactory,
-                JsonSerializer,
-                StartupOptions.FFmpegPath,
+                LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(),
                 ServerConfigurationManager,
                 FileSystemManager,
-                () => SubtitleEncoder,
-                () => MediaSourceManager,
                 ProcessFactory,
-                5000,
-                LocalizationManager);
+                LocalizationManager,
+                () => SubtitleEncoder,
+                _configuration,
+                StartupOptions.FFmpegPath);
             serviceCollection.AddSingleton(MediaEncoder);
 
             EncodingManager = new MediaEncoder.EncodingManager(FileSystemManager, LoggerFactory, MediaEncoder, ChapterManager, LibraryManager);
@@ -867,10 +861,21 @@ namespace Emby.Server.Implementations
             AuthService = new AuthService(LoggerFactory.CreateLogger<AuthService>(), authContext, ServerConfigurationManager, SessionManager, NetworkManager);
             serviceCollection.AddSingleton(AuthService);
 
-            SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory);
+            SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(
+                LibraryManager,
+                LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>(),
+                ApplicationPaths,
+                FileSystemManager,
+                MediaEncoder,
+                HttpClient,
+                MediaSourceManager,
+                ProcessFactory);
             serviceCollection.AddSingleton(SubtitleEncoder);
 
             serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager));
+            serviceCollection.AddSingleton<EncodingHelper>();
+
+            serviceCollection.AddSingleton(typeof(IAttachmentExtractor), typeof(MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor));
 
             _displayPreferencesRepository.Initialize();
 
@@ -1472,7 +1477,7 @@ namespace Emby.Server.Implementations
         /// </summary>
         /// <param name="address">The IPv6 address.</param>
         /// <returns>The IPv6 address without the scope id.</returns>
-        private string RemoveScopeId(string address)
+        private ReadOnlySpan<char> RemoveScopeId(ReadOnlySpan<char> address)
         {
             var index = address.IndexOf('%');
             if (index == -1)
@@ -1480,33 +1485,50 @@ namespace Emby.Server.Implementations
                 return address;
             }
 
-            return address.Substring(0, index);
+            return address.Slice(0, index);
         }
 
+        /// <inheritdoc />
         public string GetLocalApiUrl(IPAddress ipAddress)
         {
             if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
             {
                 var str = RemoveScopeId(ipAddress.ToString());
+                Span<char> span = new char[str.Length + 2];
+                span[0] = '[';
+                str.CopyTo(span.Slice(1));
+                span[^1] = ']';
 
-                return GetLocalApiUrl("[" + str + "]");
+                return GetLocalApiUrl(span);
             }
 
             return GetLocalApiUrl(ipAddress.ToString());
         }
 
-        public string GetLocalApiUrl(string host)
+        /// <inheritdoc />
+        public string GetLocalApiUrl(ReadOnlySpan<char> host)
         {
+            var url = new StringBuilder(64);
             if (EnableHttps)
             {
-                return string.Format("https://{0}:{1}",
-                    host,
-                    HttpsPort.ToString(CultureInfo.InvariantCulture));
+                url.Append("https://");
+            }
+            else
+            {
+                url.Append("http://");
+            }
+
+            url.Append(host)
+                .Append(':')
+                .Append(HttpPort);
+
+            string baseUrl = ServerConfigurationManager.Configuration.BaseUrl;
+            if (baseUrl.Length != 0)
+            {
+                url.Append('/').Append(baseUrl);
             }
 
-            return string.Format("http://{0}:{1}",
-                    host,
-                    HttpPort.ToString(CultureInfo.InvariantCulture));
+            return url.ToString();
         }
 
         public Task<List<IPAddress>> GetLocalIpAddresses(CancellationToken cancellationToken)

+ 10 - 38
Emby.Server.Implementations/Collections/CollectionManager.cs

@@ -31,11 +31,7 @@ namespace Emby.Server.Implementations.Collections
         private readonly ILogger _logger;
         private readonly IProviderManager _providerManager;
         private readonly ILocalizationManager _localizationManager;
-        private IApplicationPaths _appPaths;
-
-        public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
-        public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
-        public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
+        private readonly IApplicationPaths _appPaths;
 
         public CollectionManager(
             ILibraryManager libraryManager,
@@ -55,6 +51,10 @@ namespace Emby.Server.Implementations.Collections
             _appPaths = appPaths;
         }
 
+        public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
+        public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
+        public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
+
         private IEnumerable<Folder> FindFolders(string path)
         {
             return _libraryManager
@@ -341,11 +341,11 @@ namespace Emby.Server.Implementations.Collections
         }
     }
 
-    public class CollectionManagerEntryPoint : IServerEntryPoint
+    public sealed class CollectionManagerEntryPoint : IServerEntryPoint
     {
         private readonly CollectionManager _collectionManager;
         private readonly IServerConfigurationManager _config;
-        private ILogger _logger;
+        private readonly ILogger _logger;
 
         public CollectionManagerEntryPoint(ICollectionManager collectionManager, IServerConfigurationManager config, ILogger logger)
         {
@@ -354,6 +354,7 @@ namespace Emby.Server.Implementations.Collections
             _logger = logger;
         }
 
+        /// <inheritdoc />
         public async Task RunAsync()
         {
             if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted)
@@ -377,39 +378,10 @@ namespace Emby.Server.Implementations.Collections
             }
         }
 
-        #region IDisposable Support
-        private bool disposedValue = false; // To detect redundant calls
-
-        protected virtual void Dispose(bool disposing)
-        {
-            if (!disposedValue)
-            {
-                if (disposing)
-                {
-                    // TODO: dispose managed state (managed objects).
-                }
-
-                // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
-                // TODO: set large fields to null.
-
-                disposedValue = true;
-            }
-        }
-
-        // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
-        // ~CollectionManagerEntryPoint() {
-        //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
-        //   Dispose(false);
-        // }
-
-        // This code added to correctly implement the disposable pattern.
+        /// <inheritdoc />
         public void Dispose()
         {
-            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
-            Dispose(true);
-            // TODO: uncomment the following line if the finalizer is overridden above.
-            // GC.SuppressFinalize(this);
+            // Nothing to dispose
         }
-        #endregion
     }
 }

+ 5 - 2
Emby.Server.Implementations/ConfigurationOptions.cs

@@ -1,13 +1,16 @@
 using System.Collections.Generic;
+using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
 
 namespace Emby.Server.Implementations
 {
     public static class ConfigurationOptions
     {
-        public static readonly Dictionary<string, string> Configuration = new Dictionary<string, string>
+        public static Dictionary<string, string> Configuration => new Dictionary<string, string>
         {
             { "HttpListenerHost:DefaultRedirectPath", "web/index.html" },
-            { "MusicBrainz:BaseUrl", "https://www.musicbrainz.org" }
+            { "MusicBrainz:BaseUrl", "https://www.musicbrainz.org" },
+            { FfmpegProbeSizeKey, "1G" },
+            { FfmpegAnalyzeDurationKey, "200M" }
         };
     }
 }

+ 215 - 4
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -49,6 +49,21 @@ namespace Emby.Server.Implementations.Data
         private readonly TypeMapper _typeMapper;
         private readonly JsonSerializerOptions _jsonOptions;
 
+        static SqliteItemRepository()
+        {
+            var queryPrefixText = new StringBuilder();
+            queryPrefixText.Append("insert into mediaattachments (");
+            foreach (var column in _mediaAttachmentSaveColumns)
+            {
+                queryPrefixText.Append(column)
+                    .Append(',');
+            }
+
+            queryPrefixText.Length -= 1;
+            queryPrefixText.Append(") values ");
+            _mediaAttachmentInsertPrefix = queryPrefixText.ToString();
+        }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
         /// </summary>
@@ -92,6 +107,8 @@ namespace Emby.Server.Implementations.Data
         {
             const string CreateMediaStreamsTableCommand
                     = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, ColorPrimaries TEXT NULL, ColorSpace TEXT NULL, ColorTransfer TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
+            const string CreateMediaAttachmentsTableCommand
+                    = "create table if not exists mediaattachments (ItemId GUID, AttachmentIndex INT, Codec TEXT, CodecTag TEXT NULL, Comment TEXT NULL, Filename TEXT NULL, MIMEType TEXT NULL, PRIMARY KEY (ItemId, AttachmentIndex))";
 
             string[] queries =
             {
@@ -114,6 +131,7 @@ namespace Emby.Server.Implementations.Data
                 "create table if not exists " + ChaptersTableName + " (ItemId GUID, ChapterIndex INT NOT NULL, StartPositionTicks BIGINT NOT NULL, Name TEXT, ImagePath TEXT, PRIMARY KEY (ItemId, ChapterIndex))",
 
                 CreateMediaStreamsTableCommand,
+                CreateMediaAttachmentsTableCommand,
 
                 "pragma shrink_memory"
             };
@@ -421,6 +439,19 @@ namespace Emby.Server.Implementations.Data
             "ColorTransfer"
         };
 
+        private static readonly string[] _mediaAttachmentSaveColumns =
+        {
+            "ItemId",
+            "AttachmentIndex",
+            "Codec",
+            "CodecTag",
+            "Comment",
+            "Filename",
+            "MIMEType"
+        };
+
+        private static readonly string _mediaAttachmentInsertPrefix;
+
         private static string GetSaveItemCommandText()
         {
             var saveColumns = new []
@@ -4593,10 +4624,20 @@ namespace Emby.Server.Implementations.Data
 
             if (query.ExcludeInheritedTags.Length > 0)
             {
-                var tagValues = query.ExcludeInheritedTags.Select(i => "'" + GetCleanValue(i) + "'");
-                var tagValuesList = string.Join(",", tagValues);
-
-                whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + tagValuesList + ")) is null)");
+                var paramName = "@ExcludeInheritedTags";
+                if (statement == null)
+                {
+                    int index = 0;
+                    string excludedTags = string.Join(",", query.ExcludeInheritedTags.Select(t => paramName + index++));
+                    whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + excludedTags + ")) is null)");
+                }
+                else
+                {
+                    for (int index = 0; index < query.ExcludeInheritedTags.Length; index++)
+                    {
+                        statement.TryBind(paramName + index, GetCleanValue(query.ExcludeInheritedTags[index]));
+                    }
+                }
             }
 
             if (query.SeriesStatuses.Length > 0)
@@ -6126,5 +6167,175 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 
             return item;
         }
+
+        public List<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query)
+        {
+            CheckDisposed();
+
+            if (query == null)
+            {
+                throw new ArgumentNullException(nameof(query));
+            }
+
+            var cmdText = "select "
+                        + string.Join(",", _mediaAttachmentSaveColumns)
+                        + " from mediaattachments where"
+                        + " ItemId=@ItemId";
+
+            if (query.Index.HasValue)
+            {
+                cmdText += " AND AttachmentIndex=@AttachmentIndex";
+            }
+
+            cmdText += " order by AttachmentIndex ASC";
+
+            var list = new List<MediaAttachment>();
+            using (var connection = GetConnection(true))
+            using (var statement = PrepareStatement(connection, cmdText))
+            {
+                statement.TryBind("@ItemId", query.ItemId.ToByteArray());
+
+                if (query.Index.HasValue)
+                {
+                    statement.TryBind("@AttachmentIndex", query.Index.Value);
+                }
+
+                foreach (var row in statement.ExecuteQuery())
+                {
+                    list.Add(GetMediaAttachment(row));
+                }
+            }
+
+            return list;
+        }
+
+        public void SaveMediaAttachments(
+            Guid id,
+            IReadOnlyList<MediaAttachment> attachments,
+            CancellationToken cancellationToken)
+        {
+            CheckDisposed();
+            if (id == Guid.Empty)
+            {
+                throw new ArgumentException(nameof(id));
+            }
+
+            if (attachments == null)
+            {
+                throw new ArgumentNullException(nameof(attachments));
+            }
+
+            cancellationToken.ThrowIfCancellationRequested();
+
+            using (var connection = GetConnection())
+            {
+                connection.RunInTransaction(db =>
+                {
+                    var itemIdBlob = id.ToByteArray();
+
+                    db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob);
+
+                    InsertMediaAttachments(itemIdBlob, attachments, db, cancellationToken);
+
+                }, TransactionMode);
+            }
+        }
+
+        private void InsertMediaAttachments(
+            byte[] idBlob,
+            IReadOnlyList<MediaAttachment> attachments,
+            IDatabaseConnection db,
+            CancellationToken cancellationToken)
+        {
+            const int InsertAtOnce = 10;
+
+            for (var startIndex = 0; startIndex < attachments.Count; startIndex += InsertAtOnce)
+            {
+                var insertText = new StringBuilder(_mediaAttachmentInsertPrefix);
+
+                var endIndex = Math.Min(attachments.Count, startIndex + InsertAtOnce);
+
+                for (var i = startIndex; i < endIndex; i++)
+                {
+                    var index = i.ToString(CultureInfo.InvariantCulture);
+                    insertText.Append("(@ItemId, ");
+
+                    foreach (var column in _mediaAttachmentSaveColumns.Skip(1))
+                    {
+                        insertText.Append("@" + column + index + ",");
+                    }
+
+                    insertText.Length -= 1;
+
+                    insertText.Append("),");
+                }
+
+                insertText.Length--;
+
+                cancellationToken.ThrowIfCancellationRequested();
+
+                using (var statement = PrepareStatement(db, insertText.ToString()))
+                {
+                    statement.TryBind("@ItemId", idBlob);
+
+                    for (var i = startIndex; i < endIndex; i++)
+                    {
+                        var index = i.ToString(CultureInfo.InvariantCulture);
+
+                        var attachment = attachments[i];
+
+                        statement.TryBind("@AttachmentIndex" + index, attachment.Index);
+                        statement.TryBind("@Codec" + index, attachment.Codec);
+                        statement.TryBind("@CodecTag" + index, attachment.CodecTag);
+                        statement.TryBind("@Comment" + index, attachment.Comment);
+                        statement.TryBind("@FileName" + index, attachment.FileName);
+                        statement.TryBind("@MimeType" + index, attachment.MimeType);
+                    }
+
+                    statement.Reset();
+                    statement.MoveNext();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the attachment.
+        /// </summary>
+        /// <param name="reader">The reader.</param>
+        /// <returns>MediaAttachment</returns>
+        private MediaAttachment GetMediaAttachment(IReadOnlyList<IResultSetValue> reader)
+        {
+            var item = new MediaAttachment
+            {
+                Index = reader[1].ToInt()
+            };
+
+            if (reader[2].SQLiteType != SQLiteType.Null)
+            {
+                item.Codec = reader[2].ToString();
+            }
+
+            if (reader[2].SQLiteType != SQLiteType.Null)
+            {
+                item.CodecTag = reader[3].ToString();
+            }
+
+            if (reader[4].SQLiteType != SQLiteType.Null)
+            {
+                item.Comment = reader[4].ToString();
+            }
+
+            if (reader[6].SQLiteType != SQLiteType.Null)
+            {
+                item.FileName = reader[5].ToString();
+            }
+
+            if (reader[6].SQLiteType != SQLiteType.Null)
+            {
+                item.MimeType = reader[6].ToString();
+            }
+
+            return item;
+        }
     }
 }

+ 1 - 2
Emby.Server.Implementations/Emby.Server.Implementations.csproj

@@ -29,7 +29,6 @@
     <PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
     <PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
-    <PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.1" />
     <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.1" />
     <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.0.1" />
     <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.0.1" />
@@ -50,7 +49,7 @@
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
 
-  <!-- Code analysers-->
+  <!-- Code Analyzers-->
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
     <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7" />
     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" />

+ 1 - 1
Emby.Server.Implementations/IO/ManagedFileSystem.cs

@@ -109,7 +109,7 @@ namespace Emby.Server.Implementations.IO
             }
             try
             {
-                return Path.Combine(Path.GetFullPath(folderPath), filePath);
+                return Path.GetFullPath(Path.Combine(folderPath, filePath));
             }
             catch (ArgumentException)
             {

+ 2 - 2
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -392,9 +392,9 @@ namespace Emby.Server.Implementations.Library
                 // Add this flag to GetDeletePaths if required in the future
                 var isRequiredForDelete = true;
 
-                foreach (var fileSystemInfo in item.GetDeletePaths().ToList())
+                foreach (var fileSystemInfo in item.GetDeletePaths())
                 {
-                    if (File.Exists(fileSystemInfo.FullName))
+                    if (Directory.Exists(fileSystemInfo.FullName) || File.Exists(fileSystemInfo.FullName))
                     {
                         try
                         {

+ 15 - 0
Emby.Server.Implementations/Library/MediaSourceManager.cs

@@ -130,6 +130,21 @@ namespace Emby.Server.Implementations.Library
             return streams;
         }
 
+        /// <inheritdoc />
+        public List<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query)
+        {
+            return _itemRepo.GetMediaAttachments(query);
+        }
+
+        /// <inheritdoc />
+        public List<MediaAttachment> GetMediaAttachments(Guid itemId)
+        {
+            return GetMediaAttachments(new MediaAttachmentQuery
+            {
+                ItemId = itemId
+            });
+        }
+
         public async Task<List<MediaSourceInfo>> GetPlayackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken)
         {
             var mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user);

+ 31 - 57
Emby.Server.Implementations/Library/UserManager.cs

@@ -42,13 +42,13 @@ namespace Emby.Server.Implementations.Library
     /// </summary>
     public class UserManager : IUserManager
     {
+        private readonly object _policySyncLock = new object();
+        private readonly object _configSyncLock = new object();
         /// <summary>
         /// The logger.
         /// </summary>
         private readonly ILogger _logger;
 
-        private readonly object _policySyncLock = new object();
-
         /// <summary>
         /// Gets the active user repository.
         /// </summary>
@@ -255,7 +255,12 @@ namespace Emby.Server.Implementations.Library
             return builder.ToString();
         }
 
-        public async Task<User> AuthenticateUser(string username, string password, string hashedPassword, string remoteEndPoint, bool isUserSession)
+        public async Task<User> AuthenticateUser(
+            string username,
+            string password,
+            string hashedPassword,
+            string remoteEndPoint,
+            bool isUserSession)
         {
             if (string.IsNullOrWhiteSpace(username))
             {
@@ -392,7 +397,7 @@ namespace Emby.Server.Implementations.Library
             if (providers.Length == 0)
             {
                 // Assign the user to the InvalidAuthProvider since no configured auth provider was valid/found
-                _logger.LogWarning("User {UserName} was found with invalid/missing Authentication Provider {AuthenticationProviderId}. Assigning user to InvalidAuthProvider until this is corrected", user.Name, user.Policy.AuthenticationProviderId);
+                _logger.LogWarning("User {UserName} was found with invalid/missing Authentication Provider {AuthenticationProviderId}. Assigning user to InvalidAuthProvider until this is corrected", user?.Name, user?.Policy.AuthenticationProviderId);
                 providers = new IAuthenticationProvider[] { _invalidAuthProvider };
             }
 
@@ -472,7 +477,7 @@ namespace Emby.Server.Implementations.Library
 
             if (!success
                 && _networkManager.IsInLocalNetwork(remoteEndPoint)
-                && user.Configuration.EnableLocalPassword
+                && user?.Configuration.EnableLocalPassword == true
                 && !string.IsNullOrEmpty(user.EasyPassword))
             {
                 // Check easy password
@@ -754,13 +759,10 @@ namespace Emby.Server.Implementations.Library
             return user;
         }
 
-        /// <summary>
-        /// Deletes the user.
-        /// </summary>
-        /// <param name="user">The user.</param>
-        /// <returns>Task.</returns>
-        /// <exception cref="ArgumentNullException">user</exception>
-        /// <exception cref="ArgumentException"></exception>
+        /// <inheritdoc />
+        /// <exception cref="ArgumentNullException">The <c>user</c> is <c>null</c>.</exception>
+        /// <exception cref="ArgumentException">The <c>user</c> doesn't exist, or is the last administrator.</exception>
+        /// <exception cref="InvalidOperationException">The <c>user</c> can't be deleted; there are no other users.</exception>
         public void DeleteUser(User user)
         {
             if (user == null)
@@ -779,7 +781,7 @@ namespace Emby.Server.Implementations.Library
 
             if (_users.Count == 1)
             {
-                throw new ArgumentException(string.Format(
+                throw new InvalidOperationException(string.Format(
                     CultureInfo.InvariantCulture,
                     "The user '{0}' cannot be deleted because there must be at least one user in the system.",
                     user.Name));
@@ -800,17 +802,20 @@ namespace Emby.Server.Implementations.Library
 
             _userRepository.DeleteUser(user);
 
-            try
-            {
-                _fileSystem.DeleteFile(configPath);
-            }
-            catch (IOException ex)
+            // Delete user config dir
+            lock (_configSyncLock)
+            lock (_policySyncLock)
             {
-                _logger.LogError(ex, "Error deleting file {path}", configPath);
+                try
+                {
+                    Directory.Delete(user.ConfigurationDirectoryPath, true);
+                }
+                catch (IOException ex)
+                {
+                    _logger.LogError(ex, "Error deleting user config dir: {Path}", user.ConfigurationDirectoryPath);
+                }
             }
 
-            DeleteUserPolicy(user);
-
             _users.TryRemove(user.Id, out _);
 
             OnUserDeleted(user);
@@ -918,10 +923,9 @@ namespace Emby.Server.Implementations.Library
         public UserPolicy GetUserPolicy(User user)
         {
             var path = GetPolicyFilePath(user);
-
             if (!File.Exists(path))
             {
-                return GetDefaultPolicy(user);
+                return GetDefaultPolicy();
             }
 
             try
@@ -931,19 +935,15 @@ namespace Emby.Server.Implementations.Library
                     return (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), path);
                 }
             }
-            catch (IOException)
-            {
-                return GetDefaultPolicy(user);
-            }
             catch (Exception ex)
             {
-                _logger.LogError(ex, "Error reading policy file: {path}", path);
+                _logger.LogError(ex, "Error reading policy file: {Path}", path);
 
-                return GetDefaultPolicy(user);
+                return GetDefaultPolicy();
             }
         }
 
-        private static UserPolicy GetDefaultPolicy(User user)
+        private static UserPolicy GetDefaultPolicy()
         {
             return new UserPolicy
             {
@@ -983,27 +983,6 @@ namespace Emby.Server.Implementations.Library
             }
         }
 
-        private void DeleteUserPolicy(User user)
-        {
-            var path = GetPolicyFilePath(user);
-
-            try
-            {
-                lock (_policySyncLock)
-                {
-                    _fileSystem.DeleteFile(path);
-                }
-            }
-            catch (IOException)
-            {
-
-            }
-            catch (Exception ex)
-            {
-                _logger.LogError(ex, "Error deleting policy file");
-            }
-        }
-
         private static string GetPolicyFilePath(User user)
         {
             return Path.Combine(user.ConfigurationDirectoryPath, "policy.xml");
@@ -1030,19 +1009,14 @@ namespace Emby.Server.Implementations.Library
                     return (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), path);
                 }
             }
-            catch (IOException)
-            {
-                return new UserConfiguration();
-            }
             catch (Exception ex)
             {
-                _logger.LogError(ex, "Error reading policy file: {path}", path);
+                _logger.LogError(ex, "Error reading policy file: {Path}", path);
 
                 return new UserConfiguration();
             }
         }
 
-        private readonly object _configSyncLock = new object();
         public void UpdateConfiguration(Guid userId, UserConfiguration config)
         {
             var user = GetUserById(userId);

+ 2 - 1
Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs

@@ -1,5 +1,6 @@
 using System;
 using System.IO;
+using System.Net.Http;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Net;
@@ -74,7 +75,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
                 DecompressionMethod = CompressionMethod.None
             };
 
-            using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false))
+            using (var response = await _httpClient.SendAsync(httpRequestOptions, HttpMethod.Get).ConfigureAwait(false))
             {
                 _logger.LogInformation("Opened recording stream from tuner provider");
 

+ 3 - 3
Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -5,6 +5,7 @@ using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Net;
+using System.Net.Http;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common;
@@ -12,7 +13,6 @@ using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.LiveTv;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Serialization;
@@ -663,7 +663,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
 
             try
             {
-                return await _httpClient.SendAsync(options, "GET").ConfigureAwait(false);
+                return await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false);
             }
             catch (HttpException ex)
             {
@@ -738,7 +738,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
 
             httpOptions.RequestHeaders["token"] = token;
 
-            using (await _httpClient.SendAsync(httpOptions, "PUT").ConfigureAwait(false))
+            using (await _httpClient.SendAsync(httpOptions, HttpMethod.Put).ConfigureAwait(false))
             {
             }
         }

+ 2 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
+using System.Net.Http;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Configuration;
@@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 httpRequestOptions.RequestHeaders[header.Key] = header.Value;
             }
 
-            var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false);
+            var response = await _httpClient.SendAsync(httpRequestOptions, HttpMethod.Get).ConfigureAwait(false);
 
             var extension = "ts";
             var requiresRemux = false;

+ 37 - 37
Emby.Server.Implementations/Localization/Core/ca.json

@@ -1,11 +1,11 @@
 {
     "Albums": "Àlbums",
-    "AppDeviceValues": "App: {0}, Dispositiu: {1}",
-    "Application": "Application",
+    "AppDeviceValues": "Aplicació: {0}, Dispositiu: {1}",
+    "Application": "Aplicació",
     "Artists": "Artistes",
     "AuthenticationSucceededWithUserName": "{0} s'ha autenticat correctament",
     "Books": "Llibres",
-    "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+    "CameraImageUploadedFrom": "Una nova imatge de càmera ha sigut pujada des de {0}",
     "Channels": "Canals",
     "ChapterNameValue": "Episodi {0}",
     "Collections": "Col·leccions",
@@ -15,8 +15,8 @@
     "Favorites": "Preferits",
     "Folders": "Directoris",
     "Genres": "Gèneres",
-    "HeaderAlbumArtists": "Album Artists",
-    "HeaderCameraUploads": "Camera Uploads",
+    "HeaderAlbumArtists": "Artistes dels Àlbums",
+    "HeaderCameraUploads": "Pujades de Càmera",
     "HeaderContinueWatching": "Continua Veient",
     "HeaderFavoriteAlbums": "Àlbums Preferits",
     "HeaderFavoriteArtists": "Artistes Preferits",
@@ -27,71 +27,71 @@
     "HeaderNextUp": "A continuació",
     "HeaderRecordingGroups": "Grups d'Enregistrament",
     "HomeVideos": "Vídeos domèstics",
-    "Inherit": "Heretat",
-    "ItemAddedWithName": "{0} afegit a la biblioteca",
-    "ItemRemovedWithName": "{0} eliminat de la biblioteca",
+    "Inherit": "Hereta",
+    "ItemAddedWithName": "{0} ha estat afegit a la biblioteca",
+    "ItemRemovedWithName": "{0} ha estat eliminat de la biblioteca",
     "LabelIpAddressValue": "Adreça IP: {0}",
-    "LabelRunningTimeValue": "Temps en marxa: {0}",
+    "LabelRunningTimeValue": "Temps en funcionament: {0}",
     "Latest": "Darreres",
-    "MessageApplicationUpdated": "El Servidor d'Jellyfin ha estat actualitzat",
-    "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
-    "MessageNamedServerConfigurationUpdatedWithValue": "La secció de configuració {0} ha estat actualitzada",
+    "MessageApplicationUpdated": "El Servidor de Jellyfin ha estat actualitzat",
+    "MessageApplicationUpdatedTo": "El Servidor de Jellyfin ha estat actualitzat a {0}",
+    "MessageNamedServerConfigurationUpdatedWithValue": "La secció {0} de la configuració del servidor ha estat actualitzada",
     "MessageServerConfigurationUpdated": "S'ha actualitzat la configuració del servidor",
     "MixedContent": "Contingut mesclat",
     "Movies": "Pel·lícules",
     "Music": "Música",
     "MusicVideos": "Vídeos musicals",
-    "NameInstallFailed": "{0} installation failed",
+    "NameInstallFailed": "Instalació de {0} fallida",
     "NameSeasonNumber": "Temporada {0}",
-    "NameSeasonUnknown": "Season Unknown",
-    "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
+    "NameSeasonUnknown": "Temporada Desconeguda",
+    "NewVersionIsAvailable": "Una nova versió del Servidor Jellyfin està disponible per descarregar.",
     "NotificationOptionApplicationUpdateAvailable": "Actualització d'aplicació disponible",
     "NotificationOptionApplicationUpdateInstalled": "Actualització d'aplicació instal·lada",
-    "NotificationOptionAudioPlayback": "Audio playback started",
-    "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
-    "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "NotificationOptionInstallationFailed": "Installation failure",
-    "NotificationOptionNewLibraryContent": "New content added",
-    "NotificationOptionPluginError": "Un component ha fallat",
-    "NotificationOptionPluginInstalled": "Complement instal·lat",
-    "NotificationOptionPluginUninstalled": "Complement desinstal·lat",
-    "NotificationOptionPluginUpdateInstalled": "Actualització de complement instal·lada",
-    "NotificationOptionServerRestartRequired": "Server restart required",
-    "NotificationOptionTaskFailed": "Scheduled task failure",
-    "NotificationOptionUserLockedOut": "User locked out",
-    "NotificationOptionVideoPlayback": "Video playback started",
-    "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
+    "NotificationOptionAudioPlayback": "Reproducció d'audio iniciada",
+    "NotificationOptionAudioPlaybackStopped": "Reproducció d'audio aturada",
+    "NotificationOptionCameraImageUploaded": "Imatge de càmera pujada",
+    "NotificationOptionInstallationFailed": "Instalació fallida",
+    "NotificationOptionNewLibraryContent": "Nou contingut afegit",
+    "NotificationOptionPluginError": "Un connector ha fallat",
+    "NotificationOptionPluginInstalled": "Connector instal·lat",
+    "NotificationOptionPluginUninstalled": "Connector desinstal·lat",
+    "NotificationOptionPluginUpdateInstalled": "Actualització de connector instal·lada",
+    "NotificationOptionServerRestartRequired": "Reinici del servidor requerit",
+    "NotificationOptionTaskFailed": "Tasca programada fallida",
+    "NotificationOptionUserLockedOut": "Usuari tancat",
+    "NotificationOptionVideoPlayback": "Reproducció de video iniciada",
+    "NotificationOptionVideoPlaybackStopped": "Reproducció de video aturada",
     "Photos": "Fotos",
     "Playlists": "Llistes de reproducció",
-    "Plugin": "Plugin",
+    "Plugin": "Connector",
     "PluginInstalledWithName": "{0} ha estat instal·lat",
     "PluginUninstalledWithName": "{0} ha estat desinstal·lat",
     "PluginUpdatedWithName": "{0} ha estat actualitzat",
     "ProviderValue": "Proveïdor: {0}",
     "ScheduledTaskFailedWithName": "{0} ha fallat",
     "ScheduledTaskStartedWithName": "{0} iniciat",
-    "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
-    "Shows": "Espectacles",
+    "ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciat",
+    "Shows": "Programes",
     "Songs": "Cançons",
     "StartupEmbyServerIsLoading": "El Servidor d'Jellyfin est&agrave; carregant. Si et plau, prova de nou en breus.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
-    "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
+    "SubtitleDownloadFailureFromForItem": "Els subtítols no s'han pogut baixar de {0} per {1}",
     "SubtitlesDownloadedForItem": "Subtítols descarregats per a {0}",
-    "Sync": "Sync",
+    "Sync": "Sincronitzar",
     "System": "System",
     "TvShows": "Espectacles de TV",
     "User": "User",
     "UserCreatedWithName": "S'ha creat l'usuari {0}",
     "UserDeletedWithName": "L'usuari {0} ha estat eliminat",
     "UserDownloadingItemWithValues": "{0} està descarregant {1}",
-    "UserLockedOutWithName": "User {0} has been locked out",
+    "UserLockedOutWithName": "L'usuari {0} ha sigut tancat",
     "UserOfflineFromDevice": "{0} s'ha desconnectat de {1}",
     "UserOnlineFromDevice": "{0} està connectat des de {1}",
     "UserPasswordChangedWithName": "La contrasenya ha estat canviada per a l'usuari {0}",
-    "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
+    "UserPolicyUpdatedWithName": "La política d'usuari s'ha actualitzat per {0}",
     "UserStartedPlayingItemWithValues": "{0} ha començat a reproduir {1}",
     "UserStoppedPlayingItemWithValues": "{0} ha parat de reproduir {1}",
-    "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
+    "ValueHasBeenAddedToLibrary": "{0} ha sigut afegit a la teva llibreria",
     "ValueSpecialEpisodeName": "Especial - {0}",
     "VersionNumber": "Versió {0}"
 }

+ 2 - 2
Emby.Server.Implementations/Localization/Core/fr.json

@@ -19,10 +19,10 @@
     "HeaderCameraUploads": "Photos transférées",
     "HeaderContinueWatching": "Continuer à regarder",
     "HeaderFavoriteAlbums": "Albums favoris",
-    "HeaderFavoriteArtists": "Artistes favoris",
+    "HeaderFavoriteArtists": "Artistes préférés",
     "HeaderFavoriteEpisodes": "Épisodes favoris",
     "HeaderFavoriteShows": "Séries favorites",
-    "HeaderFavoriteSongs": "Chansons favorites",
+    "HeaderFavoriteSongs": "Chansons préférées",
     "HeaderLiveTV": "TV en direct",
     "HeaderNextUp": "À suivre",
     "HeaderRecordingGroups": "Groupes d'enregistrements",

+ 32 - 0
Emby.Server.Implementations/Localization/Core/id.json

@@ -0,0 +1,32 @@
+{
+    "Albums": "Album",
+    "AuthenticationSucceededWithUserName": "{0} berhasil diautentikasi",
+    "AppDeviceValues": "Aplikasi: {0}, Alat: {1}",
+    "LabelRunningTimeValue": "Waktu berjalan: {0}",
+    "MessageApplicationUpdatedTo": "Jellyfin Server sudah diperbarui ke {0}",
+    "MessageApplicationUpdated": "Jellyfin Server sudah diperbarui",
+    "Latest": "Terbaru",
+    "LabelIpAddressValue": "IP address: {0}",
+    "ItemRemovedWithName": "{0} sudah dikeluarkan dari perpustakaan",
+    "ItemAddedWithName": "{0} sudah dimasukkan ke dalam perpustakaan",
+    "Inherit": "Warisan",
+    "HomeVideos": "Video Rumah",
+    "HeaderRecordingGroups": "Grup Rekaman",
+    "HeaderNextUp": "Selanjutnya",
+    "HeaderLiveTV": "TV Live",
+    "HeaderFavoriteSongs": "Lagu Favorit",
+    "HeaderFavoriteShows": "Tayangan Favorit",
+    "HeaderFavoriteEpisodes": "Episode Favorit",
+    "HeaderFavoriteArtists": "Artis Favorit",
+    "HeaderFavoriteAlbums": "Album Favorit",
+    "HeaderContinueWatching": "Masih Melihat",
+    "HeaderCameraUploads": "Uplod Kamera",
+    "HeaderAlbumArtists": "Album Artis",
+    "Genres": "Genre",
+    "Folders": "Folder",
+    "Favorites": "Favorit",
+    "Collections": "Koleksi",
+    "Books": "Buku",
+    "Artists": "Artis",
+    "Application": "Aplikasi"
+}

+ 75 - 75
Emby.Server.Implementations/Localization/Core/lt-LT.json

@@ -1,97 +1,97 @@
 {
     "Albums": "Albumai",
-    "AppDeviceValues": "App: {0}, Device: {1}",
-    "Application": "Application",
+    "AppDeviceValues": "Programa: {0}, Įrenginys: {1}",
+    "Application": "Programa",
     "Artists": "Atlikėjai",
-    "AuthenticationSucceededWithUserName": "{0} successfully authenticated",
+    "AuthenticationSucceededWithUserName": "{0} sėkmingai autentifikuota",
     "Books": "Knygos",
-    "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+    "CameraImageUploadedFrom": "Nauja nuotrauka įkelta iš kameros {0}",
     "Channels": "Kanalai",
-    "ChapterNameValue": "Chapter {0}",
+    "ChapterNameValue": "Scena{0}",
     "Collections": "Kolekcijos",
-    "DeviceOfflineWithName": "{0} has disconnected",
-    "DeviceOnlineWithName": "{0} is connected",
-    "FailedLoginAttemptWithUserName": "Failed login attempt from {0}",
+    "DeviceOfflineWithName": "{0} buvo atjungtas",
+    "DeviceOnlineWithName": "{0} prisijungęs",
+    "FailedLoginAttemptWithUserName": "{0} - nesėkmingas bandymas prisijungti",
     "Favorites": "Mėgstami",
     "Folders": "Katalogai",
     "Genres": "Žanrai",
     "HeaderAlbumArtists": "Albumo atlikėjai",
-    "HeaderCameraUploads": "Camera Uploads",
+    "HeaderCameraUploads": "Kameros",
     "HeaderContinueWatching": "Žiūrėti toliau",
-    "HeaderFavoriteAlbums": "Favorite Albums",
-    "HeaderFavoriteArtists": "Favorite Artists",
-    "HeaderFavoriteEpisodes": "Favorite Episodes",
-    "HeaderFavoriteShows": "Favorite Shows",
-    "HeaderFavoriteSongs": "Favorite Songs",
-    "HeaderLiveTV": "Live TV",
-    "HeaderNextUp": "Next Up",
-    "HeaderRecordingGroups": "Recording Groups",
-    "HomeVideos": "Home videos",
-    "Inherit": "Inherit",
-    "ItemAddedWithName": "{0} was added to the library",
-    "ItemRemovedWithName": "{0} was removed from the library",
-    "LabelIpAddressValue": "Ip address: {0}",
-    "LabelRunningTimeValue": "Running time: {0}",
-    "Latest": "Latest",
-    "MessageApplicationUpdated": "Jellyfin Server has been updated",
-    "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
-    "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
-    "MessageServerConfigurationUpdated": "Server configuration has been updated",
+    "HeaderFavoriteAlbums": "Mėgstami Albumai",
+    "HeaderFavoriteArtists": "Mėgstami Atlikėjai",
+    "HeaderFavoriteEpisodes": "Mėgstamiausios serijos",
+    "HeaderFavoriteShows": "Mėgstamiausi serialai",
+    "HeaderFavoriteSongs": "Mėgstamos dainos",
+    "HeaderLiveTV": "TV gyvai",
+    "HeaderNextUp": "Toliau eilėje",
+    "HeaderRecordingGroups": "Įrašų grupės",
+    "HomeVideos": "Namų vaizdo įrašai",
+    "Inherit": "Paveldėti",
+    "ItemAddedWithName": "{0} - buvo įkeltas į mediateką",
+    "ItemRemovedWithName": "{0} - buvo pašalinta iš mediatekos",
+    "LabelIpAddressValue": "IP adresas: {0}",
+    "LabelRunningTimeValue": "Trukmė: {0}",
+    "Latest": "Naujausi",
+    "MessageApplicationUpdated": "\"Jellyfin Server\" atnaujintas",
+    "MessageApplicationUpdatedTo": "\"Jellyfin Server\" buvo atnaujinta iki {0}",
+    "MessageNamedServerConfigurationUpdatedWithValue": "Serverio nustatymai (skyrius {0}) buvo atnaujinti",
+    "MessageServerConfigurationUpdated": "Serverio nustatymai buvo atnaujinti",
     "MixedContent": "Mixed content",
     "Movies": "Filmai",
-    "Music": "Music",
-    "MusicVideos": "Music videos",
-    "NameInstallFailed": "{0} installation failed",
-    "NameSeasonNumber": "Season {0}",
-    "NameSeasonUnknown": "Season Unknown",
-    "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
-    "NotificationOptionApplicationUpdateAvailable": "Application update available",
-    "NotificationOptionApplicationUpdateInstalled": "Application update installed",
-    "NotificationOptionAudioPlayback": "Audio playback started",
-    "NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
-    "NotificationOptionCameraImageUploaded": "Camera image uploaded",
-    "NotificationOptionInstallationFailed": "Installation failure",
-    "NotificationOptionNewLibraryContent": "New content added",
-    "NotificationOptionPluginError": "Plugin failure",
-    "NotificationOptionPluginInstalled": "Plugin installed",
-    "NotificationOptionPluginUninstalled": "Plugin uninstalled",
-    "NotificationOptionPluginUpdateInstalled": "Plugin update installed",
-    "NotificationOptionServerRestartRequired": "Server restart required",
-    "NotificationOptionTaskFailed": "Scheduled task failure",
-    "NotificationOptionUserLockedOut": "User locked out",
-    "NotificationOptionVideoPlayback": "Video playback started",
-    "NotificationOptionVideoPlaybackStopped": "Video playback stopped",
-    "Photos": "Photos",
-    "Playlists": "Playlists",
+    "Music": "Muzika",
+    "MusicVideos": "Muzikiniai klipai",
+    "NameInstallFailed": "{0} diegimo klaida",
+    "NameSeasonNumber": "Sezonas {0}",
+    "NameSeasonUnknown": "Sezonas neatpažintas",
+    "NewVersionIsAvailable": "Nauja \"Jellyfin Server\" versija yra prieinama atsisiuntimui.",
+    "NotificationOptionApplicationUpdateAvailable": "Galimi programos atnaujinimai",
+    "NotificationOptionApplicationUpdateInstalled": "Programos atnaujinimai įdiegti",
+    "NotificationOptionAudioPlayback": "Garso atkūrimas pradėtas",
+    "NotificationOptionAudioPlaybackStopped": "Garso atkūrimas sustabdytas",
+    "NotificationOptionCameraImageUploaded": "Kameros vaizdai įkelti",
+    "NotificationOptionInstallationFailed": "Diegimo klaida",
+    "NotificationOptionNewLibraryContent": "Naujas turinys įkeltas",
+    "NotificationOptionPluginError": "Įskiepio klaida",
+    "NotificationOptionPluginInstalled": "Įskiepis įdiegtas",
+    "NotificationOptionPluginUninstalled": "Įskiepis pašalintas",
+    "NotificationOptionPluginUpdateInstalled": "Įskiepio atnaujinimas įdiegtas",
+    "NotificationOptionServerRestartRequired": "Reikalingas serverio perleidimas",
+    "NotificationOptionTaskFailed": "Suplanuotos užduoties klaida",
+    "NotificationOptionUserLockedOut": "Vartotojas užblokuotas",
+    "NotificationOptionVideoPlayback": "Vaizdo įrašo atkūrimas pradėtas",
+    "NotificationOptionVideoPlaybackStopped": "Vaizdo įrašo atkūrimas sustabdytas",
+    "Photos": "Nuotraukos",
+    "Playlists": "Grojaraštis",
     "Plugin": "Plugin",
-    "PluginInstalledWithName": "{0} was installed",
-    "PluginUninstalledWithName": "{0} was uninstalled",
-    "PluginUpdatedWithName": "{0} was updated",
+    "PluginInstalledWithName": "{0} buvo įdiegtas",
+    "PluginUninstalledWithName": "{0} buvo pašalintas",
+    "PluginUpdatedWithName": "{0} buvo atnaujintas",
     "ProviderValue": "Provider: {0}",
-    "ScheduledTaskFailedWithName": "{0} failed",
-    "ScheduledTaskStartedWithName": "{0} started",
-    "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
-    "Shows": "Shows",
-    "Songs": "Songs",
-    "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.",
+    "ScheduledTaskFailedWithName": "{0} klaida",
+    "ScheduledTaskStartedWithName": "{0} paleista",
+    "ServerNameNeedsToBeRestarted": "{0} reikia iš naujo paleisti",
+    "Shows": "Laidos",
+    "Songs": "Kūriniai",
+    "StartupEmbyServerIsLoading": "Jellyfin Server kraunasi. Netrukus pabandykite dar kartą.",
     "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
-    "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
-    "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}",
+    "SubtitleDownloadFailureFromForItem": "{1} subtitrai buvo nesėkmingai parsiųsti iš {0}",
+    "SubtitlesDownloadedForItem": "{0} subtitrai parsiųsti",
     "Sync": "Sinchronizuoti",
     "System": "System",
-    "TvShows": "TV Shows",
+    "TvShows": "TV Serialai",
     "User": "User",
-    "UserCreatedWithName": "User {0} has been created",
-    "UserDeletedWithName": "User {0} has been deleted",
-    "UserDownloadingItemWithValues": "{0} is downloading {1}",
-    "UserLockedOutWithName": "User {0} has been locked out",
-    "UserOfflineFromDevice": "{0} has disconnected from {1}",
-    "UserOnlineFromDevice": "{0} is online from {1}",
-    "UserPasswordChangedWithName": "Password has been changed for user {0}",
-    "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
-    "UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}",
-    "UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}",
-    "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
+    "UserCreatedWithName": "Vartotojas {0} buvo sukurtas",
+    "UserDeletedWithName": "Vartotojas {0} ištrintas",
+    "UserDownloadingItemWithValues": "{0} siunčiasi {1}",
+    "UserLockedOutWithName": "Vartotojas {0} užblokuotas",
+    "UserOfflineFromDevice": "{0} buvo atjungtas nuo {1}",
+    "UserOnlineFromDevice": "{0} prisijungęs iš {1}",
+    "UserPasswordChangedWithName": "Slaptažodis pakeistas vartotojui {0}",
+    "UserPolicyUpdatedWithName": "Vartotojo {0} teisės buvo pakeistos",
+    "UserStartedPlayingItemWithValues": "{0} leidžia {1} į {2}",
+    "UserStoppedPlayingItemWithValues": "{0} baigė leisti {1} į {2}",
+    "ValueHasBeenAddedToLibrary": "{0} pridėtas į mediateką",
     "ValueSpecialEpisodeName": "Ypatinga - {0}",
     "VersionNumber": "Version {0}"
 }

+ 27 - 27
Emby.Server.Implementations/Localization/Core/nb.json

@@ -17,7 +17,7 @@
     "Genres": "Sjangre",
     "HeaderAlbumArtists": "Albumartister",
     "HeaderCameraUploads": "Kameraopplastinger",
-    "HeaderContinueWatching": "Forsett å se",
+    "HeaderContinueWatching": "Fortsett å se",
     "HeaderFavoriteAlbums": "Favorittalbum",
     "HeaderFavoriteArtists": "Favorittartister",
     "HeaderFavoriteEpisodes": "Favorittepisoder",
@@ -25,18 +25,18 @@
     "HeaderFavoriteSongs": "Favorittsanger",
     "HeaderLiveTV": "Direkte-TV",
     "HeaderNextUp": "Neste",
-    "HeaderRecordingGroups": "Opptak Grupper",
-    "HomeVideos": "Hjemmelaget filmer",
+    "HeaderRecordingGroups": "Opptaksgrupper",
+    "HomeVideos": "Hjemmelagde filmer",
     "Inherit": "Arve",
     "ItemAddedWithName": "{0} ble lagt til i biblioteket",
     "ItemRemovedWithName": "{0} ble fjernet fra biblioteket",
-    "LabelIpAddressValue": "IP adresse: {0}",
-    "LabelRunningTimeValue": "Løpetid {0}",
+    "LabelIpAddressValue": "IP-adresse: {0}",
+    "LabelRunningTimeValue": "Kjøretid {0}",
     "Latest": "Siste",
-    "MessageApplicationUpdated": "Jellyfin server har blitt oppdatert",
-    "MessageApplicationUpdatedTo": "Jellyfin-serveren ble oppdatert til {0}",
-    "MessageNamedServerConfigurationUpdatedWithValue": "Server konfigurasjon seksjon {0} har blitt oppdatert",
-    "MessageServerConfigurationUpdated": "Server konfigurasjon er oppdatert",
+    "MessageApplicationUpdated": "Jellyfin Server har blitt oppdatert",
+    "MessageApplicationUpdatedTo": "Jellyfin Server ble oppdatert til {0}",
+    "MessageNamedServerConfigurationUpdatedWithValue": "Serverkonfigurasjon seksjon {0} har blitt oppdatert",
+    "MessageServerConfigurationUpdated": "Serverkonfigurasjon er oppdatert",
     "MixedContent": "Blandet innhold",
     "Movies": "Filmer",
     "Music": "Musikk",
@@ -44,38 +44,38 @@
     "NameInstallFailed": "{0}-installasjonen mislyktes",
     "NameSeasonNumber": "Sesong {0}",
     "NameSeasonUnknown": "Sesong ukjent",
-    "NewVersionIsAvailable": "En ny versjon av Jellyfin-serveren er tilgjengelig for nedlastning.",
-    "NotificationOptionApplicationUpdateAvailable": "Applikasjon oppdatering tilgjengelig",
+    "NewVersionIsAvailable": "En ny versjon av Jellyfin Server er tilgjengelig for nedlasting.",
+    "NotificationOptionApplicationUpdateAvailable": "Programvareoppdatering er tilgjengelig",
     "NotificationOptionApplicationUpdateInstalled": "Applikasjonsoppdatering installert",
-    "NotificationOptionAudioPlayback": "Lyd tilbakespilling startet",
-    "NotificationOptionAudioPlaybackStopped": "Lyd avspilling stoppet",
-    "NotificationOptionCameraImageUploaded": "Kamera bilde lastet opp",
+    "NotificationOptionAudioPlayback": "Lydavspilling startet",
+    "NotificationOptionAudioPlaybackStopped": "Lydavspilling stoppet",
+    "NotificationOptionCameraImageUploaded": "Kamerabilde lastet opp",
     "NotificationOptionInstallationFailed": "Installasjonsfeil",
-    "NotificationOptionNewLibraryContent": "Ny innhold er lagt til",
-    "NotificationOptionPluginError": "Plugin feil",
+    "NotificationOptionNewLibraryContent": "Nytt innhold lagt til",
+    "NotificationOptionPluginError": "Pluginfeil",
     "NotificationOptionPluginInstalled": "Plugin installert",
     "NotificationOptionPluginUninstalled": "Plugin avinstallert",
-    "NotificationOptionPluginUpdateInstalled": "Plugin oppdatering installert",
-    "NotificationOptionServerRestartRequired": "Server omstart er nødvendig",
-    "NotificationOptionTaskFailed": "Feil under utføring av planlagt oppgaver",
+    "NotificationOptionPluginUpdateInstalled": "Pluginoppdatering installert",
+    "NotificationOptionServerRestartRequired": "Serveromstart er nødvendig",
+    "NotificationOptionTaskFailed": "Feil under utføring av planlagt oppgave",
     "NotificationOptionUserLockedOut": "Bruker er utestengt",
-    "NotificationOptionVideoPlayback": "Video tilbakespilling startet",
-    "NotificationOptionVideoPlaybackStopped": "Video avspilling stoppet",
+    "NotificationOptionVideoPlayback": "Videoavspilling startet",
+    "NotificationOptionVideoPlaybackStopped": "Videoavspilling stoppet",
     "Photos": "Bilder",
-    "Playlists": "Spillelister",
+    "Playlists": "Spliielister",
     "Plugin": "Plugin",
     "PluginInstalledWithName": "{0} ble installert",
     "PluginUninstalledWithName": "{0} ble avinstallert",
     "PluginUpdatedWithName": "{0} ble oppdatert",
-    "ProviderValue": "Leverandører: {0}",
-    "ScheduledTaskFailedWithName": "{0} Mislykkes",
-    "ScheduledTaskStartedWithName": "{0} Startet",
+    "ProviderValue": "Leverandør: {0}",
+    "ScheduledTaskFailedWithName": "{0} mislykkes",
+    "ScheduledTaskStartedWithName": "{0} startet",
     "ServerNameNeedsToBeRestarted": "{0} må startes på nytt",
     "Shows": "Programmer",
     "Songs": "Sanger",
-    "StartupEmbyServerIsLoading": "Jellyfin server laster. Prøv igjen snart.",
+    "StartupEmbyServerIsLoading": "Jellyfin Server laster. Prøv igjen snart.",
     "SubtitleDownloadFailureForItem": "En feil oppstå under nedlasting av undertekster for  {0}",
-    "SubtitleDownloadFailureFromForItem": "Kunne ikke laste ned teksting fra {0} for {1}",
+    "SubtitleDownloadFailureFromForItem": "Kunne ikke laste ned undertekster fra {0} for {1}",
     "SubtitlesDownloadedForItem": "Undertekster lastet ned for {0}",
     "Sync": "Synkroniser",
     "System": "System",

+ 96 - 0
Emby.Server.Implementations/Localization/Core/pt.json

@@ -0,0 +1,96 @@
+{
+    "HeaderLiveTV": "TV ao Vivo",
+    "Collections": "Colecções",
+    "Books": "Livros",
+    "Artists": "Artistas",
+    "Albums": "Álbuns",
+    "HeaderNextUp": "A Seguir",
+    "HeaderFavoriteSongs": "Músicas Favoritas",
+    "HeaderFavoriteArtists": "Artistas Favoritos",
+    "HeaderFavoriteAlbums": "Álbuns Favoritos",
+    "HeaderFavoriteEpisodes": "Episódios Favoritos",
+    "HeaderFavoriteShows": "Séries Favoritas",
+    "HeaderContinueWatching": "Continuar a Ver",
+    "HeaderAlbumArtists": "Artistas do Álbum",
+    "Genres": "Géneros",
+    "Folders": "Pastas",
+    "Favorites": "Favoritos",
+    "Channels": "Canais",
+    "UserDownloadingItemWithValues": "{0} está a transferir {1}",
+    "VersionNumber": "Versão {0}",
+    "ValueHasBeenAddedToLibrary": "{0} foi adicionado à sua biblioteca multimédia",
+    "UserStoppedPlayingItemWithValues": "{0} terminou a reprodução de {1} em {2}",
+    "UserStartedPlayingItemWithValues": "{0} está a reproduzir {1} em {2}",
+    "UserPolicyUpdatedWithName": "A política do utilizador {0} foi alterada",
+    "UserPasswordChangedWithName": "A palavra-passe do utilizador {0} foi alterada",
+    "UserOnlineFromDevice": "{0} ligou-se a partir de {1}",
+    "UserOfflineFromDevice": "{0} desligou-se a partir de {1}",
+    "UserLockedOutWithName": "Utilizador {0} bloqueado",
+    "UserDeletedWithName": "Utilizador {0} removido",
+    "UserCreatedWithName": "Utilizador {0} criado",
+    "User": "Utilizador",
+    "TvShows": "Programas",
+    "System": "Sistema",
+    "SubtitlesDownloadedForItem": "Legendas transferidas para {0}",
+    "SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas de {0} para {1}",
+    "StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente dentro de momentos.",
+    "ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciado",
+    "ScheduledTaskStartedWithName": "{0} iniciou",
+    "ScheduledTaskFailedWithName": "{0} falhou",
+    "ProviderValue": "Fornecedor: {0}",
+    "PluginUpdatedWithName": "{0} foi actualizado",
+    "PluginUninstalledWithName": "{0} foi desinstalado",
+    "PluginInstalledWithName": "{0} foi instalado",
+    "Plugin": "Extensão",
+    "NotificationOptionVideoPlaybackStopped": "Reprodução de vídeo parada",
+    "NotificationOptionVideoPlayback": "Reprodução de vídeo iniciada",
+    "NotificationOptionUserLockedOut": "Utilizador bloqueado",
+    "NotificationOptionTaskFailed": "Falha em tarefa agendada",
+    "NotificationOptionServerRestartRequired": "É necessário reiniciar o servidor",
+    "NotificationOptionPluginUpdateInstalled": "Extensão actualizada",
+    "NotificationOptionPluginUninstalled": "Extensão desinstalada",
+    "NotificationOptionPluginInstalled": "Extensão instalada",
+    "NotificationOptionPluginError": "Falha na extensão",
+    "NotificationOptionNewLibraryContent": "Novo conteúdo adicionado",
+    "NotificationOptionInstallationFailed": "Falha de instalação",
+    "NotificationOptionCameraImageUploaded": "Imagem da câmara enviada",
+    "NotificationOptionAudioPlaybackStopped": "Reprodução Parada",
+    "NotificationOptionAudioPlayback": "Reprodução Iniciada",
+    "NotificationOptionApplicationUpdateInstalled": "A actualização da aplicação foi instalada",
+    "NotificationOptionApplicationUpdateAvailable": "Uma actualização da aplicação está disponível",
+    "NewVersionIsAvailable": "Uma nova versão do servidor Jellyfin está disponível para transferência.",
+    "NameSeasonUnknown": "Temporada Desconhecida",
+    "NameSeasonNumber": "Temporada {0}",
+    "NameInstallFailed": "Falha na instalação de {0}",
+    "MusicVideos": "Videoclips",
+    "Music": "Música",
+    "MixedContent": "Conteúdo Misto",
+    "MessageServerConfigurationUpdated": "A configuração do servidor foi actualizada",
+    "MessageNamedServerConfigurationUpdatedWithValue": "Configurações do servidor na secção {0} foram atualizadas",
+    "MessageApplicationUpdatedTo": "O servidor Jellyfin foi actualizado para a versão {0}",
+    "MessageApplicationUpdated": "O servidor Jellyfin foi actualizado",
+    "Latest": "Mais Recente",
+    "LabelRunningTimeValue": "Duração: {0}",
+    "LabelIpAddressValue": "Endereço IP: {0}",
+    "ItemRemovedWithName": "{0} foi removido da biblioteca",
+    "ItemAddedWithName": "{0} foi adicionado à biblioteca",
+    "Inherit": "Herdar",
+    "HomeVideos": "Vídeos Caseiros",
+    "HeaderRecordingGroups": "Grupos de Gravação",
+    "ValueSpecialEpisodeName": "Especial - {0}",
+    "Sync": "Sincronização",
+    "Songs": "Músicas",
+    "Shows": "Séries",
+    "Playlists": "Listas de Reprodução",
+    "Photos": "Fotografias",
+    "Movies": "Filmes",
+    "HeaderCameraUploads": "Envios a partir da câmara",
+    "FailedLoginAttemptWithUserName": "Tentativa de ligação  a partir de {0} falhou",
+    "DeviceOnlineWithName": "{0} ligou-se",
+    "DeviceOfflineWithName": "{0} desligou-se",
+    "ChapterNameValue": "Capítulo {0}",
+    "CameraImageUploadedFrom": "Uma nova imagem de câmara foi enviada a partir de {0}",
+    "AuthenticationSucceededWithUserName": "{0} autenticado com sucesso",
+    "Application": "Aplicação",
+    "AppDeviceValues": "Aplicação {0}, Dispositivo: {1}"
+}

+ 96 - 0
Emby.Server.Implementations/Localization/Core/ro.json

@@ -0,0 +1,96 @@
+{
+    "HeaderNextUp": "Urmează",
+    "VersionNumber": "Versiunea {0}",
+    "ValueSpecialEpisodeName": "Special - {0}",
+    "ValueHasBeenAddedToLibrary": "{0} a fost adăugat la biblioteca multimedia",
+    "UserStoppedPlayingItemWithValues": "{0} a terminat rularea {1} pe {2}",
+    "UserStartedPlayingItemWithValues": "{0} ruleaza {1} pe {2}",
+    "UserPolicyUpdatedWithName": "Politica utilizatorului {0} a fost actualizată",
+    "UserPasswordChangedWithName": "Parola utilizatorului {0} a fost schimbată",
+    "UserOnlineFromDevice": "{0} este conectat de la {1}",
+    "UserOfflineFromDevice": "{0} s-a deconectat de la {1}",
+    "UserLockedOutWithName": "Utilizatorul {0} a fost blocat",
+    "UserDownloadingItemWithValues": "{0} descarcă {1}",
+    "UserDeletedWithName": "Utilizatorul {0} a fost eliminat",
+    "UserCreatedWithName": "Utilizatorul {0} a fost creat",
+    "User": "Utilizator",
+    "TvShows": "Spectacole TV",
+    "System": "Sistem",
+    "Sync": "Sincronizare",
+    "SubtitlesDownloadedForItem": "Subtitrari descarcate pentru {0}",
+    "SubtitleDownloadFailureFromForItem": "Subtitrările nu au putut fi descărcate de la {0} pentru {1}",
+    "StartupEmbyServerIsLoading": "Se încarcă serverul Jellyfin. Încercați din nou în scurt timp.",
+    "Songs": "Melodii",
+    "Shows": "Spectacole",
+    "ServerNameNeedsToBeRestarted": "{0} trebuie repornit",
+    "ScheduledTaskStartedWithName": "{0} pornit/ă",
+    "ScheduledTaskFailedWithName": "{0} eșuat/ă",
+    "ProviderValue": "Furnizor: {0}",
+    "PluginUpdatedWithName": "{0} a fost actualizat/ă",
+    "PluginUninstalledWithName": "{0} a fost dezinstalat",
+    "PluginInstalledWithName": "{0} a fost instalat",
+    "Plugin": "Complement",
+    "Playlists": "Liste redare",
+    "Photos": "Fotografii",
+    "NotificationOptionVideoPlaybackStopped": "Redarea video oprită",
+    "NotificationOptionVideoPlayback": "Începută redarea video",
+    "NotificationOptionUserLockedOut": "Utilizatorul a fost blocat",
+    "NotificationOptionTaskFailed": "Activitate programata eșuată",
+    "NotificationOptionServerRestartRequired": "Este necesară repornirea Serverului",
+    "NotificationOptionPluginUpdateInstalled": "Actualizare plugin instalată",
+    "NotificationOptionPluginUninstalled": "Plugin dezinstalat",
+    "NotificationOptionPluginInstalled": "Plugin instalat",
+    "NotificationOptionPluginError": "Plugin-ul a eșuat",
+    "NotificationOptionNewLibraryContent": "Adăugat conținut nou",
+    "NotificationOptionInstallationFailed": "Eșec la instalare",
+    "NotificationOptionCameraImageUploaded": "Încarcată imagine cameră",
+    "NotificationOptionAudioPlaybackStopped": "Redare audio oprită",
+    "NotificationOptionAudioPlayback": "A inceput redarea audio",
+    "NotificationOptionApplicationUpdateInstalled": "Actualizarea aplicației a fost instalată",
+    "NotificationOptionApplicationUpdateAvailable": "Disponibilă o actualizare a aplicației",
+    "NewVersionIsAvailable": "O nouă versiune a Jellyfin Server este disponibilă pentru descărcare.",
+    "NameSeasonUnknown": "Sezon Necunoscut",
+    "NameSeasonNumber": "Sezonul {0}",
+    "NameInstallFailed": "{0} instalare eșuată",
+    "MusicVideos": "Videoclipuri muzicale",
+    "Music": "Muzică",
+    "Movies": "Filme",
+    "MixedContent": "Conținut mixt",
+    "MessageServerConfigurationUpdated": "Configurația serverului a fost actualizată",
+    "MessageNamedServerConfigurationUpdatedWithValue": "Secțiunea de configurare a serverului {0} a fost acualizata",
+    "MessageApplicationUpdatedTo": "Jellyfin Server a fost actualizat la {0}",
+    "MessageApplicationUpdated": "Jellyfin Server a fost actualizat",
+    "Latest": "Cele mai recente",
+    "LabelRunningTimeValue": "Durată: {0}",
+    "LabelIpAddressValue": "Adresa IP: {0}",
+    "ItemRemovedWithName": "{0} a fost eliminat din bibliotecă",
+    "ItemAddedWithName": "{0} a fost adăugat în bibliotecă",
+    "Inherit": "moștenit",
+    "HomeVideos": "Videoclipuri personale",
+    "HeaderRecordingGroups": "Grupuri de înregistrare",
+    "HeaderLiveTV": "TV în Direct",
+    "HeaderFavoriteSongs": "Melodii Favorite",
+    "HeaderFavoriteShows": "Spectacole Favorite",
+    "HeaderFavoriteEpisodes": "Episoade Favorite",
+    "HeaderFavoriteArtists": "Artiști Favoriți",
+    "HeaderFavoriteAlbums": "Albume Favorite",
+    "HeaderContinueWatching": "Vizionează în continuare",
+    "HeaderCameraUploads": "Incărcări Cameră Foto",
+    "HeaderAlbumArtists": "Album Artiști",
+    "Genres": "Genuri",
+    "Folders": "Dosare",
+    "Favorites": "Favorite",
+    "FailedLoginAttemptWithUserName": "Încercare de conectare nereușită de la {0}",
+    "DeviceOnlineWithName": "{0} este conectat",
+    "DeviceOfflineWithName": "{0} s-a deconectat",
+    "Collections": "Colecții",
+    "ChapterNameValue": "Capitol {0}",
+    "Channels": "Canale",
+    "CameraImageUploadedFrom": "O nouă fotografie a fost încărcată din {0}",
+    "Books": "Cărți",
+    "AuthenticationSucceededWithUserName": "{0} autentificare reușită",
+    "Artists": "Artiști",
+    "Application": "Aplicație",
+    "AppDeviceValues": "Aplicație: {0}, Dispozitiv: {1}",
+    "Albums": "Albume"
+}

+ 3 - 3
Emby.Server.Implementations/Localization/Core/zh-CN.json

@@ -24,7 +24,7 @@
     "HeaderFavoriteShows": "最爱的节目",
     "HeaderFavoriteSongs": "最爱的歌曲",
     "HeaderLiveTV": "电视直播",
-    "HeaderNextUp": "接下来",
+    "HeaderNextUp": "下一步",
     "HeaderRecordingGroups": "录制组",
     "HomeVideos": "家庭视频",
     "Inherit": "继承",
@@ -34,7 +34,7 @@
     "LabelRunningTimeValue": "运行时间:{0}",
     "Latest": "最新",
     "MessageApplicationUpdated": "Jellyfin 服务器已更新",
-    "MessageApplicationUpdatedTo": "Jellyfin Server 版本已更新为 {0}",
+    "MessageApplicationUpdatedTo": "Jellyfin Server 版本已更新为 {0}",
     "MessageNamedServerConfigurationUpdatedWithValue": "服务器配置 {0} 部分已更新",
     "MessageServerConfigurationUpdated": "服务器配置已更新",
     "MixedContent": "混合内容",
@@ -42,7 +42,7 @@
     "Music": "音乐",
     "MusicVideos": "音乐视频",
     "NameInstallFailed": "{0} 安装失败",
-    "NameSeasonNumber": "季 {0}",
+    "NameSeasonNumber": "第 {0} 季",
     "NameSeasonUnknown": "未知季",
     "NewVersionIsAvailable": "Jellyfin Server 有新版本可以下载。",
     "NotificationOptionApplicationUpdateAvailable": "有可用的应用程序更新",

+ 24 - 11
Emby.Server.Implementations/Playlists/PlaylistManager.cs

@@ -56,10 +56,8 @@ namespace Emby.Server.Implementations.Playlists
         {
             var name = options.Name;
 
-            var folderName = _fileSystem.GetValidFilename(name) + " [playlist]";
-
+            var folderName = _fileSystem.GetValidFilename(name);
             var parentFolder = GetPlaylistsFolder(Guid.Empty);
-
             if (parentFolder == null)
             {
                 throw new ArgumentException();
@@ -253,11 +251,13 @@ namespace Emby.Server.Implementations.Playlists
                 SavePlaylistFile(playlist);
             }
 
-            _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem))
-            {
-                ForceSave = true
-
-            }, RefreshPriority.High);
+            _providerManager.QueueRefresh(
+                playlist.Id,
+                new MetadataRefreshOptions(new DirectoryService(_fileSystem))
+                {
+                    ForceSave = true
+                },
+                RefreshPriority.High);
         }
 
         public void MoveItem(string playlistId, string entryId, int newIndex)
@@ -303,7 +303,8 @@ namespace Emby.Server.Implementations.Playlists
 
         private void SavePlaylistFile(Playlist item)
         {
-            // This is probably best done as a metatata provider, but saving a file over itself will first require some core work to prevent this from happening when not needed
+            // this is probably best done as a metadata provider
+            // saving a file over itself will require some work to prevent this from happening when not needed
             var playlistPath = item.Path;
             var extension = Path.GetExtension(playlistPath);
 
@@ -335,12 +336,14 @@ namespace Emby.Server.Implementations.Playlists
                     {
                         entry.Duration = TimeSpan.FromTicks(child.RunTimeTicks.Value);
                     }
+
                     playlist.PlaylistEntries.Add(entry);
                 }
 
                 string text = new WplContent().ToText(playlist);
                 File.WriteAllText(playlistPath, text);
             }
+
             if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase))
             {
                 var playlist = new ZplPlaylist();
@@ -375,6 +378,7 @@ namespace Emby.Server.Implementations.Playlists
                 string text = new ZplContent().ToText(playlist);
                 File.WriteAllText(playlistPath, text);
             }
+
             if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase))
             {
                 var playlist = new M3uPlaylist();
@@ -398,12 +402,14 @@ namespace Emby.Server.Implementations.Playlists
                     {
                         entry.Duration = TimeSpan.FromTicks(child.RunTimeTicks.Value);
                     }
+
                     playlist.PlaylistEntries.Add(entry);
                 }
 
                 string text = new M3uContent().ToText(playlist);
                 File.WriteAllText(playlistPath, text);
             }
+
             if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase))
             {
                 var playlist = new M3uPlaylist();
@@ -427,12 +433,14 @@ namespace Emby.Server.Implementations.Playlists
                     {
                         entry.Duration = TimeSpan.FromTicks(child.RunTimeTicks.Value);
                     }
+
                     playlist.PlaylistEntries.Add(entry);
                 }
 
                 string text = new M3u8Content().ToText(playlist);
                 File.WriteAllText(playlistPath, text);
             }
+
             if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase))
             {
                 var playlist = new PlsPlaylist();
@@ -448,6 +456,7 @@ namespace Emby.Server.Implementations.Playlists
                     {
                         entry.Length = TimeSpan.FromTicks(child.RunTimeTicks.Value);
                     }
+
                     playlist.PlaylistEntries.Add(entry);
                 }
 
@@ -473,7 +482,7 @@ namespace Emby.Server.Implementations.Playlists
                 throw new ArgumentException("File absolute path was null or empty.", nameof(fileAbsolutePath));
             }
 
-            if (!folderPath.EndsWith(Path.DirectorySeparatorChar.ToString()))
+            if (!folderPath.EndsWith(Path.DirectorySeparatorChar))
             {
                 folderPath = folderPath + Path.DirectorySeparatorChar;
             }
@@ -481,7 +490,11 @@ namespace Emby.Server.Implementations.Playlists
             var folderUri = new Uri(folderPath);
             var fileAbsoluteUri = new Uri(fileAbsolutePath);
 
-            if (folderUri.Scheme != fileAbsoluteUri.Scheme) { return fileAbsolutePath; } // path can't be made relative.
+            // path can't be made relative
+            if (folderUri.Scheme != fileAbsoluteUri.Scheme)
+            {
+                return fileAbsolutePath;
+            }
 
             var relativeUri = folderUri.MakeRelativeUri(fileAbsoluteUri);
             string relativePath = Uri.UnescapeDataString(relativeUri.ToString());

+ 2 - 2
Emby.Server.Implementations/Updates/InstallationManager.cs

@@ -1,10 +1,10 @@
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
-using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Net.Http;
+using System.Runtime.CompilerServices;
 using System.Security.Cryptography;
 using System.Threading;
 using System.Threading.Tasks;
@@ -189,7 +189,7 @@ namespace Emby.Server.Implementations.Updates
         }
 
         /// <inheritdoc />
-        public async IAsyncEnumerable<PackageVersionInfo> GetAvailablePluginUpdates(CancellationToken cancellationToken = default)
+        public async IAsyncEnumerable<PackageVersionInfo> GetAvailablePluginUpdates([EnumeratorCancellation] CancellationToken cancellationToken = default)
         {
             var catalog = await GetAvailablePackages(cancellationToken).ConfigureAwait(false);
 

+ 0 - 1
Jellyfin.Api/Controllers/StartupController.cs

@@ -96,7 +96,6 @@ namespace Jellyfin.Api.Controllers
         public StartupUserDto GetFirstUser()
         {
             var user = _userManager.Users.First();
-
             return new StartupUserDto
             {
                 Name = user.Name,

+ 1 - 1
Jellyfin.Api/Jellyfin.Api.csproj

@@ -17,7 +17,7 @@
     <ProjectReference Include="..\MediaBrowser.Controller\MediaBrowser.Controller.csproj" />
   </ItemGroup>
 
-  <!-- Code analysers-->
+  <!-- Code Analyzers-->
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
     <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7" PrivateAssets="All" />
     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />

+ 13 - 0
Jellyfin.Drawing.Skia/Jellyfin.Drawing.Skia.csproj

@@ -4,6 +4,7 @@
     <TargetFramework>netstandard2.1</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
 
   <ItemGroup>
@@ -22,4 +23,16 @@
     <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
   </ItemGroup>
 
+  <!-- Code analysers-->
+  <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7" PrivateAssets="All" />
+    <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+    <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+  </ItemGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+
 </Project>

+ 9 - 0
Jellyfin.Drawing.Skia/PercentPlayedDrawer.cs

@@ -4,10 +4,19 @@ using SkiaSharp;
 
 namespace Jellyfin.Drawing.Skia
 {
+    /// <summary>
+    /// Static helper class used to draw percentage-played indicators on images.
+    /// </summary>
     public static class PercentPlayedDrawer
     {
         private const int IndicatorHeight = 8;
 
+        /// <summary>
+        /// Draw a percentage played indicator on a canvas.
+        /// </summary>
+        /// <param name="canvas">The canvas to draw the indicator on.</param>
+        /// <param name="imageSize">The size of the image being drawn on.</param>
+        /// <param name="percent">The percentage played to display with the indicator.</param>
         public static void Process(SKCanvas canvas, ImageDimensions imageSize, double percent)
         {
             using (var paint = new SKPaint())

+ 13 - 2
Jellyfin.Drawing.Skia/PlayedIndicatorDrawer.cs

@@ -3,10 +3,21 @@ using SkiaSharp;
 
 namespace Jellyfin.Drawing.Skia
 {
+    /// <summary>
+    /// Static helper class for drawing 'played' indicators.
+    /// </summary>
     public static class PlayedIndicatorDrawer
     {
         private const int OffsetFromTopRightCorner = 38;
 
+        /// <summary>
+        /// Draw a 'played' indicator in the top right corner of a canvas.
+        /// </summary>
+        /// <param name="canvas">The canvas to draw the indicator on.</param>
+        /// <param name="imageSize">
+        /// The dimensions of the image to draw the indicator on. The width is used to determine the x-position of the
+        /// indicator.
+        /// </param>
         public static void DrawPlayedIndicator(SKCanvas canvas, ImageDimensions imageSize)
         {
             var x = imageSize.Width - OffsetFromTopRightCorner;
@@ -26,10 +37,10 @@ namespace Jellyfin.Drawing.Skia
                 paint.TextSize = 30;
                 paint.IsAntialias = true;
 
+                // or:
+                // var emojiChar = 0x1F680;
                 var text = "✔️";
                 var emojiChar = StringUtilities.GetUnicodeCharacterCode(text, SKTextEncoding.Utf32);
-                // or:
-                //var emojiChar = 0x1F680;
 
                 // ask the font manager for a font with that character
                 var fontManager = SKFontManager.Default;

+ 8 - 8
Jellyfin.Drawing.Skia/SkiaCodecException.cs

@@ -1,3 +1,4 @@
+using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using SkiaSharp;
 
@@ -8,16 +9,10 @@ namespace Jellyfin.Drawing.Skia
     /// </summary>
     public class SkiaCodecException : SkiaException
     {
-        /// <summary>
-        /// Returns the non-successfull codec result returned by Skia.
-        /// </summary>
-        /// <value>The non-successfull codec result returned by Skia.</value>
-        public SKCodecResult CodecResult { get; }
-
         /// <summary>
         /// Initializes a new instance of the <see cref="SkiaCodecException" /> class.
         /// </summary>
-        /// <param name="result">The non-successfull codec result returned by Skia.</param>
+        /// <param name="result">The non-successful codec result returned by Skia.</param>
         public SkiaCodecException(SKCodecResult result) : base()
         {
             CodecResult = result;
@@ -27,7 +22,7 @@ namespace Jellyfin.Drawing.Skia
         /// Initializes a new instance of the <see cref="SkiaCodecException" /> class
         /// with a specified error message.
         /// </summary>
-        /// <param name="result">The non-successfull codec result returned by Skia.</param>
+        /// <param name="result">The non-successful codec result returned by Skia.</param>
         /// <param name="message">The message that describes the error.</param>
         public SkiaCodecException(SKCodecResult result, string message)
             : base(message)
@@ -35,6 +30,11 @@ namespace Jellyfin.Drawing.Skia
             CodecResult = result;
         }
 
+        /// <summary>
+        /// Gets the non-successful codec result returned by Skia.
+        /// </summary>
+        public SKCodecResult CodecResult { get; }
+
         /// <inheritdoc />
         public override string ToString()
             => string.Format(

Неке датотеке нису приказане због велике количине промена