diff --git a/Jellyfin.Api/Controllers/MediaInfoController.cs b/Jellyfin.Api/Controllers/MediaInfoController.cs
index bc52be1842..f22ac0b73a 100644
--- a/Jellyfin.Api/Controllers/MediaInfoController.cs
+++ b/Jellyfin.Api/Controllers/MediaInfoController.cs
@@ -209,6 +209,7 @@ public class MediaInfoController : BaseJellyfinApiController
enableTranscoding.Value,
allowVideoStreamCopy.Value,
allowAudioStreamCopy.Value,
+ playbackInfoDto?.AlwaysBurnInSubtitleWhenTranscoding ?? false,
Request.HttpContext.GetNormalizedRemoteIP());
}
@@ -236,7 +237,8 @@ public class MediaInfoController : BaseJellyfinApiController
StartTimeTicks = startTimeTicks,
SubtitleStreamIndex = subtitleStreamIndex,
UserId = userId ?? Guid.Empty,
- OpenToken = mediaSource.OpenToken
+ OpenToken = mediaSource.OpenToken,
+ AlwaysBurnInSubtitleWhenTranscoding = playbackInfoDto?.AlwaysBurnInSubtitleWhenTranscoding ?? false
}).ConfigureAwait(false);
info.MediaSources = new[] { openStreamResult.MediaSource };
@@ -261,6 +263,7 @@ public class MediaInfoController : BaseJellyfinApiController
/// The open live stream dto.
/// Whether to enable direct play. Default: true.
/// Whether to enable direct stream. Default: true.
+ /// Always burn-in subtitle when transcoding.
/// Media source opened.
/// A containing a .
[HttpPost("LiveStreams/Open")]
@@ -277,7 +280,8 @@ public class MediaInfoController : BaseJellyfinApiController
[FromQuery] Guid? itemId,
[FromBody] OpenLiveStreamDto? openLiveStreamDto,
[FromQuery] bool? enableDirectPlay,
- [FromQuery] bool? enableDirectStream)
+ [FromQuery] bool? enableDirectStream,
+ [FromQuery] bool? alwaysBurnInSubtitleWhenTranscoding)
{
userId ??= openLiveStreamDto?.UserId;
userId = RequestHelpers.GetUserId(User, userId);
@@ -295,7 +299,8 @@ public class MediaInfoController : BaseJellyfinApiController
DeviceProfile = openLiveStreamDto?.DeviceProfile,
EnableDirectPlay = enableDirectPlay ?? openLiveStreamDto?.EnableDirectPlay ?? true,
EnableDirectStream = enableDirectStream ?? openLiveStreamDto?.EnableDirectStream ?? true,
- DirectPlayProtocols = openLiveStreamDto?.DirectPlayProtocols ?? new[] { MediaProtocol.Http }
+ DirectPlayProtocols = openLiveStreamDto?.DirectPlayProtocols ?? new[] { MediaProtocol.Http },
+ AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding ?? openLiveStreamDto?.AlwaysBurnInSubtitleWhenTranscoding ?? false
};
return await _mediaInfoHelper.OpenMediaSource(HttpContext, request).ConfigureAwait(false);
}
diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs
index fe73534967..41c4886d4f 100644
--- a/Jellyfin.Api/Controllers/UniversalAudioController.cs
+++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs
@@ -160,6 +160,7 @@ public class UniversalAudioController : BaseJellyfinApiController
true,
true,
true,
+ false,
Request.HttpContext.GetNormalizedRemoteIP());
}
diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
index 9bda27031b..5050cab418 100644
--- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs
+++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
@@ -156,6 +156,7 @@ public class MediaInfoHelper
/// Enable transcoding.
/// Allow video stream copy.
/// Allow audio stream copy.
+ /// Always burn-in subtitle when transcoding.
/// Requesting IP address.
public void SetDeviceSpecificData(
BaseItem item,
@@ -175,6 +176,7 @@ public class MediaInfoHelper
bool enableTranscoding,
bool allowVideoStreamCopy,
bool allowAudioStreamCopy,
+ bool alwaysBurnInSubtitleWhenTranscoding,
IPAddress ipAddress)
{
var streamBuilder = new StreamBuilder(_mediaEncoder, _logger);
@@ -188,7 +190,8 @@ public class MediaInfoHelper
Profile = profile,
MaxAudioChannels = maxAudioChannels,
AllowAudioStreamCopy = allowAudioStreamCopy,
- AllowVideoStreamCopy = allowVideoStreamCopy
+ AllowVideoStreamCopy = allowVideoStreamCopy,
+ AlwaysBurnInSubtitleWhenTranscoding = alwaysBurnInSubtitleWhenTranscoding,
};
if (string.Equals(mediaSourceId, mediaSource.Id, StringComparison.OrdinalIgnoreCase))
@@ -420,6 +423,7 @@ public class MediaInfoHelper
true,
true,
true,
+ request.AlwaysBurnInSubtitleWhenTranscoding,
httpContext.GetNormalizedRemoteIP());
}
else
diff --git a/Jellyfin.Api/Models/MediaInfoDtos/OpenLiveStreamDto.cs b/Jellyfin.Api/Models/MediaInfoDtos/OpenLiveStreamDto.cs
index 53104988f5..978e99b35c 100644
--- a/Jellyfin.Api/Models/MediaInfoDtos/OpenLiveStreamDto.cs
+++ b/Jellyfin.Api/Models/MediaInfoDtos/OpenLiveStreamDto.cs
@@ -65,6 +65,11 @@ public class OpenLiveStreamDto
///
public bool? EnableDirectStream { get; set; }
+ ///
+ /// Gets or sets a value indicating whether always burn in subtitles when transcoding.
+ ///
+ public bool? AlwaysBurnInSubtitleWhenTranscoding { get; set; }
+
///
/// Gets or sets the device profile.
///
diff --git a/Jellyfin.Api/Models/MediaInfoDtos/PlaybackInfoDto.cs b/Jellyfin.Api/Models/MediaInfoDtos/PlaybackInfoDto.cs
index 9e12ddde65..82f603ca1e 100644
--- a/Jellyfin.Api/Models/MediaInfoDtos/PlaybackInfoDto.cs
+++ b/Jellyfin.Api/Models/MediaInfoDtos/PlaybackInfoDto.cs
@@ -82,4 +82,9 @@ public class PlaybackInfoDto
/// Gets or sets a value indicating whether to auto open the live stream.
///
public bool? AutoOpenLiveStream { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether always burn in subtitles when transcoding.
+ ///
+ public bool? AlwaysBurnInSubtitleWhenTranscoding { get; set; }
}
diff --git a/MediaBrowser.Model/Dlna/MediaOptions.cs b/MediaBrowser.Model/Dlna/MediaOptions.cs
index eca971e95e..6b26ca94b5 100644
--- a/MediaBrowser.Model/Dlna/MediaOptions.cs
+++ b/MediaBrowser.Model/Dlna/MediaOptions.cs
@@ -49,6 +49,11 @@ namespace MediaBrowser.Model.Dlna
///
public bool AllowVideoStreamCopy { get; set; }
+ ///
+ /// Gets or sets a value indicating whether always burn in subtitles when transcoding.
+ ///
+ public bool AlwaysBurnInSubtitleWhenTranscoding { get; set; }
+
///
/// Gets or sets the item id.
///
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index f68a8bca34..e4492ac79b 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -20,8 +20,8 @@ namespace MediaBrowser.Model.Dlna
// Aliases
internal const TranscodeReason ContainerReasons = TranscodeReason.ContainerNotSupported | TranscodeReason.ContainerBitrateExceedsLimit;
internal const TranscodeReason AudioReasons = TranscodeReason.AudioCodecNotSupported | TranscodeReason.AudioBitrateNotSupported | TranscodeReason.AudioChannelsNotSupported | TranscodeReason.AudioProfileNotSupported | TranscodeReason.AudioSampleRateNotSupported | TranscodeReason.SecondaryAudioNotSupported | TranscodeReason.AudioBitDepthNotSupported | TranscodeReason.AudioIsExternal;
- internal const TranscodeReason VideoReasons = TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoResolutionNotSupported | TranscodeReason.AnamorphicVideoNotSupported | TranscodeReason.InterlacedVideoNotSupported | TranscodeReason.VideoBitDepthNotSupported | TranscodeReason.VideoBitrateNotSupported | TranscodeReason.VideoFramerateNotSupported | TranscodeReason.VideoLevelNotSupported | TranscodeReason.RefFramesNotSupported;
- internal const TranscodeReason DirectStreamReasons = AudioReasons | TranscodeReason.ContainerNotSupported;
+ internal const TranscodeReason VideoReasons = TranscodeReason.VideoCodecNotSupported | TranscodeReason.VideoResolutionNotSupported | TranscodeReason.AnamorphicVideoNotSupported | TranscodeReason.InterlacedVideoNotSupported | TranscodeReason.VideoBitDepthNotSupported | TranscodeReason.VideoBitrateNotSupported | TranscodeReason.VideoFramerateNotSupported | TranscodeReason.VideoLevelNotSupported | TranscodeReason.RefFramesNotSupported | TranscodeReason.VideoRangeTypeNotSupported | TranscodeReason.VideoProfileNotSupported;
+ internal const TranscodeReason DirectStreamReasons = AudioReasons | TranscodeReason.ContainerNotSupported | TranscodeReason.VideoCodecTagNotSupported;
private readonly ILogger _logger;
private readonly ITranscoderSupport _transcoderSupport;
@@ -352,7 +352,7 @@ namespace MediaBrowser.Model.Dlna
return TranscodeReason.VideoBitrateNotSupported;
case ProfileConditionValue.VideoCodecTag:
- return TranscodeReason.VideoCodecNotSupported;
+ return TranscodeReason.VideoCodecTagNotSupported;
case ProfileConditionValue.VideoFramerate:
return TranscodeReason.VideoFramerateNotSupported;
@@ -765,7 +765,19 @@ namespace MediaBrowser.Model.Dlna
{
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.SubtitleCodecs = new[] { subtitleProfile.Format };
}
diff --git a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs
index 24eab1a744..92f467eb08 100644
--- a/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs
+++ b/MediaBrowser.Model/MediaInfo/LiveStreamRequest.cs
@@ -13,6 +13,7 @@ namespace MediaBrowser.Model.MediaInfo
{
EnableDirectPlay = true;
EnableDirectStream = true;
+ AlwaysBurnInSubtitleWhenTranscoding = false;
DirectPlayProtocols = new MediaProtocol[] { MediaProtocol.Http };
}
@@ -40,6 +41,8 @@ namespace MediaBrowser.Model.MediaInfo
public bool EnableDirectStream { get; set; }
+ public bool AlwaysBurnInSubtitleWhenTranscoding { get; set; }
+
public IReadOnlyList DirectPlayProtocols { get; set; }
}
}
diff --git a/MediaBrowser.Model/Session/TranscodeReason.cs b/MediaBrowser.Model/Session/TranscodeReason.cs
index bbdf4536b7..39c5ac8fa4 100644
--- a/MediaBrowser.Model/Session/TranscodeReason.cs
+++ b/MediaBrowser.Model/Session/TranscodeReason.cs
@@ -18,6 +18,7 @@ namespace MediaBrowser.Model.Session
// Video Constraints
VideoProfileNotSupported = 1 << 6,
VideoRangeTypeNotSupported = 1 << 24,
+ VideoCodecTagNotSupported = 1 << 25,
VideoLevelNotSupported = 1 << 7,
VideoResolutionNotSupported = 1 << 8,
VideoBitDepthNotSupported = 1 << 9,