mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
updated dlna profiles
This commit is contained in:
parent
0ab3a1bf8e
commit
a748c660cb
@ -1665,8 +1665,21 @@ namespace MediaBrowser.Api.Playback
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mediaProfile = state.VideoRequest == null ?
|
var mediaProfile = state.VideoRequest == null ?
|
||||||
profile.GetAudioMediaProfile(state.OutputContainer, audioCodec) :
|
profile.GetAudioMediaProfile(state.OutputContainer, audioCodec, state.OutputAudioChannels, state.OutputAudioBitrate) :
|
||||||
profile.GetVideoMediaProfile(state.OutputContainer, audioCodec, videoCodec);
|
profile.GetVideoMediaProfile(state.OutputContainer,
|
||||||
|
audioCodec,
|
||||||
|
videoCodec,
|
||||||
|
state.OutputAudioBitrate,
|
||||||
|
state.OutputAudioChannels,
|
||||||
|
state.OutputWidth,
|
||||||
|
state.OutputHeight,
|
||||||
|
state.TargetVideoBitDepth,
|
||||||
|
state.OutputVideoBitrate,
|
||||||
|
state.TargetVideoProfile,
|
||||||
|
state.TargetVideoLevel,
|
||||||
|
state.TargetFramerate,
|
||||||
|
state.TargetPacketLength,
|
||||||
|
state.TargetTimestamp);
|
||||||
|
|
||||||
if (mediaProfile != null)
|
if (mediaProfile != null)
|
||||||
{
|
{
|
||||||
@ -1752,10 +1765,17 @@ namespace MediaBrowser.Api.Playback
|
|||||||
audioCodec,
|
audioCodec,
|
||||||
state.OutputWidth,
|
state.OutputWidth,
|
||||||
state.OutputHeight,
|
state.OutputHeight,
|
||||||
state.TotalOutputBitrate,
|
state.TargetVideoBitDepth,
|
||||||
TransportStreamTimestamp.VALID,
|
state.OutputVideoBitrate,
|
||||||
|
state.OutputAudioBitrate,
|
||||||
|
state.OutputAudioChannels,
|
||||||
|
state.TargetTimestamp,
|
||||||
isStaticallyStreamed,
|
isStaticallyStreamed,
|
||||||
state.RunTimeTicks,
|
state.RunTimeTicks,
|
||||||
|
state.TargetVideoProfile,
|
||||||
|
state.TargetVideoLevel,
|
||||||
|
state.TargetFramerate,
|
||||||
|
state.TargetPacketLength,
|
||||||
state.TranscodeSeekInfo
|
state.TranscodeSeekInfo
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MediaBrowser.Common.Net;
|
using System.Globalization;
|
||||||
|
using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.LiveTv;
|
using MediaBrowser.Controller.LiveTv;
|
||||||
using MediaBrowser.Model.Dlna;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
@ -221,5 +222,88 @@ namespace MediaBrowser.Api.Playback
|
|||||||
return VideoRequest.MaxHeight ?? VideoRequest.Height;
|
return VideoRequest.MaxHeight ?? VideoRequest.Height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public int? TargetVideoBitDepth
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = VideoStream;
|
||||||
|
return stream == null || !Request.Static ? null : stream.BitDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public double? TargetFramerate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = VideoStream;
|
||||||
|
var requestedFramerate = VideoRequest.MaxFramerate ?? VideoRequest.Framerate;
|
||||||
|
|
||||||
|
return requestedFramerate.HasValue && !Request.Static
|
||||||
|
? requestedFramerate
|
||||||
|
: stream == null ? null : stream.AverageFrameRate ?? stream.RealFrameRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public double? TargetVideoLevel
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = VideoStream;
|
||||||
|
return !string.IsNullOrEmpty(VideoRequest.Level) && !Request.Static
|
||||||
|
? double.Parse(VideoRequest.Level, CultureInfo.InvariantCulture)
|
||||||
|
: stream == null ? null : stream.Level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportStreamTimestamp TargetTimestamp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = VideoStream;
|
||||||
|
|
||||||
|
return !Request.Static
|
||||||
|
? TransportStreamTimestamp.VALID
|
||||||
|
: stream == null ? TransportStreamTimestamp.VALID : stream.Timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public int? TargetPacketLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = VideoStream;
|
||||||
|
return !Request.Static
|
||||||
|
? null
|
||||||
|
: stream == null ? null : stream.PacketLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public string TargetVideoProfile
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = VideoStream;
|
||||||
|
return !string.IsNullOrEmpty(VideoRequest.Profile) && !Request.Static
|
||||||
|
? VideoRequest.Profile
|
||||||
|
: stream == null ? null : stream.Profile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,6 +195,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
|
|
||||||
stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate);
|
stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate);
|
||||||
stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate);
|
stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate);
|
||||||
|
|
||||||
|
stream.BitDepth = GetBitDepth(stream.PixelFormat);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -232,6 +234,34 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int? GetBitDepth(string pixelFormat)
|
||||||
|
{
|
||||||
|
var eightBit = new List<string>
|
||||||
|
{
|
||||||
|
"yuv420p",
|
||||||
|
"yuv411p",
|
||||||
|
"yuvj420p",
|
||||||
|
"uyyvyy411",
|
||||||
|
"nv12",
|
||||||
|
"nv21",
|
||||||
|
"rgb444le",
|
||||||
|
"rgb444be",
|
||||||
|
"bgr444le",
|
||||||
|
"bgr444be",
|
||||||
|
"yuvj411p"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(pixelFormat))
|
||||||
|
{
|
||||||
|
if (eightBit.Contains(pixelFormat, StringComparer.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a string from an FFProbeResult tags dictionary
|
/// Gets a string from an FFProbeResult tags dictionary
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,7 +9,6 @@ using MediaBrowser.Model.Dlna;
|
|||||||
using MediaBrowser.Model.Drawing;
|
using MediaBrowser.Model.Drawing;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
@ -47,6 +46,12 @@ namespace MediaBrowser.Dlna.Didl
|
|||||||
didl.SetAttribute("xmlns:dlna", NS_DLNA);
|
didl.SetAttribute("xmlns:dlna", NS_DLNA);
|
||||||
didl.SetAttribute("xmlns:upnp", NS_UPNP);
|
didl.SetAttribute("xmlns:upnp", NS_UPNP);
|
||||||
//didl.SetAttribute("xmlns:sec", NS_SEC);
|
//didl.SetAttribute("xmlns:sec", NS_SEC);
|
||||||
|
|
||||||
|
foreach (var att in _profile.ContentDirectoryRootAttributes)
|
||||||
|
{
|
||||||
|
didl.SetAttribute(att.Name, att.Value);
|
||||||
|
}
|
||||||
|
|
||||||
result.AppendChild(didl);
|
result.AppendChild(didl);
|
||||||
|
|
||||||
result.DocumentElement.AppendChild(GetItemElement(result, item, deviceId, filter));
|
result.DocumentElement.AppendChild(GetItemElement(result, item, deviceId, filter));
|
||||||
@ -130,7 +135,7 @@ namespace MediaBrowser.Dlna.Didl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalBitrate = streamInfo.TotalOutputBitrate;
|
var totalBitrate = streamInfo.TargetTotalBitrate;
|
||||||
var targetSampleRate = streamInfo.TargetAudioSampleRate;
|
var targetSampleRate = streamInfo.TargetAudioSampleRate;
|
||||||
var targetChannels = streamInfo.TargetAudioChannels;
|
var targetChannels = streamInfo.TargetAudioChannels;
|
||||||
|
|
||||||
@ -162,7 +167,18 @@ namespace MediaBrowser.Dlna.Didl
|
|||||||
|
|
||||||
var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
|
var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
|
||||||
streamInfo.AudioCodec,
|
streamInfo.AudioCodec,
|
||||||
streamInfo.VideoCodec);
|
streamInfo.VideoCodec,
|
||||||
|
streamInfo.TargetAudioBitrate,
|
||||||
|
targetChannels,
|
||||||
|
targetWidth,
|
||||||
|
targetHeight,
|
||||||
|
streamInfo.TargetVideoBitDepth,
|
||||||
|
streamInfo.TargetVideoBitrate,
|
||||||
|
streamInfo.TargetVideoProfile,
|
||||||
|
streamInfo.TargetVideoLevel,
|
||||||
|
streamInfo.TargetFramerate,
|
||||||
|
streamInfo.TargetPacketLength,
|
||||||
|
streamInfo.TargetTimestamp);
|
||||||
|
|
||||||
var filename = url.Substring(0, url.IndexOf('?'));
|
var filename = url.Substring(0, url.IndexOf('?'));
|
||||||
|
|
||||||
@ -175,10 +191,17 @@ namespace MediaBrowser.Dlna.Didl
|
|||||||
streamInfo.AudioCodec,
|
streamInfo.AudioCodec,
|
||||||
targetWidth,
|
targetWidth,
|
||||||
targetHeight,
|
targetHeight,
|
||||||
totalBitrate,
|
streamInfo.TargetVideoBitDepth,
|
||||||
|
streamInfo.TargetVideoBitrate,
|
||||||
|
streamInfo.TargetAudioChannels,
|
||||||
|
streamInfo.TargetAudioBitrate,
|
||||||
streamInfo.TargetTimestamp,
|
streamInfo.TargetTimestamp,
|
||||||
streamInfo.IsDirectStream,
|
streamInfo.IsDirectStream,
|
||||||
streamInfo.RunTimeTicks,
|
streamInfo.RunTimeTicks,
|
||||||
|
streamInfo.TargetVideoProfile,
|
||||||
|
streamInfo.TargetVideoLevel,
|
||||||
|
streamInfo.TargetFramerate,
|
||||||
|
streamInfo.TargetPacketLength,
|
||||||
streamInfo.TranscodeSeekInfo);
|
streamInfo.TranscodeSeekInfo);
|
||||||
|
|
||||||
res.SetAttribute("protocolInfo", String.Format(
|
res.SetAttribute("protocolInfo", String.Format(
|
||||||
@ -248,7 +271,9 @@ namespace MediaBrowser.Dlna.Didl
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
|
var mediaProfile = _profile.GetAudioMediaProfile(streamInfo.Container,
|
||||||
streamInfo.AudioCodec);
|
streamInfo.AudioCodec,
|
||||||
|
targetChannels,
|
||||||
|
targetAudioBitrate);
|
||||||
|
|
||||||
var filename = url.Substring(0, url.IndexOf('?'));
|
var filename = url.Substring(0, url.IndexOf('?'));
|
||||||
|
|
||||||
@ -541,15 +566,12 @@ namespace MediaBrowser.Dlna.Didl
|
|||||||
var width = albumartUrlInfo.Width;
|
var width = albumartUrlInfo.Width;
|
||||||
var height = albumartUrlInfo.Height;
|
var height = albumartUrlInfo.Height;
|
||||||
|
|
||||||
var mediaProfile = new MediaFormatProfileResolver().ResolveImageFormat("jpg", width, height);
|
var contentFeatures = new ContentFeatureBuilder(_profile).BuildImageHeader("jpg", width, height);
|
||||||
|
|
||||||
var orgPn = mediaProfile.HasValue ? "DLNA.ORG_PN=:" + mediaProfile.Value + ";" : string.Empty;
|
res.SetAttribute("protocolInfo", String.Format(
|
||||||
|
"http-get:*:{0}:{1}",
|
||||||
res.SetAttribute("protocolInfo", string.Format(
|
|
||||||
"http-get:*:{1}:{0}DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS={2}",
|
|
||||||
orgPn,
|
|
||||||
"image/jpeg",
|
"image/jpeg",
|
||||||
DlnaMaps.DefaultStreaming
|
contentFeatures
|
||||||
));
|
));
|
||||||
|
|
||||||
if (width.HasValue && height.HasValue)
|
if (width.HasValue && height.HasValue)
|
||||||
|
@ -428,10 +428,17 @@ namespace MediaBrowser.Dlna.PlayTo
|
|||||||
streamInfo.AudioCodec,
|
streamInfo.AudioCodec,
|
||||||
streamInfo.TargetWidth,
|
streamInfo.TargetWidth,
|
||||||
streamInfo.TargetHeight,
|
streamInfo.TargetHeight,
|
||||||
streamInfo.TotalOutputBitrate,
|
streamInfo.TargetVideoBitDepth,
|
||||||
|
streamInfo.TargetVideoBitrate,
|
||||||
|
streamInfo.TargetAudioChannels,
|
||||||
|
streamInfo.TargetAudioBitrate,
|
||||||
streamInfo.TargetTimestamp,
|
streamInfo.TargetTimestamp,
|
||||||
streamInfo.IsDirectStream,
|
streamInfo.IsDirectStream,
|
||||||
streamInfo.RunTimeTicks,
|
streamInfo.RunTimeTicks,
|
||||||
|
streamInfo.TargetVideoProfile,
|
||||||
|
streamInfo.TargetVideoLevel,
|
||||||
|
streamInfo.TargetFramerate,
|
||||||
|
streamInfo.TargetPacketLength,
|
||||||
streamInfo.TranscodeSeekInfo);
|
streamInfo.TranscodeSeekInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.Xml.Serialization;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using System.Xml.Serialization;
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.Profiles
|
namespace MediaBrowser.Dlna.Profiles
|
||||||
{
|
{
|
||||||
@ -27,6 +26,15 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ContentDirectoryRootAttributes = new[]
|
||||||
|
{
|
||||||
|
new XmlAttribute
|
||||||
|
{
|
||||||
|
Name = "xmlns:pv",
|
||||||
|
Value = "http://www.pv.com/pvns/"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
TimelineOffsetSeconds = 10;
|
TimelineOffsetSeconds = 10;
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
|
@ -17,6 +17,15 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
ModelUrl = "samsung.com"
|
ModelUrl = "samsung.com"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ContentDirectoryRootAttributes = new[]
|
||||||
|
{
|
||||||
|
new XmlAttribute
|
||||||
|
{
|
||||||
|
Name = "xmlns:sec",
|
||||||
|
Value = "http://www.sec.co.kr/"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
TranscodingProfiles = new[]
|
TranscodingProfiles = new[]
|
||||||
{
|
{
|
||||||
new TranscodingProfile
|
new TranscodingProfile
|
||||||
|
@ -18,6 +18,15 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
ModelNumber = "BDP-2013"
|
ModelNumber = "BDP-2013"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ContentDirectoryRootAttributes = new[]
|
||||||
|
{
|
||||||
|
new XmlAttribute
|
||||||
|
{
|
||||||
|
Name = "xmlns:av",
|
||||||
|
Value = "urn:schemas-sony-com:av"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ModelName = "Windows Media Player Sharing";
|
ModelName = "Windows Media Player Sharing";
|
||||||
ModelNumber = "3.0";
|
ModelNumber = "3.0";
|
||||||
Manufacturer = "Microsoft Corporation";
|
Manufacturer = "Microsoft Corporation";
|
||||||
|
@ -33,6 +33,15 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ContentDirectoryRootAttributes = new[]
|
||||||
|
{
|
||||||
|
new XmlAttribute
|
||||||
|
{
|
||||||
|
Name = "xmlns:av",
|
||||||
|
Value = "urn:schemas-sony-com:av"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ModelName = "Windows Media Player Sharing";
|
ModelName = "Windows Media Player Sharing";
|
||||||
ModelNumber = "3.0";
|
ModelNumber = "3.0";
|
||||||
Manufacturer = "Microsoft Corporation";
|
Manufacturer = "Microsoft Corporation";
|
||||||
|
@ -27,6 +27,15 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ContentDirectoryRootAttributes = new[]
|
||||||
|
{
|
||||||
|
new XmlAttribute
|
||||||
|
{
|
||||||
|
Name = "xmlns:av",
|
||||||
|
Value = "urn:schemas-sony-com:av"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ModelName = "Windows Media Player Sharing";
|
ModelName = "Windows Media Player Sharing";
|
||||||
ModelNumber = "3.0";
|
ModelNumber = "3.0";
|
||||||
ModelUrl = "http://www.microsoft.com/";
|
ModelUrl = "http://www.microsoft.com/";
|
||||||
@ -99,7 +108,23 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
AudioCodec="ac3,aac,mp3",
|
AudioCodec="ac3,aac,mp3",
|
||||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||||
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
|
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
|
||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video,
|
||||||
|
|
||||||
|
Conditions = new []
|
||||||
|
{
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.PacketLength,
|
||||||
|
Value = "192"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.VideoTimestamp,
|
||||||
|
Value = "Valid"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new ResponseProfile
|
new ResponseProfile
|
||||||
@ -109,7 +134,17 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
AudioCodec="ac3,aac,mp3",
|
AudioCodec="ac3,aac,mp3",
|
||||||
MimeType = "video/mpeg",
|
MimeType = "video/mpeg",
|
||||||
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
|
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
|
||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video,
|
||||||
|
|
||||||
|
Conditions = new []
|
||||||
|
{
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.PacketLength,
|
||||||
|
Value = "188"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new ResponseProfile
|
new ResponseProfile
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.Xml.Serialization;
|
using MediaBrowser.Model.Dlna;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using System.Xml.Serialization;
|
||||||
using MediaBrowser.Model.Dlna;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.Profiles
|
namespace MediaBrowser.Dlna.Profiles
|
||||||
{
|
{
|
||||||
@ -27,6 +26,15 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ContentDirectoryRootAttributes = new[]
|
||||||
|
{
|
||||||
|
new XmlAttribute
|
||||||
|
{
|
||||||
|
Name = "xmlns:av",
|
||||||
|
Value = "urn:schemas-sony-com:av"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ModelName = "Windows Media Player Sharing";
|
ModelName = "Windows Media Player Sharing";
|
||||||
ModelNumber = "3.0";
|
ModelNumber = "3.0";
|
||||||
ModelUrl = "http://www.microsoft.com/";
|
ModelUrl = "http://www.microsoft.com/";
|
||||||
@ -141,7 +149,23 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
AudioCodec="ac3,aac,mp3",
|
AudioCodec="ac3,aac,mp3",
|
||||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||||
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
|
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
|
||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video,
|
||||||
|
|
||||||
|
Conditions = new []
|
||||||
|
{
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.PacketLength,
|
||||||
|
Value = "192"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.VideoTimestamp,
|
||||||
|
Value = "Valid"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new ResponseProfile
|
new ResponseProfile
|
||||||
@ -151,7 +175,17 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
AudioCodec="ac3,aac,mp3",
|
AudioCodec="ac3,aac,mp3",
|
||||||
MimeType = "video/mpeg",
|
MimeType = "video/mpeg",
|
||||||
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
|
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
|
||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video,
|
||||||
|
|
||||||
|
Conditions = new []
|
||||||
|
{
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.PacketLength,
|
||||||
|
Value = "188"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new ResponseProfile
|
new ResponseProfile
|
||||||
|
@ -27,6 +27,15 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ContentDirectoryRootAttributes = new[]
|
||||||
|
{
|
||||||
|
new XmlAttribute
|
||||||
|
{
|
||||||
|
Name = "xmlns:av",
|
||||||
|
Value = "urn:schemas-sony-com:av"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ModelName = "Windows Media Player Sharing";
|
ModelName = "Windows Media Player Sharing";
|
||||||
ModelNumber = "3.0";
|
ModelNumber = "3.0";
|
||||||
ModelUrl = "http://www.microsoft.com/";
|
ModelUrl = "http://www.microsoft.com/";
|
||||||
@ -129,7 +138,23 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
AudioCodec="ac3,aac,mp3",
|
AudioCodec="ac3,aac,mp3",
|
||||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||||
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
|
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
|
||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video,
|
||||||
|
|
||||||
|
Conditions = new []
|
||||||
|
{
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.PacketLength,
|
||||||
|
Value = "192"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.VideoTimestamp,
|
||||||
|
Value = "Valid"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new ResponseProfile
|
new ResponseProfile
|
||||||
@ -139,7 +164,17 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
AudioCodec="ac3,aac,mp3",
|
AudioCodec="ac3,aac,mp3",
|
||||||
MimeType = "video/mpeg",
|
MimeType = "video/mpeg",
|
||||||
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
|
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
|
||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video,
|
||||||
|
|
||||||
|
Conditions = new []
|
||||||
|
{
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.PacketLength,
|
||||||
|
Value = "188"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new ResponseProfile
|
new ResponseProfile
|
||||||
|
@ -26,6 +26,15 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ContentDirectoryRootAttributes = new[]
|
||||||
|
{
|
||||||
|
new XmlAttribute
|
||||||
|
{
|
||||||
|
Name = "xmlns:av",
|
||||||
|
Value = "urn:schemas-sony-com:av"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ModelName = "Windows Media Player Sharing";
|
ModelName = "Windows Media Player Sharing";
|
||||||
ModelNumber = "3.0";
|
ModelNumber = "3.0";
|
||||||
ModelUrl = "http://www.microsoft.com/";
|
ModelUrl = "http://www.microsoft.com/";
|
||||||
@ -184,7 +193,23 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
AudioCodec="ac3,aac,mp3",
|
AudioCodec="ac3,aac,mp3",
|
||||||
MimeType = "video/vnd.dlna.mpeg-tts",
|
MimeType = "video/vnd.dlna.mpeg-tts",
|
||||||
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
|
OrgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T",
|
||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video,
|
||||||
|
|
||||||
|
Conditions = new []
|
||||||
|
{
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.PacketLength,
|
||||||
|
Value = "192"
|
||||||
|
},
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.VideoTimestamp,
|
||||||
|
Value = "Valid"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new ResponseProfile
|
new ResponseProfile
|
||||||
@ -194,7 +219,17 @@ namespace MediaBrowser.Dlna.Profiles
|
|||||||
AudioCodec="ac3,aac,mp3",
|
AudioCodec="ac3,aac,mp3",
|
||||||
MimeType = "video/mpeg",
|
MimeType = "video/mpeg",
|
||||||
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
|
OrgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO",
|
||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video,
|
||||||
|
|
||||||
|
Conditions = new []
|
||||||
|
{
|
||||||
|
new ProfileCondition
|
||||||
|
{
|
||||||
|
Condition = ProfileConditionType.Equals,
|
||||||
|
Property = ProfileConditionValue.PacketLength,
|
||||||
|
Value = "188"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
new ResponseProfile
|
new ResponseProfile
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes />
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3,wma" type="Audio" />
|
<DirectPlayProfile container="mp3,wma" type="Audio" />
|
||||||
<DirectPlayProfile container="avi,mp4" type="Video" />
|
<DirectPlayProfile container="avi,mp4" type="Video" />
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes />
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
||||||
</DirectPlayProfiles>
|
</DirectPlayProfiles>
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
<TimelineOffsetSeconds>10</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>10</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes />
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
||||||
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes />
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
<DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
|
||||||
<DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />
|
<DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
<TimelineOffsetSeconds>10</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>10</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes>
|
||||||
|
<XmlAttribute name="xmlns:pv" value="http://www.pv.com/pvns/" />
|
||||||
|
</ContentDirectoryRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mpeg" audioCodec="ac3,mp3" videoCodec="mpeg2video,mpeg4" type="Video" />
|
<DirectPlayProfile container="mpeg" audioCodec="ac3,mp3" videoCodec="mpeg2video,mpeg4" type="Video" />
|
||||||
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3,pcm" videoCodec="h264" type="Video" />
|
||||||
|
@ -26,6 +26,9 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes>
|
||||||
|
<XmlAttribute name="xmlns:sec" value="http://www.sec.co.kr/" />
|
||||||
|
</ContentDirectoryRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="asf" audioCodec="mp3,ac3,wmav2,wmapro,wmavoice" videoCodec="h264,mpeg4,mjpeg" type="Video" />
|
<DirectPlayProfile container="asf" audioCodec="mp3,ac3,wmav2,wmapro,wmavoice" videoCodec="h264,mpeg4,mjpeg" type="Video" />
|
||||||
<DirectPlayProfile container="avi" audioCodec="mp3,ac3,dca" videoCodec="h264,mpeg4,mjpeg" type="Video" />
|
<DirectPlayProfile container="avi" audioCodec="mp3,ac3,dca" videoCodec="h264,mpeg4,mjpeg" type="Video" />
|
||||||
|
@ -28,6 +28,9 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes>
|
||||||
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
|
</ContentDirectoryRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||||
<DirectPlayProfile container="mpeg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
<DirectPlayProfile container="mpeg" audioCodec="ac3,mp3,mp2,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes>
|
||||||
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
|
</ContentDirectoryRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3,pcm" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />
|
||||||
<DirectPlayProfile container="mpeg" audioCodec="ac3,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
<DirectPlayProfile container="mpeg" audioCodec="ac3,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes>
|
||||||
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
|
</ContentDirectoryRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||||
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||||
@ -83,10 +86,15 @@
|
|||||||
</CodecProfiles>
|
</CodecProfiles>
|
||||||
<ResponseProfiles>
|
<ResponseProfiles>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||||
<Conditions />
|
<Conditions>
|
||||||
|
<ProfileCondition condition="Equals" property="PacketLength" value="192" isRequired="true" />
|
||||||
|
<ProfileCondition condition="Equals" property="VideoTimestamp" value="Valid" isRequired="true" />
|
||||||
|
</Conditions>
|
||||||
</ResponseProfile>
|
</ResponseProfile>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||||
<Conditions />
|
<Conditions>
|
||||||
|
<ProfileCondition condition="Equals" property="PacketLength" value="188" isRequired="true" />
|
||||||
|
</Conditions>
|
||||||
</ResponseProfile>
|
</ResponseProfile>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||||
<Conditions />
|
<Conditions />
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes>
|
||||||
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
|
</ContentDirectoryRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||||
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
||||||
@ -86,10 +89,15 @@
|
|||||||
</CodecProfiles>
|
</CodecProfiles>
|
||||||
<ResponseProfiles>
|
<ResponseProfiles>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||||
<Conditions />
|
<Conditions>
|
||||||
|
<ProfileCondition condition="Equals" property="PacketLength" value="192" isRequired="true" />
|
||||||
|
<ProfileCondition condition="Equals" property="VideoTimestamp" value="Valid" isRequired="true" />
|
||||||
|
</Conditions>
|
||||||
</ResponseProfile>
|
</ResponseProfile>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||||
<Conditions />
|
<Conditions>
|
||||||
|
<ProfileCondition condition="Equals" property="PacketLength" value="188" isRequired="true" />
|
||||||
|
</Conditions>
|
||||||
</ResponseProfile>
|
</ResponseProfile>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||||
<Conditions />
|
<Conditions />
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes>
|
||||||
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
|
</ContentDirectoryRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||||
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
||||||
@ -69,10 +72,15 @@
|
|||||||
</CodecProfiles>
|
</CodecProfiles>
|
||||||
<ResponseProfiles>
|
<ResponseProfiles>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||||
<Conditions />
|
<Conditions>
|
||||||
|
<ProfileCondition condition="Equals" property="PacketLength" value="192" isRequired="true" />
|
||||||
|
<ProfileCondition condition="Equals" property="VideoTimestamp" value="Valid" isRequired="true" />
|
||||||
|
</Conditions>
|
||||||
</ResponseProfile>
|
</ResponseProfile>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||||
<Conditions />
|
<Conditions>
|
||||||
|
<ProfileCondition condition="Equals" property="PacketLength" value="188" isRequired="true" />
|
||||||
|
</Conditions>
|
||||||
</ResponseProfile>
|
</ResponseProfile>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||||
<Conditions />
|
<Conditions />
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes>
|
||||||
|
<XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
|
||||||
|
</ContentDirectoryRootAttributes>
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="ac3,eac3,aac,mp3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="ac3,eac3,aac,mp3" videoCodec="h264" type="Video" />
|
||||||
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="mp3,mp2" videoCodec="mpeg2video" type="Video" />
|
||||||
@ -69,10 +72,15 @@
|
|||||||
</CodecProfiles>
|
</CodecProfiles>
|
||||||
<ResponseProfiles>
|
<ResponseProfiles>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_T,AVC_TS_HD_50_AC3_T,AVC_TS_HD_60_AC3_T,AVC_TS_HD_EU_T" mimeType="video/vnd.dlna.mpeg-tts">
|
||||||
<Conditions />
|
<Conditions>
|
||||||
|
<ProfileCondition condition="Equals" property="PacketLength" value="192" isRequired="true" />
|
||||||
|
<ProfileCondition condition="Equals" property="VideoTimestamp" value="Valid" isRequired="true" />
|
||||||
|
</Conditions>
|
||||||
</ResponseProfile>
|
</ResponseProfile>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3_ISO,AVC_TS_HD_50_AC3_ISO,AVC_TS_HD_60_AC3_ISO,AVC_TS_HD_EU_ISO" mimeType="video/mpeg">
|
||||||
<Conditions />
|
<Conditions>
|
||||||
|
<ProfileCondition condition="Equals" property="PacketLength" value="188" isRequired="true" />
|
||||||
|
</Conditions>
|
||||||
</ResponseProfile>
|
</ResponseProfile>
|
||||||
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
<ResponseProfile container="ts" audioCodec="ac3,aac,mp3" videoCodec="h264" type="Video" orgPn="AVC_TS_HD_24_AC3,AVC_TS_HD_50_AC3,AVC_TS_HD_60_AC3,AVC_TS_HD_EU" mimeType="video/vnd.dlna.mpeg-tts">
|
||||||
<Conditions />
|
<Conditions />
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes />
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3,wma" type="Audio" />
|
<DirectPlayProfile container="mp3,wma" type="Audio" />
|
||||||
<DirectPlayProfile container="avi,mp4" type="Video" />
|
<DirectPlayProfile container="avi,mp4" type="Video" />
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
<TimelineOffsetSeconds>5</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>5</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes />
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
<DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
|
||||||
<DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
<DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
<TimelineOffsetSeconds>40</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>40</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>true</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>true</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>true</RequiresPlainFolders>
|
<RequiresPlainFolders>true</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes />
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
||||||
<DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes />
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="ts" audioCodec="ac3" videoCodec="h264" type="Video" />
|
<DirectPlayProfile container="ts" audioCodec="ac3" videoCodec="h264" type="Video" />
|
||||||
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
<DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
<TimelineOffsetSeconds>0</TimelineOffsetSeconds>
|
||||||
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
<RequiresPlainVideoItems>false</RequiresPlainVideoItems>
|
||||||
<RequiresPlainFolders>false</RequiresPlainFolders>
|
<RequiresPlainFolders>false</RequiresPlainFolders>
|
||||||
|
<ContentDirectoryRootAttributes />
|
||||||
<DirectPlayProfiles>
|
<DirectPlayProfiles>
|
||||||
<DirectPlayProfile container="mp3,wma" type="Audio" />
|
<DirectPlayProfile container="mp3,wma" type="Audio" />
|
||||||
<DirectPlayProfile container="avi,mp4" type="Video" />
|
<DirectPlayProfile container="avi,mp4" type="Video" />
|
||||||
|
@ -40,6 +40,8 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
|
|
||||||
private readonly DidlBuilder _didlBuilder;
|
private readonly DidlBuilder _didlBuilder;
|
||||||
|
|
||||||
|
private readonly DeviceProfile _profile;
|
||||||
|
|
||||||
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, IDtoService dtoService, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId)
|
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, IDtoService dtoService, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@ -47,6 +49,7 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
_user = user;
|
_user = user;
|
||||||
_systemUpdateId = systemUpdateId;
|
_systemUpdateId = systemUpdateId;
|
||||||
|
_profile = profile;
|
||||||
|
|
||||||
_didlBuilder = new DidlBuilder(profile, imageProcessor, serverAddress, dtoService);
|
_didlBuilder = new DidlBuilder(profile, imageProcessor, serverAddress, dtoService);
|
||||||
}
|
}
|
||||||
@ -314,7 +317,6 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
|
|
||||||
// sort example: dc:title, dc:date
|
// sort example: dc:title, dc:date
|
||||||
|
|
||||||
var provided = 0;
|
|
||||||
var requested = 0;
|
var requested = 0;
|
||||||
var start = 0;
|
var start = 0;
|
||||||
|
|
||||||
@ -334,7 +336,12 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
didl.SetAttribute("xmlns:dc", NS_DC);
|
didl.SetAttribute("xmlns:dc", NS_DC);
|
||||||
didl.SetAttribute("xmlns:dlna", NS_DLNA);
|
didl.SetAttribute("xmlns:dlna", NS_DLNA);
|
||||||
didl.SetAttribute("xmlns:upnp", NS_UPNP);
|
didl.SetAttribute("xmlns:upnp", NS_UPNP);
|
||||||
//didl.SetAttribute("xmlns:sec", NS_SEC);
|
|
||||||
|
foreach (var att in _profile.ContentDirectoryRootAttributes)
|
||||||
|
{
|
||||||
|
didl.SetAttribute(att.Name, att.Value);
|
||||||
|
}
|
||||||
|
|
||||||
result.AppendChild(didl);
|
result.AppendChild(didl);
|
||||||
|
|
||||||
var folder = (Folder)GetItemFromObjectId(sparams["ContainerID"], user);
|
var folder = (Folder)GetItemFromObjectId(sparams["ContainerID"], user);
|
||||||
@ -352,7 +359,7 @@ namespace MediaBrowser.Dlna.Server
|
|||||||
children = children.Take(requested).ToList();
|
children = children.Take(requested).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
provided = children.Count;
|
var provided = children.Count;
|
||||||
|
|
||||||
foreach (var i in children)
|
foreach (var i in children)
|
||||||
{
|
{
|
||||||
|
@ -104,6 +104,9 @@
|
|||||||
<Compile Include="..\MediaBrowser.Model\Dlna\CodecProfile.cs">
|
<Compile Include="..\MediaBrowser.Model\Dlna\CodecProfile.cs">
|
||||||
<Link>Dlna\CodecProfile.cs</Link>
|
<Link>Dlna\CodecProfile.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\Dlna\ConditionProcessor.cs">
|
||||||
|
<Link>Dlna\ConditionProcessor.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\MediaBrowser.Model\Dlna\ContainerProfile.cs">
|
<Compile Include="..\MediaBrowser.Model\Dlna\ContainerProfile.cs">
|
||||||
<Link>Dlna\ContainerProfile.cs</Link>
|
<Link>Dlna\ContainerProfile.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -91,6 +91,9 @@
|
|||||||
<Compile Include="..\MediaBrowser.Model\Dlna\CodecProfile.cs">
|
<Compile Include="..\MediaBrowser.Model\Dlna\CodecProfile.cs">
|
||||||
<Link>Dlna\CodecProfile.cs</Link>
|
<Link>Dlna\CodecProfile.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\MediaBrowser.Model\Dlna\ConditionProcessor.cs">
|
||||||
|
<Link>Dlna\ConditionProcessor.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\MediaBrowser.Model\Dlna\ContainerProfile.cs">
|
<Compile Include="..\MediaBrowser.Model\Dlna\ContainerProfile.cs">
|
||||||
<Link>Dlna\ContainerProfile.cs</Link>
|
<Link>Dlna\ContainerProfile.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -76,10 +76,12 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
Width,
|
Width,
|
||||||
Height,
|
Height,
|
||||||
Has64BitOffsets,
|
Has64BitOffsets,
|
||||||
|
PacketLength,
|
||||||
VideoBitDepth,
|
VideoBitDepth,
|
||||||
VideoBitrate,
|
VideoBitrate,
|
||||||
VideoFramerate,
|
VideoFramerate,
|
||||||
VideoLevel,
|
VideoLevel,
|
||||||
VideoProfile
|
VideoProfile,
|
||||||
|
VideoTimestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
192
MediaBrowser.Model/Dlna/ConditionProcessor.cs
Normal file
192
MediaBrowser.Model/Dlna/ConditionProcessor.cs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Model.Dlna
|
||||||
|
{
|
||||||
|
public class ConditionProcessor
|
||||||
|
{
|
||||||
|
public bool IsVideoConditionSatisfied(ProfileCondition condition,
|
||||||
|
int? audioBitrate,
|
||||||
|
int? audioChannels,
|
||||||
|
int? width,
|
||||||
|
int? height,
|
||||||
|
int? bitDepth,
|
||||||
|
int? videoBitrate,
|
||||||
|
string videoProfile,
|
||||||
|
double? videoLevel,
|
||||||
|
double? videoFramerate,
|
||||||
|
int? packetLength,
|
||||||
|
TransportStreamTimestamp timestamp)
|
||||||
|
{
|
||||||
|
switch (condition.Property)
|
||||||
|
{
|
||||||
|
case ProfileConditionValue.AudioProfile:
|
||||||
|
// TODO: Implement
|
||||||
|
return true;
|
||||||
|
case ProfileConditionValue.Has64BitOffsets:
|
||||||
|
// TODO: Implement
|
||||||
|
return true;
|
||||||
|
case ProfileConditionValue.VideoFramerate:
|
||||||
|
return IsConditionSatisfied(condition, videoFramerate);
|
||||||
|
case ProfileConditionValue.VideoLevel:
|
||||||
|
return IsConditionSatisfied(condition, videoLevel);
|
||||||
|
case ProfileConditionValue.VideoProfile:
|
||||||
|
return IsConditionSatisfied(condition, videoProfile);
|
||||||
|
case ProfileConditionValue.PacketLength:
|
||||||
|
return IsConditionSatisfied(condition, packetLength);
|
||||||
|
case ProfileConditionValue.AudioBitrate:
|
||||||
|
return IsConditionSatisfied(condition, audioBitrate);
|
||||||
|
case ProfileConditionValue.AudioChannels:
|
||||||
|
return IsConditionSatisfied(condition, audioChannels);
|
||||||
|
case ProfileConditionValue.VideoBitDepth:
|
||||||
|
return IsConditionSatisfied(condition, bitDepth);
|
||||||
|
case ProfileConditionValue.VideoBitrate:
|
||||||
|
return IsConditionSatisfied(condition, videoBitrate);
|
||||||
|
case ProfileConditionValue.Height:
|
||||||
|
return IsConditionSatisfied(condition, height);
|
||||||
|
case ProfileConditionValue.Width:
|
||||||
|
return IsConditionSatisfied(condition, width);
|
||||||
|
case ProfileConditionValue.VideoTimestamp:
|
||||||
|
return IsConditionSatisfied(condition, timestamp);
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Unexpected condition on video file: " + condition.Property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height)
|
||||||
|
{
|
||||||
|
switch (condition.Property)
|
||||||
|
{
|
||||||
|
case ProfileConditionValue.Height:
|
||||||
|
return IsConditionSatisfied(condition, height);
|
||||||
|
case ProfileConditionValue.Width:
|
||||||
|
return IsConditionSatisfied(condition, width);
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Unexpected condition on image file: " + condition.Property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate)
|
||||||
|
{
|
||||||
|
switch (condition.Property)
|
||||||
|
{
|
||||||
|
case ProfileConditionValue.AudioBitrate:
|
||||||
|
return IsConditionSatisfied(condition, audioBitrate);
|
||||||
|
case ProfileConditionValue.AudioChannels:
|
||||||
|
return IsConditionSatisfied(condition, audioChannels);
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Unexpected condition on audio file: " + condition.Property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsVideoAudioConditionSatisfied(ProfileCondition condition,
|
||||||
|
int? audioChannels,
|
||||||
|
int? audioBitrate)
|
||||||
|
{
|
||||||
|
switch (condition.Property)
|
||||||
|
{
|
||||||
|
case ProfileConditionValue.AudioBitrate:
|
||||||
|
return IsConditionSatisfied(condition, audioBitrate);
|
||||||
|
case ProfileConditionValue.AudioChannels:
|
||||||
|
return IsConditionSatisfied(condition, audioChannels);
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Unexpected condition on audio file: " + condition.Property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
||||||
|
private bool IsConditionSatisfied(ProfileCondition condition, int? currentValue)
|
||||||
|
{
|
||||||
|
if (!currentValue.HasValue)
|
||||||
|
{
|
||||||
|
// If the value is unknown, it satisfies if not marked as required
|
||||||
|
return !condition.IsRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
int expected;
|
||||||
|
if (int.TryParse(condition.Value, NumberStyles.Any, UsCulture, out expected))
|
||||||
|
{
|
||||||
|
switch (condition.Condition)
|
||||||
|
{
|
||||||
|
case ProfileConditionType.Equals:
|
||||||
|
return currentValue.Value.Equals(expected);
|
||||||
|
case ProfileConditionType.GreaterThanEqual:
|
||||||
|
return currentValue.Value >= expected;
|
||||||
|
case ProfileConditionType.LessThanEqual:
|
||||||
|
return currentValue.Value <= expected;
|
||||||
|
case ProfileConditionType.NotEquals:
|
||||||
|
return !currentValue.Value.Equals(expected);
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsConditionSatisfied(ProfileCondition condition, string currentValue)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(currentValue))
|
||||||
|
{
|
||||||
|
// If the value is unknown, it satisfies if not marked as required
|
||||||
|
return !condition.IsRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
var expected = condition.Value;
|
||||||
|
|
||||||
|
switch (condition.Condition)
|
||||||
|
{
|
||||||
|
case ProfileConditionType.Equals:
|
||||||
|
return string.Equals(currentValue, expected, StringComparison.OrdinalIgnoreCase);
|
||||||
|
case ProfileConditionType.NotEquals:
|
||||||
|
return !string.Equals(currentValue, expected, StringComparison.OrdinalIgnoreCase);
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsConditionSatisfied(ProfileCondition condition, double? currentValue)
|
||||||
|
{
|
||||||
|
if (!currentValue.HasValue)
|
||||||
|
{
|
||||||
|
// If the value is unknown, it satisfies if not marked as required
|
||||||
|
return !condition.IsRequired;
|
||||||
|
}
|
||||||
|
|
||||||
|
double expected;
|
||||||
|
if (double.TryParse(condition.Value, NumberStyles.Any, UsCulture, out expected))
|
||||||
|
{
|
||||||
|
switch (condition.Condition)
|
||||||
|
{
|
||||||
|
case ProfileConditionType.Equals:
|
||||||
|
return currentValue.Value.Equals(expected);
|
||||||
|
case ProfileConditionType.GreaterThanEqual:
|
||||||
|
return currentValue.Value >= expected;
|
||||||
|
case ProfileConditionType.LessThanEqual:
|
||||||
|
return currentValue.Value <= expected;
|
||||||
|
case ProfileConditionType.NotEquals:
|
||||||
|
return !currentValue.Value.Equals(expected);
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsConditionSatisfied(ProfileCondition condition, TransportStreamTimestamp timestamp)
|
||||||
|
{
|
||||||
|
var expected = (TransportStreamTimestamp)Enum.Parse(typeof(TransportStreamTimestamp), condition.Value, true);
|
||||||
|
|
||||||
|
switch (condition.Condition)
|
||||||
|
{
|
||||||
|
case ProfileConditionType.Equals:
|
||||||
|
return timestamp == expected;
|
||||||
|
case ProfileConditionType.NotEquals:
|
||||||
|
return timestamp != expected;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
@ -11,13 +13,45 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
_profile = profile;
|
_profile = profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string BuildAudioHeader(string container,
|
public string BuildImageHeader(string container,
|
||||||
|
int? width,
|
||||||
|
int? height)
|
||||||
|
{
|
||||||
|
var orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetImageOrgOpValue();
|
||||||
|
|
||||||
|
// 0 = native, 1 = transcoded
|
||||||
|
const string orgCi = ";DLNA.ORG_CI=0";
|
||||||
|
|
||||||
|
var flagValue = DlnaFlags.StreamingTransferMode |
|
||||||
|
DlnaFlags.BackgroundTransferMode |
|
||||||
|
DlnaFlags.DlnaV15;
|
||||||
|
|
||||||
|
var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}",
|
||||||
|
FlagsToString(flagValue));
|
||||||
|
|
||||||
|
var mediaProfile = _profile.GetImageMediaProfile(container,
|
||||||
|
width,
|
||||||
|
height);
|
||||||
|
|
||||||
|
var orgPn = mediaProfile == null ? null : mediaProfile.OrgPn;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(orgPn))
|
||||||
|
{
|
||||||
|
orgPn = GetImageOrgPnValue(container, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn;
|
||||||
|
|
||||||
|
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BuildAudioHeader(string container,
|
||||||
string audioCodec,
|
string audioCodec,
|
||||||
int? audioBitrate,
|
int? audioBitrate,
|
||||||
int? audioSampleRate,
|
int? audioSampleRate,
|
||||||
int? audioChannels,
|
int? audioChannels,
|
||||||
bool isDirectStream,
|
bool isDirectStream,
|
||||||
long? runtimeTicks,
|
long? runtimeTicks,
|
||||||
TranscodeSeekInfo transcodeSeekInfo)
|
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
|
// 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
|
||||||
@ -42,7 +76,10 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}",
|
var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}",
|
||||||
FlagsToString(flagValue));
|
FlagsToString(flagValue));
|
||||||
|
|
||||||
var mediaProfile = _profile.GetAudioMediaProfile(container, audioCodec);
|
var mediaProfile = _profile.GetAudioMediaProfile(container,
|
||||||
|
audioCodec,
|
||||||
|
audioChannels,
|
||||||
|
audioBitrate);
|
||||||
|
|
||||||
var orgPn = mediaProfile == null ? null : mediaProfile.OrgPn;
|
var orgPn = mediaProfile == null ? null : mediaProfile.OrgPn;
|
||||||
|
|
||||||
@ -62,15 +99,22 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return string.Format("{0:X8}{1:D24}", (ulong)flags, 0);
|
return string.Format("{0:X8}{1:D24}", (ulong)flags, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string BuildVideoHeader(string container,
|
public string BuildVideoHeader(string container,
|
||||||
string videoCodec,
|
string videoCodec,
|
||||||
string audioCodec,
|
string audioCodec,
|
||||||
int? width,
|
int? width,
|
||||||
int? height,
|
int? height,
|
||||||
int? bitrate,
|
int? bitDepth,
|
||||||
TransportStreamTimestamp timestamp,
|
int? videoBitrate,
|
||||||
bool isDirectStream,
|
int? audioChannels,
|
||||||
long? runtimeTicks,
|
int? audioBitrate,
|
||||||
|
TransportStreamTimestamp timestamp,
|
||||||
|
bool isDirectStream,
|
||||||
|
long? runtimeTicks,
|
||||||
|
string videoProfile,
|
||||||
|
double? videoLevel,
|
||||||
|
double? videoFramerate,
|
||||||
|
int? packetLength,
|
||||||
TranscodeSeekInfo transcodeSeekInfo)
|
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
|
// 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
|
||||||
@ -95,12 +139,30 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000",
|
var dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}000000000000000000000000",
|
||||||
Enum.Format(typeof(DlnaFlags), flagValue, "x"));
|
Enum.Format(typeof(DlnaFlags), flagValue, "x"));
|
||||||
|
|
||||||
var mediaProfile = _profile.GetVideoMediaProfile(container, audioCodec, videoCodec);
|
var mediaProfile = _profile.GetVideoMediaProfile(container,
|
||||||
|
audioCodec,
|
||||||
|
videoCodec,
|
||||||
|
audioBitrate,
|
||||||
|
audioChannels,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
bitDepth,
|
||||||
|
videoBitrate,
|
||||||
|
videoProfile,
|
||||||
|
videoLevel,
|
||||||
|
videoFramerate,
|
||||||
|
packetLength,
|
||||||
|
timestamp);
|
||||||
|
|
||||||
var orgPn = mediaProfile == null ? null : mediaProfile.OrgPn;
|
var orgPn = mediaProfile == null ? null : mediaProfile.OrgPn;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(orgPn))
|
if (string.IsNullOrEmpty(orgPn))
|
||||||
{
|
{
|
||||||
orgPn = GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, bitrate, timestamp);
|
orgPn = GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
// TODO: Support multiple values and return multiple headers?
|
||||||
|
orgPn = (orgPn ?? string.Empty).Split(',').FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn;
|
var contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn;
|
||||||
@ -108,6 +170,16 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetImageOrgPnValue(string container, int? width, int? height)
|
||||||
|
{
|
||||||
|
var format = new MediaFormatProfileResolver()
|
||||||
|
.ResolveImageFormat(container,
|
||||||
|
width,
|
||||||
|
height);
|
||||||
|
|
||||||
|
return format.HasValue ? format.Value.ToString() : null;
|
||||||
|
}
|
||||||
|
|
||||||
private string GetAudioOrgPnValue(string container, int? audioBitrate, int? audioSampleRate, int? audioChannels)
|
private string GetAudioOrgPnValue(string container, int? audioBitrate, int? audioSampleRate, int? audioChannels)
|
||||||
{
|
{
|
||||||
var format = new MediaFormatProfileResolver()
|
var format = new MediaFormatProfileResolver()
|
||||||
@ -119,18 +191,16 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return format.HasValue ? format.Value.ToString() : null;
|
return format.HasValue ? format.Value.ToString() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestamp)
|
private IEnumerable<string> GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp)
|
||||||
{
|
{
|
||||||
var videoFormat = new MediaFormatProfileResolver()
|
return new MediaFormatProfileResolver()
|
||||||
.ResolveVideoFormat(container,
|
.ResolveVideoFormat(container,
|
||||||
videoCodec,
|
videoCodec,
|
||||||
audioCodec,
|
audioCodec,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
bitrate,
|
timestamp)
|
||||||
timestamp);
|
.Select(i => i.ToString());
|
||||||
|
|
||||||
return videoFormat.HasValue ? videoFormat.Value.ToString() : null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using MediaBrowser.Model.Entities;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
@ -71,6 +70,8 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
public bool RequiresPlainVideoItems { get; set; }
|
public bool RequiresPlainVideoItems { get; set; }
|
||||||
public bool RequiresPlainFolders { get; set; }
|
public bool RequiresPlainFolders { get; set; }
|
||||||
|
|
||||||
|
public XmlAttribute[] ContentDirectoryRootAttributes { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the direct play profiles.
|
/// Gets or sets the direct play profiles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -96,6 +97,8 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
CodecProfiles = new CodecProfile[] { };
|
CodecProfiles = new CodecProfile[] { };
|
||||||
ContainerProfiles = new ContainerProfile[] { };
|
ContainerProfiles = new ContainerProfile[] { };
|
||||||
|
|
||||||
|
ContentDirectoryRootAttributes = new XmlAttribute[] { };
|
||||||
|
|
||||||
SupportedMediaTypes = "Audio,Photo,Video";
|
SupportedMediaTypes = "Audio,Photo,Video";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +162,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseProfile GetAudioMediaProfile(string container, string audioCodec)
|
public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, int? audioChannels, int? audioBitrate)
|
||||||
{
|
{
|
||||||
container = (container ?? string.Empty).TrimStart('.');
|
container = (container ?? string.Empty).TrimStart('.');
|
||||||
|
|
||||||
@ -182,11 +185,51 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
var conditionProcessor = new ConditionProcessor();
|
||||||
|
return i.Conditions.All(c => conditionProcessor.IsAudioConditionSatisfied(c,
|
||||||
|
audioChannels,
|
||||||
|
audioBitrate));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseProfile GetVideoMediaProfile(string container, string audioCodec, string videoCodec)
|
public ResponseProfile GetImageMediaProfile(string container, int? width, int? height)
|
||||||
|
{
|
||||||
|
container = (container ?? string.Empty).TrimStart('.');
|
||||||
|
|
||||||
|
return ResponseProfiles.FirstOrDefault(i =>
|
||||||
|
{
|
||||||
|
if (i.Type != DlnaProfileType.Photo)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var containers = i.GetContainers().ToList();
|
||||||
|
if (containers.Count > 0 && !containers.Contains(container))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var conditionProcessor = new ConditionProcessor();
|
||||||
|
return i.Conditions.All(c => conditionProcessor.IsImageConditionSatisfied(c,
|
||||||
|
width,
|
||||||
|
height));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseProfile GetVideoMediaProfile(string container,
|
||||||
|
string audioCodec,
|
||||||
|
string videoCodec,
|
||||||
|
int? audioBitrate,
|
||||||
|
int? audioChannels,
|
||||||
|
int? width,
|
||||||
|
int? height,
|
||||||
|
int? bitDepth,
|
||||||
|
int? videoBitrate,
|
||||||
|
string videoProfile,
|
||||||
|
double? videoLevel,
|
||||||
|
double? videoFramerate,
|
||||||
|
int? packetLength,
|
||||||
|
TransportStreamTimestamp timestamp)
|
||||||
{
|
{
|
||||||
container = (container ?? string.Empty).TrimStart('.');
|
container = (container ?? string.Empty).TrimStart('.');
|
||||||
|
|
||||||
@ -215,11 +258,23 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
var conditionProcessor = new ConditionProcessor();
|
||||||
|
return i.Conditions.All(c => conditionProcessor.IsVideoConditionSatisfied(c,
|
||||||
|
audioBitrate,
|
||||||
|
audioChannels,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
bitDepth,
|
||||||
|
videoBitrate,
|
||||||
|
videoProfile,
|
||||||
|
videoLevel,
|
||||||
|
videoFramerate,
|
||||||
|
packetLength,
|
||||||
|
timestamp));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseProfile GetPhotoMediaProfile(string container)
|
public ResponseProfile GetPhotoMediaProfile(string container, int? width, int? height)
|
||||||
{
|
{
|
||||||
container = (container ?? string.Empty).TrimStart('.');
|
container = (container ?? string.Empty).TrimStart('.');
|
||||||
|
|
||||||
@ -236,7 +291,10 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
var conditionProcessor = new ConditionProcessor();
|
||||||
|
return i.Conditions.All(c => conditionProcessor.IsImageConditionSatisfied(c,
|
||||||
|
width,
|
||||||
|
height));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,15 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class XmlAttribute
|
||||||
|
{
|
||||||
|
[XmlAttribute("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("value")]
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public enum DlnaProfileType
|
public enum DlnaProfileType
|
||||||
{
|
{
|
||||||
Audio = 0,
|
Audio = 0,
|
||||||
|
@ -41,6 +41,19 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
// No seeking is available if we don't know the content runtime
|
// No seeking is available if we don't know the content runtime
|
||||||
return "00";
|
return "00";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetImageOrgOpValue()
|
||||||
|
{
|
||||||
|
var orgOp = string.Empty;
|
||||||
|
|
||||||
|
// Time-based seeking currently only possible when transcoding
|
||||||
|
orgOp += "0";
|
||||||
|
|
||||||
|
// Byte-based seeking only possible when not transcoding
|
||||||
|
orgOp += "1";
|
||||||
|
|
||||||
|
return orgOp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
public enum MediaFormatProfile
|
public enum MediaFormatProfile
|
||||||
|
@ -1,57 +1,62 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Dlna
|
namespace MediaBrowser.Model.Dlna
|
||||||
{
|
{
|
||||||
public class MediaFormatProfileResolver
|
public class MediaFormatProfileResolver
|
||||||
{
|
{
|
||||||
public MediaFormatProfile? ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestampType)
|
public IEnumerable<MediaFormatProfile> ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
|
||||||
{
|
{
|
||||||
if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase))
|
||||||
return ResolveVideoASFFormat(videoCodec, audioCodec, width, height);
|
{
|
||||||
|
var val = ResolveVideoASFFormat(videoCodec, audioCodec, width, height);
|
||||||
|
return val.HasValue ? new List<MediaFormatProfile> { val.Value } : new List<MediaFormatProfile>();
|
||||||
|
}
|
||||||
|
|
||||||
if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase))
|
||||||
return ResolveVideoMP4Format(videoCodec, audioCodec, width, height, bitrate);
|
{
|
||||||
|
var val = ResolveVideoMP4Format(videoCodec, audioCodec, width, height);
|
||||||
|
return val.HasValue ? new List<MediaFormatProfile> { val.Value } : new List<MediaFormatProfile>();
|
||||||
|
}
|
||||||
|
|
||||||
if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase))
|
||||||
return MediaFormatProfile.AVI;
|
return new[] { MediaFormatProfile.AVI };
|
||||||
|
|
||||||
if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase))
|
||||||
return MediaFormatProfile.MATROSKA;
|
return new[] { MediaFormatProfile.MATROSKA };
|
||||||
|
|
||||||
if (string.Equals(container, "mpeg2ps", StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(container, "mpeg2ps", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase))
|
string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase))
|
||||||
// MediaFormatProfile.MPEG_PS_PAL, MediaFormatProfile.MPEG_PS_NTSC
|
|
||||||
return MediaFormatProfile.MPEG_PS_NTSC;
|
return new[] { MediaFormatProfile.MPEG_PS_NTSC, MediaFormatProfile.MPEG_PS_PAL };
|
||||||
|
|
||||||
if (string.Equals(container, "mpeg1video", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(container, "mpeg1video", StringComparison.OrdinalIgnoreCase))
|
||||||
return MediaFormatProfile.MPEG1;
|
return new[] { MediaFormatProfile.MPEG1 };
|
||||||
|
|
||||||
if (string.Equals(container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) ||
|
if (string.Equals(container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(container, "mpegts", StringComparison.OrdinalIgnoreCase) ||
|
string.Equals(container, "mpegts", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase))
|
string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
|
||||||
var list = ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, timestampType)
|
return ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, timestampType);
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return list.Count > 0 ? list[0] : (MediaFormatProfile?)null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(container, "flv", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(container, "flv", StringComparison.OrdinalIgnoreCase))
|
||||||
return MediaFormatProfile.FLV;
|
return new[] { MediaFormatProfile.FLV };
|
||||||
|
|
||||||
if (string.Equals(container, "wtv", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(container, "wtv", StringComparison.OrdinalIgnoreCase))
|
||||||
return MediaFormatProfile.WTV;
|
return new[] { MediaFormatProfile.WTV };
|
||||||
|
|
||||||
if (string.Equals(container, "3gp", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(container, "3gp", StringComparison.OrdinalIgnoreCase))
|
||||||
return ResolveVideo3GPFormat(videoCodec, audioCodec);
|
{
|
||||||
|
var val = ResolveVideo3GPFormat(videoCodec, audioCodec);
|
||||||
|
return val.HasValue ? new List<MediaFormatProfile> { val.Value } : new List<MediaFormatProfile>();
|
||||||
|
}
|
||||||
|
|
||||||
if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase))
|
||||||
return MediaFormatProfile.OGV;
|
return new[] { MediaFormatProfile.OGV };
|
||||||
|
|
||||||
return null;
|
return new List<MediaFormatProfile>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<MediaFormatProfile> ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
|
private IEnumerable<MediaFormatProfile> ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
|
||||||
@ -132,11 +137,16 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
}
|
}
|
||||||
return new[] { MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO };
|
return new[] { MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO };
|
||||||
}
|
}
|
||||||
// if (audioCodec == AudioCodec.DTS) {
|
if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreCase))
|
||||||
// suffix = suffix.equals("_ISO") ? suffix : "_T";
|
{
|
||||||
// return Collections.singletonList(MediaFormatProfile.valueOf(String.format("VC1_TS_HD_DTS%s", cast(Object[])[ suffix ])));
|
suffix = string.Equals(suffix, "_ISO") ? suffix : "_T";
|
||||||
// }
|
|
||||||
//} else if ((videoCodec == VideoCodec.MPEG4) || (videoCodec == VideoCodec.MSMPEG4)) {
|
return new[] { ValueOf(string.Format("VC1_TS_HD_DTS{0}", suffix)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
// if (audioCodec == AudioCodec.AAC)
|
// if (audioCodec == AudioCodec.AAC)
|
||||||
// return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_AAC%s", cast(Object[])[ suffix ])));
|
// return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_AAC%s", cast(Object[])[ suffix ])));
|
||||||
// if (audioCodec == AudioCodec.MP3)
|
// if (audioCodec == AudioCodec.MP3)
|
||||||
@ -145,7 +155,6 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
// return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_MPEG2_L2%s", cast(Object[])[ suffix ])));
|
// return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_MPEG2_L2%s", cast(Object[])[ suffix ])));
|
||||||
// if ((audioCodec is null) || (audioCodec == AudioCodec.AC3)) {
|
// if ((audioCodec is null) || (audioCodec == AudioCodec.AC3)) {
|
||||||
// return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_AC3%s", cast(Object[])[ suffix ])));
|
// return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_AC3%s", cast(Object[])[ suffix ])));
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new List<MediaFormatProfile>();
|
return new List<MediaFormatProfile>();
|
||||||
@ -156,7 +165,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return (MediaFormatProfile)Enum.Parse(typeof(MediaFormatProfile), value, true);
|
return (MediaFormatProfile)Enum.Parse(typeof(MediaFormatProfile), value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaFormatProfile? ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height, int? bitrate)
|
private MediaFormatProfile? ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height)
|
||||||
{
|
{
|
||||||
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
@ -100,13 +100,23 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
var audioCodec = audioStream == null ? null : audioStream.Codec;
|
var audioCodec = audioStream == null ? null : audioStream.Codec;
|
||||||
|
|
||||||
// Make sure audio codec profiles are satisfied
|
// Make sure audio codec profiles are satisfied
|
||||||
if (!string.IsNullOrEmpty(audioCodec) && options.Profile.CodecProfiles.Where(i => i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
|
if (!string.IsNullOrEmpty(audioCodec))
|
||||||
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, null, audioStream)))
|
|
||||||
{
|
{
|
||||||
playlistItem.IsDirectStream = true;
|
var conditionProcessor = new ConditionProcessor();
|
||||||
playlistItem.Container = item.Container;
|
|
||||||
|
|
||||||
return playlistItem;
|
var conditions = options.Profile.CodecProfiles.Where(i => i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
|
||||||
|
.SelectMany(i => i.Conditions);
|
||||||
|
|
||||||
|
var audioChannels = audioStream == null ? null : audioStream.Channels;
|
||||||
|
var audioBitrate = audioStream == null ? null : audioStream.BitRate;
|
||||||
|
|
||||||
|
if (conditions.All(c => conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate)))
|
||||||
|
{
|
||||||
|
playlistItem.IsDirectStream = true;
|
||||||
|
playlistItem.Container = item.Container;
|
||||||
|
|
||||||
|
return playlistItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,29 +178,14 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
if (IsEligibleForDirectPlay(item, options, maxBitrateSetting))
|
if (IsEligibleForDirectPlay(item, options, maxBitrateSetting))
|
||||||
{
|
{
|
||||||
// See if it can be direct played
|
// See if it can be direct played
|
||||||
var directPlay = options.Profile.DirectPlayProfiles
|
var directPlay = GetVideoDirectPlayProfile(options.Profile, item, videoStream, audioStream);
|
||||||
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsVideoDirectPlaySupported(i, item, videoStream, audioStream));
|
|
||||||
|
|
||||||
if (directPlay != null)
|
if (directPlay != null)
|
||||||
{
|
{
|
||||||
var videoCodec = videoStream == null ? null : videoStream.Codec;
|
playlistItem.IsDirectStream = true;
|
||||||
|
playlistItem.Container = item.Container;
|
||||||
|
|
||||||
// Make sure video codec profiles are satisfied
|
return playlistItem;
|
||||||
if (!string.IsNullOrEmpty(videoCodec) && options.Profile.CodecProfiles.Where(i => i.Type == CodecType.Video && i.ContainsCodec(videoCodec))
|
|
||||||
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
|
|
||||||
{
|
|
||||||
var audioCodec = audioStream == null ? null : audioStream.Codec;
|
|
||||||
|
|
||||||
// Make sure audio codec profiles are satisfied
|
|
||||||
if (string.IsNullOrEmpty(audioCodec) || options.Profile.CodecProfiles.Where(i => i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec))
|
|
||||||
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
|
|
||||||
{
|
|
||||||
playlistItem.IsDirectStream = true;
|
|
||||||
playlistItem.Container = item.Container;
|
|
||||||
|
|
||||||
return playlistItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,6 +252,110 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DirectPlayProfile GetVideoDirectPlayProfile(DeviceProfile profile,
|
||||||
|
MediaSourceInfo mediaSource,
|
||||||
|
MediaStream videoStream,
|
||||||
|
MediaStream audioStream)
|
||||||
|
{
|
||||||
|
// See if it can be direct played
|
||||||
|
var directPlay = profile.DirectPlayProfiles
|
||||||
|
.FirstOrDefault(i => i.Type == DlnaProfileType.Video && IsVideoDirectPlaySupported(i, mediaSource, videoStream, audioStream));
|
||||||
|
|
||||||
|
if (directPlay == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var container = mediaSource.Container;
|
||||||
|
|
||||||
|
var conditions = profile.ContainerProfiles
|
||||||
|
.Where(i => i.Type == DlnaProfileType.Video && i.GetContainers().Contains(container, StringComparer.OrdinalIgnoreCase))
|
||||||
|
.SelectMany(i => i.Conditions);
|
||||||
|
|
||||||
|
var conditionProcessor = new ConditionProcessor();
|
||||||
|
|
||||||
|
var width = videoStream == null ? null : videoStream.Width;
|
||||||
|
var height = videoStream == null ? null : videoStream.Height;
|
||||||
|
var bitDepth = videoStream == null ? null : videoStream.BitDepth;
|
||||||
|
var videoBitrate = videoStream == null ? null : videoStream.BitRate;
|
||||||
|
var videoLevel = videoStream == null ? null : videoStream.Level;
|
||||||
|
var videoProfile = videoStream == null ? null : videoStream.Profile;
|
||||||
|
var videoFramerate = videoStream == null ? null : videoStream.AverageFrameRate ?? videoStream.AverageFrameRate;
|
||||||
|
|
||||||
|
var audioBitrate = audioStream == null ? null : audioStream.BitRate;
|
||||||
|
var audioChannels = audioStream == null ? null : audioStream.Channels;
|
||||||
|
|
||||||
|
var timestamp = videoStream == null ? TransportStreamTimestamp.NONE : videoStream.Timestamp;
|
||||||
|
var packetLength = videoStream == null ? null : videoStream.PacketLength;
|
||||||
|
|
||||||
|
// Check container conditions
|
||||||
|
if (!conditions.All(i => conditionProcessor.IsVideoConditionSatisfied(i,
|
||||||
|
audioBitrate,
|
||||||
|
audioChannels,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
bitDepth,
|
||||||
|
videoBitrate,
|
||||||
|
videoProfile,
|
||||||
|
videoLevel,
|
||||||
|
videoFramerate,
|
||||||
|
packetLength,
|
||||||
|
timestamp)))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var videoCodec = videoStream == null ? null : videoStream.Codec;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(videoCodec))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
conditions = profile.CodecProfiles
|
||||||
|
.Where(i => i.Type == CodecType.Video && i.ContainsCodec(videoCodec))
|
||||||
|
.SelectMany(i => i.Conditions);
|
||||||
|
|
||||||
|
if (!conditions.All(i => conditionProcessor.IsVideoConditionSatisfied(i,
|
||||||
|
audioBitrate,
|
||||||
|
audioChannels,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
bitDepth,
|
||||||
|
videoBitrate,
|
||||||
|
videoProfile,
|
||||||
|
videoLevel,
|
||||||
|
videoFramerate,
|
||||||
|
packetLength,
|
||||||
|
timestamp)))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioStream != null)
|
||||||
|
{
|
||||||
|
var audioCodec = audioStream.Codec;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(audioCodec))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
conditions = profile.CodecProfiles
|
||||||
|
.Where(i => i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec))
|
||||||
|
.SelectMany(i => i.Conditions);
|
||||||
|
|
||||||
|
if (!conditions.All(i => conditionProcessor.IsVideoAudioConditionSatisfied(i,
|
||||||
|
audioChannels,
|
||||||
|
audioBitrate)))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return directPlay;
|
||||||
|
}
|
||||||
|
|
||||||
private bool IsEligibleForDirectPlay(MediaSourceInfo item, VideoOptions options, int? maxBitrate)
|
private bool IsEligibleForDirectPlay(MediaSourceInfo item, VideoOptions options, int? maxBitrate)
|
||||||
{
|
{
|
||||||
if (options.SubtitleStreamIndex.HasValue)
|
if (options.SubtitleStreamIndex.HasValue)
|
||||||
@ -343,12 +442,18 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
}
|
}
|
||||||
case ProfileConditionValue.AudioProfile:
|
case ProfileConditionValue.AudioProfile:
|
||||||
case ProfileConditionValue.Has64BitOffsets:
|
case ProfileConditionValue.Has64BitOffsets:
|
||||||
|
case ProfileConditionValue.PacketLength:
|
||||||
|
case ProfileConditionValue.VideoTimestamp:
|
||||||
case ProfileConditionValue.VideoBitDepth:
|
case ProfileConditionValue.VideoBitDepth:
|
||||||
case ProfileConditionValue.VideoProfile:
|
|
||||||
{
|
{
|
||||||
// Not supported yet
|
// Not supported yet
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ProfileConditionValue.VideoProfile:
|
||||||
|
{
|
||||||
|
item.VideoProfile = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ProfileConditionValue.Height:
|
case ProfileConditionValue.Height:
|
||||||
{
|
{
|
||||||
int num;
|
int num;
|
||||||
@ -457,155 +562,5 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool AreConditionsSatisfied(IEnumerable<ProfileCondition> conditions, string mediaPath, MediaStream videoStream, MediaStream audioStream)
|
|
||||||
{
|
|
||||||
return conditions.All(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines whether [is condition satisfied] [the specified condition].
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="condition">The condition.</param>
|
|
||||||
/// <param name="mediaPath">The media path.</param>
|
|
||||||
/// <param name="videoStream">The video stream.</param>
|
|
||||||
/// <param name="audioStream">The audio stream.</param>
|
|
||||||
/// <returns><c>true</c> if [is condition satisfied] [the specified condition]; otherwise, <c>false</c>.</returns>
|
|
||||||
/// <exception cref="System.InvalidOperationException">Unexpected ProfileConditionType</exception>
|
|
||||||
private bool IsConditionSatisfied(ProfileCondition condition, string mediaPath, MediaStream videoStream, MediaStream audioStream)
|
|
||||||
{
|
|
||||||
if (condition.Property == ProfileConditionValue.Has64BitOffsets)
|
|
||||||
{
|
|
||||||
// TODO: Determine how to evaluate this
|
|
||||||
}
|
|
||||||
|
|
||||||
if (condition.Property == ProfileConditionValue.VideoProfile)
|
|
||||||
{
|
|
||||||
var profile = videoStream == null ? null : videoStream.Profile;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(profile))
|
|
||||||
{
|
|
||||||
switch (condition.Condition)
|
|
||||||
{
|
|
||||||
case ProfileConditionType.Equals:
|
|
||||||
return string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
|
|
||||||
case ProfileConditionType.NotEquals:
|
|
||||||
return !string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (condition.Property == ProfileConditionValue.AudioProfile)
|
|
||||||
{
|
|
||||||
var profile = audioStream == null ? null : audioStream.Profile;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(profile))
|
|
||||||
{
|
|
||||||
switch (condition.Condition)
|
|
||||||
{
|
|
||||||
case ProfileConditionType.Equals:
|
|
||||||
return string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
|
|
||||||
case ProfileConditionType.NotEquals:
|
|
||||||
return !string.Equals(profile, condition.Value, StringComparison.OrdinalIgnoreCase);
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var actualValue = GetConditionValue(condition, mediaPath, videoStream, audioStream);
|
|
||||||
|
|
||||||
if (actualValue.HasValue)
|
|
||||||
{
|
|
||||||
double expected;
|
|
||||||
if (double.TryParse(condition.Value, NumberStyles.Any, _usCulture, out expected))
|
|
||||||
{
|
|
||||||
switch (condition.Condition)
|
|
||||||
{
|
|
||||||
case ProfileConditionType.Equals:
|
|
||||||
return actualValue.Value.Equals(expected);
|
|
||||||
case ProfileConditionType.GreaterThanEqual:
|
|
||||||
return actualValue.Value >= expected;
|
|
||||||
case ProfileConditionType.LessThanEqual:
|
|
||||||
return actualValue.Value <= expected;
|
|
||||||
case ProfileConditionType.NotEquals:
|
|
||||||
return !actualValue.Value.Equals(expected);
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Unexpected ProfileConditionType");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value doesn't exist in metadata. Fail it if required.
|
|
||||||
return !condition.IsRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the condition value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="condition">The condition.</param>
|
|
||||||
/// <param name="mediaPath">The media path.</param>
|
|
||||||
/// <param name="videoStream">The video stream.</param>
|
|
||||||
/// <param name="audioStream">The audio stream.</param>
|
|
||||||
/// <returns>System.Nullable{System.Int64}.</returns>
|
|
||||||
/// <exception cref="System.InvalidOperationException">Unexpected Property</exception>
|
|
||||||
private double? GetConditionValue(ProfileCondition condition, string mediaPath, MediaStream videoStream, MediaStream audioStream)
|
|
||||||
{
|
|
||||||
switch (condition.Property)
|
|
||||||
{
|
|
||||||
case ProfileConditionValue.AudioBitrate:
|
|
||||||
return audioStream == null ? null : audioStream.BitRate;
|
|
||||||
case ProfileConditionValue.AudioChannels:
|
|
||||||
return audioStream == null ? null : audioStream.Channels;
|
|
||||||
case ProfileConditionValue.VideoBitrate:
|
|
||||||
return videoStream == null ? null : videoStream.BitRate;
|
|
||||||
case ProfileConditionValue.VideoFramerate:
|
|
||||||
return videoStream == null ? null : (videoStream.AverageFrameRate ?? videoStream.RealFrameRate);
|
|
||||||
case ProfileConditionValue.Height:
|
|
||||||
return videoStream == null ? null : videoStream.Height;
|
|
||||||
case ProfileConditionValue.Width:
|
|
||||||
return videoStream == null ? null : videoStream.Width;
|
|
||||||
case ProfileConditionValue.VideoLevel:
|
|
||||||
return videoStream == null ? null : videoStream.Level;
|
|
||||||
case ProfileConditionValue.VideoBitDepth:
|
|
||||||
return videoStream == null ? null : GetBitDepth(videoStream);
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Unexpected Property");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int? GetBitDepth(MediaStream videoStream)
|
|
||||||
{
|
|
||||||
var eightBit = new List<string>
|
|
||||||
{
|
|
||||||
"yuv420p",
|
|
||||||
"yuv411p",
|
|
||||||
"yuvj420p",
|
|
||||||
"uyyvyy411",
|
|
||||||
"nv12",
|
|
||||||
"nv21",
|
|
||||||
"rgb444le",
|
|
||||||
"rgb444be",
|
|
||||||
"bgr444le",
|
|
||||||
"bgr444be",
|
|
||||||
"yuvj411p"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(videoStream.PixelFormat))
|
|
||||||
{
|
|
||||||
if (eightBit.Contains(videoStream.PixelFormat, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
public long StartPositionTicks { get; set; }
|
public long StartPositionTicks { get; set; }
|
||||||
|
|
||||||
public string VideoCodec { get; set; }
|
public string VideoCodec { get; set; }
|
||||||
|
public string VideoProfile { get; set; }
|
||||||
|
|
||||||
public string AudioCodec { get; set; }
|
public string AudioCodec { get; set; }
|
||||||
|
|
||||||
@ -57,8 +58,6 @@ 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
|
||||||
@ -177,6 +176,74 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public int? TargetVideoBitDepth
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = TargetVideoStream;
|
||||||
|
return stream == null || !IsDirectStream ? null : stream.BitDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public double? TargetFramerate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = TargetVideoStream;
|
||||||
|
return MaxFramerate.HasValue && !IsDirectStream
|
||||||
|
? MaxFramerate
|
||||||
|
: stream == null ? null : stream.AverageFrameRate ?? stream.RealFrameRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public double? TargetVideoLevel
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = TargetVideoStream;
|
||||||
|
return VideoLevel.HasValue && !IsDirectStream
|
||||||
|
? VideoLevel
|
||||||
|
: stream == null ? null : stream.Level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public int? TargetPacketLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = TargetVideoStream;
|
||||||
|
return !IsDirectStream
|
||||||
|
? null
|
||||||
|
: stream == null ? null : stream.PacketLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Predicts the audio sample rate that will be in the output stream
|
||||||
|
/// </summary>
|
||||||
|
public string TargetVideoProfile
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = TargetVideoStream;
|
||||||
|
return !string.IsNullOrEmpty(VideoProfile) && !IsDirectStream
|
||||||
|
? VideoProfile
|
||||||
|
: stream == null ? null : stream.Profile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Predicts the audio bitrate that will be in the output stream
|
/// Predicts the audio bitrate that will be in the output stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -256,11 +323,35 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int? TotalOutputBitrate
|
public int? TargetVideoBitrate
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (TargetAudioBitrate ?? 0) + (VideoBitrate ?? 0);
|
var stream = TargetVideoStream;
|
||||||
|
|
||||||
|
return VideoBitrate.HasValue && !IsDirectStream
|
||||||
|
? VideoBitrate
|
||||||
|
: stream == null ? null : stream.BitRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportStreamTimestamp TargetTimestamp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var stream = TargetVideoStream;
|
||||||
|
|
||||||
|
return !IsDirectStream
|
||||||
|
? TransportStreamTimestamp.VALID
|
||||||
|
: stream == null ? TransportStreamTimestamp.VALID : stream.Timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int? TargetTotalBitrate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (TargetAudioBitrate ?? 0) + (TargetVideoBitrate ?? 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using MediaBrowser.Model.Dlna;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Entities
|
namespace MediaBrowser.Model.Entities
|
||||||
{
|
{
|
||||||
@ -39,6 +40,24 @@ namespace MediaBrowser.Model.Entities
|
|||||||
/// <value>The bit rate.</value>
|
/// <value>The bit rate.</value>
|
||||||
public int? BitRate { get; set; }
|
public int? BitRate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the bit depth.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The bit depth.</value>
|
||||||
|
public int? BitDepth { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the length of the packet.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The length of the packet.</value>
|
||||||
|
public int? PacketLength { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the timestamp.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The timestamp.</value>
|
||||||
|
public TransportStreamTimestamp Timestamp { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the channels.
|
/// Gets or sets the channels.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
<Compile Include="Configuration\MetadataOptions.cs" />
|
<Compile Include="Configuration\MetadataOptions.cs" />
|
||||||
<Compile Include="Configuration\ServerConfiguration.cs" />
|
<Compile Include="Configuration\ServerConfiguration.cs" />
|
||||||
<Compile Include="Dlna\CodecProfile.cs" />
|
<Compile Include="Dlna\CodecProfile.cs" />
|
||||||
|
<Compile Include="Dlna\ConditionProcessor.cs" />
|
||||||
<Compile Include="Dlna\ContainerProfile.cs" />
|
<Compile Include="Dlna\ContainerProfile.cs" />
|
||||||
<Compile Include="Dlna\ContentFeatureBuilder.cs" />
|
<Compile Include="Dlna\ContentFeatureBuilder.cs" />
|
||||||
<Compile Include="Dlna\DeviceIdentification.cs" />
|
<Compile Include="Dlna\DeviceIdentification.cs" />
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using System.Text;
|
using MediaBrowser.Controller.Persistence;
|
||||||
using MediaBrowser.Controller.Persistence;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||||||
|
|
||||||
// Add PixelFormat column
|
// Add PixelFormat column
|
||||||
|
|
||||||
createTableCommand += "(ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, PRIMARY KEY (ItemId, StreamIndex))";
|
createTableCommand += "(ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, PRIMARY KEY (ItemId, StreamIndex))";
|
||||||
|
|
||||||
string[] queries = {
|
string[] queries = {
|
||||||
|
|
||||||
@ -57,6 +57,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||||||
_connection.RunQueries(queries, _logger);
|
_connection.RunQueries(queries, _logger);
|
||||||
|
|
||||||
AddPixelFormatColumnCommand();
|
AddPixelFormatColumnCommand();
|
||||||
|
AddBitDepthCommand();
|
||||||
|
|
||||||
PrepareStatements();
|
PrepareStatements();
|
||||||
|
|
||||||
@ -94,6 +95,37 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||||||
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddBitDepthCommand()
|
||||||
|
{
|
||||||
|
using (var cmd = _connection.CreateCommand())
|
||||||
|
{
|
||||||
|
cmd.CommandText = "PRAGMA table_info(mediastreams)";
|
||||||
|
|
||||||
|
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult))
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
if (!reader.IsDBNull(1))
|
||||||
|
{
|
||||||
|
var name = reader.GetString(1);
|
||||||
|
|
||||||
|
if (string.Equals(name, "BitDepth", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
|
||||||
|
builder.AppendLine("alter table mediastreams");
|
||||||
|
builder.AppendLine("add column BitDepth INT NULL");
|
||||||
|
|
||||||
|
_connection.RunQueries(new[] { builder.ToString() }, _logger);
|
||||||
|
}
|
||||||
|
|
||||||
private readonly string[] _saveColumns =
|
private readonly string[] _saveColumns =
|
||||||
{
|
{
|
||||||
"ItemId",
|
"ItemId",
|
||||||
@ -117,7 +149,8 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||||||
"AverageFrameRate",
|
"AverageFrameRate",
|
||||||
"RealFrameRate",
|
"RealFrameRate",
|
||||||
"Level",
|
"Level",
|
||||||
"PixelFormat"
|
"PixelFormat",
|
||||||
|
"BitDepth"
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -281,6 +314,11 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||||||
item.PixelFormat = reader.GetString(21);
|
item.PixelFormat = reader.GetString(21);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!reader.IsDBNull(22))
|
||||||
|
{
|
||||||
|
item.BitDepth = reader.GetInt32(22);
|
||||||
|
}
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,6 +381,7 @@ namespace MediaBrowser.Server.Implementations.Persistence
|
|||||||
_saveStreamCommand.GetParameter(19).Value = stream.RealFrameRate;
|
_saveStreamCommand.GetParameter(19).Value = stream.RealFrameRate;
|
||||||
_saveStreamCommand.GetParameter(20).Value = stream.Level;
|
_saveStreamCommand.GetParameter(20).Value = stream.Level;
|
||||||
_saveStreamCommand.GetParameter(21).Value = stream.PixelFormat;
|
_saveStreamCommand.GetParameter(21).Value = stream.PixelFormat;
|
||||||
|
_saveStreamCommand.GetParameter(22).Value = stream.BitDepth;
|
||||||
|
|
||||||
_saveStreamCommand.Transaction = transaction;
|
_saveStreamCommand.Transaction = transaction;
|
||||||
_saveStreamCommand.ExecuteNonQuery();
|
_saveStreamCommand.ExecuteNonQuery();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user