mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-04-22 01:54:42 +01:00
fixes #838 - Support rtmp protocol with channels
This commit is contained in:
@@ -1,22 +1,27 @@
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace MediaBrowser.MediaEncoding.Encoder
|
||||
{
|
||||
public static class EncodingUtils
|
||||
{
|
||||
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||
|
||||
public static string GetInputArgument(List<string> inputFiles, bool isRemote)
|
||||
public static string GetInputArgument(List<string> inputFiles, MediaProtocol protocol)
|
||||
{
|
||||
if (isRemote)
|
||||
if (protocol == MediaProtocol.Http)
|
||||
{
|
||||
return GetHttpInputArgument(inputFiles);
|
||||
var url = inputFiles.First();
|
||||
|
||||
return string.Format("\"{0}\"", url);
|
||||
}
|
||||
if (protocol == MediaProtocol.Rtmp)
|
||||
{
|
||||
var url = inputFiles.First();
|
||||
|
||||
return string.Format("\"{0}\"", url);
|
||||
}
|
||||
|
||||
return GetConcatInputArgument(inputFiles);
|
||||
@@ -52,35 +57,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
return string.Format("file:\"{0}\"", path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HTTP input argument.
|
||||
/// </summary>
|
||||
/// <param name="inputFiles">The input files.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
private static string GetHttpInputArgument(IEnumerable<string> inputFiles)
|
||||
{
|
||||
var url = inputFiles.First();
|
||||
|
||||
return string.Format("\"{0}\"", url);
|
||||
}
|
||||
|
||||
private static string GetFastSeekValue(EncodingOptions options)
|
||||
{
|
||||
var time = options.StartTimeTicks;
|
||||
|
||||
if (time.HasValue)
|
||||
{
|
||||
var seconds = TimeSpan.FromTicks(time.Value).TotalSeconds;
|
||||
|
||||
if (seconds > 0)
|
||||
{
|
||||
return string.Format("-ss {0}", seconds.ToString(UsCulture));
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public static string GetProbeSizeArgument(bool isDvd)
|
||||
{
|
||||
return isDvd ? "-probesize 1G -analyzeduration 200M" : string.Empty;
|
||||
|
||||
@@ -3,6 +3,7 @@ using MediaBrowser.Common.IO;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Logging;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
@@ -102,37 +103,38 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
/// Gets the media info.
|
||||
/// </summary>
|
||||
/// <param name="inputFiles">The input files.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="protocol">The protocol.</param>
|
||||
/// <param name="isAudio">if set to <c>true</c> [is audio].</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, InputType type, bool isAudio,
|
||||
public Task<InternalMediaInfoResult> GetMediaInfo(string[] inputFiles, MediaProtocol protocol, bool isAudio,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return GetMediaInfoInternal(GetInputArgument(inputFiles, type), !isAudio,
|
||||
GetProbeSizeArgument(type), cancellationToken);
|
||||
return GetMediaInfoInternal(GetInputArgument(inputFiles, protocol), !isAudio,
|
||||
GetProbeSizeArgument(inputFiles, protocol), cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the input argument.
|
||||
/// </summary>
|
||||
/// <param name="inputFiles">The input files.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="protocol">The protocol.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
/// <exception cref="System.ArgumentException">Unrecognized InputType</exception>
|
||||
public string GetInputArgument(string[] inputFiles, InputType type)
|
||||
public string GetInputArgument(string[] inputFiles, MediaProtocol protocol)
|
||||
{
|
||||
return EncodingUtils.GetInputArgument(inputFiles.ToList(), type == InputType.Url);
|
||||
return EncodingUtils.GetInputArgument(inputFiles.ToList(), protocol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the probe size argument.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="inputFiles">The input files.</param>
|
||||
/// <param name="protocol">The protocol.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
public string GetProbeSizeArgument(InputType type)
|
||||
public string GetProbeSizeArgument(string[] inputFiles, MediaProtocol protocol)
|
||||
{
|
||||
return EncodingUtils.GetProbeSizeArgument(type == InputType.Dvd);
|
||||
return EncodingUtils.GetProbeSizeArgument(inputFiles.Length > 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -287,27 +289,27 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
|
||||
public Task<Stream> ExtractAudioImage(string path, CancellationToken cancellationToken)
|
||||
{
|
||||
return ExtractImage(new[] { path }, InputType.File, true, null, null, cancellationToken);
|
||||
return ExtractImage(new[] { path }, MediaProtocol.File, true, null, null, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<Stream> ExtractVideoImage(string[] inputFiles, InputType type, Video3DFormat? threedFormat,
|
||||
public Task<Stream> ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat,
|
||||
TimeSpan? offset, CancellationToken cancellationToken)
|
||||
{
|
||||
return ExtractImage(inputFiles, type, false, threedFormat, offset, cancellationToken);
|
||||
return ExtractImage(inputFiles, protocol, false, threedFormat, offset, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<Stream> ExtractImage(string[] inputFiles, InputType type, bool isAudio,
|
||||
private async Task<Stream> ExtractImage(string[] inputFiles, MediaProtocol protocol, bool isAudio,
|
||||
Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken)
|
||||
{
|
||||
var resourcePool = isAudio ? _audioImageResourcePool : _videoImageResourcePool;
|
||||
|
||||
var inputArgument = GetInputArgument(inputFiles, type);
|
||||
var inputArgument = GetInputArgument(inputFiles, protocol);
|
||||
|
||||
if (!isAudio)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await ExtractImageInternal(inputArgument, type, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false);
|
||||
return await ExtractImageInternal(inputArgument, protocol, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -315,10 +317,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
}
|
||||
}
|
||||
|
||||
return await ExtractImageInternal(inputArgument, type, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false);
|
||||
return await ExtractImageInternal(inputArgument, protocol, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<Stream> ExtractImageInternal(string inputPath, InputType type, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
|
||||
private async Task<Stream> ExtractImageInternal(string inputPath, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrEmpty(inputPath))
|
||||
{
|
||||
@@ -357,7 +359,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||
var args = useIFrame ? string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf) :
|
||||
string.Format("-i {0} -threads 0 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf);
|
||||
|
||||
var probeSize = GetProbeSizeArgument(type);
|
||||
var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol);
|
||||
|
||||
if (!string.IsNullOrEmpty(probeSize))
|
||||
{
|
||||
|
||||
@@ -127,26 +127,19 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
var subtitleStream = mediaSource.MediaStreams
|
||||
.First(i => i.Type == MediaStreamType.Subtitle && i.Index == subtitleStreamIndex);
|
||||
|
||||
var inputType = mediaSource.LocationType == LocationType.Remote ? InputType.Url : InputType.File;
|
||||
var inputFiles = new[] { mediaSource.Path };
|
||||
|
||||
if (mediaSource.VideoType.HasValue)
|
||||
{
|
||||
if (mediaSource.VideoType.Value == VideoType.BluRay)
|
||||
if (mediaSource.VideoType.Value == VideoType.BluRay ||
|
||||
mediaSource.VideoType.Value == VideoType.Dvd)
|
||||
{
|
||||
inputType = InputType.Bluray;
|
||||
var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSourceId));
|
||||
inputFiles = mediaSourceItem.GetPlayableStreamFiles().ToArray();
|
||||
}
|
||||
else if (mediaSource.VideoType.Value == VideoType.Dvd)
|
||||
{
|
||||
inputType = InputType.Dvd;
|
||||
var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSourceId));
|
||||
inputFiles = mediaSourceItem.GetPlayableStreamFiles().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, inputType, subtitleStream, cancellationToken).ConfigureAwait(false);
|
||||
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var stream = await GetSubtitleStream(fileInfo.Item1, subtitleStream.Language).ConfigureAwait(false);
|
||||
|
||||
@@ -180,7 +173,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
|
||||
private async Task<Tuple<string, string>> GetReadableFile(string mediaPath,
|
||||
string[] inputFiles,
|
||||
InputType type,
|
||||
MediaProtocol protocol,
|
||||
MediaStream subtitleStream,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -189,7 +182,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
// Extract
|
||||
var outputPath = GetSubtitleCachePath(mediaPath, subtitleStream.Index, ".ass");
|
||||
|
||||
await ExtractTextSubtitle(inputFiles, type, subtitleStream.Index, false, outputPath, cancellationToken)
|
||||
await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, false, outputPath, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return new Tuple<string, string>(outputPath, "ass");
|
||||
@@ -451,14 +444,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
/// Extracts the text subtitle.
|
||||
/// </summary>
|
||||
/// <param name="inputFiles">The input files.</param>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="protocol">The protocol.</param>
|
||||
/// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
|
||||
/// <param name="copySubtitleStream">if set to true, copy stream instead of converting.</param>
|
||||
/// <param name="outputPath">The output path.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="System.ArgumentException">Must use inputPath list overload</exception>
|
||||
private async Task ExtractTextSubtitle(string[] inputFiles, InputType type, int subtitleStreamIndex,
|
||||
private async Task ExtractTextSubtitle(string[] inputFiles, MediaProtocol protocol, int subtitleStreamIndex,
|
||||
bool copySubtitleStream, string outputPath, CancellationToken cancellationToken)
|
||||
{
|
||||
var semaphore = GetLock(outputPath);
|
||||
@@ -469,7 +462,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||
{
|
||||
if (!File.Exists(outputPath))
|
||||
{
|
||||
await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, type), subtitleStreamIndex,
|
||||
await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex,
|
||||
copySubtitleStream, outputPath, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user