Allow streaming of raw PGS subtitles without transcoding (#12056)

pull/12280/head
David Schulte 7 months ago committed by GitHub
parent 3262f8dc2a
commit fc1bee30a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -113,6 +113,11 @@ namespace Emby.Server.Implementations.Library
return true; return true;
} }
if (stream.IsPgsSubtitleStream)
{
return true;
}
return false; return false;
} }

@ -198,10 +198,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{ {
if (!subtitleStream.IsExternal || subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) 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 outputFileExtension = GetExtractableSubtitleFileExtension(subtitleStream);
var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + outputFormat); var outputFormat = GetExtractableSubtitleFormat(subtitleStream);
var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + outputFileExtension);
return new SubtitleInfo() return new SubtitleInfo()
{ {
@ -215,6 +216,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec) var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec)
.TrimStart('.'); .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 // Fallback to ffmpeg conversion
if (!_subtitleParser.SupportsFileExtension(currentFormat)) if (!_subtitleParser.SupportsFileExtension(currentFormat))
{ {
@ -428,10 +441,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
_logger.LogInformation("ffmpeg subtitle conversion succeeded for {Path}", inputPath); _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) 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; 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) private bool IsCodecCopyable(string codec)
{ {
return string.Equals(codec, "ass", StringComparison.OrdinalIgnoreCase) return string.Equals(codec, "ass", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codec, "ssa", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "ssa", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codec, "srt", 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> /// <summary>
/// Extracts all text subtitles. /// Extracts all extractable subtitles (text and pgs).
/// </summary> /// </summary>
/// <param name="mediaSource">The mediaSource.</param> /// <param name="mediaSource">The mediaSource.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <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 locks = new List<IDisposable>();
var extractableStreams = new List<MediaStream>(); var extractableStreams = new List<MediaStream>();
@ -463,11 +491,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
try try
{ {
var subtitleStreams = mediaSource.MediaStreams 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) 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); var releaser = await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false);
@ -483,7 +511,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (extractableStreams.Count > 0) if (extractableStreams.Count > 0)
{ {
await ExtractAllTextSubtitlesInternal(mediaSource, extractableStreams, cancellationToken).ConfigureAwait(false); await ExtractAllExtractableSubtitlesInternal(mediaSource, extractableStreams, cancellationToken).ConfigureAwait(false);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -496,7 +524,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
} }
} }
private async Task ExtractAllTextSubtitlesInternal( private async Task ExtractAllExtractableSubtitlesInternal(
MediaSourceInfo mediaSource, MediaSourceInfo mediaSource,
List<MediaStream> subtitleStreams, List<MediaStream> subtitleStreams,
CancellationToken cancellationToken) CancellationToken cancellationToken)
@ -510,7 +538,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
foreach (var subtitleStream in subtitleStreams) 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 outputCodec = IsCodecCopyable(subtitleStream.Codec) ? "copy" : "srt";
var streamIndex = EncodingHelper.FindIndex(mediaSource.MediaStreams, subtitleStream); var streamIndex = EncodingHelper.FindIndex(mediaSource.MediaStreams, subtitleStream);

@ -585,6 +585,31 @@ namespace MediaBrowser.Model.Entities
} }
} }
public bool IsPgsSubtitleStream
{
get
{
if (Type != MediaStreamType.Subtitle)
{
return false;
}
if (string.IsNullOrEmpty(Codec) && !IsExternal)
{
return false;
}
return IsPgsFormat(Codec);
}
}
/// <summary>
/// Gets a value indicating whether this is a subtitle steam that is extractable by ffmpeg.
/// All text-based and pgs subtitles can be extracted.
/// </summary>
/// <value><c>true</c> if this is a extractable subtitle steam otherwise, <c>false</c>.</value>
public bool IsExtractableSubtitleStream => IsTextSubtitleStream || IsPgsSubtitleStream;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether [supports external stream]. /// Gets or sets a value indicating whether [supports external stream].
/// </summary> /// </summary>
@ -666,6 +691,14 @@ namespace MediaBrowser.Model.Entities
&& !string.Equals(codec, "sub", StringComparison.OrdinalIgnoreCase)); && !string.Equals(codec, "sub", StringComparison.OrdinalIgnoreCase));
} }
public static bool IsPgsFormat(string format)
{
string codec = format ?? string.Empty;
return codec.Contains("pgs", StringComparison.OrdinalIgnoreCase)
|| string.Equals(codec, "sup", StringComparison.OrdinalIgnoreCase);
}
public bool SupportsSubtitleConversionTo(string toCodec) public bool SupportsSubtitleConversionTo(string toCodec)
{ {
if (!IsTextSubtitleStream) if (!IsTextSubtitleStream)

Loading…
Cancel
Save