2014-04-23 04:47:46 +02:00
using System ;
2014-04-24 07:08:10 +02:00
using System.Collections.Generic ;
using System.Linq ;
2014-04-25 04:00:19 +02:00
using MediaBrowser.Model.Entities ;
using MediaBrowser.Model.MediaInfo ;
2014-04-23 04:47:46 +02:00
namespace MediaBrowser.Model.Dlna
{
public class ContentFeatureBuilder
{
private readonly DeviceProfile _profile ;
public ContentFeatureBuilder ( DeviceProfile profile )
{
_profile = profile ;
}
2014-04-24 07:08:10 +02:00
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 ,
2014-04-23 04:47:46 +02:00
string audioCodec ,
2014-04-24 07:08:10 +02:00
int? audioBitrate ,
int? audioSampleRate ,
int? audioChannels ,
bool isDirectStream ,
long? runtimeTicks ,
2014-04-23 04:47:46 +02:00
TranscodeSeekInfo transcodeSeekInfo )
{
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
var orgOp = ";DLNA.ORG_OP=" + DlnaMaps . GetOrgOpValue ( runtimeTicks . HasValue , isDirectStream , transcodeSeekInfo ) ;
// 0 = native, 1 = transcoded
var orgCi = isDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1" ;
var flagValue = DlnaFlags . StreamingTransferMode |
DlnaFlags . BackgroundTransferMode |
DlnaFlags . DlnaV15 ;
if ( isDirectStream )
{
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_BYTE_BASED_SEEK;
}
else if ( runtimeTicks . HasValue )
{
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_TIME_BASED_SEEK;
}
2014-04-23 17:35:31 +02:00
var dlnaflags = string . Format ( ";DLNA.ORG_FLAGS={0}" ,
FlagsToString ( flagValue ) ) ;
2014-04-23 04:47:46 +02:00
2014-04-24 07:08:10 +02:00
var mediaProfile = _profile . GetAudioMediaProfile ( container ,
audioCodec ,
audioChannels ,
audioBitrate ) ;
2014-04-23 04:47:46 +02:00
var orgPn = mediaProfile = = null ? null : mediaProfile . OrgPn ;
if ( string . IsNullOrEmpty ( orgPn ) )
{
orgPn = GetAudioOrgPnValue ( container , audioBitrate , audioSampleRate , audioChannels ) ;
}
var contentFeatures = string . IsNullOrEmpty ( orgPn ) ? string . Empty : "DLNA.ORG_PN=" + orgPn ;
return ( contentFeatures + orgOp + orgCi + dlnaflags ) . Trim ( ';' ) ;
}
2014-04-23 17:35:31 +02:00
private static string FlagsToString ( DlnaFlags flags )
{
//return Enum.Format(typeof(DlnaFlags), flags, "x");
return string . Format ( "{0:X8}{1:D24}" , ( ulong ) flags , 0 ) ;
}
2014-04-24 07:08:10 +02:00
public string BuildVideoHeader ( string container ,
string videoCodec ,
string audioCodec ,
int? width ,
int? height ,
int? bitDepth ,
int? videoBitrate ,
int? audioChannels ,
int? audioBitrate ,
TransportStreamTimestamp timestamp ,
bool isDirectStream ,
long? runtimeTicks ,
string videoProfile ,
double? videoLevel ,
double? videoFramerate ,
int? packetLength ,
2014-04-23 04:47:46 +02:00
TranscodeSeekInfo transcodeSeekInfo )
{
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
var orgOp = ";DLNA.ORG_OP=" + DlnaMaps . GetOrgOpValue ( runtimeTicks . HasValue , isDirectStream , transcodeSeekInfo ) ;
// 0 = native, 1 = transcoded
var orgCi = isDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1" ;
var flagValue = DlnaFlags . StreamingTransferMode |
DlnaFlags . BackgroundTransferMode |
DlnaFlags . DlnaV15 ;
if ( isDirectStream )
{
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_BYTE_BASED_SEEK;
}
else if ( runtimeTicks . HasValue )
{
//flagValue = flagValue | DlnaFlags.DLNA_ORG_FLAG_TIME_BASED_SEEK;
}
var dlnaflags = string . Format ( ";DLNA.ORG_FLAGS={0}000000000000000000000000" ,
Enum . Format ( typeof ( DlnaFlags ) , flagValue , "x" ) ) ;
2014-04-24 07:08:10 +02:00
var mediaProfile = _profile . GetVideoMediaProfile ( container ,
audioCodec ,
videoCodec ,
audioBitrate ,
audioChannels ,
width ,
height ,
bitDepth ,
videoBitrate ,
videoProfile ,
videoLevel ,
videoFramerate ,
packetLength ,
timestamp ) ;
2014-04-23 04:47:46 +02:00
var orgPn = mediaProfile = = null ? null : mediaProfile . OrgPn ;
2014-04-24 07:08:10 +02:00
2014-04-23 04:47:46 +02:00
if ( string . IsNullOrEmpty ( orgPn ) )
{
2014-04-24 07:08:10 +02:00
orgPn = GetVideoOrgPnValue ( container , videoCodec , audioCodec , width , height , timestamp )
. FirstOrDefault ( ) ;
// TODO: Support multiple values and return multiple headers?
orgPn = ( orgPn ? ? string . Empty ) . Split ( ',' ) . FirstOrDefault ( ) ;
2014-04-23 04:47:46 +02:00
}
var contentFeatures = string . IsNullOrEmpty ( orgPn ) ? string . Empty : "DLNA.ORG_PN=" + orgPn ;
return ( contentFeatures + orgOp + orgCi + dlnaflags ) . Trim ( ';' ) ;
}
2014-04-24 07:08:10 +02:00
private string GetImageOrgPnValue ( string container , int? width , int? height )
{
var format = new MediaFormatProfileResolver ( )
. ResolveImageFormat ( container ,
width ,
height ) ;
return format . HasValue ? format . Value . ToString ( ) : null ;
}
2014-04-23 04:47:46 +02:00
private string GetAudioOrgPnValue ( string container , int? audioBitrate , int? audioSampleRate , int? audioChannels )
{
var format = new MediaFormatProfileResolver ( )
. ResolveAudioFormat ( container ,
audioBitrate ,
audioSampleRate ,
audioChannels ) ;
return format . HasValue ? format . Value . ToString ( ) : null ;
}
2014-04-24 07:08:10 +02:00
private IEnumerable < string > GetVideoOrgPnValue ( string container , string videoCodec , string audioCodec , int? width , int? height , TransportStreamTimestamp timestamp )
2014-04-23 04:47:46 +02:00
{
2014-04-24 07:08:10 +02:00
return new MediaFormatProfileResolver ( )
2014-04-23 04:47:46 +02:00
. ResolveVideoFormat ( container ,
videoCodec ,
audioCodec ,
width ,
height ,
2014-04-24 07:08:10 +02:00
timestamp )
. Select ( i = > i . ToString ( ) ) ;
2014-04-23 04:47:46 +02:00
}
}
}