From ccafa4b3d48cae51156b0b8043bbace151e17a64 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Sun, 15 Jul 2007 16:57:48 +0000 Subject: [PATCH] Media Player From Andreas Vogel --- Makefile | 3 +- config.c | 5 ++ media.c | 132 ++++++++++++++++++++++++++++++++++ media.h | 76 ++++++++++++++++++++ mvpclient.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++- mvpclient.h | 8 ++- mvpserver.c | 3 +- 7 files changed, 423 insertions(+), 4 deletions(-) create mode 100644 media.c create mode 100644 media.h diff --git a/Makefile b/Makefile index d7d52c3..9aa3d51 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,8 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' OBJS = $(PLUGIN).o dsock.o mvpserver.o udpreplier.o bootpd.o tftpd.o mvpclient.o tcp.o \ ringbuffer.o mvprelay.o \ - recplayer.o config.o log.o thread.o mvpreceiver.o tftpclient.o + recplayer.o config.o log.o thread.o mvpreceiver.o tftpclient.o \ + media.o ### Implicit rules: diff --git a/config.c b/config.c index e4748c1..08a217a 100644 --- a/config.c +++ b/config.c @@ -62,6 +62,11 @@ int Config::init(char* takeFileName) return 1; } +int Config::status() +{ + return initted; +} + int Config::shutdown() { if (!initted) return 1; diff --git a/media.c b/media.c new file mode 100644 index 0000000..89a75e2 --- /dev/null +++ b/media.c @@ -0,0 +1,132 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "media.h" +//#include "tools.h" +#include +#include + + + +Media::Media(int type, const char * filename, int time){ + _filename=NULL; + if (filename) { + int len=strlen(filename)+1; + _filename=new char[len]; + strcpy(_filename,filename); + } + _type=type; + _time=time; + }; + +Media::~Media(){ + delete _filename; + _filename=NULL; + }; + +const char * Media::getFilename() { + return _filename; + } + +int Media::getType() { + return _type; + } +int Media::getTime() { + return _time; + } + + +static struct mtype{ + const char* extension; + int type; + } mediatypes[]= { + {".mp3",MEDIA_TYPE_AUDIO}, + {".MP3",MEDIA_TYPE_AUDIO}, + {".jpg",MEDIA_TYPE_PICTURE}, + {".JPG",MEDIA_TYPE_PICTURE}, + {".jpeg",MEDIA_TYPE_PICTURE}, + {".JPEG",MEDIA_TYPE_PICTURE} + }; +//#define NUMTYPES (sizeof(mediatypes)/sizeof(mtype)) +#define NUMTYPES 6 + +MediaList * MediaList::readList(Config * cfg,const char * dirname, int type) { + MediaList *rt=NULL; + if (dirname == NULL) { + //the configured Media List + //for the moment up to 10 entries [Media] Dir.1 ...Dir.10 + for (int nr=1;nr<=10;nr++){ + char buffer[20]; + sprintf(buffer,"Dir.%d",nr); + const char * dn=cfg->getValueString("Media",buffer); + if (dn != NULL) { + if (rt == NULL) rt=new MediaList(); + Media *m=new Media(MEDIA_TYPE_DIR,dn,0); + rt->Add(m); + Log::getInstance()->log("Media",Log::DEBUG,"added base dir %s",dn); + } + } + } + if (rt != NULL) return rt; + //if nothing is configured, we start at / + if (dirname == NULL) dirname="/"; + rt=new MediaList(); + //open the directory and read out the entries + cReadDir d(dirname); + struct dirent *e; + while ((e=d.Next()) != NULL) { + { + const char * fname=e->d_name; + if ( fname == NULL) continue; + if (strcmp(fname,".") == 0) continue; + char *buffer; + asprintf(&buffer, "%s/%s", dirname, e->d_name); + struct stat st; + int mtype=MEDIA_TYPE_UNKNOWN; + if (stat(buffer, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + mtype=MEDIA_TYPE_DIR; + } + else { + for (int i=0;iAdd(m); + Log::getInstance()->log("Media",Log::DEBUG,"added entry %s, type=%d",fname,mtype); + } + } + } + //test + //Media *m=new Media(MEDIA_TYPE_DIR,"testMedia1",0); + //rt->Add(m); + return rt; + } + + + diff --git a/media.h b/media.h new file mode 100644 index 0000000..c8642d3 --- /dev/null +++ b/media.h @@ -0,0 +1,76 @@ +/* + Copyright 2004-2005 Chris Tallon, Andreas Vogel + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MEDIA_H +#define MEDIA_H + +#include +#include +#include +#include + +#include // sleep + +#include + +//#include "defines.h" +//#include "tcp.h" +//#include "mvpreceiver.h" +//#include "recplayer.h" +#include "config.h" + +//the following defines must be consisten to the client side +/* media types form a bitmask + so you can add them to have > 1*/ +#define MEDIA_TYPE_DIR 1 +#define MEDIA_TYPE_AUDIO 2 +#define MEDIA_TYPE_VIDEO 4 +#define MEDIA_TYPE_PICTURE 8 +#define MEDIA_TYPE_UNKNOWN 256 + +#define MEDIA_TYPE_ALL (1+2+4+8) + +class Media : public cListObject +{ + public: + /** + * create a media entry + * filename will get copied + */ + Media(int type, const char * filename, int time); + ~Media(); + const char * getFilename(); + int getType(); + int getTime(); + + private: + char * _filename; + int _type; + int _time; + + +}; + +class MediaList : public cList { + public: + static MediaList *readList(Config *cfg,const char * dirname,int type=MEDIA_TYPE_ALL); + }; + +#endif diff --git a/mvpclient.c b/mvpclient.c index fb7e34b..96f0676 100644 --- a/mvpclient.c +++ b/mvpclient.c @@ -27,15 +27,17 @@ pthread_mutex_t threadClientMutex; int MVPClient::nr_clients = 0; -MVPClient::MVPClient(char* tconfigDirExtra, int tsocket) +MVPClient::MVPClient(Config* cfgBase, char* tconfigDirExtra, int tsocket) : tcp(tsocket) { lp = NULL; rp = NULL; + imageFile = 0; recordingManager = NULL; log = Log::getInstance(); loggedIn = false; configDirExtra = tconfigDirExtra; + baseConfig = cfgBase; incClients(); } @@ -258,6 +260,15 @@ void MVPClient::run2() case 22: result = processGetChannelPids(data, packetLength); break; + case 30: + result = processGetMediaList(data, packetLength); + break; + case 31: + result = processGetPicture(data, packetLength); + break; + case 32: + result = processGetImageBlock(data, packetLength); + break; } free(buffer); @@ -1929,3 +1940,190 @@ int MVPClient::processGetMarks(UCHAR* data, int length) return 1; } + + +/** + * media List Request: + * 4 length + * 4 VDR_GETMEDIALIST + * 4 flags (currently unused) + * n dirname + * n+1 0 + * Media List response: + * 4 length + * 4 VDR_ + * 4 numentries + * per entry: + * 4 media type + * 4 time stamp + * 4 flags + * 4 strlen (incl. 0 Byte) + * string + * 0 +*/ +#define MLISTBUF 500000 +int MVPClient::processGetMediaList(UCHAR* data, int length) +{ + if (length < 4) { + log->log("Client", Log::ERR, "getMediaList packet too short %d", length); + return 0; + } + char * dirname=NULL; + if (length > 4) { + //we have a dirname provided + dirname=(char *)&data[4]; + log->log("Client", Log::DEBUG, "getMediaList for %s", dirname); + } + + + UCHAR* sendBuffer = new UCHAR[MLISTBUF]; // FIXME hope this is enough + int count = 4; // leave space for the header + + MediaList * ml=MediaList::readList(baseConfig,dirname); + if (ml == NULL) { + log->log("Client", Log::ERR, "getMediaList returned NULL"); + return 0; + } + //response code (not yet set) + *(ULONG*)&sendBuffer[count] = htonl(0); + count += 4; + //numentries + *(ULONG*)&sendBuffer[count] = htonl(ml->Count()); + count += 4; + for (int nm=0;nmCount() && count < (MLISTBUF-1000);nm++) { + Media *m=ml->Get(nm); + log->log("Client", Log::DEBUG, "found media entry %s, type=%d",m->getFilename(),m->getType()); + *(ULONG*)&sendBuffer[count] = htonl(m->getType()); + count += 4; + //time stamp + *(ULONG*)&sendBuffer[count] = htonl(m->getTime()); + count += 4; + //flags + *(ULONG*)&sendBuffer[count] = htonl(0); + count += 4; + int len=strlen(m->getFilename()); + //strlen + *(ULONG*)&sendBuffer[count] = htonl(len+1); + count += 4; + //should have a check for strlen > 1000... + strcpy((char *)&sendBuffer[count],m->getFilename()); + count+=len+1; + } + delete ml; + + *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field + + log->log("Client", Log::DEBUG, "getMediaList size %u", ntohl(*(ULONG*)&sendBuffer[0])); + + tcp.sendPacket(sendBuffer, count); + delete[] sendBuffer; + log->log("Client", Log::DEBUG, "Written Media list"); + + return 1; +} + +/** + * get image Request: + * 4 length + * 4 VDR_GETIMAGE + * 4 flags (currently unused) + * 4 x size + * 4 y size + * n filename + * n+1 0 + * get image response: + * 4 length + * 4 VDR_GETIMAGE + * 4 len of image +*/ +#define MLISTBUF 500000 +int MVPClient::processGetPicture(UCHAR* data, int length) +{ + if (length < 12) { + log->log("Client", Log::ERR, "getPicture packet too short %d", length); + return 0; + } + if (imageFile) { + fclose(imageFile); + imageFile=NULL; + } + char * filename=NULL; + if (length > 4) { + //we have a dirname provided + filename=(char *)&data[4]; + log->log("Client", Log::DEBUG, "getPicture %s", filename); + } + else { + log->log("Client", Log::ERR, "getPicture empty filename"); + } + if (filename) { + imageFile=fopen(filename,"r"); + if (!imageFile) log->log("Client", Log::ERR, "getPicture unable to open %s",filename); + } + int size=0; + if (imageFile) { + struct stat st; + if ( fstat(fileno(imageFile),&st) == 0) size=st.st_size; + } + UCHAR* sendBuffer = new UCHAR[12]; + int count = 4; // leave space for the header + //response code (not yet set) + *(ULONG*)&sendBuffer[count] = htonl(31); + count += 4; + //size + *(ULONG*)&sendBuffer[count] = htonl(size); + count += 4; + *(ULONG*)&sendBuffer[0] = htonl(count - 4); // -4 : take off the size field + log->log("Client", Log::DEBUG, "getPicture size %u", size); + + tcp.sendPacket(sendBuffer, count); + delete[] sendBuffer; + log->log("Client", Log::DEBUG, "Written Media list"); + + return 1; +} + + +int MVPClient::processGetImageBlock(UCHAR* data, int length) +{ + if (!imageFile) + { + log->log("Client", Log::DEBUG, "Get image block called when no image active"); + return 0; + } + + ULLONG position = ntohll(*(ULLONG*)data); + data += sizeof(ULLONG); + ULONG amount = ntohl(*(ULONG*)data); + + log->log("Client", Log::DEBUG, "getImageblock pos = %llu length = %lu", position, amount); + + UCHAR sendBuffer[amount + 4]; + ULONG amountReceived = 0; // compiler moan. + ULLONG cpos=ftell(imageFile); + if (position != cpos) { + fseek(imageFile,position-cpos,SEEK_CUR); + } + if (position != (ULLONG)ftell(imageFile)) { + log->log("Client", Log::DEBUG, "getImageblock pos = %llu not available", position); + } + else { + amountReceived=fread(&sendBuffer[4],1,amount,imageFile); + } + + if (!amountReceived) + { + sendULONG(0); + log->log("Client", Log::DEBUG, "written 4(0) as getblock got 0"); + } + else + { + *(ULONG*)&sendBuffer[0] = htonl(amountReceived); + tcp.sendPacket(sendBuffer, amountReceived + 4); + log->log("Client", Log::DEBUG, "written ok %lu", amountReceived); + } + + return 1; +} + + diff --git a/mvpclient.h b/mvpclient.h index 885a328..a761ce0 100644 --- a/mvpclient.h +++ b/mvpclient.h @@ -40,11 +40,12 @@ #include "mvpreceiver.h" #include "recplayer.h" #include "config.h" +#include "media.h" class MVPClient { public: - MVPClient(char* configDirExtra, int tsocket); + MVPClient(Config* baseConfig, char* configDirExtra, int tsocket); ~MVPClient(); int run(); @@ -58,9 +59,11 @@ class MVPClient int initted; TCP tcp; Config config; + Config* baseConfig; MVPReceiver* lp; bool loggedIn; char* configDirExtra; + FILE* imageFile; cRecordings* recordingManager; @@ -87,6 +90,9 @@ class MVPClient int processGetRecInfo(UCHAR* data, int length); int processGetMarks(UCHAR* data, int length); int processGetChannelPids(UCHAR* data, int length); + int processGetMediaList(UCHAR* data, int length); + int processGetPicture(UCHAR* data, int length); + int processGetImageBlock(UCHAR* data, int length); int processReScanRecording(UCHAR* data, int length); // FIXME obselete diff --git a/mvpserver.c b/mvpserver.c index f1ce562..aed8f4e 100644 --- a/mvpserver.c +++ b/mvpserver.c @@ -250,7 +250,8 @@ void MVPServer::threadMethod() while(1) { clientSocket = accept(listeningSocket,(struct sockaddr *)&address, &length); - MVPClient* m = new MVPClient(configDirExtra, clientSocket); + MVPClient* m = new MVPClient(&config, configDirExtra, clientSocket); m->run(); } } + -- 2.39.5