Add missing functions
This commit is contained in:
parent
7bb34fc9e7
commit
b8d327889b
|
@ -35,7 +35,6 @@ namespace Jellyfin.Api.Controllers
|
|||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IStreamHelper _streamHelper;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ISubtitleEncoder _subtitleEncoder;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
@ -55,7 +54,6 @@ namespace Jellyfin.Api.Controllers
|
|||
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
||||
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
||||
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
||||
/// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param>
|
||||
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
|
||||
/// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param>
|
||||
/// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param>
|
||||
|
@ -70,7 +68,6 @@ namespace Jellyfin.Api.Controllers
|
|||
IMediaSourceManager mediaSourceManager,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IMediaEncoder mediaEncoder,
|
||||
IStreamHelper streamHelper,
|
||||
IFileSystem fileSystem,
|
||||
ISubtitleEncoder subtitleEncoder,
|
||||
IConfiguration configuration,
|
||||
|
@ -85,7 +82,6 @@ namespace Jellyfin.Api.Controllers
|
|||
_mediaSourceManager = mediaSourceManager;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_streamHelper = streamHelper;
|
||||
_fileSystem = fileSystem;
|
||||
_subtitleEncoder = subtitleEncoder;
|
||||
_configuration = configuration;
|
||||
|
@ -283,8 +279,11 @@ namespace Jellyfin.Api.Controllers
|
|||
{
|
||||
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
|
||||
|
||||
// TODO AllowEndOfFile = false
|
||||
await new ProgressiveFileCopier(_streamHelper, state.DirectStreamProvider).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false);
|
||||
await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None)
|
||||
{
|
||||
AllowEndOfFile = false
|
||||
}.WriteToAsync(Response.Body, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// TODO (moved from MediaBrowser.Api): Don't hardcode contentType
|
||||
return File(Response.Body, MimeTypes.GetMimeType("file.ts")!);
|
||||
|
@ -319,8 +318,11 @@ namespace Jellyfin.Api.Controllers
|
|||
|
||||
if (state.MediaSource.IsInfiniteStream)
|
||||
{
|
||||
// TODO AllowEndOfFile = false
|
||||
await new ProgressiveFileCopier(_streamHelper, state.MediaPath).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false);
|
||||
await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None)
|
||||
{
|
||||
AllowEndOfFile = false
|
||||
}.WriteToAsync(Response.Body, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return File(Response.Body, contentType);
|
||||
}
|
||||
|
@ -339,7 +341,6 @@ namespace Jellyfin.Api.Controllers
|
|||
return await FileStreamResponseHelpers.GetTranscodedFile(
|
||||
state,
|
||||
isHeadRequest,
|
||||
_streamHelper,
|
||||
this,
|
||||
_transcodingJobHelper,
|
||||
ffmpegCommandLineArguments,
|
||||
|
|
|
@ -24,7 +24,6 @@ using MediaBrowser.Controller.LiveTv;
|
|||
using MediaBrowser.Controller.Net;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
@ -45,9 +44,9 @@ namespace Jellyfin.Api.Controllers
|
|||
private readonly ILibraryManager _libraryManager;
|
||||
private readonly IDtoService _dtoService;
|
||||
private readonly ISessionContext _sessionContext;
|
||||
private readonly IStreamHelper _streamHelper;
|
||||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IConfigurationManager _configurationManager;
|
||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LiveTvController"/> class.
|
||||
|
@ -58,9 +57,9 @@ namespace Jellyfin.Api.Controllers
|
|||
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
||||
/// <param name="dtoService">Instance of the <see cref="IDtoService"/> interface.</param>
|
||||
/// <param name="sessionContext">Instance of the <see cref="ISessionContext"/> interface.</param>
|
||||
/// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param>
|
||||
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
||||
/// <param name="configurationManager">Instance of the <see cref="IConfigurationManager"/> interface.</param>
|
||||
/// <param name="transcodingJobHelper">Instance of the <see cref="TranscodingJobHelper"/> class.</param>
|
||||
public LiveTvController(
|
||||
ILiveTvManager liveTvManager,
|
||||
IUserManager userManager,
|
||||
|
@ -68,9 +67,9 @@ namespace Jellyfin.Api.Controllers
|
|||
ILibraryManager libraryManager,
|
||||
IDtoService dtoService,
|
||||
ISessionContext sessionContext,
|
||||
IStreamHelper streamHelper,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
IConfigurationManager configurationManager)
|
||||
IConfigurationManager configurationManager,
|
||||
TranscodingJobHelper transcodingJobHelper)
|
||||
{
|
||||
_liveTvManager = liveTvManager;
|
||||
_userManager = userManager;
|
||||
|
@ -78,9 +77,9 @@ namespace Jellyfin.Api.Controllers
|
|||
_libraryManager = libraryManager;
|
||||
_dtoService = dtoService;
|
||||
_sessionContext = sessionContext;
|
||||
_streamHelper = streamHelper;
|
||||
_mediaSourceManager = mediaSourceManager;
|
||||
_configurationManager = configurationManager;
|
||||
_transcodingJobHelper = transcodingJobHelper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1187,7 +1186,9 @@ namespace Jellyfin.Api.Controllers
|
|||
}
|
||||
|
||||
await using var memoryStream = new MemoryStream();
|
||||
await new ProgressiveFileCopier(_streamHelper, path).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false);
|
||||
await new ProgressiveFileCopier(path, null, _transcodingJobHelper, CancellationToken.None)
|
||||
.WriteToAsync(memoryStream, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
return File(memoryStream, MimeTypes.GetMimeType(path));
|
||||
}
|
||||
|
||||
|
@ -1214,7 +1215,9 @@ namespace Jellyfin.Api.Controllers
|
|||
}
|
||||
|
||||
await using var memoryStream = new MemoryStream();
|
||||
await new ProgressiveFileCopier(_streamHelper, liveStreamInfo).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false);
|
||||
await new ProgressiveFileCopier(liveStreamInfo, null, _transcodingJobHelper, CancellationToken.None)
|
||||
.WriteToAsync(memoryStream, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
return File(memoryStream, MimeTypes.GetMimeType("file." + container));
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,6 @@ namespace Jellyfin.Api.Controllers
|
|||
private readonly IMediaSourceManager _mediaSourceManager;
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly IStreamHelper _streamHelper;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
private readonly ISubtitleEncoder _subtitleEncoder;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
@ -67,7 +66,6 @@ namespace Jellyfin.Api.Controllers
|
|||
/// <param name="mediaSourceManager">Instance of the <see cref="IMediaSourceManager"/> interface.</param>
|
||||
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
|
||||
/// <param name="mediaEncoder">Instance of the <see cref="IMediaEncoder"/> interface.</param>
|
||||
/// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param>
|
||||
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
|
||||
/// <param name="subtitleEncoder">Instance of the <see cref="ISubtitleEncoder"/> interface.</param>
|
||||
/// <param name="configuration">Instance of the <see cref="IConfiguration"/> interface.</param>
|
||||
|
@ -83,7 +81,6 @@ namespace Jellyfin.Api.Controllers
|
|||
IMediaSourceManager mediaSourceManager,
|
||||
IServerConfigurationManager serverConfigurationManager,
|
||||
IMediaEncoder mediaEncoder,
|
||||
IStreamHelper streamHelper,
|
||||
IFileSystem fileSystem,
|
||||
ISubtitleEncoder subtitleEncoder,
|
||||
IConfiguration configuration,
|
||||
|
@ -99,7 +96,6 @@ namespace Jellyfin.Api.Controllers
|
|||
_mediaSourceManager = mediaSourceManager;
|
||||
_serverConfigurationManager = serverConfigurationManager;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_streamHelper = streamHelper;
|
||||
_fileSystem = fileSystem;
|
||||
_subtitleEncoder = subtitleEncoder;
|
||||
_configuration = configuration;
|
||||
|
@ -376,7 +372,7 @@ namespace Jellyfin.Api.Controllers
|
|||
[FromQuery] Dictionary<string, string> streamOptions)
|
||||
{
|
||||
var isHeadRequest = Request.Method == System.Net.WebRequestMethods.Http.Head;
|
||||
using var cancellationTokenSource = new CancellationTokenSource();
|
||||
var cancellationTokenSource = new CancellationTokenSource();
|
||||
var streamingRequest = new StreamingRequestDto
|
||||
{
|
||||
Id = itemId,
|
||||
|
@ -453,8 +449,11 @@ namespace Jellyfin.Api.Controllers
|
|||
{
|
||||
StreamingHelpers.AddDlnaHeaders(state, Response.Headers, true, startTimeTicks, Request, _dlnaManager);
|
||||
|
||||
// TODO AllowEndOfFile = false
|
||||
await new ProgressiveFileCopier(_streamHelper, state.DirectStreamProvider).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false);
|
||||
await new ProgressiveFileCopier(state.DirectStreamProvider, null, _transcodingJobHelper, CancellationToken.None)
|
||||
{
|
||||
AllowEndOfFile = false
|
||||
}.WriteToAsync(Response.Body, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// TODO (moved from MediaBrowser.Api): Don't hardcode contentType
|
||||
return File(Response.Body, MimeTypes.GetMimeType("file.ts")!);
|
||||
|
@ -489,8 +488,11 @@ namespace Jellyfin.Api.Controllers
|
|||
|
||||
if (state.MediaSource.IsInfiniteStream)
|
||||
{
|
||||
// TODO AllowEndOfFile = false
|
||||
await new ProgressiveFileCopier(_streamHelper, state.MediaPath).WriteToAsync(Response.Body, CancellationToken.None).ConfigureAwait(false);
|
||||
await new ProgressiveFileCopier(state.MediaPath, null, _transcodingJobHelper, CancellationToken.None)
|
||||
{
|
||||
AllowEndOfFile = false
|
||||
}.WriteToAsync(Response.Body, CancellationToken.None)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return File(Response.Body, contentType);
|
||||
}
|
||||
|
@ -509,7 +511,6 @@ namespace Jellyfin.Api.Controllers
|
|||
return await FileStreamResponseHelpers.GetTranscodedFile(
|
||||
state,
|
||||
isHeadRequest,
|
||||
_streamHelper,
|
||||
this,
|
||||
_transcodingJobHelper,
|
||||
ffmpegCommandLineArguments,
|
||||
|
|
|
@ -3,9 +3,9 @@ using System.IO;
|
|||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models.PlaybackDtos;
|
||||
using Jellyfin.Api.Models.StreamingDtos;
|
||||
using MediaBrowser.Controller.MediaEncoding;
|
||||
using MediaBrowser.Model.IO;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
@ -80,7 +80,6 @@ namespace Jellyfin.Api.Helpers
|
|||
/// </summary>
|
||||
/// <param name="state">The current <see cref="StreamState"/>.</param>
|
||||
/// <param name="isHeadRequest">Whether the current request is a HTTP HEAD request so only the headers get returned.</param>
|
||||
/// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param>
|
||||
/// <param name="controller">The <see cref="ControllerBase"/> managing the response.</param>
|
||||
/// <param name="transcodingJobHelper">The <see cref="TranscodingJobHelper"/> singleton.</param>
|
||||
/// <param name="ffmpegCommandLineArguments">The command line arguments to start ffmpeg.</param>
|
||||
|
@ -91,7 +90,6 @@ namespace Jellyfin.Api.Helpers
|
|||
public static async Task<ActionResult> GetTranscodedFile(
|
||||
StreamState state,
|
||||
bool isHeadRequest,
|
||||
IStreamHelper streamHelper,
|
||||
ControllerBase controller,
|
||||
TranscodingJobHelper transcodingJobHelper,
|
||||
string ffmpegCommandLineArguments,
|
||||
|
@ -116,18 +114,20 @@ namespace Jellyfin.Api.Helpers
|
|||
await transcodingLock.WaitAsync(cancellationTokenSource.Token).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
TranscodingJobDto? job;
|
||||
if (!File.Exists(outputPath))
|
||||
{
|
||||
await transcodingJobHelper.StartFfMpeg(state, outputPath, ffmpegCommandLineArguments, request, transcodingJobType, cancellationTokenSource).ConfigureAwait(false);
|
||||
job = await transcodingJobHelper.StartFfMpeg(state, outputPath, ffmpegCommandLineArguments, request, transcodingJobType, cancellationTokenSource).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
transcodingJobHelper.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
|
||||
job = transcodingJobHelper.OnTranscodeBeginRequest(outputPath, TranscodingJobType.Progressive);
|
||||
state.Dispose();
|
||||
}
|
||||
|
||||
await using var memoryStream = new MemoryStream();
|
||||
await new ProgressiveFileCopier(streamHelper, outputPath).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false);
|
||||
var memoryStream = new MemoryStream();
|
||||
await new ProgressiveFileCopier(outputPath, job, transcodingJobHelper, CancellationToken.None).WriteToAsync(memoryStream, CancellationToken.None).ConfigureAwait(false);
|
||||
memoryStream.Position = 0;
|
||||
return controller.File(memoryStream, contentType);
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models.PlaybackDtos;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
||||
|
@ -12,34 +13,53 @@ namespace Jellyfin.Api.Helpers
|
|||
/// </summary>
|
||||
public class ProgressiveFileCopier
|
||||
{
|
||||
private readonly TranscodingJobDto? _job;
|
||||
private readonly string? _path;
|
||||
private readonly CancellationToken _cancellationToken;
|
||||
private readonly IDirectStreamProvider? _directStreamProvider;
|
||||
private readonly IStreamHelper _streamHelper;
|
||||
private readonly TranscodingJobHelper _transcodingJobHelper;
|
||||
private long _bytesWritten;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProgressiveFileCopier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param>
|
||||
/// <param name="path">Filepath to stream from.</param>
|
||||
public ProgressiveFileCopier(IStreamHelper streamHelper, string path)
|
||||
/// <param name="path">The path to copy from.</param>
|
||||
/// <param name="job">The transcoding job.</param>
|
||||
/// <param name="transcodingJobHelper">Instance of the <see cref="TranscodingJobHelper"/>.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
public ProgressiveFileCopier(string path, TranscodingJobDto? job, TranscodingJobHelper transcodingJobHelper, CancellationToken cancellationToken)
|
||||
{
|
||||
_path = path;
|
||||
_streamHelper = streamHelper;
|
||||
_directStreamProvider = null;
|
||||
_job = job;
|
||||
_cancellationToken = cancellationToken;
|
||||
_transcodingJobHelper = transcodingJobHelper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProgressiveFileCopier"/> class.
|
||||
/// </summary>
|
||||
/// <param name="streamHelper">Instance of the <see cref="IStreamHelper"/> interface.</param>
|
||||
/// <param name="directStreamProvider">Instance of the <see cref="IDirectStreamProvider"/> interface.</param>
|
||||
public ProgressiveFileCopier(IStreamHelper streamHelper, IDirectStreamProvider directStreamProvider)
|
||||
/// <param name="job">The transcoding job.</param>
|
||||
/// <param name="transcodingJobHelper">Instance of the <see cref="TranscodingJobHelper"/>.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, TranscodingJobDto? job, TranscodingJobHelper transcodingJobHelper, CancellationToken cancellationToken)
|
||||
{
|
||||
_directStreamProvider = directStreamProvider;
|
||||
_streamHelper = streamHelper;
|
||||
_path = null;
|
||||
_job = job;
|
||||
_cancellationToken = cancellationToken;
|
||||
_transcodingJobHelper = transcodingJobHelper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether allow read end of file.
|
||||
/// </summary>
|
||||
public bool AllowEndOfFile { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets copy start position.
|
||||
/// </summary>
|
||||
public long StartPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Write source stream to output.
|
||||
/// </summary>
|
||||
|
@ -48,37 +68,123 @@ namespace Jellyfin.Api.Helpers
|
|||
/// <returns>A <see cref="Task"/>.</returns>
|
||||
public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_directStreamProvider != null)
|
||||
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationToken).Token;
|
||||
|
||||
try
|
||||
{
|
||||
await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var fileOptions = FileOptions.SequentialScan;
|
||||
|
||||
// use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
|
||||
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
|
||||
{
|
||||
fileOptions |= FileOptions.Asynchronous;
|
||||
}
|
||||
|
||||
await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, fileOptions);
|
||||
const int emptyReadLimit = 100;
|
||||
var eofCount = 0;
|
||||
while (eofCount < emptyReadLimit)
|
||||
{
|
||||
var bytesRead = await _streamHelper.CopyToAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (bytesRead == 0)
|
||||
if (_directStreamProvider != null)
|
||||
{
|
||||
eofCount++;
|
||||
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
||||
await _directStreamProvider.CopyToAsync(outputStream, cancellationToken).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
var fileOptions = FileOptions.SequentialScan;
|
||||
var allowAsyncFileRead = false;
|
||||
|
||||
// use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039
|
||||
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
|
||||
{
|
||||
eofCount = 0;
|
||||
fileOptions |= FileOptions.Asynchronous;
|
||||
allowAsyncFileRead = true;
|
||||
}
|
||||
|
||||
await using var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, IODefaults.FileStreamBufferSize, fileOptions);
|
||||
|
||||
var eofCount = 0;
|
||||
const int emptyReadLimit = 20;
|
||||
if (StartPosition > 0)
|
||||
{
|
||||
inputStream.Position = StartPosition;
|
||||
}
|
||||
|
||||
while (eofCount < emptyReadLimit || !AllowEndOfFile)
|
||||
{
|
||||
int bytesRead;
|
||||
if (allowAsyncFileRead)
|
||||
{
|
||||
bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (bytesRead == 0)
|
||||
{
|
||||
if (_job == null || _job.HasExited)
|
||||
{
|
||||
eofCount++;
|
||||
}
|
||||
|
||||
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
eofCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_job != null)
|
||||
{
|
||||
_transcodingJobHelper.OnTranscodeEndRequest(_job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<int> CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, CancellationToken cancellationToken)
|
||||
{
|
||||
var array = new byte[IODefaults.CopyToBufferSize];
|
||||
int bytesRead;
|
||||
int totalBytesRead = 0;
|
||||
|
||||
while ((bytesRead = source.Read(array, 0, array.Length)) != 0)
|
||||
{
|
||||
var bytesToWrite = bytesRead;
|
||||
|
||||
if (bytesToWrite > 0)
|
||||
{
|
||||
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_bytesWritten += bytesRead;
|
||||
totalBytesRead += bytesRead;
|
||||
|
||||
if (_job != null)
|
||||
{
|
||||
_job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return totalBytesRead;
|
||||
}
|
||||
|
||||
private async Task<int> CopyToInternalAsync(Stream source, Stream destination, CancellationToken cancellationToken)
|
||||
{
|
||||
var array = new byte[IODefaults.CopyToBufferSize];
|
||||
int bytesRead;
|
||||
int totalBytesRead = 0;
|
||||
|
||||
while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
||||
{
|
||||
var bytesToWrite = bytesRead;
|
||||
|
||||
if (bytesToWrite > 0)
|
||||
{
|
||||
await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false);
|
||||
|
||||
_bytesWritten += bytesRead;
|
||||
totalBytesRead += bytesRead;
|
||||
|
||||
if (_job != null)
|
||||
{
|
||||
_job.BytesDownloaded = Math.Max(_job.BytesDownloaded ?? _bytesWritten, _bytesWritten);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return totalBytesRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -680,6 +680,20 @@ namespace Jellyfin.Api.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when [transcode end].
|
||||
/// </summary>
|
||||
/// <param name="job">The transcode job.</param>
|
||||
public void OnTranscodeEndRequest(TranscodingJobDto job)
|
||||
{
|
||||
job.ActiveRequestCount--;
|
||||
_logger.LogDebug("OnTranscodeEndRequest job.ActiveRequestCount={ActiveRequestCount}", job.ActiveRequestCount);
|
||||
if (job.ActiveRequestCount <= 0)
|
||||
{
|
||||
PingTimer(job, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// The progressive
|
||||
|
|
Loading…
Reference in New Issue
Block a user