summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormethodus <methodus@web.de>2012-09-29 22:48:30 +0200
committermethodus <methodus@web.de>2012-09-29 22:48:30 +0200
commit97b083ac833ada3c18a5639ee782e575ca583acf (patch)
tree257848635d775396e86f9aeab682b2a719d2d097
parent4cd5debf236f4d4315cce30c4cd11e392f00886a (diff)
downloadvdr-plugin-upnp-97b083ac833ada3c18a5639ee782e575ca583acf.tar.gz
vdr-plugin-upnp-97b083ac833ada3c18a5639ee782e575ca583acf.tar.bz2
Streamer almost completed. First tests successful. However, there are no plugins, yet.
-rw-r--r--Makefile3
-rw-r--r--common/tools.cpp4
-rw-r--r--include/media/mediaManager.h11
-rw-r--r--include/plugin.h14
-rw-r--r--include/pluginManager.h11
-rw-r--r--include/tools.h2
-rw-r--r--media/mediaManager.cpp116
-rw-r--r--media/pluginManager.cpp4
-rw-r--r--server/webserver.cpp9
9 files changed, 128 insertions, 46 deletions
diff --git a/Makefile b/Makefile
index f8fc21e..2b14a5b 100644
--- a/Makefile
+++ b/Makefile
@@ -54,7 +54,8 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
TNTOBJ = httptnt/deviceDescription.o \
httptnt/cds_scpd.o \
- httptnt/cms_scpd.o
+ httptnt/cms_scpd.o \
+ httptnt/resourceStreamer.o
OBJS = $(PLUGIN).o \
server/server.o \
diff --git a/common/tools.cpp b/common/tools.cpp
index d64b86b..61220c6 100644
--- a/common/tools.cpp
+++ b/common/tools.cpp
@@ -137,8 +137,8 @@ string GenerateUUIDRandomly(){
return uuid.str();
}
-void StringExplode(string str, string separator, StringVector results) {
- int found;
+void StringExplode(string str, string separator, StringVector& results) {
+ string::size_type found;
found = str.find_first_of(separator);
while(found != string::npos){
if(found > 0){
diff --git a/include/media/mediaManager.h b/include/media/mediaManager.h
index 7e97799..09b3919 100644
--- a/include/media/mediaManager.h
+++ b/include/media/mediaManager.h
@@ -14,6 +14,7 @@
#include <stdint.h>
#include <tntdb/connection.h>
#include <tntdb/connect.h>
+#include "../../include/plugin.h"
#include "../../include/tools.h"
namespace upnp {
@@ -32,12 +33,12 @@ private:
cResourceStreamer(cMediaManager* manager, cUPnPResourceProvider* provider, cMetadata::Resource* resource);
public:
+ virtual ~cResourceStreamer();
std::string GetContentFeatures() const;
size_t GetContentLength() const;
std::string GetContentType() const;
std::string GetTransferMode(const std::string& requestedMode ) const;
- std::string GetRange() const;
- std::string GetAvailableSeekRange(const std::string& seekRequest) const;
+ bool Seekable() const;
bool Open(string uri);
size_t Read(char* buf, size_t bufLen);
@@ -92,9 +93,9 @@ public:
int Browse(BrowseRequest& request);
int Search(SearchRequest& request);
- static BrowseFlag ToBrowseFlag(std::string browseFlag);
+ static BrowseFlag ToBrowseFlag(const std::string& browseFlag);
- cResourceStreamer* GetResourceStreamer(std::string objectID);
+ cResourceStreamer* GetResourceStreamer(const std::string& objectID, int resourceID = 0);
private:
@@ -105,6 +106,8 @@ private:
void OnContainerUpdate(string uri, long updateID);
+ cUPnPResourceProvider* CreateResourceProvider(const std::string& uri);
+
uint32_t mSystemUpdateID;
IdList mEventedContainerUpdateIDs;
StringList mScanDirectories;
diff --git a/include/plugin.h b/include/plugin.h
index fe2c5f6..da68ba9 100644
--- a/include/plugin.h
+++ b/include/plugin.h
@@ -348,6 +348,8 @@ public:
*/
virtual string GetHTTPUri(string uri);
+ virtual bool Seekable() const;
+
/**
* Opens a resource
*
@@ -480,13 +482,9 @@ public:
* object which contains all information about the resource.
*
* If the plugin is not able to fill the required information about the resource,
- * it MUST return NULL. The plugin manager will then rotate through all the
+ * it MUST return false. The plugin manager will then rotate through all the
* registered plugins until it finds a suitable one.
*
- * The required information MUST be set in the cMediaResource::Create function
- * correctly. Otherwise the object creation might fail and a NULL pointer will
- * be returned.
- *
* Additionally, a plugin implementor is advised to add as many as possible
* metadata about a resource. Especially, information about the contents might
* help the user.
@@ -500,9 +498,11 @@ public:
* A change of a resource is indicated by the resource provider.
*
* @param uri the absolute path to the resource.
- * @return the media resource information.
+ * @param metadata the metadate object, where the information shall be saved.
+ * @return true, if this profiler was able to get the specific metadata,
+ * false, if not.
*/
- virtual cMetadata GetMetadata(string uri) = 0;
+ virtual bool GetMetadata(string uri, cMetadata& metadata) = 0;
protected:
};
diff --git a/include/pluginManager.h b/include/pluginManager.h
index 90ee456..215f224 100644
--- a/include/pluginManager.h
+++ b/include/pluginManager.h
@@ -8,11 +8,22 @@
#ifndef PLUGINMANAGER_H_
#define PLUGINMANAGER_H_
+#include "../include/plugin.h"
+
namespace upnp {
class cPluginManager {
public:
+ cUPnPResourceProvider* CreateResourceProviderInstance(const std::string& schema);
private:
+ void LoadPlugins();
+ void UnloadPlugins();
+
+ typedef std::list<cUPnPResourceProvider> ProviderList;
+ typedef std::list<cMediaProfiler> ProfilerList;
+
+ ProviderList providers;
+ ProfilerList profilers;
};
} // namespace upnp
diff --git a/include/tools.h b/include/tools.h
index 008b74a..cf34b42 100644
--- a/include/tools.h
+++ b/include/tools.h
@@ -122,7 +122,7 @@ namespace tools {
string GenerateUUIDFromURL(string url);
string GenerateUUIDRandomly();
- void StringExplode(string str, string separator, StringVector results);
+ void StringExplode(string str, string separator, StringVector& results);
}
namespace ixml {
diff --git a/media/mediaManager.cpp b/media/mediaManager.cpp
index 33fafbd..b6de322 100644
--- a/media/mediaManager.cpp
+++ b/media/mediaManager.cpp
@@ -15,6 +15,7 @@
#include <tntdb/statement.h>
#include <tntdb/result.h>
#include <upnp/ixml.h>
+#include <memory>
namespace upnp {
@@ -38,19 +39,24 @@ cResourceStreamer::cResourceStreamer(cMediaManager* manager, cUPnPResourceProvid
, manager(manager)
{
if(resource)
- tools::StringExplode(resource->protocolInfo,"*",protocolInfo);
+ tools::StringExplode(resource->GetProtocolInfo(),":",protocolInfo);
+}
+
+cResourceStreamer::~cResourceStreamer(){
+ delete resource;
+ delete provider;
}
std::string cResourceStreamer::GetContentFeatures() const {
if(resource == NULL) return string();
- return protocolInfo[3];
+ return protocolInfo.size() == 4 ? protocolInfo[3] : string();
}
std::string cResourceStreamer::GetContentType() const {
if(resource == NULL) return string();
- return protocolInfo[2];
+ return protocolInfo.size() == 4 ? protocolInfo[2] : string();
}
size_t cResourceStreamer::GetContentLength() const {
@@ -68,28 +74,28 @@ std::string cResourceStreamer::GetTransferMode(const string&) const {
else return "Interactive";
}
-std::string cResourceStreamer::GetRange() const {
- return string();
-}
-
-std::string cResourceStreamer::GetAvailableSeekRange(const string& seekRequest) const {
- return string();
+bool cResourceStreamer::Seekable() const {
+ if(!provider) return false;
+ return provider->Seekable();
}
bool cResourceStreamer::Open(string uri){
+ if(!provider) return false;
return provider->Open(uri);
}
size_t cResourceStreamer::Read(char* buf, size_t bufLen){
+ if(!provider) return 0;
return provider->Read(buf, bufLen);
}
bool cResourceStreamer::Seek(size_t offset, int origin){
+ if(!provider) return false;
return provider->Seek(offset, origin);
}
void cResourceStreamer::Close(){
- provider->Close();
+ if(provider) provider->Close();
}
@@ -216,6 +222,7 @@ int cMediaManager::CreateResponse(MediaRequest& request, const string& select, c
bool isContainer;
+
if(upnpClass.find("object.item",0) == 0){
object = ixmlDocument_createElement(DIDLDoc, "item");
isContainer = false;
@@ -257,20 +264,24 @@ int cMediaManager::CreateResponse(MediaRequest& request, const string& select, c
for(tntdb::Statement::const_iterator it2 = select2.begin(); it2 != select2.end(); ++it2){
row2 = (*it2);
- string resourceURI = row2.getString(property::resource::KEY_RESOURCE);
+ std::auto_ptr<cUPnPResourceProvider> provider(CreateResourceProvider(row2.getString(property::resource::KEY_RESOURCE)));
+
+ if(provider.get()){
+ string resourceURI = provider->GetHTTPUri(row2.getString(property::resource::KEY_RESOURCE));
- IXML_Element* resource = ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_RESOURCE, resourceURI);
+ IXML_Element* resource = ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_RESOURCE, resourceURI);
- if(resource){
- ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_PROTOCOL_INFO, row2.getString(property::resource::KEY_PROTOCOL_INFO));
- ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_BITRATE, row2.getString(property::resource::KEY_BITRATE));
- ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_BITS_PER_SAMPLE, row2.getString(property::resource::KEY_BITS_PER_SAMPLE));
- ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_COLOR_DEPTH, row2.getString(property::resource::KEY_COLOR_DEPTH));
- ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_DURATION, row2.getString(property::resource::KEY_DURATION));
- ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_NR_AUDIO_CHANNELS, row2.getString(property::resource::KEY_NR_AUDIO_CHANNELS));
- ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_RESOLUTION, row2.getString(property::resource::KEY_RESOLUTION));
- ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_SAMPLE_FREQUENCY, row2.getString(property::resource::KEY_SAMPLE_FREQUENCY));
- ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_SIZE, tools::ToString(row2.getInt64(property::resource::KEY_SIZE)));
+ if(resource){
+ ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_PROTOCOL_INFO, row2.getString(property::resource::KEY_PROTOCOL_INFO));
+ ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_BITRATE, row2.getString(property::resource::KEY_BITRATE));
+ ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_BITS_PER_SAMPLE, row2.getString(property::resource::KEY_BITS_PER_SAMPLE));
+ ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_COLOR_DEPTH, row2.getString(property::resource::KEY_COLOR_DEPTH));
+ ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_DURATION, row2.getString(property::resource::KEY_DURATION));
+ ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_NR_AUDIO_CHANNELS, row2.getString(property::resource::KEY_NR_AUDIO_CHANNELS));
+ ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_RESOLUTION, row2.getString(property::resource::KEY_RESOLUTION));
+ ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_SAMPLE_FREQUENCY, row2.getString(property::resource::KEY_SAMPLE_FREQUENCY));
+ ixml::IxmlAddFilteredProperty(filterList, DIDLDoc, object, property::resource::KEY_SIZE, tools::ToString(row2.getInt64(property::resource::KEY_SIZE)));
+ }
}
}
@@ -366,7 +377,7 @@ int cMediaManager::Search(SearchRequest& request){
return (request.totalMatches == 0 && request.numberReturned == 0) ? UPNP_CDS_E_CANT_PROCESS_REQUEST : UPNP_E_SUCCESS;
}
-cMediaManager::BrowseFlag cMediaManager::ToBrowseFlag(std::string browseFlag) {
+cMediaManager::BrowseFlag cMediaManager::ToBrowseFlag(const std::string& browseFlag) {
if (browseFlag.compare("BrowseMetadata") == 0)
return CD_BROWSE_METADATA;
else if (browseFlag.compare("BrowseDirectChildren") == 0)
@@ -528,6 +539,65 @@ bool cMediaManager::CheckIntegrity(){
return true;
}
+cResourceStreamer* cMediaManager::GetResourceStreamer(const string& objectID, int resourceID){
+ dsyslog("UPnP\tTry to stream resource[%d] of objectID %s", resourceID, objectID.c_str());
+
+ stringstream resourceSQL;
+
+ resourceSQL << "SELECT * FROM " << db::Resources << " WHERE "
+ << "`" << property::object::KEY_OBJECTID << "` = "
+ << ":objectID"
+ << " ORDER BY resourceID ASC LIMIT " << resourceID << ",1";
+
+ tntdb::Statement select = mConnection.prepare(resourceSQL.str());
+
+ tntdb::Result result = select.setString("objectID", objectID)
+ .select();
+
+ if(result.size() == 0) return NULL;
+
+ tntdb::Row row = result.getRow(0);
+
+ cMetadata::Resource* resource = new cMetadata::Resource();
+
+ bool ret = true;
+ if(!row.isNull(property::resource::KEY_BITRATE))
+ ret = resource->SetBitrate(row.getInt32(property::resource::KEY_BITRATE));
+ if(!row.isNull(property::resource::KEY_BITS_PER_SAMPLE))
+ ret = resource->SetBitsPerSample(row.getInt32(property::resource::KEY_BITS_PER_SAMPLE));
+ if(!row.isNull(property::resource::KEY_COLOR_DEPTH))
+ ret = resource->SetColorDepth(row.getInt32(property::resource::KEY_COLOR_DEPTH));
+ if(!row.isNull(property::resource::KEY_DURATION))
+ ret = resource->SetDuration(row.getString(property::resource::KEY_DURATION));
+ if(!row.isNull(property::resource::KEY_NR_AUDIO_CHANNELS))
+ ret = resource->SetNrAudioChannels(row.getInt32(property::resource::KEY_NR_AUDIO_CHANNELS));
+ if(!row.isNull(property::resource::KEY_PROTOCOL_INFO))
+ ret = resource->SetProtocolInfo(row.getString(property::resource::KEY_PROTOCOL_INFO));
+ if(!row.isNull(property::resource::KEY_RESOLUTION))
+ ret = resource->SetResolution(row.getString(property::resource::KEY_RESOLUTION));
+ if(!row.isNull(property::resource::KEY_RESOURCE))
+ ret = resource->SetResourceUri(row.getString(property::resource::KEY_RESOURCE));
+ if(!row.isNull(property::resource::KEY_SAMPLE_FREQUENCY))
+ ret = resource->SetSampleFrequency(row.getInt32(property::resource::KEY_SAMPLE_FREQUENCY));
+ if(!row.isNull(property::resource::KEY_SIZE))
+ ret = resource->SetSize(row.getInt32(property::resource::KEY_SIZE));
+
+ if(!ret) {
+ delete resource;
+ return NULL;
+ }
+
+ cUPnPResourceProvider* provider = CreateResourceProvider(resource->GetResourceUri());
+
+ cResourceStreamer* streamer = new cResourceStreamer(this, provider, resource);
+
+ return streamer;
+}
+
+cUPnPResourceProvider* cMediaManager::CreateResourceProvider(const string& uri){
+ return NULL;
+}
+
void cMediaManager::SetDatabaseFile(string file){
if(file.empty()) mDatabaseFile = "metadata.db";
else mDatabaseFile = file;
diff --git a/media/pluginManager.cpp b/media/pluginManager.cpp
index a9bfd73..a3f9c75 100644
--- a/media/pluginManager.cpp
+++ b/media/pluginManager.cpp
@@ -233,6 +233,10 @@ string cUPnPResourceProvider::GetHTTPUri(string uri){
return string();
}
+bool cUPnPResourceProvider::Seekable() const {
+ return false;
+}
+
bool cUPnPResourceProvider::Open(string uri){
return false;
}
diff --git a/server/webserver.cpp b/server/webserver.cpp
index d2a25f0..f1b589b 100644
--- a/server/webserver.cpp
+++ b/server/webserver.cpp
@@ -66,14 +66,7 @@ bool cWebserver::Initialise(){
mApplication.mapUrl(ss1.str(), ss2.str(), "static@tntnet");
- // Map static contents
- ss1.clear(); ss1.str(string());
- ss1 << "^/" << mServiceUrl << "([^/.]+)";
-
- ss2.clear(); ss2.str(string());
- ss2 << mServiceUrl << "$1";
-
- mApplication.mapUrl(ss1.str(), ss2.str(), "serviceRedirect");
+ mApplication.mapUrl("^/getStream", "resourceStreamer");
isyslog("UPnP\tUsing %s for static content delivery.", mWebserverRootDir.c_str());