mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-07-22 13:40:37 +02:00
Normalize orgPn usage
This commit is contained in:
parent
fdd8c67162
commit
44bfad70d2
|
@ -1507,6 +1507,16 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var headers = new Dictionary<string, string>();
|
||||||
|
foreach (var key in Request.Headers.AllKeys)
|
||||||
|
{
|
||||||
|
headers[key] = Request.Headers[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
state.DeviceProfile = string.IsNullOrWhiteSpace(state.Request.DeviceProfileId) ?
|
||||||
|
DlnaManager.GetProfile(headers) :
|
||||||
|
DlnaManager.GetProfile(state.Request.DeviceProfileId);
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1631,16 +1641,7 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
private void ApplyDeviceProfileSettings(StreamState state)
|
private void ApplyDeviceProfileSettings(StreamState state)
|
||||||
{
|
{
|
||||||
var headers = new Dictionary<string, string>();
|
var profile = state.DeviceProfile;
|
||||||
|
|
||||||
foreach (var key in Request.Headers.AllKeys)
|
|
||||||
{
|
|
||||||
headers[key] = Request.Headers[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
var profile = string.IsNullOrWhiteSpace(state.Request.DeviceProfileId) ?
|
|
||||||
DlnaManager.GetProfile(headers) :
|
|
||||||
DlnaManager.GetProfile(state.Request.DeviceProfileId);
|
|
||||||
|
|
||||||
if (profile == null)
|
if (profile == null)
|
||||||
{
|
{
|
||||||
|
@ -1664,13 +1665,12 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
|
|
||||||
var mediaProfile = state.VideoRequest == null ?
|
var mediaProfile = state.VideoRequest == null ?
|
||||||
profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.AudioStream) :
|
profile.GetAudioMediaProfile(state.OutputContainer, audioCodec) :
|
||||||
profile.GetVideoMediaProfile(state.OutputContainer, audioCodec, videoCodec, state.AudioStream, state.VideoStream);
|
profile.GetVideoMediaProfile(state.OutputContainer, audioCodec, videoCodec);
|
||||||
|
|
||||||
if (mediaProfile != null)
|
if (mediaProfile != null)
|
||||||
{
|
{
|
||||||
state.MimeType = mediaProfile.MimeType;
|
state.MimeType = mediaProfile.MimeType;
|
||||||
state.OrgPn = mediaProfile.OrgPn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var transcodingProfile = state.VideoRequest == null ?
|
var transcodingProfile = state.VideoRequest == null ?
|
||||||
|
@ -1699,45 +1699,65 @@ namespace MediaBrowser.Api.Playback
|
||||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||||
protected void AddDlnaHeaders(StreamState state, IDictionary<string, string> responseHeaders, bool isStaticallyStreamed)
|
protected void AddDlnaHeaders(StreamState state, IDictionary<string, string> responseHeaders, bool isStaticallyStreamed)
|
||||||
{
|
{
|
||||||
|
var profile = state.DeviceProfile;
|
||||||
|
|
||||||
|
if (profile == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var transferMode = GetHeader("transferMode.dlna.org");
|
var transferMode = GetHeader("transferMode.dlna.org");
|
||||||
responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode;
|
responseHeaders["transferMode.dlna.org"] = string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode;
|
||||||
responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*";
|
responseHeaders["realTimeInfo.dlna.org"] = "DLNA.ORG_TLAG=*";
|
||||||
|
|
||||||
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
|
|
||||||
var orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(state.RunTimeTicks.HasValue, isStaticallyStreamed, state.TranscodeSeekInfo);
|
|
||||||
|
|
||||||
if (state.RunTimeTicks.HasValue && !isStaticallyStreamed)
|
if (state.RunTimeTicks.HasValue && !isStaticallyStreamed)
|
||||||
{
|
{
|
||||||
AddTimeSeekResponseHeaders(state, responseHeaders);
|
AddTimeSeekResponseHeaders(state, responseHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 = native, 1 = transcoded
|
var audioCodec = state.Request.AudioCodec;
|
||||||
var orgCi = isStaticallyStreamed ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
|
|
||||||
|
|
||||||
var flagValue = DlnaFlags.StreamingTransferMode |
|
if (state.VideoRequest == null)
|
||||||
DlnaFlags.BackgroundTransferMode |
|
|
||||||
DlnaFlags.DlnaV15;
|
|
||||||
|
|
||||||
if (isStaticallyStreamed)
|
|
||||||
{
|
{
|
||||||
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_BYTE_BASED_SEEK;
|
responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile)
|
||||||
|
.BuildAudioHeader(
|
||||||
|
state.OutputContainer,
|
||||||
|
audioCodec,
|
||||||
|
state.OutputAudioBitrate,
|
||||||
|
state.OutputAudioSampleRate,
|
||||||
|
state.OutputAudioChannels,
|
||||||
|
isStaticallyStreamed,
|
||||||
|
state.RunTimeTicks,
|
||||||
|
state.TranscodeSeekInfo
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (state.RunTimeTicks.HasValue)
|
else
|
||||||
{
|
{
|
||||||
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_TIME_BASED_SEEK;
|
if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null)
|
||||||
}
|
{
|
||||||
|
audioCodec = state.AudioStream.Codec;
|
||||||
|
}
|
||||||
|
|
||||||
var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000",
|
var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec;
|
||||||
Enum.Format(typeof(DlnaFlags), flagValue, "x"));
|
|
||||||
|
|
||||||
var orgPn = GetOrgPnValue(state);
|
if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null)
|
||||||
|
{
|
||||||
|
videoCodec = state.VideoStream.Codec;
|
||||||
|
}
|
||||||
|
|
||||||
var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty :
|
responseHeaders["contentFeatures.dlna.org"] = new ContentFeatureBuilder(profile)
|
||||||
"DLNA.ORG_PN=" + orgPn;
|
.BuildVideoHeader(
|
||||||
|
state.OutputContainer,
|
||||||
if (!string.IsNullOrEmpty(contentFeatures))
|
videoCodec,
|
||||||
{
|
audioCodec,
|
||||||
responseHeaders["contentFeatures.dlna.org"] = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
state.OutputWidth,
|
||||||
|
state.OutputHeight,
|
||||||
|
state.TotalOutputBitrate,
|
||||||
|
TransportStreamTimestamp.VALID,
|
||||||
|
isStaticallyStreamed,
|
||||||
|
state.RunTimeTicks,
|
||||||
|
state.TranscodeSeekInfo
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var item in responseHeaders)
|
foreach (var item in responseHeaders)
|
||||||
|
@ -1746,50 +1766,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetOrgPnValue(StreamState state)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(state.OrgPn))
|
|
||||||
{
|
|
||||||
return state.OrgPn;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.VideoRequest == null)
|
|
||||||
{
|
|
||||||
var format = new MediaFormatProfileResolver()
|
|
||||||
.ResolveAudioFormat(state.OutputContainer,
|
|
||||||
state.OutputAudioBitrate,
|
|
||||||
state.OutputAudioSampleRate,
|
|
||||||
state.OutputAudioChannels);
|
|
||||||
|
|
||||||
return format.HasValue ? format.Value.ToString() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var audioCodec = state.Request.AudioCodec;
|
|
||||||
|
|
||||||
if (string.Equals(audioCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.AudioStream != null)
|
|
||||||
{
|
|
||||||
audioCodec = state.AudioStream.Codec;
|
|
||||||
}
|
|
||||||
|
|
||||||
var videoCodec = state.VideoRequest == null ? null : state.VideoRequest.VideoCodec;
|
|
||||||
|
|
||||||
if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase) && state.VideoStream != null)
|
|
||||||
{
|
|
||||||
videoCodec = state.VideoStream.Codec;
|
|
||||||
}
|
|
||||||
|
|
||||||
var videoFormat = new MediaFormatProfileResolver()
|
|
||||||
.ResolveVideoFormat(state.OutputContainer,
|
|
||||||
videoCodec,
|
|
||||||
audioCodec,
|
|
||||||
state.OutputWidth,
|
|
||||||
state.OutputHeight,
|
|
||||||
state.TotalOutputBitrate,
|
|
||||||
TransportStreamTimestamp.VALID);
|
|
||||||
|
|
||||||
return videoFormat.HasValue ? videoFormat.Value.ToString() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddTimeSeekResponseHeaders(StreamState state, IDictionary<string, string> responseHeaders)
|
private void AddTimeSeekResponseHeaders(StreamState state, IDictionary<string, string> responseHeaders)
|
||||||
{
|
{
|
||||||
var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds.ToString(UsCulture);
|
var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalSeconds.ToString(UsCulture);
|
||||||
|
|
|
@ -84,7 +84,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
public string InputAudioCodec { get; set; }
|
public string InputAudioCodec { get; set; }
|
||||||
|
|
||||||
public string MimeType { get; set; }
|
public string MimeType { get; set; }
|
||||||
public string OrgPn { get; set; }
|
|
||||||
|
|
||||||
public bool EstimateContentLength { get; set; }
|
public bool EstimateContentLength { get; set; }
|
||||||
public bool EnableMpegtsM2TsMode { get; set; }
|
public bool EnableMpegtsM2TsMode { get; set; }
|
||||||
|
@ -163,6 +162,8 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
public string OutputContainer { get; set; }
|
public string OutputContainer { get; set; }
|
||||||
|
|
||||||
|
public DeviceProfile DeviceProfile { get; set; }
|
||||||
|
|
||||||
public int? TotalOutputBitrate
|
public int? TotalOutputBitrate
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
@ -401,66 +401,38 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
private string GetDlnaHeaders(PlaylistItem item)
|
private string GetDlnaHeaders(PlaylistItem item)
|
||||||
{
|
{
|
||||||
|
var profile = item.Profile;
|
||||||
var streamInfo = item.StreamInfo;
|
var streamInfo = item.StreamInfo;
|
||||||
|
|
||||||
var orgOp = !streamInfo.IsDirectStream ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01";
|
if (streamInfo.MediaType == DlnaProfileType.Audio)
|
||||||
|
|
||||||
var orgCi = !streamInfo.IsDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
|
|
||||||
|
|
||||||
const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
|
|
||||||
|
|
||||||
string contentFeatures;
|
|
||||||
|
|
||||||
var container = streamInfo.Container.TrimStart('.');
|
|
||||||
|
|
||||||
if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
contentFeatures = "DLNA.ORG_PN=MP3";
|
return new ContentFeatureBuilder(profile)
|
||||||
}
|
.BuildAudioHeader(streamInfo.Container,
|
||||||
else if (string.Equals(container, "wma", StringComparison.OrdinalIgnoreCase))
|
streamInfo.AudioCodec,
|
||||||
{
|
streamInfo.TargetAudioBitrate,
|
||||||
contentFeatures = "DLNA.ORG_PN=WMABASE";
|
streamInfo.TargetAudioSampleRate,
|
||||||
}
|
streamInfo.TargetAudioChannels,
|
||||||
else if (string.Equals(container, "wmw", StringComparison.OrdinalIgnoreCase))
|
streamInfo.IsDirectStream,
|
||||||
{
|
streamInfo.RunTimeTicks,
|
||||||
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
|
streamInfo.TranscodeSeekInfo);
|
||||||
}
|
|
||||||
else if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
|
|
||||||
}
|
|
||||||
else if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=AVI";
|
|
||||||
}
|
|
||||||
else if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=MATROSKA";
|
|
||||||
}
|
|
||||||
else if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC";
|
|
||||||
}
|
|
||||||
else if (string.Equals(container, "mpeg", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
|
||||||
}
|
|
||||||
else if (string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
|
||||||
}
|
|
||||||
else if (streamInfo.MediaType == DlnaProfileType.Video)
|
|
||||||
{
|
|
||||||
// Default to AVI for video
|
|
||||||
contentFeatures = "DLNA.ORG_PN=AVI";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Default to MP3 for audio
|
|
||||||
contentFeatures = "DLNA.ORG_PN=MP3";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
if (streamInfo.MediaType == DlnaProfileType.Video)
|
||||||
|
{
|
||||||
|
return new ContentFeatureBuilder(profile)
|
||||||
|
.BuildVideoHeader(streamInfo.Container,
|
||||||
|
streamInfo.VideoCodec,
|
||||||
|
streamInfo.AudioCodec,
|
||||||
|
streamInfo.TargetWidth,
|
||||||
|
streamInfo.TargetHeight,
|
||||||
|
streamInfo.TotalOutputBitrate,
|
||||||
|
streamInfo.TargetTimestamp,
|
||||||
|
streamInfo.IsDirectStream,
|
||||||
|
streamInfo.RunTimeTicks,
|
||||||
|
streamInfo.TranscodeSeekInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlaylistItem GetPlaylistItem(BaseItem item, List<MediaSourceInfo> mediaSources, DeviceProfile profile, string deviceId)
|
private PlaylistItem GetPlaylistItem(BaseItem item, List<MediaSourceInfo> mediaSources, DeviceProfile profile, string deviceId)
|
||||||
|
@ -477,7 +449,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
MediaSources = mediaSources,
|
MediaSources = mediaSources,
|
||||||
Profile = profile,
|
Profile = profile,
|
||||||
DeviceId = deviceId
|
DeviceId = deviceId
|
||||||
})
|
}),
|
||||||
|
|
||||||
|
Profile = profile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,7 +467,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
MediaSources = mediaSources,
|
MediaSources = mediaSources,
|
||||||
Profile = profile,
|
Profile = profile,
|
||||||
DeviceId = deviceId
|
DeviceId = deviceId
|
||||||
})
|
}),
|
||||||
|
|
||||||
|
Profile = profile
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,10 +104,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a socket for the interface and listends for data.
|
/// Creates a socket for the interface and listends for data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -104,7 +104,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_manager.Stop();
|
|
||||||
_manager.Dispose();
|
_manager.Dispose();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
@ -11,5 +11,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
public string Didl { get; set; }
|
public string Didl { get; set; }
|
||||||
|
|
||||||
public StreamInfo StreamInfo { get; set; }
|
public StreamInfo StreamInfo { get; set; }
|
||||||
|
|
||||||
|
public DeviceProfile Profile { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,7 +19,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
ItemId = item.Id.ToString("N"),
|
ItemId = item.Id.ToString("N"),
|
||||||
MediaType = DlnaProfileType.Photo,
|
MediaType = DlnaProfileType.Photo,
|
||||||
}
|
},
|
||||||
|
|
||||||
|
Profile = profile
|
||||||
};
|
};
|
||||||
|
|
||||||
var directPlay = profile.DirectPlayProfiles
|
var directPlay = profile.DirectPlayProfiles
|
||||||
|
|
|
@ -632,9 +632,7 @@ namespace MediaBrowser.Dlna.Server
|
||||||
|
|
||||||
var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
|
var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
|
||||||
streamInfo.AudioCodec,
|
streamInfo.AudioCodec,
|
||||||
streamInfo.VideoCodec,
|
streamInfo.VideoCodec);
|
||||||
streamInfo.TargetAudioStream,
|
|
||||||
streamInfo.TargetVideoStream);
|
|
||||||
|
|
||||||
var formatProfile = mediaProfile == null ? null : mediaProfile.OrgPn;
|
var formatProfile = mediaProfile == null ? null : mediaProfile.OrgPn;
|
||||||
|
|
||||||
|
@ -646,7 +644,7 @@ namespace MediaBrowser.Dlna.Server
|
||||||
targetWidth,
|
targetWidth,
|
||||||
targetHeight,
|
targetHeight,
|
||||||
targetBitrate,
|
targetBitrate,
|
||||||
TransportStreamTimestamp.VALID);
|
streamInfo.TargetTimestamp);
|
||||||
|
|
||||||
formatProfile = format.HasValue ? format.Value.ToString() : null;
|
formatProfile = format.HasValue ? format.Value.ToString() : null;
|
||||||
}
|
}
|
||||||
|
@ -731,8 +729,7 @@ namespace MediaBrowser.Dlna.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
|
var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
|
||||||
streamInfo.AudioCodec,
|
streamInfo.AudioCodec);
|
||||||
streamInfo.TargetAudioStream);
|
|
||||||
|
|
||||||
var formatProfile = mediaProfile == null ? null : mediaProfile.OrgPn;
|
var formatProfile = mediaProfile == null ? null : mediaProfile.OrgPn;
|
||||||
|
|
||||||
|
@ -780,11 +777,11 @@ namespace MediaBrowser.Dlna.Server
|
||||||
{
|
{
|
||||||
if (item is MusicAlbum)
|
if (item is MusicAlbum)
|
||||||
{
|
{
|
||||||
classType = "object.container.musicAlbum";
|
classType = "object.container.album.musicAlbum";
|
||||||
}
|
}
|
||||||
if (item is MusicArtist)
|
if (item is MusicArtist)
|
||||||
{
|
{
|
||||||
classType = "object.container.musicArtist";
|
classType = "object.container.person.musicArtist";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
130
MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
Normal file
130
MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.Dlna
|
||||||
|
{
|
||||||
|
public class ContentFeatureBuilder
|
||||||
|
{
|
||||||
|
private readonly DeviceProfile _profile;
|
||||||
|
|
||||||
|
public ContentFeatureBuilder(DeviceProfile profile)
|
||||||
|
{
|
||||||
|
_profile = profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BuildAudioHeader(string container,
|
||||||
|
string audioCodec,
|
||||||
|
int? audioBitrate,
|
||||||
|
int? audioSampleRate,
|
||||||
|
int? audioChannels,
|
||||||
|
bool isDirectStream,
|
||||||
|
long? runtimeTicks,
|
||||||
|
TranscodeSeekInfo transcodeSeekInfo)
|
||||||
|
{
|
||||||
|
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
|
||||||
|
var orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo);
|
||||||
|
|
||||||
|
// 0 = native, 1 = transcoded
|
||||||
|
var orgCi = isDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
|
||||||
|
|
||||||
|
var flagValue = DlnaFlags.StreamingTransferMode |
|
||||||
|
DlnaFlags.BackgroundTransferMode |
|
||||||
|
DlnaFlags.DlnaV15;
|
||||||
|
|
||||||
|
if (isDirectStream)
|
||||||
|
{
|
||||||
|
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_BYTE_BASED_SEEK;
|
||||||
|
}
|
||||||
|
else if (runtimeTicks.HasValue)
|
||||||
|
{
|
||||||
|
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_TIME_BASED_SEEK;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000",
|
||||||
|
Enum.Format(typeof(DlnaFlags), flagValue, "x"));
|
||||||
|
|
||||||
|
var mediaProfile = _profile.GetAudioMediaProfile(container, audioCodec);
|
||||||
|
|
||||||
|
var orgPn = mediaProfile == null ? null : mediaProfile.OrgPn;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(orgPn))
|
||||||
|
{
|
||||||
|
orgPn = GetAudioOrgPnValue(container, audioBitrate, audioSampleRate, audioChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn;
|
||||||
|
|
||||||
|
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BuildVideoHeader(string container,
|
||||||
|
string videoCodec,
|
||||||
|
string audioCodec,
|
||||||
|
int? width,
|
||||||
|
int? height,
|
||||||
|
int? bitrate,
|
||||||
|
TransportStreamTimestamp timestamp,
|
||||||
|
bool isDirectStream,
|
||||||
|
long? runtimeTicks,
|
||||||
|
TranscodeSeekInfo transcodeSeekInfo)
|
||||||
|
{
|
||||||
|
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
|
||||||
|
var orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks.HasValue, isDirectStream, transcodeSeekInfo);
|
||||||
|
|
||||||
|
// 0 = native, 1 = transcoded
|
||||||
|
var orgCi = isDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
|
||||||
|
|
||||||
|
var flagValue = DlnaFlags.StreamingTransferMode |
|
||||||
|
DlnaFlags.BackgroundTransferMode |
|
||||||
|
DlnaFlags.DlnaV15;
|
||||||
|
|
||||||
|
if (isDirectStream)
|
||||||
|
{
|
||||||
|
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_BYTE_BASED_SEEK;
|
||||||
|
}
|
||||||
|
else if (runtimeTicks.HasValue)
|
||||||
|
{
|
||||||
|
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_TIME_BASED_SEEK;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000",
|
||||||
|
Enum.Format(typeof(DlnaFlags), flagValue, "x"));
|
||||||
|
|
||||||
|
var mediaProfile = _profile.GetVideoMediaProfile(container, audioCodec, videoCodec);
|
||||||
|
var orgPn = mediaProfile == null ? null : mediaProfile.OrgPn;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(orgPn))
|
||||||
|
{
|
||||||
|
orgPn = GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, bitrate, timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn;
|
||||||
|
|
||||||
|
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetAudioOrgPnValue(string container, int? audioBitrate, int? audioSampleRate, int? audioChannels)
|
||||||
|
{
|
||||||
|
var format = new MediaFormatProfileResolver()
|
||||||
|
.ResolveAudioFormat(container,
|
||||||
|
audioBitrate,
|
||||||
|
audioSampleRate,
|
||||||
|
audioChannels);
|
||||||
|
|
||||||
|
return format.HasValue ? format.Value.ToString() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestamp)
|
||||||
|
{
|
||||||
|
var videoFormat = new MediaFormatProfileResolver()
|
||||||
|
.ResolveVideoFormat(container,
|
||||||
|
videoCodec,
|
||||||
|
audioCodec,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
bitrate,
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
return videoFormat.HasValue ? videoFormat.Value.ToString() : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -159,7 +159,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, MediaStream audioStream)
|
public ResponseProfile GetAudioMediaProfile(string container, string audioCodec)
|
||||||
{
|
{
|
||||||
container = (container ?? string.Empty).TrimStart('.');
|
container = (container ?? string.Empty).TrimStart('.');
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseProfile GetVideoMediaProfile(string container, string audioCodec, string videoCodec, MediaStream audioStream, MediaStream videoStream)
|
public ResponseProfile GetVideoMediaProfile(string container, string audioCodec, string videoCodec)
|
||||||
{
|
{
|
||||||
container = (container ?? string.Empty).TrimStart('.');
|
container = (container ?? string.Empty).TrimStart('.');
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase))
|
string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
|
||||||
var list = ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, bitrate, timestampType)
|
var list = ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, timestampType)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return list.Count > 0 ? list[0] : (MediaFormatProfile?)null;
|
return list.Count > 0 ? list[0] : (MediaFormatProfile?)null;
|
||||||
|
@ -54,7 +54,7 @@ namespace MediaBrowser.Model.Dlna
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<MediaFormatProfile> ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestampType)
|
private IEnumerable<MediaFormatProfile> ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
|
||||||
{
|
{
|
||||||
var suffix = "";
|
var suffix = "";
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Drawing;
|
||||||
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -56,6 +57,8 @@ namespace MediaBrowser.Model.Dlna
|
||||||
|
|
||||||
public MediaSourceInfo MediaSource { get; set; }
|
public MediaSourceInfo MediaSource { get; set; }
|
||||||
|
|
||||||
|
public TransportStreamTimestamp TargetTimestamp { get; set; }
|
||||||
|
|
||||||
public string MediaSourceId
|
public string MediaSourceId
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -252,6 +255,68 @@ namespace MediaBrowser.Model.Dlna
|
||||||
: stream == null ? null : stream.Channels;
|
: stream == null ? null : stream.Channels;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int? TotalOutputBitrate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (TargetAudioBitrate ?? 0) + (VideoBitrate ?? 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? TargetWidth
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var videoStream = TargetVideoStream;
|
||||||
|
|
||||||
|
if (videoStream != null && videoStream.Width.HasValue && videoStream.Height.HasValue)
|
||||||
|
{
|
||||||
|
var size = new ImageSize
|
||||||
|
{
|
||||||
|
Width = videoStream.Width.Value,
|
||||||
|
Height = videoStream.Height.Value
|
||||||
|
};
|
||||||
|
|
||||||
|
var newSize = DrawingUtils.Resize(size,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
MaxWidth,
|
||||||
|
MaxHeight);
|
||||||
|
|
||||||
|
return Convert.ToInt32(newSize.Width);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MaxWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? TargetHeight
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var videoStream = TargetVideoStream;
|
||||||
|
|
||||||
|
if (videoStream != null && videoStream.Width.HasValue && videoStream.Height.HasValue)
|
||||||
|
{
|
||||||
|
var size = new ImageSize
|
||||||
|
{
|
||||||
|
Width = videoStream.Width.Value,
|
||||||
|
Height = videoStream.Height.Value
|
||||||
|
};
|
||||||
|
|
||||||
|
var newSize = DrawingUtils.Resize(size,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
MaxWidth,
|
||||||
|
MaxHeight);
|
||||||
|
|
||||||
|
return Convert.ToInt32(newSize.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return MaxHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
<Compile Include="Configuration\ServerConfiguration.cs" />
|
<Compile Include="Configuration\ServerConfiguration.cs" />
|
||||||
<Compile Include="Dlna\CodecProfile.cs" />
|
<Compile Include="Dlna\CodecProfile.cs" />
|
||||||
<Compile Include="Dlna\ContainerProfile.cs" />
|
<Compile Include="Dlna\ContainerProfile.cs" />
|
||||||
|
<Compile Include="Dlna\ContentFeatureBuilder.cs" />
|
||||||
<Compile Include="Dlna\DeviceIdentification.cs" />
|
<Compile Include="Dlna\DeviceIdentification.cs" />
|
||||||
<Compile Include="Dlna\DeviceProfile.cs" />
|
<Compile Include="Dlna\DeviceProfile.cs" />
|
||||||
<Compile Include="Dlna\DeviceProfileInfo.cs" />
|
<Compile Include="Dlna\DeviceProfileInfo.cs" />
|
||||||
|
|
Loading…
Reference in a new issue