]> git.vomp.tv Git - vompserver.git/commitdiff
Media Player From Andreas Vogel
authorChris Tallon <chris@vomp.tv>
Sun, 15 Jul 2007 16:57:48 +0000 (16:57 +0000)
committerChris Tallon <chris@vomp.tv>
Sun, 15 Jul 2007 16:57:48 +0000 (16:57 +0000)
Makefile
config.c
media.c [new file with mode: 0644]
media.h [new file with mode: 0644]
mvpclient.c
mvpclient.h
mvpserver.c

index d7d52c322ca4bf435990742e902ed45508085505..9aa3d517fbc4ad49ec48d02852d0d83e4f8d3047 100644 (file)
--- 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:
 
index e4748c1894c8f79261293839c4ec4651adf8c64a..08a217a5ff393874b0d5d34fed2c313ba8adab4f 100644 (file)
--- 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 (file)
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 <sys/stat.h>
+#include <sys/types.h>
+
+
+
+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;i<NUMTYPES;i++) {
+            if (endswith(fname,mediatypes[i].extension)) {
+              mtype=mediatypes[i].type;
+              break;
+              }
+           }
+         }
+      }
+    free(buffer);
+    //only consider entries we accept by type here
+    if (mtype & type) {
+     Media * m =new Media(mtype,fname,(int)(st.st_mtime));
+     rt->Add(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 (file)
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 <stdio.h>
+#include <pthread.h>
+#include <signal.h>
+#include <endian.h>
+
+#include <unistd.h> // sleep
+
+#include <vdr/tools.h>
+
+//#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<Media> {
+  public:
+    static MediaList *readList(Config *cfg,const char * dirname,int type=MEDIA_TYPE_ALL);
+  };
+
+#endif
index fb7e34b7a0547bd03125ec81cb605e31b2366694..96f06768e100abc08f2c748f10026a2bee21b909 100644 (file)
@@ -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;nm<ml->Count() && 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;
+}
+
+
index 885a3282c4e3fa4ef936b52ef650b604aa3da375..a761ce00168f730201e610f519df57adf303a956 100644 (file)
 #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
 
index f1ce5622adb31db6f48f8fe298a48419a62b29c9..aed8f4ed75db884ea85be3862305f12c551b5744 100644 (file)
@@ -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();
   }
 }
+