diff options
Diffstat (limited to 'MediaBrowser.Model')
| -rw-r--r-- | MediaBrowser.Model/Dlna/DlnaMaps.cs | 62 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/MediaFormatProfile.cs | 122 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs | 342 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/StreamBuilder.cs | 8 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dlna/StreamInfo.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Model/Dto/MediaVersionInfo.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Model/Entities/BaseItemInfo.cs | 12 | ||||
| -rw-r--r-- | MediaBrowser.Model/MediaBrowser.Model.csproj | 3 | ||||
| -rw-r--r-- | MediaBrowser.Model/Session/PlaybackReports.cs | 13 | ||||
| -rw-r--r-- | MediaBrowser.Model/Session/SessionInfoDto.cs | 6 |
10 files changed, 579 insertions, 2 deletions
diff --git a/MediaBrowser.Model/Dlna/DlnaMaps.cs b/MediaBrowser.Model/Dlna/DlnaMaps.cs new file mode 100644 index 000000000..eb0c33315 --- /dev/null +++ b/MediaBrowser.Model/Dlna/DlnaMaps.cs @@ -0,0 +1,62 @@ +using System; + +namespace MediaBrowser.Model.Dlna +{ + public class DlnaMaps + { + public static readonly string DefaultStreaming = + FlagsToString(DlnaFlags.StreamingTransferMode | + DlnaFlags.BackgroundTransferMode | + DlnaFlags.ConnectionStall | + DlnaFlags.ByteBasedSeek | + DlnaFlags.DlnaV15); + + public static readonly string DefaultInteractive = + FlagsToString(DlnaFlags.InteractiveTransferMode | + DlnaFlags.BackgroundTransferMode | + DlnaFlags.ConnectionStall | + DlnaFlags.ByteBasedSeek | + DlnaFlags.DlnaV15); + + public static string FlagsToString(DlnaFlags flags) + { + return string.Format("{0:X8}{1:D24}", (ulong)flags, 0); + } + + public static string GetOrgOpValue(bool hasKnownRuntime, bool isDirectStream, TranscodeSeekInfo profileTranscodeSeekInfo) + { + if (hasKnownRuntime) + { + var orgOp = string.Empty; + + // Time-based seeking currently only possible when transcoding + orgOp += isDirectStream ? "0" : "1"; + + // Byte-based seeking only possible when not transcoding + orgOp += isDirectStream || profileTranscodeSeekInfo == TranscodeSeekInfo.Bytes ? "1" : "0"; + + return orgOp; + } + + // No seeking is available if we don't know the content runtime + return "00"; + } + } + + [Flags] + public enum DlnaFlags : ulong + { + BackgroundTransferMode = (1 << 22), + ByteBasedSeek = (1 << 29), + ConnectionStall = (1 << 21), + DlnaV15 = (1 << 20), + InteractiveTransferMode = (1 << 23), + PlayContainer = (1 << 28), + RtspPause = (1 << 25), + S0Increase = (1 << 27), + SenderPaced = (1L << 31), + SnIncrease = (1 << 26), + StreamingTransferMode = (1 << 24), + TimeBasedSeek = (1 << 30) + } +} diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfile.cs b/MediaBrowser.Model/Dlna/MediaFormatProfile.cs new file mode 100644 index 000000000..e686fe932 --- /dev/null +++ b/MediaBrowser.Model/Dlna/MediaFormatProfile.cs @@ -0,0 +1,122 @@ + +using System; + +namespace MediaBrowser.Model.Dlna +{ + public enum MediaFormatProfile + { + MP3, + WMA_BASE, + WMA_FULL, + LPCM16_44_MONO, + LPCM16_44_STEREO, + LPCM16_48_MONO, + LPCM16_48_STEREO, + AAC_ISO, + AAC_ISO_320, + AAC_ADTS, + AAC_ADTS_320, + FLAC, + OGG, + + JPEG_SM, + JPEG_MED, + JPEG_LRG, + JPEG_TN, + PNG_LRG, + PNG_TN, + GIF_LRG, + RAW, + + MPEG1, + MPEG_PS_PAL, + MPEG_PS_NTSC, + MPEG_TS_SD_EU, + MPEG_TS_SD_EU_ISO, + MPEG_TS_SD_EU_T, + MPEG_TS_SD_NA, + MPEG_TS_SD_NA_ISO, + MPEG_TS_SD_NA_T, + MPEG_TS_SD_KO, + MPEG_TS_SD_KO_ISO, + MPEG_TS_SD_KO_T, + MPEG_TS_JP_T, + AVI, + MATROSKA, + FLV, + DVR_MS, + WTV, + OGV, + AVC_MP4_MP_SD_AAC_MULT5, + AVC_MP4_MP_SD_MPEG1_L3, + AVC_MP4_MP_SD_AC3, + AVC_MP4_MP_HD_720p_AAC, + AVC_MP4_MP_HD_1080i_AAC, + AVC_MP4_HP_HD_AAC, + AVC_TS_MP_HD_AAC_MULT5, + AVC_TS_MP_HD_AAC_MULT5_T, + AVC_TS_MP_HD_AAC_MULT5_ISO, + AVC_TS_MP_HD_MPEG1_L3, + AVC_TS_MP_HD_MPEG1_L3_T, + AVC_TS_MP_HD_MPEG1_L3_ISO, + AVC_TS_MP_HD_AC3, + AVC_TS_MP_HD_AC3_T, + AVC_TS_MP_HD_AC3_ISO, + AVC_TS_HP_HD_MPEG1_L2_T, + AVC_TS_HP_HD_MPEG1_L2_ISO, + AVC_TS_MP_SD_AAC_MULT5, + AVC_TS_MP_SD_AAC_MULT5_T, + AVC_TS_MP_SD_AAC_MULT5_ISO, + AVC_TS_MP_SD_MPEG1_L3, + AVC_TS_MP_SD_MPEG1_L3_T, + AVC_TS_MP_SD_MPEG1_L3_ISO, + AVC_TS_HP_SD_MPEG1_L2_T, + AVC_TS_HP_SD_MPEG1_L2_ISO, + AVC_TS_MP_SD_AC3, + AVC_TS_MP_SD_AC3_T, + AVC_TS_MP_SD_AC3_ISO, + AVC_TS_HD_DTS_T, + AVC_TS_HD_DTS_ISO, + WMVMED_BASE, + WMVMED_FULL, + WMVMED_PRO, + WMVHIGH_FULL, + WMVHIGH_PRO, + VC1_ASF_AP_L1_WMA, + VC1_ASF_AP_L2_WMA, + VC1_ASF_AP_L3_WMA, + VC1_TS_AP_L1_AC3_ISO, + VC1_TS_AP_L2_AC3_ISO, + VC1_TS_HD_DTS_ISO, + VC1_TS_HD_DTS_T, + MPEG4_P2_MP4_ASP_AAC, + MPEG4_P2_MP4_SP_L6_AAC, + MPEG4_P2_MP4_NDSD, + MPEG4_P2_TS_ASP_AAC, + MPEG4_P2_TS_ASP_AAC_T, + MPEG4_P2_TS_ASP_AAC_ISO, + MPEG4_P2_TS_ASP_MPEG1_L3, + MPEG4_P2_TS_ASP_MPEG1_L3_T, + MPEG4_P2_TS_ASP_MPEG1_L3_ISO, + MPEG4_P2_TS_ASP_MPEG2_L2, + MPEG4_P2_TS_ASP_MPEG2_L2_T, + MPEG4_P2_TS_ASP_MPEG2_L2_ISO, + MPEG4_P2_TS_ASP_AC3, + MPEG4_P2_TS_ASP_AC3_T, + MPEG4_P2_TS_ASP_AC3_ISO, + AVC_TS_HD_50_LPCM_T, + AVC_MP4_LPCM, + MPEG4_P2_3GPP_SP_L0B_AAC, + MPEG4_P2_3GPP_SP_L0B_AMR, + AVC_3GPP_BL_QCIF15_AAC, + MPEG4_H263_3GPP_P0_L10_AMR, + MPEG4_H263_MP4_P0_L10_AAC + } + + public enum TransportStreamTimestamp + { + NONE, + ZERO, + VALID + } +} diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs new file mode 100644 index 000000000..76480930f --- /dev/null +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -0,0 +1,342 @@ +using System; + +namespace MediaBrowser.Model.Dlna +{ + public class MediaFormatProfileResolver + { + public MediaFormatProfile ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestampType) + { + if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) + return ResolveVideoASFFormat(videoCodec, audioCodec, width, height, bitrate); + if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase)) + return ResolveVideoMP4Format(videoCodec, audioCodec, width, height, bitrate); + if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.AVI; + if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.MATROSKA; + if (string.Equals(container, "mpeg2ps", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase)) + // MediaFormatProfile.MPEG_PS_PAL, MediaFormatProfile.MPEG_PS_NTSC + return MediaFormatProfile.MPEG_PS_NTSC; + if (string.Equals(container, "mpeg1video", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.MPEG1; + if (string.Equals(container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "mpegts", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase)) + return ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, bitrate, timestampType); + if (string.Equals(container, "flv", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.FLV; + if (string.Equals(container, "wtv", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.WTV; + if (string.Equals(container, "3gp", StringComparison.OrdinalIgnoreCase)) + return ResolveVideo3GPFormat(videoCodec, audioCodec, width, height, bitrate); + if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.OGV; + + throw new ArgumentException("Unsupported container: " + container); + } + + private MediaFormatProfile ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, int? bitrate, TransportStreamTimestamp timestampType) + { + // String suffix = ""; + // if (isNoTimestamp(timestampType)) + // suffix = "_ISO"; + // else if (timestampType == TransportStreamTimestamp.VALID) { + // suffix = "_T"; + // } + + // String resolution = "S"; + // if ((width.intValue() > 720) || (height.intValue() > 576)) { + // resolution = "H"; + // } + + // if (videoCodec == VideoCodec.MPEG2) + // { + // List!(MediaFormatProfile) profiles = Arrays.asList(cast(MediaFormatProfile[])[ MediaFormatProfile.valueOf("MPEG_TS_SD_EU" + suffix), MediaFormatProfile.valueOf("MPEG_TS_SD_NA" + suffix), MediaFormatProfile.valueOf("MPEG_TS_SD_KO" + suffix) ]); + + // if ((timestampType == TransportStreamTimestamp.VALID) && (audioCodec == AudioCodec.AAC)) { + // profiles.add(MediaFormatProfile.MPEG_TS_JP_T); + // } + // return profiles; + // }if (videoCodec == VideoCodec.H264) + // { + // if (audioCodec == AudioCodec.LPCM) + // return Collections.singletonList(MediaFormatProfile.AVC_TS_HD_50_LPCM_T); + // if (audioCodec == AudioCodec.DTS) { + // if (isNoTimestamp(timestampType)) { + // return Collections.singletonList(MediaFormatProfile.AVC_TS_HD_DTS_ISO); + // } + // return Collections.singletonList(MediaFormatProfile.AVC_TS_HD_DTS_T); + // } + // if (audioCodec == AudioCodec.MP2) { + // if (isNoTimestamp(timestampType)) { + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_HP_%sD_MPEG1_L2_ISO", cast(Object[])[ resolution ]))); + // } + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_HP_%sD_MPEG1_L2_T", cast(Object[])[ resolution ]))); + // } + + // if (audioCodec == AudioCodec.AAC) + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_MP_%sD_AAC_MULT5%s", cast(Object[])[ resolution, suffix ]))); + // if (audioCodec == AudioCodec.MP3) + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_MP_%sD_MPEG1_L3%s", cast(Object[])[ resolution, suffix ]))); + // if ((audioCodec is null) || (audioCodec == AudioCodec.AC3)) { + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("AVC_TS_MP_%sD_AC3%s", cast(Object[])[ resolution, suffix ]))); + // } + // } + // else if (videoCodec == VideoCodec.VC1) { + // if ((audioCodec is null) || (audioCodec == AudioCodec.AC3)) + // { + // if ((width.intValue() > 720) || (height.intValue() > 576)) { + // return Collections.singletonList(MediaFormatProfile.VC1_TS_AP_L2_AC3_ISO); + // } + // return Collections.singletonList(MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO); + // } + // if (audioCodec == AudioCodec.DTS) { + // suffix = suffix.equals("_ISO") ? suffix : "_T"; + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("VC1_TS_HD_DTS%s", cast(Object[])[ suffix ]))); + // } + // } else if ((videoCodec == VideoCodec.MPEG4) || (videoCodec == VideoCodec.MSMPEG4)) { + // if (audioCodec == AudioCodec.AAC) + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_AAC%s", cast(Object[])[ suffix ]))); + // if (audioCodec == AudioCodec.MP3) + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_MPEG1_L3%s", cast(Object[])[ suffix ]))); + // if (audioCodec == AudioCodec.MP2) + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_MPEG2_L2%s", cast(Object[])[ suffix ]))); + // if ((audioCodec is null) || (audioCodec == AudioCodec.AC3)) { + // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_AC3%s", cast(Object[])[ suffix ]))); + // } + // } + + throw new ArgumentException("Mpeg video file does not match any supported DLNA profile"); + } + + private MediaFormatProfile ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height, int? bitrate) + { + if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) + { + if (string.Equals(audioCodec, "lpcm", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.AVC_MP4_LPCM; + if (string.IsNullOrEmpty(audioCodec) || + string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.AVC_MP4_MP_SD_AC3; + } + if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.AVC_MP4_MP_SD_MPEG1_L3; + } + if (width.HasValue && height.HasValue) + { + if ((width.Value <= 720) && (height.Value <= 576)) + { + if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.AVC_MP4_MP_SD_AAC_MULT5; + } + else if ((width.Value <= 1280) && (height.Value <= 720)) + { + if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.AVC_MP4_MP_HD_720p_AAC; + } + else if ((width.Value <= 1920) && (height.Value <= 1080)) + { + if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.AVC_MP4_MP_HD_1080i_AAC; + } + } + } + } + else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase) || + string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) + { + if (width.HasValue && height.HasValue && width.Value <= 720 && height.Value <= 576) + { + if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.MPEG4_P2_MP4_ASP_AAC; + if (string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase) || string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.MPEG4_P2_MP4_NDSD; + } + } + else if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.MPEG4_P2_MP4_SP_L6_AAC; + } + } + else if (string.Equals(videoCodec, "h263", StringComparison.OrdinalIgnoreCase) && string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.MPEG4_H263_MP4_P0_L10_AAC; + } + + throw new ArgumentException("MP4 video file does not match any supported DLNA profile"); + } + + private MediaFormatProfile ResolveVideo3GPFormat(string videoCodec, string audioCodec, int? width, int? height, int? bitrate) + { + if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase)) + { + if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.AVC_3GPP_BL_QCIF15_AAC; + } + else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase) || + string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) + { + if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.MPEG4_P2_3GPP_SP_L0B_AAC; + if (string.Equals(audioCodec, "amrnb", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.MPEG4_P2_3GPP_SP_L0B_AMR; + } + else if (string.Equals(videoCodec, "h263", StringComparison.OrdinalIgnoreCase) && string.Equals(audioCodec, "amrnb", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.MPEG4_H263_3GPP_P0_L10_AMR; + } + + throw new ArgumentException("3GP video file does not match any supported DLNA profile"); + } + private MediaFormatProfile ResolveVideoASFFormat(string videoCodec, string audioCodec, int? width, int? height, int? bitrate) + { + if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase) && + (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "wmapro", StringComparison.OrdinalIgnoreCase))) + { + + if (width.HasValue && height.HasValue) + { + if ((width.Value <= 720) && (height.Value <= 576)) + { + if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.WMVMED_FULL; + } + return MediaFormatProfile.WMVMED_PRO; + } + } + + if (string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.WMVHIGH_FULL; + } + return MediaFormatProfile.WMVHIGH_PRO; + } + + if (string.Equals(videoCodec, "vc1", StringComparison.OrdinalIgnoreCase)) + { + if (width.HasValue && height.HasValue) + { + if ((width.Value <= 720) && (height.Value <= 576)) + return MediaFormatProfile.VC1_ASF_AP_L1_WMA; + if ((width.Value <= 1280) && (height.Value <= 720)) + return MediaFormatProfile.VC1_ASF_AP_L2_WMA; + if ((width.Value <= 1920) && (height.Value <= 1080)) + return MediaFormatProfile.VC1_ASF_AP_L3_WMA; + } + } + else if (string.Equals(videoCodec, "mpeg2video", StringComparison.OrdinalIgnoreCase)) + { + return MediaFormatProfile.DVR_MS; + } + + throw new ArgumentException("ASF video file does not match any supported DLNA profile"); + } + + public MediaFormatProfile ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels) + { + if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) + return ResolveAudioASFFormat(bitrate, frequency, channels); + if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.MP3; + if (string.Equals(container, "lpcm", StringComparison.OrdinalIgnoreCase)) + return ResolveAudioLPCMFormat(bitrate, frequency, channels); + if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase)) + return ResolveAudioMP4Format(bitrate, frequency, channels); + if (string.Equals(container, "adts", StringComparison.OrdinalIgnoreCase)) + return ResolveAudioADTSFormat(bitrate, frequency, channels); + if (string.Equals(container, "flac", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.FLAC; + if (string.Equals(container, "oga", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.OGG; + throw new ArgumentException("Unsupported container: " + container); + } + + private MediaFormatProfile ResolveAudioASFFormat(int? bitrate, int? frequency, int? channels) + { + if (bitrate.HasValue && bitrate.Value <= 193) + { + return MediaFormatProfile.WMA_BASE; + } + return MediaFormatProfile.WMA_FULL; + } + + private MediaFormatProfile ResolveAudioLPCMFormat(int? bitrate, int? frequency, int? channels) + { + if (frequency.HasValue && channels.HasValue) + { + if (frequency.Value == 44100 && channels.Value == 1) + { + return MediaFormatProfile.LPCM16_44_MONO; + } + if (frequency.Value == 44100 && channels.Value == 2) + { + return MediaFormatProfile.LPCM16_44_STEREO; + } + if (frequency.Value == 48000 && channels.Value == 1) + { + return MediaFormatProfile.LPCM16_48_MONO; + } + if (frequency.Value == 48000 && channels.Value == 1) + { + return MediaFormatProfile.LPCM16_48_STEREO; + } + + throw new ArgumentException("Unsupported LPCM format of file %s. Only 44100 / 48000 Hz and Mono / Stereo files are allowed."); + } + + return MediaFormatProfile.LPCM16_48_STEREO; + } + + private MediaFormatProfile ResolveAudioMP4Format(int? bitrate, int? frequency, int? channels) + { + if (bitrate.HasValue && bitrate.Value <= 320) + { + return MediaFormatProfile.AAC_ISO_320; + } + return MediaFormatProfile.AAC_ISO; + } + + private MediaFormatProfile ResolveAudioADTSFormat(int? bitrate, int? frequency, int? channels) + { + if (bitrate.HasValue && bitrate.Value <= 320) + { + return MediaFormatProfile.AAC_ADTS_320; + } + return MediaFormatProfile.AAC_ADTS; + } + + public MediaFormatProfile ResolveImageFormat(string container, int? width, int? height) + { + if (string.Equals(container, "jpeg", StringComparison.OrdinalIgnoreCase) || + string.Equals(container, "jpg", StringComparison.OrdinalIgnoreCase)) + return ResolveImageJPGFormat(width, height); + if (string.Equals(container, "png", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.PNG_LRG; + if (string.Equals(container, "gif", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.GIF_LRG; + if (string.Equals(container, "raw", StringComparison.OrdinalIgnoreCase)) + return MediaFormatProfile.RAW; + + throw new ArgumentException("Unsupported container: " + container); + } + + private MediaFormatProfile ResolveImageJPGFormat(int? width, int? height) + { + if (width.HasValue && height.HasValue) + { + if ((width.Value <= 640) && (height.Value <= 480)) + return MediaFormatProfile.JPEG_SM; + + if ((width.Value <= 1024) && (height.Value <= 768)) + { + return MediaFormatProfile.JPEG_MED; + } + } + + return MediaFormatProfile.JPEG_LRG; + } + } +} diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 3960b49ae..d975b1c4b 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -81,7 +81,8 @@ namespace MediaBrowser.Model.Dlna { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, - MediaSourceId = item.Id + MediaSourceId = item.Id, + RunTimeTicks = item.RunTimeTicks }; var audioStream = item.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); @@ -114,6 +115,7 @@ namespace MediaBrowser.Model.Dlna if (transcodingProfile != null) { playlistItem.IsDirectStream = false; + playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.Container = transcodingProfile.Container; playlistItem.AudioCodec = transcodingProfile.AudioCodec; @@ -150,7 +152,8 @@ namespace MediaBrowser.Model.Dlna { ItemId = options.ItemId, MediaType = DlnaProfileType.Video, - MediaSourceId = item.Id + MediaSourceId = item.Id, + RunTimeTicks = item.RunTimeTicks }; var audioStream = item.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); @@ -193,6 +196,7 @@ namespace MediaBrowser.Model.Dlna { playlistItem.IsDirectStream = false; playlistItem.Container = transcodingProfile.Container; + playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',').FirstOrDefault(); playlistItem.VideoCodec = transcodingProfile.VideoCodec; diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 209f33930..6ba7fe399 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -46,6 +46,10 @@ namespace MediaBrowser.Model.Dlna public string DeviceProfileId { get; set; } public string DeviceId { get; set; } + public long? RunTimeTicks { get; set; } + + public TranscodeSeekInfo TranscodeSeekInfo { get; set; } + public string ToUrl(string baseUrl) { return ToDlnaUrl(baseUrl); diff --git a/MediaBrowser.Model/Dto/MediaVersionInfo.cs b/MediaBrowser.Model/Dto/MediaVersionInfo.cs index e174c5d55..cfef83d2c 100644 --- a/MediaBrowser.Model/Dto/MediaVersionInfo.cs +++ b/MediaBrowser.Model/Dto/MediaVersionInfo.cs @@ -10,6 +10,7 @@ namespace MediaBrowser.Model.Dto public string Path { get; set; } public string Container { get; set; } + public long? Size { get; set; } public LocationType LocationType { get; set; } @@ -25,6 +26,14 @@ namespace MediaBrowser.Model.Dto public List<MediaStream> MediaStreams { get; set; } + public List<string> Formats { get; set; } + public int? Bitrate { get; set; } + + public MediaSourceInfo() + { + Formats = new List<string>(); + MediaStreams = new List<MediaStream>(); + } } } diff --git a/MediaBrowser.Model/Entities/BaseItemInfo.cs b/MediaBrowser.Model/Entities/BaseItemInfo.cs index 5554e40d5..a280b1f71 100644 --- a/MediaBrowser.Model/Entities/BaseItemInfo.cs +++ b/MediaBrowser.Model/Entities/BaseItemInfo.cs @@ -52,6 +52,18 @@ namespace MediaBrowser.Model.Entities /// </summary> /// <value>The primary image item identifier.</value> public string PrimaryImageItemId { get; set; } + + /// <summary> + /// Gets or sets the logo image tag. + /// </summary> + /// <value>The logo image tag.</value> + public Guid? LogoImageTag { get; set; } + + /// <summary> + /// Gets or sets the logo item identifier. + /// </summary> + /// <value>The logo item identifier.</value> + public string LogoItemId { get; set; } /// <summary> /// Gets or sets the thumb image tag. diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index ec78a2b1b..5e373441f 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -72,6 +72,9 @@ <Compile Include="Dlna\DeviceProfile.cs" /> <Compile Include="Dlna\DeviceProfileInfo.cs" /> <Compile Include="Dlna\DirectPlayProfile.cs" /> + <Compile Include="Dlna\DlnaMaps.cs" /> + <Compile Include="Dlna\MediaFormatProfile.cs" /> + <Compile Include="Dlna\MediaFormatProfileResolver.cs" /> <Compile Include="Dlna\ResponseProfile.cs" /> <Compile Include="Dlna\StreamBuilder.cs" /> <Compile Include="Dlna\StreamInfo.cs" /> diff --git a/MediaBrowser.Model/Session/PlaybackReports.cs b/MediaBrowser.Model/Session/PlaybackReports.cs index 24594fcb1..80524c06e 100644 --- a/MediaBrowser.Model/Session/PlaybackReports.cs +++ b/MediaBrowser.Model/Session/PlaybackReports.cs @@ -90,6 +90,19 @@ namespace MediaBrowser.Model.Session /// </summary> /// <value>The volume level.</value> public int? VolumeLevel { get; set; } + + /// <summary> + /// Gets or sets the play method. + /// </summary> + /// <value>The play method.</value> + public PlayMethod PlayMethod { get; set; } + } + + public enum PlayMethod + { + Transcode = 0, + DirectStream = 1, + DirectPlay = 2 } /// <summary> diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs index b9dcf996e..686af4849 100644 --- a/MediaBrowser.Model/Session/SessionInfoDto.cs +++ b/MediaBrowser.Model/Session/SessionInfoDto.cs @@ -233,5 +233,11 @@ namespace MediaBrowser.Model.Session /// </summary> /// <value>The now playing media version identifier.</value> public string MediaSourceId { get; set; } + + /// <summary> + /// Gets or sets the play method. + /// </summary> + /// <value>The play method.</value> + public PlayMethod? PlayMethod { get; set; } } } |
