void UPnpCDSTv::AddItem( const UPnpCDSRequest *pRequest, const QString &sObjectId, UPnpCDSExtensionResults *pResults, bool bAddRef, MSqlQuery &query ) { int nChanid = query.value( 0).toInt(); QDateTime dtStartTime = query.value( 1).toDateTime(); QDateTime dtEndTime = query.value( 2).toDateTime(); QString sTitle = query.value( 3).toString(); QString sSubtitle = query.value( 4).toString(); QString sDescription = query.value( 5).toString(); QString sCategory = query.value( 6).toString(); QString sHostName = query.value( 7).toString(); QString sRecGroup = query.value( 8).toString(); uint64_t nFileSize = query.value( 9).toULongLong(); QString sBaseName = query.value(10).toString(); QDateTime dtProgStart = query.value(11).toDateTime(); QDateTime dtProgEnd = query.value(12).toDateTime(); QString sStorageGrp = query.value(13).toString(); // ---------------------------------------------------------------------- // Cache Host ip Address & Port // ---------------------------------------------------------------------- if (!m_mapBackendIp.contains( sHostName )) m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName); if (!m_mapBackendPort.contains( sHostName )) m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName); // ---------------------------------------------------------------------- // Build Support Strings // ---------------------------------------------------------------------- QString sName = sTitle + ": " + (sSubtitle.isEmpty() ? sDescription : sSubtitle); QString sURIBase = QString( "http://%1:%2/Myth/" ) .arg( m_mapBackendIp [ sHostName ] ) .arg( m_mapBackendPort[ sHostName ] ); QString sURIParams = QString( "?ChanId=%1&StartTime=%2" ) .arg( nChanid ) .arg( dtStartTime.toString(Qt::ISODate)); QString sId = QString( "RecTv/0/item%1") .arg( sURIParams ); CDSObject *pItem = CDSObject::CreateVideoItem( sId, sName, sObjectId ); pItem->m_bRestricted = false; pItem->m_bSearchable = true; pItem->m_sWriteStatus = "WRITABLE"; if ( bAddRef ) { QString sRefId = QString( "%1/0/item%2") .arg( m_sExtensionId ) .arg( sURIParams ); pItem->SetPropValue( "refID", sRefId ); } pItem->SetPropValue( "genre" , sCategory ); pItem->SetPropValue( "longDescription", sDescription ); pItem->SetPropValue( "description" , sSubtitle ); //pItem->SetPropValue( "producer" , ); //pItem->SetPropValue( "rating" , ); //pItem->SetPropValue( "actor" , ); //pItem->SetPropValue( "director" , ); //pItem->SetPropValue( "publisher" , ); //pItem->SetPropValue( "language" , ); //pItem->SetPropValue( "relation" , ); //pItem->SetPropValue( "region" , ); // ---------------------------------------------------------------------- // Needed for Microsoft Media Player Compatibility // (Won't display correct Title without them) // ---------------------------------------------------------------------- pItem->SetPropValue( "creator" , "[Unknown Author]" ); pItem->SetPropValue( "artist" , "[Unknown Author]" ); pItem->SetPropValue( "album" , "[Unknown Series]" ); pItem->SetPropValue( "actor" , "[Unknown Author]" ); pItem->SetPropValue( "date" , dtStartTime.toString(Qt::ISODate)); pResults->Add( pItem ); // ---------------------------------------------------------------------- // Add Video Resource Element based on File contents/extension (HTTP) // ---------------------------------------------------------------------- StorageGroup sg(sStorageGrp, sHostName); QString sFilePath = sg.FindRecordingFile(sBaseName); QString sMimeType; if ( QFile::exists(sFilePath) ) sMimeType = HTTPRequest::TestMimeType( sFilePath ); else sMimeType = HTTPRequest::TestMimeType( sBaseName ); // If we are dealing with Window Media Player 12 (i.e. Windows 7) // then fake the Mime type to place the recorded TV in the // recorded TV section. if (pRequest->m_eClient == CDS_ClientWMP && pRequest->m_nClientVersion >= 12.0) { sMimeType = "video/x-ms-dvr"; } // DLNA string below is temp fix for ps3 seeking. QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType ); QString sURI = QString( "%1GetRecording%2").arg( sURIBase ) .arg( sURIParams ); Resource *pRes = pItem->AddResource( sProtocol, sURI ); uint uiStart = dtProgStart.toTime_t(); uint uiEnd = dtProgEnd.toTime_t(); uint uiDur = uiEnd - uiStart; QString sDur; sDur.sprintf("%02d:%02d:%02d", (uiDur / 3600) % 24, (uiDur / 60) % 60, uiDur % 60); pRes->AddAttribute( "duration" , sDur ); pRes->AddAttribute( "size" , QString::number( nFileSize) ); /* // ---------------------------------------------------------------------- // Add Video Resource Element based on File extension (mythtv) // ---------------------------------------------------------------------- sProtocol = QString( "myth:*:%1:*" ).arg( sMimeType ); sURI = QString( "myth://%1/%2" ) .arg( m_mapBackendIp [ sHostName ] ) .arg( sBaseName ); pRes = pItem->AddResource( sProtocol, sURI ); pRes->AddAttribute( "duration" , sDur ); pRes->AddAttribute( "size" , QString::number( nFileSize) ); */ // ---------------------------------------------------------------------- // Add Preview URI as albumArt // ---------------------------------------------------------------------- sURI = QString( "%1GetPreviewImage%2%3").arg( sURIBase ) .arg( sURIParams ) .arg( "&Width=160" ); pItem->SetPropValue( "albumArtURI", sURI ); Property *pProp = pItem->GetProperty("albumArtURI"); if (pProp) { pProp->AddAttribute("dlna:profileID", "PNG_TN"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } }
void UPnpCDSMusic::AddItem( const UPnpCDSRequest *pRequest, const QString &sObjectId, UPnpCDSExtensionResults *pResults, bool bAddRef, MSqlQuery &query ) { QString sName; int nId = query.value( 0).toInt(); QString sArtist = query.value( 1).toString(); QString sAlbum = query.value( 2).toString(); QString sTitle = query.value( 3).toString(); QString sGenre = query.value( 4).toString(); int nYear = query.value( 5).toInt(); int nTrackNum = query.value( 6).toInt(); QString sDescription = query.value( 7).toString(); QString sFileName = query.value( 8).toString(); uint nLength = query.value( 9).toInt(); uint64_t nFileSize = (quint64)query.value(10).toULongLong(); #if 0 if ((nNodeIdx == 0) || (nNodeIdx == 1)) { sName = QString( "%1-%2:%3" ) .arg( sArtist) .arg( sAlbum ) .arg( sTitle ); } else #endif sName = sTitle; // ---------------------------------------------------------------------- // Cache Host ip Address & Port // ---------------------------------------------------------------------- #if 0 if (!m_mapBackendIp.contains( sHostName )) m_mapBackendIp[ sHostName ] = gCoreContext->GetSettingOnHost( "BackendServerIp", sHostName); if (!m_mapBackendPort.contains( sHostName )) m_mapBackendPort[ sHostName ] = gCoreContext->GetSettingOnHost("BackendStatusPort", sHostName); #endif QString sServerIp = gCoreContext->GetSetting( "BackendServerIp" ); QString sPort = gCoreContext->GetSetting( "BackendStatusPort" ); // ---------------------------------------------------------------------- // Build Support Strings // ---------------------------------------------------------------------- QString sURIBase = QString( "http://%1:%2/Content/" ) .arg( sServerIp ) .arg( sPort ); QString sURIParams = QString( "?Id=%1" ) .arg( nId ); QString sId = QString( "Music/1/item%1") .arg( sURIParams ); CDSObject *pItem = CDSObject::CreateMusicTrack( sId, sName, sObjectId ); pItem->m_bRestricted = true; pItem->m_bSearchable = true; pItem->m_sWriteStatus = "NOT_WRITABLE"; if ( bAddRef ) { QString sRefId = QString( "%1/0/item%2") .arg( m_sExtensionId ) .arg( sURIParams ); pItem->SetPropValue( "refID", sRefId ); } pItem->SetPropValue( "genre" , sGenre ); pItem->SetPropValue( "description" , sTitle ); pItem->SetPropValue( "longDescription" , sDescription); pItem->SetPropValue( "artist" , sArtist ); pItem->SetPropValue( "album" , sAlbum ); pItem->SetPropValue( "originalTrackNumber" , QString::number(nTrackNum)); if (nYear > 0 && nYear < 9999) pItem->SetPropValue( "date", QDate(nYear,1,1).toString(Qt::ISODate)); #if 0 pObject->AddProperty( new Property( "publisher" , "dc" )); pObject->AddProperty( new Property( "language" , "dc" )); pObject->AddProperty( new Property( "relation" , "dc" )); pObject->AddProperty( new Property( "rights" , "dc" )); pObject->AddProperty( new Property( "playlist" , "upnp" )); pObject->AddProperty( new Property( "storageMedium" , "upnp" )); pObject->AddProperty( new Property( "contributor" , "dc" )); pObject->AddProperty( new Property( "date" , "dc" )); #endif QString sArtURI = QString( "%1GetAlbumArt?Id=%2").arg( sURIBase ) .arg( nId ); QList<Property*> propList = pItem->GetProperties("albumArtURI"); if (propList.size() >= 4) { // Prefer JPEG over PNG here, although PNG is allowed JPEG probably // has wider device support and crucially the filesizes are smaller // which speeds up loading times over the network // We MUST include the thumbnail size, but since some clients may use the // first image they see and the thumbnail is tiny, instead return the // medium first. The large could be very large, which is no good if the // client is pulling images for an entire list at once! // Medium Property *pProp = propList.at(0); if (pProp) { // Must be no more than 1024x768 pProp->m_sValue = sArtURI; pProp->m_sValue.append("&Width=1024&Height=768"); pProp->AddAttribute("dlna:profileID", "JPG_MED"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Thumbnail pProp = propList.at(1); if (pProp) { // At least one albumArtURI must be a ThumbNail (TN) no larger // than 160x160, and it must also be a jpeg pProp->m_sValue = sArtURI; pProp->m_sValue.append("&Width=160&Height=160"); pProp->AddAttribute("dlna:profileID", "JPG_TN"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Small pProp = propList.at(2); if (pProp) { // Must be no more than 640x480 pProp->m_sValue = sArtURI; pProp->m_sValue.append("&Width=640&Height=480"); pProp->AddAttribute("dlna:profileID", "JPG_SM"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Large pProp = propList.at(3); if (pProp) { // Must be no more than 4096x4096 - for our purposes, just return // a fullsize image pProp->m_sValue = sArtURI; pProp->AddAttribute("dlna:profileID", "JPG_LRG"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } } pResults->Add( pItem ); // ---------------------------------------------------------------------- // Add Music Resource Element based on File extension (HTTP) // ---------------------------------------------------------------------- QFileInfo fInfo( sFileName ); QString sMimeType = HTTPRequest::GetMimeType( fInfo.suffix() ); QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType ); QString sURI = QString( "%1GetMusic%2").arg( sURIBase ) .arg( sURIParams ); Resource *pRes = pItem->AddResource( sProtocol, sURI ); nLength /= 1000; QString sDur; sDur.sprintf("%02d:%02d:%02d", (nLength / 3600) % 24, (nLength / 60) % 60, nLength % 60); pRes->AddAttribute( "duration" , sDur ); if (nFileSize > 0) pRes->AddAttribute( "size" , QString::number( nFileSize) ); }
void UPnpCDSVideo::PopulateArtworkURIS(CDSObject* pItem, int nVidID, const QUrl& URIBase) { QUrl artURI = URIBase; artURI.setPath("/Content/GetVideoArtwork"); QUrlQuery artQuery; artQuery.addQueryItem("Id", QString::number(nVidID)); artURI.setQuery(artQuery); // Prefer JPEG over PNG here, although PNG is allowed JPEG probably // has wider device support and crucially the filesizes are smaller // which speeds up loading times over the network // We MUST include the thumbnail size, but since some clients may use the // first image they see and the thumbnail is tiny, instead return the // medium first. The large could be very large, which is no good if the // client is pulling images for an entire list at once! // Thumbnail // At least one albumArtURI must be a ThumbNail (TN) no larger // than 160x160, and it must also be a jpeg QUrl thumbURI = artURI; QUrlQuery thumbQuery(thumbURI.query()); if (pItem->m_sClass == "object.item.videoItem") // Show screenshot for TV, coverart for movies thumbQuery.addQueryItem("Type", "screenshot"); else thumbQuery.addQueryItem("Type", "coverart"); thumbQuery.addQueryItem("Width", "160"); thumbQuery.addQueryItem("Height", "160"); thumbURI.setQuery(thumbQuery); // Small // Must be no more than 640x480 QUrl smallURI = artURI; QUrlQuery smallQuery(smallURI.query()); smallQuery.addQueryItem("Type", "coverart"); smallQuery.addQueryItem("Width", "640"); smallQuery.addQueryItem("Height", "480"); smallURI.setQuery(smallQuery); // Medium // Must be no more than 1024x768 QUrl mediumURI = artURI; QUrlQuery mediumQuery(mediumURI.query()); mediumQuery.addQueryItem("Type", "coverart"); mediumQuery.addQueryItem("Width", "1024"); mediumQuery.addQueryItem("Height", "768"); mediumURI.setQuery(mediumQuery); // Large // Must be no more than 4096x4096 - for our purposes, just return // a fullsize image QUrl largeURI = artURI; QUrlQuery largeQuery(largeURI.query()); largeQuery.addQueryItem("Type", "fanart"); largeURI.setQuery(largeQuery); QList<Property*> propList = pItem->GetProperties("albumArtURI"); if (propList.size() >= 4) { Property *pProp = propList.at(0); if (pProp) { pProp->SetValue(mediumURI.toEncoded()); pProp->AddAttribute("dlna:profileID", "JPEG_MED"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } pProp = propList.at(1); if (pProp) { pProp->SetValue(thumbURI.toEncoded()); pProp->AddAttribute("dlna:profileID", "JPEG_TN"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } pProp = propList.at(2); if (pProp) { pProp->SetValue(smallURI.toEncoded()); pProp->AddAttribute("dlna:profileID", "JPEG_SM"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } pProp = propList.at(3); if (pProp) { pProp->SetValue(largeURI.toEncoded()); pProp->AddAttribute("dlna:profileID", "JPEG_LRG"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } } if (pItem->m_sClass.startsWith("object.item.videoItem")) { QString sProtocol; sProtocol = DLNA::ProtocolInfoString(UPNPProtocol::kHTTP, "image/jpeg", QSize(1024, 768)); pItem->AddResource( sProtocol, mediumURI.toEncoded()); sProtocol = DLNA::ProtocolInfoString(UPNPProtocol::kHTTP, "image/jpeg", QSize(160, 160)); pItem->AddResource( sProtocol, thumbURI.toEncoded()); sProtocol = DLNA::ProtocolInfoString(UPNPProtocol::kHTTP, "image/jpeg", QSize(640, 480)); pItem->AddResource( sProtocol, smallURI.toEncoded()); sProtocol = DLNA::ProtocolInfoString(UPNPProtocol::kHTTP, "image/jpeg", QSize(1920, 1080)); // Not the actual res, we don't know that pItem->AddResource( sProtocol, largeURI.toEncoded()); } }
void UPnpCDSTv::AddItem( const UPnpCDSRequest *pRequest, const QString &sObjectId, UPnpCDSExtensionResults *pResults, bool bAddRef, MSqlQuery &query ) { int nChanid = query.value( 0).toInt(); QDateTime dtStartTime = MythDate::as_utc(query.value(1).toDateTime()); QDateTime dtEndTime = MythDate::as_utc(query.value(2).toDateTime()); QString sTitle = query.value( 3).toString(); QString sSubtitle = query.value( 4).toString(); QString sDescription = query.value( 5).toString(); QString sCategory = query.value( 6).toString(); QString sHostName = query.value( 7).toString(); QString sRecGroup = query.value( 8).toString(); uint64_t nFileSize = query.value( 9).toULongLong(); QString sBaseName = query.value(10).toString(); QDateTime dtProgStart = MythDate::as_utc(query.value(11).toDateTime()); QDateTime dtProgEnd = MythDate::as_utc(query.value(12).toDateTime()); QString sStorageGrp = query.value(13).toString(); QString sInetRef = query.value(14).toString(); // ---------------------------------------------------------------------- // Cache Host ip Address & Port // ---------------------------------------------------------------------- if (!m_mapBackendIp.contains( sHostName )) m_mapBackendIp[ sHostName ] = gCoreContext->GetBackendServerIP4(sHostName); if (!m_mapBackendPort.contains( sHostName )) m_mapBackendPort[ sHostName ] = gCoreContext->GetBackendStatusPort(sHostName); // ---------------------------------------------------------------------- // Build Support Strings // ---------------------------------------------------------------------- QString sName = sTitle + ": " + (sSubtitle.isEmpty() ? sDescription.left(128) : sSubtitle); QString sURIBase = QString( "http://%1:%2/Content/" ) .arg( m_mapBackendIp [ sHostName ] ) .arg( m_mapBackendPort[ sHostName ] ); QString sURIParams = QString( "?ChanId=%1&StartTime=%2" ) .arg( nChanid ) .arg( dtStartTime.toString(Qt::ISODate)); QString sId = QString( "RecTv/0/item%1") .arg( sURIParams ); CDSObject *pItem = CDSObject::CreateVideoItem( sId, sName, sObjectId ); pItem->m_bRestricted = false; pItem->m_bSearchable = true; pItem->m_sWriteStatus = "WRITABLE"; if ( bAddRef ) { QString sRefId = QString( "%1/0/item%2") .arg( m_sExtensionId ) .arg( sURIParams ); pItem->SetPropValue( "refID", sRefId ); } pItem->SetPropValue( "genre" , sCategory ); pItem->SetPropValue( "longDescription", sDescription ); pItem->SetPropValue( "description" , sSubtitle ); //pItem->SetPropValue( "producer" , ); //pItem->SetPropValue( "rating" , ); //pItem->SetPropValue( "actor" , ); //pItem->SetPropValue( "director" , ); //pItem->SetPropValue( "publisher" , ); //pItem->SetPropValue( "language" , ); //pItem->SetPropValue( "relation" , ); //pItem->SetPropValue( "region" , ); // ---------------------------------------------------------------------- // Needed for Microsoft Media Player Compatibility // (Won't display correct Title without them) // ---------------------------------------------------------------------- pItem->SetPropValue( "creator" , "[Unknown Author]" ); pItem->SetPropValue( "artist" , "[Unknown Author]" ); pItem->SetPropValue( "album" , "[Unknown Series]" ); pItem->SetPropValue( "actor" , "[Unknown Author]" ); pItem->SetPropValue( "date" , dtStartTime.toString(Qt::ISODate)); pResults->Add( pItem ); // ---------------------------------------------------------------------- // Add Video Resource Element based on File contents/extension (HTTP) // ---------------------------------------------------------------------- StorageGroup sg(sStorageGrp, sHostName); QString sFilePath = sg.FindFile(sBaseName); QString sMimeType; if ( QFile::exists(sFilePath) ) sMimeType = HTTPRequest::TestMimeType( sFilePath ); else sMimeType = HTTPRequest::TestMimeType( sBaseName ); // If we are dealing with Window Media Player 12 (i.e. Windows 7) // then fake the Mime type to place the recorded TV in the // recorded TV section. if (pRequest->m_eClient == CDS_ClientWMP && pRequest->m_nClientVersion >= 12.0) { sMimeType = "video/x-ms-dvr"; } // If we are dealing with a Sony Blu-ray player then we fake the // MIME type to force the video to appear if ( pRequest->m_eClient == CDS_ClientSonyDB ) { sMimeType = "video/avi"; } // DLNA string below is temp fix for ps3 seeking. QString sProtocol = QString( "http-get:*:%1:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000" ).arg( sMimeType ); QString sURI = QString( "%1GetRecording%2").arg( sURIBase ) .arg( sURIParams ); // Sony BDPS370 requires a DLNA Profile Name // FIXME: detection to determine the correct DLNA Profile Name if (sMimeType == "video/mpeg") { sProtocol += ";DLNA.ORG_PN=MPEG_TS_SD_NA_ISO"; } Resource *pRes = pItem->AddResource( sProtocol, sURI ); uint uiStart = dtProgStart.toTime_t(); uint uiEnd = dtProgEnd.toTime_t(); uint uiDur = uiEnd - uiStart; MSqlQuery query2(MSqlQuery::InitCon()); query2.prepare( "SELECT data FROM recordedmarkup WHERE chanid=:CHANID AND " "starttime=:STARTTIME AND type = 33" ); query2.bindValue(":CHANID", (int)nChanid); query2.bindValue(":STARTTIME", dtStartTime); if (query2.exec() && query2.next()) uiDur = query2.value(0).toUInt() / 1000; QString sDur; sDur.sprintf("%02d:%02d:%02d", (uiDur / 3600) % 24, (uiDur / 60) % 60, uiDur % 60); LOG(VB_UPNP, LOG_DEBUG, "Duration: " + sDur ); pRes->AddAttribute( "duration" , sDur ); pRes->AddAttribute( "size" , QString::number( nFileSize) ); /* // ---------------------------------------------------------------------- // Add Video Resource Element based on File extension (mythtv) // ---------------------------------------------------------------------- sProtocol = QString( "myth:*:%1:*" ).arg( sMimeType ); sURI = QString( "myth://%1/%2" ) .arg( m_mapBackendIp [ sHostName ] ) .arg( sBaseName ); pRes = pItem->AddResource( sProtocol, sURI ); pRes->AddAttribute( "duration" , sDur ); pRes->AddAttribute( "size" , QString::number( nFileSize) ); */ // ---------------------------------------------------------------------- // Add Preview URI as <res> // MUST be _TN and 160px // ---------------------------------------------------------------------- sURI = QString( "%1GetPreviewImage%2%3").arg( sURIBase ) .arg( sURIParams ) .arg( "&Width=160" ); // TODO: Must be JPG for minimal compliance sProtocol = QString( "http-get:*:image/png:DLNA.ORG_PN=PNG_TN"); pItem->AddResource( sProtocol, sURI ); // ---------------------------------------------------------------------- // Add Artwork URI as albumArt // ---------------------------------------------------------------------- sURI = QString( "%1GetRecordingArtwork?Type=coverart&Inetref=%3") .arg( sURIBase ) .arg( sInetRef ); QList<Property*> propList = pItem->GetProperties("albumArtURI"); if (propList.size() >= 4) { // Prefer JPEG over PNG here, although PNG is allowed JPEG probably // has wider device support and crucially the filesizes are smaller // which speeds up loading times over the network // We MUST include the thumbnail size, but since some clients may use the // first image they see and the thumbnail is tiny, instead return the // medium first. The large could be very large, which is no good if the // client is pulling images for an entire list at once! // Medium Property *pProp = propList.at(0); if (pProp) { // Must be no more than 1024x768 pProp->m_sValue = sURI; pProp->m_sValue.append("&Width=1024&Height=768"); pProp->AddAttribute("dlna:profileID", "JPG_MED"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Thumbnail pProp = propList.at(1); if (pProp) { // At least one albumArtURI must be a ThumbNail (TN) no larger // than 160x160, and it must also be a jpeg pProp->m_sValue = sURI; pProp->m_sValue.append("&Width=160&Height=160"); pProp->AddAttribute("dlna:profileID", "JPG_TN"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Medium pProp = propList.at(2); if (pProp) { // Must be no more than 1024x768 pProp->m_sValue = sURI; pProp->m_sValue.append("&Width=1024&Height=768"); pProp->AddAttribute("dlna:profileID", "JPG_MED"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } // Large pProp = propList.at(3); if (pProp) { // Must be no more than 4096x4096 - for our purposes, just return // a fullsize image pProp->m_sValue = sURI; pProp->AddAttribute("dlna:profileID", "JPG_LRG"); pProp->AddAttribute("xmlns:dlna", "urn:schemas-dlna-org:metadata-1-0"); } } }