mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-06-23 15:30:56 -04:00
Merge pull request #12676 from gnattu/rework-burnin-during-transcoding
Co-authored-by: Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com>
This commit is contained in:
commit
c97c2217a5
@ -158,6 +158,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
/// <param name="maxHeight">Optional. The max height.</param>
|
/// <param name="maxHeight">Optional. The max height.</param>
|
||||||
/// <param name="enableSubtitlesInManifest">Optional. Whether to enable subtitles in the manifest.</param>
|
/// <param name="enableSubtitlesInManifest">Optional. Whether to enable subtitles in the manifest.</param>
|
||||||
/// <param name="enableAudioVbrEncoding">Optional. Whether to enable Audio Encoding.</param>
|
/// <param name="enableAudioVbrEncoding">Optional. Whether to enable Audio Encoding.</param>
|
||||||
|
/// <param name="alwaysBurnInSubtitleWhenTranscoding">Whether to always burn in subtitles when transcoding.</param>
|
||||||
/// <response code="200">Hls live stream retrieved.</response>
|
/// <response code="200">Hls live stream retrieved.</response>
|
||||||
/// <returns>A <see cref="FileResult"/> containing the hls file.</returns>
|
/// <returns>A <see cref="FileResult"/> containing the hls file.</returns>
|
||||||
[HttpGet("Videos/{itemId}/live.m3u8")]
|
[HttpGet("Videos/{itemId}/live.m3u8")]
|
||||||
@ -216,7 +217,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
[FromQuery] int? maxWidth,
|
[FromQuery] int? maxWidth,
|
||||||
[FromQuery] int? maxHeight,
|
[FromQuery] int? maxHeight,
|
||||||
[FromQuery] bool? enableSubtitlesInManifest,
|
[FromQuery] bool? enableSubtitlesInManifest,
|
||||||
[FromQuery] bool enableAudioVbrEncoding = true)
|
[FromQuery] bool enableAudioVbrEncoding = true,
|
||||||
|
[FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false)
|
||||||
{
|
{
|
||||||
VideoRequestDto streamingRequest = new VideoRequestDto
|
VideoRequestDto streamingRequest = new VideoRequestDto
|
||||||
{
|
{
|
||||||
@ -251,7 +253,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
Height = height,
|
Height = height,
|
||||||
VideoBitRate = videoBitRate,
|
VideoBitRate = videoBitRate,
|
||||||
SubtitleStreamIndex = subtitleStreamIndex,
|
SubtitleStreamIndex = subtitleStreamIndex,
|
||||||
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
|
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External,
|
||||||
MaxRefFrames = maxRefFrames,
|
MaxRefFrames = maxRefFrames,
|
||||||
MaxVideoBitDepth = maxVideoBitDepth,
|
MaxVideoBitDepth = maxVideoBitDepth,
|
||||||
RequireAvc = requireAvc ?? false,
|
RequireAvc = requireAvc ?? false,
|
||||||
@ -271,7 +273,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
MaxHeight = maxHeight,
|
MaxHeight = maxHeight,
|
||||||
MaxWidth = maxWidth,
|
MaxWidth = maxWidth,
|
||||||
EnableSubtitlesInManifest = enableSubtitlesInManifest ?? true,
|
EnableSubtitlesInManifest = enableSubtitlesInManifest ?? true,
|
||||||
EnableAudioVbrEncoding = enableAudioVbrEncoding
|
EnableAudioVbrEncoding = enableAudioVbrEncoding,
|
||||||
|
AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding
|
||||||
};
|
};
|
||||||
|
|
||||||
// CTS lifecycle is managed internally.
|
// CTS lifecycle is managed internally.
|
||||||
@ -398,6 +401,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
/// <param name="enableAdaptiveBitrateStreaming">Enable adaptive bitrate streaming.</param>
|
/// <param name="enableAdaptiveBitrateStreaming">Enable adaptive bitrate streaming.</param>
|
||||||
/// <param name="enableTrickplay">Enable trickplay image playlists being added to master playlist.</param>
|
/// <param name="enableTrickplay">Enable trickplay image playlists being added to master playlist.</param>
|
||||||
/// <param name="enableAudioVbrEncoding">Whether to enable Audio Encoding.</param>
|
/// <param name="enableAudioVbrEncoding">Whether to enable Audio Encoding.</param>
|
||||||
|
/// <param name="alwaysBurnInSubtitleWhenTranscoding">Whether to always burn in subtitles when transcoding.</param>
|
||||||
/// <response code="200">Video stream returned.</response>
|
/// <response code="200">Video stream returned.</response>
|
||||||
/// <returns>A <see cref="FileResult"/> containing the playlist file.</returns>
|
/// <returns>A <see cref="FileResult"/> containing the playlist file.</returns>
|
||||||
[HttpGet("Videos/{itemId}/master.m3u8")]
|
[HttpGet("Videos/{itemId}/master.m3u8")]
|
||||||
@ -457,7 +461,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
[FromQuery] Dictionary<string, string> streamOptions,
|
[FromQuery] Dictionary<string, string> streamOptions,
|
||||||
[FromQuery] bool enableAdaptiveBitrateStreaming = true,
|
[FromQuery] bool enableAdaptiveBitrateStreaming = true,
|
||||||
[FromQuery] bool enableTrickplay = true,
|
[FromQuery] bool enableTrickplay = true,
|
||||||
[FromQuery] bool enableAudioVbrEncoding = true)
|
[FromQuery] bool enableAudioVbrEncoding = true,
|
||||||
|
[FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false)
|
||||||
{
|
{
|
||||||
var streamingRequest = new HlsVideoRequestDto
|
var streamingRequest = new HlsVideoRequestDto
|
||||||
{
|
{
|
||||||
@ -493,7 +498,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
MaxHeight = maxHeight,
|
MaxHeight = maxHeight,
|
||||||
VideoBitRate = videoBitRate,
|
VideoBitRate = videoBitRate,
|
||||||
SubtitleStreamIndex = subtitleStreamIndex,
|
SubtitleStreamIndex = subtitleStreamIndex,
|
||||||
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
|
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External,
|
||||||
MaxRefFrames = maxRefFrames,
|
MaxRefFrames = maxRefFrames,
|
||||||
MaxVideoBitDepth = maxVideoBitDepth,
|
MaxVideoBitDepth = maxVideoBitDepth,
|
||||||
RequireAvc = requireAvc ?? false,
|
RequireAvc = requireAvc ?? false,
|
||||||
@ -512,7 +517,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
StreamOptions = streamOptions,
|
StreamOptions = streamOptions,
|
||||||
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming,
|
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming,
|
||||||
EnableTrickplay = enableTrickplay,
|
EnableTrickplay = enableTrickplay,
|
||||||
EnableAudioVbrEncoding = enableAudioVbrEncoding
|
EnableAudioVbrEncoding = enableAudioVbrEncoding,
|
||||||
|
AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding
|
||||||
};
|
};
|
||||||
|
|
||||||
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
|
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
|
||||||
@ -663,7 +669,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
Height = height,
|
Height = height,
|
||||||
VideoBitRate = videoBitRate,
|
VideoBitRate = videoBitRate,
|
||||||
SubtitleStreamIndex = subtitleStreamIndex,
|
SubtitleStreamIndex = subtitleStreamIndex,
|
||||||
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
|
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External,
|
||||||
MaxRefFrames = maxRefFrames,
|
MaxRefFrames = maxRefFrames,
|
||||||
MaxVideoBitDepth = maxVideoBitDepth,
|
MaxVideoBitDepth = maxVideoBitDepth,
|
||||||
RequireAvc = requireAvc ?? false,
|
RequireAvc = requireAvc ?? false,
|
||||||
@ -681,7 +687,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
Context = context ?? EncodingContext.Streaming,
|
Context = context ?? EncodingContext.Streaming,
|
||||||
StreamOptions = streamOptions,
|
StreamOptions = streamOptions,
|
||||||
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming,
|
EnableAdaptiveBitrateStreaming = enableAdaptiveBitrateStreaming,
|
||||||
EnableAudioVbrEncoding = enableAudioVbrEncoding
|
EnableAudioVbrEncoding = enableAudioVbrEncoding,
|
||||||
|
AlwaysBurnInSubtitleWhenTranscoding = false
|
||||||
};
|
};
|
||||||
|
|
||||||
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
|
return await _dynamicHlsHelper.GetMasterHlsPlaylist(TranscodingJobType, streamingRequest, enableAdaptiveBitrateStreaming).ConfigureAwait(false);
|
||||||
@ -741,6 +748,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
/// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
|
/// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
|
||||||
/// <param name="streamOptions">Optional. The streaming options.</param>
|
/// <param name="streamOptions">Optional. The streaming options.</param>
|
||||||
/// <param name="enableAudioVbrEncoding">Optional. Whether to enable Audio Encoding.</param>
|
/// <param name="enableAudioVbrEncoding">Optional. Whether to enable Audio Encoding.</param>
|
||||||
|
/// <param name="alwaysBurnInSubtitleWhenTranscoding">Whether to always burn in subtitles when transcoding.</param>
|
||||||
/// <response code="200">Video stream returned.</response>
|
/// <response code="200">Video stream returned.</response>
|
||||||
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
|
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
|
||||||
[HttpGet("Videos/{itemId}/main.m3u8")]
|
[HttpGet("Videos/{itemId}/main.m3u8")]
|
||||||
@ -797,7 +805,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
[FromQuery] int? videoStreamIndex,
|
[FromQuery] int? videoStreamIndex,
|
||||||
[FromQuery] EncodingContext? context,
|
[FromQuery] EncodingContext? context,
|
||||||
[FromQuery] Dictionary<string, string> streamOptions,
|
[FromQuery] Dictionary<string, string> streamOptions,
|
||||||
[FromQuery] bool enableAudioVbrEncoding = true)
|
[FromQuery] bool enableAudioVbrEncoding = true,
|
||||||
|
[FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false)
|
||||||
{
|
{
|
||||||
using var cancellationTokenSource = new CancellationTokenSource();
|
using var cancellationTokenSource = new CancellationTokenSource();
|
||||||
var streamingRequest = new VideoRequestDto
|
var streamingRequest = new VideoRequestDto
|
||||||
@ -834,7 +843,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
MaxHeight = maxHeight,
|
MaxHeight = maxHeight,
|
||||||
VideoBitRate = videoBitRate,
|
VideoBitRate = videoBitRate,
|
||||||
SubtitleStreamIndex = subtitleStreamIndex,
|
SubtitleStreamIndex = subtitleStreamIndex,
|
||||||
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
|
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External,
|
||||||
MaxRefFrames = maxRefFrames,
|
MaxRefFrames = maxRefFrames,
|
||||||
MaxVideoBitDepth = maxVideoBitDepth,
|
MaxVideoBitDepth = maxVideoBitDepth,
|
||||||
RequireAvc = requireAvc ?? false,
|
RequireAvc = requireAvc ?? false,
|
||||||
@ -851,7 +860,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
VideoStreamIndex = videoStreamIndex,
|
VideoStreamIndex = videoStreamIndex,
|
||||||
Context = context ?? EncodingContext.Streaming,
|
Context = context ?? EncodingContext.Streaming,
|
||||||
StreamOptions = streamOptions,
|
StreamOptions = streamOptions,
|
||||||
EnableAudioVbrEncoding = enableAudioVbrEncoding
|
EnableAudioVbrEncoding = enableAudioVbrEncoding,
|
||||||
|
AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding
|
||||||
};
|
};
|
||||||
|
|
||||||
return await GetVariantPlaylistInternal(streamingRequest, cancellationTokenSource)
|
return await GetVariantPlaylistInternal(streamingRequest, cancellationTokenSource)
|
||||||
@ -1001,7 +1011,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
Height = height,
|
Height = height,
|
||||||
VideoBitRate = videoBitRate,
|
VideoBitRate = videoBitRate,
|
||||||
SubtitleStreamIndex = subtitleStreamIndex,
|
SubtitleStreamIndex = subtitleStreamIndex,
|
||||||
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
|
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External,
|
||||||
MaxRefFrames = maxRefFrames,
|
MaxRefFrames = maxRefFrames,
|
||||||
MaxVideoBitDepth = maxVideoBitDepth,
|
MaxVideoBitDepth = maxVideoBitDepth,
|
||||||
RequireAvc = requireAvc ?? false,
|
RequireAvc = requireAvc ?? false,
|
||||||
@ -1018,7 +1028,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
VideoStreamIndex = videoStreamIndex,
|
VideoStreamIndex = videoStreamIndex,
|
||||||
Context = context ?? EncodingContext.Streaming,
|
Context = context ?? EncodingContext.Streaming,
|
||||||
StreamOptions = streamOptions,
|
StreamOptions = streamOptions,
|
||||||
EnableAudioVbrEncoding = enableAudioVbrEncoding
|
EnableAudioVbrEncoding = enableAudioVbrEncoding,
|
||||||
|
AlwaysBurnInSubtitleWhenTranscoding = false
|
||||||
};
|
};
|
||||||
|
|
||||||
return await GetVariantPlaylistInternal(streamingRequest, cancellationTokenSource)
|
return await GetVariantPlaylistInternal(streamingRequest, cancellationTokenSource)
|
||||||
@ -1084,6 +1095,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
/// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
|
/// <param name="context">Optional. The <see cref="EncodingContext"/>.</param>
|
||||||
/// <param name="streamOptions">Optional. The streaming options.</param>
|
/// <param name="streamOptions">Optional. The streaming options.</param>
|
||||||
/// <param name="enableAudioVbrEncoding">Optional. Whether to enable Audio Encoding.</param>
|
/// <param name="enableAudioVbrEncoding">Optional. Whether to enable Audio Encoding.</param>
|
||||||
|
/// <param name="alwaysBurnInSubtitleWhenTranscoding">Whether to always burn in subtitles when transcoding.</param>
|
||||||
/// <response code="200">Video stream returned.</response>
|
/// <response code="200">Video stream returned.</response>
|
||||||
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
|
/// <returns>A <see cref="FileResult"/> containing the audio file.</returns>
|
||||||
[HttpGet("Videos/{itemId}/hls1/{playlistId}/{segmentId}.{container}")]
|
[HttpGet("Videos/{itemId}/hls1/{playlistId}/{segmentId}.{container}")]
|
||||||
@ -1146,7 +1158,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
[FromQuery] int? videoStreamIndex,
|
[FromQuery] int? videoStreamIndex,
|
||||||
[FromQuery] EncodingContext? context,
|
[FromQuery] EncodingContext? context,
|
||||||
[FromQuery] Dictionary<string, string> streamOptions,
|
[FromQuery] Dictionary<string, string> streamOptions,
|
||||||
[FromQuery] bool enableAudioVbrEncoding = true)
|
[FromQuery] bool enableAudioVbrEncoding = true,
|
||||||
|
[FromQuery] bool alwaysBurnInSubtitleWhenTranscoding = false)
|
||||||
{
|
{
|
||||||
var streamingRequest = new VideoRequestDto
|
var streamingRequest = new VideoRequestDto
|
||||||
{
|
{
|
||||||
@ -1185,7 +1198,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
MaxHeight = maxHeight,
|
MaxHeight = maxHeight,
|
||||||
VideoBitRate = videoBitRate,
|
VideoBitRate = videoBitRate,
|
||||||
SubtitleStreamIndex = subtitleStreamIndex,
|
SubtitleStreamIndex = subtitleStreamIndex,
|
||||||
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
|
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External,
|
||||||
MaxRefFrames = maxRefFrames,
|
MaxRefFrames = maxRefFrames,
|
||||||
MaxVideoBitDepth = maxVideoBitDepth,
|
MaxVideoBitDepth = maxVideoBitDepth,
|
||||||
RequireAvc = requireAvc ?? false,
|
RequireAvc = requireAvc ?? false,
|
||||||
@ -1202,7 +1215,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
VideoStreamIndex = videoStreamIndex,
|
VideoStreamIndex = videoStreamIndex,
|
||||||
Context = context ?? EncodingContext.Streaming,
|
Context = context ?? EncodingContext.Streaming,
|
||||||
StreamOptions = streamOptions,
|
StreamOptions = streamOptions,
|
||||||
EnableAudioVbrEncoding = enableAudioVbrEncoding
|
EnableAudioVbrEncoding = enableAudioVbrEncoding,
|
||||||
|
AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding
|
||||||
};
|
};
|
||||||
|
|
||||||
return await GetDynamicSegment(streamingRequest, segmentId)
|
return await GetDynamicSegment(streamingRequest, segmentId)
|
||||||
@ -1365,7 +1379,7 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
Height = height,
|
Height = height,
|
||||||
VideoBitRate = videoBitRate,
|
VideoBitRate = videoBitRate,
|
||||||
SubtitleStreamIndex = subtitleStreamIndex,
|
SubtitleStreamIndex = subtitleStreamIndex,
|
||||||
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.Encode,
|
SubtitleMethod = subtitleMethod ?? SubtitleDeliveryMethod.External,
|
||||||
MaxRefFrames = maxRefFrames,
|
MaxRefFrames = maxRefFrames,
|
||||||
MaxVideoBitDepth = maxVideoBitDepth,
|
MaxVideoBitDepth = maxVideoBitDepth,
|
||||||
RequireAvc = requireAvc ?? false,
|
RequireAvc = requireAvc ?? false,
|
||||||
@ -1382,7 +1396,8 @@ public class DynamicHlsController : BaseJellyfinApiController
|
|||||||
VideoStreamIndex = videoStreamIndex,
|
VideoStreamIndex = videoStreamIndex,
|
||||||
Context = context ?? EncodingContext.Streaming,
|
Context = context ?? EncodingContext.Streaming,
|
||||||
StreamOptions = streamOptions,
|
StreamOptions = streamOptions,
|
||||||
EnableAudioVbrEncoding = enableAudioVbrEncoding
|
EnableAudioVbrEncoding = enableAudioVbrEncoding,
|
||||||
|
AlwaysBurnInSubtitleWhenTranscoding = false
|
||||||
};
|
};
|
||||||
|
|
||||||
return await GetDynamicSegment(streamingRequest, segmentId)
|
return await GetDynamicSegment(streamingRequest, segmentId)
|
||||||
|
@ -293,6 +293,10 @@ public class MediaInfoHelper
|
|||||||
mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false";
|
mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false";
|
||||||
mediaSource.TranscodingContainer = streamInfo.Container;
|
mediaSource.TranscodingContainer = streamInfo.Container;
|
||||||
mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol;
|
mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol;
|
||||||
|
if (streamInfo.AlwaysBurnInSubtitleWhenTranscoding)
|
||||||
|
{
|
||||||
|
mediaSource.TranscodingUrl += "&alwaysBurnInSubtitleWhenTranscoding=true";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -310,6 +314,11 @@ public class MediaInfoHelper
|
|||||||
{
|
{
|
||||||
mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false";
|
mediaSource.TranscodingUrl += "&allowAudioStreamCopy=false";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (streamInfo.AlwaysBurnInSubtitleWhenTranscoding)
|
||||||
|
{
|
||||||
|
mediaSource.TranscodingUrl += "&alwaysBurnInSubtitleWhenTranscoding=true";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,6 +193,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
|
|
||||||
public bool EnableAudioVbrEncoding { get; set; }
|
public bool EnableAudioVbrEncoding { get; set; }
|
||||||
|
|
||||||
|
public bool AlwaysBurnInSubtitleWhenTranscoding { get; set; }
|
||||||
|
|
||||||
public string GetOption(string qualifier, string name)
|
public string GetOption(string qualifier, string name)
|
||||||
{
|
{
|
||||||
var value = GetOption(qualifier + "-" + name);
|
var value = GetOption(qualifier + "-" + name);
|
||||||
|
@ -941,7 +941,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
{
|
{
|
||||||
// DVBSUB uses the fixed canvas size 720x576
|
// DVBSUB uses the fixed canvas size 720x576
|
||||||
if (state.SubtitleStream is not null
|
if (state.SubtitleStream is not null
|
||||||
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
|
&& ShouldEncodeSubtitle(state)
|
||||||
&& !state.SubtitleStream.IsTextSubtitleStream
|
&& !state.SubtitleStream.IsTextSubtitleStream
|
||||||
&& !string.Equals(state.SubtitleStream.Codec, "DVBSUB", StringComparison.OrdinalIgnoreCase))
|
&& !string.Equals(state.SubtitleStream.Codec, "DVBSUB", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@ -1240,7 +1240,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
|
|
||||||
// sub2video for external graphical subtitles
|
// sub2video for external graphical subtitles
|
||||||
if (state.SubtitleStream is not null
|
if (state.SubtitleStream is not null
|
||||||
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
|
&& ShouldEncodeSubtitle(state)
|
||||||
&& !state.SubtitleStream.IsTextSubtitleStream
|
&& !state.SubtitleStream.IsTextSubtitleStream
|
||||||
&& state.SubtitleStream.IsExternal)
|
&& state.SubtitleStream.IsExternal)
|
||||||
{
|
{
|
||||||
@ -2554,7 +2554,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
}
|
}
|
||||||
|
|
||||||
var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive;
|
var isCopyingTimestamps = state.CopyTimestamps || state.TranscodingType != TranscodingJobType.Progressive;
|
||||||
if (state.SubtitleStream is not null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode && !isCopyingTimestamps)
|
if (state.SubtitleStream is not null && state.SubtitleStream.IsTextSubtitleStream && ShouldEncodeSubtitle(state) && !isCopyingTimestamps)
|
||||||
{
|
{
|
||||||
var seconds = TimeSpan.FromTicks(state.StartTimeTicks ?? 0).TotalSeconds;
|
var seconds = TimeSpan.FromTicks(state.StartTimeTicks ?? 0).TotalSeconds;
|
||||||
|
|
||||||
@ -2755,7 +2755,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
if (state.AudioStream.IsExternal)
|
if (state.AudioStream.IsExternal)
|
||||||
{
|
{
|
||||||
bool hasExternalGraphicsSubs = state.SubtitleStream is not null
|
bool hasExternalGraphicsSubs = state.SubtitleStream is not null
|
||||||
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
|
&& ShouldEncodeSubtitle(state)
|
||||||
&& state.SubtitleStream.IsExternal
|
&& state.SubtitleStream.IsExternal
|
||||||
&& !state.SubtitleStream.IsTextSubtitleStream;
|
&& !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
int externalAudioMapIndex = hasExternalGraphicsSubs ? 2 : 1;
|
int externalAudioMapIndex = hasExternalGraphicsSubs ? 2 : 1;
|
||||||
@ -3475,7 +3475,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var doToneMap = IsSwTonemapAvailable(state, options);
|
var doToneMap = IsSwTonemapAvailable(state, options);
|
||||||
var requireDoviReshaping = doToneMap && state.VideoStream.VideoRangeType == VideoRangeType.DOVI;
|
var requireDoviReshaping = doToneMap && state.VideoStream.VideoRangeType == VideoRangeType.DOVI;
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
|
|
||||||
@ -3618,7 +3618,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
||||||
var doCuTonemap = IsHwTonemapAvailable(state, options);
|
var doCuTonemap = IsHwTonemapAvailable(state, options);
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasAssSubs = hasSubs
|
var hasAssSubs = hasSubs
|
||||||
@ -3824,7 +3824,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
||||||
var doOclTonemap = IsHwTonemapAvailable(state, options);
|
var doOclTonemap = IsHwTonemapAvailable(state, options);
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasAssSubs = hasSubs
|
var hasAssSubs = hasSubs
|
||||||
@ -4064,7 +4064,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var doOclTonemap = !doVppTonemap && IsHwTonemapAvailable(state, options);
|
var doOclTonemap = !doVppTonemap && IsHwTonemapAvailable(state, options);
|
||||||
var doTonemap = doVppTonemap || doOclTonemap;
|
var doTonemap = doVppTonemap || doOclTonemap;
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasAssSubs = hasSubs
|
var hasAssSubs = hasSubs
|
||||||
@ -4320,7 +4320,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var doTonemap = doVaVppTonemap || doOclTonemap;
|
var doTonemap = doVaVppTonemap || doOclTonemap;
|
||||||
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasAssSubs = hasSubs
|
var hasAssSubs = hasSubs
|
||||||
@ -4636,7 +4636,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var doTonemap = doVaVppTonemap || doOclTonemap;
|
var doTonemap = doVaVppTonemap || doOclTonemap;
|
||||||
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasAssSubs = hasSubs
|
var hasAssSubs = hasSubs
|
||||||
@ -4858,7 +4858,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var doVkTonemap = IsVulkanHwTonemapAvailable(state, options);
|
var doVkTonemap = IsVulkanHwTonemapAvailable(state, options);
|
||||||
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasAssSubs = hasSubs
|
var hasAssSubs = hasSubs
|
||||||
@ -5091,7 +5091,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
||||||
var doOclTonemap = IsHwTonemapAvailable(state, options);
|
var doOclTonemap = IsHwTonemapAvailable(state, options);
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
|
|
||||||
@ -5339,7 +5339,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
|
|
||||||
var hwScaleFilter = GetHwScaleFilter("scale", "vt", scaleFormat, false, swpInW, swpInH, reqW, reqH, reqMaxW, reqMaxH);
|
var hwScaleFilter = GetHwScaleFilter("scale", "vt", scaleFormat, false, swpInW, swpInH, reqW, reqH, reqMaxW, reqMaxH);
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasAssSubs = hasSubs
|
var hasAssSubs = hasSubs
|
||||||
@ -5511,7 +5511,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
||||||
var doOclTonemap = IsHwTonemapAvailable(state, options);
|
var doOclTonemap = IsHwTonemapAvailable(state, options);
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream != null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasAssSubs = hasSubs
|
var hasAssSubs = hasSubs
|
||||||
@ -5722,7 +5722,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hasSubs = state.SubtitleStream is not null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasSubs = state.SubtitleStream is not null && ShouldEncodeSubtitle(state);
|
||||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||||
|
|
||||||
@ -7156,7 +7156,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
|
|
||||||
args += keyFrameArg;
|
args += keyFrameArg;
|
||||||
|
|
||||||
var hasGraphicalSubs = state.SubtitleStream is not null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
var hasGraphicalSubs = state.SubtitleStream is not null && !state.SubtitleStream.IsTextSubtitleStream && ShouldEncodeSubtitle(state);
|
||||||
|
|
||||||
var hasCopyTs = false;
|
var hasCopyTs = false;
|
||||||
|
|
||||||
@ -7361,5 +7361,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
{
|
{
|
||||||
return string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase);
|
return string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool ShouldEncodeSubtitle(EncodingJobInfo state)
|
||||||
|
{
|
||||||
|
return state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
|
||||||
|
|| (state.BaseRequest.AlwaysBurnInSubtitleWhenTranscoding && !IsCopyCodec(state.OutputVideoCodec));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -639,7 +639,8 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
RunTimeTicks = item.RunTimeTicks,
|
RunTimeTicks = item.RunTimeTicks,
|
||||||
Context = options.Context,
|
Context = options.Context,
|
||||||
DeviceProfile = options.Profile,
|
DeviceProfile = options.Profile,
|
||||||
SubtitleStreamIndex = options.SubtitleStreamIndex ?? GetDefaultSubtitleStreamIndex(item, options.Profile.SubtitleProfiles)
|
SubtitleStreamIndex = options.SubtitleStreamIndex ?? GetDefaultSubtitleStreamIndex(item, options.Profile.SubtitleProfiles),
|
||||||
|
AlwaysBurnInSubtitleWhenTranscoding = options.AlwaysBurnInSubtitleWhenTranscoding
|
||||||
};
|
};
|
||||||
|
|
||||||
var subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null;
|
var subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null;
|
||||||
@ -767,20 +768,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
if (subtitleStream is not null)
|
if (subtitleStream is not null)
|
||||||
{
|
{
|
||||||
var subtitleProfile = GetSubtitleProfile(item, subtitleStream, options.Profile.SubtitleProfiles, PlayMethod.Transcode, _transcoderSupport, transcodingProfile.Container, transcodingProfile.Protocol);
|
var subtitleProfile = GetSubtitleProfile(item, subtitleStream, options.Profile.SubtitleProfiles, PlayMethod.Transcode, _transcoderSupport, transcodingProfile.Container, transcodingProfile.Protocol);
|
||||||
|
playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
|
||||||
if (options.AlwaysBurnInSubtitleWhenTranscoding && (playlistItem.TranscodeReasons & (VideoReasons | TranscodeReason.ContainerBitrateExceedsLimit)) != 0)
|
|
||||||
{
|
|
||||||
playlistItem.SubtitleDeliveryMethod = SubtitleDeliveryMethod.Encode;
|
|
||||||
foreach (SubtitleProfile profile in options.Profile.SubtitleProfiles)
|
|
||||||
{
|
|
||||||
profile.Method = SubtitleDeliveryMethod.Encode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method;
|
|
||||||
}
|
|
||||||
|
|
||||||
playlistItem.SubtitleFormat = subtitleProfile.Format;
|
playlistItem.SubtitleFormat = subtitleProfile.Format;
|
||||||
playlistItem.SubtitleCodecs = [subtitleProfile.Format];
|
playlistItem.SubtitleCodecs = [subtitleProfile.Format];
|
||||||
}
|
}
|
||||||
|
@ -270,6 +270,11 @@ public class StreamInfo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EnableAudioVbrEncoding { get; set; }
|
public bool EnableAudioVbrEncoding { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether always burn in subtitles when transcoding.
|
||||||
|
/// </summary>
|
||||||
|
public bool AlwaysBurnInSubtitleWhenTranscoding { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether the stream is direct.
|
/// Gets a value indicating whether the stream is direct.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -953,7 +958,7 @@ public class StreamInfo
|
|||||||
list.Add(new NameValuePair("VideoCodec", videoCodecs));
|
list.Add(new NameValuePair("VideoCodec", videoCodecs));
|
||||||
list.Add(new NameValuePair("AudioCodec", audioCodecs));
|
list.Add(new NameValuePair("AudioCodec", audioCodecs));
|
||||||
list.Add(new NameValuePair("AudioStreamIndex", item.AudioStreamIndex.HasValue ? item.AudioStreamIndex.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
list.Add(new NameValuePair("AudioStreamIndex", item.AudioStreamIndex.HasValue ? item.AudioStreamIndex.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
||||||
list.Add(new NameValuePair("SubtitleStreamIndex", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? item.SubtitleStreamIndex.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
list.Add(new NameValuePair("SubtitleStreamIndex", item.SubtitleStreamIndex.HasValue && (item.AlwaysBurnInSubtitleWhenTranscoding || item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External) ? item.SubtitleStreamIndex.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
||||||
list.Add(new NameValuePair("VideoBitrate", item.VideoBitrate.HasValue ? item.VideoBitrate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
list.Add(new NameValuePair("VideoBitrate", item.VideoBitrate.HasValue ? item.VideoBitrate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
||||||
list.Add(new NameValuePair("AudioBitrate", item.AudioBitrate.HasValue ? item.AudioBitrate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
list.Add(new NameValuePair("AudioBitrate", item.AudioBitrate.HasValue ? item.AudioBitrate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
||||||
list.Add(new NameValuePair("AudioSampleRate", item.AudioSampleRate.HasValue ? item.AudioSampleRate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
list.Add(new NameValuePair("AudioSampleRate", item.AudioSampleRate.HasValue ? item.AudioSampleRate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user