|
|
|
@ -204,6 +204,13 @@ namespace Jellyfin.Api.Helpers
|
|
|
|
|
|
|
|
|
|
if (state.VideoStream != null && state.VideoRequest != null)
|
|
|
|
|
{
|
|
|
|
|
// Provide a workaround for the case issue between flac and fLaC.
|
|
|
|
|
var flacWaPlaylist = ApplyFlacCaseWorkaround(state, basicPlaylist.ToString());
|
|
|
|
|
if (!String.IsNullOrEmpty(flacWaPlaylist))
|
|
|
|
|
{
|
|
|
|
|
builder.Append(flacWaPlaylist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var encodingOptions = _serverConfigurationManager.GetEncodingOptions();
|
|
|
|
|
|
|
|
|
|
// Provide SDR HEVC entrance for backward compatibility.
|
|
|
|
@ -221,26 +228,26 @@ namespace Jellyfin.Api.Helpers
|
|
|
|
|
var sdrVideoUrl = ReplaceProfile(playlistUrl, "hevc", string.Join(',', requestedVideoProfiles), "main");
|
|
|
|
|
sdrVideoUrl += "&AllowVideoStreamCopy=false";
|
|
|
|
|
|
|
|
|
|
var sdrOutputVideoBitrate = _encodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);
|
|
|
|
|
var sdrOutputAudioBitrate = 0;
|
|
|
|
|
if (EncodingHelper.LosslessAudioCodecs.Contains(state.VideoRequest.AudioCodec, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
sdrOutputAudioBitrate = state.AudioStream.BitRate ?? 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sdrOutputAudioBitrate = _encodingHelper.GetAudioBitrateParam(state.VideoRequest, state.AudioStream, state.OutputAudioChannels) ?? 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var sdrTotalBitrate = sdrOutputAudioBitrate + sdrOutputVideoBitrate;
|
|
|
|
|
var sdrPlaylist = AppendPlaylist(builder, state, sdrVideoUrl, sdrTotalBitrate, subtitleGroup);
|
|
|
|
|
|
|
|
|
|
// Provide a workaround for the case issue between flac and fLaC.
|
|
|
|
|
flacWaPlaylist = ApplyFlacCaseWorkaround(state, sdrPlaylist.ToString());
|
|
|
|
|
if (!string.IsNullOrEmpty(flacWaPlaylist))
|
|
|
|
|
{
|
|
|
|
|
builder.Append(flacWaPlaylist);
|
|
|
|
|
}
|
|
|
|
|
var sdrOutputVideoBitrate = _encodingHelper.GetVideoBitrateParamValue(state.VideoRequest, state.VideoStream, state.OutputVideoCodec);
|
|
|
|
|
var sdrOutputAudioBitrate = 0;
|
|
|
|
|
if (EncodingHelper.LosslessAudioCodecs.Contains(state.VideoRequest.AudioCodec, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
sdrOutputAudioBitrate = state.AudioStream.BitRate ?? 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sdrOutputAudioBitrate = _encodingHelper.GetAudioBitrateParam(state.VideoRequest, state.AudioStream, state.OutputAudioChannels) ?? 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var sdrTotalBitrate = sdrOutputAudioBitrate + sdrOutputVideoBitrate;
|
|
|
|
|
var sdrPlaylist = AppendPlaylist(builder, state, sdrVideoUrl, sdrTotalBitrate, subtitleGroup);
|
|
|
|
|
|
|
|
|
|
// Provide a workaround for the case issue between flac and fLaC.
|
|
|
|
|
flacWaPlaylist = ApplyFlacCaseWorkaround(state, sdrPlaylist.ToString());
|
|
|
|
|
if (!String.IsNullOrEmpty(flacWaPlaylist))
|
|
|
|
|
{
|
|
|
|
|
builder.Append(flacWaPlaylist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Restore the video codec
|
|
|
|
|
state.OutputVideoCodec = "copy";
|
|
|
|
@ -270,6 +277,13 @@ namespace Jellyfin.Api.Helpers
|
|
|
|
|
state.VideoStream.Level = originalLevel;
|
|
|
|
|
var newPlaylist = ReplacePlaylistCodecsField(basicPlaylist, playlistCodecsField, newPlaylistCodecsField);
|
|
|
|
|
builder.Append(newPlaylist);
|
|
|
|
|
|
|
|
|
|
// Provide a workaround for the case issue between flac and fLaC.
|
|
|
|
|
flacWaPlaylist = ApplyFlacCaseWorkaround(state, newPlaylist);
|
|
|
|
|
if (!String.IsNullOrEmpty(flacWaPlaylist))
|
|
|
|
|
{
|
|
|
|
|
builder.Append(flacWaPlaylist);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -628,6 +642,11 @@ namespace Jellyfin.Api.Helpers
|
|
|
|
|
return HlsCodecStringHelpers.GetALACString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.Equals(state.ActualOutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
return HlsCodecStringHelpers.GetOPUSString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -726,7 +745,19 @@ namespace Jellyfin.Api.Helpers
|
|
|
|
|
return oldPlaylist.Replace(
|
|
|
|
|
oldValue.ToString(),
|
|
|
|
|
newValue.ToString(),
|
|
|
|
|
StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
StringComparison.Ordinal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string ApplyFlacCaseWorkaround(StreamState state, string srcPlaylist)
|
|
|
|
|
{
|
|
|
|
|
if (!string.Equals(state.ActualOutputAudioCodec, "flac", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
return string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var newPlaylist = srcPlaylist.Replace(",flac\"", ",fLaC\"", StringComparison.Ordinal);
|
|
|
|
|
|
|
|
|
|
return newPlaylist.Contains(",fLaC\"", StringComparison.Ordinal) ? newPlaylist : string.Empty;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|