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:
parent
c7b3d4a90c
commit
3ad6232973
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user