Add probe / direct-stream / transcoding support for BluRays

This commit (and ffmpeg built with libbluray support), adds support
for playback of bluray images (bd-iso) and bluray folders.
This commit is contained in:
Stanislav Ionascu 2020-09-24 08:41:42 +02:00
parent c7b3d4a90c
commit 3ad6232973
11 changed files with 101 additions and 102 deletions

View File

@ -12,6 +12,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
@ -81,12 +82,7 @@ namespace Emby.Server.Implementations.MediaEncoder
return false; return false;
} }
if (video.VideoType == VideoType.Iso) if (video.VideoType == VideoType.Dvd)
{
return false;
}
if (video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd)
{ {
return false; return false;
} }
@ -140,15 +136,19 @@ namespace Emby.Server.Implementations.MediaEncoder
// Add some time for the first chapter to make sure we don't end up with a black image // Add some time for the first chapter to make sure we don't end up with a black image
var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(_firstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks); var time = chapter.StartPositionTicks == 0 ? TimeSpan.FromTicks(Math.Min(_firstChapterTicks, video.RunTimeTicks ?? 0)) : TimeSpan.FromTicks(chapter.StartPositionTicks);
var protocol = MediaProtocol.File; var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, Array.Empty<string>());
var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, video.Path, null, Array.Empty<string>());
Directory.CreateDirectory(Path.GetDirectoryName(path)); Directory.CreateDirectory(Path.GetDirectoryName(path));
var container = video.Container; var container = video.Container;
var mediaSource = new MediaSourceInfo
{
VideoType = video.VideoType,
IsoType = video.IsoType,
Protocol = video.PathProtocol.Value,
};
var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); var tempFile = await _encoder.ExtractVideoImage(inputPath, container, mediaSource, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false);
File.Copy(tempFile, path, true); File.Copy(tempFile, path, true);
try try

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
@ -762,7 +762,7 @@ namespace Jellyfin.Api.Helpers
private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource) private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource)
{ {
if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && _isoManager.CanMount(state.MediaPath)) if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && state.IsoType == IsoType.Dvd && _isoManager.CanMount(state.MediaPath))
{ {
state.IsoMount = await _isoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false); state.IsoMount = await _isoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false);
} }

View File

@ -379,25 +379,9 @@ namespace MediaBrowser.Controller.MediaEncoding
public string GetInputPathArgument(EncodingJobInfo state) public string GetInputPathArgument(EncodingJobInfo state)
{ {
var protocol = state.InputProtocol;
var mediaPath = state.MediaPath ?? string.Empty; var mediaPath = state.MediaPath ?? string.Empty;
string[] inputPath; return _mediaEncoder.GetInputArgument(mediaPath, state.MediaSource);
if (state.IsInputVideo
&& !(state.VideoType == VideoType.Iso && state.IsoMount == null))
{
inputPath = MediaEncoderHelpers.GetInputArgument(
_fileSystem,
mediaPath,
state.IsoMount,
state.PlayableStreamFileNames);
}
else
{
inputPath = new[] { mediaPath };
}
return _mediaEncoder.GetInputArgument(inputPath, protocol);
} }
/// <summary> /// <summary>
@ -2546,14 +2530,10 @@ namespace MediaBrowser.Controller.MediaEncoding
{ {
state.VideoType = mediaSource.VideoType.Value; state.VideoType = mediaSource.VideoType.Value;
if (mediaSource.VideoType.Value == VideoType.BluRay || mediaSource.VideoType.Value == VideoType.Dvd) if (mediaSource.VideoType.Value == VideoType.Dvd)
{ {
state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, mediaSource.VideoType.Value).Select(Path.GetFileName).ToArray(); state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, mediaSource.VideoType.Value).Select(Path.GetFileName).ToArray();
} }
else if (mediaSource.VideoType.Value == VideoType.Iso && state.IsoType == IsoType.BluRay)
{
state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, VideoType.BluRay).Select(Path.GetFileName).ToArray();
}
else if (mediaSource.VideoType.Value == VideoType.Iso && state.IsoType == IsoType.Dvd) else if (mediaSource.VideoType.Value == VideoType.Iso && state.IsoType == IsoType.Dvd)
{ {
state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, VideoType.Dvd).Select(Path.GetFileName).ToArray(); state.PlayableStreamFileNames = Video.QueryPlayableStreamFiles(state.MediaPath, VideoType.Dvd).Select(Path.GetFileName).ToArray();

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
@ -61,9 +62,9 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary> /// <summary>
/// Extracts the video image. /// Extracts the video image.
/// </summary> /// </summary>
Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaSourceInfo mediaSource, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken); Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Extracts the video images on interval. /// Extracts the video images on interval.
@ -71,7 +72,7 @@ namespace MediaBrowser.Controller.MediaEncoding
Task ExtractVideoImagesOnInterval(string[] inputFiles, Task ExtractVideoImagesOnInterval(string[] inputFiles,
string container, string container,
MediaStream videoStream, MediaStream videoStream,
MediaProtocol protocol, MediaSourceInfo mediaSource,
Video3DFormat? threedFormat, Video3DFormat? threedFormat,
TimeSpan interval, TimeSpan interval,
string targetDirectory, string targetDirectory,
@ -91,9 +92,9 @@ namespace MediaBrowser.Controller.MediaEncoding
/// Gets the input argument. /// Gets the input argument.
/// </summary> /// </summary>
/// <param name="inputFiles">The input files.</param> /// <param name="inputFiles">The input files.</param>
/// <param name="protocol">The protocol.</param> /// <param name="mediaSource">The mediaSource.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
string GetInputArgument(IReadOnlyList<string> inputFiles, MediaProtocol protocol); string GetInputArgument(IReadOnlyList<string> inputFiles, MediaSourceInfo mediaSource);
/// <summary> /// <summary>
/// Gets the time parameter. /// Gets the time parameter.

View File

@ -18,19 +18,13 @@ namespace MediaBrowser.Controller.MediaEncoding
/// </summary> /// </summary>
/// <param name="fileSystem">The file system.</param> /// <param name="fileSystem">The file system.</param>
/// <param name="videoPath">The video path.</param> /// <param name="videoPath">The video path.</param>
/// <param name="isoMount">The iso mount.</param>
/// <param name="playableStreamFileNames">The playable stream file names.</param> /// <param name="playableStreamFileNames">The playable stream file names.</param>
/// <returns>string[].</returns> /// <returns>string[].</returns>
public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, IIsoMount isoMount, IReadOnlyCollection<string> playableStreamFileNames) public static string[] GetInputArgument(IFileSystem fileSystem, string videoPath, IReadOnlyCollection<string> playableStreamFileNames)
{ {
if (playableStreamFileNames.Count > 0) if (playableStreamFileNames.Count > 0)
{ {
if (isoMount == null) return GetPlayableStreamFiles(fileSystem, videoPath, playableStreamFileNames);
{
return GetPlayableStreamFiles(fileSystem, videoPath, playableStreamFileNames);
}
return GetPlayableStreamFiles(fileSystem, isoMount.MountedPath, playableStreamFileNames);
} }
return new[] { videoPath }; return new[] { videoPath };

View File

@ -87,19 +87,19 @@ namespace MediaBrowser.MediaEncoding.Attachments
MediaAttachment mediaAttachment, MediaAttachment mediaAttachment,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var attachmentPath = await GetReadableFile(mediaSource.Path, mediaSource.Path, mediaSource.Protocol, mediaAttachment, cancellationToken).ConfigureAwait(false); var attachmentPath = await GetReadableFile(mediaSource.Path, mediaSource.Path, mediaSource, mediaAttachment, cancellationToken).ConfigureAwait(false);
return File.OpenRead(attachmentPath); return File.OpenRead(attachmentPath);
} }
private async Task<string> GetReadableFile( private async Task<string> GetReadableFile(
string mediaPath, string mediaPath,
string inputFile, string inputFile,
MediaProtocol protocol, MediaSourceInfo mediaSource,
MediaAttachment mediaAttachment, MediaAttachment mediaAttachment,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var outputPath = GetAttachmentCachePath(mediaPath, protocol, mediaAttachment.Index); var outputPath = GetAttachmentCachePath(mediaPath, mediaSource, mediaAttachment.Index);
await ExtractAttachment(inputFile, protocol, mediaAttachment.Index, outputPath, cancellationToken) await ExtractAttachment(inputFile, mediaSource, mediaAttachment.Index, outputPath, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
return outputPath; return outputPath;
@ -107,7 +107,7 @@ namespace MediaBrowser.MediaEncoding.Attachments
private async Task ExtractAttachment( private async Task ExtractAttachment(
string inputFile, string inputFile,
MediaProtocol protocol, MediaSourceInfo mediaSource,
int attachmentStreamIndex, int attachmentStreamIndex,
string outputPath, string outputPath,
CancellationToken cancellationToken) CancellationToken cancellationToken)
@ -121,7 +121,7 @@ namespace MediaBrowser.MediaEncoding.Attachments
if (!File.Exists(outputPath)) if (!File.Exists(outputPath))
{ {
await ExtractAttachmentInternal( await ExtractAttachmentInternal(
_mediaEncoder.GetInputArgument(new[] { inputFile }, protocol), _mediaEncoder.GetInputArgument(new[] { inputFile }, mediaSource),
attachmentStreamIndex, attachmentStreamIndex,
outputPath, outputPath,
cancellationToken).ConfigureAwait(false); cancellationToken).ConfigureAwait(false);
@ -234,10 +234,10 @@ namespace MediaBrowser.MediaEncoding.Attachments
} }
} }
private string GetAttachmentCachePath(string mediaPath, MediaProtocol protocol, int attachmentStreamIndex) private string GetAttachmentCachePath(string mediaPath, MediaSourceInfo mediaSource, int attachmentStreamIndex)
{ {
string filename; string filename;
if (protocol == MediaProtocol.File) if (mediaSource.Protocol == MediaProtocol.File)
{ {
var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); var date = _fileSystem.GetLastWriteTimeUtc(mediaPath);
filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture); filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D", CultureInfo.InvariantCulture);

View File

@ -10,7 +10,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
public static class EncodingUtils public static class EncodingUtils
{ {
public static string GetInputArgument(IReadOnlyList<string> inputFiles, MediaProtocol protocol) public static string GetInputArgument(string inputPrefix, IReadOnlyList<string> inputFiles, MediaProtocol protocol)
{ {
if (protocol != MediaProtocol.File) if (protocol != MediaProtocol.File)
{ {
@ -19,15 +19,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", url); return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", url);
} }
return GetConcatInputArgument(inputFiles); return GetConcatInputArgument(inputFiles, inputPrefix);
} }
/// <summary> /// <summary>
/// Gets the concat input argument. /// Gets the concat input argument.
/// </summary> /// </summary>
/// <param name="inputFiles">The input files.</param> /// <param name="inputFiles">The input files.</param>
/// <param name="inputPrefix">The input prefix.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
private static string GetConcatInputArgument(IReadOnlyList<string> inputFiles) private static string GetConcatInputArgument(IReadOnlyList<string> inputFiles, string inputPrefix)
{ {
// Get all streams // Get all streams
// If there's more than one we'll need to use the concat command // If there's more than one we'll need to use the concat command
@ -39,15 +40,16 @@ namespace MediaBrowser.MediaEncoding.Encoder
} }
// Determine the input path for video files // Determine the input path for video files
return GetFileInputArgument(inputFiles[0]); return GetFileInputArgument(inputFiles[0], inputPrefix);
} }
/// <summary> /// <summary>
/// Gets the file input argument. /// Gets the file input argument.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <param name="inputPrefix">The path prefix.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
private static string GetFileInputArgument(string path) private static string GetFileInputArgument(string path, string inputPrefix)
{ {
if (path.IndexOf("://", StringComparison.Ordinal) != -1) if (path.IndexOf("://", StringComparison.Ordinal) != -1)
{ {
@ -57,7 +59,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// Quotes are valid path characters in linux and they need to be escaped here with a leading \ // Quotes are valid path characters in linux and they need to be escaped here with a leading \
path = NormalizePath(path); path = NormalizePath(path);
return string.Format(CultureInfo.InvariantCulture, "file:\"{0}\"", path); return string.Format(CultureInfo.InvariantCulture, "{1}:\"{0}\"", path, inputPrefix);
} }
/// <summary> /// <summary>

View File

@ -18,6 +18,7 @@ using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.MediaEncoding.Probing; using MediaBrowser.MediaEncoding.Probing;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
@ -319,7 +320,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
{ {
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters; var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
var inputFiles = MediaEncoderHelpers.GetInputArgument(_fileSystem, request.MediaSource.Path, request.MountedIso, request.PlayableStreamFileNames); var inputFiles = MediaEncoderHelpers.GetInputArgument(_fileSystem, request.MediaSource.Path, request.PlayableStreamFileNames);
var probeSize = EncodingHelper.GetProbeSizeArgument(inputFiles.Length); var probeSize = EncodingHelper.GetProbeSizeArgument(inputFiles.Length);
string analyzeDuration; string analyzeDuration;
@ -340,7 +341,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
var forceEnableLogging = request.MediaSource.Protocol != MediaProtocol.File; var forceEnableLogging = request.MediaSource.Protocol != MediaProtocol.File;
return GetMediaInfoInternal( return GetMediaInfoInternal(
GetInputArgument(inputFiles, request.MediaSource.Protocol), GetInputArgument(inputFiles, request.MediaSource),
request.MediaSource.Path, request.MediaSource.Path,
request.MediaSource.Protocol, request.MediaSource.Protocol,
extractChapters, extractChapters,
@ -355,11 +356,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
/// Gets the input argument. /// Gets the input argument.
/// </summary> /// </summary>
/// <param name="inputFiles">The input files.</param> /// <param name="inputFiles">The input files.</param>
/// <param name="protocol">The protocol.</param> /// <param name="mediaSource">The mediaSource.</param>
/// <returns>System.String.</returns> /// <returns>System.String.</returns>
/// <exception cref="ArgumentException">Unrecognized InputType.</exception> /// <exception cref="ArgumentException">Unrecognized InputType.</exception>
public string GetInputArgument(IReadOnlyList<string> inputFiles, MediaProtocol protocol) public string GetInputArgument(IReadOnlyList<string> inputFiles, MediaSourceInfo mediaSource)
=> EncodingUtils.GetInputArgument(inputFiles, protocol); {
var prefix = "file";
if (mediaSource.VideoType == VideoType.BluRay || mediaSource.VideoType == VideoType.Iso)
{
prefix = "bluray";
}
return EncodingUtils.GetInputArgument(prefix, inputFiles, mediaSource.Protocol);
}
/// <summary> /// <summary>
/// Gets the media info internal. /// Gets the media info internal.
@ -457,17 +466,22 @@ namespace MediaBrowser.MediaEncoding.Encoder
public Task<string> ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken) public Task<string> ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken)
{ {
return ExtractImage(new[] { path }, null, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken); var mediaSource = new MediaSourceInfo
{
Protocol = MediaProtocol.File
};
return ExtractImage(new[] { path }, null, null, imageStreamIndex, mediaSource, true, null, null, cancellationToken);
} }
public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaSourceInfo mediaSource, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
{ {
return ExtractImage(inputFiles, container, videoStream, null, protocol, false, threedFormat, offset, cancellationToken); return ExtractImage(inputFiles, container, videoStream, null, mediaSource, false, threedFormat, offset, cancellationToken);
} }
public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken) public Task<string> ExtractVideoImage(string[] inputFiles, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken)
{ {
return ExtractImage(inputFiles, container, imageStream, imageStreamIndex, protocol, false, null, null, cancellationToken); return ExtractImage(inputFiles, container, imageStream, imageStreamIndex, mediaSource, false, null, null, cancellationToken);
} }
private async Task<string> ExtractImage( private async Task<string> ExtractImage(
@ -475,13 +489,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
string container, string container,
MediaStream videoStream, MediaStream videoStream,
int? imageStreamIndex, int? imageStreamIndex,
MediaProtocol protocol, MediaSourceInfo mediaSource,
bool isAudio, bool isAudio,
Video3DFormat? threedFormat, Video3DFormat? threedFormat,
TimeSpan? offset, TimeSpan? offset,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var inputArgument = GetInputArgument(inputFiles, protocol); var inputArgument = GetInputArgument(inputFiles, mediaSource);
if (isAudio) if (isAudio)
{ {
@ -671,7 +685,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
string[] inputFiles, string[] inputFiles,
string container, string container,
MediaStream videoStream, MediaStream videoStream,
MediaProtocol protocol, MediaSourceInfo mediaSource,
Video3DFormat? threedFormat, Video3DFormat? threedFormat,
TimeSpan interval, TimeSpan interval,
string targetDirectory, string targetDirectory,
@ -679,7 +693,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
int? maxWidth, int? maxWidth,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var inputArgument = GetInputArgument(inputFiles, protocol); var inputArgument = GetInputArgument(inputFiles, mediaSource);
var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(_usCulture); var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(_usCulture);

View File

@ -187,7 +187,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
protocol = _mediaSourceManager.GetPathProtocol(subtitleStream.Path); protocol = _mediaSourceManager.GetPathProtocol(subtitleStream.Path);
} }
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, protocol, subtitleStream, cancellationToken).ConfigureAwait(false); var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource, subtitleStream, cancellationToken).ConfigureAwait(false);
var stream = await GetSubtitleStream(fileInfo.Path, fileInfo.Protocol, fileInfo.IsExternal, cancellationToken).ConfigureAwait(false); var stream = await GetSubtitleStream(fileInfo.Path, fileInfo.Protocol, fileInfo.IsExternal, cancellationToken).ConfigureAwait(false);
@ -221,7 +221,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
private async Task<SubtitleInfo> GetReadableFile( private async Task<SubtitleInfo> GetReadableFile(
string mediaPath, string mediaPath,
string[] inputFiles, string[] inputFiles,
MediaProtocol protocol, MediaSourceInfo mediaSource,
MediaStream subtitleStream, MediaStream subtitleStream,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
@ -252,9 +252,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
} }
// Extract // Extract
var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, "." + outputFormat); var outputPath = GetSubtitleCachePath(mediaPath, mediaSource, subtitleStream.Index, "." + outputFormat);
await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, outputCodec, outputPath, cancellationToken) await ExtractTextSubtitle(inputFiles, mediaSource, subtitleStream.Index, outputCodec, outputPath, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
return new SubtitleInfo(outputPath, MediaProtocol.File, outputFormat, false); return new SubtitleInfo(outputPath, MediaProtocol.File, outputFormat, false);
@ -266,14 +266,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (GetReader(currentFormat, false) == null) if (GetReader(currentFormat, false) == null)
{ {
// Convert // Convert
var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, ".srt"); var outputPath = GetSubtitleCachePath(mediaPath, mediaSource, subtitleStream.Index, ".srt");
await ConvertTextSubtitleToSrt(subtitleStream.Path, subtitleStream.Language, protocol, outputPath, cancellationToken).ConfigureAwait(false); await ConvertTextSubtitleToSrt(subtitleStream.Path, subtitleStream.Language, mediaSource, outputPath, cancellationToken).ConfigureAwait(false);
return new SubtitleInfo(outputPath, MediaProtocol.File, "srt", true); return new SubtitleInfo(outputPath, MediaProtocol.File, "srt", true);
} }
return new SubtitleInfo(subtitleStream.Path, protocol, currentFormat, true); return new SubtitleInfo(subtitleStream.Path, mediaSource.Protocol, currentFormat, true);
} }
private ISubtitleParser GetReader(string format, bool throwIfMissing) private ISubtitleParser GetReader(string format, bool throwIfMissing)
@ -363,11 +363,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// </summary> /// </summary>
/// <param name="inputPath">The input path.</param> /// <param name="inputPath">The input path.</param>
/// <param name="language">The language.</param> /// <param name="language">The language.</param>
/// <param name="inputProtocol">The input protocol.</param> /// <param name="mediaSource">The input mediaSource.</param>
/// <param name="outputPath">The output path.</param> /// <param name="outputPath">The output path.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
private async Task ConvertTextSubtitleToSrt(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken) private async Task ConvertTextSubtitleToSrt(string inputPath, string language, MediaSourceInfo mediaSource, string outputPath, CancellationToken cancellationToken)
{ {
var semaphore = GetLock(outputPath); var semaphore = GetLock(outputPath);
@ -377,7 +377,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{ {
if (!File.Exists(outputPath)) if (!File.Exists(outputPath))
{ {
await ConvertTextSubtitleToSrtInternal(inputPath, language, inputProtocol, outputPath, cancellationToken).ConfigureAwait(false); await ConvertTextSubtitleToSrtInternal(inputPath, language, mediaSource, outputPath, cancellationToken).ConfigureAwait(false);
} }
} }
finally finally
@ -391,14 +391,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// </summary> /// </summary>
/// <param name="inputPath">The input path.</param> /// <param name="inputPath">The input path.</param>
/// <param name="language">The language.</param> /// <param name="language">The language.</param>
/// <param name="inputProtocol">The input protocol.</param> /// <param name="mediaSource">The input mediaSource.</param>
/// <param name="outputPath">The output path.</param> /// <param name="outputPath">The output path.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="ArgumentNullException"> /// <exception cref="ArgumentNullException">
/// The <c>inputPath</c> or <c>outputPath</c> is <c>null</c>. /// The <c>inputPath</c> or <c>outputPath</c> is <c>null</c>.
/// </exception> /// </exception>
private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken) private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaSourceInfo mediaSource, string outputPath, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(inputPath)) if (string.IsNullOrEmpty(inputPath))
{ {
@ -412,7 +412,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, inputProtocol, cancellationToken).ConfigureAwait(false); var encodingParam = await GetSubtitleFileCharacterSet(inputPath, language, mediaSource.Protocol, cancellationToken).ConfigureAwait(false);
// FFmpeg automatically convert character encoding when it is UTF-16 // FFmpeg automatically convert character encoding when it is UTF-16
// If we specify character encoding, it rejects with "do not specify a character encoding" and "Unable to recode subtitle event" // If we specify character encoding, it rejects with "do not specify a character encoding" and "Unable to recode subtitle event"
@ -516,7 +516,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// Extracts the text subtitle. /// Extracts the text subtitle.
/// </summary> /// </summary>
/// <param name="inputFiles">The input files.</param> /// <param name="inputFiles">The input files.</param>
/// <param name="protocol">The protocol.</param> /// <param name="mediaSource">The mediaSource.</param>
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param> /// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
/// <param name="outputCodec">The output codec.</param> /// <param name="outputCodec">The output codec.</param>
/// <param name="outputPath">The output path.</param> /// <param name="outputPath">The output path.</param>
@ -525,7 +525,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// <exception cref="ArgumentException">Must use inputPath list overload.</exception> /// <exception cref="ArgumentException">Must use inputPath list overload.</exception>
private async Task ExtractTextSubtitle( private async Task ExtractTextSubtitle(
string[] inputFiles, string[] inputFiles,
MediaProtocol protocol, MediaSourceInfo mediaSource,
int subtitleStreamIndex, int subtitleStreamIndex,
string outputCodec, string outputCodec,
string outputPath, string outputPath,
@ -540,7 +540,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (!File.Exists(outputPath)) if (!File.Exists(outputPath))
{ {
await ExtractTextSubtitleInternal( await ExtractTextSubtitleInternal(
_mediaEncoder.GetInputArgument(inputFiles, protocol), _mediaEncoder.GetInputArgument(inputFiles, mediaSource),
subtitleStreamIndex, subtitleStreamIndex,
outputCodec, outputCodec,
outputPath, outputPath,
@ -706,9 +706,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles
} }
} }
private string GetSubtitleCachePath(string mediaPath, MediaProtocol protocol, int subtitleStreamIndex, string outputSubtitleExtension) private string GetSubtitleCachePath(string mediaPath, MediaSourceInfo mediaSource, int subtitleStreamIndex, string outputSubtitleExtension)
{ {
if (protocol == MediaProtocol.File) if (mediaSource.Protocol == MediaProtocol.File)
{ {
var ticksParam = string.Empty; var ticksParam = string.Empty;

View File

@ -150,11 +150,6 @@ namespace MediaBrowser.Providers.MediaInfo
public Task<ItemUpdateType> FetchVideoInfo<T>(T item, MetadataRefreshOptions options, CancellationToken cancellationToken) public Task<ItemUpdateType> FetchVideoInfo<T>(T item, MetadataRefreshOptions options, CancellationToken cancellationToken)
where T : Video where T : Video
{ {
if (item.VideoType == VideoType.Iso)
{
return _cachedTask;
}
if (item.IsPlaceHolder) if (item.IsPlaceHolder)
{ {
return _cachedTask; return _cachedTask;

View File

@ -9,6 +9,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
@ -50,7 +51,7 @@ namespace MediaBrowser.Providers.MediaInfo
} }
// No support for this // No support for this
if (video.VideoType == VideoType.Iso || video.VideoType == VideoType.Dvd || video.VideoType == VideoType.BluRay) if (video.VideoType == VideoType.Dvd)
{ {
return Task.FromResult(new DynamicImageResponse { HasImage = false }); return Task.FromResult(new DynamicImageResponse { HasImage = false });
} }
@ -72,7 +73,6 @@ namespace MediaBrowser.Providers.MediaInfo
var inputPath = MediaEncoderHelpers.GetInputArgument( var inputPath = MediaEncoderHelpers.GetInputArgument(
_fileSystem, _fileSystem,
item.Path, item.Path,
null,
item.GetPlayableStreamFileNames()); item.GetPlayableStreamFileNames());
var mediaStreams = var mediaStreams =
@ -107,7 +107,14 @@ namespace MediaBrowser.Providers.MediaInfo
} }
} }
extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, imageStream, videoIndex, cancellationToken).ConfigureAwait(false); MediaSourceInfo mediaSource = new MediaSourceInfo
{
VideoType = item.VideoType,
IsoType = item.IsoType,
Protocol = item.PathProtocol.Value,
};
extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, mediaSource, imageStream, videoIndex, cancellationToken).ConfigureAwait(false);
} }
else else
{ {
@ -119,8 +126,14 @@ namespace MediaBrowser.Providers.MediaInfo
: TimeSpan.FromSeconds(10); : TimeSpan.FromSeconds(10);
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
var mediaSource = new MediaSourceInfo
{
VideoType = item.VideoType,
IsoType = item.IsoType,
Protocol = item.PathProtocol.Value,
};
extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, videoStream, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, mediaSource, videoStream, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false);
} }
return new DynamicImageResponse return new DynamicImageResponse