aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.MediaEncoding')
-rw-r--r--MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs1
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs36
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs25
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs54
-rw-r--r--MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs11
6 files changed, 80 insertions, 49 deletions
diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
index 8ebb59c59..5bae4fbd5 100644
--- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
+++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs
@@ -86,7 +86,7 @@ public class BdInfoExaminer : IBlurayExaminer
if (playlist.StreamClips is not null && playlist.StreamClips.Count > 0)
{
// Get the files in the playlist
- outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.Name).ToArray();
+ outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.FileInfo.FullName).ToArray();
}
return outputStream;
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
index ec39f159e..30bb21dcb 100644
--- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs
@@ -103,6 +103,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// sw
"alphasrc",
"zscale",
+ "tonemapx",
// qsv
"scale_qsv",
"vpp_qsv",
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index 390891fcf..de1b65482 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -708,16 +708,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
filters.Add("thumbnail=n=" + (useLargerBatchSize ? "50" : "24"));
}
- // Use SW tonemap on HDR10/HLG video stream only when the zscale filter is available.
+ // Use SW tonemap on HDR10/HLG video stream only when the zscale or tonemapx filter is available.
var enableHdrExtraction = false;
- if ((string.Equals(videoStream?.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)
+ if (string.Equals(videoStream?.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase)
|| string.Equals(videoStream?.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase))
- && SupportsFilter("zscale"))
{
- enableHdrExtraction = true;
-
- filters.Add("zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0:peak=100,zscale=t=bt709:m=bt709,format=yuv420p");
+ if (SupportsFilter("tonemapx"))
+ {
+ enableHdrExtraction = true;
+ filters.Add("tonemapx=tonemap=bt2390:desat=0:peak=100:t=bt709:m=bt709:p=bt709:format=yuv420p");
+ }
+ else if (SupportsFilter("zscale"))
+ {
+ enableHdrExtraction = true;
+ filters.Add("zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0:peak=100,zscale=t=bt709:m=bt709,format=yuv420p");
+ }
}
var vf = string.Join(',', filters);
@@ -1170,18 +1176,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// <inheritdoc />
public IReadOnlyList<string> GetPrimaryPlaylistM2tsFiles(string path)
- {
- // Get all playable .m2ts files
- var validPlaybackFiles = _blurayExaminer.GetDiscInfo(path).Files;
-
- // Get all files from the BDMV/STREAMING directory
- // Only return playable local .m2ts files
- var files = _fileSystem.GetFiles(Path.Join(path, "BDMV", "STREAM")).ToList();
- return validPlaybackFiles
- .Select(validFile => files.FirstOrDefault(f => Path.GetFileName(f.FullName.AsSpan()).Equals(validFile, StringComparison.OrdinalIgnoreCase))?.FullName)
- .Where(f => f is not null)
- .ToList();
- }
+ => _blurayExaminer.GetDiscInfo(path).Files;
/// <inheritdoc />
public string GetInputPathArgument(EncodingJobInfo state)
@@ -1192,8 +1187,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
{
return mediaSource.VideoType switch
{
- VideoType.Dvd => GetInputArgument(GetPrimaryPlaylistVobFiles(path, null).ToList(), mediaSource),
- VideoType.BluRay => GetInputArgument(GetPrimaryPlaylistM2tsFiles(path).ToList(), mediaSource),
+ VideoType.Dvd => GetInputArgument(GetPrimaryPlaylistVobFiles(path, null), mediaSource),
+ VideoType.BluRay => GetInputArgument(GetPrimaryPlaylistM2tsFiles(path), mediaSource),
_ => GetInputArgument(path, mediaSource)
};
}
@@ -1218,6 +1213,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
// Generate concat configuration entries for each file and write to file
+ Directory.CreateDirectory(Path.GetDirectoryName(concatFilePath));
using StreamWriter sw = new StreamWriter(concatFilePath);
foreach (var path in files)
{
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 8b2685fe1..f5185398c 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -1319,23 +1319,38 @@ namespace MediaBrowser.MediaEncoding.Probing
// These support multiple values, but for now we only store the first.
var mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Album Artist Id"))
?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_ALBUMARTISTID"));
- audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, mb);
+ if (!string.IsNullOrEmpty(mb))
+ {
+ audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, mb);
+ }
mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Artist Id"))
?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_ARTISTID"));
- audio.SetProviderId(MetadataProvider.MusicBrainzArtist, mb);
+ if (!string.IsNullOrEmpty(mb))
+ {
+ audio.SetProviderId(MetadataProvider.MusicBrainzArtist, mb);
+ }
mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Album Id"))
?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_ALBUMID"));
- audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, mb);
+ if (!string.IsNullOrEmpty(mb))
+ {
+ audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, mb);
+ }
mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Release Group Id"))
?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_RELEASEGROUPID"));
- audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, mb);
+ if (!string.IsNullOrEmpty(mb))
+ {
+ audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, mb);
+ }
mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Release Track Id"))
?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_RELEASETRACKID"));
- audio.SetProviderId(MetadataProvider.MusicBrainzTrack, mb);
+ if (!string.IsNullOrEmpty(mb))
+ {
+ audio.SetProviderId(MetadataProvider.MusicBrainzTrack, mb);
+ }
}
private string GetMultipleMusicBrainzId(string value)
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 16837d98b..9ecbfa9cf 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -198,10 +198,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
if (!subtitleStream.IsExternal || subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase))
{
- await ExtractAllTextSubtitles(mediaSource, cancellationToken).ConfigureAwait(false);
+ await ExtractAllExtractableSubtitles(mediaSource, cancellationToken).ConfigureAwait(false);
- var outputFormat = GetTextSubtitleFormat(subtitleStream);
- var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + outputFormat);
+ var outputFileExtension = GetExtractableSubtitleFileExtension(subtitleStream);
+ var outputFormat = GetExtractableSubtitleFormat(subtitleStream);
+ var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + outputFileExtension);
return new SubtitleInfo()
{
@@ -215,6 +216,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec)
.TrimStart('.');
+ // Handle PGS subtitles as raw streams for the client to render
+ if (MediaStream.IsPgsFormat(currentFormat))
+ {
+ return new SubtitleInfo()
+ {
+ Path = subtitleStream.Path,
+ Protocol = _mediaSourceManager.GetPathProtocol(subtitleStream.Path),
+ Format = "pgssub",
+ IsExternal = true
+ };
+ }
+
// Fallback to ffmpeg conversion
if (!_subtitleParser.SupportsFileExtension(currentFormat))
{
@@ -428,10 +441,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_logger.LogInformation("ffmpeg subtitle conversion succeeded for {Path}", inputPath);
}
- private string GetTextSubtitleFormat(MediaStream subtitleStream)
+ private string GetExtractableSubtitleFormat(MediaStream subtitleStream)
{
if (string.Equals(subtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase)
- || string.Equals(subtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase))
+ || string.Equals(subtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(subtitleStream.Codec, "pgssub", StringComparison.OrdinalIgnoreCase))
{
return subtitleStream.Codec;
}
@@ -441,21 +455,35 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
}
+ private string GetExtractableSubtitleFileExtension(MediaStream subtitleStream)
+ {
+ // Using .pgssub as file extension is not allowed by ffmpeg. The file extension for pgs subtitles is .sup.
+ if (string.Equals(subtitleStream.Codec, "pgssub", StringComparison.OrdinalIgnoreCase))
+ {
+ return "sup";
+ }
+ else
+ {
+ return GetExtractableSubtitleFormat(subtitleStream);
+ }
+ }
+
private bool IsCodecCopyable(string codec)
{
return string.Equals(codec, "ass", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codec, "ssa", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codec, "srt", StringComparison.OrdinalIgnoreCase)
- || string.Equals(codec, "subrip", StringComparison.OrdinalIgnoreCase);
+ || string.Equals(codec, "subrip", StringComparison.OrdinalIgnoreCase)
+ || string.Equals(codec, "pgssub", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
- /// Extracts all text subtitles.
+ /// Extracts all extractable subtitles (text and pgs).
/// </summary>
/// <param name="mediaSource">The mediaSource.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
- private async Task ExtractAllTextSubtitles(MediaSourceInfo mediaSource, CancellationToken cancellationToken)
+ private async Task ExtractAllExtractableSubtitles(MediaSourceInfo mediaSource, CancellationToken cancellationToken)
{
var locks = new List<IDisposable>();
var extractableStreams = new List<MediaStream>();
@@ -463,11 +491,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
try
{
var subtitleStreams = mediaSource.MediaStreams
- .Where(stream => stream is { IsTextSubtitleStream: true, SupportsExternalStream: true, IsExternal: false });
+ .Where(stream => stream is { IsExtractableSubtitleStream: true, SupportsExternalStream: true, IsExternal: false });
foreach (var subtitleStream in subtitleStreams)
{
- var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetTextSubtitleFormat(subtitleStream));
+ var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetExtractableSubtitleFileExtension(subtitleStream));
var releaser = await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false);
@@ -483,7 +511,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (extractableStreams.Count > 0)
{
- await ExtractAllTextSubtitlesInternal(mediaSource, extractableStreams, cancellationToken).ConfigureAwait(false);
+ await ExtractAllExtractableSubtitlesInternal(mediaSource, extractableStreams, cancellationToken).ConfigureAwait(false);
}
}
catch (Exception ex)
@@ -496,7 +524,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
}
}
- private async Task ExtractAllTextSubtitlesInternal(
+ private async Task ExtractAllExtractableSubtitlesInternal(
MediaSourceInfo mediaSource,
List<MediaStream> subtitleStreams,
CancellationToken cancellationToken)
@@ -510,7 +538,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
foreach (var subtitleStream in subtitleStreams)
{
- var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetTextSubtitleFormat(subtitleStream));
+ var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetExtractableSubtitleFileExtension(subtitleStream));
var outputCodec = IsCodecCopyable(subtitleStream.Codec) ? "copy" : "srt";
var streamIndex = EncodingHelper.FindIndex(mediaSource.MediaStreams, subtitleStream);
diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs
index ea5dbf7f7..0b09e57b5 100644
--- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs
+++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs
@@ -235,15 +235,6 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable
if (delete(job.Path!))
{
await DeletePartialStreamFiles(job.Path!, job.Type, 0, 1500).ConfigureAwait(false);
- if (job.MediaSource?.VideoType == VideoType.Dvd || job.MediaSource?.VideoType == VideoType.BluRay)
- {
- var concatFilePath = Path.Join(_serverConfigurationManager.GetTranscodePath(), job.MediaSource.Id + ".concat");
- if (File.Exists(concatFilePath))
- {
- _logger.LogInformation("Deleting ffmpeg concat configuration at {Path}", concatFilePath);
- File.Delete(concatFilePath);
- }
- }
}
if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId))
@@ -419,7 +410,7 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable
var attachmentPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id);
if (state.MediaSource.VideoType == VideoType.Dvd || state.MediaSource.VideoType == VideoType.BluRay)
{
- var concatPath = Path.Join(_serverConfigurationManager.GetTranscodePath(), state.MediaSource.Id + ".concat");
+ var concatPath = Path.Join(_appPaths.CachePath, "concat", state.MediaSource.Id + ".concat");
await _attachmentExtractor.ExtractAllAttachments(concatPath, state.MediaSource, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false);
}
else