From f0a303ac20552dc96f046161bc1ad6dc84118ec8 Mon Sep 17 00:00:00 2001 From: "T. Lohmar" Date: Fri, 9 Jan 2015 18:55:21 +0100 Subject: Support for MP4 Metadata added (media folder). --- Makefile | 2 +- httpresource.c | 6 ++++ responsememblk.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++---- responsememblk.h | 16 +++++++-- smarttvfactory.h | 6 ++-- 5 files changed, 117 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index f80b96c..4529f06 100755 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' ### The object files (add further files here): -OBJS = $(PLUGIN).o smarttvfactory.o httpresource.o httpclient.o mngurls.o log.o url.o stvw_cfg.o responsebase.o responsefile.o responsevdrdir.o responsememblk.o responselive.o httpresource_base.o +OBJS = $(PLUGIN).o smarttvfactory.o httpresource.o httpclient.o mngurls.o log.o url.o stvw_cfg.o responsebase.o responsefile.o responsevdrdir.o responsememblk.o responselive.o httpresource_base.o mp4.o ### The main target: diff --git a/httpresource.c b/httpresource.c index f273f6a..b6f6d06 100755 --- a/httpresource.c +++ b/httpresource.c @@ -426,6 +426,12 @@ int cHttpResource::processRequest() { return OKAY; } + if (mPath.compare("/mp4covr") == 0) { + mResponse = new cResponseMemBlk(this); + ((cResponseMemBlk*)mResponse)->sendMp4Covr(); + return OKAY; + } + if (mPath.compare("/widget.conf") == 0) { mPath = mFactory->getConfigDir() + "/widget.conf"; diff --git a/responsememblk.c b/responsememblk.c index 26dd7fa..ba36aa5 100755 --- a/responsememblk.c +++ b/responsememblk.c @@ -25,6 +25,8 @@ #include "url.h" #include "smarttvfactory.h" +#include "mp4.h" + #include #include @@ -433,6 +435,65 @@ int cResponseMemBlk::sendResumeXml () { return OKAY; } +int cResponseMemBlk::sendMp4Covr() { + if (isHeadRequest()) + return OKAY; +#ifndef STANDALONE + mResponseMessage = new string(); + *mResponseMessage = ""; + mResponseMessagePos = 0; + + mRequest->mConnState = SERVING; + + char f[400]; + + cResumeEntry entry; + string id; + vector avps; + mRequest->parseQueryLine(&avps); + string guid; + + if (mRequest->getQueryAttributeValue(&avps, "guid", guid) == OKAY){ + entry.mFilename = cUrlEncode::doUrlSaveDecode(guid); + *(mLog->log() )<< DEBUGPREFIX + << " Found guid: " << guid + << " filename: " << entry.mFilename + << endl; + } + + if (guid == "") { + *(mLog->log())<< DEBUGPREFIX + << " ERROR in sendMp4Covr: GUID is required= " << endl; + sendError(400, "Bad Request", NULL, "002 No guid in query line"); + return OKAY; + } + + struct stat statbuf; + + if (stat(guid.c_str(), &statbuf) < 0) { + // error + *(mLog->log() )<< DEBUGPREFIX << " Not found Error" << endl; + + sendError(404, "Not Found", NULL, "003 File not found."); + return OKAY; + } + + cMp4Metadata meta(guid, statbuf.st_size); + meta.parseMetadata(); + + if (! meta.mHaveCovrPos) { + // error + sendError(400, "Bad Request", NULL, "023 No covr image within the file."); + return OKAY; + } + + *mResponseMessage = string(meta.mCovr, meta.mCovrSize) ; + // read bytestream + sendHeaders(200, "OK", NULL, "image/png", mResponseMessage->size(), -1); + +#endif + return OKAY; +} int cResponseMemBlk::sendMarksXml () { if (isHeadRequest()) @@ -480,7 +541,7 @@ int cResponseMemBlk::sendMarksXml () { if (marks.Count() == 0) { *(mLog->log())<< DEBUGPREFIX << " sendMark: No Mark Found " << endl; - sendError(400, "Bad Request", NULL, "0xx No Mark Found."); + sendError(400, "Bad Request", NULL, "022 No Mark Found."); return OKAY; } @@ -1739,13 +1800,30 @@ int cResponseMemBlk::parseFiles(vector *entries, string prefix, stri entries->push_back(sFileEntry(dir_name, pathbuf, start, "video/mpeg")); } else { - // regular file + // regular folder parseFiles(entries, prefix + de->d_name + "~", dir_comp, de->d_name, statbuf); } } else { if ((de->d_name)[0] != '.' ) { - entries->push_back(sFileEntry(prefix+de->d_name, pathbuf, 1, getMimeType(de->d_name))); + // regular folder + string mime = getMimeType(de->d_name); + if ((mime == "video/mp4") || (mime == "video/3gp")) { + *(mLog->log()) << DEBUGPREFIX << " mp4 fn= " << de->d_name + << " base= " << dir_base + << " dir= " << dir_name + << " comp= " << dir_comp + << " size= " << statbuf->st_size + << " pathbuf= " << pathbuf + << endl; + cMp4Metadata meta(pathbuf, statbuf->st_size); + meta.parseMetadata(); + entries->push_back(sFileEntry(prefix+de->d_name, pathbuf, meta.mCreationTime, mime, + (meta.mHaveTitle) ? meta.mTitle : prefix+de->d_name, + meta.mShortDesc, meta.mLongDesc, meta.mDuration)); + } + else + entries->push_back(sFileEntry(prefix+de->d_name, pathbuf, statbuf->st_mtime, mime)); } } } @@ -1796,10 +1874,18 @@ int cResponseMemBlk::sendMediaXml (struct stat *statbuf) { snprintf(pathbuf, sizeof(pathbuf), "http://%s:%d%s", own_ip.c_str(), mRequest->mServerPort, cUrlEncode::doUrlSaveEncode(entries[i].sPath).c_str()); - if (writeXmlItem(cUrlEncode::doXmlSaveEncode(entries[i].sName), pathbuf, "NA", "NA", - cUrlEncode::doUrlSaveEncode(entries[i].sPath).c_str(), - -1, entries[i].sStart, -1, -1, -1, -1, entries[i].sMime) == ERROR) - return ERROR; + if (entries[i].sHaveMeta) { + if (writeXmlItem(cUrlEncode::doXmlSaveEncode(entries[i].sTitle), pathbuf, + cUrlEncode::doXmlSaveEncode(entries[i].sLongDesc), "NA", + cUrlEncode::doUrlSaveEncode(entries[i].sPath).c_str(), + -1, entries[i].sStart, entries[i].sDuration, -1, -1, -1, entries[i].sMime) == ERROR) + return ERROR; + } + else + if (writeXmlItem(cUrlEncode::doXmlSaveEncode(entries[i].sName), pathbuf, "NA", "NA", + cUrlEncode::doUrlSaveEncode(entries[i].sPath).c_str(), + -1, entries[i].sStart, -1, -1, -1, -1, entries[i].sMime) == ERROR) + return ERROR; } diff --git a/responsememblk.h b/responsememblk.h index 1895ad2..752b527 100755 --- a/responsememblk.h +++ b/responsememblk.h @@ -35,13 +35,24 @@ using namespace std; struct sFileEntry { + bool sHaveMeta; string sName; string sPath; int sStart; string sMime; + + string sTitle; + string sShortDesc; + string sLongDesc; + float sDuration; + +sFileEntry(string n, string l, int s, string m) : sHaveMeta(false), sName(n), sPath(l), + sStart(s), sMime(m), sTitle(""), sShortDesc("NA"), sLongDesc("NA"), sDuration(0.0) { +}; -sFileEntry(string n, string l, int s, string m) : sName(n), sPath(l), sStart(s), sMime(m) { - }; +sFileEntry(string n, string l, int s, string m, string t, string desc, string ldes, float dur) : sHaveMeta(true), + sName(n), sPath(l), sStart(s), sMime(m), sTitle(t), sShortDesc(desc), sLongDesc(ldes), sDuration(dur) { +}; }; @@ -66,6 +77,7 @@ class cResponseMemBlk : public cResponseBase { int sendYtBookmarkletJs(); int sendBmlInstHtml(); + int sendMp4Covr(); int sendEpgXml (struct stat *statbuf); int sendUrlsXml (); int sendMediaXml (struct stat *statbuf); diff --git a/smarttvfactory.h b/smarttvfactory.h index 625e511..ad6b2c7 100755 --- a/smarttvfactory.h +++ b/smarttvfactory.h @@ -1,7 +1,7 @@ /* * smarttvfactory.h: VDR on Smart TV plugin * - * Copyright (C) 2012 - 2014 T. Lohmar + * Copyright (C) 2012 - 2015 T. Lohmar * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -47,8 +47,8 @@ class cStatus { using namespace std; -#define PLG_VERSION "1.0.1" -#define SERVER "SmartTvWeb/1.0.1" +#define PLG_VERSION "1.0.2" +#define SERVER "SmartTvWeb/1.0.2" class cLiveRelay; struct sClientEntry { -- cgit v1.2.3